From 31e44a2516540adacd05c920275c988bbb0238a5 Mon Sep 17 00:00:00 2001 From: Tiago Quintino Date: Mon, 25 Mar 2013 12:04:10 +0000 Subject: [PATCH 001/737] Ported grib_api 1.10.4 from p4 to git --- ...rator_class_lambert_azimuthal_equal_area.c | 288 ++++++++++++++++++ src/grib_iterator_class_lambert_conformal.c | 274 +++++++++++++++++ src/grib_iterator_class_polar_stereographic.c | 279 +++++++++++++++++ 3 files changed, 841 insertions(+) create mode 100644 src/grib_iterator_class_lambert_azimuthal_equal_area.c create mode 100644 src/grib_iterator_class_lambert_conformal.c create mode 100644 src/grib_iterator_class_polar_stereographic.c diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c new file mode 100644 index 000000000..38c859959 --- /dev/null +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -0,0 +1,288 @@ +/* + * Copyright 2005-2012 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. + */ + +/************************************** + * Enrico Fucile + **************************************/ + + +#include "grib_api_internal.h" +#include + +/* + This is used by make_class.pl + + START_CLASS_DEF + CLASS = iterator + SUPER = grib_iterator_class_gen + IMPLEMENTS = destroy + IMPLEMENTS = init;next + MEMBERS = double *lats + MEMBERS = double *lons + MEMBERS = long nam + 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 "iterator.class" and rerun ./make_class.pl + +*/ + + +static void init_class (grib_iterator_class*); + +static int init (grib_iterator* i,grib_handle*,grib_arguments*); +static int next (grib_iterator* i, double *lat, double *lon, double *val); +static int destroy (grib_iterator* i); + + +typedef struct grib_iterator_lambert_azimuthal_equal_area{ + grib_iterator it; +/* Members defined in gen */ + long carg; + const char* missingValue; +/* Members defined in lambert_azimuthal_equal_area */ + double *lats; + double *lons; + long nam; +} grib_iterator_lambert_azimuthal_equal_area; + +extern grib_iterator_class* grib_iterator_class_gen; + +static grib_iterator_class _grib_iterator_class_lambert_azimuthal_equal_area = { + &grib_iterator_class_gen, /* super */ + "lambert_azimuthal_equal_area", /* name */ + sizeof(grib_iterator_lambert_azimuthal_equal_area),/* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ +}; + +grib_iterator_class* grib_iterator_class_lambert_azimuthal_equal_area = &_grib_iterator_class_lambert_azimuthal_equal_area; + + +static void init_class(grib_iterator_class* c) +{ + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; +} +/* END_CLASS_IMP */ + +static int next(grib_iterator* i, double *lat, double *lon, double *val) +{ + + grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; + + if((long)i->e >= (long)(i->nv-1)) + return 0; + i->e++; + + *lat = self->lats[i->e]; + *lon = self->lons[i->e]; + *val = i->data[i->e]; + + return 1; +} + + +static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) +{ + int ret=0; + double *lats,*lons; + double lonFirstInDegrees,latFirstInDegrees,lonFirst,latFirst,radius=0; + long nx,ny,standardParallel,centralLongitude; + double phi1,lambda0,xFirst,yFirst,x,y,Dx,Dy; + double kp,sinphi1,cosphi1; + long alternativeRowScanning,iScansNegatively; + long jScansPositively,jPointsAreConsecutive; + double sinphi,cosphi,cosdlambda,sindlambda; + double cosc,sinc; + long i,j; + + grib_iterator_lambert_azimuthal_equal_area* self = + (grib_iterator_lambert_azimuthal_equal_area*)iter; + + const char* sradius = grib_arguments_get_name(h,args,self->carg++); + const char* snx = grib_arguments_get_name(h,args,self->carg++); + const char* sny = grib_arguments_get_name(h,args,self->carg++); + const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sstandardParallel = grib_arguments_get_name(h,args,self->carg++); + const char* scentralLongitude = grib_arguments_get_name(h,args,self->carg++); + const char* sDx = grib_arguments_get_name(h,args,self->carg++); + const char* sDy = grib_arguments_get_name(h,args,self->carg++); + const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); + double c,rho; + double epsilon=1.0e-20; + double d2r=acos(0.0)/90.0; + + if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) + return ret; + + if (iter->nv!=nx*ny) { + grib_context_log(h->context,GRIB_LOG_ERROR, + "Wrong number of points (%ld!=%ldx%ld)", + iter->nv,nx,ny); + return GRIB_WRONG_GRID; + } + if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sstandardParallel,&standardParallel)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, scentralLongitude,¢ralLongitude)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sDx,&Dx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sDy,&Dy)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, + sjPointsAreConsecutive,&jPointsAreConsecutive)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, + salternativeRowScanning,&alternativeRowScanning)) + != GRIB_SUCCESS) + return ret; + + lambda0=d2r*centralLongitude/1000000; + phi1=d2r*standardParallel/1000000; + latFirst=latFirstInDegrees*d2r; + lonFirst=lonFirstInDegrees*d2r; + + cosphi1=cos(phi1); + sinphi1=sin(phi1); + + Dx = iScansNegatively == 0 ? Dx/1000 : -Dx/1000; + Dy = jScansPositively == 1 ? Dy/1000 : -Dy/1000; + self->lats = grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, + "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, + "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats=self->lats; + lons=self->lons; + + /* compute xFirst,yFirst in metres */ + sinphi=sin(latFirst); + cosphi=cos(latFirst); + cosdlambda=cos(lonFirst-lambda0); + sindlambda=sin(lonFirst-lambda0); + kp=radius*sqrt(2.0/(1+sinphi1*sinphi+cosphi1*cosphi*cosdlambda)); + xFirst=kp*cosphi*sindlambda; + yFirst=kp*(cosphi1*sinphi-sinphi1*cosphi*cosdlambda); + + if (jPointsAreConsecutive) { + + x=xFirst; + for (i=0;iepsilon) { + c=2*asin(rho/(2.0*radius)); + cosc=cos(c); + sinc=sin(c); + *lats=asin(cosc*sinphi1+y*sinc*cosphi1/rho)/d2r; + *lons=(lambda0+atan2(x*sinc,rho*cosphi1*cosc-y*sinphi1*sinc))/d2r; + } else { + *lats=phi1/d2r; + *lons=lambda0/d2r; + } + if (*lons<0) *lons+=360; + lons++; + lats++; + + y+=Dy; + } + x+=Dx; + } + + } else { + + y=yFirst; + for (j=0;jepsilon) { + c=2*asin(rho/(2.0*radius)); + cosc=cos(c); + sinc=sin(c); + *lats=asin(cosc*sinphi1+y*sinc*cosphi1/rho)/d2r; + *lons=(lambda0+atan2(x*sinc,rho*cosphi1*cosc-y*sinphi1*sinc))/d2r; + } else { + *lats=phi1/d2r; + *lons=lambda0/d2r; + } + if (*lons<0) *lons+=360; + lons++; + lats++; + + x+=Dx; + } + y+=Dy; + } + + } + + iter->e = -1; + + return ret; +} + +static int destroy(grib_iterator* i) +{ + grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; + const grib_context *c = i->h->context; + + grib_context_free(c,self->lats); + grib_context_free(c,self->lons); + return 1; +} + diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c new file mode 100644 index 000000000..4b7811f7f --- /dev/null +++ b/src/grib_iterator_class_lambert_conformal.c @@ -0,0 +1,274 @@ +/* + * Copyright 2005-2012 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" +#include + +/* + This is used by make_class.pl + + START_CLASS_DEF + CLASS = iterator + SUPER = grib_iterator_class_gen + IMPLEMENTS = destroy + IMPLEMENTS = init;next + MEMBERS = double *lats + MEMBERS = double *lons + MEMBERS = long nam + 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 "iterator.class" and rerun ./make_class.pl + +*/ + + +static void init_class (grib_iterator_class*); + +static int init (grib_iterator* i,grib_handle*,grib_arguments*); +static int next (grib_iterator* i, double *lat, double *lon, double *val); +static int destroy (grib_iterator* i); + + +typedef struct grib_iterator_lambert_conformal{ + grib_iterator it; +/* Members defined in gen */ + long carg; + const char* missingValue; +/* Members defined in lambert_conformal */ + double *lats; + double *lons; + long nam; +} grib_iterator_lambert_conformal; + +extern grib_iterator_class* grib_iterator_class_gen; + +static grib_iterator_class _grib_iterator_class_lambert_conformal = { + &grib_iterator_class_gen, /* super */ + "lambert_conformal", /* name */ + sizeof(grib_iterator_lambert_conformal),/* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ +}; + +grib_iterator_class* grib_iterator_class_lambert_conformal = &_grib_iterator_class_lambert_conformal; + + +static void init_class(grib_iterator_class* c) +{ + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; +} +/* END_CLASS_IMP */ + +static int next(grib_iterator* i, double *lat, double *lon, double *val) +{ + + grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; + + if((long)i->e >= (long)(i->nv-1)) + return 0; + i->e++; + + *lat = self->lats[i->e]; + *lon = self->lons[i->e]; + *val = i->data[i->e]; + + return 1; +} + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* Whole pie */ +#endif + +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 /* Half a pie */ +#endif + +#ifndef M_PI_4 +#define M_PI_4 0.78539816339744830962 /* Quarter of a pie */ +#endif + +#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ +#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ + +static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) +{ + int i, j, ret=0; + double *lats, *lons; /* the lat/lon arrays to be populated */ + long nx,ny,iScansNegatively,jScansPositively,jPointsAreConsecutive,alternativeRowScanning; + double LoVInDegrees,LaDInDegrees,Latin1InDegrees,Latin2InDegrees,latFirstInDegrees, + lonFirstInDegrees, Dx, Dy, radius=0; + double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, + LaDInRadians, lonDiff, lonDeg, latDeg; + double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; + + grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; + + const char* sradius = grib_arguments_get_name(h,args,self->carg++); + const char* snx = grib_arguments_get_name(h,args,self->carg++); + const char* sny = grib_arguments_get_name(h,args,self->carg++); + const char* sLoVInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sLaDInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sLatin1InDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sLatin2InDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + /* Dx and Dy are in Metres */ + const char* sDx = grib_arguments_get_name(h,args,self->carg++); + const char* sDy = grib_arguments_get_name(h,args,self->carg++); + const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); + + if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) + return ret; + + if (iter->nv!=nx*ny) { + grib_context_log(h->context,GRIB_LOG_ERROR,"Wrong number of points (%ld!=%ldx%ld)",iter->nv,nx,ny); + return GRIB_WRONG_GRID; + } + if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sLoVInDegrees, &LoVInDegrees))!=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sLaDInDegrees, &LaDInDegrees))!=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sLatin1InDegrees, &Latin1InDegrees))!=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sLatin2InDegrees, &Latin2InDegrees))!=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sDx,&Dx)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sDy,&Dy)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) !=GRIB_SUCCESS) + return ret; + + /* See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html */ + latFirstInRadians = latFirstInDegrees * DEG2RAD; + lonFirstInRadians = lonFirstInDegrees * DEG2RAD; + Latin1InRadians = Latin1InDegrees * DEG2RAD; + Latin2InRadians = Latin2InDegrees * DEG2RAD; + LaDInRadians = LaDInDegrees * DEG2RAD; + LoVInRadians = LoVInDegrees * DEG2RAD; + + if ( fabs(Latin1InRadians - Latin2InRadians) < 1E-09 ) { + n = sin(Latin1InRadians); + } + else { + n = log(cos(Latin1InRadians)/cos(Latin2InRadians)) / + log(tan(M_PI_4 + Latin2InRadians/2.0) / tan(M_PI_4 + Latin1InRadians/2.0)); + } + + f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians/2.0), n)) / n; + rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians/2.0), -n); + rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians/2.0), -n); + if ( n < 0 ) /* adjustment for southern hemisphere */ + rho0 = -rho0; + lonDiff = lonFirstInRadians - LoVInRadians; + + /* Adjust longitude to range -180 to 180 */ + if (lonDiff > M_PI) lonDiff -= 2*M_PI; + if (lonDiff < -M_PI) lonDiff += 2*M_PI; + angle = n * lonDiff; + x0 = rho * sin(angle); + y0 = rho0 - rho * cos(angle); + Dx = iScansNegatively == 0 ? Dx : -Dx; + Dy = jScansPositively == 1 ? Dy : -Dy; + + /* No support (yet) for jPointsAreConsecutive */ + if (jPointsAreConsecutive) { + grib_context_log(h->context,GRIB_LOG_ERROR,"No support for: 'Adjacent points in j (y) direction being consecutive'"); + Assert(0); + } + + /* Allocate latitude and longitude arrays */ + self->lats = grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats=self->lats; + lons=self->lons; + + /* Populate our arrays */ + for (j = 0; j < ny; j++) { + y = y0 + j*Dy; + if ( n < 0 ) { /* adjustment for southern hemisphere */ + y = -y; + } + tmp = rho0 - y; + tmp2 = tmp*tmp; + for (i = 0; i < nx; i++) { + int index =i+j*nx; + x = x0 + i*Dx; + if ( n < 0 ) { /* adjustment for southern hemisphere */ + x = -x; + } + + angle = atan(x / tmp); + rho = sqrt(x*x + tmp2); + if (n <= 0) rho = -rho; + lonDeg = LoVInDegrees + (angle/n) * RAD2DEG; + latDeg = (2.0 * atan(pow(radius * f/rho, 1.0/n)) - M_PI_2) * RAD2DEG; + while ( lonDeg >= 360.0) lonDeg -= 360.0; + while ( lonDeg < 0.0) lonDeg += 360.0; + lons[index] = lonDeg; + lats[index] = latDeg; + } + } + + iter->e = -1; + + return ret; +} + +static int destroy(grib_iterator* i) +{ + grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; + const grib_context *c = i->h->context; + + grib_context_free(c,self->lats); + grib_context_free(c,self->lons); + return 1; +} + diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c new file mode 100644 index 000000000..3d2bb4f1b --- /dev/null +++ b/src/grib_iterator_class_polar_stereographic.c @@ -0,0 +1,279 @@ +/* + * Copyright 2005-2012 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. + */ + +/************************************** + * Enrico Fucile + **************************************/ + + +#include "grib_api_internal.h" +#include + +/* + This is used by make_class.pl + + START_CLASS_DEF + CLASS = iterator + SUPER = grib_iterator_class_gen + IMPLEMENTS = destroy + IMPLEMENTS = init;next + MEMBERS = double *lats + MEMBERS = double *lons + MEMBERS = long nam + 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 "iterator.class" and rerun ./make_class.pl + +*/ + + +static void init_class (grib_iterator_class*); + +static int init (grib_iterator* i,grib_handle*,grib_arguments*); +static int next (grib_iterator* i, double *lat, double *lon, double *val); +static int destroy (grib_iterator* i); + + +typedef struct grib_iterator_polar_stereographic{ + grib_iterator it; +/* Members defined in gen */ + long carg; + const char* missingValue; +/* Members defined in polar_stereographic */ + double *lats; + double *lons; + long nam; +} grib_iterator_polar_stereographic; + +extern grib_iterator_class* grib_iterator_class_gen; + +static grib_iterator_class _grib_iterator_class_polar_stereographic = { + &grib_iterator_class_gen, /* super */ + "polar_stereographic", /* name */ + sizeof(grib_iterator_polar_stereographic),/* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ +}; + +grib_iterator_class* grib_iterator_class_polar_stereographic = &_grib_iterator_class_polar_stereographic; + + +static void init_class(grib_iterator_class* c) +{ + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; +} +/* END_CLASS_IMP */ + +static int next(grib_iterator* i, double *lat, double *lon, double *val) +{ + + grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; + + if((long)i->e >= (long)(i->nv-1)) + return 0; + i->e++; + + *lat = self->lats[i->e]; + *lon = self->lons[i->e]; + *val = i->data[i->e]; + + return 1; +} + + +static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) +{ + int ret=0; + double *lats,*lons; + double lonFirstInDegrees,latFirstInDegrees,lonFirst,latFirst,radius=0; + long nx,ny,standardParallel,centralLongitude; + double phi,lambda0,xFirst,yFirst,x,y,Dx,Dy; + double kp,sinphi1,cosphi1,sinlambda0,coslambda0; + long alternativeRowScanning,iScansNegatively; + long jScansPositively,jPointsAreConsecutive; + double sinphi,cosphi,sinlambda,coslambda,cosdlambda,sindlambda; + double cosc,sinc; + long i,j; + + + grib_iterator_polar_stereographic* self = + (grib_iterator_polar_stereographic*)iter; + + const char* sradius = grib_arguments_get_name(h,args,self->carg++); + const char* snx = grib_arguments_get_name(h,args,self->carg++); + const char* sny = grib_arguments_get_name(h,args,self->carg++); + const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sstandardParallel = grib_arguments_get_name(h,args,self->carg++); + const char* scentralLongitude = grib_arguments_get_name(h,args,self->carg++); + const char* sDx = grib_arguments_get_name(h,args,self->carg++); + const char* sDy = grib_arguments_get_name(h,args,self->carg++); + const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); + double c,rho; + double d2r=acos(0.0)/90.0; + double pi4=acos(0.0)/2.0; + sinphi1 = cosphi1 = phi = 0.0; /*TODO initialize properly*/ + + if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) + return ret; + + if (iter->nv!=nx*ny) { + grib_context_log(h->context,GRIB_LOG_ERROR, + "Wrong number of points (%ld!=%ldx%ld)", + iter->nv,nx,ny); + return GRIB_WRONG_GRID; + } + if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sstandardParallel,&standardParallel)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, scentralLongitude,¢ralLongitude)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sDx,&Dx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sDy,&Dy)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, + sjPointsAreConsecutive,&jPointsAreConsecutive)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, + salternativeRowScanning,&alternativeRowScanning)) + != GRIB_SUCCESS) + return ret; + + lambda0=d2r*standardParallel; + latFirst=latFirstInDegrees*d2r; + lonFirst=lonFirstInDegrees*d2r; + + coslambda0=cos(lambda0); + sinlambda0=sin(lambda0); + + Dx = iScansNegatively == 0 ? Dx : -Dx; + Dy = jScansPositively == 1 ? Dy : -Dy; + self->lats = grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, + "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, + "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats=self->lats; + lons=self->lons; + + /* compute xFirst,yFirst in metres */ + sinphi=sin(latFirst); + cosphi=cos(latFirst); + sinlambda=sin(lonFirst); + coslambda=cos(lonFirst); + cosdlambda=cos(lonFirst-lambda0); + sindlambda=sin(lonFirst-lambda0); + kp=radius*2.0*tan(pi4-phi/2); + xFirst=kp*cosphi*sindlambda; + yFirst=-kp*cosphi*cosdlambda; + + if (jPointsAreConsecutive) { + + x=xFirst; + for (i=0;ie = -1; + + return ret; +} + +static int destroy(grib_iterator* i) +{ + grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; + const grib_context *c = i->h->context; + + grib_context_free(c,self->lats); + grib_context_free(c,self->lons); + return 1; +} + From 900c0c44ef30fb5653f6a5db4f31e3f101d43011 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Thu, 18 Apr 2013 10:23:23 +0100 Subject: [PATCH 002/737] Update copyright text --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 2 +- src/grib_iterator_class_lambert_conformal.c | 2 +- src/grib_iterator_class_polar_stereographic.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 38c859959..791b38f55 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2012 ECMWF. + * Copyright 2005-2013 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. diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 4b7811f7f..90ea7b385 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2012 ECMWF. + * Copyright 2005-2013 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. diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 3d2bb4f1b..cfda9063c 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2012 ECMWF. + * Copyright 2005-2013 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. From a135fff023e5e6ac08449fc572040f10aa9ca86a Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 3 Jan 2014 16:22:21 +0000 Subject: [PATCH 003/737] Update copyright text --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 2 +- src/grib_iterator_class_lambert_conformal.c | 2 +- src/grib_iterator_class_polar_stereographic.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 791b38f55..f414c675e 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2013 ECMWF. + * Copyright 2005-2014 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. diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 90ea7b385..4b956e04a 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2013 ECMWF. + * Copyright 2005-2014 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. diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index cfda9063c..c203fcf2b 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2013 ECMWF. + * Copyright 2005-2014 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. From f9a3d4926b2de4e8b0219ccb0c7760c3f779e19c Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 20 Aug 2014 16:38:51 +0100 Subject: [PATCH 004/737] GRIB-574: Polar stereographic support (Part 1) --- src/grib_iterator_class_polar_stereographic.c | 332 ++++++++---------- 1 file changed, 155 insertions(+), 177 deletions(-) diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index c203fcf2b..eeb532985 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -8,11 +8,6 @@ * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction. */ -/************************************** - * Enrico Fucile - **************************************/ - - #include "grib_api_internal.h" #include @@ -88,192 +83,175 @@ static void init_class(grib_iterator_class* c) static int next(grib_iterator* i, double *lat, double *lon, double *val) { + grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; - grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; - - if((long)i->e >= (long)(i->nv-1)) - return 0; - i->e++; + if((long)i->e >= (long)(i->nv-1)) + return 0; + i->e++; - *lat = self->lats[i->e]; - *lon = self->lons[i->e]; - *val = i->data[i->e]; + *lat = self->lats[i->e]; + *lon = self->lons[i->e]; + *val = i->data[i->e]; - return 1; + return 1; } +#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ +#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) { - int ret=0; - double *lats,*lons; - double lonFirstInDegrees,latFirstInDegrees,lonFirst,latFirst,radius=0; - long nx,ny,standardParallel,centralLongitude; - double phi,lambda0,xFirst,yFirst,x,y,Dx,Dy; - double kp,sinphi1,cosphi1,sinlambda0,coslambda0; - long alternativeRowScanning,iScansNegatively; - long jScansPositively,jPointsAreConsecutive; - double sinphi,cosphi,sinlambda,coslambda,cosdlambda,sindlambda; - double cosc,sinc; - long i,j; - - - grib_iterator_polar_stereographic* self = - (grib_iterator_polar_stereographic*)iter; - - const char* sradius = grib_arguments_get_name(h,args,self->carg++); - const char* snx = grib_arguments_get_name(h,args,self->carg++); - const char* sny = grib_arguments_get_name(h,args,self->carg++); - const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sstandardParallel = grib_arguments_get_name(h,args,self->carg++); - const char* scentralLongitude = grib_arguments_get_name(h,args,self->carg++); - const char* sDx = grib_arguments_get_name(h,args,self->carg++); - const char* sDy = grib_arguments_get_name(h,args,self->carg++); - const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); - double c,rho; - double d2r=acos(0.0)/90.0; - double pi4=acos(0.0)/2.0; - sinphi1 = cosphi1 = phi = 0.0; /*TODO initialize properly*/ - - if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) - return ret; - - if (iter->nv!=nx*ny) { - grib_context_log(h->context,GRIB_LOG_ERROR, - "Wrong number of points (%ld!=%ldx%ld)", - iter->nv,nx,ny); - return GRIB_WRONG_GRID; - } - if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sstandardParallel,&standardParallel)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, scentralLongitude,¢ralLongitude)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sDx,&Dx)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sDy,&Dy)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, - sjPointsAreConsecutive,&jPointsAreConsecutive)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, - salternativeRowScanning,&alternativeRowScanning)) - != GRIB_SUCCESS) - return ret; - - lambda0=d2r*standardParallel; - latFirst=latFirstInDegrees*d2r; - lonFirst=lonFirstInDegrees*d2r; - - coslambda0=cos(lambda0); - sinlambda0=sin(lambda0); - - Dx = iScansNegatively == 0 ? Dx : -Dx; - Dy = jScansPositively == 1 ? Dy : -Dy; - self->lats = grib_context_malloc(h->context,iter->nv*sizeof(double)); - if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, - "unable to allocate %ld bytes",iter->nv*sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = grib_context_malloc(h->context,iter->nv*sizeof(double)); - if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, - "unable to allocate %ld bytes",iter->nv*sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - lats=self->lats; - lons=self->lons; - - /* compute xFirst,yFirst in metres */ - sinphi=sin(latFirst); - cosphi=cos(latFirst); - sinlambda=sin(lonFirst); - coslambda=cos(lonFirst); - cosdlambda=cos(lonFirst-lambda0); - sindlambda=sin(lonFirst-lambda0); - kp=radius*2.0*tan(pi4-phi/2); - xFirst=kp*cosphi*sindlambda; - yFirst=-kp*cosphi*cosdlambda; - - if (jPointsAreConsecutive) { - - x=xFirst; - for (i=0;icarg++); + const char* snx = grib_arguments_get_name(h,args,self->carg++); + const char* sny = grib_arguments_get_name(h,args,self->carg++); + const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sstandardParallel = grib_arguments_get_name(h,args,self->carg++); + const char* scentralLongitude = grib_arguments_get_name(h,args,self->carg++); + const char* sDx = grib_arguments_get_name(h,args,self->carg++); + const char* sDy = grib_arguments_get_name(h,args,self->carg++); + const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); + double c,rho; + /*double pi4=acos(0.0)/2.0;*/ + sinphi1 = cosphi1 = phi = 0.0; + + if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) + return ret; + + if (iter->nv!=nx*ny) { + grib_context_log(h->context,GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv,nx,ny); + return GRIB_WRONG_GRID; } - - } else { - - y=yFirst; - for (j=0;jlats = grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; } + self->lons = grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats=self->lats; + lons=self->lons; + + /* compute xFirst,yFirst in metres */ + sinphi=sin(latFirst); + cosphi=cos(latFirst); + cosdlambda=cos(lonFirst-lambda0); + sindlambda=sin(lonFirst-lambda0); + + k = 2.0 * radius / ( 1 + sinphi1*sinphi + cosphi1*cosphi*cosdlambda ); + xFirst = k * cosphi * sindlambda; + yFirst = k * (cosphi1*sinphi - sinphi1*cosphi*cosdlambda); + + /*kp=radius*2.0*tan(pi4-phi/2); + xFirst=kp*cosphi*sindlambda; + yFirst=-kp*cosphi*cosdlambda;*/ + + if (jPointsAreConsecutive) + { + x=xFirst; + for (i=0;ie = -1; - } - - iter->e = -1; - - return ret; + return ret; } static int destroy(grib_iterator* i) { - grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; - const grib_context *c = i->h->context; + grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; + const grib_context *c = i->h->context; - grib_context_free(c,self->lats); - grib_context_free(c,self->lons); - return 1; + grib_context_free(c,self->lats); + grib_context_free(c,self->lons); + return 1; } - From f55f83ff45685ec5c4bc0bbda36f34dc08f402a8 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Thu, 2 Oct 2014 16:50:49 +0100 Subject: [PATCH 005/737] GRIB-588: compile grib_api with a C++ compiler --- ...rator_class_lambert_azimuthal_equal_area.c | 4 +- src/grib_iterator_class_lambert_conformal.c | 4 +- src/grib_iterator_class_polar_stereographic.c | 38 +++++++++++++------ 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index f414c675e..9cd9be1cb 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -191,13 +191,13 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) Dx = iScansNegatively == 0 ? Dx/1000 : -Dx/1000; Dy = jScansPositively == 1 ? Dy/1000 : -Dy/1000; - self->lats = grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); return GRIB_OUT_OF_MEMORY; } - self->lons = grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 4b956e04a..a17c6b674 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -217,12 +217,12 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) } /* Allocate latitude and longitude arrays */ - self->lats = grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); return GRIB_OUT_OF_MEMORY; } - self->lons = grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); return GRIB_OUT_OF_MEMORY; diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index eeb532985..d090acc4a 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -172,12 +172,12 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) Dx = iScansNegatively == 0 ? Dx : -Dx; Dy = jScansPositively == 1 ? Dy : -Dy; - self->lats = grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); return GRIB_OUT_OF_MEMORY; } - self->lons = grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); return GRIB_OUT_OF_MEMORY; @@ -206,11 +206,18 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) y=yFirst; for (j=0;j Date: Fri, 3 Oct 2014 16:45:17 +0100 Subject: [PATCH 006/737] GRIB-574 Polar Stereographic. Use -/+90 for std parallel not LaD --- src/grib_iterator_class_polar_stereographic.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index d090acc4a..5ce36eedb 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -105,10 +105,10 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) double *lats,*lons; double lonFirstInDegrees,latFirstInDegrees,lonFirst,latFirst,radius=0; long nx,ny,standardParallel,centralLongitude; - double phi,lambda0,xFirst,yFirst,x,y,Dx,Dy; + double lambda0,xFirst,yFirst,x,y,Dx,Dy; double k,sinphi1,cosphi1; long alternativeRowScanning,iScansNegatively; - long jScansPositively,jPointsAreConsecutive; + long jScansPositively,jPointsAreConsecutive, southPoleOnPlane; double sinphi,cosphi,cosdlambda,sindlambda; double cosc,sinc; long i,j; @@ -120,7 +120,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) const char* sny = grib_arguments_get_name(h,args,self->carg++); const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sstandardParallel = grib_arguments_get_name(h,args,self->carg++); + const char* ssouthPoleOnPlane = grib_arguments_get_name(h,args,self->carg++); const char* scentralLongitude = grib_arguments_get_name(h,args,self->carg++); const char* sDx = grib_arguments_get_name(h,args,self->carg++); const char* sDy = grib_arguments_get_name(h,args,self->carg++); @@ -129,8 +129,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); double c,rho; - /*double pi4=acos(0.0)/2.0;*/ - sinphi1 = cosphi1 = phi = 0.0; + sinphi1 = cosphi1 = 0.0; if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) return ret; @@ -147,7 +146,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) return ret; if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sstandardParallel,&standardParallel)) != GRIB_SUCCESS) + if((ret = grib_get_long_internal(h, ssouthPoleOnPlane,&southPoleOnPlane)) != GRIB_SUCCESS) return ret; if((ret = grib_get_long_internal(h, scentralLongitude,¢ralLongitude)) != GRIB_SUCCESS) return ret; @@ -164,6 +163,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) if((ret = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) != GRIB_SUCCESS) return ret; + standardParallel = (southPoleOnPlane == 1) ? -90 : +90; sinphi1 = sin(standardParallel*DEG2RAD); cosphi1 = cos(standardParallel*DEG2RAD); lambda0 = centralLongitude*DEG2RAD; From 231b3abd7555fe18f3d3f698a40d6eb8d7608126 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Mon, 5 Jan 2015 15:45:46 +0000 Subject: [PATCH 007/737] Update Copyright notice to 2015 --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 2 +- src/grib_iterator_class_lambert_conformal.c | 2 +- src/grib_iterator_class_polar_stereographic.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 9cd9be1cb..516bfe5b3 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2014 ECMWF. + * 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. diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index a17c6b674..f4097e346 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2014 ECMWF. + * 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. diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 5ce36eedb..53bf189ed 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2014 ECMWF. + * 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. From ab2d5a41ad1575dab9a1f86c33642442bcdd361c Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 22 Dec 2015 17:55:45 +0000 Subject: [PATCH 008/737] Cleanup --- ...rator_class_lambert_azimuthal_equal_area.c | 353 +++++++++--------- 1 file changed, 175 insertions(+), 178 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 516bfe5b3..fb5ae6764 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -89,200 +89,197 @@ static void init_class(grib_iterator_class* c) static int next(grib_iterator* i, double *lat, double *lon, double *val) { - grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; + grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; - if((long)i->e >= (long)(i->nv-1)) - return 0; - i->e++; + if((long)i->e >= (long)(i->nv-1)) + return 0; + i->e++; - *lat = self->lats[i->e]; - *lon = self->lons[i->e]; - *val = i->data[i->e]; + *lat = self->lats[i->e]; + *lon = self->lons[i->e]; + *val = i->data[i->e]; - return 1; + return 1; } - static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) { - int ret=0; - double *lats,*lons; - double lonFirstInDegrees,latFirstInDegrees,lonFirst,latFirst,radius=0; - long nx,ny,standardParallel,centralLongitude; - double phi1,lambda0,xFirst,yFirst,x,y,Dx,Dy; - double kp,sinphi1,cosphi1; - long alternativeRowScanning,iScansNegatively; - long jScansPositively,jPointsAreConsecutive; - double sinphi,cosphi,cosdlambda,sindlambda; - double cosc,sinc; - long i,j; - - grib_iterator_lambert_azimuthal_equal_area* self = - (grib_iterator_lambert_azimuthal_equal_area*)iter; - - const char* sradius = grib_arguments_get_name(h,args,self->carg++); - const char* snx = grib_arguments_get_name(h,args,self->carg++); - const char* sny = grib_arguments_get_name(h,args,self->carg++); - const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sstandardParallel = grib_arguments_get_name(h,args,self->carg++); - const char* scentralLongitude = grib_arguments_get_name(h,args,self->carg++); - const char* sDx = grib_arguments_get_name(h,args,self->carg++); - const char* sDy = grib_arguments_get_name(h,args,self->carg++); - const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); - double c,rho; - double epsilon=1.0e-20; - double d2r=acos(0.0)/90.0; - - if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) - return ret; - - if (iter->nv!=nx*ny) { - grib_context_log(h->context,GRIB_LOG_ERROR, - "Wrong number of points (%ld!=%ldx%ld)", - iter->nv,nx,ny); - return GRIB_WRONG_GRID; - } - if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sstandardParallel,&standardParallel)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, scentralLongitude,¢ralLongitude)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sDx,&Dx)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sDy,&Dy)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, - sjPointsAreConsecutive,&jPointsAreConsecutive)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) - != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, - salternativeRowScanning,&alternativeRowScanning)) - != GRIB_SUCCESS) - return ret; - - lambda0=d2r*centralLongitude/1000000; - phi1=d2r*standardParallel/1000000; - latFirst=latFirstInDegrees*d2r; - lonFirst=lonFirstInDegrees*d2r; - - cosphi1=cos(phi1); - sinphi1=sin(phi1); - - Dx = iScansNegatively == 0 ? Dx/1000 : -Dx/1000; - Dy = jScansPositively == 1 ? Dy/1000 : -Dy/1000; - self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); - if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, - "unable to allocate %ld bytes",iter->nv*sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); - if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, - "unable to allocate %ld bytes",iter->nv*sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - lats=self->lats; - lons=self->lons; - - /* compute xFirst,yFirst in metres */ - sinphi=sin(latFirst); - cosphi=cos(latFirst); - cosdlambda=cos(lonFirst-lambda0); - sindlambda=sin(lonFirst-lambda0); - kp=radius*sqrt(2.0/(1+sinphi1*sinphi+cosphi1*cosphi*cosdlambda)); - xFirst=kp*cosphi*sindlambda; - yFirst=kp*(cosphi1*sinphi-sinphi1*cosphi*cosdlambda); - - if (jPointsAreConsecutive) { - - x=xFirst; - for (i=0;iepsilon) { - c=2*asin(rho/(2.0*radius)); - cosc=cos(c); - sinc=sin(c); - *lats=asin(cosc*sinphi1+y*sinc*cosphi1/rho)/d2r; - *lons=(lambda0+atan2(x*sinc,rho*cosphi1*cosc-y*sinphi1*sinc))/d2r; - } else { - *lats=phi1/d2r; - *lons=lambda0/d2r; - } - if (*lons<0) *lons+=360; - lons++; - lats++; - - y+=Dy; - } - x+=Dx; + int ret=0; + double *lats,*lons; + double lonFirstInDegrees,latFirstInDegrees,lonFirst,latFirst,radius=0; + long nx,ny,standardParallel,centralLongitude; + double phi1,lambda0,xFirst,yFirst,x,y,Dx,Dy; + double kp,sinphi1,cosphi1; + long alternativeRowScanning,iScansNegatively; + long jScansPositively,jPointsAreConsecutive; + double sinphi,cosphi,cosdlambda,sindlambda; + double cosc,sinc; + long i,j; + + grib_iterator_lambert_azimuthal_equal_area* self = + (grib_iterator_lambert_azimuthal_equal_area*)iter; + + const char* sradius = grib_arguments_get_name(h,args,self->carg++); + const char* snx = grib_arguments_get_name(h,args,self->carg++); + const char* sny = grib_arguments_get_name(h,args,self->carg++); + const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sstandardParallel = grib_arguments_get_name(h,args,self->carg++); + const char* scentralLongitude = grib_arguments_get_name(h,args,self->carg++); + const char* sDx = grib_arguments_get_name(h,args,self->carg++); + const char* sDy = grib_arguments_get_name(h,args,self->carg++); + const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); + double c,rho; + double epsilon=1.0e-20; + double d2r=acos(0.0)/90.0; + + if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) + return ret; + + if (iter->nv!=nx*ny) { + grib_context_log(h->context,GRIB_LOG_ERROR, + "Wrong number of points (%ld!=%ldx%ld)", + iter->nv,nx,ny); + return GRIB_WRONG_GRID; } - - } else { - - y=yFirst; - for (j=0;jepsilon) { - c=2*asin(rho/(2.0*radius)); - cosc=cos(c); - sinc=sin(c); - *lats=asin(cosc*sinphi1+y*sinc*cosphi1/rho)/d2r; - *lons=(lambda0+atan2(x*sinc,rho*cosphi1*cosc-y*sinphi1*sinc))/d2r; - } else { - *lats=phi1/d2r; - *lons=lambda0/d2r; + if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sstandardParallel,&standardParallel)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, scentralLongitude,¢ralLongitude)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sDx,&Dx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sDy,&Dy)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, + sjPointsAreConsecutive,&jPointsAreConsecutive)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) + != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, + salternativeRowScanning,&alternativeRowScanning)) + != GRIB_SUCCESS) + return ret; + + lambda0=d2r*centralLongitude/1000000; + phi1=d2r*standardParallel/1000000; + latFirst=latFirstInDegrees*d2r; + lonFirst=lonFirstInDegrees*d2r; + + cosphi1=cos(phi1); + sinphi1=sin(phi1); + + Dx = iScansNegatively == 0 ? Dx/1000 : -Dx/1000; + Dy = jScansPositively == 1 ? Dy/1000 : -Dy/1000; + self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, + "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, + "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats=self->lats; + lons=self->lons; + + /* compute xFirst,yFirst in metres */ + sinphi=sin(latFirst); + cosphi=cos(latFirst); + cosdlambda=cos(lonFirst-lambda0); + sindlambda=sin(lonFirst-lambda0); + kp=radius*sqrt(2.0/(1+sinphi1*sinphi+cosphi1*cosphi*cosdlambda)); + xFirst=kp*cosphi*sindlambda; + yFirst=kp*(cosphi1*sinphi-sinphi1*cosphi*cosdlambda); + + if (jPointsAreConsecutive) { + + x=xFirst; + for (i=0;iepsilon) { + c=2*asin(rho/(2.0*radius)); + cosc=cos(c); + sinc=sin(c); + *lats=asin(cosc*sinphi1+y*sinc*cosphi1/rho)/d2r; + *lons=(lambda0+atan2(x*sinc,rho*cosphi1*cosc-y*sinphi1*sinc))/d2r; + } else { + *lats=phi1/d2r; + *lons=lambda0/d2r; + } + if (*lons<0) *lons+=360; + lons++; + lats++; + + y+=Dy; + } + x+=Dx; } - if (*lons<0) *lons+=360; - lons++; - lats++; - x+=Dx; - } - y+=Dy; + } else { + + y=yFirst; + for (j=0;jepsilon) { + c=2*asin(rho/(2.0*radius)); + cosc=cos(c); + sinc=sin(c); + *lats=asin(cosc*sinphi1+y*sinc*cosphi1/rho)/d2r; + *lons=(lambda0+atan2(x*sinc,rho*cosphi1*cosc-y*sinphi1*sinc))/d2r; + } else { + *lats=phi1/d2r; + *lons=lambda0/d2r; + } + if (*lons<0) *lons+=360; + lons++; + lats++; + + x+=Dx; + } + y+=Dy; + } } - } - - iter->e = -1; + iter->e = -1; - return ret; + return ret; } static int destroy(grib_iterator* i) { - grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; - const grib_context *c = i->h->context; + grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; + const grib_context *c = i->h->context; - grib_context_free(c,self->lats); - grib_context_free(c,self->lons); - return 1; + grib_context_free(c,self->lats); + grib_context_free(c,self->lons); + return 1; } - From 235f49ae460fcbc0dd5ed78b05308362c6cdb0f0 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Thu, 31 Dec 2015 12:44:51 +0000 Subject: [PATCH 009/737] GRIB-902: Update copyright notices: 2015 -> 2016 --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 2 +- src/grib_iterator_class_lambert_conformal.c | 2 +- src/grib_iterator_class_polar_stereographic.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index fb5ae6764..9cdb6db92 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2015 ECMWF. + * Copyright 2005-2016 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. diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index f4097e346..2a66d6553 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2015 ECMWF. + * Copyright 2005-2016 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. diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 53bf189ed..7a21b2c08 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2015 ECMWF. + * Copyright 2005-2016 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. From b73a862272c802850c59f6fd118ae78cbcd54468 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 2 Apr 2016 12:20:55 +0100 Subject: [PATCH 010/737] GRIB-958: Some lat/lon values are invalid for Polar stereographic grid --- src/grib_iterator_class_polar_stereographic.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 7a21b2c08..7d5744515 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -218,7 +218,8 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) *lats = asin( cosc*sinphi1 + y*sinc*cosphi1/rho ) * RAD2DEG; *lons = (lambda0+atan2(x*sinc, rho*cosphi1*cosc - y*sinphi1*sinc)) * RAD2DEG; } - if (*lons<0) *lons+=360; + while (*lons<0) *lons += 360; + while (*lons>360) *lons -= 360; lons++; lats++; @@ -246,7 +247,8 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) *lats = asin( cosc*sinphi1 + y*sinc*cosphi1/rho ) * RAD2DEG; *lons = (lambda0+atan2(x*sinc, rho*cosphi1*cosc - y*sinphi1*sinc)) * RAD2DEG; } - if (*lons<0) *lons+=360; + while (*lons<0) *lons += 360; + while (*lons>360) *lons -= 360; lons++; lats++; From 4b184c42b2f778d82703cebfc2fc5718a4f133f4 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 15 Jun 2016 18:50:53 +0100 Subject: [PATCH 011/737] GRIB-405: Lambert Projection and jScansPositively=0 --- src/grib_iterator_class_lambert_conformal.c | 305 ++++++++++---------- 1 file changed, 152 insertions(+), 153 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 2a66d6553..f8c52c2dc 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -83,7 +83,6 @@ static void init_class(grib_iterator_class* c) static int next(grib_iterator* i, double *lat, double *lon, double *val) { - grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; if((long)i->e >= (long)(i->nv-1)) @@ -114,161 +113,161 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) { - int i, j, ret=0; - double *lats, *lons; /* the lat/lon arrays to be populated */ - long nx,ny,iScansNegatively,jScansPositively,jPointsAreConsecutive,alternativeRowScanning; - double LoVInDegrees,LaDInDegrees,Latin1InDegrees,Latin2InDegrees,latFirstInDegrees, - lonFirstInDegrees, Dx, Dy, radius=0; - double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, - LaDInRadians, lonDiff, lonDeg, latDeg; - double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; - - grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; - - const char* sradius = grib_arguments_get_name(h,args,self->carg++); - const char* snx = grib_arguments_get_name(h,args,self->carg++); - const char* sny = grib_arguments_get_name(h,args,self->carg++); - const char* sLoVInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sLaDInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sLatin1InDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sLatin2InDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); - /* Dx and Dy are in Metres */ - const char* sDx = grib_arguments_get_name(h,args,self->carg++); - const char* sDy = grib_arguments_get_name(h,args,self->carg++); - const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); - - if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) - return ret; - - if (iter->nv!=nx*ny) { - grib_context_log(h->context,GRIB_LOG_ERROR,"Wrong number of points (%ld!=%ldx%ld)",iter->nv,nx,ny); - return GRIB_WRONG_GRID; - } - if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sLoVInDegrees, &LoVInDegrees))!=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sLaDInDegrees, &LaDInDegrees))!=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sLatin1InDegrees, &Latin1InDegrees))!=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sLatin2InDegrees, &Latin2InDegrees))!=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sDx,&Dx)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sDy,&Dy)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) !=GRIB_SUCCESS) - return ret; - - /* See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html */ - latFirstInRadians = latFirstInDegrees * DEG2RAD; - lonFirstInRadians = lonFirstInDegrees * DEG2RAD; - Latin1InRadians = Latin1InDegrees * DEG2RAD; - Latin2InRadians = Latin2InDegrees * DEG2RAD; - LaDInRadians = LaDInDegrees * DEG2RAD; - LoVInRadians = LoVInDegrees * DEG2RAD; - - if ( fabs(Latin1InRadians - Latin2InRadians) < 1E-09 ) { - n = sin(Latin1InRadians); - } - else { - n = log(cos(Latin1InRadians)/cos(Latin2InRadians)) / - log(tan(M_PI_4 + Latin2InRadians/2.0) / tan(M_PI_4 + Latin1InRadians/2.0)); - } - - f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians/2.0), n)) / n; - rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians/2.0), -n); - rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians/2.0), -n); - if ( n < 0 ) /* adjustment for southern hemisphere */ - rho0 = -rho0; - lonDiff = lonFirstInRadians - LoVInRadians; - - /* Adjust longitude to range -180 to 180 */ - if (lonDiff > M_PI) lonDiff -= 2*M_PI; - if (lonDiff < -M_PI) lonDiff += 2*M_PI; - angle = n * lonDiff; - x0 = rho * sin(angle); - y0 = rho0 - rho * cos(angle); - Dx = iScansNegatively == 0 ? Dx : -Dx; - Dy = jScansPositively == 1 ? Dy : -Dy; - - /* No support (yet) for jPointsAreConsecutive */ - if (jPointsAreConsecutive) { - grib_context_log(h->context,GRIB_LOG_ERROR,"No support for: 'Adjacent points in j (y) direction being consecutive'"); - Assert(0); - } - - /* Allocate latitude and longitude arrays */ - self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); - if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); - if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - lats=self->lats; - lons=self->lons; - - /* Populate our arrays */ - for (j = 0; j < ny; j++) { - y = y0 + j*Dy; - if ( n < 0 ) { /* adjustment for southern hemisphere */ - y = -y; - } - tmp = rho0 - y; - tmp2 = tmp*tmp; - for (i = 0; i < nx; i++) { - int index =i+j*nx; - x = x0 + i*Dx; - if ( n < 0 ) { /* adjustment for southern hemisphere */ - x = -x; - } - - angle = atan(x / tmp); - rho = sqrt(x*x + tmp2); - if (n <= 0) rho = -rho; - lonDeg = LoVInDegrees + (angle/n) * RAD2DEG; - latDeg = (2.0 * atan(pow(radius * f/rho, 1.0/n)) - M_PI_2) * RAD2DEG; - while ( lonDeg >= 360.0) lonDeg -= 360.0; - while ( lonDeg < 0.0) lonDeg += 360.0; - lons[index] = lonDeg; - lats[index] = latDeg; - } - } - - iter->e = -1; - - return ret; + int i, j, ret=0; + double *lats, *lons; /* the lat/lon arrays to be populated */ + long nx,ny,iScansNegatively,jScansPositively,jPointsAreConsecutive,alternativeRowScanning; + double LoVInDegrees,LaDInDegrees,Latin1InDegrees,Latin2InDegrees,latFirstInDegrees, + lonFirstInDegrees, Dx, Dy, radius=0; + double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, + LaDInRadians, lonDiff, lonDeg, latDeg; + double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; + + grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; + + const char* sradius = grib_arguments_get_name(h,args,self->carg++); + const char* snx = grib_arguments_get_name(h,args,self->carg++); + const char* sny = grib_arguments_get_name(h,args,self->carg++); + const char* sLoVInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sLaDInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sLatin1InDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sLatin2InDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + /* Dx and Dy are in Metres */ + const char* sDx = grib_arguments_get_name(h,args,self->carg++); + const char* sDy = grib_arguments_get_name(h,args,self->carg++); + const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); + + if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) + return ret; + + if (iter->nv!=nx*ny) { + grib_context_log(h->context,GRIB_LOG_ERROR,"Wrong number of points (%ld!=%ldx%ld)",iter->nv,nx,ny); + return GRIB_WRONG_GRID; + } + if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sLoVInDegrees, &LoVInDegrees))!=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sLaDInDegrees, &LaDInDegrees))!=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sLatin1InDegrees, &Latin1InDegrees))!=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sLatin2InDegrees, &Latin2InDegrees))!=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sDx,&Dx)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sDy,&Dy)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) !=GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) !=GRIB_SUCCESS) + return ret; + + /* See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html */ + latFirstInRadians = latFirstInDegrees * DEG2RAD; + lonFirstInRadians = lonFirstInDegrees * DEG2RAD; + Latin1InRadians = Latin1InDegrees * DEG2RAD; + Latin2InRadians = Latin2InDegrees * DEG2RAD; + LaDInRadians = LaDInDegrees * DEG2RAD; + LoVInRadians = LoVInDegrees * DEG2RAD; + + if ( fabs(Latin1InRadians - Latin2InRadians) < 1E-09 ) { + n = sin(Latin1InRadians); + } + else { + n = log(cos(Latin1InRadians)/cos(Latin2InRadians)) / + log(tan(M_PI_4 + Latin2InRadians/2.0) / tan(M_PI_4 + Latin1InRadians/2.0)); + } + + f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians/2.0), n)) / n; + rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians/2.0), -n); + rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians/2.0), -n); + if ( n < 0 ) /* adjustment for southern hemisphere */ + rho0 = -rho0; + lonDiff = lonFirstInRadians - LoVInRadians; + + /* Adjust longitude to range -180 to 180 */ + if (lonDiff > M_PI) lonDiff -= 2*M_PI; + if (lonDiff < -M_PI) lonDiff += 2*M_PI; + angle = n * lonDiff; + x0 = rho * sin(angle); + y0 = rho0 - rho * cos(angle); + Dx = iScansNegatively == 0 ? Dx : -Dx; + /* GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint */ + /*Dy = jScansPositively == 1 ? Dy : -Dy;*/ + + /* No support (yet) for jPointsAreConsecutive */ + if (jPointsAreConsecutive) { + grib_context_log(h->context,GRIB_LOG_ERROR,"No support for: 'Adjacent points in j (y) direction being consecutive'"); + Assert(0); + } + + /* Allocate latitude and longitude arrays */ + self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats=self->lats; + lons=self->lons; + + /* Populate our arrays */ + for (j = 0; j < ny; j++) { + y = y0 + j*Dy; + if ( n < 0 ) { /* adjustment for southern hemisphere */ + y = -y; + } + tmp = rho0 - y; + tmp2 = tmp*tmp; + for (i = 0; i < nx; i++) { + int index =i+j*nx; + x = x0 + i*Dx; + if ( n < 0 ) { /* adjustment for southern hemisphere */ + x = -x; + } + + angle = atan(x / tmp); + rho = sqrt(x*x + tmp2); + if (n <= 0) rho = -rho; + lonDeg = LoVInDegrees + (angle/n) * RAD2DEG; + latDeg = (2.0 * atan(pow(radius * f/rho, 1.0/n)) - M_PI_2) * RAD2DEG; + while ( lonDeg >= 360.0) lonDeg -= 360.0; + while ( lonDeg < 0.0) lonDeg += 360.0; + lons[index] = lonDeg; + lats[index] = latDeg; + } + } + + iter->e = -1; + + return ret; } static int destroy(grib_iterator* i) { - grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; - const grib_context *c = i->h->context; + grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; + const grib_context *c = i->h->context; - grib_context_free(c,self->lats); - grib_context_free(c,self->lons); - return 1; + grib_context_free(c,self->lats); + grib_context_free(c,self->lons); + return 1; } - From a7848dee004288c6dd966bca6a5841bcbaf03c55 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 9 Dec 2016 17:55:20 +0000 Subject: [PATCH 012/737] ECC-383: Implement iterator for 'space view' (Part 1) --- src/grib_iterator_class_space_view.c | 285 +++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 src/grib_iterator_class_space_view.c diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c new file mode 100644 index 000000000..ec13c232b --- /dev/null +++ b/src/grib_iterator_class_space_view.c @@ -0,0 +1,285 @@ +/* + * Copyright 2005-2016 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" +#include + +/* + This is used by make_class.pl + + START_CLASS_DEF + CLASS = iterator + SUPER = grib_iterator_class_gen + IMPLEMENTS = destroy + IMPLEMENTS = init;next + MEMBERS = double *lats + MEMBERS = double *lons + MEMBERS = long nam + 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 "iterator.class" and rerun ./make_class.pl + +*/ + + +static void init_class (grib_iterator_class*); + +static int init (grib_iterator* i,grib_handle*,grib_arguments*); +static int next (grib_iterator* i, double *lat, double *lon, double *val); +static int destroy (grib_iterator* i); + + +typedef struct grib_iterator_space_view{ + grib_iterator it; +/* Members defined in gen */ + long carg; + const char* missingValue; +/* Members defined in space_view */ + double *lats; + double *lons; + long nam; +} grib_iterator_space_view; + +extern grib_iterator_class* grib_iterator_class_gen; + +static grib_iterator_class _grib_iterator_class_space_view = { + &grib_iterator_class_gen, /* super */ + "space_view", /* name */ + sizeof(grib_iterator_space_view),/* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ +}; + +grib_iterator_class* grib_iterator_class_space_view = &_grib_iterator_class_space_view; + + +static void init_class(grib_iterator_class* c) +{ + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; +} +/* END_CLASS_IMP */ + +static int next(grib_iterator* i, double *lat, double *lon, double *val) +{ + grib_iterator_space_view* self = (grib_iterator_space_view*)i; + + if((long)i->e >= (long)(i->nv-1)) + return 0; + i->e++; + + *lat = self->lats[i->e]; + *lon = self->lons[i->e]; + *val = i->data[i->e]; + + return 1; +} + +#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ +#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ + +static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) +{ + int ret=0; +#if 0 + double *lats,*lons; + double latOfSubSatellitePointInDegrees,lonOfSubSatellitePointInDegrees; + double orientationInDegrees; + double lonFirst,latFirst,radius=0,xpInGridLengths=0,ypInGridLengths=0; + long nx,ny,standardParallel,centralLongitude,Dx,Dy; + double lambda0,xFirst,yFirst,x,y; + double k,sinphi1,cosphi1; + long alternativeRowScanning,iScansNegatively; + long jScansPositively,jPointsAreConsecutive, southPoleOnPlane; + double sinphi,cosphi,cosdlambda,sindlambda; + double cosc,sinc; + long i,j; + + grib_iterator_space_view* self = (grib_iterator_space_view*)iter; + + const char* sradius = grib_arguments_get_name(h,args,self->carg++); + const char* snx = grib_arguments_get_name(h,args,self->carg++); + const char* sny = grib_arguments_get_name(h,args,self->carg++); + const char* sLatOfSubSatellitePointInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sLonOfSubSatellitePointInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sDx = grib_arguments_get_name(h,args,self->carg++); + const char* sDy = grib_arguments_get_name(h,args,self->carg++); + const char* sXpInGridLengths = grib_arguments_get_name(h,args,self->carg++); + const char* sYpInGridLengths = grib_arguments_get_name(h,args,self->carg++); + const char* sOrientationInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sNr = grib_arguments_get_name(h,args,self->carg++); + const char* sXo = grib_arguments_get_name(h,args,self->carg++); + const char* sYo = grib_arguments_get_name(h,args,self->carg++); + + const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); + double c,rho; + sinphi1 = cosphi1 = 0.0; + + if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) + return ret; + + if (iter->nv!=nx*ny) { + grib_context_log(h->context,GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv,nx,ny); + return GRIB_WRONG_GRID; + } + if((ret = grib_get_double_internal(h, sLatOfSubSatellitePointInDegrees,&latOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sLonOfSubSatellitePointInDegrees,&lonOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sDx,&Dx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sDy,&Dy)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sXpInGridLengths,&xpInGridLengths)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sYpInGridLengths,&ypInGridLengths)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sOrientationInDegrees,&orientationInDegrees)) != GRIB_SUCCESS) + return ret; + + if((ret = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) != GRIB_SUCCESS) + return ret; + + standardParallel = (southPoleOnPlane == 1) ? -90 : +90; + sinphi1 = sin(standardParallel*DEG2RAD); + cosphi1 = cos(standardParallel*DEG2RAD); + lambda0 = centralLongitude*DEG2RAD; + latFirst= latFirstInDegrees*DEG2RAD; + lonFirst= lonFirstInDegrees*DEG2RAD; + + Dx = iScansNegatively == 0 ? Dx : -Dx; + Dy = jScansPositively == 1 ? Dy : -Dy; + self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats=self->lats; + lons=self->lons; + + /* compute xFirst,yFirst in metres */ + sinphi=sin(latFirst); + cosphi=cos(latFirst); + cosdlambda=cos(lonFirst-lambda0); + sindlambda=sin(lonFirst-lambda0); + + k = 2.0 * radius / ( 1 + sinphi1*sinphi + cosphi1*cosphi*cosdlambda ); + xFirst = k * cosphi * sindlambda; + yFirst = k * (cosphi1*sinphi - sinphi1*cosphi*cosdlambda); + + /*kp=radius*2.0*tan(pi4-phi/2); + xFirst=kp*cosphi*sindlambda; + yFirst=-kp*cosphi*cosdlambda;*/ + + if (jPointsAreConsecutive) + { + x=xFirst; + for (i=0;i360) *lons -= 360; + lons++; + lats++; + + y+=Dy; + } + x+=Dx; + } + } + else + { + y=yFirst; + for (j=0;j360) *lons -= 360; + lons++; + lats++; + + x+=Dx; + } + y+=Dy; + } + } +#endif + iter->e = -1; + + return ret; +} + +static int destroy(grib_iterator* i) +{ + grib_iterator_space_view* self = (grib_iterator_space_view*)i; + const grib_context *c = i->h->context; + + grib_context_free(c,self->lats); + grib_context_free(c,self->lons); + return 1; +} From c6aa82002dca1da1f2e8a79e5443ea6c7c91c8c2 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Mon, 12 Dec 2016 18:09:56 +0000 Subject: [PATCH 013/737] ECC-383: Implement iterator for 'space view' (Part 2) --- src/grib_iterator_class_space_view.c | 230 ++++++++++++++++----------- 1 file changed, 133 insertions(+), 97 deletions(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index ec13c232b..492de37af 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -102,23 +102,30 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) { int ret=0; -#if 0 double *lats,*lons; double latOfSubSatellitePointInDegrees,lonOfSubSatellitePointInDegrees; - double orientationInDegrees; - double lonFirst,latFirst,radius=0,xpInGridLengths=0,ypInGridLengths=0; - long nx,ny,standardParallel,centralLongitude,Dx,Dy; - double lambda0,xFirst,yFirst,x,y; - double k,sinphi1,cosphi1; + double orientationInDegrees, nrInRadiusOfEarth; + double radius=0,xpInGridLengths=0,ypInGridLengths=0; + long nx, ny, earthIsOblate; long alternativeRowScanning,iScansNegatively; - long jScansPositively,jPointsAreConsecutive, southPoleOnPlane; - double sinphi,cosphi,cosdlambda,sindlambda; - double cosc,sinc; - long i,j; - + long Xo, Yo; + long jScansPositively,jPointsAreConsecutive; + long i; + + double major, minor, r_eq, r_pol, sat_height; + double lap, lop, orient_angle, angular_size; + double xp, yp, dx, dy, rx, ry, x, y; + double cos_x, cos_y, sin_x, sin_y; + double factor_1, factor_2, tmp1, Sd, Sn, Sxy, S1, S2, S3; + int x0, y0, ix, iy; + double *s_x, *c_x; + grib_iterator_space_view* self = (grib_iterator_space_view*)iter; const char* sradius = grib_arguments_get_name(h,args,self->carg++); + const char* sEarthIsOblate = grib_arguments_get_name(h,args,self->carg++); + const char* sMajorAxisInMetres = grib_arguments_get_name(h,args,self->carg++); + const char* sMinorAxisInMetres = grib_arguments_get_name(h,args,self->carg++); const char* snx = grib_arguments_get_name(h,args,self->carg++); const char* sny = grib_arguments_get_name(h,args,self->carg++); const char* sLatOfSubSatellitePointInDegrees = grib_arguments_get_name(h,args,self->carg++); @@ -128,7 +135,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) const char* sXpInGridLengths = grib_arguments_get_name(h,args,self->carg++); const char* sYpInGridLengths = grib_arguments_get_name(h,args,self->carg++); const char* sOrientationInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sNr = grib_arguments_get_name(h,args,self->carg++); + const char* sNrInRadiusOfEarth = grib_arguments_get_name(h,args,self->carg++); const char* sXo = grib_arguments_get_name(h,args,self->carg++); const char* sYo = grib_arguments_get_name(h,args,self->carg++); @@ -136,16 +143,24 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); - double c,rho; - sinphi1 = cosphi1 = 0.0; - if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) - return ret; if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) return ret; if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) return ret; + if((ret = grib_get_long_internal(h, sEarthIsOblate, &earthIsOblate)) != GRIB_SUCCESS) + return ret; + if (earthIsOblate) { + if((ret = grib_get_double_internal(h, sMajorAxisInMetres, &major)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sMinorAxisInMetres, &minor)) != GRIB_SUCCESS) + return ret; + } else { + if((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) + return ret; + } + if (iter->nv!=nx*ny) { grib_context_log(h->context,GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv,nx,ny); return GRIB_WRONG_GRID; @@ -154,9 +169,9 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) return ret; if((ret = grib_get_double_internal(h, sLonOfSubSatellitePointInDegrees,&lonOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sDx,&Dx)) != GRIB_SUCCESS) + if((ret = grib_get_double_internal(h, sDx, &dx)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sDy,&Dy)) != GRIB_SUCCESS) + if((ret = grib_get_double_internal(h, sDy, &dy)) != GRIB_SUCCESS) return ret; if((ret = grib_get_double_internal(h, sXpInGridLengths,&xpInGridLengths)) != GRIB_SUCCESS) return ret; @@ -164,7 +179,12 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) return ret; if((ret = grib_get_double_internal(h, sOrientationInDegrees,&orientationInDegrees)) != GRIB_SUCCESS) return ret; - + if((ret = grib_get_double_internal(h, sNrInRadiusOfEarth,&nrInRadiusOfEarth)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sXo,&Xo)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sYo,&Yo)) != GRIB_SUCCESS) + return ret; if((ret = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) != GRIB_SUCCESS) return ret; if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) != GRIB_SUCCESS) @@ -174,15 +194,38 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) if((ret = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) != GRIB_SUCCESS) return ret; - standardParallel = (southPoleOnPlane == 1) ? -90 : +90; - sinphi1 = sin(standardParallel*DEG2RAD); - cosphi1 = cos(standardParallel*DEG2RAD); - lambda0 = centralLongitude*DEG2RAD; - latFirst= latFirstInDegrees*DEG2RAD; - lonFirst= lonFirstInDegrees*DEG2RAD; - - Dx = iScansNegatively == 0 ? Dx : -Dx; - Dy = jScansPositively == 1 ? Dy : -Dy; + if (earthIsOblate) { + r_eq = major ; /* In m */ + r_pol = minor; + } else { + return GRIB_NOT_IMPLEMENTED; + r_eq = r_pol = radius * 0.001; + } + angular_size = 2.0 * asin(1.0 / nrInRadiusOfEarth); + sat_height = nrInRadiusOfEarth * r_eq; + + lap = latOfSubSatellitePointInDegrees; + lop = lonOfSubSatellitePointInDegrees; + /* apply default scaling factor */ + lap *= 1e-6; + lop *= 1e-6; + lap *= DEG2RAD; + lop *= DEG2RAD; + + orient_angle = orientationInDegrees; + /* apply default scaling factor */ + if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; + + xp = xpInGridLengths; + yp = ypInGridLengths; + x0 = Xo; + y0 = Yo; + + rx = angular_size / dx; + ry = (r_pol/r_eq) * angular_size / dy; + + /*dx = iScansNegatively == 0 ? dx : -dx; + dy = jScansPositively == 1 ? dy : -dy;*/ self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); @@ -196,79 +239,72 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) lats=self->lats; lons=self->lons; - /* compute xFirst,yFirst in metres */ - sinphi=sin(latFirst); - cosphi=cos(latFirst); - cosdlambda=cos(lonFirst-lambda0); - sindlambda=sin(lonFirst-lambda0); - - k = 2.0 * radius / ( 1 + sinphi1*sinphi + cosphi1*cosphi*cosdlambda ); - xFirst = k * cosphi * sindlambda; - yFirst = k * (cosphi1*sinphi - sinphi1*cosphi*cosdlambda); - - /*kp=radius*2.0*tan(pi4-phi/2); - xFirst=kp*cosphi*sindlambda; - yFirst=-kp*cosphi*cosdlambda;*/ - - if (jPointsAreConsecutive) - { - x=xFirst; - for (i=0;i360) *lons -= 360; - lons++; - lats++; - - y+=Dy; - } - x+=Dx; - } + if (!iScansNegatively) { + xp = xp - x0; + } else { + xp = (nx-1) - (xp - x0); + } + if (jScansPositively) { + yp = yp - y0; + } + else { + yp = (ny-1) - (yp - y0); + } + i = 0; + factor_2 = (r_eq/r_pol)*(r_eq/r_pol); + factor_1 = sat_height * sat_height - r_eq * r_eq; + + s_x = (double *) grib_context_malloc(h->context, nx*sizeof(double)); + if (!s_x) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",nx*sizeof(double)); + return GRIB_OUT_OF_MEMORY; } - else - { - y=yFirst; - for (j=0;j360) *lons -= 360; - lons++; - lats++; - - x+=Dx; + c_x = (double *) grib_context_malloc(h->context, nx*sizeof(double)); + if (!c_x) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",nx*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + + for (ix = 0; ix < nx; ix++) { + x = (ix - xp) * rx; + s_x[ix] = sin(x); + c_x[ix] = sqrt(1.0 - s_x[ix]*s_x[ix]); + } + + for (iy = 0; iy < ny; iy++) { + y = (iy - yp) * ry; + sin_y = sin(y); + cos_y = sqrt(1.0 - sin_y*sin_y); + + tmp1 = (1 + (factor_2-1.0)*sin_y*sin_y); + + for (ix = 0; ix < nx; ix++, i++) { + /* x = (ix - xp) * rx; */ + sin_x = s_x[ix]; + cos_x = c_x[ix]; + + Sd = sat_height * cos_x * cos_y; + Sd = Sd * Sd - tmp1*factor_1; + if (Sd <= 0.0) { // outside of view + lats[i] = lons[i] = 0; /* TODO: error? */ + } + else { + Sd = sqrt(Sd); + Sn = (sat_height*cos_x*cos_y - Sd) / tmp1; + S1 = sat_height - Sn * cos_x * cos_y; + S2 = Sn * sin_x * cos_y; + S3 = Sn * sin_y; + Sxy = sqrt(S1*S1 + S2*S2); + lons[i] = atan(S2/S1)*(RAD2DEG) + lop; + lats[i] = atan(factor_2*S3/Sxy)*(RAD2DEG); + /*printf("lat=%g lon=%g\n", lats[i], lons[i]);*/ } - y+=Dy; + /*while (lons[i]<0) lons[i] += 360; + while (lons[i]>360) lons[i] -= 360;*/ } } -#endif + grib_context_free(h->context, s_x); + grib_context_free(h->context, c_x); iter->e = -1; return ret; From 49fd9ac0058aee038d6825b7a8d62f72748979ba Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Thu, 15 Dec 2016 11:09:11 +0000 Subject: [PATCH 014/737] ECC-383: Implement iterator for 'space view'. Alternative impl based on MSGnavigation --- src/grib_iterator_class_space_view.c | 271 ++++++++++++++++++++++++++- 1 file changed, 266 insertions(+), 5 deletions(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 492de37af..a04783dec 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -99,6 +99,260 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +#if 0 +static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) +{ + int ret = GRIB_SUCCESS; + double *lats,*lons; + double latOfSubSatellitePointInDegrees,lonOfSubSatellitePointInDegrees; + double orientationInDegrees, nrInRadiusOfEarth; + double radius=0,xpInGridLengths=0,ypInGridLengths=0; + long nx, ny, earthIsOblate; + long alternativeRowScanning,iScansNegatively; + long Xo, Yo; + long jScansPositively,jPointsAreConsecutive; + long i; + + double major, minor, r_eq, r_pol, sat_height; + double lap, lop, orient_angle, angular_size; + double xp, yp, dx, dy, rx, ry, x, y; + double cos_x, cos_y, sin_x, sin_y; + double factor_1, factor_2, tmp1, Sd, Sn, Sxy, S1, S2, S3; + int x0, y0, ix, iy; + double *s_x, *c_x; + double const1, const2, const3; + + grib_iterator_space_view* self = (grib_iterator_space_view*)iter; + + const char* sradius = grib_arguments_get_name(h,args,self->carg++); + const char* sEarthIsOblate = grib_arguments_get_name(h,args,self->carg++); + const char* sMajorAxisInMetres = grib_arguments_get_name(h,args,self->carg++); + const char* sMinorAxisInMetres = grib_arguments_get_name(h,args,self->carg++); + const char* snx = grib_arguments_get_name(h,args,self->carg++); + const char* sny = grib_arguments_get_name(h,args,self->carg++); + const char* sLatOfSubSatellitePointInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sLonOfSubSatellitePointInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sDx = grib_arguments_get_name(h,args,self->carg++); + const char* sDy = grib_arguments_get_name(h,args,self->carg++); + const char* sXpInGridLengths = grib_arguments_get_name(h,args,self->carg++); + const char* sYpInGridLengths = grib_arguments_get_name(h,args,self->carg++); + const char* sOrientationInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sNrInRadiusOfEarth = grib_arguments_get_name(h,args,self->carg++); + const char* sXo = grib_arguments_get_name(h,args,self->carg++); + const char* sYo = grib_arguments_get_name(h,args,self->carg++); + + const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); + const char* sAlternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); + + if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sEarthIsOblate, &earthIsOblate)) != GRIB_SUCCESS) + return ret; + + if (earthIsOblate) { + if((ret = grib_get_double_internal(h, sMajorAxisInMetres, &major)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sMinorAxisInMetres, &minor)) != GRIB_SUCCESS) + return ret; + } else { + if((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) + return ret; + } + + if (iter->nv!=nx*ny) { + grib_context_log(h->context,GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv,nx,ny); + return GRIB_WRONG_GRID; + } + if((ret = grib_get_double_internal(h, sLatOfSubSatellitePointInDegrees,&latOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sLonOfSubSatellitePointInDegrees,&lonOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sDx, &dx)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sDy, &dy)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sXpInGridLengths,&xpInGridLengths)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sYpInGridLengths,&ypInGridLengths)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_double_internal(h, sOrientationInDegrees,&orientationInDegrees)) != GRIB_SUCCESS) + return ret; + + /* Orthographic not supported. This happens when Nr (camera altitude) is missing */ + if (grib_is_missing(h, sNrInRadiusOfEarth, &ret)) { + grib_context_log(h->context,GRIB_LOG_ERROR, "Orthographic view (Nr missing) not supported"); + return GRIB_NOT_IMPLEMENTED; + } + if((ret = grib_get_double_internal(h, sNrInRadiusOfEarth,&nrInRadiusOfEarth)) != GRIB_SUCCESS) + return ret; + + if((ret = grib_get_long_internal(h, sXo,&Xo)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sYo,&Yo)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) != GRIB_SUCCESS) + return ret; + if((ret = grib_get_long_internal(h, sAlternativeRowScanning,&alternativeRowScanning)) != GRIB_SUCCESS) + return ret; + + if (earthIsOblate) { + r_eq = major; /* In km */ + r_pol = minor; + } else { + r_eq = r_pol = radius * 0.001;/*conv to km*/ + } + + double as = 2 * asin(1.0 / nrInRadiusOfEarth); /* angular_size */ + double cfac = dx / as; + double lfac = dy / as; + // use km, so scale by the earth radius + double scale_factor = (Nr - 1) * majorAxis / 1000; // this sets the units of the projection x,y coords in km + double scale_x = scale_factor; // LOOK fake neg need scan value + double scale_y = -scale_factor; // LOOK fake neg need scan value + + double startx = scale_factor * (1 - Xp) / cfac; + double incrx = scale_factor / cfac; + boolean yscanPositive = GribUtils.scanModeYisPositive(scanMode); + double starty, incry; + if (yscanPositive) { + starty = scale_factor * (Yp - getNy()) / lfac; + incry = (scale_factor / lfac); + } else { + incry = -(scale_factor / lfac); + starty = scale_factor * (Yp - getNy()) / lfac - incry * (getNy() - 1); + } + + //MSGnavigation proj = new MSGnavigation(LaP, LoP, majorAxis, minorAxis, Nr * majorAxis, scale_x, scale_y); + sat_height = nrInRadiusOfEarth * r_eq; /* km */ + const1 = major / minor; + const1 *= const1; + const2 = 1.0 - (minor * minor) / (major * major); + const3 = sat_height * sat_height - major * major; + + + + + + + ///////OLD + angular_size = 2.0 * asin(1.0 / nrInRadiusOfEarth); + sat_height = nrInRadiusOfEarth * r_eq; + + lap = latOfSubSatellitePointInDegrees; + lop = lonOfSubSatellitePointInDegrees; + /* apply default scaling factor */ + lap *= 1e-6; + lop *= 1e-6; + lap *= DEG2RAD; + lop *= DEG2RAD; + + orient_angle = orientationInDegrees; + /* apply default scaling factor */ + if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; + + xp = xpInGridLengths; + yp = ypInGridLengths; + x0 = Xo; + y0 = Yo; + + rx = angular_size / dx; + ry = (r_pol/r_eq) * angular_size / dy; + + /*dx = iScansNegatively == 0 ? dx : -dx; + * dy = jScansPositively == 1 ? dy : -dy;*/ + self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + if (!self->lats) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats=self->lats; + lons=self->lons; + + if (!iScansNegatively) { + xp = xp - x0; + } else { + xp = (nx-1) - (xp - x0); + } + if (jScansPositively) { + yp = yp - y0; + } + else { + yp = (ny-1) - (yp - y0); + } + i = 0; + factor_2 = (r_eq/r_pol)*(r_eq/r_pol); + factor_1 = sat_height * sat_height - r_eq * r_eq; + + s_x = (double *) grib_context_malloc(h->context, nx*sizeof(double)); + if (!s_x) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",nx*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + c_x = (double *) grib_context_malloc(h->context, nx*sizeof(double)); + if (!c_x) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",nx*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + + for (ix = 0; ix < nx; ix++) { + x = (ix - xp) * rx; + s_x[ix] = sin(x); + c_x[ix] = sqrt(1.0 - s_x[ix]*s_x[ix]); + } + + for (iy = 0; iy < ny; iy++) { + y = (iy - yp) * ry; + sin_y = sin(y); + cos_y = sqrt(1.0 - sin_y*sin_y); + + tmp1 = (1 + (factor_2-1.0)*sin_y*sin_y); + + for (ix = 0; ix < nx; ix++, i++) { + /* x = (ix - xp) * rx; */ + sin_x = s_x[ix]; + cos_x = c_x[ix]; + + Sd = sat_height * cos_x * cos_y; + Sd = Sd * Sd - tmp1*factor_1; + if (Sd <= 0.0) { // outside of view + lats[i] = lons[i] = 0; /* TODO: error? */ + } + else { + Sd = sqrt(Sd); + Sn = (sat_height*cos_x*cos_y - Sd) / tmp1; + S1 = sat_height - Sn * cos_x * cos_y; + S2 = Sn * sin_x * cos_y; + S3 = Sn * sin_y; + Sxy = sqrt(S1*S1 + S2*S2); + lons[i] = atan(S2/S1)*(RAD2DEG) + lop; + lats[i] = atan(factor_2*S3/Sxy)*(RAD2DEG); + /*printf("lat=%g lon=%g\n", lats[i], lons[i]);*/ + } + /*while (lons[i]<0) lons[i] += 360; + * while (lons[i]>360) lons[i] -= 360;*/ + } + } + grib_context_free(h->context, s_x); + grib_context_free(h->context, c_x); + iter->e = -1; + + return ret; +} +#endif +#if 1 static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) { int ret=0; @@ -142,7 +396,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); + const char* sAlternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) return ret; @@ -179,8 +433,15 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) return ret; if((ret = grib_get_double_internal(h, sOrientationInDegrees,&orientationInDegrees)) != GRIB_SUCCESS) return ret; + + /* Orthographic not supported. This happens when Nr (camera altitude) is missing */ + if (grib_is_missing(h, sNrInRadiusOfEarth, &ret)) { + grib_context_log(h->context,GRIB_LOG_ERROR, "Orthographic view (Nr missing) not supported"); + return GRIB_NOT_IMPLEMENTED; + } if((ret = grib_get_double_internal(h, sNrInRadiusOfEarth,&nrInRadiusOfEarth)) != GRIB_SUCCESS) return ret; + if((ret = grib_get_long_internal(h, sXo,&Xo)) != GRIB_SUCCESS) return ret; if((ret = grib_get_long_internal(h, sYo,&Yo)) != GRIB_SUCCESS) @@ -191,15 +452,14 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) return ret; if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) != GRIB_SUCCESS) + if((ret = grib_get_long_internal(h, sAlternativeRowScanning,&alternativeRowScanning)) != GRIB_SUCCESS) return ret; if (earthIsOblate) { - r_eq = major ; /* In m */ + r_eq = major; /* In km */ r_pol = minor; } else { - return GRIB_NOT_IMPLEMENTED; - r_eq = r_pol = radius * 0.001; + r_eq = r_pol = radius * 0.001;/*conv to km*/ } angular_size = 2.0 * asin(1.0 / nrInRadiusOfEarth); sat_height = nrInRadiusOfEarth * r_eq; @@ -309,6 +569,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) return ret; } +#endif static int destroy(grib_iterator* i) { From 5346e250deb51d59c04f9ac298c22ec9a74d7490 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 3 Jan 2017 11:03:48 +0000 Subject: [PATCH 015/737] Update copyright notices: 2016 -> 2017 --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 2 +- src/grib_iterator_class_lambert_conformal.c | 2 +- src/grib_iterator_class_polar_stereographic.c | 2 +- src/grib_iterator_class_space_view.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 9cdb6db92..83c321824 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2016 ECMWF. + * Copyright 2005-2017 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. diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index f8c52c2dc..7ebde391f 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2016 ECMWF. + * Copyright 2005-2017 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. diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 7d5744515..e9e3955d9 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2016 ECMWF. + * Copyright 2005-2017 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. diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index a04783dec..43ec6fcb4 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2016 ECMWF. + * Copyright 2005-2017 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. From a7cbece96b934e6229bb3c5727824c012be1df23 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 4 Jan 2017 11:37:39 +0000 Subject: [PATCH 016/737] ECC-383: Implement iterator for 'space view' --- src/grib_iterator_class_space_view.c | 273 +-------------------------- 1 file changed, 9 insertions(+), 264 deletions(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 43ec6fcb4..e086ce28e 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -99,260 +99,6 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ -#if 0 -static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) -{ - int ret = GRIB_SUCCESS; - double *lats,*lons; - double latOfSubSatellitePointInDegrees,lonOfSubSatellitePointInDegrees; - double orientationInDegrees, nrInRadiusOfEarth; - double radius=0,xpInGridLengths=0,ypInGridLengths=0; - long nx, ny, earthIsOblate; - long alternativeRowScanning,iScansNegatively; - long Xo, Yo; - long jScansPositively,jPointsAreConsecutive; - long i; - - double major, minor, r_eq, r_pol, sat_height; - double lap, lop, orient_angle, angular_size; - double xp, yp, dx, dy, rx, ry, x, y; - double cos_x, cos_y, sin_x, sin_y; - double factor_1, factor_2, tmp1, Sd, Sn, Sxy, S1, S2, S3; - int x0, y0, ix, iy; - double *s_x, *c_x; - double const1, const2, const3; - - grib_iterator_space_view* self = (grib_iterator_space_view*)iter; - - const char* sradius = grib_arguments_get_name(h,args,self->carg++); - const char* sEarthIsOblate = grib_arguments_get_name(h,args,self->carg++); - const char* sMajorAxisInMetres = grib_arguments_get_name(h,args,self->carg++); - const char* sMinorAxisInMetres = grib_arguments_get_name(h,args,self->carg++); - const char* snx = grib_arguments_get_name(h,args,self->carg++); - const char* sny = grib_arguments_get_name(h,args,self->carg++); - const char* sLatOfSubSatellitePointInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sLonOfSubSatellitePointInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sDx = grib_arguments_get_name(h,args,self->carg++); - const char* sDy = grib_arguments_get_name(h,args,self->carg++); - const char* sXpInGridLengths = grib_arguments_get_name(h,args,self->carg++); - const char* sYpInGridLengths = grib_arguments_get_name(h,args,self->carg++); - const char* sOrientationInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sNrInRadiusOfEarth = grib_arguments_get_name(h,args,self->carg++); - const char* sXo = grib_arguments_get_name(h,args,self->carg++); - const char* sYo = grib_arguments_get_name(h,args,self->carg++); - - const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); - const char* sAlternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); - - if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sEarthIsOblate, &earthIsOblate)) != GRIB_SUCCESS) - return ret; - - if (earthIsOblate) { - if((ret = grib_get_double_internal(h, sMajorAxisInMetres, &major)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sMinorAxisInMetres, &minor)) != GRIB_SUCCESS) - return ret; - } else { - if((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) - return ret; - } - - if (iter->nv!=nx*ny) { - grib_context_log(h->context,GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv,nx,ny); - return GRIB_WRONG_GRID; - } - if((ret = grib_get_double_internal(h, sLatOfSubSatellitePointInDegrees,&latOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sLonOfSubSatellitePointInDegrees,&lonOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sDx, &dx)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sDy, &dy)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sXpInGridLengths,&xpInGridLengths)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sYpInGridLengths,&ypInGridLengths)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sOrientationInDegrees,&orientationInDegrees)) != GRIB_SUCCESS) - return ret; - - /* Orthographic not supported. This happens when Nr (camera altitude) is missing */ - if (grib_is_missing(h, sNrInRadiusOfEarth, &ret)) { - grib_context_log(h->context,GRIB_LOG_ERROR, "Orthographic view (Nr missing) not supported"); - return GRIB_NOT_IMPLEMENTED; - } - if((ret = grib_get_double_internal(h, sNrInRadiusOfEarth,&nrInRadiusOfEarth)) != GRIB_SUCCESS) - return ret; - - if((ret = grib_get_long_internal(h, sXo,&Xo)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sYo,&Yo)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sAlternativeRowScanning,&alternativeRowScanning)) != GRIB_SUCCESS) - return ret; - - if (earthIsOblate) { - r_eq = major; /* In km */ - r_pol = minor; - } else { - r_eq = r_pol = radius * 0.001;/*conv to km*/ - } - - double as = 2 * asin(1.0 / nrInRadiusOfEarth); /* angular_size */ - double cfac = dx / as; - double lfac = dy / as; - // use km, so scale by the earth radius - double scale_factor = (Nr - 1) * majorAxis / 1000; // this sets the units of the projection x,y coords in km - double scale_x = scale_factor; // LOOK fake neg need scan value - double scale_y = -scale_factor; // LOOK fake neg need scan value - - double startx = scale_factor * (1 - Xp) / cfac; - double incrx = scale_factor / cfac; - boolean yscanPositive = GribUtils.scanModeYisPositive(scanMode); - double starty, incry; - if (yscanPositive) { - starty = scale_factor * (Yp - getNy()) / lfac; - incry = (scale_factor / lfac); - } else { - incry = -(scale_factor / lfac); - starty = scale_factor * (Yp - getNy()) / lfac - incry * (getNy() - 1); - } - - //MSGnavigation proj = new MSGnavigation(LaP, LoP, majorAxis, minorAxis, Nr * majorAxis, scale_x, scale_y); - sat_height = nrInRadiusOfEarth * r_eq; /* km */ - const1 = major / minor; - const1 *= const1; - const2 = 1.0 - (minor * minor) / (major * major); - const3 = sat_height * sat_height - major * major; - - - - - - - ///////OLD - angular_size = 2.0 * asin(1.0 / nrInRadiusOfEarth); - sat_height = nrInRadiusOfEarth * r_eq; - - lap = latOfSubSatellitePointInDegrees; - lop = lonOfSubSatellitePointInDegrees; - /* apply default scaling factor */ - lap *= 1e-6; - lop *= 1e-6; - lap *= DEG2RAD; - lop *= DEG2RAD; - - orient_angle = orientationInDegrees; - /* apply default scaling factor */ - if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; - - xp = xpInGridLengths; - yp = ypInGridLengths; - x0 = Xo; - y0 = Yo; - - rx = angular_size / dx; - ry = (r_pol/r_eq) * angular_size / dy; - - /*dx = iScansNegatively == 0 ? dx : -dx; - * dy = jScansPositively == 1 ? dy : -dy;*/ - self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); - if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); - if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - lats=self->lats; - lons=self->lons; - - if (!iScansNegatively) { - xp = xp - x0; - } else { - xp = (nx-1) - (xp - x0); - } - if (jScansPositively) { - yp = yp - y0; - } - else { - yp = (ny-1) - (yp - y0); - } - i = 0; - factor_2 = (r_eq/r_pol)*(r_eq/r_pol); - factor_1 = sat_height * sat_height - r_eq * r_eq; - - s_x = (double *) grib_context_malloc(h->context, nx*sizeof(double)); - if (!s_x) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",nx*sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - c_x = (double *) grib_context_malloc(h->context, nx*sizeof(double)); - if (!c_x) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",nx*sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - - for (ix = 0; ix < nx; ix++) { - x = (ix - xp) * rx; - s_x[ix] = sin(x); - c_x[ix] = sqrt(1.0 - s_x[ix]*s_x[ix]); - } - - for (iy = 0; iy < ny; iy++) { - y = (iy - yp) * ry; - sin_y = sin(y); - cos_y = sqrt(1.0 - sin_y*sin_y); - - tmp1 = (1 + (factor_2-1.0)*sin_y*sin_y); - - for (ix = 0; ix < nx; ix++, i++) { - /* x = (ix - xp) * rx; */ - sin_x = s_x[ix]; - cos_x = c_x[ix]; - - Sd = sat_height * cos_x * cos_y; - Sd = Sd * Sd - tmp1*factor_1; - if (Sd <= 0.0) { // outside of view - lats[i] = lons[i] = 0; /* TODO: error? */ - } - else { - Sd = sqrt(Sd); - Sn = (sat_height*cos_x*cos_y - Sd) / tmp1; - S1 = sat_height - Sn * cos_x * cos_y; - S2 = Sn * sin_x * cos_y; - S3 = Sn * sin_y; - Sxy = sqrt(S1*S1 + S2*S2); - lons[i] = atan(S2/S1)*(RAD2DEG) + lop; - lats[i] = atan(factor_2*S3/Sxy)*(RAD2DEG); - /*printf("lat=%g lon=%g\n", lats[i], lons[i]);*/ - } - /*while (lons[i]<0) lons[i] += 360; - * while (lons[i]>360) lons[i] -= 360;*/ - } - } - grib_context_free(h->context, s_x); - grib_context_free(h->context, c_x); - iter->e = -1; - - return ret; -} -#endif -#if 1 static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) { int ret=0; @@ -484,8 +230,6 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) rx = angular_size / dx; ry = (r_pol/r_eq) * angular_size / dy; - /*dx = iScansNegatively == 0 ? dx : -dx; - dy = jScansPositively == 1 ? dy : -dy;*/ self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); @@ -525,13 +269,15 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) return GRIB_OUT_OF_MEMORY; } + /* Store results of sin/cos to avoid recalculation */ for (ix = 0; ix < nx; ix++) { x = (ix - xp) * rx; s_x[ix] = sin(x); c_x[ix] = sqrt(1.0 - s_x[ix]*s_x[ix]); } - for (iy = 0; iy < ny; iy++) { + /*for (iy = 0; iy < ny; iy++) {*/ + for (iy = ny-1; iy >= 0; --iy) { y = (iy - yp) * ry; sin_y = sin(y); cos_y = sqrt(1.0 - sin_y*sin_y); @@ -539,9 +285,9 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) tmp1 = (1 + (factor_2-1.0)*sin_y*sin_y); for (ix = 0; ix < nx; ix++, i++) { - /* x = (ix - xp) * rx; */ - sin_x = s_x[ix]; - cos_x = c_x[ix]; + /*x = (ix - xp) * rx;*/ + /* Use sin/cos previously computed */ + sin_x = s_x[ix]; cos_x = c_x[ix]; Sd = sat_height * cos_x * cos_y; Sd = Sd * Sd - tmp1*factor_1; @@ -557,10 +303,10 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) Sxy = sqrt(S1*S1 + S2*S2); lons[i] = atan(S2/S1)*(RAD2DEG) + lop; lats[i] = atan(factor_2*S3/Sxy)*(RAD2DEG); - /*printf("lat=%g lon=%g\n", lats[i], lons[i]);*/ + /*fprintf(stderr, "lat=%g lon=%g\n", lats[i], lons[i]);*/ } - /*while (lons[i]<0) lons[i] += 360; - while (lons[i]>360) lons[i] -= 360;*/ + while (lons[i]<0) lons[i] += 360; + while (lons[i]>360) lons[i] -= 360; } } grib_context_free(h->context, s_x); @@ -569,7 +315,6 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) return ret; } -#endif static int destroy(grib_iterator* i) { From 201fb43ccc20ae3cba6c0b44270c46bf64391b2d Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 4 Jan 2017 14:23:38 +0000 Subject: [PATCH 017/737] ECC-383: Clean up --- src/grib_iterator_class_space_view.c | 40 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index e086ce28e..9d4fa7859 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -101,31 +101,32 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) { - int ret=0; - double *lats,*lons; + /* REFERENCE: + * LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) + */ + int ret = GRIB_SUCCESS; + double *lats,*lons; /* arrays of latitudes and longitudes */ double latOfSubSatellitePointInDegrees,lonOfSubSatellitePointInDegrees; double orientationInDegrees, nrInRadiusOfEarth; double radius=0,xpInGridLengths=0,ypInGridLengths=0; - long nx, ny, earthIsOblate; + long nx, ny, earthIsOblate=0; long alternativeRowScanning,iScansNegatively; - long Xo, Yo; - long jScansPositively,jPointsAreConsecutive; - long i; + long Xo, Yo, jScansPositively,jPointsAreConsecutive, i; - double major, minor, r_eq, r_pol, sat_height; + double major, minor, r_eq, r_pol, height; double lap, lop, orient_angle, angular_size; double xp, yp, dx, dy, rx, ry, x, y; double cos_x, cos_y, sin_x, sin_y; double factor_1, factor_2, tmp1, Sd, Sn, Sxy, S1, S2, S3; int x0, y0, ix, iy; - double *s_x, *c_x; + double *s_x, *c_x; /* arrays storing sin and cos values */ grib_iterator_space_view* self = (grib_iterator_space_view*)iter; const char* sradius = grib_arguments_get_name(h,args,self->carg++); const char* sEarthIsOblate = grib_arguments_get_name(h,args,self->carg++); - const char* sMajorAxisInMetres = grib_arguments_get_name(h,args,self->carg++); - const char* sMinorAxisInMetres = grib_arguments_get_name(h,args,self->carg++); + const char* sMajorAxisInMetres = grib_arguments_get_name(h,args,self->carg++); + const char* sMinorAxisInMetres = grib_arguments_get_name(h,args,self->carg++); const char* snx = grib_arguments_get_name(h,args,self->carg++); const char* sny = grib_arguments_get_name(h,args,self->carg++); const char* sLatOfSubSatellitePointInDegrees = grib_arguments_get_name(h,args,self->carg++); @@ -136,8 +137,8 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) const char* sYpInGridLengths = grib_arguments_get_name(h,args,self->carg++); const char* sOrientationInDegrees = grib_arguments_get_name(h,args,self->carg++); const char* sNrInRadiusOfEarth = grib_arguments_get_name(h,args,self->carg++); - const char* sXo = grib_arguments_get_name(h,args,self->carg++); - const char* sYo = grib_arguments_get_name(h,args,self->carg++); + const char* sXo = grib_arguments_get_name(h,args,self->carg++); + const char* sYo = grib_arguments_get_name(h,args,self->carg++); const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); @@ -208,12 +209,11 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) r_eq = r_pol = radius * 0.001;/*conv to km*/ } angular_size = 2.0 * asin(1.0 / nrInRadiusOfEarth); - sat_height = nrInRadiusOfEarth * r_eq; + height = nrInRadiusOfEarth * r_eq; lap = latOfSubSatellitePointInDegrees; lop = lonOfSubSatellitePointInDegrees; - /* apply default scaling factor */ - lap *= 1e-6; + lap *= 1e-6; /* default scaling factor */ lop *= 1e-6; lap *= DEG2RAD; lop *= DEG2RAD; @@ -256,8 +256,9 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) } i = 0; factor_2 = (r_eq/r_pol)*(r_eq/r_pol); - factor_1 = sat_height * sat_height - r_eq * r_eq; + factor_1 = height * height - r_eq * r_eq; + /* Store array of sin and cosine values to avoid recalculation */ s_x = (double *) grib_context_malloc(h->context, nx*sizeof(double)); if (!s_x) { grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",nx*sizeof(double)); @@ -269,7 +270,6 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) return GRIB_OUT_OF_MEMORY; } - /* Store results of sin/cos to avoid recalculation */ for (ix = 0; ix < nx; ix++) { x = (ix - xp) * rx; s_x[ix] = sin(x); @@ -289,15 +289,15 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) /* Use sin/cos previously computed */ sin_x = s_x[ix]; cos_x = c_x[ix]; - Sd = sat_height * cos_x * cos_y; + Sd = height * cos_x * cos_y; Sd = Sd * Sd - tmp1*factor_1; if (Sd <= 0.0) { // outside of view lats[i] = lons[i] = 0; /* TODO: error? */ } else { Sd = sqrt(Sd); - Sn = (sat_height*cos_x*cos_y - Sd) / tmp1; - S1 = sat_height - Sn * cos_x * cos_y; + Sn = (height*cos_x*cos_y - Sd) / tmp1; + S1 = height - Sn * cos_x * cos_y; S2 = Sn * sin_x * cos_y; S3 = Sn * sin_y; Sxy = sqrt(S1*S1 + S2*S2); From ee2676e0e4758166021b2b861a3e13812d859a2a Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 4 Jan 2017 14:29:15 +0000 Subject: [PATCH 018/737] ECC-383: latitude of sub-satellite point should be zero --- src/grib_iterator_class_space_view.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 9d4fa7859..9e8d0249a 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -215,11 +215,11 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) lop = lonOfSubSatellitePointInDegrees; lap *= 1e-6; /* default scaling factor */ lop *= 1e-6; + if (lap != 0.0) return GRIB_NOT_IMPLEMENTED; lap *= DEG2RAD; lop *= DEG2RAD; orient_angle = orientationInDegrees; - /* apply default scaling factor */ if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; xp = xpInGridLengths; From a6edf594cb4f9060a8ed7664d8f8d535b60e8b1d Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 4 Jan 2017 17:16:49 +0000 Subject: [PATCH 019/737] Cleanup --- src/grib_iterator_class_space_view.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 9e8d0249a..9e15ed48b 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -99,7 +99,7 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ -static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { /* REFERENCE: * LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) @@ -120,6 +120,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) double factor_1, factor_2, tmp1, Sd, Sn, Sxy, S1, S2, S3; int x0, y0, ix, iy; double *s_x, *c_x; /* arrays storing sin and cos values */ + size_t array_size = (iter->nv * sizeof(double)); grib_iterator_space_view* self = (grib_iterator_space_view*)iter; @@ -230,14 +231,14 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) rx = angular_size / dx; ry = (r_pol/r_eq) * angular_size / dy; - self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lats = (double*)grib_context_malloc(h->context, array_size); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes", array_size); return GRIB_OUT_OF_MEMORY; } - self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lons = (double*)grib_context_malloc(h->context, array_size); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes", array_size); return GRIB_OUT_OF_MEMORY; } lats=self->lats; From 61e724a3f2d4e14b7204dd02a0e2adb5debf5e4c Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 2 May 2017 17:59:04 +0100 Subject: [PATCH 020/737] Compiler warnings --- src/grib_iterator_class_space_view.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 9e15ed48b..218942f98 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -292,7 +292,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) Sd = height * cos_x * cos_y; Sd = Sd * Sd - tmp1*factor_1; - if (Sd <= 0.0) { // outside of view + if (Sd <= 0.0) { /* outside of view */ lats[i] = lons[i] = 0; /* TODO: error? */ } else { From 69734a7d5e1920e82b830e3a67aeab2cbdc27c36 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Mon, 14 Aug 2017 16:49:50 +0100 Subject: [PATCH 021/737] ECC-521: grib_get_data for Lambert Conformal: incorrect if adjacent rows scan in the opposite direction --- src/grib_iterator_class_lambert_conformal.c | 183 ++++++++++++++------ 1 file changed, 134 insertions(+), 49 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 7ebde391f..f03416e93 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -83,17 +83,17 @@ static void init_class(grib_iterator_class* c) static int next(grib_iterator* i, double *lat, double *lon, double *val) { - grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; + grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; - if((long)i->e >= (long)(i->nv-1)) - return 0; - i->e++; + if((long)i->e >= (long)(i->nv-1)) + return 0; + i->e++; - *lat = self->lats[i->e]; - *lon = self->lons[i->e]; - *val = i->data[i->e]; + *lat = self->lats[i->e]; + *lon = self->lons[i->e]; + *val = i->data[i->e]; - return 1; + return 1; } #ifndef M_PI @@ -111,9 +111,90 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +/* + * Return pointer to data at (i,j) (Fortran convention) + */ +static double* pointer_to_data(unsigned int i, unsigned int j, + long iScansNegatively, long jScansPositively, long jPointsAreConsecutive, long alternativeRowScanning, + unsigned int nx, unsigned int ny, double *data) +{ + /* Regular grid */ + if (nx > 0 && ny > 0) { + if (i >= nx || j >= ny) return NULL; + j = (jScansPositively) ? j : ny - 1 - j; + i = ((alternativeRowScanning) && (j % 2 == 1)) ? nx - 1 - i : i; + i = (iScansNegatively) ? nx - 1 - i : i; + + return (jPointsAreConsecutive) ? data + j + i*ny : data + i + nx*j; + } + + /* Reduced or other data not on a grid */ + Assert(0); + return NULL; +} + +static int transform_data(grib_handle* h, double* data, + long iScansNegatively, long jScansPositively, long jPointsAreConsecutive, long alternativeRowScanning, + size_t numPoints, long nx, long ny) +{ + double* data2; + double *pData0, *pData1, *pData2; + unsigned long ix, iy; + + if ( !iScansNegatively && jScansPositively && !jPointsAreConsecutive && !alternativeRowScanning ) + { + /* Already +i and +j. No need to change */ + return GRIB_SUCCESS; + } +#if 0 + if ( !iScansNegatively && !jScansPositively && !jPointsAreConsecutive && !alternativeRowScanning && + nx > 0 && ny > 0) + { + /* regular grid +i -j: convert from we:ns to we:sn */ + size_t row_size = ((size_t) nx) * sizeof(double); + data2 = (double*)grib_context_malloc(h->context, row_size); + if (!data2) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes", row_size); + return GRIB_OUT_OF_MEMORY; + } + for (iy = 0; iy < ny/2; iy++) { + memcpy(data2, data + ((size_t) iy) * nx, row_size); + memcpy(data + iy*nx, data + (ny-1-iy) * ((size_t) nx), row_size); + memcpy(data + (ny-1-iy) * ((size_t) nx), data2, row_size); + } + grib_context_free(h->context, data2); + return GRIB_SUCCESS; + } +#endif + if (nx < 1 || ny < 1) { + grib_context_log(h->context,GRIB_LOG_ERROR, "Invalid values for Nx and/or Ny"); + return GRIB_GEOCALCULUS_PROBLEM; + } + data2 = (double*)grib_context_malloc(h->context, numPoints*sizeof(double)); + if (!data2) { + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",numPoints*sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + pData0 = data2; + for (iy = 0; iy < ny; iy++) { + long deltaX = 0; + pData1 = pointer_to_data(0, iy, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, nx,ny, data); + pData2 = pointer_to_data(1, iy, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, nx,ny, data); + deltaX = pData2 - pData1; + for (ix = 0; ix < nx; ix++) { + *pData0++ = *pData1; + pData1 += deltaX; + } + } + memcpy(data, data2, ((size_t)numPoints) * sizeof(double)); + grib_context_free(h->context, data2); + + return GRIB_SUCCESS; +} + static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) { - int i, j, ret=0; + int i, j, err=0; double *lats, *lons; /* the lat/lon arrays to be populated */ long nx,ny,iScansNegatively,jScansPositively,jPointsAreConsecutive,alternativeRowScanning; double LoVInDegrees,LaDInDegrees,Latin1InDegrees,Latin2InDegrees,latFirstInDegrees, @@ -141,41 +222,41 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); - if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) - return ret; + if((err = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) + return err; + if((err = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) + return err; if (iter->nv!=nx*ny) { grib_context_log(h->context,GRIB_LOG_ERROR,"Wrong number of points (%ld!=%ldx%ld)",iter->nv,nx,ny); return GRIB_WRONG_GRID; } - if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sLoVInDegrees, &LoVInDegrees))!=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sLaDInDegrees, &LaDInDegrees))!=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sLatin1InDegrees, &Latin1InDegrees))!=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sLatin2InDegrees, &Latin2InDegrees))!=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sDx,&Dx)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_double_internal(h, sDy,&Dy)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) !=GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) !=GRIB_SUCCESS) - return ret; + if((err = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) + return err; + if((err = grib_get_double_internal(h, sLoVInDegrees, &LoVInDegrees))!=GRIB_SUCCESS) + return err; + if((err = grib_get_double_internal(h, sLaDInDegrees, &LaDInDegrees))!=GRIB_SUCCESS) + return err; + if((err = grib_get_double_internal(h, sLatin1InDegrees, &Latin1InDegrees))!=GRIB_SUCCESS) + return err; + if((err = grib_get_double_internal(h, sLatin2InDegrees, &Latin2InDegrees))!=GRIB_SUCCESS) + return err; + if((err = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) !=GRIB_SUCCESS) + return err; + if((err = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) !=GRIB_SUCCESS) + return err; + if((err = grib_get_double_internal(h, sDx,&Dx)) !=GRIB_SUCCESS) + return err; + if((err = grib_get_double_internal(h, sDy,&Dy)) !=GRIB_SUCCESS) + return err; + if((err = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) !=GRIB_SUCCESS) + return err; + if((err = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) !=GRIB_SUCCESS) + return err; + if((err = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) !=GRIB_SUCCESS) + return err; + if((err = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) !=GRIB_SUCCESS) + return err; /* See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html */ latFirstInRadians = latFirstInDegrees * DEG2RAD; @@ -206,25 +287,19 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) angle = n * lonDiff; x0 = rho * sin(angle); y0 = rho0 - rho * cos(angle); - Dx = iScansNegatively == 0 ? Dx : -Dx; + /*Dx = iScansNegatively == 0 ? Dx : -Dx;*/ /* GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint */ /*Dy = jScansPositively == 1 ? Dy : -Dy;*/ - /* No support (yet) for jPointsAreConsecutive */ - if (jPointsAreConsecutive) { - grib_context_log(h->context,GRIB_LOG_ERROR,"No support for: 'Adjacent points in j (y) direction being consecutive'"); - Assert(0); - } - /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); return GRIB_OUT_OF_MEMORY; } lats=self->lats; @@ -259,7 +334,17 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) iter->e = -1; - return ret; + if (alternativeRowScanning || jPointsAreConsecutive) { + /* TODO: Test this thoroughly for all scanning modes. + * For now we transform the data array only for the specific + * cases of alternativeRowScanning or jPointsAreConsecutive + */ + err = transform_data(h, iter->data, + iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, + iter->nv, nx, ny); + if (err) return err; + } + return err; } static int destroy(grib_iterator* i) From 8d0053a2d28ad13b30c883b635cb4884bc17b1b3 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Mon, 14 Aug 2017 17:25:56 +0100 Subject: [PATCH 022/737] ECC-521: grib_get_data for Lambert Conformal: incorrect if adjacent rows scan in the opposite direction --- src/grib_iterator_class_lambert_conformal.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index f03416e93..c04a42042 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -146,7 +146,7 @@ static int transform_data(grib_handle* h, double* data, /* Already +i and +j. No need to change */ return GRIB_SUCCESS; } -#if 0 + if ( !iScansNegatively && !jScansPositively && !jPointsAreConsecutive && !alternativeRowScanning && nx > 0 && ny > 0) { @@ -165,7 +165,7 @@ static int transform_data(grib_handle* h, double* data, grib_context_free(h->context, data2); return GRIB_SUCCESS; } -#endif + if (nx < 1 || ny < 1) { grib_context_log(h->context,GRIB_LOG_ERROR, "Invalid values for Nx and/or Ny"); return GRIB_GEOCALCULUS_PROBLEM; @@ -334,16 +334,11 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) iter->e = -1; - if (alternativeRowScanning || jPointsAreConsecutive) { - /* TODO: Test this thoroughly for all scanning modes. - * For now we transform the data array only for the specific - * cases of alternativeRowScanning or jPointsAreConsecutive - */ - err = transform_data(h, iter->data, - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, - iter->nv, nx, ny); - if (err) return err; - } + err = transform_data(h, iter->data, + iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, + iter->nv, nx, ny); + if (err) return err; + return err; } From 6010059553c7b2aac179015647c450515d4e314a Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 15 Aug 2017 10:01:55 +0100 Subject: [PATCH 023/737] ECC-521: clean up --- src/grib_iterator_class_lambert_conformal.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index c04a42042..f5711a8cb 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -129,7 +129,6 @@ static double* pointer_to_data(unsigned int i, unsigned int j, } /* Reduced or other data not on a grid */ - Assert(0); return NULL; } @@ -154,7 +153,7 @@ static int transform_data(grib_handle* h, double* data, size_t row_size = ((size_t) nx) * sizeof(double); data2 = (double*)grib_context_malloc(h->context, row_size); if (!data2) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes", row_size); + grib_context_log(h->context,GRIB_LOG_ERROR, "Unable to allocate %ld bytes", row_size); return GRIB_OUT_OF_MEMORY; } for (iy = 0; iy < ny/2; iy++) { @@ -172,14 +171,16 @@ static int transform_data(grib_handle* h, double* data, } data2 = (double*)grib_context_malloc(h->context, numPoints*sizeof(double)); if (!data2) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",numPoints*sizeof(double)); + grib_context_log(h->context,GRIB_LOG_ERROR, "Unable to allocate %ld bytes",numPoints*sizeof(double)); return GRIB_OUT_OF_MEMORY; } pData0 = data2; for (iy = 0; iy < ny; iy++) { long deltaX = 0; pData1 = pointer_to_data(0, iy, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, nx,ny, data); + if (!pData1) return GRIB_GEOCALCULUS_PROBLEM; pData2 = pointer_to_data(1, iy, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, nx,ny, data); + if (!pData2) return GRIB_GEOCALCULUS_PROBLEM; deltaX = pData2 - pData1; for (ix = 0; ix < nx; ix++) { *pData0++ = *pData1; @@ -294,12 +295,12 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + grib_context_log(h->context,GRIB_LOG_ERROR, "Unable to allocate %ld bytes",iter->nv*sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + grib_context_log(h->context,GRIB_LOG_ERROR, "Unable to allocate %ld bytes",iter->nv*sizeof(double)); return GRIB_OUT_OF_MEMORY; } lats=self->lats; @@ -334,6 +335,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) iter->e = -1; + /* Apply the scanning mode flags which may require data array to be transformed */ err = transform_data(h, iter->data, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, iter->nv, nx, ny); From 6ff1c9e6d2bf428c3551e603767558739f2a258c Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 15 Aug 2017 13:56:20 +0100 Subject: [PATCH 024/737] ECC-521: Refactoring --- src/grib_iterator_class_lambert_conformal.c | 86 +-------------------- 1 file changed, 2 insertions(+), 84 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index f5711a8cb..228b5ec86 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -111,89 +111,7 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ -/* - * Return pointer to data at (i,j) (Fortran convention) - */ -static double* pointer_to_data(unsigned int i, unsigned int j, - long iScansNegatively, long jScansPositively, long jPointsAreConsecutive, long alternativeRowScanning, - unsigned int nx, unsigned int ny, double *data) -{ - /* Regular grid */ - if (nx > 0 && ny > 0) { - if (i >= nx || j >= ny) return NULL; - j = (jScansPositively) ? j : ny - 1 - j; - i = ((alternativeRowScanning) && (j % 2 == 1)) ? nx - 1 - i : i; - i = (iScansNegatively) ? nx - 1 - i : i; - - return (jPointsAreConsecutive) ? data + j + i*ny : data + i + nx*j; - } - - /* Reduced or other data not on a grid */ - return NULL; -} - -static int transform_data(grib_handle* h, double* data, - long iScansNegatively, long jScansPositively, long jPointsAreConsecutive, long alternativeRowScanning, - size_t numPoints, long nx, long ny) -{ - double* data2; - double *pData0, *pData1, *pData2; - unsigned long ix, iy; - - if ( !iScansNegatively && jScansPositively && !jPointsAreConsecutive && !alternativeRowScanning ) - { - /* Already +i and +j. No need to change */ - return GRIB_SUCCESS; - } - - if ( !iScansNegatively && !jScansPositively && !jPointsAreConsecutive && !alternativeRowScanning && - nx > 0 && ny > 0) - { - /* regular grid +i -j: convert from we:ns to we:sn */ - size_t row_size = ((size_t) nx) * sizeof(double); - data2 = (double*)grib_context_malloc(h->context, row_size); - if (!data2) { - grib_context_log(h->context,GRIB_LOG_ERROR, "Unable to allocate %ld bytes", row_size); - return GRIB_OUT_OF_MEMORY; - } - for (iy = 0; iy < ny/2; iy++) { - memcpy(data2, data + ((size_t) iy) * nx, row_size); - memcpy(data + iy*nx, data + (ny-1-iy) * ((size_t) nx), row_size); - memcpy(data + (ny-1-iy) * ((size_t) nx), data2, row_size); - } - grib_context_free(h->context, data2); - return GRIB_SUCCESS; - } - - if (nx < 1 || ny < 1) { - grib_context_log(h->context,GRIB_LOG_ERROR, "Invalid values for Nx and/or Ny"); - return GRIB_GEOCALCULUS_PROBLEM; - } - data2 = (double*)grib_context_malloc(h->context, numPoints*sizeof(double)); - if (!data2) { - grib_context_log(h->context,GRIB_LOG_ERROR, "Unable to allocate %ld bytes",numPoints*sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - pData0 = data2; - for (iy = 0; iy < ny; iy++) { - long deltaX = 0; - pData1 = pointer_to_data(0, iy, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, nx,ny, data); - if (!pData1) return GRIB_GEOCALCULUS_PROBLEM; - pData2 = pointer_to_data(1, iy, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, nx,ny, data); - if (!pData2) return GRIB_GEOCALCULUS_PROBLEM; - deltaX = pData2 - pData1; - for (ix = 0; ix < nx; ix++) { - *pData0++ = *pData1; - pData1 += deltaX; - } - } - memcpy(data, data2, ((size_t)numPoints) * sizeof(double)); - grib_context_free(h->context, data2); - - return GRIB_SUCCESS; -} - -static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { int i, j, err=0; double *lats, *lons; /* the lat/lon arrays to be populated */ @@ -336,7 +254,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) iter->e = -1; /* Apply the scanning mode flags which may require data array to be transformed */ - err = transform_data(h, iter->data, + err = transform_iterator_data(h, iter->data, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, iter->nv, nx, ny); if (err) return err; From 927b76b3494d9778661dbea8d43163c17c5f935b Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 16 Aug 2017 14:26:24 +0100 Subject: [PATCH 025/737] ECC-524: grib_iterator behaves strangely for lambert representation --- src/grib_iterator_class_lambert_conformal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 228b5ec86..6e3df8241 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -239,7 +239,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) x = -x; } - angle = atan(x / tmp); + angle = atan2(x, tmp); /* See ECC-524 */ rho = sqrt(x*x + tmp2); if (n <= 0) rho = -rho; lonDeg = LoVInDegrees + (angle/n) * RAD2DEG; @@ -248,6 +248,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) while ( lonDeg < 0.0) lonDeg += 360.0; lons[index] = lonDeg; lats[index] = latDeg; + /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ } } From 7b51154480a2287466b6a0360b049b84fdc478dc Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 18 Aug 2017 18:09:44 +0100 Subject: [PATCH 026/737] GRIB-574 and GRIB-739: Part 1 --- src/grib_iterator_class_polar_stereographic.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index e9e3955d9..24ef7a896 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -104,7 +104,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) int ret=0; double *lats,*lons; double lonFirstInDegrees,latFirstInDegrees,lonFirst,latFirst,radius=0; - long nx,ny,standardParallel,centralLongitude; + long nx,ny,standardParallel,centralLongitude,centralLatitude; double lambda0,xFirst,yFirst,x,y,Dx,Dy; double k,sinphi1,cosphi1; long alternativeRowScanning,iScansNegatively; @@ -122,6 +122,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); const char* ssouthPoleOnPlane = grib_arguments_get_name(h,args,self->carg++); const char* scentralLongitude = grib_arguments_get_name(h,args,self->carg++); + const char* scentralLatitude = grib_arguments_get_name(h,args,self->carg++); const char* sDx = grib_arguments_get_name(h,args,self->carg++); const char* sDy = grib_arguments_get_name(h,args,self->carg++); const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); @@ -150,6 +151,8 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) return ret; if((ret = grib_get_long_internal(h, scentralLongitude,¢ralLongitude)) != GRIB_SUCCESS) return ret; + if((ret = grib_get_long_internal(h, scentralLatitude,¢ralLatitude)) != GRIB_SUCCESS) + return ret; if((ret = grib_get_double_internal(h, sDx,&Dx)) != GRIB_SUCCESS) return ret; if((ret = grib_get_double_internal(h, sDy,&Dy)) != GRIB_SUCCESS) @@ -163,7 +166,8 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) if((ret = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) != GRIB_SUCCESS) return ret; - standardParallel = (southPoleOnPlane == 1) ? -90 : +90; + /*standardParallel = (southPoleOnPlane == 1) ? -90 : +90;*/ + standardParallel = centralLatitude; sinphi1 = sin(standardParallel*DEG2RAD); cosphi1 = cos(standardParallel*DEG2RAD); lambda0 = centralLongitude*DEG2RAD; @@ -191,9 +195,9 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) cosdlambda=cos(lonFirst-lambda0); sindlambda=sin(lonFirst-lambda0); - k = 2.0 * radius / ( 1 + sinphi1*sinphi + cosphi1*cosphi*cosdlambda ); - xFirst = k * cosphi * sindlambda; - yFirst = k * (cosphi1*sinphi - sinphi1*cosphi*cosdlambda); + k = 2.0 / ( 1 + sinphi1*sinphi + cosphi1*cosphi*cosdlambda ); + xFirst = k * radius * cosphi * sindlambda; + yFirst = k * radius * (cosphi1*sinphi - sinphi1*cosphi*cosdlambda); /*kp=radius*2.0*tan(pi4-phi/2); xFirst=kp*cosphi*sindlambda; @@ -234,6 +238,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) for (j=0;j360) *lons -= 360; + /* printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,*lats, index,*lons); */ lons++; lats++; From bf0b8be2ddbc3f5b9672992e761a0ce5d1bcb95f Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Mon, 21 Aug 2017 14:51:55 +0100 Subject: [PATCH 027/737] ECC-529: grib_get_data for polar stereographic gets wrong lat and long --- src/grib_iterator_class_polar_stereographic.c | 177 +++++++++++++----- 1 file changed, 133 insertions(+), 44 deletions(-) diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 24ef7a896..18c807b86 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -96,21 +96,53 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) return 1; } -#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ -#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +/* Data struct for Forward Projection i.e. from lat,lon to x,y */ +typedef struct forward_proj_data { + double centre_lon; /* centre longitude */ + double centre_lat; /* centre latitude */ + double fac; /* sign variable */ + double ind; /* flag variable */ + double mcs; /* small m */ + double tcs; /* small t */ + double false_northing; /* y offset in meters */ + double false_easting; /* x offset in meters */ +} forward_proj_data; + +/* Data struct for Inverse Projection i.e. from x,y to lat,lon */ +typedef struct inverse_proj_data { + double centre_lon; /* centre longitude */ + double centre_lat; /* centre latitude */ + double fac; /* sign variable */ + double ind; /* flag variable */ + double mcs; /* small m */ + double tcs; /* small t */ + double false_northing; /* y offset in meters */ + double false_easting; /* x offset in meters */ +} inverse_proj_data; + +#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ +#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +#define PI_OVER_2 1.5707963267948966 /* half pi */ +#define EPSILON 1.0e-10 static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) { int ret=0; double *lats,*lons; - double lonFirstInDegrees,latFirstInDegrees,lonFirst,latFirst,radius=0; - long nx,ny,standardParallel,centralLongitude,centralLatitude; - double lambda0,xFirst,yFirst,x,y,Dx,Dy; - double k,sinphi1,cosphi1; - long alternativeRowScanning,iScansNegatively; - long jScansPositively,jPointsAreConsecutive, southPoleOnPlane; - double sinphi,cosphi,cosdlambda,sindlambda; - double cosc,sinc; + double lonFirstInDegrees, latFirstInDegrees, radius=0; + long nx,ny,centralLongitudeInDegrees,centralLatitudeInDegrees; + double x, y, Dx, Dy; + long alternativeRowScanning, iScansNegatively; + long jScansPositively, jPointsAreConsecutive, southPoleOnPlane; + double cosphi; + double centralLongitude, centralLatitude; /* in radians */ + double con1; /* temporary angle */ + double con2; /* adjusted latitude */ + double ts; /* value of small t */ + double height; /* height above ellipsoid */ + double x0, y0, lonFirst, latFirst; + forward_proj_data fwd_proj_data = {0,}; + inverse_proj_data inv_proj_data = {0,}; long i,j; grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)iter; @@ -129,15 +161,10 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); - double c,rho; - sinphi1 = cosphi1 = 0.0; - if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) - return ret; - if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) - return ret; + if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) return ret; + if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) return ret; + if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) return ret; if (iter->nv!=nx*ny) { grib_context_log(h->context,GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv,nx,ny); @@ -149,9 +176,9 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) return ret; if((ret = grib_get_long_internal(h, ssouthPoleOnPlane,&southPoleOnPlane)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, scentralLongitude,¢ralLongitude)) != GRIB_SUCCESS) + if((ret = grib_get_long_internal(h, scentralLongitude,¢ralLongitudeInDegrees)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, scentralLatitude,¢ralLatitude)) != GRIB_SUCCESS) + if((ret = grib_get_long_internal(h, scentralLatitude,¢ralLatitudeInDegrees)) != GRIB_SUCCESS) return ret; if((ret = grib_get_double_internal(h, sDx,&Dx)) != GRIB_SUCCESS) return ret; @@ -166,16 +193,56 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) if((ret = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) != GRIB_SUCCESS) return ret; - /*standardParallel = (southPoleOnPlane == 1) ? -90 : +90;*/ - standardParallel = centralLatitude; - sinphi1 = sin(standardParallel*DEG2RAD); - cosphi1 = cos(standardParallel*DEG2RAD); - lambda0 = centralLongitude*DEG2RAD; - latFirst= latFirstInDegrees*DEG2RAD; - lonFirst= lonFirstInDegrees*DEG2RAD; + centralLongitude = centralLongitudeInDegrees * DEG2RAD; + centralLatitude = centralLatitudeInDegrees * DEG2RAD; + lonFirst = lonFirstInDegrees * DEG2RAD; + latFirst = latFirstInDegrees*DEG2RAD; + + /* Forward projection initialisation */ + fwd_proj_data.false_northing = 0; + fwd_proj_data.false_easting = 0; + fwd_proj_data.centre_lon = centralLongitude; + fwd_proj_data.centre_lat = centralLatitude; + if (centralLatitude < 0) fwd_proj_data.fac = -1.0; + else fwd_proj_data.fac = +1.0; + fwd_proj_data.ind = 0; + if (fabs(fabs(centralLatitude) - PI_OVER_2) > EPSILON) { + fwd_proj_data.ind = 1; + con1 = fwd_proj_data.fac * centralLatitude; + cosphi = cos(con1); + fwd_proj_data.mcs = cosphi; + fwd_proj_data.tcs = tan(0.5 * (PI_OVER_2 - con1)); + } - Dx = iScansNegatively == 0 ? Dx : -Dx; - Dy = jScansPositively == 1 ? Dy : -Dy; + /* Forward projection from initial lat,lon to initial x,y */ + con1 = fwd_proj_data.fac * (lonFirst - fwd_proj_data.centre_lon); + con2 = fwd_proj_data.fac * latFirst; + ts = tan(0.5 * (PI_OVER_2 - con2)); + if (fwd_proj_data.ind) + height = radius * fwd_proj_data.mcs * ts / fwd_proj_data.tcs; + else + height = 2.0 * radius * ts; + x0 = fwd_proj_data.fac * height * sin(con1) + fwd_proj_data.false_easting; + y0 = -fwd_proj_data.fac * height * cos(con1) + fwd_proj_data.false_northing; + + x0 = -x0; + y0 = -y0; + + /* Inverse projection initialisation */ + inv_proj_data.false_easting = x0; + inv_proj_data.false_northing= y0; + inv_proj_data.centre_lon = centralLongitude; + inv_proj_data.centre_lat = centralLatitude; + if (centralLatitude < 0) inv_proj_data.fac = -1.0; + else inv_proj_data.fac = +1.0; + inv_proj_data.ind = 0; + if (fabs(fabs(centralLatitude) - PI_OVER_2) > EPSILON) { + inv_proj_data.ind = 1; + con1 = inv_proj_data.fac * inv_proj_data.centre_lat; + cosphi = cos(con1); + inv_proj_data.mcs = cosphi; + inv_proj_data.tcs = tan(0.5 * (PI_OVER_2 - con1)); + } self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); if (!self->lats) { grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); @@ -188,21 +255,43 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) } lats=self->lats; lons=self->lons; + Dx = iScansNegatively == 0 ? Dx : -Dx; + Dy = jScansPositively == 1 ? Dy : -Dy; - /* compute xFirst,yFirst in metres */ - sinphi=sin(latFirst); - cosphi=cos(latFirst); - cosdlambda=cos(lonFirst-lambda0); - sindlambda=sin(lonFirst-lambda0); - - k = 2.0 / ( 1 + sinphi1*sinphi + cosphi1*cosphi*cosdlambda ); - xFirst = k * radius * cosphi * sindlambda; - yFirst = k * radius * (cosphi1*sinphi - sinphi1*cosphi*cosdlambda); - - /*kp=radius*2.0*tan(pi4-phi/2); - xFirst=kp*cosphi*sindlambda; - yFirst=-kp*cosphi*cosdlambda;*/ - + y = 0; + for (j=0;j360) *lons -= 360; + /* printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,*lats, index,*lons); */ + lons++; + lats++; + + x += Dx; + } + y += Dy; + } +#if 0 + /*standardParallel = (southPoleOnPlane == 1) ? -90 : +90;*/ if (jPointsAreConsecutive) { x=xFirst; @@ -254,7 +343,6 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) } while (*lons<0) *lons += 360; while (*lons>360) *lons -= 360; - /* printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,*lats, index,*lons); */ lons++; lats++; @@ -263,6 +351,7 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) y+=Dy; } } +#endif iter->e = -1; return ret; From 16f8410889cf688ff0f677a8842b161bbf33efbe Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 22 Aug 2017 11:39:34 +0100 Subject: [PATCH 028/737] ECC-529: clean up --- src/grib_iterator_class_polar_stereographic.c | 78 +++++++------------ 1 file changed, 30 insertions(+), 48 deletions(-) diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 18c807b86..702d4c5a2 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -96,29 +96,17 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) return 1; } -/* Data struct for Forward Projection i.e. from lat,lon to x,y */ -typedef struct forward_proj_data { - double centre_lon; /* centre longitude */ - double centre_lat; /* centre latitude */ - double fac; /* sign variable */ - double ind; /* flag variable */ - double mcs; /* small m */ - double tcs; /* small t */ - double false_northing; /* y offset in meters */ - double false_easting; /* x offset in meters */ -} forward_proj_data; - -/* Data struct for Inverse Projection i.e. from x,y to lat,lon */ -typedef struct inverse_proj_data { - double centre_lon; /* centre longitude */ - double centre_lat; /* centre latitude */ - double fac; /* sign variable */ +/* Data struct for Forward and Inverse Projections */ +typedef struct proj_data_t { + double centre_lon; /* central longitude */ + double centre_lat; /* central latitude */ + double sign; /* sign variable */ double ind; /* flag variable */ double mcs; /* small m */ double tcs; /* small t */ double false_northing; /* y offset in meters */ double false_easting; /* x offset in meters */ -} inverse_proj_data; +} proj_data_t; #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ @@ -128,22 +116,19 @@ typedef struct inverse_proj_data { static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) { int ret=0; - double *lats,*lons; - double lonFirstInDegrees, latFirstInDegrees, radius=0; - long nx,ny,centralLongitudeInDegrees,centralLatitudeInDegrees; + double *lats, *lons; /* arrays for latitudes and longitudes */ + double lonFirstInDegrees, latFirstInDegrees, radius; double x, y, Dx, Dy; - long alternativeRowScanning, iScansNegatively; + long nx, ny, centralLongitudeInDegrees, centralLatitudeInDegrees; + long alternativeRowScanning, iScansNegatively, i, j; long jScansPositively, jPointsAreConsecutive, southPoleOnPlane; - double cosphi; double centralLongitude, centralLatitude; /* in radians */ double con1; /* temporary angle */ - double con2; /* adjusted latitude */ double ts; /* value of small t */ double height; /* height above ellipsoid */ double x0, y0, lonFirst, latFirst; - forward_proj_data fwd_proj_data = {0,}; - inverse_proj_data inv_proj_data = {0,}; - long i,j; + proj_data_t fwd_proj_data = {0,}; + proj_data_t inv_proj_data = {0,}; grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)iter; @@ -203,27 +188,26 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) fwd_proj_data.false_easting = 0; fwd_proj_data.centre_lon = centralLongitude; fwd_proj_data.centre_lat = centralLatitude; - if (centralLatitude < 0) fwd_proj_data.fac = -1.0; - else fwd_proj_data.fac = +1.0; + if (centralLatitude < 0) fwd_proj_data.sign = -1.0; + else fwd_proj_data.sign = +1.0; fwd_proj_data.ind = 0; if (fabs(fabs(centralLatitude) - PI_OVER_2) > EPSILON) { + /* central latitude different from 90 i.e. not north/south polar */ fwd_proj_data.ind = 1; - con1 = fwd_proj_data.fac * centralLatitude; - cosphi = cos(con1); - fwd_proj_data.mcs = cosphi; + con1 = fwd_proj_data.sign * centralLatitude; + fwd_proj_data.mcs = cos(con1); fwd_proj_data.tcs = tan(0.5 * (PI_OVER_2 - con1)); } /* Forward projection from initial lat,lon to initial x,y */ - con1 = fwd_proj_data.fac * (lonFirst - fwd_proj_data.centre_lon); - con2 = fwd_proj_data.fac * latFirst; - ts = tan(0.5 * (PI_OVER_2 - con2)); + con1 = fwd_proj_data.sign * (lonFirst - fwd_proj_data.centre_lon); + ts = tan(0.5 * (PI_OVER_2 - fwd_proj_data.sign * latFirst)); if (fwd_proj_data.ind) height = radius * fwd_proj_data.mcs * ts / fwd_proj_data.tcs; else height = 2.0 * radius * ts; - x0 = fwd_proj_data.fac * height * sin(con1) + fwd_proj_data.false_easting; - y0 = -fwd_proj_data.fac * height * cos(con1) + fwd_proj_data.false_northing; + x0 = fwd_proj_data.sign * height * sin(con1) + fwd_proj_data.false_easting; + y0 = -fwd_proj_data.sign * height * cos(con1) + fwd_proj_data.false_northing; x0 = -x0; y0 = -y0; @@ -233,14 +217,13 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) inv_proj_data.false_northing= y0; inv_proj_data.centre_lon = centralLongitude; inv_proj_data.centre_lat = centralLatitude; - if (centralLatitude < 0) inv_proj_data.fac = -1.0; - else inv_proj_data.fac = +1.0; + if (centralLatitude < 0) inv_proj_data.sign = -1.0; + else inv_proj_data.sign = +1.0; inv_proj_data.ind = 0; if (fabs(fabs(centralLatitude) - PI_OVER_2) > EPSILON) { inv_proj_data.ind = 1; - con1 = inv_proj_data.fac * inv_proj_data.centre_lat; - cosphi = cos(con1); - inv_proj_data.mcs = cosphi; + con1 = inv_proj_data.sign * inv_proj_data.centre_lat; + inv_proj_data.mcs = cos(con1); inv_proj_data.tcs = tan(0.5 * (PI_OVER_2 - con1)); } self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); @@ -264,25 +247,24 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) for (i=0;i360) *lons -= 360; - /* printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,*lats, index,*lons); */ lons++; lats++; From 6e7d29c25920a2f06abb4df1d615b71adff41ced Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 25 Aug 2017 17:32:07 +0100 Subject: [PATCH 029/737] Clang compiler warnings --- src/grib_iterator_class_space_view.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 218942f98..56e732540 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -113,7 +113,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) long alternativeRowScanning,iScansNegatively; long Xo, Yo, jScansPositively,jPointsAreConsecutive, i; - double major, minor, r_eq, r_pol, height; + double major=0, minor=0, r_eq, r_pol, height; double lap, lop, orient_angle, angular_size; double xp, yp, dx, dy, rx, ry, x, y; double cos_x, cos_y, sin_x, sin_y; From db37185e61fb35b16609b93a7b602eeb004a087f Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 2 Jan 2018 11:31:02 +0000 Subject: [PATCH 030/737] Update copyright notices: 2017 -> 2018 --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 2 +- src/grib_iterator_class_lambert_conformal.c | 2 +- src/grib_iterator_class_polar_stereographic.c | 2 +- src/grib_iterator_class_space_view.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 83c321824..908781808 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2017 ECMWF. + * Copyright 2005-2018 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. diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 6e3df8241..c93f090cd 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2017 ECMWF. + * Copyright 2005-2018 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. diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 702d4c5a2..5afac4021 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2017 ECMWF. + * Copyright 2005-2018 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. diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 56e732540..e57c09b87 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2017 ECMWF. + * Copyright 2005-2018 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. From 8eb0ed988ffa5037b59700c7d938ec4cddcaed23 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 19 Feb 2018 19:53:45 +0000 Subject: [PATCH 031/737] eckit::geometry::Sphere update (Willem, please confirm) --- src/atlas/util/UnitSphere.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/atlas/util/UnitSphere.h diff --git a/src/atlas/util/UnitSphere.h b/src/atlas/util/UnitSphere.h new file mode 100644 index 000000000..3a49f230d --- /dev/null +++ b/src/atlas/util/UnitSphere.h @@ -0,0 +1,27 @@ +/* + * (C) Copyright 1996-2017 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. + */ + +#pragma once + +#include "eckit/geometry/UnitSphere.h" + +//------------------------------------------------------------------------------------------------------ + +namespace atlas { +namespace util { + +//------------------------------------------------------------------------------------------------------ + +using eckit::geometry::UnitSphere; + +//------------------------------------------------------------------------------------------------------ + +} // namespace util +} // namespace atlas From 17c30594219b1cf8130fbad9369b2e59f23fbde1 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Thu, 10 May 2018 16:31:34 +0100 Subject: [PATCH 032/737] Apply clang-format --- src/atlas/util/UnitSphere.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/atlas/util/UnitSphere.h b/src/atlas/util/UnitSphere.h index 3a49f230d..de3889222 100644 --- a/src/atlas/util/UnitSphere.h +++ b/src/atlas/util/UnitSphere.h @@ -23,5 +23,5 @@ using eckit::geometry::UnitSphere; //------------------------------------------------------------------------------------------------------ -} // namespace util -} // namespace atlas +} // namespace util +} // namespace atlas From 08900258f1674f72f9cf5f3a0d97826baa83f417 Mon Sep 17 00:00:00 2001 From: Willem Deconinck Date: Fri, 8 Feb 2019 09:51:27 +0000 Subject: [PATCH 033/737] Add missing license headers --- src/atlas/util/UnitSphere.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/atlas/util/UnitSphere.h b/src/atlas/util/UnitSphere.h index de3889222..c1458468f 100644 --- a/src/atlas/util/UnitSphere.h +++ b/src/atlas/util/UnitSphere.h @@ -1,11 +1,11 @@ /* - * (C) Copyright 1996-2017 ECMWF. + * (C) Copyright 2013 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. + * granted to it by virtue of its status as an intergovernmental organisation + * nor does it submit to any jurisdiction. */ #pragma once From 767f0fc3a9777be8ad084fd226701633d44e0d69 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Mon, 15 Apr 2019 14:44:45 +0100 Subject: [PATCH 034/737] Copyright updated --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 2 +- src/grib_iterator_class_lambert_conformal.c | 2 +- src/grib_iterator_class_polar_stereographic.c | 2 +- src/grib_iterator_class_space_view.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 908781808..3b7365b78 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2018 ECMWF. + * 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. diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index c93f090cd..d8e4ccbb9 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2018 ECMWF. + * 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. diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 5afac4021..11eb2653e 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2018 ECMWF. + * 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. diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index e57c09b87..caf21f9ed 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2018 ECMWF. + * 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. From fe0dd100c445be6b2c01fabf0b615d212c34f8c7 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Thu, 8 Aug 2019 16:37:40 +0100 Subject: [PATCH 035/737] lambert_azimuthal_equal_area: print more user-friendly error message if oblate spheroid --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 3b7365b78..e999ec2f0 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -136,8 +136,13 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) double epsilon=1.0e-20; double d2r=acos(0.0)/90.0; - if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) + if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) { + /* Check if it's an oblate spheroid */ + long oblate=0; + if (grib_get_long(h,"earthIsOblate",&oblate)==GRIB_SUCCESS && oblate==1) + grib_context_log(h->context,GRIB_LOG_ERROR,"Lambert Azimuthal Equal Area only supported for spherical earth."); return ret; + } if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) return ret; if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) From 9bdfe574fab3c27fa12da8ba3d565cdbb6753aaa Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 25 Sep 2019 14:35:43 +0100 Subject: [PATCH 036/737] Refactoring --- src/grib_iterator_class_lambert_conformal.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index d8e4ccbb9..2f01801c4 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -177,7 +177,9 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) if((err = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) !=GRIB_SUCCESS) return err; - /* See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html */ + /* + * See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html + */ latFirstInRadians = latFirstInDegrees * DEG2RAD; lonFirstInRadians = lonFirstInDegrees * DEG2RAD; Latin1InRadians = Latin1InDegrees * DEG2RAD; From e78c5369ac8e44ef7001ba23ab728923809d21bf Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 15 Jan 2020 16:07:14 +0000 Subject: [PATCH 037/737] Geoiterator: Fail if oblate spheroid --- src/grib_iterator_class_lambert_conformal.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 2f01801c4..8161de653 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -116,6 +116,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) int i, j, err=0; double *lats, *lons; /* the lat/lon arrays to be populated */ long nx,ny,iScansNegatively,jScansPositively,jPointsAreConsecutive,alternativeRowScanning; + long oblate=0; double LoVInDegrees,LaDInDegrees,Latin1InDegrees,Latin2InDegrees,latFirstInDegrees, lonFirstInDegrees, Dx, Dy, radius=0; double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, @@ -146,6 +147,11 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) if((err = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) return err; + if(grib_get_long(h, "earthIsOblate", &oblate) == GRIB_SUCCESS && oblate == 1) { + grib_context_log(h->context,GRIB_LOG_ERROR,"Lambert Conformal only supported for spherical earth."); + return GRIB_GEOCALCULUS_PROBLEM; + } + if (iter->nv!=nx*ny) { grib_context_log(h->context,GRIB_LOG_ERROR,"Wrong number of points (%ld!=%ldx%ld)",iter->nv,nx,ny); return GRIB_WRONG_GRID; From 918d2d3d064908063d3c699f6924c58915b40cd8 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 15 Jan 2020 17:56:02 +0000 Subject: [PATCH 038/737] Add helper function for oblate spheroid --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 4 ++-- src/grib_iterator_class_lambert_conformal.c | 3 +-- src/grib_iterator_class_polar_stereographic.c | 5 +++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index e999ec2f0..26af32179 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -138,11 +138,11 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) { /* Check if it's an oblate spheroid */ - long oblate=0; - if (grib_get_long(h,"earthIsOblate",&oblate)==GRIB_SUCCESS && oblate==1) + if (grib_is_earth_oblate(h)) grib_context_log(h->context,GRIB_LOG_ERROR,"Lambert Azimuthal Equal Area only supported for spherical earth."); return ret; } + if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) return ret; if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 8161de653..c3e5e245c 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -116,7 +116,6 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) int i, j, err=0; double *lats, *lons; /* the lat/lon arrays to be populated */ long nx,ny,iScansNegatively,jScansPositively,jPointsAreConsecutive,alternativeRowScanning; - long oblate=0; double LoVInDegrees,LaDInDegrees,Latin1InDegrees,Latin2InDegrees,latFirstInDegrees, lonFirstInDegrees, Dx, Dy, radius=0; double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, @@ -147,7 +146,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) if((err = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) return err; - if(grib_get_long(h, "earthIsOblate", &oblate) == GRIB_SUCCESS && oblate == 1) { + if (grib_is_earth_oblate(h)) { grib_context_log(h->context,GRIB_LOG_ERROR,"Lambert Conformal only supported for spherical earth."); return GRIB_GEOCALCULUS_PROBLEM; } diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 11eb2653e..de2af4f7b 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -151,6 +151,11 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) return ret; if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) return ret; + if (grib_is_earth_oblate(h)) { + grib_context_log(h->context,GRIB_LOG_ERROR,"Polar stereographic only supported for spherical earth."); + return GRIB_GEOCALCULUS_PROBLEM; + } + if (iter->nv!=nx*ny) { grib_context_log(h->context,GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv,nx,ny); return GRIB_WRONG_GRID; From a4aa44a8cb14793ad827a817c92fd85e39f71105 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 22 Jan 2020 13:10:59 +0000 Subject: [PATCH 039/737] Applied clang-format (Part 1) --- ...rator_class_lambert_azimuthal_equal_area.c | 310 +++++++++--------- src/grib_iterator_class_lambert_conformal.c | 231 ++++++------- src/grib_iterator_class_polar_stereographic.c | 252 +++++++------- src/grib_iterator_class_space_view.c | 275 ++++++++-------- 4 files changed, 547 insertions(+), 521 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 26af32179..7566b7c2a 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -41,38 +41,39 @@ or edit "iterator.class" and rerun ./make_class.pl */ -static void init_class (grib_iterator_class*); - -static int init (grib_iterator* i,grib_handle*,grib_arguments*); -static int next (grib_iterator* i, double *lat, double *lon, double *val); -static int destroy (grib_iterator* i); - - -typedef struct grib_iterator_lambert_azimuthal_equal_area{ - grib_iterator it; -/* Members defined in gen */ - long carg; - const char* missingValue; -/* Members defined in lambert_azimuthal_equal_area */ - double *lats; - double *lons; - long nam; +static void init_class(grib_iterator_class*); + +static int init(grib_iterator* i, grib_handle*, grib_arguments*); +static int next(grib_iterator* i, double* lat, double* lon, double* val); +static int destroy(grib_iterator* i); + + +typedef struct grib_iterator_lambert_azimuthal_equal_area +{ + grib_iterator it; + /* Members defined in gen */ + long carg; + const char* missingValue; + /* Members defined in lambert_azimuthal_equal_area */ + double* lats; + double* lons; + long nam; } grib_iterator_lambert_azimuthal_equal_area; extern grib_iterator_class* grib_iterator_class_gen; static grib_iterator_class _grib_iterator_class_lambert_azimuthal_equal_area = { - &grib_iterator_class_gen, /* super */ - "lambert_azimuthal_equal_area", /* name */ - sizeof(grib_iterator_lambert_azimuthal_equal_area),/* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ + &grib_iterator_class_gen, /* super */ + "lambert_azimuthal_equal_area", /* name */ + sizeof(grib_iterator_lambert_azimuthal_equal_area), /* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ }; grib_iterator_class* grib_iterator_class_lambert_azimuthal_equal_area = &_grib_iterator_class_lambert_azimuthal_equal_area; @@ -80,18 +81,17 @@ grib_iterator_class* grib_iterator_class_lambert_azimuthal_equal_area = &_grib_i static void init_class(grib_iterator_class* c) { - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; } /* END_CLASS_IMP */ -static int next(grib_iterator* i, double *lat, double *lon, double *val) +static int next(grib_iterator* i, double* lat, double* lon, double* val) { - grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; - if((long)i->e >= (long)(i->nv-1)) + if ((long)i->e >= (long)(i->nv - 1)) return 0; i->e++; @@ -102,175 +102,169 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) return 1; } -static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { - int ret=0; - double *lats,*lons; - double lonFirstInDegrees,latFirstInDegrees,lonFirst,latFirst,radius=0; - long nx,ny,standardParallel,centralLongitude; - double phi1,lambda0,xFirst,yFirst,x,y,Dx,Dy; - double kp,sinphi1,cosphi1; - long alternativeRowScanning,iScansNegatively; - long jScansPositively,jPointsAreConsecutive; - double sinphi,cosphi,cosdlambda,sindlambda; - double cosc,sinc; - long i,j; + int ret = 0; + double *lats, *lons; + double lonFirstInDegrees, latFirstInDegrees, lonFirst, latFirst, radius = 0; + long nx, ny, standardParallel, centralLongitude; + double phi1, lambda0, xFirst, yFirst, x, y, Dx, Dy; + double kp, sinphi1, cosphi1; + long alternativeRowScanning, iScansNegatively; + long jScansPositively, jPointsAreConsecutive; + double sinphi, cosphi, cosdlambda, sindlambda; + double cosc, sinc; + long i, j; grib_iterator_lambert_azimuthal_equal_area* self = - (grib_iterator_lambert_azimuthal_equal_area*)iter; - - const char* sradius = grib_arguments_get_name(h,args,self->carg++); - const char* snx = grib_arguments_get_name(h,args,self->carg++); - const char* sny = grib_arguments_get_name(h,args,self->carg++); - const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sstandardParallel = grib_arguments_get_name(h,args,self->carg++); - const char* scentralLongitude = grib_arguments_get_name(h,args,self->carg++); - const char* sDx = grib_arguments_get_name(h,args,self->carg++); - const char* sDy = grib_arguments_get_name(h,args,self->carg++); - const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); - double c,rho; - double epsilon=1.0e-20; - double d2r=acos(0.0)/90.0; - - if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) { + (grib_iterator_lambert_azimuthal_equal_area*)iter; + + const char* sradius = grib_arguments_get_name(h, args, self->carg++); + const char* snx = grib_arguments_get_name(h, args, self->carg++); + const char* sny = grib_arguments_get_name(h, args, self->carg++); + const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sstandardParallel = grib_arguments_get_name(h, args, self->carg++); + const char* scentralLongitude = grib_arguments_get_name(h, args, self->carg++); + const char* sDx = grib_arguments_get_name(h, args, self->carg++); + const char* sDy = grib_arguments_get_name(h, args, self->carg++); + const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); + double c, rho; + double epsilon = 1.0e-20; + double d2r = acos(0.0) / 90.0; + + if ((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) { /* Check if it's an oblate spheroid */ if (grib_is_earth_oblate(h)) - grib_context_log(h->context,GRIB_LOG_ERROR,"Lambert Azimuthal Equal Area only supported for spherical earth."); + grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Azimuthal Equal Area only supported for spherical earth."); return ret; } - if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) return ret; - if (iter->nv!=nx*ny) { - grib_context_log(h->context,GRIB_LOG_ERROR, - "Wrong number of points (%ld!=%ldx%ld)", - iter->nv,nx,ny); + if (iter->nv != nx * ny) { + grib_context_log(h->context, GRIB_LOG_ERROR, + "Wrong number of points (%ld!=%ldx%ld)", + iter->nv, nx, ny); return GRIB_WRONG_GRID; } - if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) - != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) - != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, slonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sstandardParallel,&standardParallel)) - != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, sstandardParallel, &standardParallel)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, scentralLongitude,¢ralLongitude)) - != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, scentralLongitude, ¢ralLongitude)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, sDx,&Dx)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sDx, &Dx)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, sDy,&Dy)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sDy, &Dy)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, - sjPointsAreConsecutive,&jPointsAreConsecutive)) - != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, + sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) - != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) - != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, - salternativeRowScanning,&alternativeRowScanning)) - != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, + salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) return ret; - lambda0=d2r*centralLongitude/1000000; - phi1=d2r*standardParallel/1000000; - latFirst=latFirstInDegrees*d2r; - lonFirst=lonFirstInDegrees*d2r; + lambda0 = d2r * centralLongitude / 1000000; + phi1 = d2r * standardParallel / 1000000; + latFirst = latFirstInDegrees * d2r; + lonFirst = lonFirstInDegrees * d2r; - cosphi1=cos(phi1); - sinphi1=sin(phi1); + cosphi1 = cos(phi1); + sinphi1 = sin(phi1); - Dx = iScansNegatively == 0 ? Dx/1000 : -Dx/1000; - Dy = jScansPositively == 1 ? Dy/1000 : -Dy/1000; - self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; + Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; + self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, - "unable to allocate %ld bytes",iter->nv*sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, + "unable to allocate %ld bytes", iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } - self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, - "unable to allocate %ld bytes",iter->nv*sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, + "unable to allocate %ld bytes", iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } - lats=self->lats; - lons=self->lons; + lats = self->lats; + lons = self->lons; /* compute xFirst,yFirst in metres */ - sinphi=sin(latFirst); - cosphi=cos(latFirst); - cosdlambda=cos(lonFirst-lambda0); - sindlambda=sin(lonFirst-lambda0); - kp=radius*sqrt(2.0/(1+sinphi1*sinphi+cosphi1*cosphi*cosdlambda)); - xFirst=kp*cosphi*sindlambda; - yFirst=kp*(cosphi1*sinphi-sinphi1*cosphi*cosdlambda); + sinphi = sin(latFirst); + cosphi = cos(latFirst); + cosdlambda = cos(lonFirst - lambda0); + sindlambda = sin(lonFirst - lambda0); + kp = radius * sqrt(2.0 / (1 + sinphi1 * sinphi + cosphi1 * cosphi * cosdlambda)); + xFirst = kp * cosphi * sindlambda; + yFirst = kp * (cosphi1 * sinphi - sinphi1 * cosphi * cosdlambda); if (jPointsAreConsecutive) { - - x=xFirst; - for (i=0;iepsilon) { - c=2*asin(rho/(2.0*radius)); - cosc=cos(c); - sinc=sin(c); - *lats=asin(cosc*sinphi1+y*sinc*cosphi1/rho)/d2r; - *lons=(lambda0+atan2(x*sinc,rho*cosphi1*cosc-y*sinphi1*sinc))/d2r; - } else { - *lats=phi1/d2r; - *lons=lambda0/d2r; + x = xFirst; + for (i = 0; i < nx; i++) { + double xsq = x * x; + y = yFirst; + for (j = 0; j < ny; j++) { + rho = sqrt(xsq + y * y); + if (rho > epsilon) { + c = 2 * asin(rho / (2.0 * radius)); + cosc = cos(c); + sinc = sin(c); + *lats = asin(cosc * sinphi1 + y * sinc * cosphi1 / rho) / d2r; + *lons = (lambda0 + atan2(x * sinc, rho * cosphi1 * cosc - y * sinphi1 * sinc)) / d2r; + } + else { + *lats = phi1 / d2r; + *lons = lambda0 / d2r; } - if (*lons<0) *lons+=360; + if (*lons < 0) + *lons += 360; lons++; lats++; - y+=Dy; + y += Dy; } - x+=Dx; + x += Dx; } - - } else { - - y=yFirst; - for (j=0;jepsilon) { - c=2*asin(rho/(2.0*radius)); - cosc=cos(c); - sinc=sin(c); - *lats=asin(cosc*sinphi1+y*sinc*cosphi1/rho)/d2r; - *lons=(lambda0+atan2(x*sinc,rho*cosphi1*cosc-y*sinphi1*sinc))/d2r; - } else { - *lats=phi1/d2r; - *lons=lambda0/d2r; + } + else { + y = yFirst; + for (j = 0; j < ny; j++) { + double ysq = y * y; + x = xFirst; + for (i = 0; i < nx; i++) { + rho = sqrt(x * x + ysq); + if (rho > epsilon) { + c = 2 * asin(rho / (2.0 * radius)); + cosc = cos(c); + sinc = sin(c); + *lats = asin(cosc * sinphi1 + y * sinc * cosphi1 / rho) / d2r; + *lons = (lambda0 + atan2(x * sinc, rho * cosphi1 * cosc - y * sinphi1 * sinc)) / d2r; + } + else { + *lats = phi1 / d2r; + *lons = lambda0 / d2r; } - if (*lons<0) *lons+=360; + if (*lons < 0) + *lons += 360; lons++; lats++; - x+=Dx; + x += Dx; } - y+=Dy; + y += Dy; } } @@ -282,9 +276,9 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) static int destroy(grib_iterator* i) { grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; - const grib_context *c = i->h->context; + const grib_context* c = i->h->context; - grib_context_free(c,self->lats); - grib_context_free(c,self->lons); + grib_context_free(c, self->lats); + grib_context_free(c, self->lons); return 1; } diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index c3e5e245c..6bae1d000 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -36,38 +36,39 @@ or edit "iterator.class" and rerun ./make_class.pl */ -static void init_class (grib_iterator_class*); - -static int init (grib_iterator* i,grib_handle*,grib_arguments*); -static int next (grib_iterator* i, double *lat, double *lon, double *val); -static int destroy (grib_iterator* i); - - -typedef struct grib_iterator_lambert_conformal{ - grib_iterator it; -/* Members defined in gen */ - long carg; - const char* missingValue; -/* Members defined in lambert_conformal */ - double *lats; - double *lons; - long nam; +static void init_class(grib_iterator_class*); + +static int init(grib_iterator* i, grib_handle*, grib_arguments*); +static int next(grib_iterator* i, double* lat, double* lon, double* val); +static int destroy(grib_iterator* i); + + +typedef struct grib_iterator_lambert_conformal +{ + grib_iterator it; + /* Members defined in gen */ + long carg; + const char* missingValue; + /* Members defined in lambert_conformal */ + double* lats; + double* lons; + long nam; } grib_iterator_lambert_conformal; extern grib_iterator_class* grib_iterator_class_gen; static grib_iterator_class _grib_iterator_class_lambert_conformal = { - &grib_iterator_class_gen, /* super */ - "lambert_conformal", /* name */ - sizeof(grib_iterator_lambert_conformal),/* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ + &grib_iterator_class_gen, /* super */ + "lambert_conformal", /* name */ + sizeof(grib_iterator_lambert_conformal), /* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ }; grib_iterator_class* grib_iterator_class_lambert_conformal = &_grib_iterator_class_lambert_conformal; @@ -75,17 +76,17 @@ grib_iterator_class* grib_iterator_class_lambert_conformal = &_grib_iterator_cla static void init_class(grib_iterator_class* c) { - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; } /* END_CLASS_IMP */ -static int next(grib_iterator* i, double *lat, double *lon, double *val) +static int next(grib_iterator* i, double* lat, double* lon, double* val) { grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; - if((long)i->e >= (long)(i->nv-1)) + if ((long)i->e >= (long)(i->nv - 1)) return 0; i->e++; @@ -97,89 +98,89 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) } #ifndef M_PI -#define M_PI 3.14159265358979323846 /* Whole pie */ +#define M_PI 3.14159265358979323846 /* Whole pie */ #endif #ifndef M_PI_2 -#define M_PI_2 1.57079632679489661923 /* Half a pie */ +#define M_PI_2 1.57079632679489661923 /* Half a pie */ #endif #ifndef M_PI_4 -#define M_PI_4 0.78539816339744830962 /* Quarter of a pie */ +#define M_PI_4 0.78539816339744830962 /* Quarter of a pie */ #endif -#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ -#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ +#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { - int i, j, err=0; + int i, j, err = 0; double *lats, *lons; /* the lat/lon arrays to be populated */ - long nx,ny,iScansNegatively,jScansPositively,jPointsAreConsecutive,alternativeRowScanning; - double LoVInDegrees,LaDInDegrees,Latin1InDegrees,Latin2InDegrees,latFirstInDegrees, - lonFirstInDegrees, Dx, Dy, radius=0; + long nx, ny, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning; + double LoVInDegrees, LaDInDegrees, Latin1InDegrees, Latin2InDegrees, latFirstInDegrees, + lonFirstInDegrees, Dx, Dy, radius = 0; double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, - LaDInRadians, lonDiff, lonDeg, latDeg; + LaDInRadians, lonDiff, lonDeg, latDeg; double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; - const char* sradius = grib_arguments_get_name(h,args,self->carg++); - const char* snx = grib_arguments_get_name(h,args,self->carg++); - const char* sny = grib_arguments_get_name(h,args,self->carg++); - const char* sLoVInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sLaDInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sLatin1InDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sLatin2InDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); + const char* sradius = grib_arguments_get_name(h, args, self->carg++); + const char* snx = grib_arguments_get_name(h, args, self->carg++); + const char* sny = grib_arguments_get_name(h, args, self->carg++); + const char* sLoVInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sLaDInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sLatin1InDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sLatin2InDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); /* Dx and Dy are in Metres */ - const char* sDx = grib_arguments_get_name(h,args,self->carg++); - const char* sDy = grib_arguments_get_name(h,args,self->carg++); - const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); - - if((err = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) + const char* sDx = grib_arguments_get_name(h, args, self->carg++); + const char* sDy = grib_arguments_get_name(h, args, self->carg++); + const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); + + if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) return err; - if((err = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) + if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) return err; if (grib_is_earth_oblate(h)) { - grib_context_log(h->context,GRIB_LOG_ERROR,"Lambert Conformal only supported for spherical earth."); + grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Conformal only supported for spherical earth."); return GRIB_GEOCALCULUS_PROBLEM; } - if (iter->nv!=nx*ny) { - grib_context_log(h->context,GRIB_LOG_ERROR,"Wrong number of points (%ld!=%ldx%ld)",iter->nv,nx,ny); + if (iter->nv != nx * ny) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); return GRIB_WRONG_GRID; } - if((err = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) + if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) return err; - if((err = grib_get_double_internal(h, sLoVInDegrees, &LoVInDegrees))!=GRIB_SUCCESS) + if ((err = grib_get_double_internal(h, sLoVInDegrees, &LoVInDegrees)) != GRIB_SUCCESS) return err; - if((err = grib_get_double_internal(h, sLaDInDegrees, &LaDInDegrees))!=GRIB_SUCCESS) + if ((err = grib_get_double_internal(h, sLaDInDegrees, &LaDInDegrees)) != GRIB_SUCCESS) return err; - if((err = grib_get_double_internal(h, sLatin1InDegrees, &Latin1InDegrees))!=GRIB_SUCCESS) + if ((err = grib_get_double_internal(h, sLatin1InDegrees, &Latin1InDegrees)) != GRIB_SUCCESS) return err; - if((err = grib_get_double_internal(h, sLatin2InDegrees, &Latin2InDegrees))!=GRIB_SUCCESS) + if ((err = grib_get_double_internal(h, sLatin2InDegrees, &Latin2InDegrees)) != GRIB_SUCCESS) return err; - if((err = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) !=GRIB_SUCCESS) + if ((err = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) return err; - if((err = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) !=GRIB_SUCCESS) + if ((err = grib_get_double_internal(h, slonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) return err; - if((err = grib_get_double_internal(h, sDx,&Dx)) !=GRIB_SUCCESS) + if ((err = grib_get_double_internal(h, sDx, &Dx)) != GRIB_SUCCESS) return err; - if((err = grib_get_double_internal(h, sDy,&Dy)) !=GRIB_SUCCESS) + if ((err = grib_get_double_internal(h, sDy, &Dy)) != GRIB_SUCCESS) return err; - if((err = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) !=GRIB_SUCCESS) + if ((err = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) return err; - if((err = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) !=GRIB_SUCCESS) + if ((err = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) return err; - if((err = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) !=GRIB_SUCCESS) + if ((err = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) return err; - if((err = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) !=GRIB_SUCCESS) + if ((err = grib_get_long_internal(h, salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) return err; /* @@ -192,67 +193,72 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) LaDInRadians = LaDInDegrees * DEG2RAD; LoVInRadians = LoVInDegrees * DEG2RAD; - if ( fabs(Latin1InRadians - Latin2InRadians) < 1E-09 ) { + if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { n = sin(Latin1InRadians); } else { - n = log(cos(Latin1InRadians)/cos(Latin2InRadians)) / - log(tan(M_PI_4 + Latin2InRadians/2.0) / tan(M_PI_4 + Latin1InRadians/2.0)); + n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) / + log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); } - f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians/2.0), n)) / n; - rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians/2.0), -n); - rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians/2.0), -n); - if ( n < 0 ) /* adjustment for southern hemisphere */ + f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; + rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); + rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); + if (n < 0) /* adjustment for southern hemisphere */ rho0 = -rho0; lonDiff = lonFirstInRadians - LoVInRadians; /* Adjust longitude to range -180 to 180 */ - if (lonDiff > M_PI) lonDiff -= 2*M_PI; - if (lonDiff < -M_PI) lonDiff += 2*M_PI; + if (lonDiff > M_PI) + lonDiff -= 2 * M_PI; + if (lonDiff < -M_PI) + lonDiff += 2 * M_PI; angle = n * lonDiff; - x0 = rho * sin(angle); - y0 = rho0 - rho * cos(angle); + x0 = rho * sin(angle); + y0 = rho0 - rho * cos(angle); /*Dx = iScansNegatively == 0 ? Dx : -Dx;*/ /* GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint */ /*Dy = jScansPositively == 1 ? Dy : -Dy;*/ /* Allocate latitude and longitude arrays */ - self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "Unable to allocate %ld bytes",iter->nv*sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } - self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "Unable to allocate %ld bytes",iter->nv*sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } - lats=self->lats; - lons=self->lons; + lats = self->lats; + lons = self->lons; /* Populate our arrays */ for (j = 0; j < ny; j++) { - y = y0 + j*Dy; - if ( n < 0 ) { /* adjustment for southern hemisphere */ + y = y0 + j * Dy; + if (n < 0) { /* adjustment for southern hemisphere */ y = -y; } - tmp = rho0 - y; - tmp2 = tmp*tmp; + tmp = rho0 - y; + tmp2 = tmp * tmp; for (i = 0; i < nx; i++) { - int index =i+j*nx; - x = x0 + i*Dx; - if ( n < 0 ) { /* adjustment for southern hemisphere */ + int index = i + j * nx; + x = x0 + i * Dx; + if (n < 0) { /* adjustment for southern hemisphere */ x = -x; } angle = atan2(x, tmp); /* See ECC-524 */ - rho = sqrt(x*x + tmp2); - if (n <= 0) rho = -rho; - lonDeg = LoVInDegrees + (angle/n) * RAD2DEG; - latDeg = (2.0 * atan(pow(radius * f/rho, 1.0/n)) - M_PI_2) * RAD2DEG; - while ( lonDeg >= 360.0) lonDeg -= 360.0; - while ( lonDeg < 0.0) lonDeg += 360.0; + rho = sqrt(x * x + tmp2); + if (n <= 0) + rho = -rho; + lonDeg = LoVInDegrees + (angle / n) * RAD2DEG; + latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * RAD2DEG; + while (lonDeg >= 360.0) + lonDeg -= 360.0; + while (lonDeg < 0.0) + lonDeg += 360.0; lons[index] = lonDeg; lats[index] = latDeg; /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ @@ -263,9 +269,10 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) /* Apply the scanning mode flags which may require data array to be transformed */ err = transform_iterator_data(h, iter->data, - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, - iter->nv, nx, ny); - if (err) return err; + iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, + iter->nv, nx, ny); + if (err) + return err; return err; } @@ -273,9 +280,9 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) static int destroy(grib_iterator* i) { grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; - const grib_context *c = i->h->context; + const grib_context* c = i->h->context; - grib_context_free(c,self->lats); - grib_context_free(c,self->lons); + grib_context_free(c, self->lats); + grib_context_free(c, self->lons); return 1; } diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index de2af4f7b..68f781057 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -36,38 +36,39 @@ or edit "iterator.class" and rerun ./make_class.pl */ -static void init_class (grib_iterator_class*); - -static int init (grib_iterator* i,grib_handle*,grib_arguments*); -static int next (grib_iterator* i, double *lat, double *lon, double *val); -static int destroy (grib_iterator* i); - - -typedef struct grib_iterator_polar_stereographic{ - grib_iterator it; -/* Members defined in gen */ - long carg; - const char* missingValue; -/* Members defined in polar_stereographic */ - double *lats; - double *lons; - long nam; +static void init_class(grib_iterator_class*); + +static int init(grib_iterator* i, grib_handle*, grib_arguments*); +static int next(grib_iterator* i, double* lat, double* lon, double* val); +static int destroy(grib_iterator* i); + + +typedef struct grib_iterator_polar_stereographic +{ + grib_iterator it; + /* Members defined in gen */ + long carg; + const char* missingValue; + /* Members defined in polar_stereographic */ + double* lats; + double* lons; + long nam; } grib_iterator_polar_stereographic; extern grib_iterator_class* grib_iterator_class_gen; static grib_iterator_class _grib_iterator_class_polar_stereographic = { - &grib_iterator_class_gen, /* super */ - "polar_stereographic", /* name */ - sizeof(grib_iterator_polar_stereographic),/* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ + &grib_iterator_class_gen, /* super */ + "polar_stereographic", /* name */ + sizeof(grib_iterator_polar_stereographic), /* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ }; grib_iterator_class* grib_iterator_class_polar_stereographic = &_grib_iterator_class_polar_stereographic; @@ -75,17 +76,17 @@ grib_iterator_class* grib_iterator_class_polar_stereographic = &_grib_iterator_c static void init_class(grib_iterator_class* c) { - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; } /* END_CLASS_IMP */ -static int next(grib_iterator* i, double *lat, double *lon, double *val) +static int next(grib_iterator* i, double* lat, double* lon, double* val) { grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; - if((long)i->e >= (long)(i->nv-1)) + if ((long)i->e >= (long)(i->nv - 1)) return 0; i->e++; @@ -97,25 +98,26 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) } /* Data struct for Forward and Inverse Projections */ -typedef struct proj_data_t { - double centre_lon; /* central longitude */ - double centre_lat; /* central latitude */ - double sign; /* sign variable */ - double ind; /* flag variable */ - double mcs; /* small m */ - double tcs; /* small t */ +typedef struct proj_data_t +{ + double centre_lon; /* central longitude */ + double centre_lat; /* central latitude */ + double sign; /* sign variable */ + double ind; /* flag variable */ + double mcs; /* small m */ + double tcs; /* small t */ double false_northing; /* y offset in meters */ double false_easting; /* x offset in meters */ } proj_data_t; -#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ -#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ -#define PI_OVER_2 1.5707963267948966 /* half pi */ -#define EPSILON 1.0e-10 +#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ +#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +#define PI_OVER_2 1.5707963267948966 /* half pi */ +#define EPSILON 1.0e-10 -static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { - int ret=0; + int ret = 0; double *lats, *lons; /* arrays for latitudes and longitudes */ double lonFirstInDegrees, latFirstInDegrees, radius; double x, y, Dx, Dy; @@ -123,153 +125,167 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) long alternativeRowScanning, iScansNegatively, i, j; long jScansPositively, jPointsAreConsecutive, southPoleOnPlane; double centralLongitude, centralLatitude; /* in radians */ - double con1; /* temporary angle */ - double ts; /* value of small t */ - double height; /* height above ellipsoid */ + double con1; /* temporary angle */ + double ts; /* value of small t */ + double height; /* height above ellipsoid */ double x0, y0, lonFirst, latFirst; - proj_data_t fwd_proj_data = {0,}; - proj_data_t inv_proj_data = {0,}; + proj_data_t fwd_proj_data = { + 0, + }; + proj_data_t inv_proj_data = { + 0, + }; grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)iter; - const char* sradius = grib_arguments_get_name(h,args,self->carg++); - const char* snx = grib_arguments_get_name(h,args,self->carg++); - const char* sny = grib_arguments_get_name(h,args,self->carg++); - const char* slatFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* slonFirstInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* ssouthPoleOnPlane = grib_arguments_get_name(h,args,self->carg++); - const char* scentralLongitude = grib_arguments_get_name(h,args,self->carg++); - const char* scentralLatitude = grib_arguments_get_name(h,args,self->carg++); - const char* sDx = grib_arguments_get_name(h,args,self->carg++); - const char* sDy = grib_arguments_get_name(h,args,self->carg++); - const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); - - if((ret = grib_get_double_internal(h, sradius,&radius)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) return ret; + const char* sradius = grib_arguments_get_name(h, args, self->carg++); + const char* snx = grib_arguments_get_name(h, args, self->carg++); + const char* sny = grib_arguments_get_name(h, args, self->carg++); + const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* ssouthPoleOnPlane = grib_arguments_get_name(h, args, self->carg++); + const char* scentralLongitude = grib_arguments_get_name(h, args, self->carg++); + const char* scentralLatitude = grib_arguments_get_name(h, args, self->carg++); + const char* sDx = grib_arguments_get_name(h, args, self->carg++); + const char* sDy = grib_arguments_get_name(h, args, self->carg++); + const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); + + if ((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) + return ret; if (grib_is_earth_oblate(h)) { - grib_context_log(h->context,GRIB_LOG_ERROR,"Polar stereographic only supported for spherical earth."); + grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic only supported for spherical earth."); return GRIB_GEOCALCULUS_PROBLEM; } - if (iter->nv!=nx*ny) { - grib_context_log(h->context,GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv,nx,ny); + if (iter->nv != nx * ny) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); return GRIB_WRONG_GRID; } - if((ret = grib_get_double_internal(h, slatFirstInDegrees,&latFirstInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, slonFirstInDegrees,&lonFirstInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, slonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, ssouthPoleOnPlane,&southPoleOnPlane)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, ssouthPoleOnPlane, &southPoleOnPlane)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, scentralLongitude,¢ralLongitudeInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, scentralLongitude, ¢ralLongitudeInDegrees)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, scentralLatitude,¢ralLatitudeInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, scentralLatitude, ¢ralLatitudeInDegrees)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, sDx,&Dx)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sDx, &Dx)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, sDy,&Dy)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sDy, &Dy)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, salternativeRowScanning,&alternativeRowScanning)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) return ret; centralLongitude = centralLongitudeInDegrees * DEG2RAD; - centralLatitude = centralLatitudeInDegrees * DEG2RAD; - lonFirst = lonFirstInDegrees * DEG2RAD; - latFirst = latFirstInDegrees*DEG2RAD; + centralLatitude = centralLatitudeInDegrees * DEG2RAD; + lonFirst = lonFirstInDegrees * DEG2RAD; + latFirst = latFirstInDegrees * DEG2RAD; /* Forward projection initialisation */ fwd_proj_data.false_northing = 0; - fwd_proj_data.false_easting = 0; - fwd_proj_data.centre_lon = centralLongitude; - fwd_proj_data.centre_lat = centralLatitude; - if (centralLatitude < 0) fwd_proj_data.sign = -1.0; - else fwd_proj_data.sign = +1.0; + fwd_proj_data.false_easting = 0; + fwd_proj_data.centre_lon = centralLongitude; + fwd_proj_data.centre_lat = centralLatitude; + if (centralLatitude < 0) + fwd_proj_data.sign = -1.0; + else + fwd_proj_data.sign = +1.0; fwd_proj_data.ind = 0; if (fabs(fabs(centralLatitude) - PI_OVER_2) > EPSILON) { /* central latitude different from 90 i.e. not north/south polar */ fwd_proj_data.ind = 1; - con1 = fwd_proj_data.sign * centralLatitude; + con1 = fwd_proj_data.sign * centralLatitude; fwd_proj_data.mcs = cos(con1); fwd_proj_data.tcs = tan(0.5 * (PI_OVER_2 - con1)); } /* Forward projection from initial lat,lon to initial x,y */ con1 = fwd_proj_data.sign * (lonFirst - fwd_proj_data.centre_lon); - ts = tan(0.5 * (PI_OVER_2 - fwd_proj_data.sign * latFirst)); + ts = tan(0.5 * (PI_OVER_2 - fwd_proj_data.sign * latFirst)); if (fwd_proj_data.ind) height = radius * fwd_proj_data.mcs * ts / fwd_proj_data.tcs; else height = 2.0 * radius * ts; x0 = fwd_proj_data.sign * height * sin(con1) + fwd_proj_data.false_easting; y0 = -fwd_proj_data.sign * height * cos(con1) + fwd_proj_data.false_northing; - + x0 = -x0; y0 = -y0; /* Inverse projection initialisation */ - inv_proj_data.false_easting = x0; - inv_proj_data.false_northing= y0; - inv_proj_data.centre_lon = centralLongitude; - inv_proj_data.centre_lat = centralLatitude; - if (centralLatitude < 0) inv_proj_data.sign = -1.0; - else inv_proj_data.sign = +1.0; + inv_proj_data.false_easting = x0; + inv_proj_data.false_northing = y0; + inv_proj_data.centre_lon = centralLongitude; + inv_proj_data.centre_lat = centralLatitude; + if (centralLatitude < 0) + inv_proj_data.sign = -1.0; + else + inv_proj_data.sign = +1.0; inv_proj_data.ind = 0; if (fabs(fabs(centralLatitude) - PI_OVER_2) > EPSILON) { inv_proj_data.ind = 1; - con1 = inv_proj_data.sign * inv_proj_data.centre_lat; + con1 = inv_proj_data.sign * inv_proj_data.centre_lat; inv_proj_data.mcs = cos(con1); inv_proj_data.tcs = tan(0.5 * (PI_OVER_2 - con1)); } - self->lats = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "unable to allocate %ld bytes", iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } - self->lons = (double*)grib_context_malloc(h->context,iter->nv*sizeof(double)); + self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",iter->nv*sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "unable to allocate %ld bytes", iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } - lats=self->lats; - lons=self->lons; - Dx = iScansNegatively == 0 ? Dx : -Dx; - Dy = jScansPositively == 1 ? Dy : -Dy; + lats = self->lats; + lons = self->lons; + Dx = iScansNegatively == 0 ? Dx : -Dx; + Dy = jScansPositively == 1 ? Dy : -Dy; y = 0; - for (j=0;j360) *lons -= 360; + while (*lons < 0) + *lons += 360; + while (*lons > 360) + *lons -= 360; lons++; lats++; @@ -347,9 +363,9 @@ static int init(grib_iterator* iter,grib_handle* h,grib_arguments* args) static int destroy(grib_iterator* i) { grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; - const grib_context *c = i->h->context; + const grib_context* c = i->h->context; - grib_context_free(c,self->lats); - grib_context_free(c,self->lons); + grib_context_free(c, self->lats); + grib_context_free(c, self->lons); return 1; } diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index caf21f9ed..73a663771 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -36,38 +36,39 @@ or edit "iterator.class" and rerun ./make_class.pl */ -static void init_class (grib_iterator_class*); - -static int init (grib_iterator* i,grib_handle*,grib_arguments*); -static int next (grib_iterator* i, double *lat, double *lon, double *val); -static int destroy (grib_iterator* i); - - -typedef struct grib_iterator_space_view{ - grib_iterator it; -/* Members defined in gen */ - long carg; - const char* missingValue; -/* Members defined in space_view */ - double *lats; - double *lons; - long nam; +static void init_class(grib_iterator_class*); + +static int init(grib_iterator* i, grib_handle*, grib_arguments*); +static int next(grib_iterator* i, double* lat, double* lon, double* val); +static int destroy(grib_iterator* i); + + +typedef struct grib_iterator_space_view +{ + grib_iterator it; + /* Members defined in gen */ + long carg; + const char* missingValue; + /* Members defined in space_view */ + double* lats; + double* lons; + long nam; } grib_iterator_space_view; extern grib_iterator_class* grib_iterator_class_gen; static grib_iterator_class _grib_iterator_class_space_view = { - &grib_iterator_class_gen, /* super */ - "space_view", /* name */ - sizeof(grib_iterator_space_view),/* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ + &grib_iterator_class_gen, /* super */ + "space_view", /* name */ + sizeof(grib_iterator_space_view), /* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ }; grib_iterator_class* grib_iterator_class_space_view = &_grib_iterator_class_space_view; @@ -75,17 +76,17 @@ grib_iterator_class* grib_iterator_class_space_view = &_grib_iterator_class_spac static void init_class(grib_iterator_class* c) { - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; } /* END_CLASS_IMP */ -static int next(grib_iterator* i, double *lat, double *lon, double *val) +static int next(grib_iterator* i, double* lat, double* lon, double* val) { grib_iterator_space_view* self = (grib_iterator_space_view*)i; - if((long)i->e >= (long)(i->nv-1)) + if ((long)i->e >= (long)(i->nv - 1)) return 0; i->e++; @@ -96,8 +97,8 @@ static int next(grib_iterator* i, double *lat, double *lon, double *val) return 1; } -#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ -#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ +#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { @@ -105,15 +106,15 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) * LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) */ int ret = GRIB_SUCCESS; - double *lats,*lons; /* arrays of latitudes and longitudes */ - double latOfSubSatellitePointInDegrees,lonOfSubSatellitePointInDegrees; + double *lats, *lons; /* arrays of latitudes and longitudes */ + double latOfSubSatellitePointInDegrees, lonOfSubSatellitePointInDegrees; double orientationInDegrees, nrInRadiusOfEarth; - double radius=0,xpInGridLengths=0,ypInGridLengths=0; - long nx, ny, earthIsOblate=0; - long alternativeRowScanning,iScansNegatively; - long Xo, Yo, jScansPositively,jPointsAreConsecutive, i; + double radius = 0, xpInGridLengths = 0, ypInGridLengths = 0; + long nx, ny, earthIsOblate = 0; + long alternativeRowScanning, iScansNegatively; + long Xo, Yo, jScansPositively, jPointsAreConsecutive, i; - double major=0, minor=0, r_eq, r_pol, height; + double major = 0, minor = 0, r_eq, r_pol, height; double lap, lop, orient_angle, angular_size; double xp, yp, dx, dy, rx, ry, x, y; double cos_x, cos_y, sin_x, sin_y; @@ -121,107 +122,111 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) int x0, y0, ix, iy; double *s_x, *c_x; /* arrays storing sin and cos values */ size_t array_size = (iter->nv * sizeof(double)); - + grib_iterator_space_view* self = (grib_iterator_space_view*)iter; - const char* sradius = grib_arguments_get_name(h,args,self->carg++); - const char* sEarthIsOblate = grib_arguments_get_name(h,args,self->carg++); - const char* sMajorAxisInMetres = grib_arguments_get_name(h,args,self->carg++); - const char* sMinorAxisInMetres = grib_arguments_get_name(h,args,self->carg++); - const char* snx = grib_arguments_get_name(h,args,self->carg++); - const char* sny = grib_arguments_get_name(h,args,self->carg++); - const char* sLatOfSubSatellitePointInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sLonOfSubSatellitePointInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sDx = grib_arguments_get_name(h,args,self->carg++); - const char* sDy = grib_arguments_get_name(h,args,self->carg++); - const char* sXpInGridLengths = grib_arguments_get_name(h,args,self->carg++); - const char* sYpInGridLengths = grib_arguments_get_name(h,args,self->carg++); - const char* sOrientationInDegrees = grib_arguments_get_name(h,args,self->carg++); - const char* sNrInRadiusOfEarth = grib_arguments_get_name(h,args,self->carg++); - const char* sXo = grib_arguments_get_name(h,args,self->carg++); - const char* sYo = grib_arguments_get_name(h,args,self->carg++); - - const char* siScansNegatively = grib_arguments_get_name(h,args,self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h,args,self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h,args,self->carg++); - const char* sAlternativeRowScanning = grib_arguments_get_name(h,args,self->carg++); - - if((ret = grib_get_long_internal(h, snx,&nx)) != GRIB_SUCCESS) + const char* sradius = grib_arguments_get_name(h, args, self->carg++); + const char* sEarthIsOblate = grib_arguments_get_name(h, args, self->carg++); + const char* sMajorAxisInMetres = grib_arguments_get_name(h, args, self->carg++); + const char* sMinorAxisInMetres = grib_arguments_get_name(h, args, self->carg++); + const char* snx = grib_arguments_get_name(h, args, self->carg++); + const char* sny = grib_arguments_get_name(h, args, self->carg++); + const char* sLatOfSubSatellitePointInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sLonOfSubSatellitePointInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sDx = grib_arguments_get_name(h, args, self->carg++); + const char* sDy = grib_arguments_get_name(h, args, self->carg++); + const char* sXpInGridLengths = grib_arguments_get_name(h, args, self->carg++); + const char* sYpInGridLengths = grib_arguments_get_name(h, args, self->carg++); + const char* sOrientationInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sNrInRadiusOfEarth = grib_arguments_get_name(h, args, self->carg++); + const char* sXo = grib_arguments_get_name(h, args, self->carg++); + const char* sYo = grib_arguments_get_name(h, args, self->carg++); + + const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); + const char* sAlternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); + + if ((ret = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sny,&ny)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sEarthIsOblate, &earthIsOblate)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, sEarthIsOblate, &earthIsOblate)) != GRIB_SUCCESS) return ret; if (earthIsOblate) { - if((ret = grib_get_double_internal(h, sMajorAxisInMetres, &major)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sMajorAxisInMetres, &major)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, sMinorAxisInMetres, &minor)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sMinorAxisInMetres, &minor)) != GRIB_SUCCESS) return ret; - } else { - if((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) + } + else { + if ((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) return ret; } - - if (iter->nv!=nx*ny) { - grib_context_log(h->context,GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv,nx,ny); + + if (iter->nv != nx * ny) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); return GRIB_WRONG_GRID; } - if((ret = grib_get_double_internal(h, sLatOfSubSatellitePointInDegrees,&latOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sLatOfSubSatellitePointInDegrees, &latOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, sLonOfSubSatellitePointInDegrees,&lonOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sLonOfSubSatellitePointInDegrees, &lonOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, sDx, &dx)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sDx, &dx)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, sDy, &dy)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sDy, &dy)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, sXpInGridLengths,&xpInGridLengths)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sXpInGridLengths, &xpInGridLengths)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, sYpInGridLengths,&ypInGridLengths)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sYpInGridLengths, &ypInGridLengths)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_double_internal(h, sOrientationInDegrees,&orientationInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sOrientationInDegrees, &orientationInDegrees)) != GRIB_SUCCESS) return ret; /* Orthographic not supported. This happens when Nr (camera altitude) is missing */ if (grib_is_missing(h, sNrInRadiusOfEarth, &ret)) { - grib_context_log(h->context,GRIB_LOG_ERROR, "Orthographic view (Nr missing) not supported"); + grib_context_log(h->context, GRIB_LOG_ERROR, "Orthographic view (Nr missing) not supported"); return GRIB_NOT_IMPLEMENTED; } - if((ret = grib_get_double_internal(h, sNrInRadiusOfEarth,&nrInRadiusOfEarth)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sNrInRadiusOfEarth, &nrInRadiusOfEarth)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sXo,&Xo)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, sXo, &Xo)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sYo,&Yo)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, sYo, &Yo)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sjPointsAreConsecutive,&jPointsAreConsecutive)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sjScansPositively,&jScansPositively)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, siScansNegatively,&iScansNegatively)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) return ret; - if((ret = grib_get_long_internal(h, sAlternativeRowScanning,&alternativeRowScanning)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, sAlternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) return ret; if (earthIsOblate) { - r_eq = major; /* In km */ + r_eq = major; /* In km */ r_pol = minor; - } else { - r_eq = r_pol = radius * 0.001;/*conv to km*/ + } + else { + r_eq = r_pol = radius * 0.001; /*conv to km*/ } angular_size = 2.0 * asin(1.0 / nrInRadiusOfEarth); - height = nrInRadiusOfEarth * r_eq; + height = nrInRadiusOfEarth * r_eq; lap = latOfSubSatellitePointInDegrees; lop = lonOfSubSatellitePointInDegrees; lap *= 1e-6; /* default scaling factor */ lop *= 1e-6; - if (lap != 0.0) return GRIB_NOT_IMPLEMENTED; + if (lap != 0.0) + return GRIB_NOT_IMPLEMENTED; lap *= DEG2RAD; lop *= DEG2RAD; orient_angle = orientationInDegrees; - if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; + if (orient_angle != 0.0) + return GRIB_NOT_IMPLEMENTED; xp = xpInGridLengths; yp = ypInGridLengths; @@ -229,85 +234,89 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) y0 = Yo; rx = angular_size / dx; - ry = (r_pol/r_eq) * angular_size / dy; + ry = (r_pol / r_eq) * angular_size / dy; self->lats = (double*)grib_context_malloc(h->context, array_size); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes", array_size); + grib_context_log(h->context, GRIB_LOG_ERROR, "unable to allocate %ld bytes", array_size); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, array_size); if (!self->lats) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes", array_size); + grib_context_log(h->context, GRIB_LOG_ERROR, "unable to allocate %ld bytes", array_size); return GRIB_OUT_OF_MEMORY; } - lats=self->lats; - lons=self->lons; + lats = self->lats; + lons = self->lons; if (!iScansNegatively) { xp = xp - x0; - } else { - xp = (nx-1) - (xp - x0); + } + else { + xp = (nx - 1) - (xp - x0); } if (jScansPositively) { yp = yp - y0; } else { - yp = (ny-1) - (yp - y0); + yp = (ny - 1) - (yp - y0); } - i = 0; - factor_2 = (r_eq/r_pol)*(r_eq/r_pol); + i = 0; + factor_2 = (r_eq / r_pol) * (r_eq / r_pol); factor_1 = height * height - r_eq * r_eq; /* Store array of sin and cosine values to avoid recalculation */ - s_x = (double *) grib_context_malloc(h->context, nx*sizeof(double)); + s_x = (double*)grib_context_malloc(h->context, nx * sizeof(double)); if (!s_x) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",nx*sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "unable to allocate %ld bytes", nx * sizeof(double)); return GRIB_OUT_OF_MEMORY; } - c_x = (double *) grib_context_malloc(h->context, nx*sizeof(double)); + c_x = (double*)grib_context_malloc(h->context, nx * sizeof(double)); if (!c_x) { - grib_context_log(h->context,GRIB_LOG_ERROR, "unable to allocate %ld bytes",nx*sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "unable to allocate %ld bytes", nx * sizeof(double)); return GRIB_OUT_OF_MEMORY; } for (ix = 0; ix < nx; ix++) { - x = (ix - xp) * rx; + x = (ix - xp) * rx; s_x[ix] = sin(x); - c_x[ix] = sqrt(1.0 - s_x[ix]*s_x[ix]); + c_x[ix] = sqrt(1.0 - s_x[ix] * s_x[ix]); } /*for (iy = 0; iy < ny; iy++) {*/ - for (iy = ny-1; iy >= 0; --iy) { - y = (iy - yp) * ry; + for (iy = ny - 1; iy >= 0; --iy) { + y = (iy - yp) * ry; sin_y = sin(y); - cos_y = sqrt(1.0 - sin_y*sin_y); + cos_y = sqrt(1.0 - sin_y * sin_y); + + tmp1 = (1 + (factor_2 - 1.0) * sin_y * sin_y); - tmp1 = (1 + (factor_2-1.0)*sin_y*sin_y); - for (ix = 0; ix < nx; ix++, i++) { /*x = (ix - xp) * rx;*/ /* Use sin/cos previously computed */ - sin_x = s_x[ix]; cos_x = c_x[ix]; - + sin_x = s_x[ix]; + cos_x = c_x[ix]; + Sd = height * cos_x * cos_y; - Sd = Sd * Sd - tmp1*factor_1; - if (Sd <= 0.0) { /* outside of view */ + Sd = Sd * Sd - tmp1 * factor_1; + if (Sd <= 0.0) { /* outside of view */ lats[i] = lons[i] = 0; /* TODO: error? */ } else { - Sd = sqrt(Sd); - Sn = (height*cos_x*cos_y - Sd) / tmp1; - S1 = height - Sn * cos_x * cos_y; - S2 = Sn * sin_x * cos_y; - S3 = Sn * sin_y; - Sxy = sqrt(S1*S1 + S2*S2); - lons[i] = atan(S2/S1)*(RAD2DEG) + lop; - lats[i] = atan(factor_2*S3/Sxy)*(RAD2DEG); + Sd = sqrt(Sd); + Sn = (height * cos_x * cos_y - Sd) / tmp1; + S1 = height - Sn * cos_x * cos_y; + S2 = Sn * sin_x * cos_y; + S3 = Sn * sin_y; + Sxy = sqrt(S1 * S1 + S2 * S2); + lons[i] = atan(S2 / S1) * (RAD2DEG) + lop; + lats[i] = atan(factor_2 * S3 / Sxy) * (RAD2DEG); /*fprintf(stderr, "lat=%g lon=%g\n", lats[i], lons[i]);*/ } - while (lons[i]<0) lons[i] += 360; - while (lons[i]>360) lons[i] -= 360; + while (lons[i] < 0) + lons[i] += 360; + while (lons[i] > 360) + lons[i] -= 360; } } grib_context_free(h->context, s_x); @@ -320,9 +329,9 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) static int destroy(grib_iterator* i) { grib_iterator_space_view* self = (grib_iterator_space_view*)i; - const grib_context *c = i->h->context; + const grib_context* c = i->h->context; - grib_context_free(c,self->lats); - grib_context_free(c,self->lons); + grib_context_free(c, self->lats); + grib_context_free(c, self->lons); return 1; } From 1059a48ad4c6dfa3a88805c10ab43a85dc4131bd Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 22 Jan 2020 14:48:06 +0000 Subject: [PATCH 040/737] Applied clang-format (Part 2) --- src/grib_iterator_class_polar_stereographic.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 68f781057..7f2b8876d 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -129,12 +129,8 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) double ts; /* value of small t */ double height; /* height above ellipsoid */ double x0, y0, lonFirst, latFirst; - proj_data_t fwd_proj_data = { - 0, - }; - proj_data_t inv_proj_data = { - 0, - }; + proj_data_t fwd_proj_data = {0,}; + proj_data_t inv_proj_data = {0,}; grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)iter; From 591d7bbdcac29de55a9a21f3e952435854fed221 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 28 Jan 2020 14:32:34 +0000 Subject: [PATCH 041/737] Copyright notices: use new format --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 2 +- src/grib_iterator_class_lambert_conformal.c | 2 +- src/grib_iterator_class_polar_stereographic.c | 2 +- src/grib_iterator_class_space_view.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 7566b7c2a..5d23253b2 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2019 ECMWF. + * (C) Copyright 2005- 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. diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 6bae1d000..e0f75d8fe 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2019 ECMWF. + * (C) Copyright 2005- 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. diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 7f2b8876d..4bf22502a 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2019 ECMWF. + * (C) Copyright 2005- 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. diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 73a663771..e3119b607 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -1,5 +1,5 @@ /* - * Copyright 2005-2019 ECMWF. + * (C) Copyright 2005- 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. From 674ae42e951974df58a17f3cee1e018995fa5634 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 12 Feb 2020 17:47:14 +0000 Subject: [PATCH 042/737] Clang static analyser: Dead increment --- src/grib_iterator_class_space_view.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index e3119b607..2c26dcc93 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -221,7 +221,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) lop *= 1e-6; if (lap != 0.0) return GRIB_NOT_IMPLEMENTED; - lap *= DEG2RAD; + /*lap *= DEG2RAD;*/ lop *= DEG2RAD; orient_angle = orientationInDegrees; From 48939fc71b73194e66e81af645d4d8ad139edf87 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 14 Mar 2020 13:07:01 +0000 Subject: [PATCH 043/737] Refactoring: cryptic variable names --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 4 ++-- src/grib_iterator_class_lambert_conformal.c | 4 ++-- src/grib_iterator_class_polar_stereographic.c | 4 ++-- src/grib_iterator_class_space_view.c | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 5d23253b2..2a5fb80cc 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -26,7 +26,7 @@ IMPLEMENTS = init;next MEMBERS = double *lats MEMBERS = double *lons - MEMBERS = long nam + MEMBERS = long Nj END_CLASS_DEF */ @@ -57,7 +57,7 @@ typedef struct grib_iterator_lambert_azimuthal_equal_area /* Members defined in lambert_azimuthal_equal_area */ double* lats; double* lons; - long nam; + long Nj; } grib_iterator_lambert_azimuthal_equal_area; extern grib_iterator_class* grib_iterator_class_gen; diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index e0f75d8fe..4ca01506e 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -21,7 +21,7 @@ IMPLEMENTS = init;next MEMBERS = double *lats MEMBERS = double *lons - MEMBERS = long nam + MEMBERS = long Nj END_CLASS_DEF */ @@ -52,7 +52,7 @@ typedef struct grib_iterator_lambert_conformal /* Members defined in lambert_conformal */ double* lats; double* lons; - long nam; + long Nj; } grib_iterator_lambert_conformal; extern grib_iterator_class* grib_iterator_class_gen; diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 4bf22502a..93b2cd660 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -21,7 +21,7 @@ IMPLEMENTS = init;next MEMBERS = double *lats MEMBERS = double *lons - MEMBERS = long nam + MEMBERS = long Nj END_CLASS_DEF */ @@ -52,7 +52,7 @@ typedef struct grib_iterator_polar_stereographic /* Members defined in polar_stereographic */ double* lats; double* lons; - long nam; + long Nj; } grib_iterator_polar_stereographic; extern grib_iterator_class* grib_iterator_class_gen; diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 2c26dcc93..99c441a2d 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -21,7 +21,7 @@ IMPLEMENTS = init;next MEMBERS = double *lats MEMBERS = double *lons - MEMBERS = long nam + MEMBERS = long Nj END_CLASS_DEF */ @@ -52,7 +52,7 @@ typedef struct grib_iterator_space_view /* Members defined in space_view */ double* lats; double* lons; - long nam; + long Nj; } grib_iterator_space_view; extern grib_iterator_class* grib_iterator_class_gen; From 938effb9db74dc374518417ae6a71f2a1dccb6fa Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Thu, 26 Mar 2020 18:41:58 +0000 Subject: [PATCH 044/737] ECC-1055: Shape of the earth not taken into account for Lambert Conformal Conic (part 1) --- src/grib_iterator_class_lambert_conformal.c | 37 +++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 4ca01506e..98cf5f330 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -112,6 +112,35 @@ static int next(grib_iterator* i, double* lat, double* lon, double* val) #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +double msfnz(double eccent, double sinphi, double cosphi) +{ + double con = eccent * sinphi; + return((cosphi / (sqrt (1.0 - con * con)))); +} + +/* Function to compute the constant small t for use in the forward + computations in the Lambert Conformal Conic and the Polar + Stereographic projections. +--------------------------------------------------------------*/ +double tsfnz( + double eccent, /* Eccentricity of the spheroid */ + double phi, /* Latitude phi */ + double sinphi) /* Sine of the latitude */ +{ + double con; + double com; + + con = eccent * sinphi; + com = .5 * eccent; + con = pow(((1.0 - con) / (1.0 + con)),com); + return (tan(.5 * (M_PI_2 - phi))/con); +} + +static double calculate_eccentricity(double minor, double major) +{ + double temp = minor / major; + return sqrt(1.0 - temp*temp); +} static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { int i, j, err = 0; @@ -148,8 +177,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return err; if (grib_is_earth_oblate(h)) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Conformal only supported for spherical earth."); - return GRIB_GEOCALCULUS_PROBLEM; + double earthMajorAxisInMetres, earthMinorAxisInMetres, e; + //grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Conformal only supported for spherical earth."); + //return GRIB_GEOCALCULUS_PROBLEM; + if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; + if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; + e = calculate_eccentricity(earthMinorAxisInMetres,earthMajorAxisInMetres); } if (iter->nv != nx * ny) { From 9eac3f68f96c8f46ce497b3c3579a14e2fca1e66 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 27 Mar 2020 15:19:31 +0000 Subject: [PATCH 045/737] ECC-1055: Compiler warnings --- src/grib_iterator_class_lambert_conformal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 98cf5f330..88ae41eff 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -183,6 +183,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; e = calculate_eccentricity(earthMinorAxisInMetres,earthMajorAxisInMetres); + (void)e; } if (iter->nv != nx * ny) { From 54f509a725a6e433c82936119c20519b478b1d90 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 27 Mar 2020 16:45:00 +0000 Subject: [PATCH 046/737] ECC-1055: Shape of the earth not taken into account for Lambert Conformal Conic (part 2) --- src/grib_iterator_class_lambert_conformal.c | 278 ++++++++++++++------ 1 file changed, 202 insertions(+), 76 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 88ae41eff..057b0cedd 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -141,15 +141,197 @@ static double calculate_eccentricity(double minor, double major) double temp = minor / major; return sqrt(1.0 - temp*temp); } -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) + +static int init_sphere(grib_handle* h, + grib_iterator_lambert_conformal* self, + size_t nv, long nx, long ny, + double LoVInDegrees, + double Dx, double Dy, double radius, + double latFirstInRadians, double lonFirstInRadians, + double LoVInRadians, double Latin1InRadians, double Latin2InRadians, + double LaDInRadians, + long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) { int i, j, err = 0; double *lats, *lons; /* the lat/lon arrays to be populated */ + double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; + double latDeg, lonDeg, lonDiff; + + if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { + n = sin(Latin1InRadians); + } + else { + n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) / + log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); + } + + f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; + rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); + rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); + if (n < 0) /* adjustment for southern hemisphere */ + rho0 = -rho0; + lonDiff = lonFirstInRadians - LoVInRadians; + + /* Adjust longitude to range -180 to 180 */ + if (lonDiff > M_PI) + lonDiff -= 2 * M_PI; + if (lonDiff < -M_PI) + lonDiff += 2 * M_PI; + angle = n * lonDiff; + x0 = rho * sin(angle); + y0 = rho0 - rho * cos(angle); + /*Dx = iScansNegatively == 0 ? Dx : -Dx;*/ + /* GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint */ + /*Dy = jScansPositively == 1 ? Dy : -Dy;*/ + + /* Allocate latitude and longitude arrays */ + self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats = self->lats; + lons = self->lons; + + /* Populate our arrays */ + for (j = 0; j < ny; j++) { + y = y0 + j * Dy; + if (n < 0) { /* adjustment for southern hemisphere */ + y = -y; + } + tmp = rho0 - y; + tmp2 = tmp * tmp; + for (i = 0; i < nx; i++) { + int index = i + j * nx; + x = x0 + i * Dx; + if (n < 0) { /* adjustment for southern hemisphere */ + x = -x; + } + + angle = atan2(x, tmp); /* See ECC-524 */ + rho = sqrt(x * x + tmp2); + if (n <= 0) + rho = -rho; + lonDeg = LoVInDegrees + (angle / n) * RAD2DEG; + latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * RAD2DEG; + while (lonDeg >= 360.0) + lonDeg -= 360.0; + while (lonDeg < 0.0) + lonDeg += 360.0; + lons[index] = lonDeg; + lats[index] = latDeg; + /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ + } + } +} +// Oblate spheroid +static int init_oblate(grib_handle* h, + grib_iterator_lambert_conformal* self, + size_t nv, + double LoVInDegrees, + double Dx, double Dy, + double earthMinorAxisInMetres, double earthMajorAxisInMetres, + double latFirstInRadians, double lonFirstInRadians, + double LoVInRadians, double Latin1InRadians, double Latin2InRadians, + double LaDInRadians) +{ + int i, j, err = 0; + long nx, ny, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning; + double *lats, *lons; /* the lat/lon arrays to be populated */ + double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; + double latDeg, lonDeg, lonDiff; + double radius = 1; // TODO + double e = calculate_eccentricity(earthMinorAxisInMetres,earthMajorAxisInMetres); + (void)e; + + if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { + n = sin(Latin1InRadians); + } + else { + n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) / + log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); + } + + f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; + rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); + rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); + if (n < 0) /* adjustment for southern hemisphere */ + rho0 = -rho0; + lonDiff = lonFirstInRadians - LoVInRadians; + + /* Adjust longitude to range -180 to 180 */ + if (lonDiff > M_PI) + lonDiff -= 2 * M_PI; + if (lonDiff < -M_PI) + lonDiff += 2 * M_PI; + angle = n * lonDiff; + x0 = rho * sin(angle); + y0 = rho0 - rho * cos(angle); + /*Dx = iScansNegatively == 0 ? Dx : -Dx;*/ + /* GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint */ + /*Dy = jScansPositively == 1 ? Dy : -Dy;*/ + + /* Allocate latitude and longitude arrays */ + self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats = self->lats; + lons = self->lons; + + /* Populate our arrays */ + for (j = 0; j < ny; j++) { + y = y0 + j * Dy; + if (n < 0) { /* adjustment for southern hemisphere */ + y = -y; + } + tmp = rho0 - y; + tmp2 = tmp * tmp; + for (i = 0; i < nx; i++) { + int index = i + j * nx; + x = x0 + i * Dx; + if (n < 0) { /* adjustment for southern hemisphere */ + x = -x; + } + + angle = atan2(x, tmp); /* See ECC-524 */ + rho = sqrt(x * x + tmp2); + if (n <= 0) + rho = -rho; + lonDeg = LoVInDegrees + (angle / n) * RAD2DEG; + latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * RAD2DEG; + while (lonDeg >= 360.0) + lonDeg -= 360.0; + while (lonDeg < 0.0) + lonDeg += 360.0; + lons[index] = lonDeg; + lats[index] = latDeg; + /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ + } + } +} + +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) +{ + int i, j, err = 0, is_oblate = 0; + double *lats, *lons; /* the lat/lon arrays to be populated */ long nx, ny, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning; double LoVInDegrees, LaDInDegrees, Latin1InDegrees, Latin2InDegrees, latFirstInDegrees, lonFirstInDegrees, Dx, Dy, radius = 0; double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians, lonDiff, lonDeg, latDeg; + double earthMajorAxisInMetres, earthMinorAxisInMetres; double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; @@ -175,15 +357,14 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return err; if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) return err; + + is_oblate = grib_is_earth_oblate(h); - if (grib_is_earth_oblate(h)) { - double earthMajorAxisInMetres, earthMinorAxisInMetres, e; + if (is_oblate) { //grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Conformal only supported for spherical earth."); //return GRIB_GEOCALCULUS_PROBLEM; if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; - e = calculate_eccentricity(earthMinorAxisInMetres,earthMajorAxisInMetres); - (void)e; } if (iter->nv != nx * ny) { @@ -226,77 +407,22 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) Latin2InRadians = Latin2InDegrees * DEG2RAD; LaDInRadians = LaDInDegrees * DEG2RAD; LoVInRadians = LoVInDegrees * DEG2RAD; - - if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { - n = sin(Latin1InRadians); - } - else { - n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) / - log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); - } - - f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; - rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); - rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); - if (n < 0) /* adjustment for southern hemisphere */ - rho0 = -rho0; - lonDiff = lonFirstInRadians - LoVInRadians; - - /* Adjust longitude to range -180 to 180 */ - if (lonDiff > M_PI) - lonDiff -= 2 * M_PI; - if (lonDiff < -M_PI) - lonDiff += 2 * M_PI; - angle = n * lonDiff; - x0 = rho * sin(angle); - y0 = rho0 - rho * cos(angle); - /*Dx = iScansNegatively == 0 ? Dx : -Dx;*/ - /* GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint */ - /*Dy = jScansPositively == 1 ? Dy : -Dy;*/ - - /* Allocate latitude and longitude arrays */ - self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", iter->nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", iter->nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - lats = self->lats; - lons = self->lons; - - /* Populate our arrays */ - for (j = 0; j < ny; j++) { - y = y0 + j * Dy; - if (n < 0) { /* adjustment for southern hemisphere */ - y = -y; - } - tmp = rho0 - y; - tmp2 = tmp * tmp; - for (i = 0; i < nx; i++) { - int index = i + j * nx; - x = x0 + i * Dx; - if (n < 0) { /* adjustment for southern hemisphere */ - x = -x; - } - - angle = atan2(x, tmp); /* See ECC-524 */ - rho = sqrt(x * x + tmp2); - if (n <= 0) - rho = -rho; - lonDeg = LoVInDegrees + (angle / n) * RAD2DEG; - latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * RAD2DEG; - while (lonDeg >= 360.0) - lonDeg -= 360.0; - while (lonDeg < 0.0) - lonDeg += 360.0; - lons[index] = lonDeg; - lats[index] = latDeg; - /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ - } + + if (is_oblate) { + init_oblate(h, self, iter->nv, + LoVInDegrees, + Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, + latFirstInRadians, lonFirstInRadians, + LoVInRadians, Latin1InRadians, Latin2InRadians, + LaDInRadians); + } else { + init_sphere(h, self, iter->nv, + nx, ny, + LoVInDegrees, + Dx, Dy, radius, + latFirstInRadians, lonFirstInRadians, + LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians, + iScansNegatively, jScansPositively, jPointsAreConsecutive); } iter->e = -1; From cbef702df4a34745df52072a31cc356baf6bcd15 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 27 Mar 2020 17:56:21 +0000 Subject: [PATCH 047/737] ECC-1055: Shape of the earth not taken into account for Lambert Conformal Conic (part 3) --- src/grib_iterator_class_lambert_conformal.c | 80 ++++++++++----------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 057b0cedd..b78b95357 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -115,7 +115,7 @@ static int next(grib_iterator* i, double* lat, double* lon, double* val) double msfnz(double eccent, double sinphi, double cosphi) { double con = eccent * sinphi; - return((cosphi / (sqrt (1.0 - con * con)))); + return ((cosphi / (sqrt(1.0 - con * con)))); } /* Function to compute the constant small t for use in the forward @@ -123,26 +123,26 @@ double msfnz(double eccent, double sinphi, double cosphi) Stereographic projections. --------------------------------------------------------------*/ double tsfnz( - double eccent, /* Eccentricity of the spheroid */ - double phi, /* Latitude phi */ - double sinphi) /* Sine of the latitude */ + double eccent, /* Eccentricity of the spheroid */ + double phi, /* Latitude phi */ + double sinphi) /* Sine of the latitude */ { double con; double com; con = eccent * sinphi; com = .5 * eccent; - con = pow(((1.0 - con) / (1.0 + con)),com); - return (tan(.5 * (M_PI_2 - phi))/con); + con = pow(((1.0 - con) / (1.0 + con)), com); + return (tan(.5 * (M_PI_2 - phi)) / con); } static double calculate_eccentricity(double minor, double major) { double temp = minor / major; - return sqrt(1.0 - temp*temp); + return sqrt(1.0 - temp * temp); } -static int init_sphere(grib_handle* h, +static int init_sphere(grib_handle* h, grib_iterator_lambert_conformal* self, size_t nv, long nx, long ny, double LoVInDegrees, @@ -152,15 +152,14 @@ static int init_sphere(grib_handle* h, double LaDInRadians, long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) { - int i, j, err = 0; + int i, j; double *lats, *lons; /* the lat/lon arrays to be populated */ double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; double latDeg, lonDeg, lonDiff; if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { n = sin(Latin1InRadians); - } - else { + } else { n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) / log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); } @@ -228,11 +227,14 @@ static int init_sphere(grib_handle* h, /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ } } + + return GRIB_SUCCESS; } + // Oblate spheroid -static int init_oblate(grib_handle* h, +static int init_oblate(grib_handle* h, grib_iterator_lambert_conformal* self, - size_t nv, + size_t nv, long nx, long ny, double LoVInDegrees, double Dx, double Dy, double earthMinorAxisInMetres, double earthMajorAxisInMetres, @@ -240,19 +242,17 @@ static int init_oblate(grib_handle* h, double LoVInRadians, double Latin1InRadians, double Latin2InRadians, double LaDInRadians) { - int i, j, err = 0; - long nx, ny, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning; + int i, j; double *lats, *lons; /* the lat/lon arrays to be populated */ double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; double latDeg, lonDeg, lonDiff; - double radius = 1; // TODO - double e = calculate_eccentricity(earthMinorAxisInMetres,earthMajorAxisInMetres); + double radius = 1; // TODO(masn): no need + double e = calculate_eccentricity(earthMinorAxisInMetres, earthMajorAxisInMetres); (void)e; if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { n = sin(Latin1InRadians); - } - else { + } else { n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) / log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); } @@ -320,19 +320,18 @@ static int init_oblate(grib_handle* h, /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ } } + return GRIB_SUCCESS; } static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { - int i, j, err = 0, is_oblate = 0; - double *lats, *lons; /* the lat/lon arrays to be populated */ + int err = 0, is_oblate = 0; long nx, ny, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning; double LoVInDegrees, LaDInDegrees, Latin1InDegrees, Latin2InDegrees, latFirstInDegrees, lonFirstInDegrees, Dx, Dy, radius = 0; double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, - LaDInRadians, lonDiff, lonDeg, latDeg; + LaDInRadians; double earthMajorAxisInMetres, earthMinorAxisInMetres; - double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; @@ -357,12 +356,10 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return err; if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) return err; - + is_oblate = grib_is_earth_oblate(h); if (is_oblate) { - //grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Conformal only supported for spherical earth."); - //return GRIB_GEOCALCULUS_PROBLEM; if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; } @@ -407,23 +404,23 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) Latin2InRadians = Latin2InDegrees * DEG2RAD; LaDInRadians = LaDInDegrees * DEG2RAD; LoVInRadians = LoVInDegrees * DEG2RAD; - + if (is_oblate) { - init_oblate(h, self, iter->nv, - LoVInDegrees, - Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, - latFirstInRadians, lonFirstInRadians, - LoVInRadians, Latin1InRadians, Latin2InRadians, - LaDInRadians); + err = init_oblate(h, self, iter->nv, nx, ny, + LoVInDegrees, + Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, + latFirstInRadians, lonFirstInRadians, + LoVInRadians, Latin1InRadians, Latin2InRadians, + LaDInRadians); } else { - init_sphere(h, self, iter->nv, - nx, ny, - LoVInDegrees, - Dx, Dy, radius, - latFirstInRadians, lonFirstInRadians, - LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians, - iScansNegatively, jScansPositively, jPointsAreConsecutive); + err = init_sphere(h, self, iter->nv, nx, ny, + LoVInDegrees, + Dx, Dy, radius, + latFirstInRadians, lonFirstInRadians, + LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians, + iScansNegatively, jScansPositively, jPointsAreConsecutive); } + if (err) return err; iter->e = -1; @@ -431,9 +428,6 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) err = transform_iterator_data(h, iter->data, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, iter->nv, nx, ny); - if (err) - return err; - return err; } From 2739d3040ea1084046d7a3fa5d542695b2ef6295 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 27 Mar 2020 21:17:24 +0000 Subject: [PATCH 048/737] ECC-1055: Shape of the earth not taken into account for Lambert Conformal Conic (part 4) --- src/grib_iterator_class_lambert_conformal.c | 208 ++++++++++++++------ 1 file changed, 153 insertions(+), 55 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index b78b95357..b0224bc3a 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -112,12 +112,62 @@ static int next(grib_iterator* i, double* lat, double* lon, double* val) #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +static double adjust_lon(double x) +{ + /* Adjust longitude to range -180 to 180 */ + if (x > M_PI) + x -= 2 * M_PI; + if (x < -M_PI) + x += 2 * M_PI; + return x; +} + +/* Function to compute the latitude angle, phi2, for the inverse of the + Lambert Conformal Conic and Polar Stereographic projections. +----------------------------------------------------------------*/ +double phi2z(eccent,ts,flag) +double eccent; /* Spheroid eccentricity */ +double ts; /* Constant value t */ +long *flag; /* Error flag number */ + +{ + double eccnth; + double phi; + double con; + double dphi; + double sinpi; + long i; + + *flag = 0; + eccnth = .5 * eccent; + phi = M_PI_2 - 2 * atan(ts); + for (i = 0; i <= 15; i++) + { + sinpi = sin(phi); + con = eccent * sinpi; + dphi = M_PI_2 - 2 * atan(ts *(pow(((1.0 - con)/(1.0 + con)),eccnth))) - + phi; + phi += dphi; + if (fabs(dphi) <= .0000000001) + return(phi); + } + Assert (!"Convergence error"); + *flag = 002; + return(002); +} + double msfnz(double eccent, double sinphi, double cosphi) { double con = eccent * sinphi; return ((cosphi / (sqrt(1.0 - con * con)))); } +void sincos(double val, double* sin_val, double* cos_val) +{ + *sin_val = sin(val); + *cos_val = cos(val); +} + /* Function to compute the constant small t for use in the forward computations in the Lambert Conformal Conic and the Polar Stereographic projections. @@ -127,12 +177,9 @@ double tsfnz( double phi, /* Latitude phi */ double sinphi) /* Sine of the latitude */ { - double con; - double com; - - con = eccent * sinphi; - com = .5 * eccent; - con = pow(((1.0 - con) / (1.0 + con)), com); + double con = eccent * sinphi; + double com = .5 * eccent; + con = pow(((1.0 - con) / (1.0 + con)), com); return (tan(.5 * (M_PI_2 - phi)) / con); } @@ -159,7 +206,8 @@ static int init_sphere(grib_handle* h, if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { n = sin(Latin1InRadians); - } else { + } + else { n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) / log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); } @@ -231,6 +279,8 @@ static int init_sphere(grib_handle* h, return GRIB_SUCCESS; } +#define EPSILON 1.0e-10 + // Oblate spheroid static int init_oblate(grib_handle* h, grib_iterator_lambert_conformal* self, @@ -244,37 +294,69 @@ static int init_oblate(grib_handle* h, { int i, j; double *lats, *lons; /* the lat/lon arrays to be populated */ - double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; - double latDeg, lonDeg, lonDiff; - double radius = 1; // TODO(masn): no need - double e = calculate_eccentricity(earthMinorAxisInMetres, earthMajorAxisInMetres); - (void)e; - - if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { - n = sin(Latin1InRadians); - } else { - n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) / - log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); + double x0, y0, x, y; + double latDeg, lonDeg; + + double ns; /* ratio of angle between meridian*/ + double f0; /* flattening of ellipsoid */ + double rh; /* height above ellipsoid */ + double center_lon, center_lat; + double sin_po; /* sin value */ + double cos_po; /* cos value */ + double con; /* temporary variable */ + double ms1; /* small m 1 */ + double ms2; /* small m 2 */ + double ts0; /* small t 0 */ + double ts1; /* small t 1 */ + double ts2; /* small t 2 */ + + double sinphi; + double ts; + double rh1; + double theta; + + double e = calculate_eccentricity(earthMinorAxisInMetres, earthMajorAxisInMetres); + + // wgrib2 lamccfor + center_lon = LoVInRadians; + center_lat = LaDInRadians; + sincos(Latin1InRadians, &sin_po, &cos_po); + con = sin_po; + ms1 = msfnz(e, sin_po, cos_po); + ts1 = tsfnz(e, Latin2InRadians, sin_po); + sincos(Latin2InRadians, &sin_po, &cos_po); + ms2 = msfnz(e, sin_po, cos_po); + ts2 = tsfnz(e, Latin2InRadians, sin_po); + sin_po = sin(center_lat); + ts0 = tsfnz(e, center_lat, sin_po); + + if (fabs(Latin1InRadians - Latin2InRadians) > EPSILON) + ns = log(ms1 / ms2) / log(ts1 / ts2); + else + ns = con; + f0 = ms1 / (ns * pow(ts1, ns)); + rh = earthMajorAxisInMetres * f0 * pow(ts0, ns); + + // lat,lon to x,y + con = fabs(fabs(latFirstInRadians) - M_PI_2); + if (con > EPSILON) { + sinphi = sin(latFirstInRadians); + ts = tsfnz(e, latFirstInRadians, sinphi); + rh1 = earthMajorAxisInMetres * f0 * pow(ts, ns); } + else { + con = latFirstInRadians * ns; + if (con <= 0) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Point cannot be projected"); + return GRIB_GEOCALCULUS_PROBLEM; + } + rh1 = 0; + } + theta = ns * adjust_lon(lonFirstInRadians - center_lon); + x0 = rh1 * sin(theta); + y0 = rh - rh1 * cos(theta); - f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; - rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); - rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); - if (n < 0) /* adjustment for southern hemisphere */ - rho0 = -rho0; - lonDiff = lonFirstInRadians - LoVInRadians; - - /* Adjust longitude to range -180 to 180 */ - if (lonDiff > M_PI) - lonDiff -= 2 * M_PI; - if (lonDiff < -M_PI) - lonDiff += 2 * M_PI; - angle = n * lonDiff; - x0 = rho * sin(angle); - y0 = rho0 - rho * cos(angle); - /*Dx = iScansNegatively == 0 ? Dx : -Dx;*/ - /* GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint */ - /*Dy = jScansPositively == 1 ? Dy : -Dy;*/ + // reverse /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); @@ -293,28 +375,43 @@ static int init_oblate(grib_handle* h, /* Populate our arrays */ for (j = 0; j < ny; j++) { y = y0 + j * Dy; - if (n < 0) { /* adjustment for southern hemisphere */ - y = -y; - } - tmp = rho0 - y; - tmp2 = tmp * tmp; + //if (n < 0) { /* adjustment for southern hemisphere */ + // y = -y; + //} for (i = 0; i < nx; i++) { + long flag; int index = i + j * nx; x = x0 + i * Dx; - if (n < 0) { /* adjustment for southern hemisphere */ - x = -x; + //if (n < 0) { /* adjustment for southern hemisphere */ + // x = -x; + //} + + // from x,y to lat,lon + flag = 0; + y = rh - y; + if (ns > 0) { + rh1 = sqrt(x * x + y * y); + con = 1.0; } - - angle = atan2(x, tmp); /* See ECC-524 */ - rho = sqrt(x * x + tmp2); - if (n <= 0) - rho = -rho; - lonDeg = LoVInDegrees + (angle / n) * RAD2DEG; - latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * RAD2DEG; - while (lonDeg >= 360.0) - lonDeg -= 360.0; - while (lonDeg < 0.0) - lonDeg += 360.0; + else { + rh1 = -sqrt(x * x + y * y); + con = -1.0; + } + theta = 0.0; + if (rh1 != 0) + theta = atan2((con * x), (con * y)); + if ((rh1 != 0) || (ns > 0.0)) { + con = 1.0 / ns; + ts = pow((rh1 / (earthMajorAxisInMetres * f0)), con); + latDeg = phi2z(e, ts, &flag); + if (flag != 0) + return (flag); + } else { + latDeg = -M_PI_2; + } + lonDeg = adjust_lon(theta / ns + center_lon); + while (lonDeg >= 360.0) lonDeg -= 360.0; + while (lonDeg < 0.0) lonDeg += 360.0; lons[index] = lonDeg; lats[index] = latDeg; /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ @@ -412,7 +509,8 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians); - } else { + } + else { err = init_sphere(h, self, iter->nv, nx, ny, LoVInDegrees, Dx, Dy, radius, From cd1fa6b089e37e2fa1f0fcf41795fe2f32f81771 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 28 Mar 2020 14:21:05 +0000 Subject: [PATCH 049/737] ECC-1055: Clean up --- src/grib_iterator_class_lambert_conformal.c | 180 ++++++++------------ 1 file changed, 69 insertions(+), 111 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index b0224bc3a..db2dec665 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -112,80 +112,62 @@ static int next(grib_iterator* i, double* lat, double* lon, double* val) #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +/* Adjust longitude to range -180 to 180 */ static double adjust_lon(double x) { - /* Adjust longitude to range -180 to 180 */ - if (x > M_PI) - x -= 2 * M_PI; - if (x < -M_PI) - x += 2 * M_PI; + if (x > M_PI) x -= 2 * M_PI; + if (x < -M_PI) x += 2 * M_PI; return x; } -/* Function to compute the latitude angle, phi2, for the inverse of the - Lambert Conformal Conic and Polar Stereographic projections. -----------------------------------------------------------------*/ -double phi2z(eccent,ts,flag) -double eccent; /* Spheroid eccentricity */ -double ts; /* Constant value t */ -long *flag; /* Error flag number */ - +/* Function to compute the latitude angle, phi2, for the inverse */ +double phi2z( + double eccent, /* Spheroid eccentricity */ + double ts, /* Constant value t */ + int* error) { - double eccnth; - double phi; - double con; - double dphi; - double sinpi; - long i; - - *flag = 0; - eccnth = .5 * eccent; + double eccnth, phi, con, dphi, sinpi; + int i, MAX_ITER = 15; + + eccnth = 0.5 * eccent; phi = M_PI_2 - 2 * atan(ts); - for (i = 0; i <= 15; i++) - { + for (i = 0; i <= MAX_ITER; i++) { sinpi = sin(phi); con = eccent * sinpi; - dphi = M_PI_2 - 2 * atan(ts *(pow(((1.0 - con)/(1.0 + con)),eccnth))) - - phi; + dphi = M_PI_2 - 2 * atan(ts *(pow(((1.0 - con)/(1.0 + con)),eccnth))) - phi; phi += dphi; if (fabs(dphi) <= .0000000001) return(phi); } - Assert (!"Convergence error"); - *flag = 002; - return(002); + /*Assert(!"Convergence error");*/ + *error = GRIB_INTERNAL_ERROR; + return 0; } +/* Compute the constant small m which is the radius of + a parallel of latitude, phi, divided by the semimajor axis */ double msfnz(double eccent, double sinphi, double cosphi) { - double con = eccent * sinphi; + const double con = eccent * sinphi; return ((cosphi / (sqrt(1.0 - con * con)))); } -void sincos(double val, double* sin_val, double* cos_val) -{ - *sin_val = sin(val); - *cos_val = cos(val); -} - -/* Function to compute the constant small t for use in the forward - computations in the Lambert Conformal Conic and the Polar - Stereographic projections. ---------------------------------------------------------------*/ +/* Compute the constant small t for use in the forward + computations */ double tsfnz( double eccent, /* Eccentricity of the spheroid */ double phi, /* Latitude phi */ double sinphi) /* Sine of the latitude */ { double con = eccent * sinphi; - double com = .5 * eccent; + double com = 0.5 * eccent; con = pow(((1.0 - con) / (1.0 + con)), com); - return (tan(.5 * (M_PI_2 - phi)) / con); + return (tan(0.5 * (M_PI_2 - phi)) / con); } static double calculate_eccentricity(double minor, double major) { - double temp = minor / major; + const double temp = minor / major; return sqrt(1.0 - temp * temp); } @@ -200,7 +182,6 @@ static int init_sphere(grib_handle* h, long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) { int i, j; - double *lats, *lons; /* the lat/lon arrays to be populated */ double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; double latDeg, lonDeg, lonDiff; @@ -242,8 +223,6 @@ static int init_sphere(grib_handle* h, grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } - lats = self->lats; - lons = self->lons; /* Populate our arrays */ for (j = 0; j < ny; j++) { @@ -270,8 +249,8 @@ static int init_sphere(grib_handle* h, lonDeg -= 360.0; while (lonDeg < 0.0) lonDeg += 360.0; - lons[index] = lonDeg; - lats[index] = latDeg; + self->lons[index] = lonDeg; + self->lats[index] = latDeg; /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ } } @@ -281,7 +260,7 @@ static int init_sphere(grib_handle* h, #define EPSILON 1.0e-10 -// Oblate spheroid +/* Oblate spheroid */ static int init_oblate(grib_handle* h, grib_iterator_lambert_conformal* self, size_t nv, long nx, long ny, @@ -292,59 +271,50 @@ static int init_oblate(grib_handle* h, double LoVInRadians, double Latin1InRadians, double Latin2InRadians, double LaDInRadians) { - int i, j; - double *lats, *lons; /* the lat/lon arrays to be populated */ - double x0, y0, x, y; - double latDeg, lonDeg; - - double ns; /* ratio of angle between meridian*/ - double f0; /* flattening of ellipsoid */ - double rh; /* height above ellipsoid */ - double center_lon, center_lat; - double sin_po; /* sin value */ - double cos_po; /* cos value */ - double con; /* temporary variable */ - double ms1; /* small m 1 */ - double ms2; /* small m 2 */ - double ts0; /* small t 0 */ - double ts1; /* small t 1 */ - double ts2; /* small t 2 */ - - double sinphi; - double ts; - double rh1; - double theta; + int i, j, err = 0; + double x0, y0, x, y, latDeg, lonDeg, sinphi, ts, rh1, theta; + + double ns; /* ratio of angle between meridian */ + double f0; /* flattening of ellipsoid */ + double rh; /* height above ellipsoid */ + double sin_po; /* sin value */ + double cos_po; /* cos value */ + double con; /* temporary variable */ + double ms1; /* small m 1 */ + double ms2; /* small m 2 */ + double ts0; /* small t 0 */ + double ts1; /* small t 1 */ + double ts2; /* small t 2 */ double e = calculate_eccentricity(earthMinorAxisInMetres, earthMajorAxisInMetres); - // wgrib2 lamccfor - center_lon = LoVInRadians; - center_lat = LaDInRadians; - sincos(Latin1InRadians, &sin_po, &cos_po); - con = sin_po; - ms1 = msfnz(e, sin_po, cos_po); - ts1 = tsfnz(e, Latin2InRadians, sin_po); - sincos(Latin2InRadians, &sin_po, &cos_po); + sin_po = sin(Latin1InRadians); + cos_po = cos(Latin1InRadians); + con = sin_po; + ms1 = msfnz(e, sin_po, cos_po); + ts1 = tsfnz(e, Latin2InRadians, sin_po); + sin_po = sin(Latin2InRadians); + cos_po = cos(Latin2InRadians); ms2 = msfnz(e, sin_po, cos_po); ts2 = tsfnz(e, Latin2InRadians, sin_po); - sin_po = sin(center_lat); - ts0 = tsfnz(e, center_lat, sin_po); + sin_po = sin(LaDInRadians); + ts0 = tsfnz(e, LaDInRadians, sin_po); - if (fabs(Latin1InRadians - Latin2InRadians) > EPSILON) + if (fabs(Latin1InRadians - Latin2InRadians) > EPSILON) { ns = log(ms1 / ms2) / log(ts1 / ts2); - else + } else { ns = con; + } f0 = ms1 / (ns * pow(ts1, ns)); rh = earthMajorAxisInMetres * f0 * pow(ts0, ns); - // lat,lon to x,y + /* lat,lon to x,y */ con = fabs(fabs(latFirstInRadians) - M_PI_2); if (con > EPSILON) { sinphi = sin(latFirstInRadians); ts = tsfnz(e, latFirstInRadians, sinphi); rh1 = earthMajorAxisInMetres * f0 * pow(ts, ns); - } - else { + } else { con = latFirstInRadians * ns; if (con <= 0) { grib_context_log(h->context, GRIB_LOG_ERROR, "Point cannot be projected"); @@ -352,12 +322,10 @@ static int init_oblate(grib_handle* h, } rh1 = 0; } - theta = ns * adjust_lon(lonFirstInRadians - center_lon); + theta = ns * adjust_lon(lonFirstInRadians - LoVInRadians); x0 = rh1 * sin(theta); y0 = rh - rh1 * cos(theta); - // reverse - /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { @@ -369,31 +337,19 @@ static int init_oblate(grib_handle* h, grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } - lats = self->lats; - lons = self->lons; /* Populate our arrays */ for (j = 0; j < ny; j++) { y = y0 + j * Dy; - //if (n < 0) { /* adjustment for southern hemisphere */ - // y = -y; - //} for (i = 0; i < nx; i++) { - long flag; - int index = i + j * nx; - x = x0 + i * Dx; - //if (n < 0) { /* adjustment for southern hemisphere */ - // x = -x; - //} - - // from x,y to lat,lon - flag = 0; + const int index = i + j * nx; + x = x0 + i * Dx; + /* from x,y to lat,lon */ y = rh - y; if (ns > 0) { rh1 = sqrt(x * x + y * y); con = 1.0; - } - else { + } else { rh1 = -sqrt(x * x + y * y); con = -1.0; } @@ -403,17 +359,19 @@ static int init_oblate(grib_handle* h, if ((rh1 != 0) || (ns > 0.0)) { con = 1.0 / ns; ts = pow((rh1 / (earthMajorAxisInMetres * f0)), con); - latDeg = phi2z(e, ts, &flag); - if (flag != 0) - return (flag); + latDeg = phi2z(e, ts, &err); + if (err) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Failed to compute the latitude angle, phi2, for the inverse"); + return err; + } } else { latDeg = -M_PI_2; } - lonDeg = adjust_lon(theta / ns + center_lon); + lonDeg = adjust_lon(theta / ns + LoVInRadians); while (lonDeg >= 360.0) lonDeg -= 360.0; while (lonDeg < 0.0) lonDeg += 360.0; - lons[index] = lonDeg; - lats[index] = latDeg; + self->lons[index] = lonDeg; + self->lats[index] = latDeg; /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ } } From f2bbe0a8a406201398b8f7ca8fdb0e4fd45a6ca4 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 28 Mar 2020 17:52:19 +0000 Subject: [PATCH 050/737] ECC-1055: Shape of the earth not taken into account for Lambert Conformal Conic (part 5) --- src/grib_iterator_class_lambert_conformal.c | 99 ++++++++++++--------- 1 file changed, 57 insertions(+), 42 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index db2dec665..9510efe69 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -82,20 +82,7 @@ static void init_class(grib_iterator_class* c) } /* END_CLASS_IMP */ -static int next(grib_iterator* i, double* lat, double* lon, double* val) -{ - grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; - - if ((long)i->e >= (long)(i->nv - 1)) - return 0; - i->e++; - - *lat = self->lats[i->e]; - *lon = self->lons[i->e]; - *val = i->data[i->e]; - - return 1; -} +#define EPSILON 1.0e-10 #ifndef M_PI #define M_PI 3.14159265358979323846 /* Whole pie */ @@ -112,12 +99,12 @@ static int next(grib_iterator* i, double* lat, double* lon, double* val) #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ -/* Adjust longitude to range -180 to 180 */ -static double adjust_lon(double x) +/* Adjust longitude (in radians) to range -180 to 180 */ +static double adjust_lon_radians(double lon) { - if (x > M_PI) x -= 2 * M_PI; - if (x < -M_PI) x += 2 * M_PI; - return x; + if (lon > M_PI) lon -= 2 * M_PI; + if (lon < -M_PI) lon += 2 * M_PI; + return lon; } /* Function to compute the latitude angle, phi2, for the inverse */ @@ -130,14 +117,14 @@ double phi2z( int i, MAX_ITER = 15; eccnth = 0.5 * eccent; - phi = M_PI_2 - 2 * atan(ts); + phi = M_PI_2 - 2 * atan(ts); for (i = 0; i <= MAX_ITER; i++) { sinpi = sin(phi); - con = eccent * sinpi; - dphi = M_PI_2 - 2 * atan(ts *(pow(((1.0 - con)/(1.0 + con)),eccnth))) - phi; + con = eccent * sinpi; + dphi = M_PI_2 - 2 * atan(ts * (pow(((1.0 - con) / (1.0 + con)), eccnth))) - phi; phi += dphi; if (fabs(dphi) <= .0000000001) - return(phi); + return (phi); } /*Assert(!"Convergence error");*/ *error = GRIB_INTERNAL_ERROR; @@ -245,10 +232,8 @@ static int init_sphere(grib_handle* h, rho = -rho; lonDeg = LoVInDegrees + (angle / n) * RAD2DEG; latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * RAD2DEG; - while (lonDeg >= 360.0) - lonDeg -= 360.0; - while (lonDeg < 0.0) - lonDeg += 360.0; + while (lonDeg >= 360.0) lonDeg -= 360.0; + while (lonDeg < 0.0) lonDeg += 360.0; self->lons[index] = lonDeg; self->lats[index] = latDeg; /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ @@ -258,8 +243,6 @@ static int init_sphere(grib_handle* h, return GRIB_SUCCESS; } -#define EPSILON 1.0e-10 - /* Oblate spheroid */ static int init_oblate(grib_handle* h, grib_iterator_lambert_conformal* self, @@ -292,7 +275,8 @@ static int init_oblate(grib_handle* h, cos_po = cos(Latin1InRadians); con = sin_po; ms1 = msfnz(e, sin_po, cos_po); - ts1 = tsfnz(e, Latin2InRadians, sin_po); + ts1 = tsfnz(e, Latin1InRadians, sin_po); + sin_po = sin(Latin2InRadians); cos_po = cos(Latin2InRadians); ms2 = msfnz(e, sin_po, cos_po); @@ -302,7 +286,8 @@ static int init_oblate(grib_handle* h, if (fabs(Latin1InRadians - Latin2InRadians) > EPSILON) { ns = log(ms1 / ms2) / log(ts1 / ts2); - } else { + } + else { ns = con; } f0 = ms1 / (ns * pow(ts1, ns)); @@ -314,7 +299,8 @@ static int init_oblate(grib_handle* h, sinphi = sin(latFirstInRadians); ts = tsfnz(e, latFirstInRadians, sinphi); rh1 = earthMajorAxisInMetres * f0 * pow(ts, ns); - } else { + } + else { con = latFirstInRadians * ns; if (con <= 0) { grib_context_log(h->context, GRIB_LOG_ERROR, "Point cannot be projected"); @@ -322,9 +308,11 @@ static int init_oblate(grib_handle* h, } rh1 = 0; } - theta = ns * adjust_lon(lonFirstInRadians - LoVInRadians); + theta = ns * adjust_lon_radians(lonFirstInRadians - LoVInRadians); x0 = rh1 * sin(theta); y0 = rh - rh1 * cos(theta); + x0 = -x0; + y0 = -y0; /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); @@ -343,13 +331,14 @@ static int init_oblate(grib_handle* h, y = y0 + j * Dy; for (i = 0; i < nx; i++) { const int index = i + j * nx; - x = x0 + i * Dx; + x = x0 + i * Dx; /* from x,y to lat,lon */ y = rh - y; if (ns > 0) { rh1 = sqrt(x * x + y * y); con = 1.0; - } else { + } + else { rh1 = -sqrt(x * x + y * y); con = -1.0; } @@ -357,22 +346,26 @@ static int init_oblate(grib_handle* h, if (rh1 != 0) theta = atan2((con * x), (con * y)); if ((rh1 != 0) || (ns > 0.0)) { - con = 1.0 / ns; - ts = pow((rh1 / (earthMajorAxisInMetres * f0)), con); + con = 1.0 / ns; + ts = pow((rh1 / (earthMajorAxisInMetres * f0)), con); latDeg = phi2z(e, ts, &err); if (err) { grib_context_log(h->context, GRIB_LOG_ERROR, "Failed to compute the latitude angle, phi2, for the inverse"); return err; } - } else { + } + else { latDeg = -M_PI_2; } - lonDeg = adjust_lon(theta / ns + LoVInRadians); + lonDeg = adjust_lon_radians(theta / ns + LoVInRadians); + // Convert to degrees + latDeg *= RAD2DEG; + lonDeg *= RAD2DEG; while (lonDeg >= 360.0) lonDeg -= 360.0; while (lonDeg < 0.0) lonDeg += 360.0; self->lons[index] = lonDeg; self->lats[index] = latDeg; - /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ + //printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index, self->lats[index], index, self->lons[index]); } } return GRIB_SUCCESS; @@ -417,14 +410,15 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) if (is_oblate) { if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; + } else { + if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) return err; } if (iter->nv != nx * ny) { grib_context_log(h->context, GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); return GRIB_WRONG_GRID; } - if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) - return err; + if ((err = grib_get_double_internal(h, sLoVInDegrees, &LoVInDegrees)) != GRIB_SUCCESS) return err; if ((err = grib_get_double_internal(h, sLaDInDegrees, &LaDInDegrees)) != GRIB_SUCCESS) @@ -450,6 +444,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) if ((err = grib_get_long_internal(h, salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) return err; + /* Standard Parallels cannot be equal and on opposite sides of the equator */ + if (fabs(Latin1InDegrees + Latin2InDegrees) < EPSILON) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Cannot have equal latitudes for standard parallels on opposite sides of equator"); + return GRIB_WRONG_GRID; + } + /* * See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html */ @@ -487,6 +487,21 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return err; } +static int next(grib_iterator* i, double* lat, double* lon, double* val) +{ + grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; + + if ((long)i->e >= (long)(i->nv - 1)) + return 0; + i->e++; + + *lat = self->lats[i->e]; + *lon = self->lons[i->e]; + *val = i->data[i->e]; + + return 1; +} + static int destroy(grib_iterator* i) { grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; From 041290c11afb3bbae3c5ec9ba6235ac59b69ca36 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 28 Mar 2020 20:30:00 +0000 Subject: [PATCH 051/737] ECC-1055: First working version --- src/grib_iterator_class_lambert_conformal.c | 51 ++++++++++----------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 9510efe69..62174a373 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -225,18 +225,15 @@ static int init_sphere(grib_handle* h, if (n < 0) { /* adjustment for southern hemisphere */ x = -x; } - angle = atan2(x, tmp); /* See ECC-524 */ rho = sqrt(x * x + tmp2); - if (n <= 0) - rho = -rho; + if (n <= 0) rho = -rho; lonDeg = LoVInDegrees + (angle / n) * RAD2DEG; latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * RAD2DEG; while (lonDeg >= 360.0) lonDeg -= 360.0; while (lonDeg < 0.0) lonDeg += 360.0; self->lons[index] = lonDeg; self->lats[index] = latDeg; - /*printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index,lats[index], index,lons[index]);*/ } } @@ -255,7 +252,9 @@ static int init_oblate(grib_handle* h, double LaDInRadians) { int i, j, err = 0; - double x0, y0, x, y, latDeg, lonDeg, sinphi, ts, rh1, theta; + double x0, y0, x, y, latRad, lonRad, latDeg, lonDeg, sinphi, ts, rh1, theta; + double false_easting; /* x offset in meters */ + double false_northing; /* y offset in meters */ double ns; /* ratio of angle between meridian */ double f0; /* flattening of ellipsoid */ @@ -293,7 +292,7 @@ static int init_oblate(grib_handle* h, f0 = ms1 / (ns * pow(ts1, ns)); rh = earthMajorAxisInMetres * f0 * pow(ts0, ns); - /* lat,lon to x,y */ + /* Forward projection: convert lat,lon to x,y */ con = fabs(fabs(latFirstInRadians) - M_PI_2); if (con > EPSILON) { sinphi = sin(latFirstInRadians); @@ -311,8 +310,8 @@ static int init_oblate(grib_handle* h, theta = ns * adjust_lon_radians(lonFirstInRadians - LoVInRadians); x0 = rh1 * sin(theta); y0 = rh - rh1 * cos(theta); - x0 = -x0; - y0 = -y0; + x0 = -x0; + y0 = -y0; /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); @@ -327,45 +326,45 @@ static int init_oblate(grib_handle* h, } /* Populate our arrays */ + false_easting = x0; + false_northing = y0; for (j = 0; j < ny; j++) { - y = y0 + j * Dy; + y = j * Dy; for (i = 0; i < nx; i++) { const int index = i + j * nx; - x = x0 + i * Dx; - /* from x,y to lat,lon */ - y = rh - y; + double _x, _y; + x = i * Dx; + /* Inverse projection to convert from x,y to lat,lon */ + _x = x - false_easting; + _y = rh - y + false_northing; if (ns > 0) { - rh1 = sqrt(x * x + y * y); + rh1 = sqrt(_x * _x + _y * _y); con = 1.0; - } - else { - rh1 = -sqrt(x * x + y * y); + } else { + rh1 = -sqrt(_x * _x + _y * _y); con = -1.0; } theta = 0.0; if (rh1 != 0) - theta = atan2((con * x), (con * y)); + theta = atan2((con * _x), (con * _y)); if ((rh1 != 0) || (ns > 0.0)) { con = 1.0 / ns; ts = pow((rh1 / (earthMajorAxisInMetres * f0)), con); - latDeg = phi2z(e, ts, &err); + latRad = phi2z(e, ts, &err); if (err) { grib_context_log(h->context, GRIB_LOG_ERROR, "Failed to compute the latitude angle, phi2, for the inverse"); return err; } + } else { + latRad = -M_PI_2; } - else { - latDeg = -M_PI_2; - } - lonDeg = adjust_lon_radians(theta / ns + LoVInRadians); - // Convert to degrees - latDeg *= RAD2DEG; - lonDeg *= RAD2DEG; + lonRad = adjust_lon_radians(theta / ns + LoVInRadians); + latDeg = latRad * RAD2DEG; /* Convert to degrees */ + lonDeg = lonRad * RAD2DEG; while (lonDeg >= 360.0) lonDeg -= 360.0; while (lonDeg < 0.0) lonDeg += 360.0; self->lons[index] = lonDeg; self->lats[index] = latDeg; - //printf("DBK: llat[%d] = %g \t llon[%d] = %g\n", index, self->lats[index], index, self->lons[index]); } } return GRIB_SUCCESS; From 596bfecfa08234b41432f24b32a242a18185802d Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 28 Mar 2020 21:11:26 +0000 Subject: [PATCH 052/737] ECC-1055: Clean up --- src/grib_iterator_class_lambert_conformal.c | 29 +++++++++------------ 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 62174a373..facc58ac9 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -126,7 +126,6 @@ double phi2z( if (fabs(dphi) <= .0000000001) return (phi); } - /*Assert(!"Convergence error");*/ *error = GRIB_INTERNAL_ERROR; return 0; } @@ -139,8 +138,7 @@ double msfnz(double eccent, double sinphi, double cosphi) return ((cosphi / (sqrt(1.0 - con * con)))); } -/* Compute the constant small t for use in the forward - computations */ +/* Compute the constant small t for use in the forward computations */ double tsfnz( double eccent, /* Eccentricity of the spheroid */ double phi, /* Latitude phi */ @@ -174,8 +172,7 @@ static int init_sphere(grib_handle* h, if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { n = sin(Latin1InRadians); - } - else { + } else { n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) / log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); } @@ -285,8 +282,7 @@ static int init_oblate(grib_handle* h, if (fabs(Latin1InRadians - Latin2InRadians) > EPSILON) { ns = log(ms1 / ms2) / log(ts1 / ts2); - } - else { + } else { ns = con; } f0 = ms1 / (ns * pow(ts1, ns)); @@ -298,8 +294,7 @@ static int init_oblate(grib_handle* h, sinphi = sin(latFirstInRadians); ts = tsfnz(e, latFirstInRadians, sinphi); rh1 = earthMajorAxisInMetres * f0 * pow(ts, ns); - } - else { + } else { con = latFirstInRadians * ns; if (con <= 0) { grib_context_log(h->context, GRIB_LOG_ERROR, "Point cannot be projected"); @@ -353,6 +348,8 @@ static int init_oblate(grib_handle* h, latRad = phi2z(e, ts, &err); if (err) { grib_context_log(h->context, GRIB_LOG_ERROR, "Failed to compute the latitude angle, phi2, for the inverse"); + grib_context_free(h->context, self->lats); + grib_context_free(h->context, self->lons); return err; } } else { @@ -399,16 +396,14 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); - if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) - return err; + if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) return err; + if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) return err; is_oblate = grib_is_earth_oblate(h); if (is_oblate) { - if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; + if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; } else { if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) return err; } @@ -445,7 +440,8 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) /* Standard Parallels cannot be equal and on opposite sides of the equator */ if (fabs(Latin1InDegrees + Latin2InDegrees) < EPSILON) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Cannot have equal latitudes for standard parallels on opposite sides of equator"); + grib_context_log(h->context, GRIB_LOG_ERROR, + "Cannot have equal latitudes for standard parallels on opposite sides of equator"); return GRIB_WRONG_GRID; } @@ -466,8 +462,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians); - } - else { + } else { err = init_sphere(h, self, iter->nv, nx, ny, LoVInDegrees, Dx, Dy, radius, From ec3e1a4771cd8b83575e0b3053c5b78be722f5d3 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sun, 29 Mar 2020 13:00:14 +0100 Subject: [PATCH 053/737] ECC-1055: Clean up --- src/grib_iterator_class_lambert_conformal.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index facc58ac9..65662e7b9 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -108,7 +108,7 @@ static double adjust_lon_radians(double lon) } /* Function to compute the latitude angle, phi2, for the inverse */ -double phi2z( +static double compute_phi2( double eccent, /* Spheroid eccentricity */ double ts, /* Constant value t */ int* error) @@ -132,14 +132,14 @@ double phi2z( /* Compute the constant small m which is the radius of a parallel of latitude, phi, divided by the semimajor axis */ -double msfnz(double eccent, double sinphi, double cosphi) +static double compute_m(double eccent, double sinphi, double cosphi) { const double con = eccent * sinphi; return ((cosphi / (sqrt(1.0 - con * con)))); } /* Compute the constant small t for use in the forward computations */ -double tsfnz( +static double compute_t( double eccent, /* Eccentricity of the spheroid */ double phi, /* Latitude phi */ double sinphi) /* Sine of the latitude */ @@ -270,15 +270,15 @@ static int init_oblate(grib_handle* h, sin_po = sin(Latin1InRadians); cos_po = cos(Latin1InRadians); con = sin_po; - ms1 = msfnz(e, sin_po, cos_po); - ts1 = tsfnz(e, Latin1InRadians, sin_po); + ms1 = compute_m(e, sin_po, cos_po); + ts1 = compute_t(e, Latin1InRadians, sin_po); sin_po = sin(Latin2InRadians); cos_po = cos(Latin2InRadians); - ms2 = msfnz(e, sin_po, cos_po); - ts2 = tsfnz(e, Latin2InRadians, sin_po); + ms2 = compute_m(e, sin_po, cos_po); + ts2 = compute_t(e, Latin2InRadians, sin_po); sin_po = sin(LaDInRadians); - ts0 = tsfnz(e, LaDInRadians, sin_po); + ts0 = compute_t(e, LaDInRadians, sin_po); if (fabs(Latin1InRadians - Latin2InRadians) > EPSILON) { ns = log(ms1 / ms2) / log(ts1 / ts2); @@ -292,7 +292,7 @@ static int init_oblate(grib_handle* h, con = fabs(fabs(latFirstInRadians) - M_PI_2); if (con > EPSILON) { sinphi = sin(latFirstInRadians); - ts = tsfnz(e, latFirstInRadians, sinphi); + ts = compute_t(e, latFirstInRadians, sinphi); rh1 = earthMajorAxisInMetres * f0 * pow(ts, ns); } else { con = latFirstInRadians * ns; @@ -345,7 +345,7 @@ static int init_oblate(grib_handle* h, if ((rh1 != 0) || (ns > 0.0)) { con = 1.0 / ns; ts = pow((rh1 / (earthMajorAxisInMetres * f0)), con); - latRad = phi2z(e, ts, &err); + latRad = compute_phi2(e, ts, &err); if (err) { grib_context_log(h->context, GRIB_LOG_ERROR, "Failed to compute the latitude angle, phi2, for the inverse"); grib_context_free(h->context, self->lats); From 5091445e3f04fe08864582aa60bc0b68b9c8b0b3 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 31 Mar 2020 14:08:46 +0100 Subject: [PATCH 054/737] ECC-1055: Add reference to Map Projections book --- src/grib_iterator_class_lambert_conformal.c | 35 ++++++++++++--------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 65662e7b9..62a773847 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -107,8 +107,14 @@ static double adjust_lon_radians(double lon) return lon; } -/* Function to compute the latitude angle, phi2, for the inverse */ -static double compute_phi2( +/* Function to compute the latitude angle, phi2, for the inverse + * From the book "Map Projections-A Working Manual-John P. Snyder (1987)" + * Equation (7–9) involves rapidly converging iteration: Calculate t from (15-11) + * Then, assuming an initial trial phi equal to (pi/2 - 2*arctan t) in the right side of equation (7–9), + * calculate phi on the left side. Substitute the calculated phi) into the right side, + * calculate a new phi, etc., until phi does not change significantly from the preceding trial value of phi + */ +static double compute_phi( double eccent, /* Spheroid eccentricity */ double ts, /* Constant value t */ int* error) @@ -123,7 +129,7 @@ static double compute_phi2( con = eccent * sinpi; dphi = M_PI_2 - 2 * atan(ts * (pow(((1.0 - con) / (1.0 + con)), eccnth))) - phi; phi += dphi; - if (fabs(dphi) <= .0000000001) + if (fabs(dphi) <= 0.0000000001) return (phi); } *error = GRIB_INTERNAL_ERROR; @@ -254,7 +260,7 @@ static int init_oblate(grib_handle* h, double false_northing; /* y offset in meters */ double ns; /* ratio of angle between meridian */ - double f0; /* flattening of ellipsoid */ + double F; /* flattening of ellipsoid */ double rh; /* height above ellipsoid */ double sin_po; /* sin value */ double cos_po; /* cos value */ @@ -285,15 +291,15 @@ static int init_oblate(grib_handle* h, } else { ns = con; } - f0 = ms1 / (ns * pow(ts1, ns)); - rh = earthMajorAxisInMetres * f0 * pow(ts0, ns); + F = ms1 / (ns * pow(ts1, ns)); + rh = earthMajorAxisInMetres * F * pow(ts0, ns); /* Forward projection: convert lat,lon to x,y */ con = fabs(fabs(latFirstInRadians) - M_PI_2); if (con > EPSILON) { sinphi = sin(latFirstInRadians); ts = compute_t(e, latFirstInRadians, sinphi); - rh1 = earthMajorAxisInMetres * f0 * pow(ts, ns); + rh1 = earthMajorAxisInMetres * F * pow(ts, ns); } else { con = latFirstInRadians * ns; if (con <= 0) { @@ -332,20 +338,19 @@ static int init_oblate(grib_handle* h, /* Inverse projection to convert from x,y to lat,lon */ _x = x - false_easting; _y = rh - y + false_northing; - if (ns > 0) { - rh1 = sqrt(_x * _x + _y * _y); - con = 1.0; - } else { - rh1 = -sqrt(_x * _x + _y * _y); - con = -1.0; + rh1 = sqrt(_x * _x + _y * _y); + con = 1.0; + if (ns <= 0) { + rh1 = -rh1; + con = -con; } theta = 0.0; if (rh1 != 0) theta = atan2((con * _x), (con * _y)); if ((rh1 != 0) || (ns > 0.0)) { con = 1.0 / ns; - ts = pow((rh1 / (earthMajorAxisInMetres * f0)), con); - latRad = compute_phi2(e, ts, &err); + ts = pow((rh1 / (earthMajorAxisInMetres * F)), con); + latRad = compute_phi(e, ts, &err); if (err) { grib_context_log(h->context, GRIB_LOG_ERROR, "Failed to compute the latitude angle, phi2, for the inverse"); grib_context_free(h->context, self->lats); From b68b18c161925bc483ca3f44159b4b1fb0f686f8 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 31 Mar 2020 15:00:14 +0100 Subject: [PATCH 055/737] Refactoring: utility function to normalise longitudes --- src/grib_iterator_class_lambert_conformal.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 62a773847..399c46200 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -233,8 +233,7 @@ static int init_sphere(grib_handle* h, if (n <= 0) rho = -rho; lonDeg = LoVInDegrees + (angle / n) * RAD2DEG; latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * RAD2DEG; - while (lonDeg >= 360.0) lonDeg -= 360.0; - while (lonDeg < 0.0) lonDeg += 360.0; + lonDeg = normalise_longitude(lonDeg); self->lons[index] = lonDeg; self->lats[index] = latDeg; } @@ -363,8 +362,7 @@ static int init_oblate(grib_handle* h, lonRad = adjust_lon_radians(theta / ns + LoVInRadians); latDeg = latRad * RAD2DEG; /* Convert to degrees */ lonDeg = lonRad * RAD2DEG; - while (lonDeg >= 360.0) lonDeg -= 360.0; - while (lonDeg < 0.0) lonDeg += 360.0; + lonDeg = normalise_longitude(lonDeg); self->lons[index] = lonDeg; self->lats[index] = latDeg; } From e6193c1bd81af1abb3efcb28589d6528da1b1f8c Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 31 Mar 2020 16:38:00 +0100 Subject: [PATCH 056/737] Rename function --- src/grib_iterator_class_lambert_conformal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 399c46200..a64ec1514 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -233,7 +233,7 @@ static int init_sphere(grib_handle* h, if (n <= 0) rho = -rho; lonDeg = LoVInDegrees + (angle / n) * RAD2DEG; latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * RAD2DEG; - lonDeg = normalise_longitude(lonDeg); + lonDeg = normalise_longitude_in_degrees(lonDeg); self->lons[index] = lonDeg; self->lats[index] = latDeg; } @@ -362,7 +362,7 @@ static int init_oblate(grib_handle* h, lonRad = adjust_lon_radians(theta / ns + LoVInRadians); latDeg = latRad * RAD2DEG; /* Convert to degrees */ lonDeg = lonRad * RAD2DEG; - lonDeg = normalise_longitude(lonDeg); + lonDeg = normalise_longitude_in_degrees(lonDeg); self->lons[index] = lonDeg; self->lats[index] = latDeg; } From bdd04417ad1559a02d088f9bea44bbc600e30b57 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Thu, 30 Apr 2020 15:57:21 +0100 Subject: [PATCH 057/737] Clang 9.0.1 warnings --- src/grib_iterator_class_lambert_conformal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index a64ec1514..f1c9b1098 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -378,7 +378,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) lonFirstInDegrees, Dx, Dy, radius = 0; double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians; - double earthMajorAxisInMetres, earthMinorAxisInMetres; + double earthMajorAxisInMetres=0, earthMinorAxisInMetres=0; grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; From 0757e7945ab33780c2a4560515816df0aebd326d Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sun, 17 May 2020 19:51:40 +0100 Subject: [PATCH 058/737] Error messages --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 4 ++-- src/grib_iterator_class_lambert_conformal.c | 8 ++++---- src/grib_iterator_class_polar_stereographic.c | 4 ++-- src/grib_iterator_class_space_view.c | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 2a5fb80cc..73290b326 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -190,13 +190,13 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { grib_context_log(h->context, GRIB_LOG_ERROR, - "unable to allocate %ld bytes", iter->nv * sizeof(double)); + "Error allocating %ld bytes", iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { grib_context_log(h->context, GRIB_LOG_ERROR, - "unable to allocate %ld bytes", iter->nv * sizeof(double)); + "Error allocating %ld bytes", iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } lats = self->lats; diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index f1c9b1098..eb05b7fa6 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -205,12 +205,12 @@ static int init_sphere(grib_handle* h, /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } @@ -316,12 +316,12 @@ static int init_oblate(grib_handle* h, /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Unable to allocate %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 93b2cd660..f0f8a606d 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -242,12 +242,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "unable to allocate %ld bytes", iter->nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "unable to allocate %ld bytes", iter->nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } lats = self->lats; diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 99c441a2d..d939030e7 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -238,12 +238,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) self->lats = (double*)grib_context_malloc(h->context, array_size); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "unable to allocate %ld bytes", array_size); + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", array_size); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, array_size); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "unable to allocate %ld bytes", array_size); + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", array_size); return GRIB_OUT_OF_MEMORY; } lats = self->lats; @@ -268,12 +268,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) /* Store array of sin and cosine values to avoid recalculation */ s_x = (double*)grib_context_malloc(h->context, nx * sizeof(double)); if (!s_x) { - grib_context_log(h->context, GRIB_LOG_ERROR, "unable to allocate %ld bytes", nx * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nx * sizeof(double)); return GRIB_OUT_OF_MEMORY; } c_x = (double*)grib_context_malloc(h->context, nx * sizeof(double)); if (!c_x) { - grib_context_log(h->context, GRIB_LOG_ERROR, "unable to allocate %ld bytes", nx * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nx * sizeof(double)); return GRIB_OUT_OF_MEMORY; } From 323b6da0a6af3cf526ea7da60da3ebd5718706cc Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Thu, 11 Jun 2020 15:09:33 +0100 Subject: [PATCH 059/737] Geoiterator for Lambert Azimuthal Equal Area on ellipsoid (part 1) --- ...rator_class_lambert_azimuthal_equal_area.c | 213 +++++++++++------- 1 file changed, 128 insertions(+), 85 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 73290b326..0b810e54e 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -8,11 +8,6 @@ * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction. */ -/************************************** - * Enrico Fucile - **************************************/ - - #include "grib_api_internal.h" #include @@ -102,111 +97,64 @@ static int next(grib_iterator* i, double* lat, double* lon, double* val) return 1; } -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) +static int init_oblate(grib_handle* h, + grib_iterator_lambert_azimuthal_equal_area* self, + size_t nv, long nx, long ny, + double Dx, double Dy, double earthMinorAxisInMetres, double earthMajorAxisInMetres, + double latFirstInRadians, double lonFirstInRadians, + double centralLongitudeInRadians, double standardParallelInRadians, + long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) +{ + grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Azimuthal Equal Area only supported for spherical earth."); + return GRIB_GEOCALCULUS_PROBLEM; +} + +static int init_sphere(grib_handle* h, + grib_iterator_lambert_azimuthal_equal_area* self, + size_t nv, long nx, long ny, + double Dx, double Dy, double radius, + double latFirstInRadians, double lonFirstInRadians, + double centralLongitudeInRadians, double standardParallelInRadians, + long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) { - int ret = 0; double *lats, *lons; - double lonFirstInDegrees, latFirstInDegrees, lonFirst, latFirst, radius = 0; - long nx, ny, standardParallel, centralLongitude; - double phi1, lambda0, xFirst, yFirst, x, y, Dx, Dy; + double phi1, lambda0, xFirst, yFirst, x, y; double kp, sinphi1, cosphi1; - long alternativeRowScanning, iScansNegatively; - long jScansPositively, jPointsAreConsecutive; double sinphi, cosphi, cosdlambda, sindlambda; double cosc, sinc; long i, j; - - grib_iterator_lambert_azimuthal_equal_area* self = - (grib_iterator_lambert_azimuthal_equal_area*)iter; - - const char* sradius = grib_arguments_get_name(h, args, self->carg++); - const char* snx = grib_arguments_get_name(h, args, self->carg++); - const char* sny = grib_arguments_get_name(h, args, self->carg++); - const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sstandardParallel = grib_arguments_get_name(h, args, self->carg++); - const char* scentralLongitude = grib_arguments_get_name(h, args, self->carg++); - const char* sDx = grib_arguments_get_name(h, args, self->carg++); - const char* sDy = grib_arguments_get_name(h, args, self->carg++); - const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); double c, rho; - double epsilon = 1.0e-20; - double d2r = acos(0.0) / 90.0; - - if ((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) { - /* Check if it's an oblate spheroid */ - if (grib_is_earth_oblate(h)) - grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Azimuthal Equal Area only supported for spherical earth."); - return ret; - } - - if ((ret = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) - return ret; + const double epsilon = 1.0e-20; + const double d2r = acos(0.0) / 90.0; - if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "Wrong number of points (%ld!=%ldx%ld)", - iter->nv, nx, ny); - return GRIB_WRONG_GRID; - } - if ((ret = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, slonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sstandardParallel, &standardParallel)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, scentralLongitude, ¢ralLongitude)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sDx, &Dx)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sDy, &Dy)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, - sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, - salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) - return ret; - - lambda0 = d2r * centralLongitude / 1000000; - phi1 = d2r * standardParallel / 1000000; - latFirst = latFirstInDegrees * d2r; - lonFirst = lonFirstInDegrees * d2r; + lambda0 = centralLongitudeInRadians; // / 1000000; + phi1 = standardParallelInRadians; // / 1000000; cosphi1 = cos(phi1); sinphi1 = sin(phi1); Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; - self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); + self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { grib_context_log(h->context, GRIB_LOG_ERROR, - "Error allocating %ld bytes", iter->nv * sizeof(double)); + "Error allocating %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } - self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); + self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { grib_context_log(h->context, GRIB_LOG_ERROR, - "Error allocating %ld bytes", iter->nv * sizeof(double)); + "Error allocating %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } lats = self->lats; lons = self->lons; /* compute xFirst,yFirst in metres */ - sinphi = sin(latFirst); - cosphi = cos(latFirst); - cosdlambda = cos(lonFirst - lambda0); - sindlambda = sin(lonFirst - lambda0); + sinphi = sin(latFirstInRadians); + cosphi = cos(latFirstInRadians); + cosdlambda = cos(lonFirstInRadians - lambda0); + sindlambda = sin(lonFirstInRadians - lambda0); kp = radius * sqrt(2.0 / (1 + sinphi1 * sinphi + cosphi1 * cosphi * cosdlambda)); xFirst = kp * cosphi * sindlambda; yFirst = kp * (cosphi1 * sinphi - sinphi1 * cosphi * cosdlambda); @@ -267,10 +215,105 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) y += Dy; } } + return GRIB_SUCCESS; +} + +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) +{ + int err = 0; + int is_oblate = 0; + double lonFirstInDegrees, latFirstInDegrees, lonFirstInRadians, latFirstInRadians, radius = 0; + long nx, ny; + double standardParallelInDegrees, centralLongitudeInDegrees; + double standardParallelInRadians, centralLongitudeInRadians; + double Dx, Dy; + long alternativeRowScanning, iScansNegatively; + long jScansPositively, jPointsAreConsecutive; + double earthMajorAxisInMetres = 0, earthMinorAxisInMetres = 0; + + grib_iterator_lambert_azimuthal_equal_area* self = + (grib_iterator_lambert_azimuthal_equal_area*)iter; + + const char* sradius = grib_arguments_get_name(h, args, self->carg++); + const char* snx = grib_arguments_get_name(h, args, self->carg++); + const char* sny = grib_arguments_get_name(h, args, self->carg++); + const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sstandardParallel = grib_arguments_get_name(h, args, self->carg++); + const char* scentralLongitude = grib_arguments_get_name(h, args, self->carg++); + const char* sDx = grib_arguments_get_name(h, args, self->carg++); + const char* sDy = grib_arguments_get_name(h, args, self->carg++); + const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); + const double d2r = acos(0.0) / 90.0; + + is_oblate = grib_is_earth_oblate(h); + if (is_oblate) { + if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; + if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; + } + else { + if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) return err; + } + + if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) + return err; + + if (iter->nv != nx * ny) { + grib_context_log(h->context, GRIB_LOG_ERROR, + "Wrong number of points (%ld!=%ldx%ld)", + iter->nv, nx, ny); + return GRIB_WRONG_GRID; + } + if ((err = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, slonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, sstandardParallel, &standardParallelInDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, scentralLongitude, ¢ralLongitudeInDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, sDx, &Dx)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, sDy, &Dy)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) + return err; + + latFirstInRadians = latFirstInDegrees * d2r; + lonFirstInRadians = lonFirstInDegrees * d2r; + centralLongitudeInRadians = centralLongitudeInDegrees * d2r; + standardParallelInRadians = standardParallelInDegrees * d2r; + + if (is_oblate) { + err = init_oblate(h, self, iter->nv, nx, ny, + Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, + latFirstInRadians, lonFirstInRadians, + centralLongitudeInRadians, standardParallelInRadians, + iScansNegatively, jScansPositively, jPointsAreConsecutive); + } + else { + err = init_sphere(h, self, iter->nv, nx, ny, + Dx, Dy, radius, + latFirstInRadians, lonFirstInRadians, + centralLongitudeInRadians, standardParallelInRadians, + iScansNegatively, jScansPositively, jPointsAreConsecutive); + } + if (err) return err; iter->e = -1; - return ret; + return err; } static int destroy(grib_iterator* i) From ece5f895c4b00d6e1ea55c1bd83abae6073c4556 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 12 Jun 2020 13:12:28 +0100 Subject: [PATCH 060/737] Geoiterator for Lambert Azimuthal Equal Area on ellipsoid (part 2) --- ...rator_class_lambert_azimuthal_equal_area.c | 180 +++++++++++++++++- 1 file changed, 178 insertions(+), 2 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 0b810e54e..2f1539e4f 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -97,6 +97,66 @@ static int next(grib_iterator* i, double* lat, double* lon, double* val) return 1; } +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* Whole pie */ +#endif + +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 /* Half a pie */ +#endif + +#ifndef M_PI_4 +#define M_PI_4 0.78539816339744830962 /* Quarter of a pie */ +#endif + +#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ +#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ + +# define P00 .33333333333333333333 /* 1 / 3 */ +# define P01 .17222222222222222222 /* 31 / 180 */ +# define P02 .10257936507936507937 /* 517 / 5040 */ +# define P10 .06388888888888888888 /* 23 / 360 */ +# define P11 .06640211640211640212 /* 251 / 3780 */ +# define P20 .01677689594356261023 /* 761 / 45360 */ + +void pj_authset(double es, double* APA) +{ + double t; + APA[0] = es * P00; + t = es * es; + APA[0] += t * P01; + APA[1] = t * P10; + t *= es; + APA[0] += t * P02; + APA[1] += t * P11; + APA[2] = t * P20; +} +double pj_authlat(double beta, double *APA) +{ + double t = beta+beta; + return(beta + APA[0] * sin(t) + APA[1] * sin(t+t) + APA[2] * sin(t+t+t)); +} + +static double pj_qsfn(double sinphi, double e, double one_es) +{ + double con, div1, div2; + const double EPSILON = 1.0e-7; + + if (e >= EPSILON) { + con = e * sinphi; + div1 = 1.0 - con * con; + div2 = 1.0 + con; + + /* avoid zero division, fail gracefully */ + if (div1 == 0.0 || div2 == 0.0) + return HUGE_VAL; + + return (one_es * (sinphi / div1 - (.5 / e) * log ((1. - con) / div2 ))); + } else + return (sinphi + sinphi); +} + +#define EPS10 1.e-10 static int init_oblate(grib_handle* h, grib_iterator_lambert_azimuthal_equal_area* self, size_t nv, long nx, long ny, @@ -105,8 +165,124 @@ static int init_oblate(grib_handle* h, double centralLongitudeInRadians, double standardParallelInRadians, long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Azimuthal Equal Area only supported for spherical earth."); - return GRIB_GEOCALCULUS_PROBLEM; + double *lats, *lons; + long i, j; + double x0, y0, x, y; + double coslam, sinlam, sinphi, sinphi_, q, sinb=0.0, cosb=0.0, b=0.0, cosb2;//fwd + double Q__qp = 0, Q__rq = 0, Q__mmf = 0, Q__cosb1, Q__sinb1, Q__dd, Q__xmf, Q__ymf, t; + double e, es, temp, one_es; + double false_easting; /* x offset in meters */ + double false_northing; /* y offset in meters */ + double latRad, lonRad, latDeg, lonDeg; + double APA[3] = {0,}; + + //temp = earthMinorAxisInMetres/earthMajorAxisInMetres; + //es = 1.0 - temp * temp; + temp = (earthMajorAxisInMetres - earthMinorAxisInMetres)/earthMajorAxisInMetres; + es = 2*temp - temp*temp; + one_es = 1.0 - es; + e = sqrt(es); + + coslam = cos(lonFirstInRadians - centralLongitudeInRadians); //cos(lp.lam); + sinlam = sin(lonFirstInRadians - centralLongitudeInRadians); + sinphi = sin(latFirstInRadians); // sin(lp.phi); + q = pj_qsfn(sinphi, e, one_es); + + //----------- setp start + t = fabs(standardParallelInRadians); + if (t > M_PI_2 + EPS10 ) { + return GRIB_GEOCALCULUS_PROBLEM; + } + //if (fabs(t - M_HALFPI) < EPS10) + // Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; + //else if (fabs(t) < EPS10) + // Q->mode = EQUIT; + //else + // Q->mode = OBLIQ; + Q__qp = pj_qsfn(1.0, e, one_es); + Q__mmf = 0.5 / one_es; + pj_authset(es, APA); // sets up APA array + Q__rq = sqrt(0.5 * Q__qp); + sinphi_ = sin(standardParallelInRadians); // (P->phi0); + Q__sinb1 = pj_qsfn(sinphi_, e, one_es) / Q__qp; + Q__cosb1 = sqrt(1.0 - Q__sinb1 * Q__sinb1); + Q__dd = cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); + Q__ymf = (Q__xmf = Q__rq) / Q__dd; + Q__xmf *= Q__dd; + //----------- setup end + + sinb = q/Q__qp; + cosb2 = 1.0 - sinb * sinb; + cosb = cosb2 > 0 ? sqrt(cosb2) : 0; + b = 1. + Q__sinb1 * sinb + Q__cosb1 * cosb * coslam; + if (fabs(b) < EPS10) { + return GRIB_GEOCALCULUS_PROBLEM; + } + b = sqrt(2.0 / b); + + // OBLIQUE + y0 = Q__ymf * b * (Q__cosb1 * sinb - Q__sinb1 * cosb * coslam); + x0 = Q__xmf * b * cosb * sinlam; + y0 *= earthMajorAxisInMetres; + x0 *= earthMajorAxisInMetres; + + /* Allocate latitude and longitude arrays */ + self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + + /* Populate the lat and lon arrays */ + false_easting = x0; + false_northing = y0; + for (j = 0; j < ny; j++) { + y = j * Dy; + for (i = 0; i < nx; i++) { + double cCe, sCe, q, rho, ab=0.0, lp__lam, lp__phi, xy_x,xy_y; + const int index = i + j * nx; + + x = i * Dx; + xy_x = x; + xy_y = y; + /* Inverse projection to convert from x,y to lat,lon */ + //_x = x - false_easting; + //_y = rh - y + false_northing; + // calculate latRad and lonRad + xy_x /= Q__dd; + xy_y *= Q__dd; + rho = hypot(xy_x, xy_y); + Assert(rho >= EPS10); // TODO + sCe = 2. * asin(.5 * rho / Q__rq); + cCe = cos(sCe); + sCe = sin(sCe); + xy_x *= sCe; + // if oblique + ab = cCe * Q__sinb1 + xy_y * sCe * Q__cosb1 / rho; + xy_y = rho * Q__cosb1 * cCe - xy_y * Q__sinb1 * sCe; + // else + //ab = xy.y * sCe / rho; + //xy.y = rho * cCe; + + lp__lam = atan2(xy_x, xy_y); //longitude + lp__phi = pj_authlat(asin(ab), APA); // latitude + + latDeg = latRad * RAD2DEG; /* Convert to degrees */ + lonDeg = lonRad * RAD2DEG; + lonDeg = normalise_longitude_in_degrees(lonDeg); + self->lons[index] = lonDeg; + self->lats[index] = latDeg; + } + } + + //grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Azimuthal Equal Area only supported for spherical earth."); + //return GRIB_GEOCALCULUS_PROBLEM; + return GRIB_SUCCESS; } static int init_sphere(grib_handle* h, From 256944ef177f4417d1defbae9f4875e81cffce89 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 23 Jun 2020 20:49:04 +0100 Subject: [PATCH 061/737] Refactoring and DebugAssert --- src/grib_iterator_class_lambert_conformal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index eb05b7fa6..153d9455a 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -360,9 +360,11 @@ static int init_oblate(grib_handle* h, latRad = -M_PI_2; } lonRad = adjust_lon_radians(theta / ns + LoVInRadians); + if (i == 0 && j == 0) { + DebugAssert(fabs(latFirstInRadians - latRad) <= EPSILON); + } latDeg = latRad * RAD2DEG; /* Convert to degrees */ - lonDeg = lonRad * RAD2DEG; - lonDeg = normalise_longitude_in_degrees(lonDeg); + lonDeg = normalise_longitude_in_degrees(lonRad * RAD2DEG); self->lons[index] = lonDeg; self->lats[index] = latDeg; } From 178cc2b534a9a85cd26ddba0f1143b5455d2c129 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sun, 28 Jun 2020 16:19:30 +0100 Subject: [PATCH 062/737] Geoiterator for Lambert Azimuthal Equal Area on ellipsoid (part 3) --- ...rator_class_lambert_azimuthal_equal_area.c | 73 +++++++++++++++++-- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 2f1539e4f..2f61a5d98 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -173,8 +173,12 @@ static int init_oblate(grib_handle* h, double e, es, temp, one_es; double false_easting; /* x offset in meters */ double false_northing; /* y offset in meters */ - double latRad, lonRad, latDeg, lonDeg; + double latRad=0, lonRad=0, latDeg, lonDeg; double APA[3] = {0,}; + double xFirst, yFirst; + + Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; + Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; //temp = earthMinorAxisInMetres/earthMajorAxisInMetres; //es = 1.0 - temp * temp; @@ -182,7 +186,7 @@ static int init_oblate(grib_handle* h, es = 2*temp - temp*temp; one_es = 1.0 - es; e = sqrt(es); - +printf("latFirstInRadians=%g, lonFirstInRadians=%g\n", latFirstInRadians, lonFirstInRadians); coslam = cos(lonFirstInRadians - centralLongitudeInRadians); //cos(lp.lam); sinlam = sin(lonFirstInRadians - centralLongitudeInRadians); sinphi = sin(latFirstInRadians); // sin(lp.phi); @@ -223,8 +227,8 @@ static int init_oblate(grib_handle* h, // OBLIQUE y0 = Q__ymf * b * (Q__cosb1 * sinb - Q__sinb1 * cosb * coslam); x0 = Q__xmf * b * cosb * sinlam; - y0 *= earthMajorAxisInMetres; - x0 *= earthMajorAxisInMetres; + //y0 *= earthMajorAxisInMetres; + //x0 *= earthMajorAxisInMetres; /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); @@ -237,8 +241,63 @@ static int init_oblate(grib_handle* h, grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } + lats = self->lats; + lons = self->lons; /* Populate the lat and lon arrays */ + { + xFirst = x0; yFirst = y0; + y = yFirst; + for (j = 0; j < ny; j++) { + x = xFirst; + for (i = 0; i < nx; i++) { + double cCe, sCe, q, rho, ab=0.0, lp__lam, lp__phi, xy_x=x , xy_y = y; + xy_x /= Q__dd; + xy_y *= Q__dd; + rho = hypot(xy_x, xy_y); + Assert(rho >= EPS10); // TODO + sCe = 2. * asin(.5 * rho / Q__rq); + cCe = cos(sCe); + sCe = sin(sCe); + xy_x *= sCe; + // if oblique + ab = cCe * Q__sinb1 + xy_y * sCe * Q__cosb1 / rho; + xy_y = rho * Q__cosb1 * cCe - xy_y * Q__sinb1 * sCe; + // else + //ab = xy.y * sCe / rho; + //xy.y = rho * cCe; + lp__lam = atan2(xy_x, xy_y); //longitude + lp__phi = pj_authlat(asin(ab), APA); // latitude + //printf("lp__phi=%g, lp__lam=%g\n", lp__phi, lp__lam); + //printf("lp__phi=%g, lp__lam=%g\n", lp__phi * RAD2DEG, lp__lam* RAD2DEG); + + *lats = lp__phi * RAD2DEG; + *lons = lp__lam * RAD2DEG; + //rho = sqrt(x * x + ysq); + //if (rho > epsilon) { + // c = 2 * asin(rho / (2.0 * radius)); + // cosc = cos(c); + // sinc = sin(c); + // *lats = asin(cosc * sinphi1 + y * sinc * cosphi1 / rho) / d2r; + // *lons = (lambda0 + atan2(x * sinc, rho * cosphi1 * cosc - y * sinphi1 * sinc)) / d2r; + //} + //else { + // *lats = phi1 / d2r; + // *lons = lambda0 / d2r; + //} + //if (*lons < 0) *lons += 360; + lons++; + lats++; + + //x += Dx; + x += Dx/earthMajorAxisInMetres; + } + //y += Dy; + y += Dy/earthMajorAxisInMetres; + } + } + +#if 0 false_easting = x0; false_northing = y0; for (j = 0; j < ny; j++) { @@ -271,6 +330,8 @@ static int init_oblate(grib_handle* h, lp__lam = atan2(xy_x, xy_y); //longitude lp__phi = pj_authlat(asin(ab), APA); // latitude + printf("lp__phi=%g, lp__lam=%g\n", lp__phi, lp__lam); + latDeg = latRad * RAD2DEG; /* Convert to degrees */ lonDeg = lonRad * RAD2DEG; @@ -279,7 +340,7 @@ static int init_oblate(grib_handle* h, self->lats[index] = latDeg; } } - +#endif //grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Azimuthal Equal Area only supported for spherical earth."); //return GRIB_GEOCALCULUS_PROBLEM; return GRIB_SUCCESS; @@ -470,7 +531,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) lonFirstInRadians = lonFirstInDegrees * d2r; centralLongitudeInRadians = centralLongitudeInDegrees * d2r; standardParallelInRadians = standardParallelInDegrees * d2r; - +printf("latFirstInDegrees=%g, lonFirstInDegrees=%g\n",latFirstInDegrees,lonFirstInDegrees); if (is_oblate) { err = init_oblate(h, self, iter->nv, nx, ny, Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, From 47e047b8d6380b23d9b228e11e118195021d4f3e Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 5 May 2021 16:41:35 +0100 Subject: [PATCH 063/737] ECC-1239: grib_get_data: Polar Stereographic: Better error message if earth is oblate --- src/grib_iterator_class_polar_stereographic.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index f0f8a606d..1a29fd567 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -149,6 +149,11 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); + if (grib_is_earth_oblate(h)) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic only supported for spherical earth."); + return GRIB_GEOCALCULUS_PROBLEM; + } + if ((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) return ret; if ((ret = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) @@ -156,11 +161,6 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) if ((ret = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) return ret; - if (grib_is_earth_oblate(h)) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic only supported for spherical earth."); - return GRIB_GEOCALCULUS_PROBLEM; - } - if (iter->nv != nx * ny) { grib_context_log(h->context, GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); return GRIB_WRONG_GRID; From 3da90770e4e4a75070b07ea984d41d486162c36d Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 11 Sep 2021 13:44:40 +0100 Subject: [PATCH 064/737] ECC-1280: GRIB1: geoiterator for 'space view' is not implemented --- src/grib_iterator_class_space_view.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index d939030e7..6c9f97cd8 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -225,8 +225,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) lop *= DEG2RAD; orient_angle = orientationInDegrees; - if (orient_angle != 0.0) - return GRIB_NOT_IMPLEMENTED; + /* if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; */ xp = xpInGridLengths; yp = ypInGridLengths; From d09844a37e3b7b9f3752f7fe16be4c77de37536d Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 11 Sep 2021 13:52:23 +0100 Subject: [PATCH 065/737] ECC-1280: remove unused variable --- src/grib_iterator_class_space_view.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 6c9f97cd8..1035dbdaf 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -115,7 +115,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) long Xo, Yo, jScansPositively, jPointsAreConsecutive, i; double major = 0, minor = 0, r_eq, r_pol, height; - double lap, lop, orient_angle, angular_size; + double lap, lop, angular_size; double xp, yp, dx, dy, rx, ry, x, y; double cos_x, cos_y, sin_x, sin_y; double factor_1, factor_2, tmp1, Sd, Sn, Sxy, S1, S2, S3; @@ -224,7 +224,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) /*lap *= DEG2RAD;*/ lop *= DEG2RAD; - orient_angle = orientationInDegrees; + /*orient_angle = orientationInDegrees;*/ /* if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; */ xp = xpInGridLengths; From 799d45a7f90fe1f5188e7d6bcd7d285a20598ab1 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Mon, 13 Sep 2021 15:03:02 +0100 Subject: [PATCH 066/737] ECC-1280: Revert NrInRadiusOfEarth (Breaks Magics). Fix angle conversions --- src/grib_iterator_class_space_view.c | 50 ++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 1035dbdaf..73a416f87 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -97,6 +97,48 @@ static int next(grib_iterator* i, double* lat, double* lon, double* val) return 1; } +#if 0 +static void adjustBadlyEncodedEcmwfGribs(grib_handle* h, + long* nx, long* ny, double* dx, double* dy, double* xp, double* yp) +{ + /* Correct the information provided in the headers of certain satellite imagery that + * we have available. This is specific to ECMWF. + * Obtained through trial-and-error to get the best match with the coastlines. + * + * Copied from Magics GribSatelliteInterpretor::AdjustBadlyEncodedGribs() + */ + long centre = 0; + int err = grib_get_long(h, "centre", ¢re); + if (!err && centre == 98) { + int err1 = 0, err2 = 0, err3 = 0; + long satelliteIdentifier, channelNumber, functionCode; + /* These keys are defined in the ECMWF local definition 24 - Satellite image simulation */ + err1 = grib_get_long(h, "satelliteIdentifier", &satelliteIdentifier); + err2 = grib_get_long(h, "channelNumber", &channelNumber); + err3 = grib_get_long(h, "functionCode", &functionCode); + if (!err1 && !err2 && !err3) { + if (satelliteIdentifier == 54 && channelNumber == 2 && *dx == 1179) { /* Meteosat 7, channel 2 */ + *nx = *ny = 900; + *dx = *dy = 853; + *xp = *yp = 450; + } + else if (satelliteIdentifier == 54 && channelNumber == 3 && *dx == 1179) { /* Meteosat 7, channel 3 */ + *dx = *dy = 1184; + *xp = *yp = 635; + } + else if (satelliteIdentifier == 259 && channelNumber == 4 && *dx == 1185) { /* GOES-15 (West) channel 4 */ + *dx = *dy = 880; + *xp = *yp = 450; + } + else if (satelliteIdentifier == 57 && *dx == 1732) { /* MSG (Meteosat second generation), non-HRV channels */ + *dx = *dy = 1811; + *xp = *yp = 928; + } + } + } +} +#endif + #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ @@ -217,12 +259,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) lap = latOfSubSatellitePointInDegrees; lop = lonOfSubSatellitePointInDegrees; - lap *= 1e-6; /* default scaling factor */ - lop *= 1e-6; + /* lap *= 1e-6; // default scaling factor */ + /* lop *= 1e-6; */ if (lap != 0.0) return GRIB_NOT_IMPLEMENTED; /*lap *= DEG2RAD;*/ - lop *= DEG2RAD; + /*lop *= DEG2RAD;*/ /*orient_angle = orientationInDegrees;*/ /* if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; */ @@ -232,6 +274,8 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) x0 = Xo; y0 = Yo; + /* adjustBadlyEncodedEcmwfGribs(h, &nx, &ny, &dx, &dy, &xp, &yp); */ + rx = angular_size / dx; ry = (r_pol / r_eq) * angular_size / dy; From 01096ddbccc31b5f05ab1f32953b07b858d7f369 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Mon, 13 Sep 2021 21:34:35 +0100 Subject: [PATCH 067/737] ECC-1280: Check to avoid divide by zero --- src/grib_iterator_class_space_view.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 73a416f87..bbfc6d366 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -254,17 +254,19 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) else { r_eq = r_pol = radius * 0.001; /*conv to km*/ } + + if (nrInRadiusOfEarth == 0) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Key %s must be greater than zero", sNrInRadiusOfEarth); + return GRIB_GEOCALCULUS_PROBLEM; + } + angular_size = 2.0 * asin(1.0 / nrInRadiusOfEarth); height = nrInRadiusOfEarth * r_eq; lap = latOfSubSatellitePointInDegrees; lop = lonOfSubSatellitePointInDegrees; - /* lap *= 1e-6; // default scaling factor */ - /* lop *= 1e-6; */ if (lap != 0.0) return GRIB_NOT_IMPLEMENTED; - /*lap *= DEG2RAD;*/ - /*lop *= DEG2RAD;*/ /*orient_angle = orientationInDegrees;*/ /* if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; */ @@ -275,7 +277,10 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) y0 = Yo; /* adjustBadlyEncodedEcmwfGribs(h, &nx, &ny, &dx, &dy, &xp, &yp); */ - + if (dx == 0 || dy == 0) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Keys %s and %s must be greater than zero", sDx, sDy); + return GRIB_GEOCALCULUS_PROBLEM; + } rx = angular_size / dx; ry = (r_pol / r_eq) * angular_size / dy; From b71550b9cefab09b9a031c5a16713500cdfd82a0 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 21 Sep 2021 11:03:32 +0100 Subject: [PATCH 068/737] Space View iterator: add more checks --- src/grib_iterator_class_space_view.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index bbfc6d366..90456fc56 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -228,7 +228,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) /* Orthographic not supported. This happens when Nr (camera altitude) is missing */ if (grib_is_missing(h, sNrInRadiusOfEarth, &ret)) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Orthographic view (Nr missing) not supported"); + grib_context_log(h->context, GRIB_LOG_ERROR, "Space View: Orthographic view (Nr missing) not supported"); return GRIB_NOT_IMPLEMENTED; } if ((ret = grib_get_double_internal(h, sNrInRadiusOfEarth, &nrInRadiusOfEarth)) != GRIB_SUCCESS) @@ -256,7 +256,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } if (nrInRadiusOfEarth == 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Key %s must be greater than zero", sNrInRadiusOfEarth); + grib_context_log(h->context, GRIB_LOG_ERROR, "Space View: Key %s must be greater than zero", sNrInRadiusOfEarth); return GRIB_GEOCALCULUS_PROBLEM; } @@ -265,8 +265,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) lap = latOfSubSatellitePointInDegrees; lop = lonOfSubSatellitePointInDegrees; - if (lap != 0.0) - return GRIB_NOT_IMPLEMENTED; + if (lap != 0.0) { + grib_context_log(h->context, GRIB_LOG_ERROR, + "Space View: Key '%s' must be 0 (satellite must be located in the equator plane)", + sLatOfSubSatellitePointInDegrees); + return GRIB_GEOCALCULUS_PROBLEM; + } /*orient_angle = orientationInDegrees;*/ /* if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; */ @@ -278,7 +282,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) /* adjustBadlyEncodedEcmwfGribs(h, &nx, &ny, &dx, &dy, &xp, &yp); */ if (dx == 0 || dy == 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Keys %s and %s must be greater than zero", sDx, sDy); + grib_context_log(h->context, GRIB_LOG_ERROR, "Space View: Keys %s and %s must be greater than zero", sDx, sDy); return GRIB_GEOCALCULUS_PROBLEM; } rx = angular_size / dx; From 8671cc9cfef99a9a6ce0b3487a1123e7a8de615b Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 26 Oct 2021 12:19:33 +0100 Subject: [PATCH 069/737] ECC-1291: Merge from develop and make tests pass --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 2f61a5d98..7f53e99fb 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -531,7 +531,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) lonFirstInRadians = lonFirstInDegrees * d2r; centralLongitudeInRadians = centralLongitudeInDegrees * d2r; standardParallelInRadians = standardParallelInDegrees * d2r; -printf("latFirstInDegrees=%g, lonFirstInDegrees=%g\n",latFirstInDegrees,lonFirstInDegrees); +//printf("latFirstInDegrees=%g, lonFirstInDegrees=%g\n",latFirstInDegrees,lonFirstInDegrees); if (is_oblate) { err = init_oblate(h, self, iter->nv, nx, ny, Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, From a225c4faa80c8369b5ab71f4ff0e597807e25b9f Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 26 Oct 2021 13:34:19 +0100 Subject: [PATCH 070/737] ECC-1291: Test --- ...rator_class_lambert_azimuthal_equal_area.c | 98 ++++++++++--------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 7f53e99fb..ee8684027 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -112,18 +112,18 @@ static int next(grib_iterator* i, double* lat, double* lon, double* val) #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ -# define P00 .33333333333333333333 /* 1 / 3 */ -# define P01 .17222222222222222222 /* 31 / 180 */ -# define P02 .10257936507936507937 /* 517 / 5040 */ -# define P10 .06388888888888888888 /* 23 / 360 */ -# define P11 .06640211640211640212 /* 251 / 3780 */ -# define P20 .01677689594356261023 /* 761 / 45360 */ +#define P00 .33333333333333333333 /* 1 / 3 */ +#define P01 .17222222222222222222 /* 31 / 180 */ +#define P02 .10257936507936507937 /* 517 / 5040 */ +#define P10 .06388888888888888888 /* 23 / 360 */ +#define P11 .06640211640211640212 /* 251 / 3780 */ +#define P20 .01677689594356261023 /* 761 / 45360 */ void pj_authset(double es, double* APA) { double t; APA[0] = es * P00; - t = es * es; + t = es * es; APA[0] += t * P01; APA[1] = t * P10; t *= es; @@ -131,10 +131,10 @@ void pj_authset(double es, double* APA) APA[1] += t * P11; APA[2] = t * P20; } -double pj_authlat(double beta, double *APA) +double pj_authlat(double beta, double* APA) { - double t = beta+beta; - return(beta + APA[0] * sin(t) + APA[1] * sin(t+t) + APA[2] * sin(t+t+t)); + double t = beta + beta; + return (beta + APA[0] * sin(t) + APA[1] * sin(t + t) + APA[2] * sin(t + t + t)); } static double pj_qsfn(double sinphi, double e, double one_es) @@ -143,7 +143,7 @@ static double pj_qsfn(double sinphi, double e, double one_es) const double EPSILON = 1.0e-7; if (e >= EPSILON) { - con = e * sinphi; + con = e * sinphi; div1 = 1.0 - con * con; div2 = 1.0 + con; @@ -151,8 +151,9 @@ static double pj_qsfn(double sinphi, double e, double one_es) if (div1 == 0.0 || div2 == 0.0) return HUGE_VAL; - return (one_es * (sinphi / div1 - (.5 / e) * log ((1. - con) / div2 ))); - } else + return (one_es * (sinphi / div1 - (.5 / e) * log((1. - con) / div2))); + } + else return (sinphi + sinphi); } @@ -168,33 +169,33 @@ static int init_oblate(grib_handle* h, double *lats, *lons; long i, j; double x0, y0, x, y; - double coslam, sinlam, sinphi, sinphi_, q, sinb=0.0, cosb=0.0, b=0.0, cosb2;//fwd + double coslam, sinlam, sinphi, sinphi_, q, sinb = 0.0, cosb = 0.0, b = 0.0, cosb2; //fwd double Q__qp = 0, Q__rq = 0, Q__mmf = 0, Q__cosb1, Q__sinb1, Q__dd, Q__xmf, Q__ymf, t; double e, es, temp, one_es; double false_easting; /* x offset in meters */ double false_northing; /* y offset in meters */ - double latRad=0, lonRad=0, latDeg, lonDeg; + double latRad = 0, lonRad = 0, latDeg, lonDeg; double APA[3] = {0,}; double xFirst, yFirst; - - Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; - Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; + + Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; + Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; //temp = earthMinorAxisInMetres/earthMajorAxisInMetres; //es = 1.0 - temp * temp; - temp = (earthMajorAxisInMetres - earthMinorAxisInMetres)/earthMajorAxisInMetres; - es = 2*temp - temp*temp; + temp = (earthMajorAxisInMetres - earthMinorAxisInMetres) / earthMajorAxisInMetres; + es = 2 * temp - temp * temp; one_es = 1.0 - es; - e = sqrt(es); -printf("latFirstInRadians=%g, lonFirstInRadians=%g\n", latFirstInRadians, lonFirstInRadians); + e = sqrt(es); + //printf("latFirstInRadians=%g, lonFirstInRadians=%g\n", latFirstInRadians, lonFirstInRadians); coslam = cos(lonFirstInRadians - centralLongitudeInRadians); //cos(lp.lam); sinlam = sin(lonFirstInRadians - centralLongitudeInRadians); - sinphi = sin(latFirstInRadians); // sin(lp.phi); - q = pj_qsfn(sinphi, e, one_es); - + sinphi = sin(latFirstInRadians); // sin(lp.phi); + q = pj_qsfn(sinphi, e, one_es); + //----------- setp start t = fabs(standardParallelInRadians); - if (t > M_PI_2 + EPS10 ) { + if (t > M_PI_2 + EPS10) { return GRIB_GEOCALCULUS_PROBLEM; } //if (fabs(t - M_HALFPI) < EPS10) @@ -203,22 +204,22 @@ printf("latFirstInRadians=%g, lonFirstInRadians=%g\n", latFirstInRadians, lonFi // Q->mode = EQUIT; //else // Q->mode = OBLIQ; - Q__qp = pj_qsfn(1.0, e, one_es); + Q__qp = pj_qsfn(1.0, e, one_es); Q__mmf = 0.5 / one_es; - pj_authset(es, APA); // sets up APA array - Q__rq = sqrt(0.5 * Q__qp); - sinphi_ = sin(standardParallelInRadians); // (P->phi0); + pj_authset(es, APA); // sets up APA array + Q__rq = sqrt(0.5 * Q__qp); + sinphi_ = sin(standardParallelInRadians); // (P->phi0); Q__sinb1 = pj_qsfn(sinphi_, e, one_es) / Q__qp; Q__cosb1 = sqrt(1.0 - Q__sinb1 * Q__sinb1); - Q__dd = cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); - Q__ymf = (Q__xmf = Q__rq) / Q__dd; + Q__dd = cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); + Q__ymf = (Q__xmf = Q__rq) / Q__dd; Q__xmf *= Q__dd; //----------- setup end - sinb = q/Q__qp; + sinb = q / Q__qp; cosb2 = 1.0 - sinb * sinb; - cosb = cosb2 > 0 ? sqrt(cosb2) : 0; - b = 1. + Q__sinb1 * sinb + Q__cosb1 * cosb * coslam; + cosb = cosb2 > 0 ? sqrt(cosb2) : 0; + b = 1. + Q__sinb1 * sinb + Q__cosb1 * cosb * coslam; if (fabs(b) < EPS10) { return GRIB_GEOCALCULUS_PROBLEM; } @@ -246,31 +247,32 @@ printf("latFirstInRadians=%g, lonFirstInRadians=%g\n", latFirstInRadians, lonFi /* Populate the lat and lon arrays */ { - xFirst = x0; yFirst = y0; - y = yFirst; + xFirst = x0; + yFirst = y0; + y = yFirst; for (j = 0; j < ny; j++) { - x = xFirst; + x = xFirst; for (i = 0; i < nx; i++) { - double cCe, sCe, q, rho, ab=0.0, lp__lam, lp__phi, xy_x=x , xy_y = y; + double cCe, sCe, q, rho, ab = 0.0, lp__lam, lp__phi, xy_x = x, xy_y = y; xy_x /= Q__dd; xy_y *= Q__dd; rho = hypot(xy_x, xy_y); - Assert(rho >= EPS10); // TODO + Assert(rho >= EPS10); // TODO sCe = 2. * asin(.5 * rho / Q__rq); cCe = cos(sCe); sCe = sin(sCe); xy_x *= sCe; // if oblique - ab = cCe * Q__sinb1 + xy_y * sCe * Q__cosb1 / rho; + ab = cCe * Q__sinb1 + xy_y * sCe * Q__cosb1 / rho; xy_y = rho * Q__cosb1 * cCe - xy_y * Q__sinb1 * sCe; // else //ab = xy.y * sCe / rho; //xy.y = rho * cCe; - lp__lam = atan2(xy_x, xy_y); //longitude - lp__phi = pj_authlat(asin(ab), APA); // latitude + lp__lam = atan2(xy_x, xy_y); //longitude + lp__phi = pj_authlat(asin(ab), APA); // latitude //printf("lp__phi=%g, lp__lam=%g\n", lp__phi, lp__lam); //printf("lp__phi=%g, lp__lam=%g\n", lp__phi * RAD2DEG, lp__lam* RAD2DEG); - + *lats = lp__phi * RAD2DEG; *lons = lp__lam * RAD2DEG; //rho = sqrt(x * x + ysq); @@ -290,10 +292,10 @@ printf("latFirstInRadians=%g, lonFirstInRadians=%g\n", latFirstInRadians, lonFi lats++; //x += Dx; - x += Dx/earthMajorAxisInMetres; + x += Dx / earthMajorAxisInMetres; } //y += Dy; - y += Dy/earthMajorAxisInMetres; + y += Dy / earthMajorAxisInMetres; } } @@ -340,7 +342,7 @@ printf("latFirstInRadians=%g, lonFirstInRadians=%g\n", latFirstInRadians, lonFi self->lats[index] = latDeg; } } -#endif +#endif //grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Azimuthal Equal Area only supported for spherical earth."); //return GRIB_GEOCALCULUS_PROBLEM; return GRIB_SUCCESS; @@ -531,7 +533,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) lonFirstInRadians = lonFirstInDegrees * d2r; centralLongitudeInRadians = centralLongitudeInDegrees * d2r; standardParallelInRadians = standardParallelInDegrees * d2r; -//printf("latFirstInDegrees=%g, lonFirstInDegrees=%g\n",latFirstInDegrees,lonFirstInDegrees); + //printf("latFirstInDegrees=%g, lonFirstInDegrees=%g\n",latFirstInDegrees,lonFirstInDegrees); if (is_oblate) { err = init_oblate(h, self, iter->nv, nx, ny, Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, From 78e493f980a585f3b53abc9a1ae8acbb281c2e8b Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 2 Nov 2021 17:13:02 +0000 Subject: [PATCH 071/737] ECC-1291: GRIB2: Implement Lambert Azimuthal geoiterator on oblate spheroid (First working version) --- ...grib_iterator_class_lambert_azimuthal_equal_area.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index ee8684027..155d1ad9d 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -257,7 +257,7 @@ static int init_oblate(grib_handle* h, xy_x /= Q__dd; xy_y *= Q__dd; rho = hypot(xy_x, xy_y); - Assert(rho >= EPS10); // TODO + Assert(rho >= EPS10); // TODO(masn): check sCe = 2. * asin(.5 * rho / Q__rq); cCe = cos(sCe); sCe = sin(sCe); @@ -274,7 +274,8 @@ static int init_oblate(grib_handle* h, //printf("lp__phi=%g, lp__lam=%g\n", lp__phi * RAD2DEG, lp__lam* RAD2DEG); *lats = lp__phi * RAD2DEG; - *lons = lp__lam * RAD2DEG; + *lons = (lp__lam + centralLongitudeInRadians) * RAD2DEG; + //rho = sqrt(x * x + ysq); //if (rho > epsilon) { // c = 2 * asin(rho / (2.0 * radius)); @@ -318,7 +319,7 @@ static int init_oblate(grib_handle* h, xy_x /= Q__dd; xy_y *= Q__dd; rho = hypot(xy_x, xy_y); - Assert(rho >= EPS10); // TODO + Assert(rho >= EPS10); sCe = 2. * asin(.5 * rho / Q__rq); cCe = cos(sCe); sCe = sin(sCe); @@ -334,7 +335,6 @@ static int init_oblate(grib_handle* h, lp__phi = pj_authlat(asin(ab), APA); // latitude printf("lp__phi=%g, lp__lam=%g\n", lp__phi, lp__lam); - latDeg = latRad * RAD2DEG; /* Convert to degrees */ lonDeg = lonRad * RAD2DEG; lonDeg = normalise_longitude_in_degrees(lonDeg); @@ -343,8 +343,7 @@ static int init_oblate(grib_handle* h, } } #endif - //grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert Azimuthal Equal Area only supported for spherical earth."); - //return GRIB_GEOCALCULUS_PROBLEM; + return GRIB_SUCCESS; } From a868d83329102372d9adcd5b69ab5000b664c091 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 2 Nov 2021 17:33:01 +0000 Subject: [PATCH 072/737] ECC-1291: clean up --- ...rator_class_lambert_azimuthal_equal_area.c | 115 ++++-------------- 1 file changed, 25 insertions(+), 90 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 155d1ad9d..e46fd6d42 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -169,7 +169,7 @@ static int init_oblate(grib_handle* h, double *lats, *lons; long i, j; double x0, y0, x, y; - double coslam, sinlam, sinphi, sinphi_, q, sinb = 0.0, cosb = 0.0, b = 0.0, cosb2; //fwd + double coslam, sinlam, sinphi, sinphi_, q, sinb = 0.0, cosb = 0.0, b = 0.0, cosb2; double Q__qp = 0, Q__rq = 0, Q__mmf = 0, Q__cosb1, Q__sinb1, Q__dd, Q__xmf, Q__ymf, t; double e, es, temp, one_es; double false_easting; /* x offset in meters */ @@ -181,40 +181,37 @@ static int init_oblate(grib_handle* h, Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; - //temp = earthMinorAxisInMetres/earthMajorAxisInMetres; - //es = 1.0 - temp * temp; temp = (earthMajorAxisInMetres - earthMinorAxisInMetres) / earthMajorAxisInMetres; es = 2 * temp - temp * temp; one_es = 1.0 - es; e = sqrt(es); - //printf("latFirstInRadians=%g, lonFirstInRadians=%g\n", latFirstInRadians, lonFirstInRadians); - coslam = cos(lonFirstInRadians - centralLongitudeInRadians); //cos(lp.lam); + + coslam = cos(lonFirstInRadians - centralLongitudeInRadians); /* cos(lp.lam) */ sinlam = sin(lonFirstInRadians - centralLongitudeInRadians); - sinphi = sin(latFirstInRadians); // sin(lp.phi); + sinphi = sin(latFirstInRadians); /* sin(lp.phi) */ q = pj_qsfn(sinphi, e, one_es); - //----------- setp start t = fabs(standardParallelInRadians); if (t > M_PI_2 + EPS10) { return GRIB_GEOCALCULUS_PROBLEM; } - //if (fabs(t - M_HALFPI) < EPS10) - // Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; - //else if (fabs(t) < EPS10) - // Q->mode = EQUIT; - //else - // Q->mode = OBLIQ; + /* if (fabs(t - M_HALFPI) < EPS10) + Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; + else if (fabs(t) < EPS10) + Q->mode = EQUIT; + else + Q->mode = OBLIQ; + */ Q__qp = pj_qsfn(1.0, e, one_es); Q__mmf = 0.5 / one_es; - pj_authset(es, APA); // sets up APA array + pj_authset(es, APA); /* sets up APA array */ Q__rq = sqrt(0.5 * Q__qp); - sinphi_ = sin(standardParallelInRadians); // (P->phi0); + sinphi_ = sin(standardParallelInRadians); /* (P->phi0); */ Q__sinb1 = pj_qsfn(sinphi_, e, one_es) / Q__qp; Q__cosb1 = sqrt(1.0 - Q__sinb1 * Q__sinb1); Q__dd = cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); Q__ymf = (Q__xmf = Q__rq) / Q__dd; Q__xmf *= Q__dd; - //----------- setup end sinb = q / Q__qp; cosb2 = 1.0 - sinb * sinb; @@ -225,11 +222,9 @@ static int init_oblate(grib_handle* h, } b = sqrt(2.0 / b); - // OBLIQUE + /* OBLIQUE */ y0 = Q__ymf * b * (Q__cosb1 * sinb - Q__sinb1 * cosb * coslam); x0 = Q__xmf * b * cosb * sinlam; - //y0 *= earthMajorAxisInMetres; - //x0 *= earthMajorAxisInMetres; /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); @@ -257,93 +252,33 @@ static int init_oblate(grib_handle* h, xy_x /= Q__dd; xy_y *= Q__dd; rho = hypot(xy_x, xy_y); - Assert(rho >= EPS10); // TODO(masn): check + Assert(rho >= EPS10); /* TODO(masn): check */ sCe = 2. * asin(.5 * rho / Q__rq); cCe = cos(sCe); sCe = sin(sCe); xy_x *= sCe; - // if oblique + /* if oblique */ ab = cCe * Q__sinb1 + xy_y * sCe * Q__cosb1 / rho; xy_y = rho * Q__cosb1 * cCe - xy_y * Q__sinb1 * sCe; - // else - //ab = xy.y * sCe / rho; - //xy.y = rho * cCe; - lp__lam = atan2(xy_x, xy_y); //longitude - lp__phi = pj_authlat(asin(ab), APA); // latitude - //printf("lp__phi=%g, lp__lam=%g\n", lp__phi, lp__lam); - //printf("lp__phi=%g, lp__lam=%g\n", lp__phi * RAD2DEG, lp__lam* RAD2DEG); + /* else + ab = xy.y * sCe / rho; + xy.y = rho * cCe; + */ + lp__lam = atan2(xy_x, xy_y); /* longitude */ + lp__phi = pj_authlat(asin(ab), APA); /* latitude */ *lats = lp__phi * RAD2DEG; *lons = (lp__lam + centralLongitudeInRadians) * RAD2DEG; - //rho = sqrt(x * x + ysq); - //if (rho > epsilon) { - // c = 2 * asin(rho / (2.0 * radius)); - // cosc = cos(c); - // sinc = sin(c); - // *lats = asin(cosc * sinphi1 + y * sinc * cosphi1 / rho) / d2r; - // *lons = (lambda0 + atan2(x * sinc, rho * cosphi1 * cosc - y * sinphi1 * sinc)) / d2r; - //} - //else { - // *lats = phi1 / d2r; - // *lons = lambda0 / d2r; - //} - //if (*lons < 0) *lons += 360; lons++; lats++; - //x += Dx; x += Dx / earthMajorAxisInMetres; } - //y += Dy; y += Dy / earthMajorAxisInMetres; } } -#if 0 - false_easting = x0; - false_northing = y0; - for (j = 0; j < ny; j++) { - y = j * Dy; - for (i = 0; i < nx; i++) { - double cCe, sCe, q, rho, ab=0.0, lp__lam, lp__phi, xy_x,xy_y; - const int index = i + j * nx; - - x = i * Dx; - xy_x = x; - xy_y = y; - /* Inverse projection to convert from x,y to lat,lon */ - //_x = x - false_easting; - //_y = rh - y + false_northing; - // calculate latRad and lonRad - xy_x /= Q__dd; - xy_y *= Q__dd; - rho = hypot(xy_x, xy_y); - Assert(rho >= EPS10); - sCe = 2. * asin(.5 * rho / Q__rq); - cCe = cos(sCe); - sCe = sin(sCe); - xy_x *= sCe; - // if oblique - ab = cCe * Q__sinb1 + xy_y * sCe * Q__cosb1 / rho; - xy_y = rho * Q__cosb1 * cCe - xy_y * Q__sinb1 * sCe; - // else - //ab = xy.y * sCe / rho; - //xy.y = rho * cCe; - - lp__lam = atan2(xy_x, xy_y); //longitude - lp__phi = pj_authlat(asin(ab), APA); // latitude - printf("lp__phi=%g, lp__lam=%g\n", lp__phi, lp__lam); - - latDeg = latRad * RAD2DEG; /* Convert to degrees */ - lonDeg = lonRad * RAD2DEG; - lonDeg = normalise_longitude_in_degrees(lonDeg); - self->lons[index] = lonDeg; - self->lats[index] = latDeg; - } - } -#endif - return GRIB_SUCCESS; } @@ -365,8 +300,8 @@ static int init_sphere(grib_handle* h, const double epsilon = 1.0e-20; const double d2r = acos(0.0) / 90.0; - lambda0 = centralLongitudeInRadians; // / 1000000; - phi1 = standardParallelInRadians; // / 1000000; + lambda0 = centralLongitudeInRadians; + phi1 = standardParallelInRadians; cosphi1 = cos(phi1); sinphi1 = sin(phi1); @@ -532,7 +467,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) lonFirstInRadians = lonFirstInDegrees * d2r; centralLongitudeInRadians = centralLongitudeInDegrees * d2r; standardParallelInRadians = standardParallelInDegrees * d2r; - //printf("latFirstInDegrees=%g, lonFirstInDegrees=%g\n",latFirstInDegrees,lonFirstInDegrees); + if (is_oblate) { err = init_oblate(h, self, iter->nv, nx, ny, Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, From 1bc6881dfc383871e19ccdc0ed699f39b908c8a3 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 2 Nov 2021 17:38:51 +0000 Subject: [PATCH 073/737] ECC-1291: Remove unused variables --- ...rator_class_lambert_azimuthal_equal_area.c | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index e46fd6d42..402b8bccb 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -170,11 +170,9 @@ static int init_oblate(grib_handle* h, long i, j; double x0, y0, x, y; double coslam, sinlam, sinphi, sinphi_, q, sinb = 0.0, cosb = 0.0, b = 0.0, cosb2; - double Q__qp = 0, Q__rq = 0, Q__mmf = 0, Q__cosb1, Q__sinb1, Q__dd, Q__xmf, Q__ymf, t; + double Q__qp = 0, Q__rq = 0, Q__cosb1, Q__sinb1, Q__dd, Q__xmf, Q__ymf, t; + /* double Q__mmf = 0; */ double e, es, temp, one_es; - double false_easting; /* x offset in meters */ - double false_northing; /* y offset in meters */ - double latRad = 0, lonRad = 0, latDeg, lonDeg; double APA[3] = {0,}; double xFirst, yFirst; @@ -185,10 +183,10 @@ static int init_oblate(grib_handle* h, es = 2 * temp - temp * temp; one_es = 1.0 - es; e = sqrt(es); - - coslam = cos(lonFirstInRadians - centralLongitudeInRadians); /* cos(lp.lam) */ + + coslam = cos(lonFirstInRadians - centralLongitudeInRadians); /* cos(lp.lam) */ sinlam = sin(lonFirstInRadians - centralLongitudeInRadians); - sinphi = sin(latFirstInRadians); /* sin(lp.phi) */ + sinphi = sin(latFirstInRadians); /* sin(lp.phi) */ q = pj_qsfn(sinphi, e, one_es); t = fabs(standardParallelInRadians); @@ -203,10 +201,10 @@ static int init_oblate(grib_handle* h, Q->mode = OBLIQ; */ Q__qp = pj_qsfn(1.0, e, one_es); - Q__mmf = 0.5 / one_es; - pj_authset(es, APA); /* sets up APA array */ + /* Q__mmf = 0.5 / one_es; ---- TODO(masn): do I need this? */ + pj_authset(es, APA); /* sets up APA array */ Q__rq = sqrt(0.5 * Q__qp); - sinphi_ = sin(standardParallelInRadians); /* (P->phi0); */ + sinphi_ = sin(standardParallelInRadians); /* (P->phi0); */ Q__sinb1 = pj_qsfn(sinphi_, e, one_es) / Q__qp; Q__cosb1 = sqrt(1.0 - Q__sinb1 * Q__sinb1); Q__dd = cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); @@ -248,11 +246,11 @@ static int init_oblate(grib_handle* h, for (j = 0; j < ny; j++) { x = xFirst; for (i = 0; i < nx; i++) { - double cCe, sCe, q, rho, ab = 0.0, lp__lam, lp__phi, xy_x = x, xy_y = y; + double cCe, sCe, rho, ab = 0.0, lp__lam, lp__phi, xy_x = x, xy_y = y; xy_x /= Q__dd; xy_y *= Q__dd; rho = hypot(xy_x, xy_y); - Assert(rho >= EPS10); /* TODO(masn): check */ + Assert(rho >= EPS10); /* TODO(masn): check */ sCe = 2. * asin(.5 * rho / Q__rq); cCe = cos(sCe); sCe = sin(sCe); @@ -264,8 +262,8 @@ static int init_oblate(grib_handle* h, ab = xy.y * sCe / rho; xy.y = rho * cCe; */ - lp__lam = atan2(xy_x, xy_y); /* longitude */ - lp__phi = pj_authlat(asin(ab), APA); /* latitude */ + lp__lam = atan2(xy_x, xy_y); /* longitude */ + lp__phi = pj_authlat(asin(ab), APA); /* latitude */ *lats = lp__phi * RAD2DEG; *lons = (lp__lam + centralLongitudeInRadians) * RAD2DEG; From 0fb40e7396e0600d0d0240ebd702e22c3d91a389 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Thu, 4 Nov 2021 11:07:09 +0000 Subject: [PATCH 074/737] Clang warning [-Wmissing-prototypes] --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 402b8bccb..0ba3be713 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -119,7 +119,7 @@ static int next(grib_iterator* i, double* lat, double* lon, double* val) #define P11 .06640211640211640212 /* 251 / 3780 */ #define P20 .01677689594356261023 /* 761 / 45360 */ -void pj_authset(double es, double* APA) +static void pj_authset(double es, double* APA) { double t; APA[0] = es * P00; @@ -131,7 +131,7 @@ void pj_authset(double es, double* APA) APA[1] += t * P11; APA[2] = t * P20; } -double pj_authlat(double beta, double* APA) +static double pj_authlat(double beta, double* APA) { double t = beta + beta; return (beta + APA[0] * sin(t) + APA[1] * sin(t + t) + APA[2] * sin(t + t + t)); From 8e76bd3f686e4dbafc88ebdcf8d0fa076ff8fc3f Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 6 Nov 2021 17:56:21 +0000 Subject: [PATCH 075/737] Cppcheck warnings: Const correctness --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 0ba3be713..f105094ae 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -131,7 +131,7 @@ static void pj_authset(double es, double* APA) APA[1] += t * P11; APA[2] = t * P20; } -static double pj_authlat(double beta, double* APA) +static double pj_authlat(double beta, const double* APA) { double t = beta + beta; return (beta + APA[0] * sin(t) + APA[1] * sin(t + t) + APA[2] * sin(t + t + t)); From 8314434b1a4fa7b32c19767eab73469c511e9a2f Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 3 Dec 2021 21:05:03 +0000 Subject: [PATCH 076/737] Cppcheck warnings --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index f105094ae..ebc2a9768 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -484,7 +484,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) iter->e = -1; - return err; + return GRIB_SUCCESS; } static int destroy(grib_iterator* i) From 750424d4d3d6b93ae0bbda9fd4ffcd2a4d0d2106 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 29 Jan 2022 15:49:44 +0000 Subject: [PATCH 077/737] ECC-1331: Better to fail rather than generate wrong results --- src/grib_iterator_class_polar_stereographic.c | 62 ++++++++++--------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 1a29fd567..d8c734b18 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -134,60 +134,66 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)iter; - const char* sradius = grib_arguments_get_name(h, args, self->carg++); - const char* snx = grib_arguments_get_name(h, args, self->carg++); - const char* sny = grib_arguments_get_name(h, args, self->carg++); - const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* ssouthPoleOnPlane = grib_arguments_get_name(h, args, self->carg++); - const char* scentralLongitude = grib_arguments_get_name(h, args, self->carg++); - const char* scentralLatitude = grib_arguments_get_name(h, args, self->carg++); - const char* sDx = grib_arguments_get_name(h, args, self->carg++); - const char* sDy = grib_arguments_get_name(h, args, self->carg++); - const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); + const char* s_radius = grib_arguments_get_name(h, args, self->carg++); + const char* s_nx = grib_arguments_get_name(h, args, self->carg++); + const char* s_ny = grib_arguments_get_name(h, args, self->carg++); + const char* s_latFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* s_lonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* s_southPoleOnPlane = grib_arguments_get_name(h, args, self->carg++); + const char* s_centralLongitude = grib_arguments_get_name(h, args, self->carg++); + const char* s_centralLatitude = grib_arguments_get_name(h, args, self->carg++); + const char* s_Dx = grib_arguments_get_name(h, args, self->carg++); + const char* s_Dy = grib_arguments_get_name(h, args, self->carg++); + const char* s_iScansNegatively = grib_arguments_get_name(h, args, self->carg++); + const char* s_jScansPositively = grib_arguments_get_name(h, args, self->carg++); + const char* s_jPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); + const char* s_alternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); if (grib_is_earth_oblate(h)) { grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic only supported for spherical earth."); return GRIB_GEOCALCULUS_PROBLEM; } - if ((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, s_radius, &radius)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, s_nx, &nx)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, s_ny, &ny)) != GRIB_SUCCESS) return ret; if (iter->nv != nx * ny) { grib_context_log(h->context, GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); return GRIB_WRONG_GRID; } - if ((ret = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, s_latFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_double_internal(h, slonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, s_lonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_long_internal(h, ssouthPoleOnPlane, &southPoleOnPlane)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, s_southPoleOnPlane, &southPoleOnPlane)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_long_internal(h, scentralLongitude, ¢ralLongitudeInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, s_centralLongitude, ¢ralLongitudeInDegrees)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_long_internal(h, scentralLatitude, ¢ralLatitudeInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, s_centralLatitude, ¢ralLatitudeInDegrees)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_double_internal(h, sDx, &Dx)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, s_Dx, &Dx)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_double_internal(h, sDy, &Dy)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, s_Dy, &Dy)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, s_jPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, s_jScansPositively, &jScansPositively)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, s_iScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_long_internal(h, salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) + if ((ret = grib_get_long_internal(h, s_alternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) return ret; + if (alternativeRowScanning) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic not supported when alternativeRowScanning=1 " + "i.e., When adjacent rows scan in the opposite direction"); + return GRIB_GEOCALCULUS_PROBLEM; + } + centralLongitude = centralLongitudeInDegrees * DEG2RAD; centralLatitude = centralLatitudeInDegrees * DEG2RAD; lonFirst = lonFirstInDegrees * DEG2RAD; From ce1a94518558a6c3cd7b782d5a53c3b824fdc5ce Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sun, 30 Jan 2022 22:26:38 +0000 Subject: [PATCH 078/737] ECC-1331: GRIB: Polar stereographic projection with alternativeRowScanning is incorrect --- src/grib_iterator_class_polar_stereographic.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index d8c734b18..42d7e64d6 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -188,12 +188,6 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) if ((ret = grib_get_long_internal(h, s_alternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) return ret; - if (alternativeRowScanning) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic not supported when alternativeRowScanning=1 " - "i.e., When adjacent rows scan in the opposite direction"); - return GRIB_GEOCALCULUS_PROBLEM; - } - centralLongitude = centralLongitudeInDegrees * DEG2RAD; centralLatitude = centralLatitudeInDegrees * DEG2RAD; lonFirst = lonFirstInDegrees * DEG2RAD; @@ -258,8 +252,9 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } lats = self->lats; lons = self->lons; - Dx = iScansNegatively == 0 ? Dx : -Dx; - Dy = jScansPositively == 1 ? Dy : -Dy; + /* These will be processed later in transform_iterator_data() */ + /* Dx = iScansNegatively == 0 ? Dx : -Dx; */ + /* Dy = jScansPositively == 1 ? Dy : -Dy; */ y = 0; for (j = 0; j < ny; j++) { @@ -359,6 +354,11 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) #endif iter->e = -1; + /* Apply the scanning mode flags which may require data array to be transformed */ + ret = transform_iterator_data(h, iter->data, + iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, + iter->nv, nx, ny); + return ret; } From 26b8eb8cde24d7163ff45777043bdb75a5d122ec Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sun, 6 Feb 2022 13:11:54 +0000 Subject: [PATCH 079/737] transform_iterator_data: No need to pass in handle. Also fix memory leak --- src/grib_iterator_class_lambert_conformal.c | 2 +- src/grib_iterator_class_polar_stereographic.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 153d9455a..8252a5d4e 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -480,7 +480,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) iter->e = -1; /* Apply the scanning mode flags which may require data array to be transformed */ - err = transform_iterator_data(h, iter->data, + err = transform_iterator_data(h->context, iter->data, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, iter->nv, nx, ny); return err; diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 42d7e64d6..70c6a60e9 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -355,7 +355,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) iter->e = -1; /* Apply the scanning mode flags which may require data array to be transformed */ - ret = transform_iterator_data(h, iter->data, + ret = transform_iterator_data(h->context, iter->data, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, iter->nv, nx, ny); From 2d3b807d38d2c8dcc7fd04d7cc6dd0128b2e99f5 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sun, 6 Feb 2022 17:45:29 +0000 Subject: [PATCH 080/737] Print name of Geoiterator in error messages --- src/grib_iterator_class_lambert_conformal.c | 17 +++++++++-------- src/grib_iterator_class_polar_stereographic.c | 6 +++--- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 8252a5d4e..7e2fffce7 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -205,12 +205,12 @@ static int init_sphere(grib_handle* h, /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert conformal Geoiterator: Error allocating %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert conformal Geoiterator: Error allocating %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } @@ -302,7 +302,7 @@ static int init_oblate(grib_handle* h, } else { con = latFirstInRadians * ns; if (con <= 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Point cannot be projected"); + grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert conformal Geoiterator: Point cannot be projected"); return GRIB_GEOCALCULUS_PROBLEM; } rh1 = 0; @@ -316,12 +316,12 @@ static int init_oblate(grib_handle* h, /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert conformal Geoiterator: Error allocating %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert conformal Geoiterator: Error allocating %ld bytes", nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } @@ -351,7 +351,8 @@ static int init_oblate(grib_handle* h, ts = pow((rh1 / (earthMajorAxisInMetres * F)), con); latRad = compute_phi(e, ts, &err); if (err) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Failed to compute the latitude angle, phi2, for the inverse"); + grib_context_log(h->context, GRIB_LOG_ERROR, + "Lambert conformal Geoiterator: Failed to compute the latitude angle, phi2, for the inverse"); grib_context_free(h->context, self->lats); grib_context_free(h->context, self->lons); return err; @@ -414,7 +415,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); + grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert conformal Geoiterator: Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); return GRIB_WRONG_GRID; } @@ -446,7 +447,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) /* Standard Parallels cannot be equal and on opposite sides of the equator */ if (fabs(Latin1InDegrees + Latin2InDegrees) < EPSILON) { grib_context_log(h->context, GRIB_LOG_ERROR, - "Cannot have equal latitudes for standard parallels on opposite sides of equator"); + "Lambert conformal Geoiterator: Cannot have equal latitudes for standard parallels on opposite sides of equator"); return GRIB_WRONG_GRID; } diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 70c6a60e9..8e252a0c2 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -162,7 +162,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return ret; if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); + grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic Geoiterator: Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); return GRIB_WRONG_GRID; } if ((ret = grib_get_double_internal(h, s_latFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) @@ -242,12 +242,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", iter->nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic Geoiterator: Error allocating %ld bytes", iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", iter->nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic Geoiterator: Error allocating %ld bytes", iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } lats = self->lats; From 5c5a9737251f0ccbfb9d0abd27b7d18d6e0eb8f7 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sun, 6 Feb 2022 18:50:04 +0000 Subject: [PATCH 081/737] Geoiterator: improved error messages --- src/grib_iterator_class_lambert_conformal.c | 17 +++++++++-------- src/grib_iterator_class_polar_stereographic.c | 10 ++++++---- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 7e2fffce7..f8c04392b 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -82,6 +82,7 @@ static void init_class(grib_iterator_class* c) } /* END_CLASS_IMP */ +#define ITER "Lambert conformal Geoiterator" #define EPSILON 1.0e-10 #ifndef M_PI @@ -205,12 +206,12 @@ static int init_sphere(grib_handle* h, /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert conformal Geoiterator: Error allocating %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert conformal Geoiterator: Error allocating %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } @@ -302,7 +303,7 @@ static int init_oblate(grib_handle* h, } else { con = latFirstInRadians * ns; if (con <= 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert conformal Geoiterator: Point cannot be projected"); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Point cannot be projected: latFirstInRadians=%g", ITER, latFirstInRadians); return GRIB_GEOCALCULUS_PROBLEM; } rh1 = 0; @@ -316,12 +317,12 @@ static int init_oblate(grib_handle* h, /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert conformal Geoiterator: Error allocating %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert conformal Geoiterator: Error allocating %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } @@ -352,7 +353,7 @@ static int init_oblate(grib_handle* h, latRad = compute_phi(e, ts, &err); if (err) { grib_context_log(h->context, GRIB_LOG_ERROR, - "Lambert conformal Geoiterator: Failed to compute the latitude angle, phi2, for the inverse"); + "%s: Failed to compute the latitude angle, phi2, for the inverse", ITER); grib_context_free(h->context, self->lats); grib_context_free(h->context, self->lons); return err; @@ -415,7 +416,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Lambert conformal Geoiterator: Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%ld!=%ldx%ld)", ITER, iter->nv, nx, ny); return GRIB_WRONG_GRID; } @@ -447,7 +448,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) /* Standard Parallels cannot be equal and on opposite sides of the equator */ if (fabs(Latin1InDegrees + Latin2InDegrees) < EPSILON) { grib_context_log(h->context, GRIB_LOG_ERROR, - "Lambert conformal Geoiterator: Cannot have equal latitudes for standard parallels on opposite sides of equator"); + "%s: Cannot have equal latitudes for standard parallels on opposite sides of equator", ITER); return GRIB_WRONG_GRID; } diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 8e252a0c2..223079c64 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -82,6 +82,8 @@ static void init_class(grib_iterator_class* c) } /* END_CLASS_IMP */ +#define ITER "Polar stereographic Geoiterator" + static int next(grib_iterator* i, double* lat, double* lon, double* val) { grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; @@ -150,7 +152,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) const char* s_alternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); if (grib_is_earth_oblate(h)) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic only supported for spherical earth."); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Only supported for spherical earth.", ITER); return GRIB_GEOCALCULUS_PROBLEM; } @@ -162,7 +164,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return ret; if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic Geoiterator: Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%ld!=%ldx%ld)", ITER, iter->nv, nx, ny); return GRIB_WRONG_GRID; } if ((ret = grib_get_double_internal(h, s_latFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) @@ -242,12 +244,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic Geoiterator: Error allocating %ld bytes", iter->nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Polar stereographic Geoiterator: Error allocating %ld bytes", iter->nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } lats = self->lats; From 983908836703fbf027e99b371e67dc98640ae3a4 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 4 Mar 2022 14:07:30 +0000 Subject: [PATCH 082/737] Refactoring: Remove unused keys --- src/grib_iterator_class_lambert_conformal.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index f8c04392b..843ad691b 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -170,8 +170,7 @@ static int init_sphere(grib_handle* h, double Dx, double Dy, double radius, double latFirstInRadians, double lonFirstInRadians, double LoVInRadians, double Latin1InRadians, double Latin2InRadians, - double LaDInRadians, - long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) + double LaDInRadians) { int i, j; double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; @@ -474,8 +473,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) LoVInDegrees, Dx, Dy, radius, latFirstInRadians, lonFirstInRadians, - LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians, - iScansNegatively, jScansPositively, jPointsAreConsecutive); + LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians); } if (err) return err; From 83107a1b203d5d094577f7d979654b0428740427 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 5 Apr 2022 16:37:01 +0100 Subject: [PATCH 083/737] Fix non-printable characters --- src/grib_iterator_class_lambert_conformal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 843ad691b..0733e2a05 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -110,8 +110,8 @@ static double adjust_lon_radians(double lon) /* Function to compute the latitude angle, phi2, for the inverse * From the book "Map Projections-A Working Manual-John P. Snyder (1987)" - * Equation (7–9) involves rapidly converging iteration: Calculate t from (15-11) - * Then, assuming an initial trial phi equal to (pi/2 - 2*arctan t) in the right side of equation (7–9), + * Equation (7-9) involves rapidly converging iteration: Calculate t from (15-11) + * Then, assuming an initial trial phi equal to (pi/2 - 2*arctan t) in the right side of equation (7-9), * calculate phi on the left side. Substitute the calculated phi) into the right side, * calculate a new phi, etc., until phi does not change significantly from the preceding trial value of phi */ From 11e930ec894f8d289722329237d547d1ee85aab1 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 14 Jun 2022 15:07:16 +0100 Subject: [PATCH 084/737] ECC-1403 continued: Add method unpack_double_element_set --- ...rator_class_lambert_azimuthal_equal_area.c | 45 +++++++++---------- src/grib_iterator_class_lambert_conformal.c | 45 +++++++++---------- src/grib_iterator_class_polar_stereographic.c | 45 +++++++++---------- src/grib_iterator_class_space_view.c | 45 +++++++++---------- 4 files changed, 88 insertions(+), 92 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index ebc2a9768..8998e7017 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -36,39 +36,38 @@ or edit "iterator.class" and rerun ./make_class.pl */ -static void init_class(grib_iterator_class*); +static void init_class (grib_iterator_class*); -static int init(grib_iterator* i, grib_handle*, grib_arguments*); -static int next(grib_iterator* i, double* lat, double* lon, double* val); -static int destroy(grib_iterator* i); +static int init (grib_iterator* i,grib_handle*,grib_arguments*); +static int next (grib_iterator* i, double *lat, double *lon, double *val); +static int destroy (grib_iterator* i); -typedef struct grib_iterator_lambert_azimuthal_equal_area -{ - grib_iterator it; +typedef struct grib_iterator_lambert_azimuthal_equal_area{ + grib_iterator it; /* Members defined in gen */ long carg; const char* missingValue; /* Members defined in lambert_azimuthal_equal_area */ - double* lats; - double* lons; + double *lats; + double *lons; long Nj; } grib_iterator_lambert_azimuthal_equal_area; extern grib_iterator_class* grib_iterator_class_gen; static grib_iterator_class _grib_iterator_class_lambert_azimuthal_equal_area = { - &grib_iterator_class_gen, /* super */ - "lambert_azimuthal_equal_area", /* name */ - sizeof(grib_iterator_lambert_azimuthal_equal_area), /* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ + &grib_iterator_class_gen, /* super */ + "lambert_azimuthal_equal_area", /* name */ + sizeof(grib_iterator_lambert_azimuthal_equal_area),/* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ }; grib_iterator_class* grib_iterator_class_lambert_azimuthal_equal_area = &_grib_iterator_class_lambert_azimuthal_equal_area; @@ -76,9 +75,9 @@ grib_iterator_class* grib_iterator_class_lambert_azimuthal_equal_area = &_grib_i static void init_class(grib_iterator_class* c) { - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; } /* END_CLASS_IMP */ diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 0733e2a05..4fd681cdb 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -36,39 +36,38 @@ or edit "iterator.class" and rerun ./make_class.pl */ -static void init_class(grib_iterator_class*); +static void init_class (grib_iterator_class*); -static int init(grib_iterator* i, grib_handle*, grib_arguments*); -static int next(grib_iterator* i, double* lat, double* lon, double* val); -static int destroy(grib_iterator* i); +static int init (grib_iterator* i,grib_handle*,grib_arguments*); +static int next (grib_iterator* i, double *lat, double *lon, double *val); +static int destroy (grib_iterator* i); -typedef struct grib_iterator_lambert_conformal -{ - grib_iterator it; +typedef struct grib_iterator_lambert_conformal{ + grib_iterator it; /* Members defined in gen */ long carg; const char* missingValue; /* Members defined in lambert_conformal */ - double* lats; - double* lons; + double *lats; + double *lons; long Nj; } grib_iterator_lambert_conformal; extern grib_iterator_class* grib_iterator_class_gen; static grib_iterator_class _grib_iterator_class_lambert_conformal = { - &grib_iterator_class_gen, /* super */ - "lambert_conformal", /* name */ - sizeof(grib_iterator_lambert_conformal), /* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ + &grib_iterator_class_gen, /* super */ + "lambert_conformal", /* name */ + sizeof(grib_iterator_lambert_conformal),/* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ }; grib_iterator_class* grib_iterator_class_lambert_conformal = &_grib_iterator_class_lambert_conformal; @@ -76,9 +75,9 @@ grib_iterator_class* grib_iterator_class_lambert_conformal = &_grib_iterator_cla static void init_class(grib_iterator_class* c) { - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; } /* END_CLASS_IMP */ diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 223079c64..542e9c155 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -36,39 +36,38 @@ or edit "iterator.class" and rerun ./make_class.pl */ -static void init_class(grib_iterator_class*); +static void init_class (grib_iterator_class*); -static int init(grib_iterator* i, grib_handle*, grib_arguments*); -static int next(grib_iterator* i, double* lat, double* lon, double* val); -static int destroy(grib_iterator* i); +static int init (grib_iterator* i,grib_handle*,grib_arguments*); +static int next (grib_iterator* i, double *lat, double *lon, double *val); +static int destroy (grib_iterator* i); -typedef struct grib_iterator_polar_stereographic -{ - grib_iterator it; +typedef struct grib_iterator_polar_stereographic{ + grib_iterator it; /* Members defined in gen */ long carg; const char* missingValue; /* Members defined in polar_stereographic */ - double* lats; - double* lons; + double *lats; + double *lons; long Nj; } grib_iterator_polar_stereographic; extern grib_iterator_class* grib_iterator_class_gen; static grib_iterator_class _grib_iterator_class_polar_stereographic = { - &grib_iterator_class_gen, /* super */ - "polar_stereographic", /* name */ - sizeof(grib_iterator_polar_stereographic), /* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ + &grib_iterator_class_gen, /* super */ + "polar_stereographic", /* name */ + sizeof(grib_iterator_polar_stereographic),/* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ }; grib_iterator_class* grib_iterator_class_polar_stereographic = &_grib_iterator_class_polar_stereographic; @@ -76,9 +75,9 @@ grib_iterator_class* grib_iterator_class_polar_stereographic = &_grib_iterator_c static void init_class(grib_iterator_class* c) { - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; } /* END_CLASS_IMP */ diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index 90456fc56..c42a2bbe1 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -36,39 +36,38 @@ or edit "iterator.class" and rerun ./make_class.pl */ -static void init_class(grib_iterator_class*); +static void init_class (grib_iterator_class*); -static int init(grib_iterator* i, grib_handle*, grib_arguments*); -static int next(grib_iterator* i, double* lat, double* lon, double* val); -static int destroy(grib_iterator* i); +static int init (grib_iterator* i,grib_handle*,grib_arguments*); +static int next (grib_iterator* i, double *lat, double *lon, double *val); +static int destroy (grib_iterator* i); -typedef struct grib_iterator_space_view -{ - grib_iterator it; +typedef struct grib_iterator_space_view{ + grib_iterator it; /* Members defined in gen */ long carg; const char* missingValue; /* Members defined in space_view */ - double* lats; - double* lons; + double *lats; + double *lons; long Nj; } grib_iterator_space_view; extern grib_iterator_class* grib_iterator_class_gen; static grib_iterator_class _grib_iterator_class_space_view = { - &grib_iterator_class_gen, /* super */ - "space_view", /* name */ - sizeof(grib_iterator_space_view), /* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ + &grib_iterator_class_gen, /* super */ + "space_view", /* name */ + sizeof(grib_iterator_space_view),/* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ }; grib_iterator_class* grib_iterator_class_space_view = &_grib_iterator_class_space_view; @@ -76,9 +75,9 @@ grib_iterator_class* grib_iterator_class_space_view = &_grib_iterator_class_spac static void init_class(grib_iterator_class* c) { - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; } /* END_CLASS_IMP */ From 1e77fe16fbf640a3417f782a1e361278acd527e9 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 6 Jan 2023 15:10:38 +0000 Subject: [PATCH 085/737] Warnings: implicit conversion loses integer precision --- src/grib_iterator_class_lambert_azimuthal_equal_area.c | 2 +- src/grib_iterator_class_lambert_conformal.c | 2 +- src/grib_iterator_class_polar_stereographic.c | 2 +- src/grib_iterator_class_space_view.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c index 8998e7017..5d54aee88 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.c @@ -46,7 +46,7 @@ static int destroy (grib_iterator* i); typedef struct grib_iterator_lambert_azimuthal_equal_area{ grib_iterator it; /* Members defined in gen */ - long carg; + int carg; const char* missingValue; /* Members defined in lambert_azimuthal_equal_area */ double *lats; diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c index 4fd681cdb..a39b314ab 100644 --- a/src/grib_iterator_class_lambert_conformal.c +++ b/src/grib_iterator_class_lambert_conformal.c @@ -46,7 +46,7 @@ static int destroy (grib_iterator* i); typedef struct grib_iterator_lambert_conformal{ grib_iterator it; /* Members defined in gen */ - long carg; + int carg; const char* missingValue; /* Members defined in lambert_conformal */ double *lats; diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c index 542e9c155..0e3988030 100644 --- a/src/grib_iterator_class_polar_stereographic.c +++ b/src/grib_iterator_class_polar_stereographic.c @@ -46,7 +46,7 @@ static int destroy (grib_iterator* i); typedef struct grib_iterator_polar_stereographic{ grib_iterator it; /* Members defined in gen */ - long carg; + int carg; const char* missingValue; /* Members defined in polar_stereographic */ double *lats; diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c index c42a2bbe1..355acfa13 100644 --- a/src/grib_iterator_class_space_view.c +++ b/src/grib_iterator_class_space_view.c @@ -46,7 +46,7 @@ static int destroy (grib_iterator* i); typedef struct grib_iterator_space_view{ grib_iterator it; /* Members defined in gen */ - long carg; + int carg; const char* missingValue; /* Members defined in space_view */ double *lats; From 1de6e9a85ee689d748504044e3fe7f60f4855095 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 28 Jan 2023 15:18:23 +0000 Subject: [PATCH 086/737] ECC-1508: Set project language to be C++ --- ...rator_class_lambert_azimuthal_equal_area.c | 497 ----------------- src/grib_iterator_class_lambert_conformal.c | 511 ------------------ src/grib_iterator_class_polar_stereographic.c | 374 ------------- src/grib_iterator_class_space_view.c | 388 ------------- 4 files changed, 1770 deletions(-) delete mode 100644 src/grib_iterator_class_lambert_azimuthal_equal_area.c delete mode 100644 src/grib_iterator_class_lambert_conformal.c delete mode 100644 src/grib_iterator_class_polar_stereographic.c delete mode 100644 src/grib_iterator_class_space_view.c diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.c b/src/grib_iterator_class_lambert_azimuthal_equal_area.c deleted file mode 100644 index 5d54aee88..000000000 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * (C) Copyright 2005- 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" -#include - -/* - This is used by make_class.pl - - START_CLASS_DEF - CLASS = iterator - SUPER = grib_iterator_class_gen - IMPLEMENTS = destroy - IMPLEMENTS = init;next - MEMBERS = double *lats - MEMBERS = double *lons - MEMBERS = long Nj - 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 "iterator.class" and rerun ./make_class.pl - -*/ - - -static void init_class (grib_iterator_class*); - -static int init (grib_iterator* i,grib_handle*,grib_arguments*); -static int next (grib_iterator* i, double *lat, double *lon, double *val); -static int destroy (grib_iterator* i); - - -typedef struct grib_iterator_lambert_azimuthal_equal_area{ - grib_iterator it; - /* Members defined in gen */ - int carg; - const char* missingValue; - /* Members defined in lambert_azimuthal_equal_area */ - double *lats; - double *lons; - long Nj; -} grib_iterator_lambert_azimuthal_equal_area; - -extern grib_iterator_class* grib_iterator_class_gen; - -static grib_iterator_class _grib_iterator_class_lambert_azimuthal_equal_area = { - &grib_iterator_class_gen, /* super */ - "lambert_azimuthal_equal_area", /* name */ - sizeof(grib_iterator_lambert_azimuthal_equal_area),/* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ -}; - -grib_iterator_class* grib_iterator_class_lambert_azimuthal_equal_area = &_grib_iterator_class_lambert_azimuthal_equal_area; - - -static void init_class(grib_iterator_class* c) -{ - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; -} -/* END_CLASS_IMP */ - -static int next(grib_iterator* i, double* lat, double* lon, double* val) -{ - grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; - - if ((long)i->e >= (long)(i->nv - 1)) - return 0; - i->e++; - - *lat = self->lats[i->e]; - *lon = self->lons[i->e]; - *val = i->data[i->e]; - - return 1; -} - -#ifndef M_PI -#define M_PI 3.14159265358979323846 /* Whole pie */ -#endif - -#ifndef M_PI_2 -#define M_PI_2 1.57079632679489661923 /* Half a pie */ -#endif - -#ifndef M_PI_4 -#define M_PI_4 0.78539816339744830962 /* Quarter of a pie */ -#endif - -#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ -#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ - -#define P00 .33333333333333333333 /* 1 / 3 */ -#define P01 .17222222222222222222 /* 31 / 180 */ -#define P02 .10257936507936507937 /* 517 / 5040 */ -#define P10 .06388888888888888888 /* 23 / 360 */ -#define P11 .06640211640211640212 /* 251 / 3780 */ -#define P20 .01677689594356261023 /* 761 / 45360 */ - -static void pj_authset(double es, double* APA) -{ - double t; - APA[0] = es * P00; - t = es * es; - APA[0] += t * P01; - APA[1] = t * P10; - t *= es; - APA[0] += t * P02; - APA[1] += t * P11; - APA[2] = t * P20; -} -static double pj_authlat(double beta, const double* APA) -{ - double t = beta + beta; - return (beta + APA[0] * sin(t) + APA[1] * sin(t + t) + APA[2] * sin(t + t + t)); -} - -static double pj_qsfn(double sinphi, double e, double one_es) -{ - double con, div1, div2; - const double EPSILON = 1.0e-7; - - if (e >= EPSILON) { - con = e * sinphi; - div1 = 1.0 - con * con; - div2 = 1.0 + con; - - /* avoid zero division, fail gracefully */ - if (div1 == 0.0 || div2 == 0.0) - return HUGE_VAL; - - return (one_es * (sinphi / div1 - (.5 / e) * log((1. - con) / div2))); - } - else - return (sinphi + sinphi); -} - -#define EPS10 1.e-10 -static int init_oblate(grib_handle* h, - grib_iterator_lambert_azimuthal_equal_area* self, - size_t nv, long nx, long ny, - double Dx, double Dy, double earthMinorAxisInMetres, double earthMajorAxisInMetres, - double latFirstInRadians, double lonFirstInRadians, - double centralLongitudeInRadians, double standardParallelInRadians, - long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) -{ - double *lats, *lons; - long i, j; - double x0, y0, x, y; - double coslam, sinlam, sinphi, sinphi_, q, sinb = 0.0, cosb = 0.0, b = 0.0, cosb2; - double Q__qp = 0, Q__rq = 0, Q__cosb1, Q__sinb1, Q__dd, Q__xmf, Q__ymf, t; - /* double Q__mmf = 0; */ - double e, es, temp, one_es; - double APA[3] = {0,}; - double xFirst, yFirst; - - Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; - Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; - - temp = (earthMajorAxisInMetres - earthMinorAxisInMetres) / earthMajorAxisInMetres; - es = 2 * temp - temp * temp; - one_es = 1.0 - es; - e = sqrt(es); - - coslam = cos(lonFirstInRadians - centralLongitudeInRadians); /* cos(lp.lam) */ - sinlam = sin(lonFirstInRadians - centralLongitudeInRadians); - sinphi = sin(latFirstInRadians); /* sin(lp.phi) */ - q = pj_qsfn(sinphi, e, one_es); - - t = fabs(standardParallelInRadians); - if (t > M_PI_2 + EPS10) { - return GRIB_GEOCALCULUS_PROBLEM; - } - /* if (fabs(t - M_HALFPI) < EPS10) - Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; - else if (fabs(t) < EPS10) - Q->mode = EQUIT; - else - Q->mode = OBLIQ; - */ - Q__qp = pj_qsfn(1.0, e, one_es); - /* Q__mmf = 0.5 / one_es; ---- TODO(masn): do I need this? */ - pj_authset(es, APA); /* sets up APA array */ - Q__rq = sqrt(0.5 * Q__qp); - sinphi_ = sin(standardParallelInRadians); /* (P->phi0); */ - Q__sinb1 = pj_qsfn(sinphi_, e, one_es) / Q__qp; - Q__cosb1 = sqrt(1.0 - Q__sinb1 * Q__sinb1); - Q__dd = cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); - Q__ymf = (Q__xmf = Q__rq) / Q__dd; - Q__xmf *= Q__dd; - - sinb = q / Q__qp; - cosb2 = 1.0 - sinb * sinb; - cosb = cosb2 > 0 ? sqrt(cosb2) : 0; - b = 1. + Q__sinb1 * sinb + Q__cosb1 * cosb * coslam; - if (fabs(b) < EPS10) { - return GRIB_GEOCALCULUS_PROBLEM; - } - b = sqrt(2.0 / b); - - /* OBLIQUE */ - y0 = Q__ymf * b * (Q__cosb1 * sinb - Q__sinb1 * cosb * coslam); - x0 = Q__xmf * b * cosb * sinlam; - - /* Allocate latitude and longitude arrays */ - self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - lats = self->lats; - lons = self->lons; - - /* Populate the lat and lon arrays */ - { - xFirst = x0; - yFirst = y0; - y = yFirst; - for (j = 0; j < ny; j++) { - x = xFirst; - for (i = 0; i < nx; i++) { - double cCe, sCe, rho, ab = 0.0, lp__lam, lp__phi, xy_x = x, xy_y = y; - xy_x /= Q__dd; - xy_y *= Q__dd; - rho = hypot(xy_x, xy_y); - Assert(rho >= EPS10); /* TODO(masn): check */ - sCe = 2. * asin(.5 * rho / Q__rq); - cCe = cos(sCe); - sCe = sin(sCe); - xy_x *= sCe; - /* if oblique */ - ab = cCe * Q__sinb1 + xy_y * sCe * Q__cosb1 / rho; - xy_y = rho * Q__cosb1 * cCe - xy_y * Q__sinb1 * sCe; - /* else - ab = xy.y * sCe / rho; - xy.y = rho * cCe; - */ - lp__lam = atan2(xy_x, xy_y); /* longitude */ - lp__phi = pj_authlat(asin(ab), APA); /* latitude */ - - *lats = lp__phi * RAD2DEG; - *lons = (lp__lam + centralLongitudeInRadians) * RAD2DEG; - - lons++; - lats++; - - x += Dx / earthMajorAxisInMetres; - } - y += Dy / earthMajorAxisInMetres; - } - } - - return GRIB_SUCCESS; -} - -static int init_sphere(grib_handle* h, - grib_iterator_lambert_azimuthal_equal_area* self, - size_t nv, long nx, long ny, - double Dx, double Dy, double radius, - double latFirstInRadians, double lonFirstInRadians, - double centralLongitudeInRadians, double standardParallelInRadians, - long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) -{ - double *lats, *lons; - double phi1, lambda0, xFirst, yFirst, x, y; - double kp, sinphi1, cosphi1; - double sinphi, cosphi, cosdlambda, sindlambda; - double cosc, sinc; - long i, j; - double c, rho; - const double epsilon = 1.0e-20; - const double d2r = acos(0.0) / 90.0; - - lambda0 = centralLongitudeInRadians; - phi1 = standardParallelInRadians; - - cosphi1 = cos(phi1); - sinphi1 = sin(phi1); - - Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; - Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; - self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "Error allocating %ld bytes", nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "Error allocating %ld bytes", nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - lats = self->lats; - lons = self->lons; - - /* compute xFirst,yFirst in metres */ - sinphi = sin(latFirstInRadians); - cosphi = cos(latFirstInRadians); - cosdlambda = cos(lonFirstInRadians - lambda0); - sindlambda = sin(lonFirstInRadians - lambda0); - kp = radius * sqrt(2.0 / (1 + sinphi1 * sinphi + cosphi1 * cosphi * cosdlambda)); - xFirst = kp * cosphi * sindlambda; - yFirst = kp * (cosphi1 * sinphi - sinphi1 * cosphi * cosdlambda); - - if (jPointsAreConsecutive) { - x = xFirst; - for (i = 0; i < nx; i++) { - double xsq = x * x; - y = yFirst; - for (j = 0; j < ny; j++) { - rho = sqrt(xsq + y * y); - if (rho > epsilon) { - c = 2 * asin(rho / (2.0 * radius)); - cosc = cos(c); - sinc = sin(c); - *lats = asin(cosc * sinphi1 + y * sinc * cosphi1 / rho) / d2r; - *lons = (lambda0 + atan2(x * sinc, rho * cosphi1 * cosc - y * sinphi1 * sinc)) / d2r; - } - else { - *lats = phi1 / d2r; - *lons = lambda0 / d2r; - } - if (*lons < 0) - *lons += 360; - lons++; - lats++; - - y += Dy; - } - x += Dx; - } - } - else { - y = yFirst; - for (j = 0; j < ny; j++) { - double ysq = y * y; - x = xFirst; - for (i = 0; i < nx; i++) { - rho = sqrt(x * x + ysq); - if (rho > epsilon) { - c = 2 * asin(rho / (2.0 * radius)); - cosc = cos(c); - sinc = sin(c); - *lats = asin(cosc * sinphi1 + y * sinc * cosphi1 / rho) / d2r; - *lons = (lambda0 + atan2(x * sinc, rho * cosphi1 * cosc - y * sinphi1 * sinc)) / d2r; - } - else { - *lats = phi1 / d2r; - *lons = lambda0 / d2r; - } - if (*lons < 0) - *lons += 360; - lons++; - lats++; - - x += Dx; - } - y += Dy; - } - } - return GRIB_SUCCESS; -} - -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) -{ - int err = 0; - int is_oblate = 0; - double lonFirstInDegrees, latFirstInDegrees, lonFirstInRadians, latFirstInRadians, radius = 0; - long nx, ny; - double standardParallelInDegrees, centralLongitudeInDegrees; - double standardParallelInRadians, centralLongitudeInRadians; - double Dx, Dy; - long alternativeRowScanning, iScansNegatively; - long jScansPositively, jPointsAreConsecutive; - double earthMajorAxisInMetres = 0, earthMinorAxisInMetres = 0; - - grib_iterator_lambert_azimuthal_equal_area* self = - (grib_iterator_lambert_azimuthal_equal_area*)iter; - - const char* sradius = grib_arguments_get_name(h, args, self->carg++); - const char* snx = grib_arguments_get_name(h, args, self->carg++); - const char* sny = grib_arguments_get_name(h, args, self->carg++); - const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sstandardParallel = grib_arguments_get_name(h, args, self->carg++); - const char* scentralLongitude = grib_arguments_get_name(h, args, self->carg++); - const char* sDx = grib_arguments_get_name(h, args, self->carg++); - const char* sDy = grib_arguments_get_name(h, args, self->carg++); - const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); - const double d2r = acos(0.0) / 90.0; - - is_oblate = grib_is_earth_oblate(h); - if (is_oblate) { - if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; - if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; - } - else { - if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) return err; - } - - if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) - return err; - - if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "Wrong number of points (%ld!=%ldx%ld)", - iter->nv, nx, ny); - return GRIB_WRONG_GRID; - } - if ((err = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, slonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sstandardParallel, &standardParallelInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, scentralLongitude, ¢ralLongitudeInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sDx, &Dx)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sDy, &Dy)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) - return err; - - latFirstInRadians = latFirstInDegrees * d2r; - lonFirstInRadians = lonFirstInDegrees * d2r; - centralLongitudeInRadians = centralLongitudeInDegrees * d2r; - standardParallelInRadians = standardParallelInDegrees * d2r; - - if (is_oblate) { - err = init_oblate(h, self, iter->nv, nx, ny, - Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, - latFirstInRadians, lonFirstInRadians, - centralLongitudeInRadians, standardParallelInRadians, - iScansNegatively, jScansPositively, jPointsAreConsecutive); - } - else { - err = init_sphere(h, self, iter->nv, nx, ny, - Dx, Dy, radius, - latFirstInRadians, lonFirstInRadians, - centralLongitudeInRadians, standardParallelInRadians, - iScansNegatively, jScansPositively, jPointsAreConsecutive); - } - if (err) return err; - - iter->e = -1; - - return GRIB_SUCCESS; -} - -static int destroy(grib_iterator* i) -{ - grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; - const grib_context* c = i->h->context; - - grib_context_free(c, self->lats); - grib_context_free(c, self->lons); - return 1; -} diff --git a/src/grib_iterator_class_lambert_conformal.c b/src/grib_iterator_class_lambert_conformal.c deleted file mode 100644 index a39b314ab..000000000 --- a/src/grib_iterator_class_lambert_conformal.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * (C) Copyright 2005- 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" -#include - -/* - This is used by make_class.pl - - START_CLASS_DEF - CLASS = iterator - SUPER = grib_iterator_class_gen - IMPLEMENTS = destroy - IMPLEMENTS = init;next - MEMBERS = double *lats - MEMBERS = double *lons - MEMBERS = long Nj - 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 "iterator.class" and rerun ./make_class.pl - -*/ - - -static void init_class (grib_iterator_class*); - -static int init (grib_iterator* i,grib_handle*,grib_arguments*); -static int next (grib_iterator* i, double *lat, double *lon, double *val); -static int destroy (grib_iterator* i); - - -typedef struct grib_iterator_lambert_conformal{ - grib_iterator it; - /* Members defined in gen */ - int carg; - const char* missingValue; - /* Members defined in lambert_conformal */ - double *lats; - double *lons; - long Nj; -} grib_iterator_lambert_conformal; - -extern grib_iterator_class* grib_iterator_class_gen; - -static grib_iterator_class _grib_iterator_class_lambert_conformal = { - &grib_iterator_class_gen, /* super */ - "lambert_conformal", /* name */ - sizeof(grib_iterator_lambert_conformal),/* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ -}; - -grib_iterator_class* grib_iterator_class_lambert_conformal = &_grib_iterator_class_lambert_conformal; - - -static void init_class(grib_iterator_class* c) -{ - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; -} -/* END_CLASS_IMP */ - -#define ITER "Lambert conformal Geoiterator" -#define EPSILON 1.0e-10 - -#ifndef M_PI -#define M_PI 3.14159265358979323846 /* Whole pie */ -#endif - -#ifndef M_PI_2 -#define M_PI_2 1.57079632679489661923 /* Half a pie */ -#endif - -#ifndef M_PI_4 -#define M_PI_4 0.78539816339744830962 /* Quarter of a pie */ -#endif - -#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ -#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ - -/* Adjust longitude (in radians) to range -180 to 180 */ -static double adjust_lon_radians(double lon) -{ - if (lon > M_PI) lon -= 2 * M_PI; - if (lon < -M_PI) lon += 2 * M_PI; - return lon; -} - -/* Function to compute the latitude angle, phi2, for the inverse - * From the book "Map Projections-A Working Manual-John P. Snyder (1987)" - * Equation (7-9) involves rapidly converging iteration: Calculate t from (15-11) - * Then, assuming an initial trial phi equal to (pi/2 - 2*arctan t) in the right side of equation (7-9), - * calculate phi on the left side. Substitute the calculated phi) into the right side, - * calculate a new phi, etc., until phi does not change significantly from the preceding trial value of phi - */ -static double compute_phi( - double eccent, /* Spheroid eccentricity */ - double ts, /* Constant value t */ - int* error) -{ - double eccnth, phi, con, dphi, sinpi; - int i, MAX_ITER = 15; - - eccnth = 0.5 * eccent; - phi = M_PI_2 - 2 * atan(ts); - for (i = 0; i <= MAX_ITER; i++) { - sinpi = sin(phi); - con = eccent * sinpi; - dphi = M_PI_2 - 2 * atan(ts * (pow(((1.0 - con) / (1.0 + con)), eccnth))) - phi; - phi += dphi; - if (fabs(dphi) <= 0.0000000001) - return (phi); - } - *error = GRIB_INTERNAL_ERROR; - return 0; -} - -/* Compute the constant small m which is the radius of - a parallel of latitude, phi, divided by the semimajor axis */ -static double compute_m(double eccent, double sinphi, double cosphi) -{ - const double con = eccent * sinphi; - return ((cosphi / (sqrt(1.0 - con * con)))); -} - -/* Compute the constant small t for use in the forward computations */ -static double compute_t( - double eccent, /* Eccentricity of the spheroid */ - double phi, /* Latitude phi */ - double sinphi) /* Sine of the latitude */ -{ - double con = eccent * sinphi; - double com = 0.5 * eccent; - con = pow(((1.0 - con) / (1.0 + con)), com); - return (tan(0.5 * (M_PI_2 - phi)) / con); -} - -static double calculate_eccentricity(double minor, double major) -{ - const double temp = minor / major; - return sqrt(1.0 - temp * temp); -} - -static int init_sphere(grib_handle* h, - grib_iterator_lambert_conformal* self, - size_t nv, long nx, long ny, - double LoVInDegrees, - double Dx, double Dy, double radius, - double latFirstInRadians, double lonFirstInRadians, - double LoVInRadians, double Latin1InRadians, double Latin2InRadians, - double LaDInRadians) -{ - int i, j; - double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; - double latDeg, lonDeg, lonDiff; - - if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { - n = sin(Latin1InRadians); - } else { - n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) / - log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); - } - - f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; - rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); - rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); - if (n < 0) /* adjustment for southern hemisphere */ - rho0 = -rho0; - lonDiff = lonFirstInRadians - LoVInRadians; - - /* Adjust longitude to range -180 to 180 */ - if (lonDiff > M_PI) - lonDiff -= 2 * M_PI; - if (lonDiff < -M_PI) - lonDiff += 2 * M_PI; - angle = n * lonDiff; - x0 = rho * sin(angle); - y0 = rho0 - rho * cos(angle); - /*Dx = iScansNegatively == 0 ? Dx : -Dx;*/ - /* GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint */ - /*Dy = jScansPositively == 1 ? Dy : -Dy;*/ - - /* Allocate latitude and longitude arrays */ - self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - - /* Populate our arrays */ - for (j = 0; j < ny; j++) { - y = y0 + j * Dy; - if (n < 0) { /* adjustment for southern hemisphere */ - y = -y; - } - tmp = rho0 - y; - tmp2 = tmp * tmp; - for (i = 0; i < nx; i++) { - int index = i + j * nx; - x = x0 + i * Dx; - if (n < 0) { /* adjustment for southern hemisphere */ - x = -x; - } - angle = atan2(x, tmp); /* See ECC-524 */ - rho = sqrt(x * x + tmp2); - if (n <= 0) rho = -rho; - lonDeg = LoVInDegrees + (angle / n) * RAD2DEG; - latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * RAD2DEG; - lonDeg = normalise_longitude_in_degrees(lonDeg); - self->lons[index] = lonDeg; - self->lats[index] = latDeg; - } - } - - return GRIB_SUCCESS; -} - -/* Oblate spheroid */ -static int init_oblate(grib_handle* h, - grib_iterator_lambert_conformal* self, - size_t nv, long nx, long ny, - double LoVInDegrees, - double Dx, double Dy, - double earthMinorAxisInMetres, double earthMajorAxisInMetres, - double latFirstInRadians, double lonFirstInRadians, - double LoVInRadians, double Latin1InRadians, double Latin2InRadians, - double LaDInRadians) -{ - int i, j, err = 0; - double x0, y0, x, y, latRad, lonRad, latDeg, lonDeg, sinphi, ts, rh1, theta; - double false_easting; /* x offset in meters */ - double false_northing; /* y offset in meters */ - - double ns; /* ratio of angle between meridian */ - double F; /* flattening of ellipsoid */ - double rh; /* height above ellipsoid */ - double sin_po; /* sin value */ - double cos_po; /* cos value */ - double con; /* temporary variable */ - double ms1; /* small m 1 */ - double ms2; /* small m 2 */ - double ts0; /* small t 0 */ - double ts1; /* small t 1 */ - double ts2; /* small t 2 */ - - double e = calculate_eccentricity(earthMinorAxisInMetres, earthMajorAxisInMetres); - - sin_po = sin(Latin1InRadians); - cos_po = cos(Latin1InRadians); - con = sin_po; - ms1 = compute_m(e, sin_po, cos_po); - ts1 = compute_t(e, Latin1InRadians, sin_po); - - sin_po = sin(Latin2InRadians); - cos_po = cos(Latin2InRadians); - ms2 = compute_m(e, sin_po, cos_po); - ts2 = compute_t(e, Latin2InRadians, sin_po); - sin_po = sin(LaDInRadians); - ts0 = compute_t(e, LaDInRadians, sin_po); - - if (fabs(Latin1InRadians - Latin2InRadians) > EPSILON) { - ns = log(ms1 / ms2) / log(ts1 / ts2); - } else { - ns = con; - } - F = ms1 / (ns * pow(ts1, ns)); - rh = earthMajorAxisInMetres * F * pow(ts0, ns); - - /* Forward projection: convert lat,lon to x,y */ - con = fabs(fabs(latFirstInRadians) - M_PI_2); - if (con > EPSILON) { - sinphi = sin(latFirstInRadians); - ts = compute_t(e, latFirstInRadians, sinphi); - rh1 = earthMajorAxisInMetres * F * pow(ts, ns); - } else { - con = latFirstInRadians * ns; - if (con <= 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Point cannot be projected: latFirstInRadians=%g", ITER, latFirstInRadians); - return GRIB_GEOCALCULUS_PROBLEM; - } - rh1 = 0; - } - theta = ns * adjust_lon_radians(lonFirstInRadians - LoVInRadians); - x0 = rh1 * sin(theta); - y0 = rh - rh1 * cos(theta); - x0 = -x0; - y0 = -y0; - - /* Allocate latitude and longitude arrays */ - self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - - /* Populate our arrays */ - false_easting = x0; - false_northing = y0; - for (j = 0; j < ny; j++) { - y = j * Dy; - for (i = 0; i < nx; i++) { - const int index = i + j * nx; - double _x, _y; - x = i * Dx; - /* Inverse projection to convert from x,y to lat,lon */ - _x = x - false_easting; - _y = rh - y + false_northing; - rh1 = sqrt(_x * _x + _y * _y); - con = 1.0; - if (ns <= 0) { - rh1 = -rh1; - con = -con; - } - theta = 0.0; - if (rh1 != 0) - theta = atan2((con * _x), (con * _y)); - if ((rh1 != 0) || (ns > 0.0)) { - con = 1.0 / ns; - ts = pow((rh1 / (earthMajorAxisInMetres * F)), con); - latRad = compute_phi(e, ts, &err); - if (err) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "%s: Failed to compute the latitude angle, phi2, for the inverse", ITER); - grib_context_free(h->context, self->lats); - grib_context_free(h->context, self->lons); - return err; - } - } else { - latRad = -M_PI_2; - } - lonRad = adjust_lon_radians(theta / ns + LoVInRadians); - if (i == 0 && j == 0) { - DebugAssert(fabs(latFirstInRadians - latRad) <= EPSILON); - } - latDeg = latRad * RAD2DEG; /* Convert to degrees */ - lonDeg = normalise_longitude_in_degrees(lonRad * RAD2DEG); - self->lons[index] = lonDeg; - self->lats[index] = latDeg; - } - } - return GRIB_SUCCESS; -} - -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) -{ - int err = 0, is_oblate = 0; - long nx, ny, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning; - double LoVInDegrees, LaDInDegrees, Latin1InDegrees, Latin2InDegrees, latFirstInDegrees, - lonFirstInDegrees, Dx, Dy, radius = 0; - double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, - LaDInRadians; - double earthMajorAxisInMetres=0, earthMinorAxisInMetres=0; - - grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; - - const char* sradius = grib_arguments_get_name(h, args, self->carg++); - const char* snx = grib_arguments_get_name(h, args, self->carg++); - const char* sny = grib_arguments_get_name(h, args, self->carg++); - const char* sLoVInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sLaDInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sLatin1InDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sLatin2InDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - /* Dx and Dy are in Metres */ - const char* sDx = grib_arguments_get_name(h, args, self->carg++); - const char* sDy = grib_arguments_get_name(h, args, self->carg++); - const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); - - if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) return err; - if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) return err; - - is_oblate = grib_is_earth_oblate(h); - - if (is_oblate) { - if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; - if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; - } else { - if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) return err; - } - - if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%ld!=%ldx%ld)", ITER, iter->nv, nx, ny); - return GRIB_WRONG_GRID; - } - - if ((err = grib_get_double_internal(h, sLoVInDegrees, &LoVInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sLaDInDegrees, &LaDInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sLatin1InDegrees, &Latin1InDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sLatin2InDegrees, &Latin2InDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, slonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sDx, &Dx)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sDy, &Dy)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) - return err; - - /* Standard Parallels cannot be equal and on opposite sides of the equator */ - if (fabs(Latin1InDegrees + Latin2InDegrees) < EPSILON) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "%s: Cannot have equal latitudes for standard parallels on opposite sides of equator", ITER); - return GRIB_WRONG_GRID; - } - - /* - * See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html - */ - latFirstInRadians = latFirstInDegrees * DEG2RAD; - lonFirstInRadians = lonFirstInDegrees * DEG2RAD; - Latin1InRadians = Latin1InDegrees * DEG2RAD; - Latin2InRadians = Latin2InDegrees * DEG2RAD; - LaDInRadians = LaDInDegrees * DEG2RAD; - LoVInRadians = LoVInDegrees * DEG2RAD; - - if (is_oblate) { - err = init_oblate(h, self, iter->nv, nx, ny, - LoVInDegrees, - Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, - latFirstInRadians, lonFirstInRadians, - LoVInRadians, Latin1InRadians, Latin2InRadians, - LaDInRadians); - } else { - err = init_sphere(h, self, iter->nv, nx, ny, - LoVInDegrees, - Dx, Dy, radius, - latFirstInRadians, lonFirstInRadians, - LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians); - } - if (err) return err; - - iter->e = -1; - - /* Apply the scanning mode flags which may require data array to be transformed */ - err = transform_iterator_data(h->context, iter->data, - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, - iter->nv, nx, ny); - return err; -} - -static int next(grib_iterator* i, double* lat, double* lon, double* val) -{ - grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; - - if ((long)i->e >= (long)(i->nv - 1)) - return 0; - i->e++; - - *lat = self->lats[i->e]; - *lon = self->lons[i->e]; - *val = i->data[i->e]; - - return 1; -} - -static int destroy(grib_iterator* i) -{ - grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; - const grib_context* c = i->h->context; - - grib_context_free(c, self->lats); - grib_context_free(c, self->lons); - return 1; -} diff --git a/src/grib_iterator_class_polar_stereographic.c b/src/grib_iterator_class_polar_stereographic.c deleted file mode 100644 index 0e3988030..000000000 --- a/src/grib_iterator_class_polar_stereographic.c +++ /dev/null @@ -1,374 +0,0 @@ -/* - * (C) Copyright 2005- 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" -#include - -/* - This is used by make_class.pl - - START_CLASS_DEF - CLASS = iterator - SUPER = grib_iterator_class_gen - IMPLEMENTS = destroy - IMPLEMENTS = init;next - MEMBERS = double *lats - MEMBERS = double *lons - MEMBERS = long Nj - 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 "iterator.class" and rerun ./make_class.pl - -*/ - - -static void init_class (grib_iterator_class*); - -static int init (grib_iterator* i,grib_handle*,grib_arguments*); -static int next (grib_iterator* i, double *lat, double *lon, double *val); -static int destroy (grib_iterator* i); - - -typedef struct grib_iterator_polar_stereographic{ - grib_iterator it; - /* Members defined in gen */ - int carg; - const char* missingValue; - /* Members defined in polar_stereographic */ - double *lats; - double *lons; - long Nj; -} grib_iterator_polar_stereographic; - -extern grib_iterator_class* grib_iterator_class_gen; - -static grib_iterator_class _grib_iterator_class_polar_stereographic = { - &grib_iterator_class_gen, /* super */ - "polar_stereographic", /* name */ - sizeof(grib_iterator_polar_stereographic),/* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ -}; - -grib_iterator_class* grib_iterator_class_polar_stereographic = &_grib_iterator_class_polar_stereographic; - - -static void init_class(grib_iterator_class* c) -{ - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; -} -/* END_CLASS_IMP */ - -#define ITER "Polar stereographic Geoiterator" - -static int next(grib_iterator* i, double* lat, double* lon, double* val) -{ - grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; - - if ((long)i->e >= (long)(i->nv - 1)) - return 0; - i->e++; - - *lat = self->lats[i->e]; - *lon = self->lons[i->e]; - *val = i->data[i->e]; - - return 1; -} - -/* Data struct for Forward and Inverse Projections */ -typedef struct proj_data_t -{ - double centre_lon; /* central longitude */ - double centre_lat; /* central latitude */ - double sign; /* sign variable */ - double ind; /* flag variable */ - double mcs; /* small m */ - double tcs; /* small t */ - double false_northing; /* y offset in meters */ - double false_easting; /* x offset in meters */ -} proj_data_t; - -#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ -#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ -#define PI_OVER_2 1.5707963267948966 /* half pi */ -#define EPSILON 1.0e-10 - -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) -{ - int ret = 0; - double *lats, *lons; /* arrays for latitudes and longitudes */ - double lonFirstInDegrees, latFirstInDegrees, radius; - double x, y, Dx, Dy; - long nx, ny, centralLongitudeInDegrees, centralLatitudeInDegrees; - long alternativeRowScanning, iScansNegatively, i, j; - long jScansPositively, jPointsAreConsecutive, southPoleOnPlane; - double centralLongitude, centralLatitude; /* in radians */ - double con1; /* temporary angle */ - double ts; /* value of small t */ - double height; /* height above ellipsoid */ - double x0, y0, lonFirst, latFirst; - proj_data_t fwd_proj_data = {0,}; - proj_data_t inv_proj_data = {0,}; - - grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)iter; - - const char* s_radius = grib_arguments_get_name(h, args, self->carg++); - const char* s_nx = grib_arguments_get_name(h, args, self->carg++); - const char* s_ny = grib_arguments_get_name(h, args, self->carg++); - const char* s_latFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* s_lonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* s_southPoleOnPlane = grib_arguments_get_name(h, args, self->carg++); - const char* s_centralLongitude = grib_arguments_get_name(h, args, self->carg++); - const char* s_centralLatitude = grib_arguments_get_name(h, args, self->carg++); - const char* s_Dx = grib_arguments_get_name(h, args, self->carg++); - const char* s_Dy = grib_arguments_get_name(h, args, self->carg++); - const char* s_iScansNegatively = grib_arguments_get_name(h, args, self->carg++); - const char* s_jScansPositively = grib_arguments_get_name(h, args, self->carg++); - const char* s_jPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); - const char* s_alternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); - - if (grib_is_earth_oblate(h)) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Only supported for spherical earth.", ITER); - return GRIB_GEOCALCULUS_PROBLEM; - } - - if ((ret = grib_get_double_internal(h, s_radius, &radius)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_nx, &nx)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_ny, &ny)) != GRIB_SUCCESS) - return ret; - - if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%ld!=%ldx%ld)", ITER, iter->nv, nx, ny); - return GRIB_WRONG_GRID; - } - if ((ret = grib_get_double_internal(h, s_latFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, s_lonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_southPoleOnPlane, &southPoleOnPlane)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_centralLongitude, ¢ralLongitudeInDegrees)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_centralLatitude, ¢ralLatitudeInDegrees)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, s_Dx, &Dx)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, s_Dy, &Dy)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_jPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_jScansPositively, &jScansPositively)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_iScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_alternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) - return ret; - - centralLongitude = centralLongitudeInDegrees * DEG2RAD; - centralLatitude = centralLatitudeInDegrees * DEG2RAD; - lonFirst = lonFirstInDegrees * DEG2RAD; - latFirst = latFirstInDegrees * DEG2RAD; - - /* Forward projection initialisation */ - fwd_proj_data.false_northing = 0; - fwd_proj_data.false_easting = 0; - fwd_proj_data.centre_lon = centralLongitude; - fwd_proj_data.centre_lat = centralLatitude; - if (centralLatitude < 0) - fwd_proj_data.sign = -1.0; - else - fwd_proj_data.sign = +1.0; - fwd_proj_data.ind = 0; - if (fabs(fabs(centralLatitude) - PI_OVER_2) > EPSILON) { - /* central latitude different from 90 i.e. not north/south polar */ - fwd_proj_data.ind = 1; - con1 = fwd_proj_data.sign * centralLatitude; - fwd_proj_data.mcs = cos(con1); - fwd_proj_data.tcs = tan(0.5 * (PI_OVER_2 - con1)); - } - - /* Forward projection from initial lat,lon to initial x,y */ - con1 = fwd_proj_data.sign * (lonFirst - fwd_proj_data.centre_lon); - ts = tan(0.5 * (PI_OVER_2 - fwd_proj_data.sign * latFirst)); - if (fwd_proj_data.ind) - height = radius * fwd_proj_data.mcs * ts / fwd_proj_data.tcs; - else - height = 2.0 * radius * ts; - x0 = fwd_proj_data.sign * height * sin(con1) + fwd_proj_data.false_easting; - y0 = -fwd_proj_data.sign * height * cos(con1) + fwd_proj_data.false_northing; - - x0 = -x0; - y0 = -y0; - - /* Inverse projection initialisation */ - inv_proj_data.false_easting = x0; - inv_proj_data.false_northing = y0; - inv_proj_data.centre_lon = centralLongitude; - inv_proj_data.centre_lat = centralLatitude; - if (centralLatitude < 0) - inv_proj_data.sign = -1.0; - else - inv_proj_data.sign = +1.0; - inv_proj_data.ind = 0; - if (fabs(fabs(centralLatitude) - PI_OVER_2) > EPSILON) { - inv_proj_data.ind = 1; - con1 = inv_proj_data.sign * inv_proj_data.centre_lat; - inv_proj_data.mcs = cos(con1); - inv_proj_data.tcs = tan(0.5 * (PI_OVER_2 - con1)); - } - self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, iter->nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, iter->nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - lats = self->lats; - lons = self->lons; - /* These will be processed later in transform_iterator_data() */ - /* Dx = iScansNegatively == 0 ? Dx : -Dx; */ - /* Dy = jScansPositively == 1 ? Dy : -Dy; */ - - y = 0; - for (j = 0; j < ny; j++) { - x = 0; - for (i = 0; i < nx; i++) { - /* Inverse projection from x,y to lat,lon */ - /* int index =i+j*nx; */ - double _x = (x - inv_proj_data.false_easting) * inv_proj_data.sign; - double _y = (y - inv_proj_data.false_northing) * inv_proj_data.sign; - double rh = sqrt(_x * _x + _y * _y); - if (inv_proj_data.ind) - ts = rh * inv_proj_data.tcs / (radius * inv_proj_data.mcs); - else - ts = rh / (radius * 2.0); - *lats = inv_proj_data.sign * (PI_OVER_2 - 2 * atan(ts)); - if (rh == 0) { - *lons = inv_proj_data.sign * inv_proj_data.centre_lon; - } - else { - double temp = atan2(_x, -_y); - *lons = inv_proj_data.sign * temp + inv_proj_data.centre_lon; - } - *lats = *lats * RAD2DEG; - *lons = *lons * RAD2DEG; - while (*lons < 0) - *lons += 360; - while (*lons > 360) - *lons -= 360; - lons++; - lats++; - - x += Dx; - } - y += Dy; - } -#if 0 - /*standardParallel = (southPoleOnPlane == 1) ? -90 : +90;*/ - if (jPointsAreConsecutive) - { - x=xFirst; - for (i=0;i360) *lons -= 360; - lons++; - lats++; - - y+=Dy; - } - x+=Dx; - } - } - else - { - y=yFirst; - for (j=0;j360) *lons -= 360; - lons++; - lats++; - - x+=Dx; - } - y+=Dy; - } - } -#endif - iter->e = -1; - - /* Apply the scanning mode flags which may require data array to be transformed */ - ret = transform_iterator_data(h->context, iter->data, - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, - iter->nv, nx, ny); - - return ret; -} - -static int destroy(grib_iterator* i) -{ - grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; - const grib_context* c = i->h->context; - - grib_context_free(c, self->lats); - grib_context_free(c, self->lons); - return 1; -} diff --git a/src/grib_iterator_class_space_view.c b/src/grib_iterator_class_space_view.c deleted file mode 100644 index 355acfa13..000000000 --- a/src/grib_iterator_class_space_view.c +++ /dev/null @@ -1,388 +0,0 @@ -/* - * (C) Copyright 2005- 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" -#include - -/* - This is used by make_class.pl - - START_CLASS_DEF - CLASS = iterator - SUPER = grib_iterator_class_gen - IMPLEMENTS = destroy - IMPLEMENTS = init;next - MEMBERS = double *lats - MEMBERS = double *lons - MEMBERS = long Nj - 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 "iterator.class" and rerun ./make_class.pl - -*/ - - -static void init_class (grib_iterator_class*); - -static int init (grib_iterator* i,grib_handle*,grib_arguments*); -static int next (grib_iterator* i, double *lat, double *lon, double *val); -static int destroy (grib_iterator* i); - - -typedef struct grib_iterator_space_view{ - grib_iterator it; - /* Members defined in gen */ - int carg; - const char* missingValue; - /* Members defined in space_view */ - double *lats; - double *lons; - long Nj; -} grib_iterator_space_view; - -extern grib_iterator_class* grib_iterator_class_gen; - -static grib_iterator_class _grib_iterator_class_space_view = { - &grib_iterator_class_gen, /* super */ - "space_view", /* name */ - sizeof(grib_iterator_space_view),/* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ -}; - -grib_iterator_class* grib_iterator_class_space_view = &_grib_iterator_class_space_view; - - -static void init_class(grib_iterator_class* c) -{ - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; -} -/* END_CLASS_IMP */ - -static int next(grib_iterator* i, double* lat, double* lon, double* val) -{ - grib_iterator_space_view* self = (grib_iterator_space_view*)i; - - if ((long)i->e >= (long)(i->nv - 1)) - return 0; - i->e++; - - *lat = self->lats[i->e]; - *lon = self->lons[i->e]; - *val = i->data[i->e]; - - return 1; -} - -#if 0 -static void adjustBadlyEncodedEcmwfGribs(grib_handle* h, - long* nx, long* ny, double* dx, double* dy, double* xp, double* yp) -{ - /* Correct the information provided in the headers of certain satellite imagery that - * we have available. This is specific to ECMWF. - * Obtained through trial-and-error to get the best match with the coastlines. - * - * Copied from Magics GribSatelliteInterpretor::AdjustBadlyEncodedGribs() - */ - long centre = 0; - int err = grib_get_long(h, "centre", ¢re); - if (!err && centre == 98) { - int err1 = 0, err2 = 0, err3 = 0; - long satelliteIdentifier, channelNumber, functionCode; - /* These keys are defined in the ECMWF local definition 24 - Satellite image simulation */ - err1 = grib_get_long(h, "satelliteIdentifier", &satelliteIdentifier); - err2 = grib_get_long(h, "channelNumber", &channelNumber); - err3 = grib_get_long(h, "functionCode", &functionCode); - if (!err1 && !err2 && !err3) { - if (satelliteIdentifier == 54 && channelNumber == 2 && *dx == 1179) { /* Meteosat 7, channel 2 */ - *nx = *ny = 900; - *dx = *dy = 853; - *xp = *yp = 450; - } - else if (satelliteIdentifier == 54 && channelNumber == 3 && *dx == 1179) { /* Meteosat 7, channel 3 */ - *dx = *dy = 1184; - *xp = *yp = 635; - } - else if (satelliteIdentifier == 259 && channelNumber == 4 && *dx == 1185) { /* GOES-15 (West) channel 4 */ - *dx = *dy = 880; - *xp = *yp = 450; - } - else if (satelliteIdentifier == 57 && *dx == 1732) { /* MSG (Meteosat second generation), non-HRV channels */ - *dx = *dy = 1811; - *xp = *yp = 928; - } - } - } -} -#endif - -#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ -#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ - -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) -{ - /* REFERENCE: - * LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) - */ - int ret = GRIB_SUCCESS; - double *lats, *lons; /* arrays of latitudes and longitudes */ - double latOfSubSatellitePointInDegrees, lonOfSubSatellitePointInDegrees; - double orientationInDegrees, nrInRadiusOfEarth; - double radius = 0, xpInGridLengths = 0, ypInGridLengths = 0; - long nx, ny, earthIsOblate = 0; - long alternativeRowScanning, iScansNegatively; - long Xo, Yo, jScansPositively, jPointsAreConsecutive, i; - - double major = 0, minor = 0, r_eq, r_pol, height; - double lap, lop, angular_size; - double xp, yp, dx, dy, rx, ry, x, y; - double cos_x, cos_y, sin_x, sin_y; - double factor_1, factor_2, tmp1, Sd, Sn, Sxy, S1, S2, S3; - int x0, y0, ix, iy; - double *s_x, *c_x; /* arrays storing sin and cos values */ - size_t array_size = (iter->nv * sizeof(double)); - - grib_iterator_space_view* self = (grib_iterator_space_view*)iter; - - const char* sradius = grib_arguments_get_name(h, args, self->carg++); - const char* sEarthIsOblate = grib_arguments_get_name(h, args, self->carg++); - const char* sMajorAxisInMetres = grib_arguments_get_name(h, args, self->carg++); - const char* sMinorAxisInMetres = grib_arguments_get_name(h, args, self->carg++); - const char* snx = grib_arguments_get_name(h, args, self->carg++); - const char* sny = grib_arguments_get_name(h, args, self->carg++); - const char* sLatOfSubSatellitePointInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sLonOfSubSatellitePointInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sDx = grib_arguments_get_name(h, args, self->carg++); - const char* sDy = grib_arguments_get_name(h, args, self->carg++); - const char* sXpInGridLengths = grib_arguments_get_name(h, args, self->carg++); - const char* sYpInGridLengths = grib_arguments_get_name(h, args, self->carg++); - const char* sOrientationInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sNrInRadiusOfEarth = grib_arguments_get_name(h, args, self->carg++); - const char* sXo = grib_arguments_get_name(h, args, self->carg++); - const char* sYo = grib_arguments_get_name(h, args, self->carg++); - - const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); - const char* sAlternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); - - if ((ret = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sEarthIsOblate, &earthIsOblate)) != GRIB_SUCCESS) - return ret; - - if (earthIsOblate) { - if ((ret = grib_get_double_internal(h, sMajorAxisInMetres, &major)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sMinorAxisInMetres, &minor)) != GRIB_SUCCESS) - return ret; - } - else { - if ((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) - return ret; - } - - if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); - return GRIB_WRONG_GRID; - } - if ((ret = grib_get_double_internal(h, sLatOfSubSatellitePointInDegrees, &latOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sLonOfSubSatellitePointInDegrees, &lonOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sDx, &dx)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sDy, &dy)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sXpInGridLengths, &xpInGridLengths)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sYpInGridLengths, &ypInGridLengths)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sOrientationInDegrees, &orientationInDegrees)) != GRIB_SUCCESS) - return ret; - - /* Orthographic not supported. This happens when Nr (camera altitude) is missing */ - if (grib_is_missing(h, sNrInRadiusOfEarth, &ret)) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Space View: Orthographic view (Nr missing) not supported"); - return GRIB_NOT_IMPLEMENTED; - } - if ((ret = grib_get_double_internal(h, sNrInRadiusOfEarth, &nrInRadiusOfEarth)) != GRIB_SUCCESS) - return ret; - - if ((ret = grib_get_long_internal(h, sXo, &Xo)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sYo, &Yo)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sAlternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) - return ret; - - if (earthIsOblate) { - r_eq = major; /* In km */ - r_pol = minor; - } - else { - r_eq = r_pol = radius * 0.001; /*conv to km*/ - } - - if (nrInRadiusOfEarth == 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Space View: Key %s must be greater than zero", sNrInRadiusOfEarth); - return GRIB_GEOCALCULUS_PROBLEM; - } - - angular_size = 2.0 * asin(1.0 / nrInRadiusOfEarth); - height = nrInRadiusOfEarth * r_eq; - - lap = latOfSubSatellitePointInDegrees; - lop = lonOfSubSatellitePointInDegrees; - if (lap != 0.0) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "Space View: Key '%s' must be 0 (satellite must be located in the equator plane)", - sLatOfSubSatellitePointInDegrees); - return GRIB_GEOCALCULUS_PROBLEM; - } - - /*orient_angle = orientationInDegrees;*/ - /* if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; */ - - xp = xpInGridLengths; - yp = ypInGridLengths; - x0 = Xo; - y0 = Yo; - - /* adjustBadlyEncodedEcmwfGribs(h, &nx, &ny, &dx, &dy, &xp, &yp); */ - if (dx == 0 || dy == 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Space View: Keys %s and %s must be greater than zero", sDx, sDy); - return GRIB_GEOCALCULUS_PROBLEM; - } - rx = angular_size / dx; - ry = (r_pol / r_eq) * angular_size / dy; - - self->lats = (double*)grib_context_malloc(h->context, array_size); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", array_size); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, array_size); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", array_size); - return GRIB_OUT_OF_MEMORY; - } - lats = self->lats; - lons = self->lons; - - if (!iScansNegatively) { - xp = xp - x0; - } - else { - xp = (nx - 1) - (xp - x0); - } - if (jScansPositively) { - yp = yp - y0; - } - else { - yp = (ny - 1) - (yp - y0); - } - i = 0; - factor_2 = (r_eq / r_pol) * (r_eq / r_pol); - factor_1 = height * height - r_eq * r_eq; - - /* Store array of sin and cosine values to avoid recalculation */ - s_x = (double*)grib_context_malloc(h->context, nx * sizeof(double)); - if (!s_x) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nx * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - c_x = (double*)grib_context_malloc(h->context, nx * sizeof(double)); - if (!c_x) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nx * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - - for (ix = 0; ix < nx; ix++) { - x = (ix - xp) * rx; - s_x[ix] = sin(x); - c_x[ix] = sqrt(1.0 - s_x[ix] * s_x[ix]); - } - - /*for (iy = 0; iy < ny; iy++) {*/ - for (iy = ny - 1; iy >= 0; --iy) { - y = (iy - yp) * ry; - sin_y = sin(y); - cos_y = sqrt(1.0 - sin_y * sin_y); - - tmp1 = (1 + (factor_2 - 1.0) * sin_y * sin_y); - - for (ix = 0; ix < nx; ix++, i++) { - /*x = (ix - xp) * rx;*/ - /* Use sin/cos previously computed */ - sin_x = s_x[ix]; - cos_x = c_x[ix]; - - Sd = height * cos_x * cos_y; - Sd = Sd * Sd - tmp1 * factor_1; - if (Sd <= 0.0) { /* outside of view */ - lats[i] = lons[i] = 0; /* TODO: error? */ - } - else { - Sd = sqrt(Sd); - Sn = (height * cos_x * cos_y - Sd) / tmp1; - S1 = height - Sn * cos_x * cos_y; - S2 = Sn * sin_x * cos_y; - S3 = Sn * sin_y; - Sxy = sqrt(S1 * S1 + S2 * S2); - lons[i] = atan(S2 / S1) * (RAD2DEG) + lop; - lats[i] = atan(factor_2 * S3 / Sxy) * (RAD2DEG); - /*fprintf(stderr, "lat=%g lon=%g\n", lats[i], lons[i]);*/ - } - while (lons[i] < 0) - lons[i] += 360; - while (lons[i] > 360) - lons[i] -= 360; - } - } - grib_context_free(h->context, s_x); - grib_context_free(h->context, c_x); - iter->e = -1; - - return ret; -} - -static int destroy(grib_iterator* i) -{ - grib_iterator_space_view* self = (grib_iterator_space_view*)i; - const grib_context* c = i->h->context; - - grib_context_free(c, self->lats); - grib_context_free(c, self->lons); - return 1; -} From f643dad10dfc1478a8430318f8cff8366a7cb56d Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Mon, 30 Jan 2023 12:01:31 +0000 Subject: [PATCH 087/737] ECC-1508: Change file extensions to '.cc' --- ...ator_class_lambert_azimuthal_equal_area.cc | 497 +++++++++++++++++ src/grib_iterator_class_lambert_conformal.cc | 511 ++++++++++++++++++ ...grib_iterator_class_polar_stereographic.cc | 374 +++++++++++++ src/grib_iterator_class_space_view.cc | 388 +++++++++++++ 4 files changed, 1770 insertions(+) create mode 100644 src/grib_iterator_class_lambert_azimuthal_equal_area.cc create mode 100644 src/grib_iterator_class_lambert_conformal.cc create mode 100644 src/grib_iterator_class_polar_stereographic.cc create mode 100644 src/grib_iterator_class_space_view.cc diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.cc b/src/grib_iterator_class_lambert_azimuthal_equal_area.cc new file mode 100644 index 000000000..5d54aee88 --- /dev/null +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.cc @@ -0,0 +1,497 @@ +/* + * (C) Copyright 2005- 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" +#include + +/* + This is used by make_class.pl + + START_CLASS_DEF + CLASS = iterator + SUPER = grib_iterator_class_gen + IMPLEMENTS = destroy + IMPLEMENTS = init;next + MEMBERS = double *lats + MEMBERS = double *lons + MEMBERS = long Nj + 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 "iterator.class" and rerun ./make_class.pl + +*/ + + +static void init_class (grib_iterator_class*); + +static int init (grib_iterator* i,grib_handle*,grib_arguments*); +static int next (grib_iterator* i, double *lat, double *lon, double *val); +static int destroy (grib_iterator* i); + + +typedef struct grib_iterator_lambert_azimuthal_equal_area{ + grib_iterator it; + /* Members defined in gen */ + int carg; + const char* missingValue; + /* Members defined in lambert_azimuthal_equal_area */ + double *lats; + double *lons; + long Nj; +} grib_iterator_lambert_azimuthal_equal_area; + +extern grib_iterator_class* grib_iterator_class_gen; + +static grib_iterator_class _grib_iterator_class_lambert_azimuthal_equal_area = { + &grib_iterator_class_gen, /* super */ + "lambert_azimuthal_equal_area", /* name */ + sizeof(grib_iterator_lambert_azimuthal_equal_area),/* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ +}; + +grib_iterator_class* grib_iterator_class_lambert_azimuthal_equal_area = &_grib_iterator_class_lambert_azimuthal_equal_area; + + +static void init_class(grib_iterator_class* c) +{ + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; +} +/* END_CLASS_IMP */ + +static int next(grib_iterator* i, double* lat, double* lon, double* val) +{ + grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; + + if ((long)i->e >= (long)(i->nv - 1)) + return 0; + i->e++; + + *lat = self->lats[i->e]; + *lon = self->lons[i->e]; + *val = i->data[i->e]; + + return 1; +} + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* Whole pie */ +#endif + +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 /* Half a pie */ +#endif + +#ifndef M_PI_4 +#define M_PI_4 0.78539816339744830962 /* Quarter of a pie */ +#endif + +#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ +#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ + +#define P00 .33333333333333333333 /* 1 / 3 */ +#define P01 .17222222222222222222 /* 31 / 180 */ +#define P02 .10257936507936507937 /* 517 / 5040 */ +#define P10 .06388888888888888888 /* 23 / 360 */ +#define P11 .06640211640211640212 /* 251 / 3780 */ +#define P20 .01677689594356261023 /* 761 / 45360 */ + +static void pj_authset(double es, double* APA) +{ + double t; + APA[0] = es * P00; + t = es * es; + APA[0] += t * P01; + APA[1] = t * P10; + t *= es; + APA[0] += t * P02; + APA[1] += t * P11; + APA[2] = t * P20; +} +static double pj_authlat(double beta, const double* APA) +{ + double t = beta + beta; + return (beta + APA[0] * sin(t) + APA[1] * sin(t + t) + APA[2] * sin(t + t + t)); +} + +static double pj_qsfn(double sinphi, double e, double one_es) +{ + double con, div1, div2; + const double EPSILON = 1.0e-7; + + if (e >= EPSILON) { + con = e * sinphi; + div1 = 1.0 - con * con; + div2 = 1.0 + con; + + /* avoid zero division, fail gracefully */ + if (div1 == 0.0 || div2 == 0.0) + return HUGE_VAL; + + return (one_es * (sinphi / div1 - (.5 / e) * log((1. - con) / div2))); + } + else + return (sinphi + sinphi); +} + +#define EPS10 1.e-10 +static int init_oblate(grib_handle* h, + grib_iterator_lambert_azimuthal_equal_area* self, + size_t nv, long nx, long ny, + double Dx, double Dy, double earthMinorAxisInMetres, double earthMajorAxisInMetres, + double latFirstInRadians, double lonFirstInRadians, + double centralLongitudeInRadians, double standardParallelInRadians, + long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) +{ + double *lats, *lons; + long i, j; + double x0, y0, x, y; + double coslam, sinlam, sinphi, sinphi_, q, sinb = 0.0, cosb = 0.0, b = 0.0, cosb2; + double Q__qp = 0, Q__rq = 0, Q__cosb1, Q__sinb1, Q__dd, Q__xmf, Q__ymf, t; + /* double Q__mmf = 0; */ + double e, es, temp, one_es; + double APA[3] = {0,}; + double xFirst, yFirst; + + Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; + Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; + + temp = (earthMajorAxisInMetres - earthMinorAxisInMetres) / earthMajorAxisInMetres; + es = 2 * temp - temp * temp; + one_es = 1.0 - es; + e = sqrt(es); + + coslam = cos(lonFirstInRadians - centralLongitudeInRadians); /* cos(lp.lam) */ + sinlam = sin(lonFirstInRadians - centralLongitudeInRadians); + sinphi = sin(latFirstInRadians); /* sin(lp.phi) */ + q = pj_qsfn(sinphi, e, one_es); + + t = fabs(standardParallelInRadians); + if (t > M_PI_2 + EPS10) { + return GRIB_GEOCALCULUS_PROBLEM; + } + /* if (fabs(t - M_HALFPI) < EPS10) + Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; + else if (fabs(t) < EPS10) + Q->mode = EQUIT; + else + Q->mode = OBLIQ; + */ + Q__qp = pj_qsfn(1.0, e, one_es); + /* Q__mmf = 0.5 / one_es; ---- TODO(masn): do I need this? */ + pj_authset(es, APA); /* sets up APA array */ + Q__rq = sqrt(0.5 * Q__qp); + sinphi_ = sin(standardParallelInRadians); /* (P->phi0); */ + Q__sinb1 = pj_qsfn(sinphi_, e, one_es) / Q__qp; + Q__cosb1 = sqrt(1.0 - Q__sinb1 * Q__sinb1); + Q__dd = cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); + Q__ymf = (Q__xmf = Q__rq) / Q__dd; + Q__xmf *= Q__dd; + + sinb = q / Q__qp; + cosb2 = 1.0 - sinb * sinb; + cosb = cosb2 > 0 ? sqrt(cosb2) : 0; + b = 1. + Q__sinb1 * sinb + Q__cosb1 * cosb * coslam; + if (fabs(b) < EPS10) { + return GRIB_GEOCALCULUS_PROBLEM; + } + b = sqrt(2.0 / b); + + /* OBLIQUE */ + y0 = Q__ymf * b * (Q__cosb1 * sinb - Q__sinb1 * cosb * coslam); + x0 = Q__xmf * b * cosb * sinlam; + + /* Allocate latitude and longitude arrays */ + self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats = self->lats; + lons = self->lons; + + /* Populate the lat and lon arrays */ + { + xFirst = x0; + yFirst = y0; + y = yFirst; + for (j = 0; j < ny; j++) { + x = xFirst; + for (i = 0; i < nx; i++) { + double cCe, sCe, rho, ab = 0.0, lp__lam, lp__phi, xy_x = x, xy_y = y; + xy_x /= Q__dd; + xy_y *= Q__dd; + rho = hypot(xy_x, xy_y); + Assert(rho >= EPS10); /* TODO(masn): check */ + sCe = 2. * asin(.5 * rho / Q__rq); + cCe = cos(sCe); + sCe = sin(sCe); + xy_x *= sCe; + /* if oblique */ + ab = cCe * Q__sinb1 + xy_y * sCe * Q__cosb1 / rho; + xy_y = rho * Q__cosb1 * cCe - xy_y * Q__sinb1 * sCe; + /* else + ab = xy.y * sCe / rho; + xy.y = rho * cCe; + */ + lp__lam = atan2(xy_x, xy_y); /* longitude */ + lp__phi = pj_authlat(asin(ab), APA); /* latitude */ + + *lats = lp__phi * RAD2DEG; + *lons = (lp__lam + centralLongitudeInRadians) * RAD2DEG; + + lons++; + lats++; + + x += Dx / earthMajorAxisInMetres; + } + y += Dy / earthMajorAxisInMetres; + } + } + + return GRIB_SUCCESS; +} + +static int init_sphere(grib_handle* h, + grib_iterator_lambert_azimuthal_equal_area* self, + size_t nv, long nx, long ny, + double Dx, double Dy, double radius, + double latFirstInRadians, double lonFirstInRadians, + double centralLongitudeInRadians, double standardParallelInRadians, + long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) +{ + double *lats, *lons; + double phi1, lambda0, xFirst, yFirst, x, y; + double kp, sinphi1, cosphi1; + double sinphi, cosphi, cosdlambda, sindlambda; + double cosc, sinc; + long i, j; + double c, rho; + const double epsilon = 1.0e-20; + const double d2r = acos(0.0) / 90.0; + + lambda0 = centralLongitudeInRadians; + phi1 = standardParallelInRadians; + + cosphi1 = cos(phi1); + sinphi1 = sin(phi1); + + Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; + Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; + self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, + "Error allocating %ld bytes", nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, + "Error allocating %ld bytes", nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats = self->lats; + lons = self->lons; + + /* compute xFirst,yFirst in metres */ + sinphi = sin(latFirstInRadians); + cosphi = cos(latFirstInRadians); + cosdlambda = cos(lonFirstInRadians - lambda0); + sindlambda = sin(lonFirstInRadians - lambda0); + kp = radius * sqrt(2.0 / (1 + sinphi1 * sinphi + cosphi1 * cosphi * cosdlambda)); + xFirst = kp * cosphi * sindlambda; + yFirst = kp * (cosphi1 * sinphi - sinphi1 * cosphi * cosdlambda); + + if (jPointsAreConsecutive) { + x = xFirst; + for (i = 0; i < nx; i++) { + double xsq = x * x; + y = yFirst; + for (j = 0; j < ny; j++) { + rho = sqrt(xsq + y * y); + if (rho > epsilon) { + c = 2 * asin(rho / (2.0 * radius)); + cosc = cos(c); + sinc = sin(c); + *lats = asin(cosc * sinphi1 + y * sinc * cosphi1 / rho) / d2r; + *lons = (lambda0 + atan2(x * sinc, rho * cosphi1 * cosc - y * sinphi1 * sinc)) / d2r; + } + else { + *lats = phi1 / d2r; + *lons = lambda0 / d2r; + } + if (*lons < 0) + *lons += 360; + lons++; + lats++; + + y += Dy; + } + x += Dx; + } + } + else { + y = yFirst; + for (j = 0; j < ny; j++) { + double ysq = y * y; + x = xFirst; + for (i = 0; i < nx; i++) { + rho = sqrt(x * x + ysq); + if (rho > epsilon) { + c = 2 * asin(rho / (2.0 * radius)); + cosc = cos(c); + sinc = sin(c); + *lats = asin(cosc * sinphi1 + y * sinc * cosphi1 / rho) / d2r; + *lons = (lambda0 + atan2(x * sinc, rho * cosphi1 * cosc - y * sinphi1 * sinc)) / d2r; + } + else { + *lats = phi1 / d2r; + *lons = lambda0 / d2r; + } + if (*lons < 0) + *lons += 360; + lons++; + lats++; + + x += Dx; + } + y += Dy; + } + } + return GRIB_SUCCESS; +} + +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) +{ + int err = 0; + int is_oblate = 0; + double lonFirstInDegrees, latFirstInDegrees, lonFirstInRadians, latFirstInRadians, radius = 0; + long nx, ny; + double standardParallelInDegrees, centralLongitudeInDegrees; + double standardParallelInRadians, centralLongitudeInRadians; + double Dx, Dy; + long alternativeRowScanning, iScansNegatively; + long jScansPositively, jPointsAreConsecutive; + double earthMajorAxisInMetres = 0, earthMinorAxisInMetres = 0; + + grib_iterator_lambert_azimuthal_equal_area* self = + (grib_iterator_lambert_azimuthal_equal_area*)iter; + + const char* sradius = grib_arguments_get_name(h, args, self->carg++); + const char* snx = grib_arguments_get_name(h, args, self->carg++); + const char* sny = grib_arguments_get_name(h, args, self->carg++); + const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sstandardParallel = grib_arguments_get_name(h, args, self->carg++); + const char* scentralLongitude = grib_arguments_get_name(h, args, self->carg++); + const char* sDx = grib_arguments_get_name(h, args, self->carg++); + const char* sDy = grib_arguments_get_name(h, args, self->carg++); + const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); + const double d2r = acos(0.0) / 90.0; + + is_oblate = grib_is_earth_oblate(h); + if (is_oblate) { + if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; + if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; + } + else { + if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) return err; + } + + if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) + return err; + + if (iter->nv != nx * ny) { + grib_context_log(h->context, GRIB_LOG_ERROR, + "Wrong number of points (%ld!=%ldx%ld)", + iter->nv, nx, ny); + return GRIB_WRONG_GRID; + } + if ((err = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, slonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, sstandardParallel, &standardParallelInDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, scentralLongitude, ¢ralLongitudeInDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, sDx, &Dx)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, sDy, &Dy)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) + return err; + + latFirstInRadians = latFirstInDegrees * d2r; + lonFirstInRadians = lonFirstInDegrees * d2r; + centralLongitudeInRadians = centralLongitudeInDegrees * d2r; + standardParallelInRadians = standardParallelInDegrees * d2r; + + if (is_oblate) { + err = init_oblate(h, self, iter->nv, nx, ny, + Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, + latFirstInRadians, lonFirstInRadians, + centralLongitudeInRadians, standardParallelInRadians, + iScansNegatively, jScansPositively, jPointsAreConsecutive); + } + else { + err = init_sphere(h, self, iter->nv, nx, ny, + Dx, Dy, radius, + latFirstInRadians, lonFirstInRadians, + centralLongitudeInRadians, standardParallelInRadians, + iScansNegatively, jScansPositively, jPointsAreConsecutive); + } + if (err) return err; + + iter->e = -1; + + return GRIB_SUCCESS; +} + +static int destroy(grib_iterator* i) +{ + grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; + const grib_context* c = i->h->context; + + grib_context_free(c, self->lats); + grib_context_free(c, self->lons); + return 1; +} diff --git a/src/grib_iterator_class_lambert_conformal.cc b/src/grib_iterator_class_lambert_conformal.cc new file mode 100644 index 000000000..a39b314ab --- /dev/null +++ b/src/grib_iterator_class_lambert_conformal.cc @@ -0,0 +1,511 @@ +/* + * (C) Copyright 2005- 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" +#include + +/* + This is used by make_class.pl + + START_CLASS_DEF + CLASS = iterator + SUPER = grib_iterator_class_gen + IMPLEMENTS = destroy + IMPLEMENTS = init;next + MEMBERS = double *lats + MEMBERS = double *lons + MEMBERS = long Nj + 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 "iterator.class" and rerun ./make_class.pl + +*/ + + +static void init_class (grib_iterator_class*); + +static int init (grib_iterator* i,grib_handle*,grib_arguments*); +static int next (grib_iterator* i, double *lat, double *lon, double *val); +static int destroy (grib_iterator* i); + + +typedef struct grib_iterator_lambert_conformal{ + grib_iterator it; + /* Members defined in gen */ + int carg; + const char* missingValue; + /* Members defined in lambert_conformal */ + double *lats; + double *lons; + long Nj; +} grib_iterator_lambert_conformal; + +extern grib_iterator_class* grib_iterator_class_gen; + +static grib_iterator_class _grib_iterator_class_lambert_conformal = { + &grib_iterator_class_gen, /* super */ + "lambert_conformal", /* name */ + sizeof(grib_iterator_lambert_conformal),/* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ +}; + +grib_iterator_class* grib_iterator_class_lambert_conformal = &_grib_iterator_class_lambert_conformal; + + +static void init_class(grib_iterator_class* c) +{ + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; +} +/* END_CLASS_IMP */ + +#define ITER "Lambert conformal Geoiterator" +#define EPSILON 1.0e-10 + +#ifndef M_PI +#define M_PI 3.14159265358979323846 /* Whole pie */ +#endif + +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 /* Half a pie */ +#endif + +#ifndef M_PI_4 +#define M_PI_4 0.78539816339744830962 /* Quarter of a pie */ +#endif + +#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ +#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ + +/* Adjust longitude (in radians) to range -180 to 180 */ +static double adjust_lon_radians(double lon) +{ + if (lon > M_PI) lon -= 2 * M_PI; + if (lon < -M_PI) lon += 2 * M_PI; + return lon; +} + +/* Function to compute the latitude angle, phi2, for the inverse + * From the book "Map Projections-A Working Manual-John P. Snyder (1987)" + * Equation (7-9) involves rapidly converging iteration: Calculate t from (15-11) + * Then, assuming an initial trial phi equal to (pi/2 - 2*arctan t) in the right side of equation (7-9), + * calculate phi on the left side. Substitute the calculated phi) into the right side, + * calculate a new phi, etc., until phi does not change significantly from the preceding trial value of phi + */ +static double compute_phi( + double eccent, /* Spheroid eccentricity */ + double ts, /* Constant value t */ + int* error) +{ + double eccnth, phi, con, dphi, sinpi; + int i, MAX_ITER = 15; + + eccnth = 0.5 * eccent; + phi = M_PI_2 - 2 * atan(ts); + for (i = 0; i <= MAX_ITER; i++) { + sinpi = sin(phi); + con = eccent * sinpi; + dphi = M_PI_2 - 2 * atan(ts * (pow(((1.0 - con) / (1.0 + con)), eccnth))) - phi; + phi += dphi; + if (fabs(dphi) <= 0.0000000001) + return (phi); + } + *error = GRIB_INTERNAL_ERROR; + return 0; +} + +/* Compute the constant small m which is the radius of + a parallel of latitude, phi, divided by the semimajor axis */ +static double compute_m(double eccent, double sinphi, double cosphi) +{ + const double con = eccent * sinphi; + return ((cosphi / (sqrt(1.0 - con * con)))); +} + +/* Compute the constant small t for use in the forward computations */ +static double compute_t( + double eccent, /* Eccentricity of the spheroid */ + double phi, /* Latitude phi */ + double sinphi) /* Sine of the latitude */ +{ + double con = eccent * sinphi; + double com = 0.5 * eccent; + con = pow(((1.0 - con) / (1.0 + con)), com); + return (tan(0.5 * (M_PI_2 - phi)) / con); +} + +static double calculate_eccentricity(double minor, double major) +{ + const double temp = minor / major; + return sqrt(1.0 - temp * temp); +} + +static int init_sphere(grib_handle* h, + grib_iterator_lambert_conformal* self, + size_t nv, long nx, long ny, + double LoVInDegrees, + double Dx, double Dy, double radius, + double latFirstInRadians, double lonFirstInRadians, + double LoVInRadians, double Latin1InRadians, double Latin2InRadians, + double LaDInRadians) +{ + int i, j; + double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; + double latDeg, lonDeg, lonDiff; + + if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { + n = sin(Latin1InRadians); + } else { + n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) / + log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); + } + + f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; + rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); + rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); + if (n < 0) /* adjustment for southern hemisphere */ + rho0 = -rho0; + lonDiff = lonFirstInRadians - LoVInRadians; + + /* Adjust longitude to range -180 to 180 */ + if (lonDiff > M_PI) + lonDiff -= 2 * M_PI; + if (lonDiff < -M_PI) + lonDiff += 2 * M_PI; + angle = n * lonDiff; + x0 = rho * sin(angle); + y0 = rho0 - rho * cos(angle); + /*Dx = iScansNegatively == 0 ? Dx : -Dx;*/ + /* GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint */ + /*Dy = jScansPositively == 1 ? Dy : -Dy;*/ + + /* Allocate latitude and longitude arrays */ + self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + + /* Populate our arrays */ + for (j = 0; j < ny; j++) { + y = y0 + j * Dy; + if (n < 0) { /* adjustment for southern hemisphere */ + y = -y; + } + tmp = rho0 - y; + tmp2 = tmp * tmp; + for (i = 0; i < nx; i++) { + int index = i + j * nx; + x = x0 + i * Dx; + if (n < 0) { /* adjustment for southern hemisphere */ + x = -x; + } + angle = atan2(x, tmp); /* See ECC-524 */ + rho = sqrt(x * x + tmp2); + if (n <= 0) rho = -rho; + lonDeg = LoVInDegrees + (angle / n) * RAD2DEG; + latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * RAD2DEG; + lonDeg = normalise_longitude_in_degrees(lonDeg); + self->lons[index] = lonDeg; + self->lats[index] = latDeg; + } + } + + return GRIB_SUCCESS; +} + +/* Oblate spheroid */ +static int init_oblate(grib_handle* h, + grib_iterator_lambert_conformal* self, + size_t nv, long nx, long ny, + double LoVInDegrees, + double Dx, double Dy, + double earthMinorAxisInMetres, double earthMajorAxisInMetres, + double latFirstInRadians, double lonFirstInRadians, + double LoVInRadians, double Latin1InRadians, double Latin2InRadians, + double LaDInRadians) +{ + int i, j, err = 0; + double x0, y0, x, y, latRad, lonRad, latDeg, lonDeg, sinphi, ts, rh1, theta; + double false_easting; /* x offset in meters */ + double false_northing; /* y offset in meters */ + + double ns; /* ratio of angle between meridian */ + double F; /* flattening of ellipsoid */ + double rh; /* height above ellipsoid */ + double sin_po; /* sin value */ + double cos_po; /* cos value */ + double con; /* temporary variable */ + double ms1; /* small m 1 */ + double ms2; /* small m 2 */ + double ts0; /* small t 0 */ + double ts1; /* small t 1 */ + double ts2; /* small t 2 */ + + double e = calculate_eccentricity(earthMinorAxisInMetres, earthMajorAxisInMetres); + + sin_po = sin(Latin1InRadians); + cos_po = cos(Latin1InRadians); + con = sin_po; + ms1 = compute_m(e, sin_po, cos_po); + ts1 = compute_t(e, Latin1InRadians, sin_po); + + sin_po = sin(Latin2InRadians); + cos_po = cos(Latin2InRadians); + ms2 = compute_m(e, sin_po, cos_po); + ts2 = compute_t(e, Latin2InRadians, sin_po); + sin_po = sin(LaDInRadians); + ts0 = compute_t(e, LaDInRadians, sin_po); + + if (fabs(Latin1InRadians - Latin2InRadians) > EPSILON) { + ns = log(ms1 / ms2) / log(ts1 / ts2); + } else { + ns = con; + } + F = ms1 / (ns * pow(ts1, ns)); + rh = earthMajorAxisInMetres * F * pow(ts0, ns); + + /* Forward projection: convert lat,lon to x,y */ + con = fabs(fabs(latFirstInRadians) - M_PI_2); + if (con > EPSILON) { + sinphi = sin(latFirstInRadians); + ts = compute_t(e, latFirstInRadians, sinphi); + rh1 = earthMajorAxisInMetres * F * pow(ts, ns); + } else { + con = latFirstInRadians * ns; + if (con <= 0) { + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Point cannot be projected: latFirstInRadians=%g", ITER, latFirstInRadians); + return GRIB_GEOCALCULUS_PROBLEM; + } + rh1 = 0; + } + theta = ns * adjust_lon_radians(lonFirstInRadians - LoVInRadians); + x0 = rh1 * sin(theta); + y0 = rh - rh1 * cos(theta); + x0 = -x0; + y0 = -y0; + + /* Allocate latitude and longitude arrays */ + self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + + /* Populate our arrays */ + false_easting = x0; + false_northing = y0; + for (j = 0; j < ny; j++) { + y = j * Dy; + for (i = 0; i < nx; i++) { + const int index = i + j * nx; + double _x, _y; + x = i * Dx; + /* Inverse projection to convert from x,y to lat,lon */ + _x = x - false_easting; + _y = rh - y + false_northing; + rh1 = sqrt(_x * _x + _y * _y); + con = 1.0; + if (ns <= 0) { + rh1 = -rh1; + con = -con; + } + theta = 0.0; + if (rh1 != 0) + theta = atan2((con * _x), (con * _y)); + if ((rh1 != 0) || (ns > 0.0)) { + con = 1.0 / ns; + ts = pow((rh1 / (earthMajorAxisInMetres * F)), con); + latRad = compute_phi(e, ts, &err); + if (err) { + grib_context_log(h->context, GRIB_LOG_ERROR, + "%s: Failed to compute the latitude angle, phi2, for the inverse", ITER); + grib_context_free(h->context, self->lats); + grib_context_free(h->context, self->lons); + return err; + } + } else { + latRad = -M_PI_2; + } + lonRad = adjust_lon_radians(theta / ns + LoVInRadians); + if (i == 0 && j == 0) { + DebugAssert(fabs(latFirstInRadians - latRad) <= EPSILON); + } + latDeg = latRad * RAD2DEG; /* Convert to degrees */ + lonDeg = normalise_longitude_in_degrees(lonRad * RAD2DEG); + self->lons[index] = lonDeg; + self->lats[index] = latDeg; + } + } + return GRIB_SUCCESS; +} + +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) +{ + int err = 0, is_oblate = 0; + long nx, ny, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning; + double LoVInDegrees, LaDInDegrees, Latin1InDegrees, Latin2InDegrees, latFirstInDegrees, + lonFirstInDegrees, Dx, Dy, radius = 0; + double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, + LaDInRadians; + double earthMajorAxisInMetres=0, earthMinorAxisInMetres=0; + + grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; + + const char* sradius = grib_arguments_get_name(h, args, self->carg++); + const char* snx = grib_arguments_get_name(h, args, self->carg++); + const char* sny = grib_arguments_get_name(h, args, self->carg++); + const char* sLoVInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sLaDInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sLatin1InDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sLatin2InDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + /* Dx and Dy are in Metres */ + const char* sDx = grib_arguments_get_name(h, args, self->carg++); + const char* sDy = grib_arguments_get_name(h, args, self->carg++); + const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); + const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); + + if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) return err; + if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) return err; + + is_oblate = grib_is_earth_oblate(h); + + if (is_oblate) { + if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; + if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; + } else { + if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) return err; + } + + if (iter->nv != nx * ny) { + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%ld!=%ldx%ld)", ITER, iter->nv, nx, ny); + return GRIB_WRONG_GRID; + } + + if ((err = grib_get_double_internal(h, sLoVInDegrees, &LoVInDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, sLaDInDegrees, &LaDInDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, sLatin1InDegrees, &Latin1InDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, sLatin2InDegrees, &Latin2InDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, slonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, sDx, &Dx)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, sDy, &Dy)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) + return err; + + /* Standard Parallels cannot be equal and on opposite sides of the equator */ + if (fabs(Latin1InDegrees + Latin2InDegrees) < EPSILON) { + grib_context_log(h->context, GRIB_LOG_ERROR, + "%s: Cannot have equal latitudes for standard parallels on opposite sides of equator", ITER); + return GRIB_WRONG_GRID; + } + + /* + * See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html + */ + latFirstInRadians = latFirstInDegrees * DEG2RAD; + lonFirstInRadians = lonFirstInDegrees * DEG2RAD; + Latin1InRadians = Latin1InDegrees * DEG2RAD; + Latin2InRadians = Latin2InDegrees * DEG2RAD; + LaDInRadians = LaDInDegrees * DEG2RAD; + LoVInRadians = LoVInDegrees * DEG2RAD; + + if (is_oblate) { + err = init_oblate(h, self, iter->nv, nx, ny, + LoVInDegrees, + Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, + latFirstInRadians, lonFirstInRadians, + LoVInRadians, Latin1InRadians, Latin2InRadians, + LaDInRadians); + } else { + err = init_sphere(h, self, iter->nv, nx, ny, + LoVInDegrees, + Dx, Dy, radius, + latFirstInRadians, lonFirstInRadians, + LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians); + } + if (err) return err; + + iter->e = -1; + + /* Apply the scanning mode flags which may require data array to be transformed */ + err = transform_iterator_data(h->context, iter->data, + iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, + iter->nv, nx, ny); + return err; +} + +static int next(grib_iterator* i, double* lat, double* lon, double* val) +{ + grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; + + if ((long)i->e >= (long)(i->nv - 1)) + return 0; + i->e++; + + *lat = self->lats[i->e]; + *lon = self->lons[i->e]; + *val = i->data[i->e]; + + return 1; +} + +static int destroy(grib_iterator* i) +{ + grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; + const grib_context* c = i->h->context; + + grib_context_free(c, self->lats); + grib_context_free(c, self->lons); + return 1; +} diff --git a/src/grib_iterator_class_polar_stereographic.cc b/src/grib_iterator_class_polar_stereographic.cc new file mode 100644 index 000000000..0e3988030 --- /dev/null +++ b/src/grib_iterator_class_polar_stereographic.cc @@ -0,0 +1,374 @@ +/* + * (C) Copyright 2005- 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" +#include + +/* + This is used by make_class.pl + + START_CLASS_DEF + CLASS = iterator + SUPER = grib_iterator_class_gen + IMPLEMENTS = destroy + IMPLEMENTS = init;next + MEMBERS = double *lats + MEMBERS = double *lons + MEMBERS = long Nj + 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 "iterator.class" and rerun ./make_class.pl + +*/ + + +static void init_class (grib_iterator_class*); + +static int init (grib_iterator* i,grib_handle*,grib_arguments*); +static int next (grib_iterator* i, double *lat, double *lon, double *val); +static int destroy (grib_iterator* i); + + +typedef struct grib_iterator_polar_stereographic{ + grib_iterator it; + /* Members defined in gen */ + int carg; + const char* missingValue; + /* Members defined in polar_stereographic */ + double *lats; + double *lons; + long Nj; +} grib_iterator_polar_stereographic; + +extern grib_iterator_class* grib_iterator_class_gen; + +static grib_iterator_class _grib_iterator_class_polar_stereographic = { + &grib_iterator_class_gen, /* super */ + "polar_stereographic", /* name */ + sizeof(grib_iterator_polar_stereographic),/* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ +}; + +grib_iterator_class* grib_iterator_class_polar_stereographic = &_grib_iterator_class_polar_stereographic; + + +static void init_class(grib_iterator_class* c) +{ + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; +} +/* END_CLASS_IMP */ + +#define ITER "Polar stereographic Geoiterator" + +static int next(grib_iterator* i, double* lat, double* lon, double* val) +{ + grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; + + if ((long)i->e >= (long)(i->nv - 1)) + return 0; + i->e++; + + *lat = self->lats[i->e]; + *lon = self->lons[i->e]; + *val = i->data[i->e]; + + return 1; +} + +/* Data struct for Forward and Inverse Projections */ +typedef struct proj_data_t +{ + double centre_lon; /* central longitude */ + double centre_lat; /* central latitude */ + double sign; /* sign variable */ + double ind; /* flag variable */ + double mcs; /* small m */ + double tcs; /* small t */ + double false_northing; /* y offset in meters */ + double false_easting; /* x offset in meters */ +} proj_data_t; + +#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ +#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +#define PI_OVER_2 1.5707963267948966 /* half pi */ +#define EPSILON 1.0e-10 + +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) +{ + int ret = 0; + double *lats, *lons; /* arrays for latitudes and longitudes */ + double lonFirstInDegrees, latFirstInDegrees, radius; + double x, y, Dx, Dy; + long nx, ny, centralLongitudeInDegrees, centralLatitudeInDegrees; + long alternativeRowScanning, iScansNegatively, i, j; + long jScansPositively, jPointsAreConsecutive, southPoleOnPlane; + double centralLongitude, centralLatitude; /* in radians */ + double con1; /* temporary angle */ + double ts; /* value of small t */ + double height; /* height above ellipsoid */ + double x0, y0, lonFirst, latFirst; + proj_data_t fwd_proj_data = {0,}; + proj_data_t inv_proj_data = {0,}; + + grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)iter; + + const char* s_radius = grib_arguments_get_name(h, args, self->carg++); + const char* s_nx = grib_arguments_get_name(h, args, self->carg++); + const char* s_ny = grib_arguments_get_name(h, args, self->carg++); + const char* s_latFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* s_lonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* s_southPoleOnPlane = grib_arguments_get_name(h, args, self->carg++); + const char* s_centralLongitude = grib_arguments_get_name(h, args, self->carg++); + const char* s_centralLatitude = grib_arguments_get_name(h, args, self->carg++); + const char* s_Dx = grib_arguments_get_name(h, args, self->carg++); + const char* s_Dy = grib_arguments_get_name(h, args, self->carg++); + const char* s_iScansNegatively = grib_arguments_get_name(h, args, self->carg++); + const char* s_jScansPositively = grib_arguments_get_name(h, args, self->carg++); + const char* s_jPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); + const char* s_alternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); + + if (grib_is_earth_oblate(h)) { + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Only supported for spherical earth.", ITER); + return GRIB_GEOCALCULUS_PROBLEM; + } + + if ((ret = grib_get_double_internal(h, s_radius, &radius)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, s_nx, &nx)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, s_ny, &ny)) != GRIB_SUCCESS) + return ret; + + if (iter->nv != nx * ny) { + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%ld!=%ldx%ld)", ITER, iter->nv, nx, ny); + return GRIB_WRONG_GRID; + } + if ((ret = grib_get_double_internal(h, s_latFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_double_internal(h, s_lonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, s_southPoleOnPlane, &southPoleOnPlane)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, s_centralLongitude, ¢ralLongitudeInDegrees)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, s_centralLatitude, ¢ralLatitudeInDegrees)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_double_internal(h, s_Dx, &Dx)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_double_internal(h, s_Dy, &Dy)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, s_jPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, s_jScansPositively, &jScansPositively)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, s_iScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, s_alternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) + return ret; + + centralLongitude = centralLongitudeInDegrees * DEG2RAD; + centralLatitude = centralLatitudeInDegrees * DEG2RAD; + lonFirst = lonFirstInDegrees * DEG2RAD; + latFirst = latFirstInDegrees * DEG2RAD; + + /* Forward projection initialisation */ + fwd_proj_data.false_northing = 0; + fwd_proj_data.false_easting = 0; + fwd_proj_data.centre_lon = centralLongitude; + fwd_proj_data.centre_lat = centralLatitude; + if (centralLatitude < 0) + fwd_proj_data.sign = -1.0; + else + fwd_proj_data.sign = +1.0; + fwd_proj_data.ind = 0; + if (fabs(fabs(centralLatitude) - PI_OVER_2) > EPSILON) { + /* central latitude different from 90 i.e. not north/south polar */ + fwd_proj_data.ind = 1; + con1 = fwd_proj_data.sign * centralLatitude; + fwd_proj_data.mcs = cos(con1); + fwd_proj_data.tcs = tan(0.5 * (PI_OVER_2 - con1)); + } + + /* Forward projection from initial lat,lon to initial x,y */ + con1 = fwd_proj_data.sign * (lonFirst - fwd_proj_data.centre_lon); + ts = tan(0.5 * (PI_OVER_2 - fwd_proj_data.sign * latFirst)); + if (fwd_proj_data.ind) + height = radius * fwd_proj_data.mcs * ts / fwd_proj_data.tcs; + else + height = 2.0 * radius * ts; + x0 = fwd_proj_data.sign * height * sin(con1) + fwd_proj_data.false_easting; + y0 = -fwd_proj_data.sign * height * cos(con1) + fwd_proj_data.false_northing; + + x0 = -x0; + y0 = -y0; + + /* Inverse projection initialisation */ + inv_proj_data.false_easting = x0; + inv_proj_data.false_northing = y0; + inv_proj_data.centre_lon = centralLongitude; + inv_proj_data.centre_lat = centralLatitude; + if (centralLatitude < 0) + inv_proj_data.sign = -1.0; + else + inv_proj_data.sign = +1.0; + inv_proj_data.ind = 0; + if (fabs(fabs(centralLatitude) - PI_OVER_2) > EPSILON) { + inv_proj_data.ind = 1; + con1 = inv_proj_data.sign * inv_proj_data.centre_lat; + inv_proj_data.mcs = cos(con1); + inv_proj_data.tcs = tan(0.5 * (PI_OVER_2 - con1)); + } + self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, iter->nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, iter->nv * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + lats = self->lats; + lons = self->lons; + /* These will be processed later in transform_iterator_data() */ + /* Dx = iScansNegatively == 0 ? Dx : -Dx; */ + /* Dy = jScansPositively == 1 ? Dy : -Dy; */ + + y = 0; + for (j = 0; j < ny; j++) { + x = 0; + for (i = 0; i < nx; i++) { + /* Inverse projection from x,y to lat,lon */ + /* int index =i+j*nx; */ + double _x = (x - inv_proj_data.false_easting) * inv_proj_data.sign; + double _y = (y - inv_proj_data.false_northing) * inv_proj_data.sign; + double rh = sqrt(_x * _x + _y * _y); + if (inv_proj_data.ind) + ts = rh * inv_proj_data.tcs / (radius * inv_proj_data.mcs); + else + ts = rh / (radius * 2.0); + *lats = inv_proj_data.sign * (PI_OVER_2 - 2 * atan(ts)); + if (rh == 0) { + *lons = inv_proj_data.sign * inv_proj_data.centre_lon; + } + else { + double temp = atan2(_x, -_y); + *lons = inv_proj_data.sign * temp + inv_proj_data.centre_lon; + } + *lats = *lats * RAD2DEG; + *lons = *lons * RAD2DEG; + while (*lons < 0) + *lons += 360; + while (*lons > 360) + *lons -= 360; + lons++; + lats++; + + x += Dx; + } + y += Dy; + } +#if 0 + /*standardParallel = (southPoleOnPlane == 1) ? -90 : +90;*/ + if (jPointsAreConsecutive) + { + x=xFirst; + for (i=0;i360) *lons -= 360; + lons++; + lats++; + + y+=Dy; + } + x+=Dx; + } + } + else + { + y=yFirst; + for (j=0;j360) *lons -= 360; + lons++; + lats++; + + x+=Dx; + } + y+=Dy; + } + } +#endif + iter->e = -1; + + /* Apply the scanning mode flags which may require data array to be transformed */ + ret = transform_iterator_data(h->context, iter->data, + iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, + iter->nv, nx, ny); + + return ret; +} + +static int destroy(grib_iterator* i) +{ + grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; + const grib_context* c = i->h->context; + + grib_context_free(c, self->lats); + grib_context_free(c, self->lons); + return 1; +} diff --git a/src/grib_iterator_class_space_view.cc b/src/grib_iterator_class_space_view.cc new file mode 100644 index 000000000..355acfa13 --- /dev/null +++ b/src/grib_iterator_class_space_view.cc @@ -0,0 +1,388 @@ +/* + * (C) Copyright 2005- 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" +#include + +/* + This is used by make_class.pl + + START_CLASS_DEF + CLASS = iterator + SUPER = grib_iterator_class_gen + IMPLEMENTS = destroy + IMPLEMENTS = init;next + MEMBERS = double *lats + MEMBERS = double *lons + MEMBERS = long Nj + 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 "iterator.class" and rerun ./make_class.pl + +*/ + + +static void init_class (grib_iterator_class*); + +static int init (grib_iterator* i,grib_handle*,grib_arguments*); +static int next (grib_iterator* i, double *lat, double *lon, double *val); +static int destroy (grib_iterator* i); + + +typedef struct grib_iterator_space_view{ + grib_iterator it; + /* Members defined in gen */ + int carg; + const char* missingValue; + /* Members defined in space_view */ + double *lats; + double *lons; + long Nj; +} grib_iterator_space_view; + +extern grib_iterator_class* grib_iterator_class_gen; + +static grib_iterator_class _grib_iterator_class_space_view = { + &grib_iterator_class_gen, /* super */ + "space_view", /* name */ + sizeof(grib_iterator_space_view),/* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ +}; + +grib_iterator_class* grib_iterator_class_space_view = &_grib_iterator_class_space_view; + + +static void init_class(grib_iterator_class* c) +{ + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; +} +/* END_CLASS_IMP */ + +static int next(grib_iterator* i, double* lat, double* lon, double* val) +{ + grib_iterator_space_view* self = (grib_iterator_space_view*)i; + + if ((long)i->e >= (long)(i->nv - 1)) + return 0; + i->e++; + + *lat = self->lats[i->e]; + *lon = self->lons[i->e]; + *val = i->data[i->e]; + + return 1; +} + +#if 0 +static void adjustBadlyEncodedEcmwfGribs(grib_handle* h, + long* nx, long* ny, double* dx, double* dy, double* xp, double* yp) +{ + /* Correct the information provided in the headers of certain satellite imagery that + * we have available. This is specific to ECMWF. + * Obtained through trial-and-error to get the best match with the coastlines. + * + * Copied from Magics GribSatelliteInterpretor::AdjustBadlyEncodedGribs() + */ + long centre = 0; + int err = grib_get_long(h, "centre", ¢re); + if (!err && centre == 98) { + int err1 = 0, err2 = 0, err3 = 0; + long satelliteIdentifier, channelNumber, functionCode; + /* These keys are defined in the ECMWF local definition 24 - Satellite image simulation */ + err1 = grib_get_long(h, "satelliteIdentifier", &satelliteIdentifier); + err2 = grib_get_long(h, "channelNumber", &channelNumber); + err3 = grib_get_long(h, "functionCode", &functionCode); + if (!err1 && !err2 && !err3) { + if (satelliteIdentifier == 54 && channelNumber == 2 && *dx == 1179) { /* Meteosat 7, channel 2 */ + *nx = *ny = 900; + *dx = *dy = 853; + *xp = *yp = 450; + } + else if (satelliteIdentifier == 54 && channelNumber == 3 && *dx == 1179) { /* Meteosat 7, channel 3 */ + *dx = *dy = 1184; + *xp = *yp = 635; + } + else if (satelliteIdentifier == 259 && channelNumber == 4 && *dx == 1185) { /* GOES-15 (West) channel 4 */ + *dx = *dy = 880; + *xp = *yp = 450; + } + else if (satelliteIdentifier == 57 && *dx == 1732) { /* MSG (Meteosat second generation), non-HRV channels */ + *dx = *dy = 1811; + *xp = *yp = 928; + } + } + } +} +#endif + +#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ +#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ + +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) +{ + /* REFERENCE: + * LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) + */ + int ret = GRIB_SUCCESS; + double *lats, *lons; /* arrays of latitudes and longitudes */ + double latOfSubSatellitePointInDegrees, lonOfSubSatellitePointInDegrees; + double orientationInDegrees, nrInRadiusOfEarth; + double radius = 0, xpInGridLengths = 0, ypInGridLengths = 0; + long nx, ny, earthIsOblate = 0; + long alternativeRowScanning, iScansNegatively; + long Xo, Yo, jScansPositively, jPointsAreConsecutive, i; + + double major = 0, minor = 0, r_eq, r_pol, height; + double lap, lop, angular_size; + double xp, yp, dx, dy, rx, ry, x, y; + double cos_x, cos_y, sin_x, sin_y; + double factor_1, factor_2, tmp1, Sd, Sn, Sxy, S1, S2, S3; + int x0, y0, ix, iy; + double *s_x, *c_x; /* arrays storing sin and cos values */ + size_t array_size = (iter->nv * sizeof(double)); + + grib_iterator_space_view* self = (grib_iterator_space_view*)iter; + + const char* sradius = grib_arguments_get_name(h, args, self->carg++); + const char* sEarthIsOblate = grib_arguments_get_name(h, args, self->carg++); + const char* sMajorAxisInMetres = grib_arguments_get_name(h, args, self->carg++); + const char* sMinorAxisInMetres = grib_arguments_get_name(h, args, self->carg++); + const char* snx = grib_arguments_get_name(h, args, self->carg++); + const char* sny = grib_arguments_get_name(h, args, self->carg++); + const char* sLatOfSubSatellitePointInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sLonOfSubSatellitePointInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sDx = grib_arguments_get_name(h, args, self->carg++); + const char* sDy = grib_arguments_get_name(h, args, self->carg++); + const char* sXpInGridLengths = grib_arguments_get_name(h, args, self->carg++); + const char* sYpInGridLengths = grib_arguments_get_name(h, args, self->carg++); + const char* sOrientationInDegrees = grib_arguments_get_name(h, args, self->carg++); + const char* sNrInRadiusOfEarth = grib_arguments_get_name(h, args, self->carg++); + const char* sXo = grib_arguments_get_name(h, args, self->carg++); + const char* sYo = grib_arguments_get_name(h, args, self->carg++); + + const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); + const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); + const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); + const char* sAlternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); + + if ((ret = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, sEarthIsOblate, &earthIsOblate)) != GRIB_SUCCESS) + return ret; + + if (earthIsOblate) { + if ((ret = grib_get_double_internal(h, sMajorAxisInMetres, &major)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_double_internal(h, sMinorAxisInMetres, &minor)) != GRIB_SUCCESS) + return ret; + } + else { + if ((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) + return ret; + } + + if (iter->nv != nx * ny) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); + return GRIB_WRONG_GRID; + } + if ((ret = grib_get_double_internal(h, sLatOfSubSatellitePointInDegrees, &latOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_double_internal(h, sLonOfSubSatellitePointInDegrees, &lonOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_double_internal(h, sDx, &dx)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_double_internal(h, sDy, &dy)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_double_internal(h, sXpInGridLengths, &xpInGridLengths)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_double_internal(h, sYpInGridLengths, &ypInGridLengths)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_double_internal(h, sOrientationInDegrees, &orientationInDegrees)) != GRIB_SUCCESS) + return ret; + + /* Orthographic not supported. This happens when Nr (camera altitude) is missing */ + if (grib_is_missing(h, sNrInRadiusOfEarth, &ret)) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Space View: Orthographic view (Nr missing) not supported"); + return GRIB_NOT_IMPLEMENTED; + } + if ((ret = grib_get_double_internal(h, sNrInRadiusOfEarth, &nrInRadiusOfEarth)) != GRIB_SUCCESS) + return ret; + + if ((ret = grib_get_long_internal(h, sXo, &Xo)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, sYo, &Yo)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) + return ret; + if ((ret = grib_get_long_internal(h, sAlternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) + return ret; + + if (earthIsOblate) { + r_eq = major; /* In km */ + r_pol = minor; + } + else { + r_eq = r_pol = radius * 0.001; /*conv to km*/ + } + + if (nrInRadiusOfEarth == 0) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Space View: Key %s must be greater than zero", sNrInRadiusOfEarth); + return GRIB_GEOCALCULUS_PROBLEM; + } + + angular_size = 2.0 * asin(1.0 / nrInRadiusOfEarth); + height = nrInRadiusOfEarth * r_eq; + + lap = latOfSubSatellitePointInDegrees; + lop = lonOfSubSatellitePointInDegrees; + if (lap != 0.0) { + grib_context_log(h->context, GRIB_LOG_ERROR, + "Space View: Key '%s' must be 0 (satellite must be located in the equator plane)", + sLatOfSubSatellitePointInDegrees); + return GRIB_GEOCALCULUS_PROBLEM; + } + + /*orient_angle = orientationInDegrees;*/ + /* if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; */ + + xp = xpInGridLengths; + yp = ypInGridLengths; + x0 = Xo; + y0 = Yo; + + /* adjustBadlyEncodedEcmwfGribs(h, &nx, &ny, &dx, &dy, &xp, &yp); */ + if (dx == 0 || dy == 0) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Space View: Keys %s and %s must be greater than zero", sDx, sDy); + return GRIB_GEOCALCULUS_PROBLEM; + } + rx = angular_size / dx; + ry = (r_pol / r_eq) * angular_size / dy; + + self->lats = (double*)grib_context_malloc(h->context, array_size); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", array_size); + return GRIB_OUT_OF_MEMORY; + } + self->lons = (double*)grib_context_malloc(h->context, array_size); + if (!self->lats) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", array_size); + return GRIB_OUT_OF_MEMORY; + } + lats = self->lats; + lons = self->lons; + + if (!iScansNegatively) { + xp = xp - x0; + } + else { + xp = (nx - 1) - (xp - x0); + } + if (jScansPositively) { + yp = yp - y0; + } + else { + yp = (ny - 1) - (yp - y0); + } + i = 0; + factor_2 = (r_eq / r_pol) * (r_eq / r_pol); + factor_1 = height * height - r_eq * r_eq; + + /* Store array of sin and cosine values to avoid recalculation */ + s_x = (double*)grib_context_malloc(h->context, nx * sizeof(double)); + if (!s_x) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nx * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + c_x = (double*)grib_context_malloc(h->context, nx * sizeof(double)); + if (!c_x) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nx * sizeof(double)); + return GRIB_OUT_OF_MEMORY; + } + + for (ix = 0; ix < nx; ix++) { + x = (ix - xp) * rx; + s_x[ix] = sin(x); + c_x[ix] = sqrt(1.0 - s_x[ix] * s_x[ix]); + } + + /*for (iy = 0; iy < ny; iy++) {*/ + for (iy = ny - 1; iy >= 0; --iy) { + y = (iy - yp) * ry; + sin_y = sin(y); + cos_y = sqrt(1.0 - sin_y * sin_y); + + tmp1 = (1 + (factor_2 - 1.0) * sin_y * sin_y); + + for (ix = 0; ix < nx; ix++, i++) { + /*x = (ix - xp) * rx;*/ + /* Use sin/cos previously computed */ + sin_x = s_x[ix]; + cos_x = c_x[ix]; + + Sd = height * cos_x * cos_y; + Sd = Sd * Sd - tmp1 * factor_1; + if (Sd <= 0.0) { /* outside of view */ + lats[i] = lons[i] = 0; /* TODO: error? */ + } + else { + Sd = sqrt(Sd); + Sn = (height * cos_x * cos_y - Sd) / tmp1; + S1 = height - Sn * cos_x * cos_y; + S2 = Sn * sin_x * cos_y; + S3 = Sn * sin_y; + Sxy = sqrt(S1 * S1 + S2 * S2); + lons[i] = atan(S2 / S1) * (RAD2DEG) + lop; + lats[i] = atan(factor_2 * S3 / Sxy) * (RAD2DEG); + /*fprintf(stderr, "lat=%g lon=%g\n", lats[i], lons[i]);*/ + } + while (lons[i] < 0) + lons[i] += 360; + while (lons[i] > 360) + lons[i] -= 360; + } + } + grib_context_free(h->context, s_x); + grib_context_free(h->context, c_x); + iter->e = -1; + + return ret; +} + +static int destroy(grib_iterator* i) +{ + grib_iterator_space_view* self = (grib_iterator_space_view*)i; + const grib_context* c = i->h->context; + + grib_context_free(c, self->lats); + grib_context_free(c, self->lons); + return 1; +} From 3b45b2cead18bd02c4d92baad094df37e9a031e5 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Mon, 6 Feb 2023 11:17:16 +0000 Subject: [PATCH 088/737] GeoIterator: Ability to not decode values --- ...erator_class_lambert_azimuthal_equal_area.cc | 17 +++++++++-------- src/grib_iterator_class_lambert_conformal.cc | 17 +++++++++-------- src/grib_iterator_class_polar_stereographic.cc | 17 +++++++++-------- src/grib_iterator_class_space_view.cc | 17 +++++++++-------- 4 files changed, 36 insertions(+), 32 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.cc b/src/grib_iterator_class_lambert_azimuthal_equal_area.cc index 5d54aee88..f20153e62 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.cc +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.cc @@ -81,18 +81,19 @@ static void init_class(grib_iterator_class* c) } /* END_CLASS_IMP */ -static int next(grib_iterator* i, double* lat, double* lon, double* val) +static int next(grib_iterator* iter, double* lat, double* lon, double* val) { - grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; + grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)iter; - if ((long)i->e >= (long)(i->nv - 1)) + if ((long)iter->e >= (long)(iter->nv - 1)) return 0; - i->e++; - - *lat = self->lats[i->e]; - *lon = self->lons[i->e]; - *val = i->data[i->e]; + iter->e++; + *lat = self->lats[iter->e]; + *lon = self->lons[iter->e]; + if (val && iter->data) { + *val = iter->data[iter->e]; + } return 1; } diff --git a/src/grib_iterator_class_lambert_conformal.cc b/src/grib_iterator_class_lambert_conformal.cc index a39b314ab..1cb34e412 100644 --- a/src/grib_iterator_class_lambert_conformal.cc +++ b/src/grib_iterator_class_lambert_conformal.cc @@ -485,18 +485,19 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return err; } -static int next(grib_iterator* i, double* lat, double* lon, double* val) +static int next(grib_iterator* iter, double* lat, double* lon, double* val) { - grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; + grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; - if ((long)i->e >= (long)(i->nv - 1)) + if ((long)iter->e >= (long)(iter->nv - 1)) return 0; - i->e++; - - *lat = self->lats[i->e]; - *lon = self->lons[i->e]; - *val = i->data[i->e]; + iter->e++; + *lat = self->lats[iter->e]; + *lon = self->lons[iter->e]; + if (val && iter->data) { + *val = iter->data[iter->e]; + } return 1; } diff --git a/src/grib_iterator_class_polar_stereographic.cc b/src/grib_iterator_class_polar_stereographic.cc index 0e3988030..10a1eccd4 100644 --- a/src/grib_iterator_class_polar_stereographic.cc +++ b/src/grib_iterator_class_polar_stereographic.cc @@ -83,18 +83,19 @@ static void init_class(grib_iterator_class* c) #define ITER "Polar stereographic Geoiterator" -static int next(grib_iterator* i, double* lat, double* lon, double* val) +static int next(grib_iterator* iter, double* lat, double* lon, double* val) { - grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; + grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)iter; - if ((long)i->e >= (long)(i->nv - 1)) + if ((long)iter->e >= (long)(iter->nv - 1)) return 0; - i->e++; - - *lat = self->lats[i->e]; - *lon = self->lons[i->e]; - *val = i->data[i->e]; + iter->e++; + *lat = self->lats[iter->e]; + *lon = self->lons[iter->e]; + if (val && iter->data) { + *val = iter->data[iter->e]; + } return 1; } diff --git a/src/grib_iterator_class_space_view.cc b/src/grib_iterator_class_space_view.cc index 355acfa13..e04b3e714 100644 --- a/src/grib_iterator_class_space_view.cc +++ b/src/grib_iterator_class_space_view.cc @@ -81,18 +81,19 @@ static void init_class(grib_iterator_class* c) } /* END_CLASS_IMP */ -static int next(grib_iterator* i, double* lat, double* lon, double* val) +static int next(grib_iterator* iter, double* lat, double* lon, double* val) { - grib_iterator_space_view* self = (grib_iterator_space_view*)i; + grib_iterator_space_view* self = (grib_iterator_space_view*)iter; - if ((long)i->e >= (long)(i->nv - 1)) + if ((long)iter->e >= (long)(iter->nv - 1)) return 0; - i->e++; - - *lat = self->lats[i->e]; - *lon = self->lons[i->e]; - *val = i->data[i->e]; + iter->e++; + *lat = self->lats[iter->e]; + *lon = self->lons[iter->e]; + if (val && iter->data) { + *val = iter->data[iter->e]; + } return 1; } From 5e47a0f8def524cfa0a50a23d47123fc9bb5d8c0 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 7 Feb 2023 19:30:39 +0000 Subject: [PATCH 089/737] Return value should be GRIB_SUCCESS --- src/grib_iterator_class_lambert_azimuthal_equal_area.cc | 8 ++++---- src/grib_iterator_class_lambert_conformal.cc | 2 +- src/grib_iterator_class_polar_stereographic.cc | 2 +- src/grib_iterator_class_space_view.cc | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.cc b/src/grib_iterator_class_lambert_azimuthal_equal_area.cc index f20153e62..f77b23afc 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.cc +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.cc @@ -487,12 +487,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return GRIB_SUCCESS; } -static int destroy(grib_iterator* i) +static int destroy(grib_iterator* iter) { - grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)i; - const grib_context* c = i->h->context; + grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)iter; + const grib_context* c = iter->h->context; grib_context_free(c, self->lats); grib_context_free(c, self->lons); - return 1; + return GRIB_SUCCESS; } diff --git a/src/grib_iterator_class_lambert_conformal.cc b/src/grib_iterator_class_lambert_conformal.cc index 1cb34e412..8c5fed223 100644 --- a/src/grib_iterator_class_lambert_conformal.cc +++ b/src/grib_iterator_class_lambert_conformal.cc @@ -508,5 +508,5 @@ static int destroy(grib_iterator* i) grib_context_free(c, self->lats); grib_context_free(c, self->lons); - return 1; + return GRIB_SUCCESS; } diff --git a/src/grib_iterator_class_polar_stereographic.cc b/src/grib_iterator_class_polar_stereographic.cc index 10a1eccd4..1f8b0d17b 100644 --- a/src/grib_iterator_class_polar_stereographic.cc +++ b/src/grib_iterator_class_polar_stereographic.cc @@ -371,5 +371,5 @@ static int destroy(grib_iterator* i) grib_context_free(c, self->lats); grib_context_free(c, self->lons); - return 1; + return GRIB_SUCCESS; } diff --git a/src/grib_iterator_class_space_view.cc b/src/grib_iterator_class_space_view.cc index e04b3e714..70299278b 100644 --- a/src/grib_iterator_class_space_view.cc +++ b/src/grib_iterator_class_space_view.cc @@ -378,12 +378,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return ret; } -static int destroy(grib_iterator* i) +static int destroy(grib_iterator* iter) { - grib_iterator_space_view* self = (grib_iterator_space_view*)i; - const grib_context* c = i->h->context; + grib_iterator_space_view* self = (grib_iterator_space_view*)iter; + const grib_context* c = iter->h->context; grib_context_free(c, self->lats); grib_context_free(c, self->lons); - return 1; + return GRIB_SUCCESS; } From 88ab6029025e0f7b530e97e767b667e72922a1b8 Mon Sep 17 00:00:00 2001 From: Tiago Quintino Date: Tue, 28 Feb 2023 09:18:29 +0000 Subject: [PATCH 090/737] Initial commit --- .gitignore | 32 +++++++++ LICENSE | 201 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 2 + 3 files changed, 235 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..259148fa1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,32 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 000000000..f0d1d1442 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# griditer +Geospatial Grid definitiona and iteration library From 69124b7814eca019c934ca493ac718d7119c4c68 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 28 Feb 2023 09:26:13 +0000 Subject: [PATCH 091/737] README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f0d1d1442..5874a75ff 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ # griditer -Geospatial Grid definitiona and iteration library +Geospatial Grid definitions and iterators library From 2498e22d40f4f50c9efb3194c5be76a8b9f0ba96 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 28 Feb 2023 09:26:24 +0000 Subject: [PATCH 092/737] clang-format --- .clang-format | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..3cc0f3f0c --- /dev/null +++ b/.clang-format @@ -0,0 +1,106 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: true + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: AfterColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeCategories: + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: false +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 4 +UseTab: Never +... From 0b4147f43ce6edace0fc89d9ed0928ed9746e0b6 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 28 Feb 2023 09:46:05 +0000 Subject: [PATCH 093/737] cmake --- CMakeLists.txt | 22 ++++++++++++++++++++++ etc/CMakeLists.txt | 2 ++ etc/griditer/CMakeLists.txt | 1 + share/CMakeLists.txt | 2 ++ share/griditer/CMakeLists.txt | 1 + src/CMakeLists.txt | 2 ++ src/griditer/CMakeLists.txt | 1 + tests/CMakeLists.txt | 1 + 8 files changed, 32 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 etc/CMakeLists.txt create mode 100644 etc/griditer/CMakeLists.txt create mode 100644 share/CMakeLists.txt create mode 100644 share/griditer/CMakeLists.txt create mode 100644 src/CMakeLists.txt create mode 100644 src/griditer/CMakeLists.txt create mode 100644 tests/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..7aaca0aaf --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,22 @@ +# (C) Copyright 1996- 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. + + +cmake_minimum_required(VERSION 3.14 FATAL_ERROR) + +project(griditer VERSION 0.0.0 LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +add_subdirectory(src) +add_subdirectory(etc) +add_subdirectory(share) +add_subdirectory(tests) + diff --git a/etc/CMakeLists.txt b/etc/CMakeLists.txt new file mode 100644 index 000000000..988ef9af4 --- /dev/null +++ b/etc/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(griditer) + diff --git a/etc/griditer/CMakeLists.txt b/etc/griditer/CMakeLists.txt new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/etc/griditer/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt new file mode 100644 index 000000000..988ef9af4 --- /dev/null +++ b/share/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(griditer) + diff --git a/share/griditer/CMakeLists.txt b/share/griditer/CMakeLists.txt new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/share/griditer/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 000000000..988ef9af4 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(griditer) + diff --git a/src/griditer/CMakeLists.txt b/src/griditer/CMakeLists.txt new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/src/griditer/CMakeLists.txt @@ -0,0 +1 @@ + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1 @@ + From 271d7026bac09f5e8c369eb35cf29623119d63e3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 14 Mar 2023 14:32:28 +0000 Subject: [PATCH 094/737] cmake --- .gitignore | 4 ++++ src/CMakeLists.txt | 3 +++ src/griditer/CMakeLists.txt | 1 + src/griditer/griditer.h.in | 4 ++++ src/tools/CMakeLists.txt | 2 ++ src/tools/griditer-version.cc | 21 +++++++++++++++++++++ 6 files changed, 35 insertions(+) create mode 100644 src/griditer/griditer.h.in create mode 100644 src/tools/CMakeLists.txt create mode 100644 src/tools/griditer-version.cc diff --git a/.gitignore b/.gitignore index 259148fa1..11f3eb0e5 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,7 @@ *.exe *.out *.app + +# Other +CMakeLists.txt.user +.vscode diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 988ef9af4..2a4935927 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,2 +1,5 @@ +include_directories(BEFORE . ${CMAKE_CURRENT_BINARY_DIR}) + add_subdirectory(griditer) +add_subdirectory(tools) diff --git a/src/griditer/CMakeLists.txt b/src/griditer/CMakeLists.txt index 8b1378917..16c8ef916 100644 --- a/src/griditer/CMakeLists.txt +++ b/src/griditer/CMakeLists.txt @@ -1 +1,2 @@ +configure_file(griditer.h.in griditer.h) diff --git a/src/griditer/griditer.h.in b/src/griditer/griditer.h.in new file mode 100644 index 000000000..e7daf3544 --- /dev/null +++ b/src/griditer/griditer.h.in @@ -0,0 +1,4 @@ + +#define griditer_VERSION_MAJOR @griditer_VERSION_MAJOR@ +#define griditer_VERSION_MINOR @griditer_VERSION_MINOR@ +#define griditer_VERSION_PATCH @griditer_VERSION_PATCH@ diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt new file mode 100644 index 000000000..b756a9bc7 --- /dev/null +++ b/src/tools/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(griditer-version griditer-version.cc) + diff --git a/src/tools/griditer-version.cc b/src/tools/griditer-version.cc new file mode 100644 index 000000000..d8564adee --- /dev/null +++ b/src/tools/griditer-version.cc @@ -0,0 +1,21 @@ +/* + * (C) Copyright 1996- 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 + +#include "griditer/griditer.h" + + +int main(int /*argc*/, const char* /*argv*/[]) { + std::cout << griditer_VERSION_MAJOR << '.' << griditer_VERSION_MINOR << '.' << griditer_VERSION_PATCH << std::endl; + return 0; +} From b14a49aa3fc6709538282615aafbcd8ee0fb579d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 15 Mar 2023 17:48:11 +0000 Subject: [PATCH 095/737] cmake --- CMakeLists.txt | 35 ++++++++++++++++++++++++++++++++++- src/griditer/CMakeLists.txt | 4 ++++ src/griditer/example.cc | 17 +++++++++++++++++ src/griditer/example.h | 0 src/tools/CMakeLists.txt | 7 ++++++- tests/CMakeLists.txt | 8 ++++++++ tests/example.cc | 19 +++++++++++++++++++ 7 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 src/griditer/example.cc create mode 100644 src/griditer/example.h create mode 100644 tests/example.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 7aaca0aaf..c26b1c97a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,8 +15,41 @@ project(griditer VERSION 0.0.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) +if(APPLE) + set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON) +endif() + + +# library/resources add_subdirectory(src) add_subdirectory(etc) add_subdirectory(share) -add_subdirectory(tests) + +macro(get_all_targets targets dir) + get_property(subdirs DIRECTORY ${dir} PROPERTY SUBDIRECTORIES) + foreach(subdir ${subdirs}) + get_all_targets(${targets} ${subdir}) + endforeach() + + get_property(current_targets DIRECTORY ${dir} PROPERTY BUILDSYSTEM_TARGETS) + list(APPEND ${targets} ${current_targets}) +endmacro() + +set(all_targets) +get_all_targets(all_targets ${CMAKE_CURRENT_SOURCE_DIR}) + +install( + TARGETS ${all_targets} + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + PUBLIC_HEADER DESTINATION include + RUNTIME DESTINATION bin) + + +# tests +include(CTest) +if(BUILD_TESTING) + add_subdirectory(tests) +endif() + diff --git a/src/griditer/CMakeLists.txt b/src/griditer/CMakeLists.txt index 16c8ef916..3056ee166 100644 --- a/src/griditer/CMakeLists.txt +++ b/src/griditer/CMakeLists.txt @@ -1,2 +1,6 @@ configure_file(griditer.h.in griditer.h) +add_library(grit SHARED + example.h + example.cc) + diff --git a/src/griditer/example.cc b/src/griditer/example.cc new file mode 100644 index 000000000..c987f7c7b --- /dev/null +++ b/src/griditer/example.cc @@ -0,0 +1,17 @@ +/* + * (C) Copyright 1996- 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 "griditer/example.h" +#include "griditer/griditer.h" + + +static const int ANSWER = 42; diff --git a/src/griditer/example.h b/src/griditer/example.h new file mode 100644 index 000000000..e69de29bb diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index b756a9bc7..b6b148ab2 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -1,2 +1,7 @@ -add_executable(griditer-version griditer-version.cc) + +foreach(name + griditer-version) + add_executable(${name} ${name}.cc) + target_link_libraries(${name} grit) +endforeach() diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8b1378917..e564ee220 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1 +1,9 @@ +include(CTest) + +foreach(name + example) + add_executable(test_${name} ${name}.cc) + target_link_libraries(test_${name} grit) + add_test(test_${name} test_${name}) +endforeach() diff --git a/tests/example.cc b/tests/example.cc new file mode 100644 index 000000000..ca9ee7edb --- /dev/null +++ b/tests/example.cc @@ -0,0 +1,19 @@ +/* + * (C) Copyright 1996- 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 + + +int main(int argc, char* argv[]) { + std::cout << "Hello, example!" << std::endl; + return 0; +} From 835c171cb4ccc4d37418d900d50514e05814c357 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 20 Mar 2023 11:52:07 +0000 Subject: [PATCH 096/737] util --- src/griditer/CMakeLists.txt | 5 +++-- src/griditer/util.h | 28 ++++++++++++++++++++++++++++ src/griditer/util/arange.cc | 29 +++++++++++++++++++++++++++++ src/griditer/util/linspace.cc | 29 +++++++++++++++++++++++++++++ tests/CMakeLists.txt | 2 +- tests/{example.cc => util.cc} | 0 6 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 src/griditer/util.h create mode 100644 src/griditer/util/arange.cc create mode 100644 src/griditer/util/linspace.cc rename tests/{example.cc => util.cc} (100%) diff --git a/src/griditer/CMakeLists.txt b/src/griditer/CMakeLists.txt index 3056ee166..bdeb63a8a 100644 --- a/src/griditer/CMakeLists.txt +++ b/src/griditer/CMakeLists.txt @@ -1,6 +1,7 @@ configure_file(griditer.h.in griditer.h) add_library(grit SHARED - example.h - example.cc) + util.h + util/arange.cc + util/linspace.cc) diff --git a/src/griditer/util.h b/src/griditer/util.h new file mode 100644 index 000000000..9dfff46fa --- /dev/null +++ b/src/griditer/util.h @@ -0,0 +1,28 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + + +namespace grit::util { + + +std::vector arange(double start, double stop, double step); + + +std::vector linspace(double start, double stop, size_t num, bool endpoint); + + +} + diff --git a/src/griditer/util/arange.cc b/src/griditer/util/arange.cc new file mode 100644 index 000000000..89b1c6cd8 --- /dev/null +++ b/src/griditer/util/arange.cc @@ -0,0 +1,29 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "griditer/util.h" + + +namespace grit::util { + + +std::vector arange(double start, double stop, double step) { + return {}; +} + + +} + diff --git a/src/griditer/util/linspace.cc b/src/griditer/util/linspace.cc new file mode 100644 index 000000000..7ecebb2e5 --- /dev/null +++ b/src/griditer/util/linspace.cc @@ -0,0 +1,29 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "griditer/util.h" + + +namespace grit::util { + + +std::vector linspace(double start, double stop, size_t num, bool endpoint) { + return {}; +} + + +} + diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e564ee220..af355ef6e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,7 @@ include(CTest) foreach(name - example) + util) add_executable(test_${name} ${name}.cc) target_link_libraries(test_${name} grit) add_test(test_${name} test_${name}) diff --git a/tests/example.cc b/tests/util.cc similarity index 100% rename from tests/example.cc rename to tests/util.cc From b439997308bcb026e9df2952471db2a06fa720f3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 20 Mar 2023 16:52:33 +0000 Subject: [PATCH 097/737] util --- src/griditer/CMakeLists.txt | 2 ++ src/griditer/util.h | 3 +-- src/griditer/util/arange.cc | 27 ++++++++++++++++++++++----- src/griditer/util/linspace.cc | 17 ++++++++++++----- tests/util.cc | 18 ++++++++++++++++-- 5 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/griditer/CMakeLists.txt b/src/griditer/CMakeLists.txt index bdeb63a8a..80b99b373 100644 --- a/src/griditer/CMakeLists.txt +++ b/src/griditer/CMakeLists.txt @@ -5,3 +5,5 @@ add_library(grit SHARED util/arange.cc util/linspace.cc) +target_include_directories(grit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") + diff --git a/src/griditer/util.h b/src/griditer/util.h index 9dfff46fa..4a32d0339 100644 --- a/src/griditer/util.h +++ b/src/griditer/util.h @@ -24,5 +24,4 @@ std::vector arange(double start, double stop, double step); std::vector linspace(double start, double stop, size_t num, bool endpoint); -} - +} // namespace grit::util diff --git a/src/griditer/util/arange.cc b/src/griditer/util/arange.cc index 89b1c6cd8..45b3680ca 100644 --- a/src/griditer/util/arange.cc +++ b/src/griditer/util/arange.cc @@ -10,9 +10,9 @@ */ -#pragma once - -#include +#include +#include +#include #include "griditer/util.h" @@ -20,10 +20,27 @@ namespace grit::util { +template +bool approximately_equal(T x, T y, T eps = std::numeric_limits::epsilon()) { + auto min = std::min(std::abs(x), std::abs(y)); + return std::abs(min) == 0. ? std::abs(x - y) < eps + : std::abs(x - y) / std::max(std::numeric_limits::min(), min) < eps; +}; + + std::vector arange(double start, double stop, double step) { - return {}; -} + if (approximately_equal(step, 0.) || approximately_equal(start, stop) || (stop - start) * step < 0.) { + std::vector l(1, start); + return l; + } + + const auto num = static_cast((stop - start) / step) + 1; + std::vector l(num); + std::generate_n(l.begin(), num, [start, step, n = 0]() mutable { return start + static_cast(n++) * step; }); + return l; } + +} // namespace grit::util diff --git a/src/griditer/util/linspace.cc b/src/griditer/util/linspace.cc index 7ecebb2e5..5561ed51c 100644 --- a/src/griditer/util/linspace.cc +++ b/src/griditer/util/linspace.cc @@ -10,9 +10,7 @@ */ -#pragma once - -#include +#include #include "griditer/util.h" @@ -21,9 +19,18 @@ namespace grit::util { std::vector linspace(double start, double stop, size_t num, bool endpoint) { - return {}; -} + if (num == 0) { + return {}; + } + const auto step = num > 1 ? (stop - start) / static_cast(endpoint ? (num - 1) : num) : 0; + std::vector l(num); + std::generate_n(l.begin(), num, + [start, step, n = 0ull]() mutable { return start + static_cast(n++) * step; }); + + return l; } + +} // namespace grit::util diff --git a/tests/util.cc b/tests/util.cc index ca9ee7edb..f90917928 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -12,8 +12,22 @@ #include +#include "griditer/util.h" + + +template +std::ostream& operator<<(std::ostream& out, const std::vector& v) { + const auto* sep = ""; + for (const auto& value : v) { + out << sep << value; + sep = ", "; + } + return out; +} + int main(int argc, char* argv[]) { - std::cout << "Hello, example!" << std::endl; - return 0; + + std::cout << grit::util::linspace(1, 2, 2, true) << std::endl; + std::cout << grit::util::arange(1, 2, 0.5) << std::endl; } From 3e36f63e574cf4741d4af981e821bba5dea22eae Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 21 Mar 2023 16:31:53 +0000 Subject: [PATCH 098/737] util --- src/griditer/CMakeLists.txt | 1 + src/griditer/util.h | 4 + src/griditer/util/gaussian_latitudes.cc | 99 +++++++++++++++++++++++++ tests/util.cc | 2 +- 4 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 src/griditer/util/gaussian_latitudes.cc diff --git a/src/griditer/CMakeLists.txt b/src/griditer/CMakeLists.txt index 80b99b373..4ed65da34 100644 --- a/src/griditer/CMakeLists.txt +++ b/src/griditer/CMakeLists.txt @@ -3,6 +3,7 @@ configure_file(griditer.h.in griditer.h) add_library(grit SHARED util.h util/arange.cc + util/gaussian_latitudes.cc util/linspace.cc) target_include_directories(grit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") diff --git a/src/griditer/util.h b/src/griditer/util.h index 4a32d0339..71f1792fb 100644 --- a/src/griditer/util.h +++ b/src/griditer/util.h @@ -12,6 +12,7 @@ #pragma once +#include #include @@ -24,4 +25,7 @@ std::vector arange(double start, double stop, double step); std::vector linspace(double start, double stop, size_t num, bool endpoint); +std::vector gaussian_latitudes(size_t N, bool increasing); + + } // namespace grit::util diff --git a/src/griditer/util/gaussian_latitudes.cc b/src/griditer/util/gaussian_latitudes.cc new file mode 100644 index 000000000..280237722 --- /dev/null +++ b/src/griditer/util/gaussian_latitudes.cc @@ -0,0 +1,99 @@ +/* + * (C) Copyright 1996- 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 "griditer/util.h" + +#include +#include +#include +#include + + +namespace grit::util { + + +std::vector gaussian_latitudes(size_t N, bool increasing) { + std::vector lats(2 * N); + + + // Fourier coefficients of series expansion for the ordinary Legendre polynomials + std::vector zzfn(N + 1); + { + // Belousov, Swarztrauber use zfn(0)=std::sqrt(2.) + // IFS normalisation chosen to be 0.5*Integral(Pnm**2) = 1 + std::vector zfn(2 * N + 1, 2.); + + for (size_t i = 1; i <= 2 * N; ++i) { + for (size_t j = 1; j <= i; ++j) { + zfn[i] *= std::sqrt(1. - 0.25 / (static_cast(j * j))); + } + + for (size_t j = 2; j <= i - (i % 2); j += 2) { + zfn[i - j] = zfn[i - j + 2] * static_cast((j - 1) * (2 * i - j + 2)) / + static_cast(j * (2 * i - j + 1)); + } + } + + for (size_t i = 0; i <= N; ++i) { + zzfn[i] = zfn[i * 2]; + } + } + + + // Newton loop (per latitude) to find 0 of Legendre polynomial of degree N (GAWL) + constexpr size_t Nmax = 20; + constexpr auto eps = std::numeric_limits::epsilon() * 1000.; + + for (size_t i = 0; i < N; ++i) { + // First guess for colatitude [rad] + double z = static_cast(4 * (i + 1) - 1) * M_PI / static_cast(4 * 2 * N + 2); + double x = (z + 1. / (std::tan(z) * static_cast(8 * (2 * N) * (2 * N)))); + + auto converged = false; + + for (size_t n = 0; n < Nmax; ++n) { + auto f = 0.5 * zzfn[0]; // normalised ordinary Legendre polynomial == \overbar{P_n}^0 + auto fp = 0.; // normalised derivative == d/d\theta(\overbar{P_n}^0) + + for (size_t i = 1; i <= N; ++i) { + const auto i2 = static_cast(i * 2); + f += zzfn[i] * std::cos(i2 * x); + fp -= zzfn[i] * std::sin(i2 * x) * i2; + } + + auto dx = -f / fp; + x += dx; + + if (converged) { + break; + } + + converged = std::abs(dx) <= eps; + } + + if (!converged) { + throw std::runtime_error("Could not calculate latitude within accuracy/iterations: " + std::to_string(eps) + + "/" + std::to_string(Nmax)); + } + + // Convert colatitude [rad] to latitude [degree], symmetry + const auto j = 2 * N - 1 - i; + lats[i] = (increasing ? (x - M_PI_2) : (M_PI_2 - x)) * 180. * M_1_PI; + lats[j] = -lats[i]; + } + + + return lats; +} + + +} // namespace grit::util diff --git a/tests/util.cc b/tests/util.cc index f90917928..926b93621 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -27,7 +27,7 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) { int main(int argc, char* argv[]) { - std::cout << grit::util::linspace(1, 2, 2, true) << std::endl; std::cout << grit::util::arange(1, 2, 0.5) << std::endl; + std::cout << grit::util::gaussian_latitudes(64, false) << std::endl; } From 503f2c6889e44d67a767d2fd9238afd89d86c41b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 23 Mar 2023 13:58:12 +0000 Subject: [PATCH 099/737] grib --- CMakeLists.txt | 9 ++++++ src/griditer/util.cc | 16 ++++++++++ src/tools/CMakeLists.txt | 5 +++ src/tools/griditer-grib.cc | 51 ++++++++++++++++++++++++++++++ tests/reduced_gg.grib2 | Bin 0 -> 6420 bytes tests/regular_ll.grib1 | Bin 0 -> 108 bytes tests/util.cc | 62 +++++++++++++++++++++++++++++++++++-- 7 files changed, 140 insertions(+), 3 deletions(-) create mode 100644 src/griditer/util.cc create mode 100644 src/tools/griditer-grib.cc create mode 100644 tests/reduced_gg.grib2 create mode 100644 tests/regular_ll.grib1 diff --git a/CMakeLists.txt b/CMakeLists.txt index c26b1c97a..2ee55dfc3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,15 @@ if(APPLE) endif() +# dependencies (all optional) +find_package(eccodes 2.29) + +option(REQUIRE_ECCODES "Require ecCodes") +if(REQUIRE_ECCODES AND NOT eccodes_FOUND) + message(FATAL_ERROR "eccodes_FOUND=${eccodes_FOUND}") +endif() + + # library/resources add_subdirectory(src) add_subdirectory(etc) diff --git a/src/griditer/util.cc b/src/griditer/util.cc new file mode 100644 index 000000000..4e509b7e3 --- /dev/null +++ b/src/griditer/util.cc @@ -0,0 +1,16 @@ +/* + * (C) Copyright 1996- 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 "griditer/util.h" + + +namespace grit::util {} // namespace grit::util diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index b6b148ab2..a1e59d0f9 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -5,3 +5,8 @@ foreach(name target_link_libraries(${name} grit) endforeach() +if(TARGET eccodes) + add_executable(griditer-grib griditer-grib.cc) + target_link_libraries(griditer-grib grit eccodes) +endif() + diff --git a/src/tools/griditer-grib.cc b/src/tools/griditer-grib.cc new file mode 100644 index 000000000..825f16ba9 --- /dev/null +++ b/src/tools/griditer-grib.cc @@ -0,0 +1,51 @@ +/* + * (C) Copyright 1996- 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 "eccodes.h" + +#include +#include +#include + +#include "griditer/griditer.h" + + +int main(int argc, const char* argv[]) { + for (int i = 1; i < argc; ++i) { + auto* in = std::fopen(argv[1], "rb"); + assert(in != nullptr && "unable to open file"); + + int err = 0; + for (codes_handle* h = nullptr; nullptr != (h = codes_handle_new_from_file(nullptr, in, PRODUCT_GRIB, &err));) { + assert(CODES_SUCCESS == err); + + // long bitmapPresent = 0; + // assert(CODES_SUCCESS == codes_get_long(h, "bitmapPresent", &bitmapPresent)); + + auto* it = codes_grib_iterator_new(h, 0, &err); + assert(CODES_SUCCESS == err); + + int n = 0; + for (double lat = 0, lon = 0, value = 0; codes_grib_iterator_next(it, &lat, &lon, &value) > 0; ++n) { + std::cout << "- " << n << " - lat=" << lat << " lon=" << lon << " value=" << value << "\n"; + } + std::cout.flush(); + + codes_grib_iterator_delete(it); + codes_handle_delete(h); + } + + std::fclose(in); + } + + return 0; +} diff --git a/tests/reduced_gg.grib2 b/tests/reduced_gg.grib2 new file mode 100644 index 0000000000000000000000000000000000000000..74275e4fbc65f71ac771d1e7d06ef2e7e74a547f GIT binary patch literal 6420 zcmds+|CeKDUB{n$?{mL@zc(#Ii7-fj@fbLvq;1+}C+Y6Z?T7&bM2r$4&>&Mzgjix5 zAuItR1RL#0Lp!B$cf`OMA;qCY88nrtC(1~3?0^A=5^;c_11G>NrZ7loeQ)tM{{yq< z%=aYsKF{ZQe|hcAulSX-Pd-Ul^3>z$0erfGA+IMSNEq=yxhu7w|AN>oVepToOe7L{ z5g~y!j*w!Xunbudp8UTLLX@YTdHFYdzM6jOn?J-CS5%f>eEElj@c3DPEa9D&NrTiIF%-5|6BrG|7-G$&oxMkRn+pB~m68QYAG~Ck@ghEwVw{WRrBr7U`00(jz;h zPj<xlzc+47;W-?5c$uW7Rz!aHvro@z)3R7ijOr2>kO{T?cFl}a&=`dSNm)T}|%ns9M zc9{XQ#|)W$X2cvYW9E>VFh|UkIc8?e2{UI-nFWhwWF=N(EjGX|u|am34Y4b1n2oSe zHpa%;B>fL0_t_D9z>e8NcETR9Q}&phu_x@DJ!Kah;V36@8fS3ATn=G-Z_poCH?QH@$OK$mEcF4GWQpAHTA)R`PD`{*E3`^$v`!neNn3P-w&^DA&@I}f+q6e_XrJ!V z0o|iRx=%;+fR5=QozNpXrN?wePw1SU(gja=%1gY)TYP|D;)DD$AL3W|FdyNge2kCt zN#5hv_%xs4vwV)v^98=huk$6o%vbm-U*qe1gKzRJeuHoGn|z1g;=BAd-{W`qKEKNk z_&t8e@AD)6fFJXR{DeQ^r~ENL<4^cGf66ZeB2YmRG{F)A!jcdamW7b8B7}vA5EWuV zTu2I@uqLF1jF1&_LS85cMPXei31y)oRE3&Q7aBrSXbBraTi6sj!j{k#wuPRsBlLw` zVIb@YLt$SS2?xShI20zrkuVjGg_&?7%!N~7Arg^_lBkK67!a4lptvlC#1%0tM#QKX z6XRl1^u#qWEoQ{5m=p72K`e^vVo5BE6|pMT#JboJn_^4c5ZmIW*b%qHuDC7s#2v9O z?ur9(PaKN-;z&FY$Ks(l5s$>Fcr4Du6LBt{iVKNIRFWi3vZR2tBn72qDI~2(VJRX- zrI-|#l9DH_Nogq~Wu=^ymkLr*T9-;vS*l1?sV3E>hSZc=(uUNQHl>cVC3U53sVD77 zeQ8%3NPE&y+LuPsfi#v5rHOPTO{HULCY?xg=~PMuF5sJE;r<++>$rsw!A5K)RL1kG9DJx1? zi6~Jero@$`;wfuNTFEF`C8y+-f>Ko0m6B3cDoRzUDRrfxG?kXJp|q7vrK4;qU1eM8 zDLYDE*;NM0o-$PSm639wjFm%Wq8uqxZ!WWh(C_ ziWb%)T2zZ^aV@EN+M1TuGFn#4X?d-n6}5G(q?NUbR@G`+U2AAft)*>fZEaKQXj@uW z+tzy8j@H+9wSl&$4Yhr3q#bBu?NFO&N7__7)@Is?HrGzIg-&#;OS-08dO%;&gZi=_ z(pU7b9?_$EOpohH-P70fw4TwkdQQ*l1-+=R>m|LcSM;i0)9ZReZ|W_5LvQPwdPm>V zyZW}?(|7c~zN-)PJ$m&U@AM1zuL_gA}`msLKPxQHdsxJ&;P(v~_!!iQKk`XkP zjgYZogpG(1HDX5GNE)88W~7abku`Eg-Y6JFW8EkjWuszLjhaz68b;G-85>61*fcuE zmeDn~jh?Y%^o?C(VC)$~W8WAV2gcYqG$zK8F*S~jnQ>ywjZoXW0okD^A#nI8i6&#GRz$IcrYZ$v9aj=j5G&Q*_pyl2djnPSvS7b*JGpotCrV zw4F_-<7_!yXWQvHJ5Jx(bq3C!Gj#Tyk#pdTokM5h963|x*qJ#e&fGb57A|qAE4i9$ zxdC^{4Z6#2$X#*6Zp4kcF*oieUC&)}({9Gix;Z!R7Tlt{?v~uLTXCyy&8@o)x9PUr z4Y%!Xx*d1R?Yi4;&)sqR?yfs<_uQeo?~dF9ckCXz6ZgoSy2tL!J#pvmsk;b}01Ze1 zEr9LEM+x5%cY)u`@fS1v0 z)o^7MTww`UTErFSaphUuK^k}B;f~_CvncK`j5`hCj)S=K09HW5N>GD>TDO zO|fDVtlStYIKoN}v7!U4Y#%G!!%BCt;vKAf8#~a#PBgG1HSA0UJ5<6>6|rM^>|7Q* zn8r?e*wHw4Hi{h%W2Zyd@gR0SfC0+TVvgv>B0Q%uYRlQYHyjW9_=Ow<6A z)yIVOFlk*(TnCfa#ss!7i49C-4U<{HgqAR=MNDiSlbgi^r!mPMCOVGEj$*>YnDh`P zK8VQ=-~?zm3DhRm0w-gR6Eed|nc~DuaB{{tK_i@`Ax_i)C##PW*278b;>2}u^4d6o zEu6##PGk)yvw{;^!bvUS#O85wvpB(NoMaCtI*yYa#R(7Nq=#_ggE;vCD1ZhfpcXL~ zP=+}aVg{v{LNO*#jxiKu1SJ_lQ3gO@<>8Ru}w8Juzo$DF`9$8gXQoOB3B9l%-paM&K4whPDYz#nRFF_gNGe4nmOPS676~Se zB;z5`#F1>GNH}36oe&aF5XmQi1f(GeQI#kQB%?VJ(hNyyio`TQavCE+jgX{NbNbK_Y6|}8q$0csXm5uA3@4rLE2wN>R&?ox6lG4v;iV6&quEB$aKmW2AvE3~nr{FN zSVI%0JfRCT<2f4g3{828#ymlD9-~2z(4>cG)B`l@J{oopO}mT6-9hti(+%39O|`XDSlkd`ipO9$ko4Fb~wiD`hy)Ieq`AT%YAnj(lz9^@tqf|CZx@j!Iq zAUjbIo-jyH2*f7{@)H07(m;YJ;MxLYXbwU&11Xw<7)?Nq#vn)|kfb4q(g0+s55m*~ zY3hPFbwHllAW$uks0N5s4P>eULRA8(DuP($L9VhOSZR4J3>*ge*YD<{)GnwJFCi-GP%K>1cc`<6ldmO%dqy^S*XgbR4` zK2Sk?Cgj%3ADGLK@G>SOcryRfq<`l#lON37m3-{{=Wlw(f8Bl4Z~oO6ZfgJg({B3Q zH}}qRmtJ%Bmm9gWum0j2&fclK|Lg;w|K!;(k0*n{JOT4Og?v_*i+K3euR?ti(r z^{J-!$={rjJ{?{_}^Z~mYCIO|{d*5CRUs~7x>{T2V>-DUrx`(gjWiv_>) z{jh((r~CK4=(+wq{fdA0=V$)LTi@ij9(c@ezVj3QdoC6H^Ggx`tq<<|>;HV<|Mu^v z{g*!)@Kcv0|N6)C{tF(D`M)Uj{VRRTR~|k{J^2ih`p#{8sqtSFQhUQ>>Va=rsg6-d z-TA8|bw{F*`Ym@al?WtL&$~LAGH*HZ9*+?3(YGYM2Y#>a{mC)$-ndowuKR4=GblMX zzJ{E;_Y67rk{UTXkCL-*UnV#G%??SH>+I$E`2YNPamdbH`^~TZW>#w{1!OG8WaIg7|8*aVf!VRCyT)dHe|2uEIarNFC-~G&gx^XA=x*Naq*{kAD zd+2rXo8GL&Z+j>izsG9FKmF`?$0y(X&>8NLE6zOQ;SZd-_Kw+^ta<57VN+2)!^vS)$orVTU~u_VKq}AtG9gohSjQZ zu=?K5byq*|^x5hKa$)sjw?DD^>EB&i9X^s;{o?r_t{znmR=4~eFpGZ9WC1T?FU(Y07xOy=WeM2O1!%MGBB!2kuMCuhkOT47?ro^wEc{uUP z&l!oFw3*0rpGmy-GvmZ9F9;=m=e6HR+?xG(qGa5jc=KHkCCZa<;*1#_~FMA=XYy~cNTXN^`|D~3jXqcT>Sh|f6o7Y OAqbbHh8M5H<9`6U`uP_C literal 0 HcmV?d00001 diff --git a/tests/regular_ll.grib1 b/tests/regular_ll.grib1 new file mode 100644 index 0000000000000000000000000000000000000000..ded2691ba3885b190d06b69d6c56fcfc57e0b9a8 GIT binary patch literal 108 zcmZ<{@^oTg$YEq)Flk7d`M+T~kR{G6#=`)lK|mBj!AV9&CKg5m0|P^_hyufZ2F47A gXvX*nKz>7G`~=pj2<8{;7oh5SI2t%1OmiRr081wiSpWb4 literal 0 HcmV?d00001 diff --git a/tests/util.cc b/tests/util.cc index 926b93621..d053809c7 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -11,6 +11,7 @@ #include +#include #include "griditer/util.h" @@ -26,8 +27,63 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) { } +template +struct iterator_t { + X& cnt; + size_t pos; + + bool operator!=(const iterator_t& other) const { return &cnt != &other.cnt || pos != other.pos; } + + iterator_t& operator++() { + pos++; + return *this; + } + + iterator_t operator++(int) { + auto old = *this; + operator++(); + return old; + } + + typename X::value_type& operator*() { return cnt.at(pos); } + + const typename X::value_type& operator*() const { return cnt.at(pos); } +}; + + +class iterable_t : public std::vector { + + using iterator = iterator_t; + using const_iterator = iterator_t; + +public: + using vector::vector; + + iterator begin() { return {*this, 0}; } + + iterator end() { return {*this, this->size()}; } + + const_iterator cbegin() const { return {*this, 0}; } + + const_iterator cend() const { return {*this, this->size()}; } + + const_iterator begin() const { return cbegin(); } + + const_iterator end() const { return cend(); } +}; + + int main(int argc, char* argv[]) { - std::cout << grit::util::linspace(1, 2, 2, true) << std::endl; - std::cout << grit::util::arange(1, 2, 0.5) << std::endl; - std::cout << grit::util::gaussian_latitudes(64, false) << std::endl; + // std::cout << grit::util::linspace(1, 2, 2, true) << std::endl; + // std::cout << grit::util::arange(1, 2, 0.5) << std::endl; + // std::cout << grit::util::gaussian_latitudes(64, false) << std::endl; + + + iterable_t it{1, 2, 3, 4}; + + for (const auto& v : it) { + std::cout << v << std::endl; + } + + std::cout << std::accumulate(it.begin(), it.end(), 0) << std::endl; } From cd38192f4bbb94a678c31abce93facaeb3a1e3b7 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 Mar 2023 08:14:17 +0000 Subject: [PATCH 100/737] grib --- src/griditer/CMakeLists.txt | 1 + src/griditer/util.cc | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/griditer/CMakeLists.txt b/src/griditer/CMakeLists.txt index 4ed65da34..1ec1292d8 100644 --- a/src/griditer/CMakeLists.txt +++ b/src/griditer/CMakeLists.txt @@ -1,6 +1,7 @@ configure_file(griditer.h.in griditer.h) add_library(grit SHARED + util.cc util.h util/arange.cc util/gaussian_latitudes.cc diff --git a/src/griditer/util.cc b/src/griditer/util.cc index 4e509b7e3..ce7f58acc 100644 --- a/src/griditer/util.cc +++ b/src/griditer/util.cc @@ -13,4 +13,19 @@ #include "griditer/util.h" -namespace grit::util {} // namespace grit::util +namespace grit::util { + + +struct regular_ll_args { + size_t Ni; + size_t Nj; + double iStart; + double iStop; + double iStep; + double jStart; + double jStop; + double jStep; +}; + + +} // namespace grit::util From 77b8e2e27c4052eeef4afb2741e2f28c4d897006 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 Mar 2023 11:59:56 +0000 Subject: [PATCH 101/737] grib --- CMakeLists.txt | 2 +- README.md | 2 +- etc/CMakeLists.txt | 2 +- etc/{griditer => grit}/CMakeLists.txt | 0 share/CMakeLists.txt | 2 +- share/{griditer => grit}/CMakeLists.txt | 0 src/CMakeLists.txt | 2 +- src/griditer/example.cc | 17 -- src/griditer/example.h | 0 src/griditer/griditer.h.in | 4 - src/griditer/util.cc | 31 --- src/{griditer => grit}/CMakeLists.txt | 2 +- src/grit/grit.h.in | 4 + src/grit/util.cc | 183 ++++++++++++++++++ src/{griditer => grit}/util.h | 0 src/{griditer => grit}/util/arange.cc | 2 +- .../util/gaussian_latitudes.cc | 2 +- src/{griditer => grit}/util/linspace.cc | 2 +- src/tools/CMakeLists.txt | 6 +- src/tools/{griditer-grib.cc => grit-grib.cc} | 2 +- .../{griditer-version.cc => grit-version.cc} | 4 +- tests/util.cc | 2 +- 22 files changed, 203 insertions(+), 68 deletions(-) rename etc/{griditer => grit}/CMakeLists.txt (100%) rename share/{griditer => grit}/CMakeLists.txt (100%) delete mode 100644 src/griditer/example.cc delete mode 100644 src/griditer/example.h delete mode 100644 src/griditer/griditer.h.in delete mode 100644 src/griditer/util.cc rename src/{griditer => grit}/CMakeLists.txt (82%) create mode 100644 src/grit/grit.h.in create mode 100644 src/grit/util.cc rename src/{griditer => grit}/util.h (100%) rename src/{griditer => grit}/util/arange.cc (97%) rename src/{griditer => grit}/util/gaussian_latitudes.cc (99%) rename src/{griditer => grit}/util/linspace.cc (97%) rename src/tools/{griditer-grib.cc => grit-grib.cc} (97%) rename src/tools/{griditer-version.cc => grit-version.cc} (76%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ee55dfc3..663b88afb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ cmake_minimum_required(VERSION 3.14 FATAL_ERROR) -project(griditer VERSION 0.0.0 LANGUAGES CXX) +project(grit VERSION 0.0.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) diff --git a/README.md b/README.md index 5874a75ff..9b83875b5 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# griditer +# grit Geospatial Grid definitions and iterators library diff --git a/etc/CMakeLists.txt b/etc/CMakeLists.txt index 988ef9af4..4827d7957 100644 --- a/etc/CMakeLists.txt +++ b/etc/CMakeLists.txt @@ -1,2 +1,2 @@ -add_subdirectory(griditer) +add_subdirectory(grit) diff --git a/etc/griditer/CMakeLists.txt b/etc/grit/CMakeLists.txt similarity index 100% rename from etc/griditer/CMakeLists.txt rename to etc/grit/CMakeLists.txt diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt index 988ef9af4..4827d7957 100644 --- a/share/CMakeLists.txt +++ b/share/CMakeLists.txt @@ -1,2 +1,2 @@ -add_subdirectory(griditer) +add_subdirectory(grit) diff --git a/share/griditer/CMakeLists.txt b/share/grit/CMakeLists.txt similarity index 100% rename from share/griditer/CMakeLists.txt rename to share/grit/CMakeLists.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a4935927..bd1c6a472 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ include_directories(BEFORE . ${CMAKE_CURRENT_BINARY_DIR}) -add_subdirectory(griditer) +add_subdirectory(grit) add_subdirectory(tools) diff --git a/src/griditer/example.cc b/src/griditer/example.cc deleted file mode 100644 index c987f7c7b..000000000 --- a/src/griditer/example.cc +++ /dev/null @@ -1,17 +0,0 @@ -/* - * (C) Copyright 1996- 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 "griditer/example.h" -#include "griditer/griditer.h" - - -static const int ANSWER = 42; diff --git a/src/griditer/example.h b/src/griditer/example.h deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/griditer/griditer.h.in b/src/griditer/griditer.h.in deleted file mode 100644 index e7daf3544..000000000 --- a/src/griditer/griditer.h.in +++ /dev/null @@ -1,4 +0,0 @@ - -#define griditer_VERSION_MAJOR @griditer_VERSION_MAJOR@ -#define griditer_VERSION_MINOR @griditer_VERSION_MINOR@ -#define griditer_VERSION_PATCH @griditer_VERSION_PATCH@ diff --git a/src/griditer/util.cc b/src/griditer/util.cc deleted file mode 100644 index ce7f58acc..000000000 --- a/src/griditer/util.cc +++ /dev/null @@ -1,31 +0,0 @@ -/* - * (C) Copyright 1996- 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 "griditer/util.h" - - -namespace grit::util { - - -struct regular_ll_args { - size_t Ni; - size_t Nj; - double iStart; - double iStop; - double iStep; - double jStart; - double jStop; - double jStep; -}; - - -} // namespace grit::util diff --git a/src/griditer/CMakeLists.txt b/src/grit/CMakeLists.txt similarity index 82% rename from src/griditer/CMakeLists.txt rename to src/grit/CMakeLists.txt index 1ec1292d8..29c36128f 100644 --- a/src/griditer/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -1,4 +1,4 @@ -configure_file(griditer.h.in griditer.h) +configure_file(grit.h.in grit.h) add_library(grit SHARED util.cc diff --git a/src/grit/grit.h.in b/src/grit/grit.h.in new file mode 100644 index 000000000..31da02161 --- /dev/null +++ b/src/grit/grit.h.in @@ -0,0 +1,4 @@ + +#define grit_VERSION_MAJOR @grit_VERSION_MAJOR@ +#define grit_VERSION_MINOR @grit_VERSION_MINOR@ +#define grit_VERSION_PATCH @grit_VERSION_PATCH@ diff --git a/src/grit/util.cc b/src/grit/util.cc new file mode 100644 index 000000000..cd8823c87 --- /dev/null +++ b/src/grit/util.cc @@ -0,0 +1,183 @@ +/* + * (C) Copyright 1996- 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 "grit/util.h" + + +namespace grit::util { + + +struct regular_ll_args { + size_t Ni; + size_t Nj; + double i_start; + double i_stop; + double i_step; + double j_start; + double j_stop; + double j_step; +}; + + +} // namespace grit::util + + +#if 0 +gridType: gridDefinitionTemplateNumber + - PLPresent: false + - regular_ll: + - rotated_ll: + - mercator: + double DiInMetres + double DjInMetres + double LaDInDegrees + double latitudeOfFirstPointInDegrees + double latitudeOfLastPointInDegrees + double longitudeOfFirstPointInDegrees + double longitudeOfLastPointInDegrees + double projectionOrientationInDegrees + size_t Ni + size_t Nj + - polar_stereographic: + double DiInMetres + double DjInMetres + double LaDInDegrees + double latitudeOfFirstPointInDegrees + double longitudeOfFirstPointInDegrees + double projectionOrientationInDegrees + flags projectionCentreFlag + size_t Ni + size_t Nj + - lambert: + double DiInMetres + double DjInMetres + double LaDInDegrees + double Latin1InDegrees + double Latin2InDegrees + double LoVInDegrees + double latitudeOfFirstPointInDegrees + double latitudeOfSouthernPoleInDegrees + double longitudeOfFirstPointInDegrees + double longitudeOfSouthernPoleInDegrees + flags projectionCentreFlag + size_t Ni + size_t Nj + - albers: + double DiInMetres + double DjInMetres + double LaDInDegrees + double Latin1InDegrees + double Latin2InDegrees + double LoVInDegrees + double latitudeOfFirstPointInDegrees + double latitudeOfSouthernPoleInDegrees + double longitudeOfFirstPointInDegrees + double longitudeOfSouthernPoleInDegrees + flags projectionCentreFlag + size_t Ni + size_t Nj + - regular_gg + - rotated_gg + - space_view: + double DiInMetres + double DjInMetres + double altitudeFromEarthCentreInMetres + double latitudeOfSubSatellitePointInDegrees + double longitudeOfSubSatellitePointInDegrees + double projectionOrientationInDegrees + double xOriginOfSectorImageInMetres + double xSubSatellitePointInMetres + double yOriginOfSectorImageInMetres + double ySubSatellitePointInMetres + size_t Ni + size_t Nj + - unstructured_grid (grib2/localConcepts/[centre:s]/unstructuredGrid*): + string unstructuredGridSubtype = undefined/T/U/V/W/F (numberOfGridInReference) + string unstructuredGridType = undefined/ORCA2/ORCA1/ORCA025/ORCA12/eORCA1/eORCA025/eORCA12 (numberOfGridInReference) + string uuidOfHGrid + - equatorial_azimuthal_equidistant: + double DiInMetres + double DjInMetres + double latitudeOfTangencyPointInDegrees + double longitudeOfTangencyPointInDegrees + flags projectionCentreFlag + - irregular_latlon + - lambert_azimuthal_equal_area: + double DiInMetres + double DjInMetres + double centralLongitudeInDegrees + double latitudeOfFirstPointInDegrees + double longitudeOfFirstPointInDegrees + double standardParallelInDegrees + - PLPresent: true + - reduced_ll + - reduced_gg + - reduced_rotated_gg + +Projection, rotation, shape (grib2/template.3.(rotation|shape_of_the_earth).def) + - projSourceString, projTargetString, projString=projTargetString + + double latitudeOfSouthernPoleInDegrees + double longitudeOfSouthernPoleInDegrees + double angleOfRotationInDegrees + + bool is_oblate + double majorAxisInMetres + double minorAxisInMetres + double radiusInMetres + +Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) + - 1 0 Points of first row or column scan in the +i (+x) direction + - 1 1 Points of first row or column scan in the -i (-x) direction + - 2 0 Points of first row or column scan in the -j (-y) direction + - 2 1 Points of first row or column scan in the +j (+y) direction + - 3 0 Adjacent points in i (x) direction are consecutive + - 3 1 Adjacent points in j (y) direction is consecutive + - 4 0 All rows scan in the same direction + - 4 1 Adjacent rows scan in the opposite direction + - 5 0 Points within odd rows are not offset in i (x) direction + - 5 1 Points within odd rows are offset by Di/2 in i (x) direction + - 6 0 Points within even rows are not offset in i (x) direction + - 6 1 Points within even rows are offset by Di/2 in i (x) direction + - 7 0 Points are not offset in j (y) direction + - 7 1 Points are offset by Dj/2 in j (y) direction + - 8 0 Rows have Ni grid points and columns have Nj grid points + - 8 1 Rows have Ni grid points if points are not offset in i direction + Rows have Ni-1 grid points if points are offset by Di/2 in i direction + Columns have Nj grid points if points are not offset in j direction + Columns have Nj-1 grid points if points are offset by Dj/2 in j direction + + bool iScansPositively + bool jScansPositively + bool jPointsAreConsecutive + bool alternativeRowScanning + +Projection centre (grib2/tables/30/3.5.table) + 1 0 North Pole is on the projection plane + 1 1 South Pole is on the projection plane + 2 0 Only one projection centre is used + 2 1 Projection is bipolar and symmetric + +(grib2/template.3.(gaussian|grid|latlon).def) + double latitudeOfFirstPointInDegrees + double latitudeOfLastPointInDegrees + double longitudeOfFirstPointInDegrees + double longitudeOfLastPointInDegrees + double DiInDegrees + double DjInDegrees + size_t Ni + size_t Nj + size_t numberOfParallelsBetweenAPoleAndTheEquator + size_t basicAngleOfTheInitialProductionDomain + size_t subdivisionsOfBasicAngle +#endif + diff --git a/src/griditer/util.h b/src/grit/util.h similarity index 100% rename from src/griditer/util.h rename to src/grit/util.h diff --git a/src/griditer/util/arange.cc b/src/grit/util/arange.cc similarity index 97% rename from src/griditer/util/arange.cc rename to src/grit/util/arange.cc index 45b3680ca..870a824c2 100644 --- a/src/griditer/util/arange.cc +++ b/src/grit/util/arange.cc @@ -14,7 +14,7 @@ #include #include -#include "griditer/util.h" +#include "grit/util.h" namespace grit::util { diff --git a/src/griditer/util/gaussian_latitudes.cc b/src/grit/util/gaussian_latitudes.cc similarity index 99% rename from src/griditer/util/gaussian_latitudes.cc rename to src/grit/util/gaussian_latitudes.cc index 280237722..b3340fded 100644 --- a/src/griditer/util/gaussian_latitudes.cc +++ b/src/grit/util/gaussian_latitudes.cc @@ -10,7 +10,7 @@ */ -#include "griditer/util.h" +#include "grit/util.h" #include #include diff --git a/src/griditer/util/linspace.cc b/src/grit/util/linspace.cc similarity index 97% rename from src/griditer/util/linspace.cc rename to src/grit/util/linspace.cc index 5561ed51c..acf2bc8c6 100644 --- a/src/griditer/util/linspace.cc +++ b/src/grit/util/linspace.cc @@ -12,7 +12,7 @@ #include -#include "griditer/util.h" +#include "grit/util.h" namespace grit::util { diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index a1e59d0f9..f67b64467 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -1,12 +1,12 @@ foreach(name - griditer-version) + grit-version) add_executable(${name} ${name}.cc) target_link_libraries(${name} grit) endforeach() if(TARGET eccodes) - add_executable(griditer-grib griditer-grib.cc) - target_link_libraries(griditer-grib grit eccodes) + add_executable(grit-grib grit-grib.cc) + target_link_libraries(grit-grib grit eccodes) endif() diff --git a/src/tools/griditer-grib.cc b/src/tools/grit-grib.cc similarity index 97% rename from src/tools/griditer-grib.cc rename to src/tools/grit-grib.cc index 825f16ba9..4c406c12d 100644 --- a/src/tools/griditer-grib.cc +++ b/src/tools/grit-grib.cc @@ -16,7 +16,7 @@ #include #include -#include "griditer/griditer.h" +#include "grit/grit.h" int main(int argc, const char* argv[]) { diff --git a/src/tools/griditer-version.cc b/src/tools/grit-version.cc similarity index 76% rename from src/tools/griditer-version.cc rename to src/tools/grit-version.cc index d8564adee..39e9afb5b 100644 --- a/src/tools/griditer-version.cc +++ b/src/tools/grit-version.cc @@ -12,10 +12,10 @@ #include -#include "griditer/griditer.h" +#include "grit/grit.h" int main(int /*argc*/, const char* /*argv*/[]) { - std::cout << griditer_VERSION_MAJOR << '.' << griditer_VERSION_MINOR << '.' << griditer_VERSION_PATCH << std::endl; + std::cout << grit_VERSION_MAJOR << '.' << grit_VERSION_MINOR << '.' << grit_VERSION_PATCH << std::endl; return 0; } diff --git a/tests/util.cc b/tests/util.cc index d053809c7..7964d1aa4 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -13,7 +13,7 @@ #include #include -#include "griditer/util.h" +#include "grit/util.h" template From 9036d211ec9e4f6afdd4a9b25115fdb789930f99 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 Mar 2023 16:40:48 +0000 Subject: [PATCH 102/737] grib --- src/grit/util.cc | 73 ++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/src/grit/util.cc b/src/grit/util.cc index cd8823c87..87e5a9e0f 100644 --- a/src/grit/util.cc +++ b/src/grit/util.cc @@ -17,8 +17,8 @@ namespace grit::util { struct regular_ll_args { - size_t Ni; - size_t Nj; + size_t n_i; + size_t n_j; double i_start; double i_stop; double i_step; @@ -34,19 +34,21 @@ struct regular_ll_args { #if 0 gridType: gridDefinitionTemplateNumber - PLPresent: false - - regular_ll: - - rotated_ll: + - regular_ll + - rotated_ll + - regular_gg + - rotated_gg + + - projections: - mercator: double DiInMetres double DjInMetres double LaDInDegrees double latitudeOfFirstPointInDegrees - double latitudeOfLastPointInDegrees double longitudeOfFirstPointInDegrees - double longitudeOfLastPointInDegrees double projectionOrientationInDegrees - size_t Ni - size_t Nj + size_t n_i + size_t n_j - polar_stereographic: double DiInMetres double DjInMetres @@ -55,8 +57,8 @@ gridType: gridDefinitionTemplateNumber double longitudeOfFirstPointInDegrees double projectionOrientationInDegrees flags projectionCentreFlag - size_t Ni - size_t Nj + size_t n_i + size_t n_j - lambert: double DiInMetres double DjInMetres @@ -69,8 +71,8 @@ gridType: gridDefinitionTemplateNumber double longitudeOfFirstPointInDegrees double longitudeOfSouthernPoleInDegrees flags projectionCentreFlag - size_t Ni - size_t Nj + size_t n_i + size_t n_j - albers: double DiInMetres double DjInMetres @@ -83,10 +85,8 @@ gridType: gridDefinitionTemplateNumber double longitudeOfFirstPointInDegrees double longitudeOfSouthernPoleInDegrees flags projectionCentreFlag - size_t Ni - size_t Nj - - regular_gg - - rotated_gg + size_t n_i + size_t n_j - space_view: double DiInMetres double DjInMetres @@ -98,19 +98,8 @@ gridType: gridDefinitionTemplateNumber double xSubSatellitePointInMetres double yOriginOfSectorImageInMetres double ySubSatellitePointInMetres - size_t Ni - size_t Nj - - unstructured_grid (grib2/localConcepts/[centre:s]/unstructuredGrid*): - string unstructuredGridSubtype = undefined/T/U/V/W/F (numberOfGridInReference) - string unstructuredGridType = undefined/ORCA2/ORCA1/ORCA025/ORCA12/eORCA1/eORCA025/eORCA12 (numberOfGridInReference) - string uuidOfHGrid - - equatorial_azimuthal_equidistant: - double DiInMetres - double DjInMetres - double latitudeOfTangencyPointInDegrees - double longitudeOfTangencyPointInDegrees - flags projectionCentreFlag - - irregular_latlon + size_t n_i + size_t n_j - lambert_azimuthal_equal_area: double DiInMetres double DjInMetres @@ -118,6 +107,18 @@ gridType: gridDefinitionTemplateNumber double latitudeOfFirstPointInDegrees double longitudeOfFirstPointInDegrees double standardParallelInDegrees + - equatorial_azimuthal_equidistant: + double DiInMetres + double DjInMetres + double latitudeOfTangencyPointInDegrees + double longitudeOfTangencyPointInDegrees + flags projectionCentreFlag + + - unstructured_grid (grib2/localConcepts/[centre:s]/unstructuredGrid*): + string unstructuredGridSubtype = undefined/T/U/V/W/F (numberOfGridInReference) + string unstructuredGridType = undefined/ORCA2/ORCA1/ORCA025/ORCA12/eORCA1/eORCA025/eORCA12 (numberOfGridInReference) + string uuidOfHGrid + - irregular_latlon - PLPresent: true - reduced_ll - reduced_gg @@ -150,11 +151,11 @@ Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) - 6 1 Points within even rows are offset by Di/2 in i (x) direction - 7 0 Points are not offset in j (y) direction - 7 1 Points are offset by Dj/2 in j (y) direction - - 8 0 Rows have Ni grid points and columns have Nj grid points - - 8 1 Rows have Ni grid points if points are not offset in i direction - Rows have Ni-1 grid points if points are offset by Di/2 in i direction - Columns have Nj grid points if points are not offset in j direction - Columns have Nj-1 grid points if points are offset by Dj/2 in j direction + - 8 0 n_i columns, n_j rows + - 8 1 Rows have n_i points if points are not offset in i direction + Rows have n_i-1 points if points are offset by Di/2 in i direction + Columns have n_j points if points are not offset in j direction + Columns have n_j-1 points if points are offset by Dj/2 in j direction bool iScansPositively bool jScansPositively @@ -174,8 +175,8 @@ Projection centre (grib2/tables/30/3.5.table) double longitudeOfLastPointInDegrees double DiInDegrees double DjInDegrees - size_t Ni - size_t Nj + size_t n_i + size_t n_j size_t numberOfParallelsBetweenAPoleAndTheEquator size_t basicAngleOfTheInitialProductionDomain size_t subdivisionsOfBasicAngle From f476b7cdde0c406d55083c04d9f9e5b60ab9c07a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 Mar 2023 16:47:06 +0000 Subject: [PATCH 103/737] grib --- CMakeLists.txt | 7 ++++++- src/grit/CMakeLists.txt | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 663b88afb..9823d78c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,12 +22,17 @@ endif() # dependencies (all optional) find_package(eccodes 2.29) - option(REQUIRE_ECCODES "Require ecCodes") if(REQUIRE_ECCODES AND NOT eccodes_FOUND) message(FATAL_ERROR "eccodes_FOUND=${eccodes_FOUND}") endif() +find_package(PROJ 9.2) +option(REQUIRE_PROJ "Require PROJ") +if(REQUIRE_PROJ AND NOT PROJ_FOUND) + message(FATAL_ERROR "PROJ_FOUND=${PROJ_FOUND}") +endif() + # library/resources add_subdirectory(src) diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 29c36128f..3ff4ee5e6 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -9,3 +9,7 @@ add_library(grit SHARED target_include_directories(grit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") +if(TARGET PROJ::proj) + target_link_libraries(grit PROJ::proj) +endif() + From f1ceaf34c3a270f4e2a1a4cc2a7055fea107e28b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 Mar 2023 17:29:01 +0000 Subject: [PATCH 104/737] grib --- src/grit/CMakeLists.txt | 4 + src/grit/scanner.cc | 48 +++++++++++ src/grit/scanner.h | 10 +++ src/grit/transformation.cc | 119 ++++++++++++++++++++++++++ src/grit/transformation.h | 10 +++ src/grit/util.cc | 170 +------------------------------------ src/tools/grit-grib.cc | 74 ++++++++++++++++ 7 files changed, 266 insertions(+), 169 deletions(-) create mode 100644 src/grit/scanner.cc create mode 100644 src/grit/scanner.h create mode 100644 src/grit/transformation.cc create mode 100644 src/grit/transformation.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 3ff4ee5e6..682145680 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -1,6 +1,10 @@ configure_file(grit.h.in grit.h) add_library(grit SHARED + scanner.cc + scanner.h + transformation.cc + transformation.h util.cc util.h util/arange.cc diff --git a/src/grit/scanner.cc b/src/grit/scanner.cc new file mode 100644 index 000000000..db1a6f49c --- /dev/null +++ b/src/grit/scanner.cc @@ -0,0 +1,48 @@ +/* + * (C) Copyright 1996- 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 "grit/scanner.h" + + +namespace grit { + + +#if 0 +Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) +- 1 0 Points of first row or column scan in the +i (+x) direction +- 1 1 Points of first row or column scan in the -i (-x) direction +- 2 0 Points of first row or column scan in the -j (-y) direction +- 2 1 Points of first row or column scan in the +j (+y) direction +- 3 0 Adjacent points in i (x) direction are consecutive +- 3 1 Adjacent points in j (y) direction is consecutive +- 4 0 All rows scan in the same direction +- 4 1 Adjacent rows scan in the opposite direction +- 5 0 Points within odd rows are not offset in i (x) direction +- 5 1 Points within odd rows are offset by Di/2 in i (x) direction +- 6 0 Points within even rows are not offset in i (x) direction +- 6 1 Points within even rows are offset by Di/2 in i (x) direction +- 7 0 Points are not offset in j (y) direction +- 7 1 Points are offset by Dj/2 in j (y) direction +- 8 0 n_i columns, n_j rows +- 8 1 Rows have n_i points if points are not offset in i direction + Rows have n_i-1 points if points are offset by Di/2 in i direction + Columns have n_j points if points are not offset in j direction + Columns have n_j-1 points if points are offset by Dj/2 in j direction + + bool iScansPositively + bool jScansPositively + bool jPointsAreConsecutive + bool alternativeRowScanning +#endif + + +} // namespace grit diff --git a/src/grit/scanner.h b/src/grit/scanner.h new file mode 100644 index 000000000..ac23a4e5d --- /dev/null +++ b/src/grit/scanner.h @@ -0,0 +1,10 @@ +/* + * (C) Copyright 1996- 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. + */ diff --git a/src/grit/transformation.cc b/src/grit/transformation.cc new file mode 100644 index 000000000..7bb8cb5e6 --- /dev/null +++ b/src/grit/transformation.cc @@ -0,0 +1,119 @@ +/* + * (C) Copyright 1996- 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 "grit/transformation.h" + + +namespace grit { + + +#if 0 +- mercator: + double DiInMetres + double DjInMetres + double LaDInDegrees + double latitudeOfFirstPointInDegrees + double longitudeOfFirstPointInDegrees + double projectionOrientationInDegrees + size_t n_i + size_t n_j +- polar_stereographic: + double DiInMetres + double DjInMetres + double LaDInDegrees + double latitudeOfFirstPointInDegrees + double longitudeOfFirstPointInDegrees + double projectionOrientationInDegrees + flags projectionCentreFlag + size_t n_i + size_t n_j +- lambert: + double DiInMetres + double DjInMetres + double LaDInDegrees + double Latin1InDegrees + double Latin2InDegrees + double LoVInDegrees + double latitudeOfFirstPointInDegrees + double latitudeOfSouthernPoleInDegrees + double longitudeOfFirstPointInDegrees + double longitudeOfSouthernPoleInDegrees + flags projectionCentreFlag + size_t n_i + size_t n_j +- albers: + double DiInMetres + double DjInMetres + double LaDInDegrees + double Latin1InDegrees + double Latin2InDegrees + double LoVInDegrees + double latitudeOfFirstPointInDegrees + double latitudeOfSouthernPoleInDegrees + double longitudeOfFirstPointInDegrees + double longitudeOfSouthernPoleInDegrees + flags projectionCentreFlag + size_t n_i + size_t n_j +- space_view: + double DiInMetres + double DjInMetres + double altitudeFromEarthCentreInMetres + double latitudeOfSubSatellitePointInDegrees + double longitudeOfSubSatellitePointInDegrees + double projectionOrientationInDegrees + double xOriginOfSectorImageInMetres + double xSubSatellitePointInMetres + double yOriginOfSectorImageInMetres + double ySubSatellitePointInMetres + size_t n_i + size_t n_j +- lambert_azimuthal_equal_area: + double DiInMetres + double DjInMetres + double centralLongitudeInDegrees + double latitudeOfFirstPointInDegrees + double longitudeOfFirstPointInDegrees + double standardParallelInDegrees +- equatorial_azimuthal_equidistant: + double DiInMetres + double DjInMetres + double latitudeOfTangencyPointInDegrees + double longitudeOfTangencyPointInDegrees + flags projectionCentreFlag +- unstructured_grid (grib2/localConcepts/[centre:s]/unstructuredGrid*): + string unstructuredGridSubtype = undefined/T/U/V/W/F (numberOfGridInReference) + string unstructuredGridType = undefined/ORCA2/ORCA1/ORCA025/ORCA12/eORCA1/eORCA025/eORCA12 (numberOfGridInReference) + string uuidOfHGrid +- irregular_latlon + +Projection, rotation, shape (grib2/template.3.(rotation|shape_of_the_earth).def) +- projSourceString, projTargetString, projString=projTargetString + + double latitudeOfSouthernPoleInDegrees + double longitudeOfSouthernPoleInDegrees + double angleOfRotationInDegrees + + bool is_oblate + double majorAxisInMetres + double minorAxisInMetres + double radiusInMetres + +Projection centre (grib2/tables/30/3.5.table) + 1 0 North Pole is on the projection plane + 1 1 South Pole is on the projection plane + 2 0 Only one projection centre is used + 2 1 Projection is bipolar and symmetric +#endif + + +} // namespace grit diff --git a/src/grit/transformation.h b/src/grit/transformation.h new file mode 100644 index 000000000..ac23a4e5d --- /dev/null +++ b/src/grit/transformation.h @@ -0,0 +1,10 @@ +/* + * (C) Copyright 1996- 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. + */ diff --git a/src/grit/util.cc b/src/grit/util.cc index 87e5a9e0f..c124fa966 100644 --- a/src/grit/util.cc +++ b/src/grit/util.cc @@ -13,172 +13,4 @@ #include "grit/util.h" -namespace grit::util { - - -struct regular_ll_args { - size_t n_i; - size_t n_j; - double i_start; - double i_stop; - double i_step; - double j_start; - double j_stop; - double j_step; -}; - - -} // namespace grit::util - - -#if 0 -gridType: gridDefinitionTemplateNumber - - PLPresent: false - - regular_ll - - rotated_ll - - regular_gg - - rotated_gg - - - projections: - - mercator: - double DiInMetres - double DjInMetres - double LaDInDegrees - double latitudeOfFirstPointInDegrees - double longitudeOfFirstPointInDegrees - double projectionOrientationInDegrees - size_t n_i - size_t n_j - - polar_stereographic: - double DiInMetres - double DjInMetres - double LaDInDegrees - double latitudeOfFirstPointInDegrees - double longitudeOfFirstPointInDegrees - double projectionOrientationInDegrees - flags projectionCentreFlag - size_t n_i - size_t n_j - - lambert: - double DiInMetres - double DjInMetres - double LaDInDegrees - double Latin1InDegrees - double Latin2InDegrees - double LoVInDegrees - double latitudeOfFirstPointInDegrees - double latitudeOfSouthernPoleInDegrees - double longitudeOfFirstPointInDegrees - double longitudeOfSouthernPoleInDegrees - flags projectionCentreFlag - size_t n_i - size_t n_j - - albers: - double DiInMetres - double DjInMetres - double LaDInDegrees - double Latin1InDegrees - double Latin2InDegrees - double LoVInDegrees - double latitudeOfFirstPointInDegrees - double latitudeOfSouthernPoleInDegrees - double longitudeOfFirstPointInDegrees - double longitudeOfSouthernPoleInDegrees - flags projectionCentreFlag - size_t n_i - size_t n_j - - space_view: - double DiInMetres - double DjInMetres - double altitudeFromEarthCentreInMetres - double latitudeOfSubSatellitePointInDegrees - double longitudeOfSubSatellitePointInDegrees - double projectionOrientationInDegrees - double xOriginOfSectorImageInMetres - double xSubSatellitePointInMetres - double yOriginOfSectorImageInMetres - double ySubSatellitePointInMetres - size_t n_i - size_t n_j - - lambert_azimuthal_equal_area: - double DiInMetres - double DjInMetres - double centralLongitudeInDegrees - double latitudeOfFirstPointInDegrees - double longitudeOfFirstPointInDegrees - double standardParallelInDegrees - - equatorial_azimuthal_equidistant: - double DiInMetres - double DjInMetres - double latitudeOfTangencyPointInDegrees - double longitudeOfTangencyPointInDegrees - flags projectionCentreFlag - - - unstructured_grid (grib2/localConcepts/[centre:s]/unstructuredGrid*): - string unstructuredGridSubtype = undefined/T/U/V/W/F (numberOfGridInReference) - string unstructuredGridType = undefined/ORCA2/ORCA1/ORCA025/ORCA12/eORCA1/eORCA025/eORCA12 (numberOfGridInReference) - string uuidOfHGrid - - irregular_latlon - - PLPresent: true - - reduced_ll - - reduced_gg - - reduced_rotated_gg - -Projection, rotation, shape (grib2/template.3.(rotation|shape_of_the_earth).def) - - projSourceString, projTargetString, projString=projTargetString - - double latitudeOfSouthernPoleInDegrees - double longitudeOfSouthernPoleInDegrees - double angleOfRotationInDegrees - - bool is_oblate - double majorAxisInMetres - double minorAxisInMetres - double radiusInMetres - -Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) - - 1 0 Points of first row or column scan in the +i (+x) direction - - 1 1 Points of first row or column scan in the -i (-x) direction - - 2 0 Points of first row or column scan in the -j (-y) direction - - 2 1 Points of first row or column scan in the +j (+y) direction - - 3 0 Adjacent points in i (x) direction are consecutive - - 3 1 Adjacent points in j (y) direction is consecutive - - 4 0 All rows scan in the same direction - - 4 1 Adjacent rows scan in the opposite direction - - 5 0 Points within odd rows are not offset in i (x) direction - - 5 1 Points within odd rows are offset by Di/2 in i (x) direction - - 6 0 Points within even rows are not offset in i (x) direction - - 6 1 Points within even rows are offset by Di/2 in i (x) direction - - 7 0 Points are not offset in j (y) direction - - 7 1 Points are offset by Dj/2 in j (y) direction - - 8 0 n_i columns, n_j rows - - 8 1 Rows have n_i points if points are not offset in i direction - Rows have n_i-1 points if points are offset by Di/2 in i direction - Columns have n_j points if points are not offset in j direction - Columns have n_j-1 points if points are offset by Dj/2 in j direction - - bool iScansPositively - bool jScansPositively - bool jPointsAreConsecutive - bool alternativeRowScanning - -Projection centre (grib2/tables/30/3.5.table) - 1 0 North Pole is on the projection plane - 1 1 South Pole is on the projection plane - 2 0 Only one projection centre is used - 2 1 Projection is bipolar and symmetric - -(grib2/template.3.(gaussian|grid|latlon).def) - double latitudeOfFirstPointInDegrees - double latitudeOfLastPointInDegrees - double longitudeOfFirstPointInDegrees - double longitudeOfLastPointInDegrees - double DiInDegrees - double DjInDegrees - size_t n_i - size_t n_j - size_t numberOfParallelsBetweenAPoleAndTheEquator - size_t basicAngleOfTheInitialProductionDomain - size_t subdivisionsOfBasicAngle -#endif - +namespace grit::util {} diff --git a/src/tools/grit-grib.cc b/src/tools/grit-grib.cc index 4c406c12d..edb2221ee 100644 --- a/src/tools/grit-grib.cc +++ b/src/tools/grit-grib.cc @@ -15,10 +15,84 @@ #include #include #include +#include +#include #include "grit/grit.h" +#if 0 +struct regular_ll_args { // also, rotated_ll + size_t n_i; + size_t n_j; + double i_start; + double i_stop; + double i_step; + double j_start; + double j_stop; + double j_step; +}; + + +struct regular_gg_args { // also, rotated_gg + size_t n; + size_t n_i; + double i_start; + double i_stop; + double j_start; + double j_stop; +}; + + +struct reduced_gg_args { // also, reduced_rotated_gg + size_t n; + std::vector n_i; + double i_start; + double i_stop; + double i_step; + double j_start; + double j_stop; + double j_step; +}; + + +struct reduced_ll_args { + std::vector n_i; + double i_start; + double i_stop; + double i_step; + double j_start; + double j_stop; + double j_step; +}; + + +template using function = R(*)(ARGS...); +using type_creator = function; + + +static const std::map __types{ + {"regular_ll", nullptr} +}; +#endif + + +#if 0 +(grib2/template.3.(gaussian|grid|latlon).def) + double latitudeOfFirstPointInDegrees + double latitudeOfLastPointInDegrees + double longitudeOfFirstPointInDegrees + double longitudeOfLastPointInDegrees + double DiInDegrees + double DjInDegrees + size_t n_i + size_t n_j + size_t numberOfParallelsBetweenAPoleAndTheEquator + size_t basicAngleOfTheInitialProductionDomain + size_t subdivisionsOfBasicAngle +#endif + + int main(int argc, const char* argv[]) { for (int i = 1; i < argc; ++i) { auto* in = std::fopen(argv[1], "rb"); From 56a3fc51a415cf765d53647521c08ceadf0a02ce Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 Mar 2023 21:38:06 +0000 Subject: [PATCH 105/737] grib --- src/tools/grit-grib.cc | 50 +++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/src/tools/grit-grib.cc b/src/tools/grit-grib.cc index edb2221ee..329bc4a91 100644 --- a/src/tools/grit-grib.cc +++ b/src/tools/grit-grib.cc @@ -93,28 +93,52 @@ static const std::map __types{ #endif +void test_grib_gridtype(codes_handle* h) { + assert(h != nullptr); + + char mesg[1024]; + auto length = sizeof(mesg); + assert(CODES_SUCCESS == codes_get_string(h, "gridType", mesg, &length)); + + std::string gridType(mesg); + + std::cout << "gridType='" << gridType << "'" << std::endl; +} + + +void test_grib_iterator(codes_handle* h) { + assert(h != nullptr); + + int err = 0; + + // long bitmapPresent = 0; + // assert(CODES_SUCCESS == codes_get_long(h, "bitmapPresent", &bitmapPresent)); + + auto* it = codes_grib_iterator_new(h, 0, &err); + assert(CODES_SUCCESS == err); + + int n = 0; + for (double lat = 0, lon = 0, value = 0; codes_grib_iterator_next(it, &lat, &lon, &value) > 0; ++n) { + std::cout << "- " << n << " - lat=" << lat << " lon=" << lon << " value=" << value << "\n"; + } + std::cout.flush(); + + codes_grib_iterator_delete(it); +} + + int main(int argc, const char* argv[]) { for (int i = 1; i < argc; ++i) { - auto* in = std::fopen(argv[1], "rb"); + auto* in = std::fopen(argv[i], "rb"); assert(in != nullptr && "unable to open file"); int err = 0; for (codes_handle* h = nullptr; nullptr != (h = codes_handle_new_from_file(nullptr, in, PRODUCT_GRIB, &err));) { assert(CODES_SUCCESS == err); - // long bitmapPresent = 0; - // assert(CODES_SUCCESS == codes_get_long(h, "bitmapPresent", &bitmapPresent)); - - auto* it = codes_grib_iterator_new(h, 0, &err); - assert(CODES_SUCCESS == err); - - int n = 0; - for (double lat = 0, lon = 0, value = 0; codes_grib_iterator_next(it, &lat, &lon, &value) > 0; ++n) { - std::cout << "- " << n << " - lat=" << lat << " lon=" << lon << " value=" << value << "\n"; - } - std::cout.flush(); + test_grib_gridtype(h); + // test_grib_iterator(h); - codes_grib_iterator_delete(it); codes_handle_delete(h); } From 18c12e4dd3391829ed6431f46b2d6f13a5b65452 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 27 Mar 2023 14:26:21 +0100 Subject: [PATCH 106/737] grib --- src/grit/CMakeLists.txt | 8 +-- src/grit/{scanner.cc => Scanner.cc} | 2 +- src/grit/{scanner.h => Scanner.h} | 0 .../{transformation.cc => Transformation.cc} | 2 +- .../{transformation.h => Transformation.h} | 0 src/tools/grit-grib.cc | 71 ++++++++++++++----- 6 files changed, 60 insertions(+), 23 deletions(-) rename src/grit/{scanner.cc => Scanner.cc} (98%) rename src/grit/{scanner.h => Scanner.h} (100%) rename src/grit/{transformation.cc => Transformation.cc} (99%) rename src/grit/{transformation.h => Transformation.h} (100%) diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 682145680..73869da82 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -1,10 +1,10 @@ configure_file(grit.h.in grit.h) add_library(grit SHARED - scanner.cc - scanner.h - transformation.cc - transformation.h + Scanner.cc + Scanner.h + Transformation.cc + Transformation.h util.cc util.h util/arange.cc diff --git a/src/grit/scanner.cc b/src/grit/Scanner.cc similarity index 98% rename from src/grit/scanner.cc rename to src/grit/Scanner.cc index db1a6f49c..3dc97380e 100644 --- a/src/grit/scanner.cc +++ b/src/grit/Scanner.cc @@ -10,7 +10,7 @@ */ -#include "grit/scanner.h" +#include "grit/Scanner.h" namespace grit { diff --git a/src/grit/scanner.h b/src/grit/Scanner.h similarity index 100% rename from src/grit/scanner.h rename to src/grit/Scanner.h diff --git a/src/grit/transformation.cc b/src/grit/Transformation.cc similarity index 99% rename from src/grit/transformation.cc rename to src/grit/Transformation.cc index 7bb8cb5e6..64c718fc4 100644 --- a/src/grit/transformation.cc +++ b/src/grit/Transformation.cc @@ -10,7 +10,7 @@ */ -#include "grit/transformation.h" +#include "grit/Transformation.h" namespace grit { diff --git a/src/grit/transformation.h b/src/grit/Transformation.h similarity index 100% rename from src/grit/transformation.h rename to src/grit/Transformation.h diff --git a/src/tools/grit-grib.cc b/src/tools/grit-grib.cc index 329bc4a91..4b3f1eee2 100644 --- a/src/tools/grit-grib.cc +++ b/src/tools/grit-grib.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "grit/grit.h" @@ -106,24 +107,56 @@ void test_grib_gridtype(codes_handle* h) { } -void test_grib_iterator(codes_handle* h) { - assert(h != nullptr); +struct grib : std::unique_ptr { + std::string get_string(const std::string& key) { + char mesg[1024]; + auto length = sizeof(mesg); + assert(CODES_SUCCESS == codes_get_string(get(), key.c_str(), mesg, &length)); + return mesg; + } - int err = 0; - // long bitmapPresent = 0; - // assert(CODES_SUCCESS == codes_get_long(h, "bitmapPresent", &bitmapPresent)); +public: + using t = std::unique_ptr; - auto* it = codes_grib_iterator_new(h, 0, &err); - assert(CODES_SUCCESS == err); + explicit grib(codes_handle* h) : t(h, &codes_handle_delete) { + assert(*this); + } - int n = 0; - for (double lat = 0, lon = 0, value = 0; codes_grib_iterator_next(it, &lat, &lon, &value) > 0; ++n) { - std::cout << "- " << n << " - lat=" << lat << " lon=" << lon << " value=" << value << "\n"; + std::string gridType() { + return get_string("gridType"); } - std::cout.flush(); - codes_grib_iterator_delete(it); + struct iterator : std::unique_ptr { + using t = std::unique_ptr; + + explicit iterator(codes_handle* h) : t(codes_grib_iterator_new(h, 0, &err), &codes_grib_iterator_delete) { + assert(CODES_SUCCESS == err); + assert(*this); + } + + bool next() { return codes_grib_iterator_next(get(), &lat, &lon, &value) > 0; } + + friend std::ostream& operator<<(std::ostream& out, const iterator& it) { + return (out << "- lat=" << it.lat << " lon=" << it.lon << " value=" << it.value); + } + + int err = 0; + double lat = 0; + double lon = 0; + double value = 0; + }; +}; + + + + + +void test_grib_iterator(codes_handle* h) { + assert(h != nullptr); + + // long bitmapPresent = 0; + // assert(CODES_SUCCESS == codes_get_long(h, "bitmapPresent", &bitmapPresent)); } @@ -134,12 +167,16 @@ int main(int argc, const char* argv[]) { int err = 0; for (codes_handle* h = nullptr; nullptr != (h = codes_handle_new_from_file(nullptr, in, PRODUCT_GRIB, &err));) { - assert(CODES_SUCCESS == err); + grib g(h); - test_grib_gridtype(h); - // test_grib_iterator(h); - - codes_handle_delete(h); +#if 0 + int n = 0; + for (grib::iterator it(h); it.next(); ++n) { + std::cout << "- " << n << " " << it << "\n"; + } + std::cout.flush(); +#endif + std::cout << "gridType: '" << g.gridType() << "'" << std::endl; } std::fclose(in); From a16d15b2fb3ef20d3d642cf4e2aad01a32dbea25 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 Mar 2023 09:45:45 +0100 Subject: [PATCH 107/737] figure --- src/grit/CMakeLists.txt | 6 + src/grit/Figure.cc | 33 +++ src/grit/Figure.h | 97 +++++++++ src/grit/Iterator.cc | 16 ++ src/grit/Iterator.h | 54 +++++ src/grit/Projection.cc | 16 ++ src/grit/Projection.h | 19 ++ src/grit/Scanner.cc | 14 +- src/grit/Scanner.h | 17 ++ src/grit/Transformation.h | 9 + src/grit/geometry/EllipsoidOfRevolution.cc | 85 ++++++++ src/grit/geometry/EllipsoidOfRevolution.h | 37 ++++ src/grit/geometry/GreatCircle.cc | 138 ++++++++++++ src/grit/geometry/GreatCircle.h | 49 +++++ src/grit/geometry/Sphere.cc | 232 +++++++++++++++++++++ src/grit/geometry/Sphere.h | 67 ++++++ src/grit/geometry/SphereT.h | 85 ++++++++ src/grit/geometry/UnitSphere.h | 45 ++++ src/grit/util.cc | 27 ++- src/grit/util.h | 18 ++ src/grit/util/arange.cc | 8 - src/grit/util/linspace.cc | 2 +- src/tools/grit-grib.cc | 182 +++++++++------- tests/util.cc | 11 +- 24 files changed, 1176 insertions(+), 91 deletions(-) create mode 100644 src/grit/Figure.cc create mode 100644 src/grit/Figure.h create mode 100644 src/grit/Iterator.cc create mode 100644 src/grit/Iterator.h create mode 100644 src/grit/Projection.cc create mode 100644 src/grit/Projection.h create mode 100644 src/grit/geometry/EllipsoidOfRevolution.cc create mode 100644 src/grit/geometry/EllipsoidOfRevolution.h create mode 100644 src/grit/geometry/GreatCircle.cc create mode 100644 src/grit/geometry/GreatCircle.h create mode 100644 src/grit/geometry/Sphere.cc create mode 100644 src/grit/geometry/Sphere.h create mode 100644 src/grit/geometry/SphereT.h create mode 100644 src/grit/geometry/UnitSphere.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 73869da82..9321b7b0c 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -1,6 +1,12 @@ configure_file(grit.h.in grit.h) add_library(grit SHARED + Figure.cc + Figure.h + Iterator.cc + Iterator.h + Projection.cc + Projection.h Scanner.cc Scanner.h Transformation.cc diff --git a/src/grit/Figure.cc b/src/grit/Figure.cc new file mode 100644 index 000000000..dc2f5ac33 --- /dev/null +++ b/src/grit/Figure.cc @@ -0,0 +1,33 @@ +/* + * (C) Copyright 1996- 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 "grit/Figure.h" + +#include + +#include "grit/util.h" + + +namespace grit { + + +Figure::Figure(double R) : Figure(R, R) {} + + +Figure::Figure(double a, double b) : + a_(a), b_(b), R_(util::approximately_equal(a, b) ? a : std::numeric_limits::signaling_NaN()) { + assert(a > 0. && "Figure::a > 0."); + assert(b > 0. && "Figure::b > 0."); +} + + +} // namespace grit diff --git a/src/grit/Figure.h b/src/grit/Figure.h new file mode 100644 index 000000000..130769b67 --- /dev/null +++ b/src/grit/Figure.h @@ -0,0 +1,97 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + + +namespace grit { + + +class Figure { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit Figure(double R); + explicit Figure(double a, double b); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + bool sphere() const { return R_ == R_; } + double a() const { return a_; } + double b() const { return b_; } + double R() const { return R_; } + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + const double a_; + const double b_; + const double R_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit diff --git a/src/grit/Iterator.cc b/src/grit/Iterator.cc new file mode 100644 index 000000000..708ba706d --- /dev/null +++ b/src/grit/Iterator.cc @@ -0,0 +1,16 @@ +/* + * (C) Copyright 1996- 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 "grit/Iterator.h" + + +namespace grit {} // namespace grit diff --git a/src/grit/Iterator.h b/src/grit/Iterator.h new file mode 100644 index 000000000..46d6edef1 --- /dev/null +++ b/src/grit/Iterator.h @@ -0,0 +1,54 @@ +/* + * (C) Copyright 1996- 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 +#include +#include + +#include "grit/Figure.h" + + +namespace grit { +struct Figure; +struct Scanner; +struct Transformation; +} // namespace grit + + +namespace grit { + + +struct Iterator { + Iterator() {} + + Iterator(const Iterator&) = delete; + Iterator(Iterator&&) = delete; + + Iterator& operator=(const Iterator&) = delete; + Iterator& operator=(Iterator&&) = delete; + + virtual ~Iterator() = delete; + + bool operator++() { + pos_++; + return false; + } + + size_t pos_; + + std::unique_ptr scanner_; + std::vector transformation_; + // Figure figure_; +}; + + +} // namespace grit diff --git a/src/grit/Projection.cc b/src/grit/Projection.cc new file mode 100644 index 000000000..7f8b737ff --- /dev/null +++ b/src/grit/Projection.cc @@ -0,0 +1,16 @@ +/* + * (C) Copyright 1996- 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 "grit/Transformation.h" + + +namespace grit {} // namespace grit diff --git a/src/grit/Projection.h b/src/grit/Projection.h new file mode 100644 index 000000000..3642101d6 --- /dev/null +++ b/src/grit/Projection.h @@ -0,0 +1,19 @@ +/* + * (C) Copyright 1996- 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. + */ + + +namespace grit { + + +struct Projection {}; + + +} // namespace grit diff --git a/src/grit/Scanner.cc b/src/grit/Scanner.cc index 3dc97380e..14654ef64 100644 --- a/src/grit/Scanner.cc +++ b/src/grit/Scanner.cc @@ -18,30 +18,36 @@ namespace grit { #if 0 Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) + + bool iScansPositively - 1 0 Points of first row or column scan in the +i (+x) direction - 1 1 Points of first row or column scan in the -i (-x) direction + + bool jScansPositively - 2 0 Points of first row or column scan in the -j (-y) direction - 2 1 Points of first row or column scan in the +j (+y) direction + + bool jPointsAreConsecutive - 3 0 Adjacent points in i (x) direction are consecutive - 3 1 Adjacent points in j (y) direction is consecutive + + bool alternativeRowScanning - 4 0 All rows scan in the same direction - 4 1 Adjacent rows scan in the opposite direction + - 5 0 Points within odd rows are not offset in i (x) direction - 5 1 Points within odd rows are offset by Di/2 in i (x) direction - 6 0 Points within even rows are not offset in i (x) direction - 6 1 Points within even rows are offset by Di/2 in i (x) direction - 7 0 Points are not offset in j (y) direction - 7 1 Points are offset by Dj/2 in j (y) direction + - 8 0 n_i columns, n_j rows - 8 1 Rows have n_i points if points are not offset in i direction Rows have n_i-1 points if points are offset by Di/2 in i direction Columns have n_j points if points are not offset in j direction Columns have n_j-1 points if points are offset by Dj/2 in j direction - bool iScansPositively - bool jScansPositively - bool jPointsAreConsecutive - bool alternativeRowScanning #endif diff --git a/src/grit/Scanner.h b/src/grit/Scanner.h index ac23a4e5d..c2c54cb30 100644 --- a/src/grit/Scanner.h +++ b/src/grit/Scanner.h @@ -8,3 +8,20 @@ * granted to it by virtue of its status as an intergovernmental organisation nor * does it submit to any jurisdiction. */ + + +namespace grit { + + +struct Scanner { + Scanner(const Scanner&) = default; + Scanner(Scanner&&) = default; + + Scanner& operator=(const Scanner&) = default; + Scanner& operator=(Scanner&&) = default; + + virtual ~Scanner() = default; +}; + + +} // namespace grit diff --git a/src/grit/Transformation.h b/src/grit/Transformation.h index ac23a4e5d..e76e2ef5c 100644 --- a/src/grit/Transformation.h +++ b/src/grit/Transformation.h @@ -8,3 +8,12 @@ * granted to it by virtue of its status as an intergovernmental organisation nor * does it submit to any jurisdiction. */ + + +namespace grit { + + +struct Transformation {}; + + +} // namespace grit diff --git a/src/grit/geometry/EllipsoidOfRevolution.cc b/src/grit/geometry/EllipsoidOfRevolution.cc new file mode 100644 index 000000000..ddbeef73c --- /dev/null +++ b/src/grit/geometry/EllipsoidOfRevolution.cc @@ -0,0 +1,85 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/EllipsoidOfRevolution.h" + +#include +#include +//#include // for std::numeric_limits +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geometry/Point2.h" +#include "eckit/geometry/Point3.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit { +namespace geometry { + +//---------------------------------------------------------------------------------------------------------------------- + +namespace { + +static double normalise_longitude(double a, const double& minimum) { + while (a < minimum) { + a += 360; + } + while (a >= minimum + 360) { + a -= 360; + } + return a; +} + +static const double degrees_to_radians = M_PI / 180.; + +static std::streamsize max_digits10 = 15 + 3; + +// C++-11: std::numeric_limits::max_digits10; + +} // namespace + +//---------------------------------------------------------------------------------------------------------------------- + +void EllipsoidOfRevolution::convertSphericalToCartesian(const double& a, const double& b, const Point2& Alonlat, + Point3& B, double height) { + ASSERT(a > 0.); + ASSERT(b > 0.); + + if (!(-90. <= Alonlat[1] && Alonlat[1] <= 90.)) { + std::ostringstream oss; + oss.precision(max_digits10); + oss << "Invalid latitude " << Alonlat[1]; + throw BadValue(oss.str(), Here()); + } + + // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates + // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) + + const double lambda_deg = normalise_longitude(Alonlat[0], -180.); + const double lambda = degrees_to_radians * lambda_deg; + const double phi = degrees_to_radians * Alonlat[1]; + + const double sin_phi = std::sin(phi); + const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); + const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; + const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); + + const double N_phi = a * a / std::sqrt(a * a * cos_phi * cos_phi + b * b * sin_phi * sin_phi); + + B[0] = (N_phi + height) * cos_phi * cos_lambda; + B[1] = (N_phi + height) * cos_phi * sin_lambda; + B[2] = (N_phi * (b * b) / (a * a) + height) * sin_phi; +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace geometry +} // namespace eckit diff --git a/src/grit/geometry/EllipsoidOfRevolution.h b/src/grit/geometry/EllipsoidOfRevolution.h new file mode 100644 index 000000000..e838dd256 --- /dev/null +++ b/src/grit/geometry/EllipsoidOfRevolution.h @@ -0,0 +1,37 @@ +/* + * (C) Copyright 1996- 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. + */ + +#ifndef EllipsoidOfRevolution_H +#define EllipsoidOfRevolution_H + +//------------------------------------------------------------------------------------------------------ + +namespace eckit { +namespace geometry { + +//------------------------------------------------------------------------------------------------------ + +class Point2; +class Point3; + +//------------------------------------------------------------------------------------------------------ + +struct EllipsoidOfRevolution { + // Convert elliptic coordinates to Cartesian + static void convertSphericalToCartesian(const double& radiusA, const double& radiusB, const Point2& Alonlat, + Point3& B, double height = 0.); +}; + +//------------------------------------------------------------------------------------------------------ + +} // namespace geometry +} // namespace eckit + +#endif diff --git a/src/grit/geometry/GreatCircle.cc b/src/grit/geometry/GreatCircle.cc new file mode 100644 index 000000000..7e8a805da --- /dev/null +++ b/src/grit/geometry/GreatCircle.cc @@ -0,0 +1,138 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/GreatCircle.h" + +#include +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/types/FloatCompare.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit { +namespace geometry { + +//---------------------------------------------------------------------------------------------------------------------- + +static double normalise_longitude(double a, const double& minimum) { + while (a < minimum) { + a += 360; + } + while (a >= minimum + 360) { + a -= 360; + } + return a; +} + +static const double radians_to_degrees = 180. * M_1_PI; + +static const double degrees_to_radians = M_PI / 180.; + +static constexpr std::streamsize max_digits10 = std::numeric_limits::max_digits10; + +static bool pole(const double lat) { + return types::is_approximately_equal(std::abs(lat), 90.); +} + +//---------------------------------------------------------------------------------------------------------------------- + +GreatCircle::GreatCircle(const Point2& Alonlat, const Point2& Blonlat) : + A_(Alonlat), B_(Blonlat) { + using namespace std; + using types::is_approximately_equal; + + const bool Apole = pole(A_[1]); + const bool Bpole = pole(B_[1]); + const double lon12_deg = normalise_longitude(A_[0] - B_[0], -180); + + const bool lon_same = Apole || Bpole || is_approximately_equal(lon12_deg, 0.); + const bool lon_opposite = Apole || Bpole || is_approximately_equal(abs(lon12_deg), 180.); + const bool lat_same = is_approximately_equal(A_[1], B_[1]); + const bool lat_opposite = is_approximately_equal(A_[1], -B_[1]); + + if ((lat_same && lon_same) || (lat_opposite && lon_opposite)) { + ostringstream oss; + oss.precision(max_digits10); + oss << "Great circle cannot be defined by points collinear with the centre, " << A_ << " and " << B_; + throw BadValue(oss.str(), Here()); + } + + crossesPoles_ = lon_same || lon_opposite; +} + +std::vector GreatCircle::latitude(double lon) const { + using namespace std; + + if (crossesPoles()) { + return {}; + } + + const double lat1 = degrees_to_radians * A_[1]; + const double lat2 = degrees_to_radians * B_[1]; + const double lambda1p = degrees_to_radians * (lon - A_[0]); + const double lambda2p = degrees_to_radians * (lon - B_[0]); + const double lambda = degrees_to_radians * normalise_longitude(B_[0] - A_[0], -180); + + double lat = atan((tan(lat2) * sin(lambda1p) - tan(lat1) * sin(lambda2p)) / (sin(lambda))); + return {radians_to_degrees * lat}; +} + +std::vector GreatCircle::longitude(double lat) const { + using namespace std; + using types::is_approximately_equal; + + if (crossesPoles()) { + const double lon = pole(A_[1]) ? B_[0] : A_[0]; + return pole(lat) ? vector{lon} : vector{lon, lon + 180}; + } + + const double lon12 = degrees_to_radians * normalise_longitude(A_[0] - B_[0], -180); + const double lon1 = degrees_to_radians * A_[0]; + const double lat1 = degrees_to_radians * A_[1]; + const double lat2 = degrees_to_radians * B_[1]; + const double lat3 = degrees_to_radians * lat; + + const double X = sin(lat1) * cos(lat2) * sin(lon12); + const double Y = sin(lat1) * cos(lat2) * cos(lon12) - cos(lat1) * sin(lat2); + + if (is_approximately_equal(X, 0.) && is_approximately_equal(Y, 0.)) { + return {}; // parallel (that is, equator) + } + + const double lon0 = lon1 + atan2(Y, X); + const double C = cos(lat1) * cos(lat2) * tan(lat3) * sin(lon12) / sqrt(X * X + Y * Y); + + if (is_approximately_equal(C, -1.)) { + return {radians_to_degrees * (lon0 + M_PI)}; + } + + if (is_approximately_equal(C, 1.)) { + return {radians_to_degrees * lon0}; + } + + if (-1 < C && C < 1) { + const double dlon = acos(C); + return {radians_to_degrees * (lon0 - dlon + 2 * M_PI), radians_to_degrees * (lon0 + dlon)}; + } + + return {}; +} + +bool GreatCircle::crossesPoles() const { + return crossesPoles_; +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace geometry +} // namespace eckit diff --git a/src/grit/geometry/GreatCircle.h b/src/grit/geometry/GreatCircle.h new file mode 100644 index 000000000..c23e09d2b --- /dev/null +++ b/src/grit/geometry/GreatCircle.h @@ -0,0 +1,49 @@ +/* + * (C) Copyright 1996- 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. + */ + +#ifndef GreatCircle_H +#define GreatCircle_H + +#include +#include "eckit/geometry/Point2.h" + +//------------------------------------------------------------------------------------------------------ + +namespace eckit { +namespace geometry { + +//------------------------------------------------------------------------------------------------------ + +class GreatCircle { +public: + /// Great circle given two points in geographic coordinates + GreatCircle(const Point2&, const Point2&); + + /// Great circle latitude given longitude, see http://www.edwilliams.org/avform.htm#Int + std::vector latitude(double lon) const; + + /// Great circle longitude given latitude, see http://www.edwilliams.org/avform.htm#Par + std::vector longitude(double lat) const; + + bool crossesPoles() const; + +private: + const Point2 A_; + const Point2 B_; + + bool crossesPoles_; +}; + +//------------------------------------------------------------------------------------------------------ + +} // namespace geometry +} // namespace eckit + +#endif diff --git a/src/grit/geometry/Sphere.cc b/src/grit/geometry/Sphere.cc new file mode 100644 index 000000000..bdd602035 --- /dev/null +++ b/src/grit/geometry/Sphere.cc @@ -0,0 +1,232 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/Sphere.h" + +#include +#include +#include +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geometry/GreatCircle.h" +#include "eckit/geometry/Point2.h" +#include "eckit/geometry/Point3.h" +#include "eckit/types/FloatCompare.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit { +namespace geometry { + +//---------------------------------------------------------------------------------------------------------------------- + +static double normalise_longitude(double a, const double& minimum) { + while (a < minimum) { + a += 360; + } + while (a >= minimum + 360) { + a -= 360; + } + return a; +} + +static const double radians_to_degrees = 180. * M_1_PI; + +static const double degrees_to_radians = M_PI / 180.; + +static constexpr std::streamsize max_digits10 = std::numeric_limits::max_digits10; + +inline double squared(double x) { + return x * x; +} + +//---------------------------------------------------------------------------------------------------------------------- + +double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { + using namespace std; + + /* + * Δσ = atan( ((cos(ϕ2) * sin(Δλ))^2 + (cos(ϕ1) * sin(ϕ2) - sin(ϕ1) * cos(ϕ2) * cos(Δλ))^2) / + * (sin(ϕ1) * sin(ϕ2) + cos(ϕ1) * cos(ϕ2) * cos(Δλ)) ) + * + * @article{doi:10.1179/sre.1975.23.176.88, + * author = {T. Vincenty}, + * title = {Direct and Inverse Solutions of Geodesics on the Ellipsoid With Application of Nested Equations}, + * journal = {Survey Review}, + * volume = {23}, + * number = {176}, + * pages = {88-93}, + * year = {1975}, + * doi = {10.1179/sre.1975.23.176.88} + * } + */ + + if (!(-90. <= Alonlat[1] && Alonlat[1] <= 90.)) { + ostringstream oss; + oss.precision(max_digits10); + oss << "Invalid latitude " << Alonlat[1]; + throw BadValue(oss.str(), Here()); + } + + if (!(-90. <= Blonlat[1] && Blonlat[1] <= 90.)) { + ostringstream oss; + oss.precision(max_digits10); + oss << "Invalid latitude " << Blonlat[1]; + throw BadValue(oss.str(), Here()); + } + + const double phi1 = degrees_to_radians * Alonlat[1]; + const double phi2 = degrees_to_radians * Blonlat[1]; + const double lambda = degrees_to_radians * (Blonlat[0] - Alonlat[0]); + + const double cos_phi1 = cos(phi1); + const double sin_phi1 = sin(phi1); + const double cos_phi2 = cos(phi2); + const double sin_phi2 = sin(phi2); + const double cos_lambda = cos(lambda); + const double sin_lambda = sin(lambda); + + const double angle = atan2(sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), + sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); + + if (types::is_approximately_equal(angle, 0.)) { + return 0.; + } + + ASSERT(angle > 0.); + return angle; +} + +double Sphere::centralAngle(const double& radius, const Point3& A, const Point3& B) { + ASSERT(radius > 0.); + + // Δσ = 2 * asin( chord / 2 ) + + const double d2 = Point3::distance2(A, B); + if (types::is_approximately_equal(d2, 0.)) { + return 0.; + } + + const double chord = std::sqrt(d2) / radius; + const double angle = std::asin(chord * 0.5) * 2.; + + return angle; +} + +double Sphere::distance(const double& radius, const Point2& Alonlat, const Point2& Blonlat) { + return radius * centralAngle(Alonlat, Blonlat); +} + +double Sphere::distance(const double& radius, const Point3& A, const Point3& B) { + return radius * centralAngle(radius, A, B); +} + +double Sphere::area(const double& radius) { + ASSERT(radius > 0.); + return 4. * M_PI * radius * radius; +} + +double Sphere::area(const double& radius, const Point2& WestNorth, const Point2& EastSouth) { + ASSERT(radius > 0.); + + // Set longitude fraction + double W = WestNorth[0]; + double E = normalise_longitude(EastSouth[0], W); + double longitude_range( + types::is_approximately_equal(W, E) && !types::is_approximately_equal(EastSouth[0], WestNorth[0]) ? 360. + : E - W); + ASSERT(longitude_range <= 360.); + + double longitude_fraction = longitude_range / 360.; + + // Set latitude fraction + double N = WestNorth[1]; + double S = EastSouth[1]; + ASSERT(-90. <= N && N <= 90.); + ASSERT(-90. <= S && S <= 90.); + ASSERT(N >= S); + + double latitude_fraction = 0.5 * (std::sin(degrees_to_radians * N) - std::sin(degrees_to_radians * S)); + + // Calculate area + return area(radius) * latitude_fraction * longitude_fraction; +} + +double Sphere::greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clon) { + GreatCircle gc(Alonlat, Blonlat); + auto lat = gc.latitude(Clon); + return lat.size() == 1 ? lat[0] : std::numeric_limits::signaling_NaN(); +} + +void Sphere::greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clat, + double& Clon1, double& Clon2) { + GreatCircle gc(Alonlat, Blonlat); + auto lon = gc.longitude(Clat); + + Clon1 = lon.size() > 0 ? lon[0] : std::numeric_limits::signaling_NaN(); + Clon2 = lon.size() > 1 ? lon[1] : std::numeric_limits::signaling_NaN(); +} + +void Sphere::convertSphericalToCartesian(const double& radius, const Point2& Alonlat, Point3& B, double height) { + ASSERT(radius > 0.); + + if (!(-90. <= Alonlat[1] && Alonlat[1] <= 90.)) { + std::ostringstream oss; + oss.precision(max_digits10); + oss << "Invalid latitude " << Alonlat[1]; + throw BadValue(oss.str(), Here()); + } + + /* + * See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates + * numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line). + * + * cos α = sqrt( 1 - sin^2 α) is better conditioned than explicit cos α, and + * coupled with λ in [-180°, 180°[ the accuracy of the trigonometric + * functions is the same (before converting/multiplying its angle argument + * to radian) and explicitly chosing -180° over 180° for longitude. + * + * These three conditionings combined project very accurately to the sphere + * poles and quadrants. + */ + + const double lambda_deg = normalise_longitude(Alonlat[0], -180.); + const double lambda = degrees_to_radians * lambda_deg; + const double phi = degrees_to_radians * Alonlat[1]; + + const double sin_phi = std::sin(phi); + const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); + const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; + const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); + + B[0] = (radius + height) * cos_phi * cos_lambda; + B[1] = (radius + height) * cos_phi * sin_lambda; + B[2] = (radius + height) * sin_phi; +} + +void Sphere::convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat) { + ASSERT(radius > 0.); + + // numerical conditioning for both z (poles) and y + + const double x = A[0]; + const double y = types::is_approximately_equal(A[1], 0.) ? 0. : A[1]; + const double z = std::min(radius, std::max(-radius, A[2])) / radius; + + Blonlat[0] = radians_to_degrees * std::atan2(y, x); + Blonlat[1] = radians_to_degrees * std::asin(z); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace geometry +} // namespace eckit diff --git a/src/grit/geometry/Sphere.h b/src/grit/geometry/Sphere.h new file mode 100644 index 000000000..bd79725e1 --- /dev/null +++ b/src/grit/geometry/Sphere.h @@ -0,0 +1,67 @@ +/* + * (C) Copyright 1996- 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. + */ + +#ifndef Sphere_H +#define Sphere_H + +//------------------------------------------------------------------------------------------------------ + +namespace eckit { +namespace geometry { + +//------------------------------------------------------------------------------------------------------ + +class Point2; +class Point3; + +//------------------------------------------------------------------------------------------------------ + +struct Sphere { + /// Great-circle central angle between two points (latitude/longitude coordinates) in radians + static double centralAngle(const Point2& Alonlat, const Point2& Blonlat); + + /// Great-circle central angle between two points (Cartesian coordinates) in radians + static double centralAngle(const double& radius, const Point3& A, const Point3& B); + + /// Great-circle distance between two points (latitude/longitude coordinates) in metres + static double distance(const double& radius, const Point2& Alonlat, const Point2& Blonlat); + + /// Great-circle distance between two points (Cartesian coordinates) in metres + static double distance(const double& radius, const Point3& A, const Point3& B); + + /// Surface area in square metres + static double area(const double& radius); + + /// Surface area between parallels and meridians defined by two points (longitude/latitude + /// coordinates) in square metres + static double area(const double& radius, const Point2& Alonlat, const Point2& Blonlat); + + // Great-circle intermediate latitude provided two circle points (A, B) and intermediate + // longitude (C) in degrees + static double greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clon); + + // Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate + // latitude (C) in degrees + static void greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clat, + double& Clon1, double& Clon2); + + // Convert spherical coordinates to Cartesian + static void convertSphericalToCartesian(const double& radius, const Point2& Alonlat, Point3& B, double height = 0.); + + // Convert Cartesian coordinates to spherical + static void convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat); +}; + +//------------------------------------------------------------------------------------------------------ + +} // namespace geometry +} // namespace eckit + +#endif diff --git a/src/grit/geometry/SphereT.h b/src/grit/geometry/SphereT.h new file mode 100644 index 000000000..5db54c3c3 --- /dev/null +++ b/src/grit/geometry/SphereT.h @@ -0,0 +1,85 @@ +/* + * (C) Copyright 1996- 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. + */ + +#ifndef SphereT_H +#define SphereT_H + +#include "eckit/geometry/Sphere.h" + +//------------------------------------------------------------------------------------------------------ + +namespace eckit { +namespace geometry { + +//------------------------------------------------------------------------------------------------------ + +/// Definition of a sphere parametrised with a geodetic datum +template +struct SphereT { + + /// Sphere radius in metres + inline static double radius() { return DATUM::radius(); } + + /// Great-circle central angle between two points (longitude/latitude coordinates) in radians + inline static double centralAngle(const Point2& Alonlat, const Point2& Blonlat) { + return Sphere::centralAngle(Alonlat, Blonlat); + } + + /// Great-circle central angle between two points (Cartesian coordinates) in radians + inline static double centralAngle(const Point3& A, const Point3& B) { + return Sphere::centralAngle(DATUM::radius(), A, B); + } + + /// Great-circle distance between two points (longitude/latitude coordinates) in metres + inline static double distance(const Point2& Alonlat, const Point2& Blonlat) { + return Sphere::distance(DATUM::radius(), Alonlat, Blonlat); + } + + /// Great-circle distance between two points (Cartesian coordinates) in metres + inline static double distance(const Point3& A, const Point3& B) { return Sphere::distance(DATUM::radius(), A, B); } + + /// Surface area in square metres + inline static double area() { return Sphere::area(DATUM::radius()); } + + /// Surface area between parallels and meridians defined by two points (longitude/latitude coordinates) in square + /// metres + inline static double area(const Point2& WestNorth, const Point2& EastSouth) { + return Sphere::area(DATUM::radius(), WestNorth, EastSouth); + } + + // Great-circle intermediate latitude provided two circle points (A, B) and intermediate longitude (C) in degrees + inline static double greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, + const double& Clon) { + return Sphere::greatCircleLatitudeGivenLongitude(Alonlat, Blonlat, Clon); + } + + // Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate latitude (C) in degrees + inline static void greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, + const double& Clat, double& Clon1, double& Clon2) { + return Sphere::greatCircleLongitudeGivenLatitude(Alonlat, Blonlat, Clat, Clon1, Clon2); + } + + // Convert spherical coordinates to Cartesian + inline static void convertSphericalToCartesian(const Point2& Alonlat, Point3& B, double height = 0.) { + Sphere::convertSphericalToCartesian(DATUM::radius(), Alonlat, B, height); + } + + // Convert Cartesian coordinates to spherical + inline static void convertCartesianToSpherical(const Point3& A, Point2& Blonlat) { + Sphere::convertCartesianToSpherical(DATUM::radius(), A, Blonlat); + } +}; + +//------------------------------------------------------------------------------------------------------ + +} // namespace geometry +} // namespace eckit + +#endif diff --git a/src/grit/geometry/UnitSphere.h b/src/grit/geometry/UnitSphere.h new file mode 100644 index 000000000..eabe66e28 --- /dev/null +++ b/src/grit/geometry/UnitSphere.h @@ -0,0 +1,45 @@ +/* + * (C) Copyright 1996- 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. + */ + +#ifndef UnitSphere_H +#define UnitSphere_H + +#include "eckit/geometry/SphereT.h" + +//------------------------------------------------------------------------------------------------------ + +namespace eckit { +namespace geometry { + +//------------------------------------------------------------------------------------------------------ + +/// Definition of a unit datum +struct DatumUnit { + + /* C++-11: + static constexpr double radius() { + return 1.; + } + */ + + static double radius() { return 1.; } +}; + +//------------------------------------------------------------------------------------------------------ + +/// Definition of a unit sphere +typedef SphereT UnitSphere; + +//------------------------------------------------------------------------------------------------------ + +} // namespace geometry +} // namespace eckit + +#endif diff --git a/src/grit/util.cc b/src/grit/util.cc index c124fa966..e84ebe6fb 100644 --- a/src/grit/util.cc +++ b/src/grit/util.cc @@ -13,4 +13,29 @@ #include "grit/util.h" -namespace grit::util {} +namespace grit::util { + + +double normalise_longitude_to_minimum(double lon, double minimum) { + while (lon < minimum) { + lon += 360.; + } + while (lon >= minimum + 360.) { + lon -= 360.; + } + return lon; +} + + +double normalise_longitude_to_maximum(double lon, double maximum) { + while (lon > maximum) { + lon -= 360.; + } + while (lon <= maximum - 360.) { + lon += 360.; + } + return lon; +} + + +} // namespace grit::util diff --git a/src/grit/util.h b/src/grit/util.h index 71f1792fb..a1a738b16 100644 --- a/src/grit/util.h +++ b/src/grit/util.h @@ -12,13 +12,23 @@ #pragma once +#include #include +#include #include namespace grit::util { +template +bool approximately_equal(T x, T y, T eps = std::numeric_limits::epsilon()) { + auto min = std::min(std::abs(x), std::abs(y)); + return std::abs(min) == 0. ? std::abs(x - y) < eps + : std::abs(x - y) / std::max(std::numeric_limits::min(), min) < eps; +}; + + std::vector arange(double start, double stop, double step); @@ -28,4 +38,12 @@ std::vector linspace(double start, double stop, size_t num, bool endpoin std::vector gaussian_latitudes(size_t N, bool increasing); +/// @return longitude in degree within range [minimum, minimum + 360[ +double normalise_longitude_to_minimum(double lon, double minimum); + + +/// @return longitude in degree within range ]maximum - 360, maximum] +double normalise_longitude_to_maximum(double lon, double maximum); + + } // namespace grit::util diff --git a/src/grit/util/arange.cc b/src/grit/util/arange.cc index 870a824c2..9db500ffb 100644 --- a/src/grit/util/arange.cc +++ b/src/grit/util/arange.cc @@ -20,14 +20,6 @@ namespace grit::util { -template -bool approximately_equal(T x, T y, T eps = std::numeric_limits::epsilon()) { - auto min = std::min(std::abs(x), std::abs(y)); - return std::abs(min) == 0. ? std::abs(x - y) < eps - : std::abs(x - y) / std::max(std::numeric_limits::min(), min) < eps; -}; - - std::vector arange(double start, double stop, double step) { if (approximately_equal(step, 0.) || approximately_equal(start, stop) || (stop - start) * step < 0.) { std::vector l(1, start); diff --git a/src/grit/util/linspace.cc b/src/grit/util/linspace.cc index acf2bc8c6..95cc41a6e 100644 --- a/src/grit/util/linspace.cc +++ b/src/grit/util/linspace.cc @@ -27,7 +27,7 @@ std::vector linspace(double start, double stop, size_t num, bool endpoin std::vector l(num); std::generate_n(l.begin(), num, - [start, step, n = 0ull]() mutable { return start + static_cast(n++) * step; }); + [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); return l; } diff --git a/src/tools/grit-grib.cc b/src/tools/grit-grib.cc index 4b3f1eee2..14f9bca0c 100644 --- a/src/tools/grit-grib.cc +++ b/src/tools/grit-grib.cc @@ -23,55 +23,6 @@ #if 0 -struct regular_ll_args { // also, rotated_ll - size_t n_i; - size_t n_j; - double i_start; - double i_stop; - double i_step; - double j_start; - double j_stop; - double j_step; -}; - - -struct regular_gg_args { // also, rotated_gg - size_t n; - size_t n_i; - double i_start; - double i_stop; - double j_start; - double j_stop; -}; - - -struct reduced_gg_args { // also, reduced_rotated_gg - size_t n; - std::vector n_i; - double i_start; - double i_stop; - double i_step; - double j_start; - double j_stop; - double j_step; -}; - - -struct reduced_ll_args { - std::vector n_i; - double i_start; - double i_stop; - double i_step; - double j_start; - double j_stop; - double j_step; -}; - - -template using function = R(*)(ARGS...); -using type_creator = function; - - static const std::map __types{ {"regular_ll", nullptr} }; @@ -94,38 +45,69 @@ static const std::map __types{ #endif -void test_grib_gridtype(codes_handle* h) { - assert(h != nullptr); +struct grib_type : std::unique_ptr { + using t = std::unique_ptr; - char mesg[1024]; - auto length = sizeof(mesg); - assert(CODES_SUCCESS == codes_get_string(h, "gridType", mesg, &length)); + bool get_bool(const std::string& key) const { return get_long(key) != 0L; } - std::string gridType(mesg); + double get_double(const std::string& key) const { + if (auto value = cache_double.find(key); value != cache_double.end()) { + return value->second; + } - std::cout << "gridType='" << gridType << "'" << std::endl; -} + double value = 0; + assert(CODES_SUCCESS == codes_get_double(get(), key.c_str(), &value)); + + cache_double[key] = value; + return value; + } + long get_long(const std::string& key) const { + if (auto value = cache_long.find(key); value != cache_long.end()) { + return value->second; + } + + long value = 0; + assert(CODES_SUCCESS == codes_get_long(get(), key.c_str(), &value)); + + cache_long[key] = value; + return value; + } + + size_t get_size_t(const std::string& key) const { + auto value = get_long(key); + assert(value >= 0); + return static_cast(value); + } -struct grib : std::unique_ptr { - std::string get_string(const std::string& key) { + std::string get_string(const std::string& key) const { char mesg[1024]; auto length = sizeof(mesg); assert(CODES_SUCCESS == codes_get_string(get(), key.c_str(), mesg, &length)); - return mesg; + const std::string value(mesg); + + cache_string[key] = value; + return value; } + mutable std::map cache_double; + mutable std::map cache_long; + mutable std::map cache_string; -public: - using t = std::unique_ptr; + explicit grib_type(codes_handle* h) : t(h, &codes_handle_delete) { assert(*this); } - explicit grib(codes_handle* h) : t(h, &codes_handle_delete) { - assert(*this); - } + std::string type() const { return get_string("gridType"); } - std::string gridType() { - return get_string("gridType"); - } + size_t Ni() const { return get_size_t("Ni"); } + size_t Nj() const { return get_size_t("Nj"); } + + double i_start() const { return get_double("longitudeOfFirstGridPointInDegrees"); } + double i_step() const { return get_double("iDirectionIncrementInDegrees"); } + double i_stop() const { return get_double("longitudeOfLastGridPointInDegrees"); } + + double j_start() const { return get_double("latitudeOfFirstGridPointInDegrees"); } + double j_step() const { return get_double("jDirectionIncrementInDegrees"); } + double j_stop() const { return get_double("latitudeOfLastGridPointInDegrees"); } struct iterator : std::unique_ptr { using t = std::unique_ptr; @@ -149,9 +131,6 @@ struct grib : std::unique_ptr { }; - - - void test_grib_iterator(codes_handle* h) { assert(h != nullptr); @@ -160,14 +139,21 @@ void test_grib_iterator(codes_handle* h) { } +struct test; + +static const std::map __builders{}; + + int main(int argc, const char* argv[]) { + + for (int i = 1; i < argc; ++i) { auto* in = std::fopen(argv[i], "rb"); assert(in != nullptr && "unable to open file"); int err = 0; for (codes_handle* h = nullptr; nullptr != (h = codes_handle_new_from_file(nullptr, in, PRODUCT_GRIB, &err));) { - grib g(h); + grib_type grib(h); #if 0 int n = 0; @@ -176,7 +162,57 @@ int main(int argc, const char* argv[]) { } std::cout.flush(); #endif - std::cout << "gridType: '" << g.gridType() << "'" << std::endl; + + auto type = grib.type(); + std::cout << "type: '" << type << "'" << std::endl; + + if (type == "regular_ll") { + struct regular_ll_args { // also, rotated_ll + size_t n_i; + double i_start; + double i_stop; + double i_step; + size_t n_j; + double j_start; + double j_stop; + double j_step; + }; + + regular_ll_args args{grib.Ni(), grib.i_start(), grib.i_stop(), grib.i_step(), + grib.Nj(), grib.j_start(), grib.j_stop(), grib.j_step()}; + + + // struct regular_gg_args { // also, rotated_gg + // size_t n; + // size_t n_i; + // double i_start; + // double i_stop; + // double j_start; + // double j_stop; + // }; + + + // struct reduced_gg_args { // also, reduced_rotated_gg + // size_t n; + // std::vector n_i; + // double i_start; + // double i_stop; + // double i_step; + // double j_start; + // double j_stop; + // double j_step; + // }; + + + // struct reduced_ll_args { + // std::vector n_i; + // double i_start; + // double i_stop; + // double i_step; + // double j_start; + // double j_stop; + // double j_step; + }; } std::fclose(in); diff --git a/tests/util.cc b/tests/util.cc index 7964d1aa4..1f6973421 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -74,11 +74,13 @@ class iterable_t : public std::vector { int main(int argc, char* argv[]) { - // std::cout << grit::util::linspace(1, 2, 2, true) << std::endl; - // std::cout << grit::util::arange(1, 2, 0.5) << std::endl; - // std::cout << grit::util::gaussian_latitudes(64, false) << std::endl; - + // std::cout << grit::util::linspace(1, 2, 2, true) << std::endl; + // std::cout << grit::util::arange(1, 2, 0.5) << std::endl; + // std::cout << grit::util::gaussian_latitudes(64, false) << std::endl; + // std::cout << grit::util::normalise_longitude_to_maximum(0.,0.) << std::endl; + // std::cout << grit::util::normalise_longitude_to_minimum(0.,0.) << std::endl; +#if 0 iterable_t it{1, 2, 3, 4}; for (const auto& v : it) { @@ -86,4 +88,5 @@ int main(int argc, char* argv[]) { } std::cout << std::accumulate(it.begin(), it.end(), 0) << std::endl; +#endif } From 5afdc692c87c440eb4aabe637b25b215270a05c5 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 Mar 2023 10:29:38 +0100 Subject: [PATCH 108/737] figure --- src/grit/CMakeLists.txt | 9 ++ src/grit/geometry/EllipsoidOfRevolution.cc | 55 ++--------- src/grit/geometry/EllipsoidOfRevolution.h | 19 ++-- src/grit/geometry/GreatCircle.cc | 74 +++++---------- src/grit/geometry/GreatCircle.h | 18 ++-- src/grit/geometry/Sphere.cc | 103 +++++++-------------- src/grit/geometry/Sphere.h | 19 ++-- src/grit/geometry/SphereT.h | 17 ++-- src/grit/geometry/UnitSphere.h | 28 ++---- src/grit/types.h | 25 +++++ src/grit/util.h | 7 ++ 11 files changed, 144 insertions(+), 230 deletions(-) create mode 100644 src/grit/types.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 9321b7b0c..6afc590c3 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -5,12 +5,21 @@ add_library(grit SHARED Figure.h Iterator.cc Iterator.h + types.h Projection.cc Projection.h Scanner.cc Scanner.h Transformation.cc Transformation.h + geometry/EllipsoidOfRevolution.cc + geometry/EllipsoidOfRevolution.h + geometry/GreatCircle.cc + geometry/GreatCircle.h + geometry/Sphere.cc + geometry/Sphere.h + geometry/SphereT.h + geometry/UnitSphere.h util.cc util.h util/arange.cc diff --git a/src/grit/geometry/EllipsoidOfRevolution.cc b/src/grit/geometry/EllipsoidOfRevolution.cc index ddbeef73c..1899dab00 100644 --- a/src/grit/geometry/EllipsoidOfRevolution.cc +++ b/src/grit/geometry/EllipsoidOfRevolution.cc @@ -3,67 +3,33 @@ * * 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 "eckit/geometry/EllipsoidOfRevolution.h" -#include -#include -//#include // for std::numeric_limits -#include +#include "grit/geometry/EllipsoidOfRevolution.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Point2.h" -#include "eckit/geometry/Point3.h" +#include +#include -//---------------------------------------------------------------------------------------------------------------------- -namespace eckit { +namespace grit { namespace geometry { -//---------------------------------------------------------------------------------------------------------------------- - -namespace { - -static double normalise_longitude(double a, const double& minimum) { - while (a < minimum) { - a += 360; - } - while (a >= minimum + 360) { - a -= 360; - } - return a; -} - -static const double degrees_to_radians = M_PI / 180.; - -static std::streamsize max_digits10 = 15 + 3; - -// C++-11: std::numeric_limits::max_digits10; - -} // namespace - -//---------------------------------------------------------------------------------------------------------------------- void EllipsoidOfRevolution::convertSphericalToCartesian(const double& a, const double& b, const Point2& Alonlat, Point3& B, double height) { - ASSERT(a > 0.); - ASSERT(b > 0.); - - if (!(-90. <= Alonlat[1] && Alonlat[1] <= 90.)) { - std::ostringstream oss; - oss.precision(max_digits10); - oss << "Invalid latitude " << Alonlat[1]; - throw BadValue(oss.str(), Here()); - } + assert(a > 0.); + assert(b > 0.); + assert(-90. <= Alonlat[1] && Alonlat[1] <= 90. && "Invalid latitude"); // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) - const double lambda_deg = normalise_longitude(Alonlat[0], -180.); + const double lambda_deg = util::normalise_longitude_to_minimum(Alonlat[0], -180.); const double lambda = degrees_to_radians * lambda_deg; const double phi = degrees_to_radians * Alonlat[1]; @@ -79,7 +45,6 @@ void EllipsoidOfRevolution::convertSphericalToCartesian(const double& a, const d B[2] = (N_phi * (b * b) / (a * a) + height) * sin_phi; } -//---------------------------------------------------------------------------------------------------------------------- } // namespace geometry -} // namespace eckit +} // namespace grit diff --git a/src/grit/geometry/EllipsoidOfRevolution.h b/src/grit/geometry/EllipsoidOfRevolution.h index e838dd256..b02b15589 100644 --- a/src/grit/geometry/EllipsoidOfRevolution.h +++ b/src/grit/geometry/EllipsoidOfRevolution.h @@ -3,25 +3,23 @@ * * 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. */ -#ifndef EllipsoidOfRevolution_H -#define EllipsoidOfRevolution_H -//------------------------------------------------------------------------------------------------------ +#pragma once + -namespace eckit { +namespace grit { namespace geometry { -//------------------------------------------------------------------------------------------------------ -class Point2; -class Point3; +struct Point2; +struct Point3; -//------------------------------------------------------------------------------------------------------ struct EllipsoidOfRevolution { // Convert elliptic coordinates to Cartesian @@ -29,9 +27,6 @@ struct EllipsoidOfRevolution { Point3& B, double height = 0.); }; -//------------------------------------------------------------------------------------------------------ } // namespace geometry -} // namespace eckit - -#endif +} // namespace grit diff --git a/src/grit/geometry/GreatCircle.cc b/src/grit/geometry/GreatCircle.cc index 7e8a805da..a32b0c619 100644 --- a/src/grit/geometry/GreatCircle.cc +++ b/src/grit/geometry/GreatCircle.cc @@ -3,69 +3,45 @@ * * 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 "eckit/geometry/GreatCircle.h" +#include "grit/geometry/GreatCircle.h" + +#include #include #include -#include -#include "eckit/exception/Exceptions.h" -#include "eckit/types/FloatCompare.h" +#include "grit/util.h" -//---------------------------------------------------------------------------------------------------------------------- -namespace eckit { +namespace grit { namespace geometry { -//---------------------------------------------------------------------------------------------------------------------- - -static double normalise_longitude(double a, const double& minimum) { - while (a < minimum) { - a += 360; - } - while (a >= minimum + 360) { - a -= 360; - } - return a; -} - -static const double radians_to_degrees = 180. * M_1_PI; - -static const double degrees_to_radians = M_PI / 180.; - -static constexpr std::streamsize max_digits10 = std::numeric_limits::max_digits10; -static bool pole(const double lat) { - return types::is_approximately_equal(std::abs(lat), 90.); +static bool pole(double lat) { + return util::approximately_equal(std::abs(lat), 90.); } -//---------------------------------------------------------------------------------------------------------------------- -GreatCircle::GreatCircle(const Point2& Alonlat, const Point2& Blonlat) : - A_(Alonlat), B_(Blonlat) { +GreatCircle::GreatCircle(const Point2& Alonlat, const Point2& Blonlat) : A_(Alonlat), B_(Blonlat) { using namespace std; - using types::is_approximately_equal; const bool Apole = pole(A_[1]); const bool Bpole = pole(B_[1]); - const double lon12_deg = normalise_longitude(A_[0] - B_[0], -180); - - const bool lon_same = Apole || Bpole || is_approximately_equal(lon12_deg, 0.); - const bool lon_opposite = Apole || Bpole || is_approximately_equal(abs(lon12_deg), 180.); - const bool lat_same = is_approximately_equal(A_[1], B_[1]); - const bool lat_opposite = is_approximately_equal(A_[1], -B_[1]); - - if ((lat_same && lon_same) || (lat_opposite && lon_opposite)) { - ostringstream oss; - oss.precision(max_digits10); - oss << "Great circle cannot be defined by points collinear with the centre, " << A_ << " and " << B_; - throw BadValue(oss.str(), Here()); - } + const double lon12_deg = util::normalise_longitude_to_minimum(A_[0] - B_[0], -180); + + const bool lon_same = Apole || Bpole || util::approximately_equal(lon12_deg, 0.); + const bool lon_opposite = Apole || Bpole || util::approximately_equal(abs(lon12_deg), 180.); + const bool lat_same = util::approximately_equal(A_[1], B_[1]); + const bool lat_opposite = util::approximately_equal(A_[1], -B_[1]); + + assert(!(lat_same && lon_same) && !(lat_opposite && lon_opposite) && + "Great circle cannot be defined by points collinear with the centre"); crossesPoles_ = lon_same || lon_opposite; } @@ -81,7 +57,7 @@ std::vector GreatCircle::latitude(double lon) const { const double lat2 = degrees_to_radians * B_[1]; const double lambda1p = degrees_to_radians * (lon - A_[0]); const double lambda2p = degrees_to_radians * (lon - B_[0]); - const double lambda = degrees_to_radians * normalise_longitude(B_[0] - A_[0], -180); + const double lambda = degrees_to_radians * util::normalise_longitude_to_minimum(B_[0] - A_[0], -180); double lat = atan((tan(lat2) * sin(lambda1p) - tan(lat1) * sin(lambda2p)) / (sin(lambda))); return {radians_to_degrees * lat}; @@ -89,14 +65,13 @@ std::vector GreatCircle::latitude(double lon) const { std::vector GreatCircle::longitude(double lat) const { using namespace std; - using types::is_approximately_equal; if (crossesPoles()) { const double lon = pole(A_[1]) ? B_[0] : A_[0]; return pole(lat) ? vector{lon} : vector{lon, lon + 180}; } - const double lon12 = degrees_to_radians * normalise_longitude(A_[0] - B_[0], -180); + const double lon12 = degrees_to_radians * util::normalise_longitude_to_minimum(A_[0] - B_[0], -180); const double lon1 = degrees_to_radians * A_[0]; const double lat1 = degrees_to_radians * A_[1]; const double lat2 = degrees_to_radians * B_[1]; @@ -105,18 +80,18 @@ std::vector GreatCircle::longitude(double lat) const { const double X = sin(lat1) * cos(lat2) * sin(lon12); const double Y = sin(lat1) * cos(lat2) * cos(lon12) - cos(lat1) * sin(lat2); - if (is_approximately_equal(X, 0.) && is_approximately_equal(Y, 0.)) { + if (util::approximately_equal(X, 0.) && util::approximately_equal(Y, 0.)) { return {}; // parallel (that is, equator) } const double lon0 = lon1 + atan2(Y, X); const double C = cos(lat1) * cos(lat2) * tan(lat3) * sin(lon12) / sqrt(X * X + Y * Y); - if (is_approximately_equal(C, -1.)) { + if (util::approximately_equal(C, -1.)) { return {radians_to_degrees * (lon0 + M_PI)}; } - if (is_approximately_equal(C, 1.)) { + if (util::approximately_equal(C, 1.)) { return {radians_to_degrees * lon0}; } @@ -132,7 +107,6 @@ bool GreatCircle::crossesPoles() const { return crossesPoles_; } -//---------------------------------------------------------------------------------------------------------------------- } // namespace geometry -} // namespace eckit +} // namespace grit diff --git a/src/grit/geometry/GreatCircle.h b/src/grit/geometry/GreatCircle.h index c23e09d2b..9d85afc2d 100644 --- a/src/grit/geometry/GreatCircle.h +++ b/src/grit/geometry/GreatCircle.h @@ -3,23 +3,24 @@ * * 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. */ -#ifndef GreatCircle_H -#define GreatCircle_H + +#pragma once + #include -#include "eckit/geometry/Point2.h" -//------------------------------------------------------------------------------------------------------ +#include "grit/types.h" -namespace eckit { + +namespace grit { namespace geometry { -//------------------------------------------------------------------------------------------------------ class GreatCircle { public: @@ -41,9 +42,6 @@ class GreatCircle { bool crossesPoles_; }; -//------------------------------------------------------------------------------------------------------ } // namespace geometry -} // namespace eckit - -#endif +} // namespace grit diff --git a/src/grit/geometry/Sphere.cc b/src/grit/geometry/Sphere.cc index bdd602035..41e867dae 100644 --- a/src/grit/geometry/Sphere.cc +++ b/src/grit/geometry/Sphere.cc @@ -3,53 +3,32 @@ * * 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 "eckit/geometry/Sphere.h" + +#include "grit/geometry/Sphere.h" #include +#include #include -#include #include -#include -#include "eckit/exception/Exceptions.h" -#include "eckit/geometry/GreatCircle.h" -#include "eckit/geometry/Point2.h" -#include "eckit/geometry/Point3.h" -#include "eckit/types/FloatCompare.h" +#include "grit/geometry/GreatCircle.h" +#include "grit/util.h" -//---------------------------------------------------------------------------------------------------------------------- -namespace eckit { +namespace grit { namespace geometry { -//---------------------------------------------------------------------------------------------------------------------- - -static double normalise_longitude(double a, const double& minimum) { - while (a < minimum) { - a += 360; - } - while (a >= minimum + 360) { - a -= 360; - } - return a; -} - -static const double radians_to_degrees = 180. * M_1_PI; - -static const double degrees_to_radians = M_PI / 180.; - -static constexpr std::streamsize max_digits10 = std::numeric_limits::max_digits10; inline double squared(double x) { return x * x; } -//---------------------------------------------------------------------------------------------------------------------- double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { using namespace std; @@ -70,19 +49,8 @@ double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { * } */ - if (!(-90. <= Alonlat[1] && Alonlat[1] <= 90.)) { - ostringstream oss; - oss.precision(max_digits10); - oss << "Invalid latitude " << Alonlat[1]; - throw BadValue(oss.str(), Here()); - } - - if (!(-90. <= Blonlat[1] && Blonlat[1] <= 90.)) { - ostringstream oss; - oss.precision(max_digits10); - oss << "Invalid latitude " << Blonlat[1]; - throw BadValue(oss.str(), Here()); - } + assert(-90. <= Alonlat[1] && Alonlat[1] <= 90. && "Invalid latitude"); + assert(-90. <= Blonlat[1] && Blonlat[1] <= 90. && "Invalid latitude"); const double phi1 = degrees_to_radians * Alonlat[1]; const double phi2 = degrees_to_radians * Blonlat[1]; @@ -95,24 +63,25 @@ double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { const double cos_lambda = cos(lambda); const double sin_lambda = sin(lambda); - const double angle = atan2(sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), - sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); + const double angle = + atan2(sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), + sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); - if (types::is_approximately_equal(angle, 0.)) { + if (util::approximately_equal(angle, 0.)) { return 0.; } - ASSERT(angle > 0.); + assert(angle > 0.); return angle; } double Sphere::centralAngle(const double& radius, const Point3& A, const Point3& B) { - ASSERT(radius > 0.); + assert(radius > 0.); // Δσ = 2 * asin( chord / 2 ) const double d2 = Point3::distance2(A, B); - if (types::is_approximately_equal(d2, 0.)) { + if (util::approximately_equal(d2, 0.)) { return 0.; } @@ -131,29 +100,28 @@ double Sphere::distance(const double& radius, const Point3& A, const Point3& B) } double Sphere::area(const double& radius) { - ASSERT(radius > 0.); + assert(radius > 0.); return 4. * M_PI * radius * radius; } double Sphere::area(const double& radius, const Point2& WestNorth, const Point2& EastSouth) { - ASSERT(radius > 0.); + assert(radius > 0.); // Set longitude fraction double W = WestNorth[0]; - double E = normalise_longitude(EastSouth[0], W); + double E = util::normalise_longitude_to_minimum(EastSouth[0], W); double longitude_range( - types::is_approximately_equal(W, E) && !types::is_approximately_equal(EastSouth[0], WestNorth[0]) ? 360. - : E - W); - ASSERT(longitude_range <= 360.); + util::approximately_equal(W, E) && !util::approximately_equal(EastSouth[0], WestNorth[0]) ? 360. : E - W); + assert(longitude_range <= 360.); double longitude_fraction = longitude_range / 360.; // Set latitude fraction double N = WestNorth[1]; double S = EastSouth[1]; - ASSERT(-90. <= N && N <= 90.); - ASSERT(-90. <= S && S <= 90.); - ASSERT(N >= S); + assert(-90. <= N && N <= 90.); + assert(-90. <= S && S <= 90.); + assert(N >= S); double latitude_fraction = 0.5 * (std::sin(degrees_to_radians * N) - std::sin(degrees_to_radians * S)); @@ -177,14 +145,8 @@ void Sphere::greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Poin } void Sphere::convertSphericalToCartesian(const double& radius, const Point2& Alonlat, Point3& B, double height) { - ASSERT(radius > 0.); - - if (!(-90. <= Alonlat[1] && Alonlat[1] <= 90.)) { - std::ostringstream oss; - oss.precision(max_digits10); - oss << "Invalid latitude " << Alonlat[1]; - throw BadValue(oss.str(), Here()); - } + assert(radius > 0.); + assert(-90. <= Alonlat[1] && Alonlat[1] <= 90. && "Invalid latitude"); /* * See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates @@ -199,9 +161,9 @@ void Sphere::convertSphericalToCartesian(const double& radius, const Point2& Alo * poles and quadrants. */ - const double lambda_deg = normalise_longitude(Alonlat[0], -180.); - const double lambda = degrees_to_radians * lambda_deg; - const double phi = degrees_to_radians * Alonlat[1]; + const double lambda_deg = util::normalise_longitude_to_minimum(Alonlat[0], -180.); + const double lambda = util::degrees_to_radians * lambda_deg; + const double phi = util::degrees_to_radians * Alonlat[1]; const double sin_phi = std::sin(phi); const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); @@ -214,19 +176,18 @@ void Sphere::convertSphericalToCartesian(const double& radius, const Point2& Alo } void Sphere::convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat) { - ASSERT(radius > 0.); + assert(radius > 0.); // numerical conditioning for both z (poles) and y const double x = A[0]; - const double y = types::is_approximately_equal(A[1], 0.) ? 0. : A[1]; + const double y = util::approximately_equal(A[1], 0.) ? 0. : A[1]; const double z = std::min(radius, std::max(-radius, A[2])) / radius; Blonlat[0] = radians_to_degrees * std::atan2(y, x); Blonlat[1] = radians_to_degrees * std::asin(z); } -//---------------------------------------------------------------------------------------------------------------------- } // namespace geometry -} // namespace eckit +} // namespace grit diff --git a/src/grit/geometry/Sphere.h b/src/grit/geometry/Sphere.h index bd79725e1..c7fd5bb56 100644 --- a/src/grit/geometry/Sphere.h +++ b/src/grit/geometry/Sphere.h @@ -3,25 +3,23 @@ * * 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. */ -#ifndef Sphere_H -#define Sphere_H -//------------------------------------------------------------------------------------------------------ +#pragma once + -namespace eckit { +namespace grit { namespace geometry { -//------------------------------------------------------------------------------------------------------ -class Point2; -class Point3; +struct Point2; +struct Point3; -//------------------------------------------------------------------------------------------------------ struct Sphere { /// Great-circle central angle between two points (latitude/longitude coordinates) in radians @@ -59,9 +57,6 @@ struct Sphere { static void convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat); }; -//------------------------------------------------------------------------------------------------------ } // namespace geometry -} // namespace eckit - -#endif +} // namespace grit diff --git a/src/grit/geometry/SphereT.h b/src/grit/geometry/SphereT.h index 5db54c3c3..d3b08f596 100644 --- a/src/grit/geometry/SphereT.h +++ b/src/grit/geometry/SphereT.h @@ -3,22 +3,22 @@ * * 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. */ -#ifndef SphereT_H -#define SphereT_H -#include "eckit/geometry/Sphere.h" +#pragma once + -//------------------------------------------------------------------------------------------------------ +#include "grit/geometry/Sphere.h" -namespace eckit { + +namespace grit { namespace geometry { -//------------------------------------------------------------------------------------------------------ /// Definition of a sphere parametrised with a geodetic datum template @@ -77,9 +77,6 @@ struct SphereT { } }; -//------------------------------------------------------------------------------------------------------ } // namespace geometry -} // namespace eckit - -#endif +} // namespace grit diff --git a/src/grit/geometry/UnitSphere.h b/src/grit/geometry/UnitSphere.h index eabe66e28..5eab2a669 100644 --- a/src/grit/geometry/UnitSphere.h +++ b/src/grit/geometry/UnitSphere.h @@ -3,43 +3,31 @@ * * 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. */ -#ifndef UnitSphere_H -#define UnitSphere_H -#include "eckit/geometry/SphereT.h" +#pragma once + +#include "grit/geometry/SphereT.h" -//------------------------------------------------------------------------------------------------------ -namespace eckit { +namespace grit { namespace geometry { -//------------------------------------------------------------------------------------------------------ /// Definition of a unit datum struct DatumUnit { - - /* C++-11: - static constexpr double radius() { - return 1.; - } - */ - - static double radius() { return 1.; } + static constexpr double radius() { return 1.; } }; -//------------------------------------------------------------------------------------------------------ /// Definition of a unit sphere -typedef SphereT UnitSphere; +using UnitSphere = SphereT; -//------------------------------------------------------------------------------------------------------ } // namespace geometry -} // namespace eckit - -#endif +} // namespace grit diff --git a/src/grit/types.h b/src/grit/types.h new file mode 100644 index 000000000..e63b63b18 --- /dev/null +++ b/src/grit/types.h @@ -0,0 +1,25 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + + +namespace grit { + + +using Point2 = std::array; +using Point3 = std::array; + + +} // namespace grit diff --git a/src/grit/util.h b/src/grit/util.h index a1a738b16..aa73a2d15 100644 --- a/src/grit/util.h +++ b/src/grit/util.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include #include #include @@ -29,6 +30,12 @@ bool approximately_equal(T x, T y, T eps = std::numeric_limits::epsilon()) { }; +static const double degrees_to_radians = M_PI / 180.; + + +static const double radians_to_degrees = 180. * M_1_PI; + + std::vector arange(double start, double stop, double step); From 70ee92ede07a06ef0902410baeb35442e294e8ec Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 Mar 2023 11:55:05 +0100 Subject: [PATCH 109/737] figure --- src/grit/CMakeLists.txt | 5 +- src/grit/geometry/EllipsoidOfRevolution.h | 32 --------- src/grit/geometry/GreatCircle.cc | 69 +++++++++---------- src/grit/geometry/GreatCircle.h | 8 +-- src/grit/geometry/Sphere.cc | 18 +++-- src/grit/geometry/Sphere.h | 10 +-- src/grit/geometry/SphereT.h | 6 +- src/grit/geometry/UnitSphere.h | 6 +- src/grit/types.h | 4 +- src/grit/util/gaussian_latitudes.cc | 3 +- src/grit/util/linspace.cc | 3 +- .../spherical_to_cartesian.cc} | 22 +++--- 12 files changed, 67 insertions(+), 119 deletions(-) delete mode 100644 src/grit/geometry/EllipsoidOfRevolution.h rename src/grit/{geometry/EllipsoidOfRevolution.cc => util/spherical_to_cartesian.cc} (69%) diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 6afc590c3..2a4a7ebb6 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -12,8 +12,6 @@ add_library(grit SHARED Scanner.h Transformation.cc Transformation.h - geometry/EllipsoidOfRevolution.cc - geometry/EllipsoidOfRevolution.h geometry/GreatCircle.cc geometry/GreatCircle.h geometry/Sphere.cc @@ -24,7 +22,8 @@ add_library(grit SHARED util.h util/arange.cc util/gaussian_latitudes.cc - util/linspace.cc) + util/linspace.cc + util/spherical_to_cartesian.cc) target_include_directories(grit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") diff --git a/src/grit/geometry/EllipsoidOfRevolution.h b/src/grit/geometry/EllipsoidOfRevolution.h deleted file mode 100644 index b02b15589..000000000 --- a/src/grit/geometry/EllipsoidOfRevolution.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - - -namespace grit { -namespace geometry { - - -struct Point2; -struct Point3; - - -struct EllipsoidOfRevolution { - // Convert elliptic coordinates to Cartesian - static void convertSphericalToCartesian(const double& radiusA, const double& radiusB, const Point2& Alonlat, - Point3& B, double height = 0.); -}; - - -} // namespace geometry -} // namespace grit diff --git a/src/grit/geometry/GreatCircle.cc b/src/grit/geometry/GreatCircle.cc index a32b0c619..e4e5cde72 100644 --- a/src/grit/geometry/GreatCircle.cc +++ b/src/grit/geometry/GreatCircle.cc @@ -19,8 +19,7 @@ #include "grit/util.h" -namespace grit { -namespace geometry { +namespace grit::geometry { static bool pole(double lat) { @@ -29,14 +28,12 @@ static bool pole(double lat) { GreatCircle::GreatCircle(const Point2& Alonlat, const Point2& Blonlat) : A_(Alonlat), B_(Blonlat) { - using namespace std; - const bool Apole = pole(A_[1]); const bool Bpole = pole(B_[1]); - const double lon12_deg = util::normalise_longitude_to_minimum(A_[0] - B_[0], -180); + const double lon12_deg = util::normalise_longitude_to_minimum(A_[0] - B_[0], -180.); const bool lon_same = Apole || Bpole || util::approximately_equal(lon12_deg, 0.); - const bool lon_opposite = Apole || Bpole || util::approximately_equal(abs(lon12_deg), 180.); + const bool lon_opposite = Apole || Bpole || util::approximately_equal(std::abs(lon12_deg), 180.); const bool lat_same = util::approximately_equal(A_[1], B_[1]); const bool lat_opposite = util::approximately_equal(A_[1], -B_[1]); @@ -46,67 +43,65 @@ GreatCircle::GreatCircle(const Point2& Alonlat, const Point2& Blonlat) : A_(Alon crossesPoles_ = lon_same || lon_opposite; } -std::vector GreatCircle::latitude(double lon) const { - using namespace std; +std::vector GreatCircle::latitude(double lon) const { if (crossesPoles()) { return {}; } - const double lat1 = degrees_to_radians * A_[1]; - const double lat2 = degrees_to_radians * B_[1]; - const double lambda1p = degrees_to_radians * (lon - A_[0]); - const double lambda2p = degrees_to_radians * (lon - B_[0]); - const double lambda = degrees_to_radians * util::normalise_longitude_to_minimum(B_[0] - A_[0], -180); + const double lat1 = util::degrees_to_radians * A_[1]; + const double lat2 = util::degrees_to_radians * B_[1]; + const double lambda1p = util::degrees_to_radians * (lon - A_[0]); + const double lambda2p = util::degrees_to_radians * (lon - B_[0]); + const double lambda = util::degrees_to_radians * util::normalise_longitude_to_minimum(B_[0] - A_[0], -180.); - double lat = atan((tan(lat2) * sin(lambda1p) - tan(lat1) * sin(lambda2p)) / (sin(lambda))); - return {radians_to_degrees * lat}; + double lat = + std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); + return {util::radians_to_degrees * lat}; } -std::vector GreatCircle::longitude(double lat) const { - using namespace std; +std::vector GreatCircle::longitude(double lat) const { if (crossesPoles()) { const double lon = pole(A_[1]) ? B_[0] : A_[0]; - return pole(lat) ? vector{lon} : vector{lon, lon + 180}; + if (pole(lat)) { + return {lon}; + } + + return {lon, lon + 180.}; } - const double lon12 = degrees_to_radians * util::normalise_longitude_to_minimum(A_[0] - B_[0], -180); - const double lon1 = degrees_to_radians * A_[0]; - const double lat1 = degrees_to_radians * A_[1]; - const double lat2 = degrees_to_radians * B_[1]; - const double lat3 = degrees_to_radians * lat; + const double lon12 = util::degrees_to_radians * util::normalise_longitude_to_minimum(A_[0] - B_[0], -180.); + const double lon1 = util::degrees_to_radians * A_[0]; + const double lat1 = util::degrees_to_radians * A_[1]; + const double lat2 = util::degrees_to_radians * B_[1]; + const double lat3 = util::degrees_to_radians * lat; - const double X = sin(lat1) * cos(lat2) * sin(lon12); - const double Y = sin(lat1) * cos(lat2) * cos(lon12) - cos(lat1) * sin(lat2); + const double X = std::sin(lat1) * std::cos(lat2) * std::sin(lon12); + const double Y = std::sin(lat1) * std::cos(lat2) * std::cos(lon12) - std::cos(lat1) * std::sin(lat2); if (util::approximately_equal(X, 0.) && util::approximately_equal(Y, 0.)) { return {}; // parallel (that is, equator) } - const double lon0 = lon1 + atan2(Y, X); - const double C = cos(lat1) * cos(lat2) * tan(lat3) * sin(lon12) / sqrt(X * X + Y * Y); + const double lon0 = lon1 + std::atan2(Y, X); + const double C = std::cos(lat1) * std::cos(lat2) * std::tan(lat3) * std::sin(lon12) / std::sqrt(X * X + Y * Y); if (util::approximately_equal(C, -1.)) { - return {radians_to_degrees * (lon0 + M_PI)}; + return {util::radians_to_degrees * (lon0 + M_PI)}; } if (util::approximately_equal(C, 1.)) { - return {radians_to_degrees * lon0}; + return {util::radians_to_degrees * lon0}; } if (-1 < C && C < 1) { - const double dlon = acos(C); - return {radians_to_degrees * (lon0 - dlon + 2 * M_PI), radians_to_degrees * (lon0 + dlon)}; + const double dlon = std::acos(C); + return {util::radians_to_degrees * (lon0 - dlon + 2 * M_PI), util::radians_to_degrees * (lon0 + dlon)}; } return {}; } -bool GreatCircle::crossesPoles() const { - return crossesPoles_; -} - -} // namespace geometry -} // namespace grit +} // namespace grit::geometry diff --git a/src/grit/geometry/GreatCircle.h b/src/grit/geometry/GreatCircle.h index 9d85afc2d..848f75763 100644 --- a/src/grit/geometry/GreatCircle.h +++ b/src/grit/geometry/GreatCircle.h @@ -18,8 +18,7 @@ #include "grit/types.h" -namespace grit { -namespace geometry { +namespace grit::geometry { class GreatCircle { @@ -33,7 +32,7 @@ class GreatCircle { /// Great circle longitude given latitude, see http://www.edwilliams.org/avform.htm#Par std::vector longitude(double lat) const; - bool crossesPoles() const; + bool crossesPoles() const { return crossesPoles_; } private: const Point2 A_; @@ -43,5 +42,4 @@ class GreatCircle { }; -} // namespace geometry -} // namespace grit +} // namespace grit::geometry diff --git a/src/grit/geometry/Sphere.cc b/src/grit/geometry/Sphere.cc index 41e867dae..2ae5cd54c 100644 --- a/src/grit/geometry/Sphere.cc +++ b/src/grit/geometry/Sphere.cc @@ -21,8 +21,7 @@ #include "grit/util.h" -namespace grit { -namespace geometry { +namespace grit::geometry { inline double squared(double x) { @@ -52,9 +51,9 @@ double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { assert(-90. <= Alonlat[1] && Alonlat[1] <= 90. && "Invalid latitude"); assert(-90. <= Blonlat[1] && Blonlat[1] <= 90. && "Invalid latitude"); - const double phi1 = degrees_to_radians * Alonlat[1]; - const double phi2 = degrees_to_radians * Blonlat[1]; - const double lambda = degrees_to_radians * (Blonlat[0] - Alonlat[0]); + const double phi1 = util::degrees_to_radians * Alonlat[1]; + const double phi2 = util::degrees_to_radians * Blonlat[1]; + const double lambda = util::degrees_to_radians * (Blonlat[0] - Alonlat[0]); const double cos_phi1 = cos(phi1); const double sin_phi1 = sin(phi1); @@ -123,7 +122,7 @@ double Sphere::area(const double& radius, const Point2& WestNorth, const Point2& assert(-90. <= S && S <= 90.); assert(N >= S); - double latitude_fraction = 0.5 * (std::sin(degrees_to_radians * N) - std::sin(degrees_to_radians * S)); + double latitude_fraction = 0.5 * (std::sin(util::degrees_to_radians * N) - std::sin(util::degrees_to_radians * S)); // Calculate area return area(radius) * latitude_fraction * longitude_fraction; @@ -184,10 +183,9 @@ void Sphere::convertCartesianToSpherical(const double& radius, const Point3& A, const double y = util::approximately_equal(A[1], 0.) ? 0. : A[1]; const double z = std::min(radius, std::max(-radius, A[2])) / radius; - Blonlat[0] = radians_to_degrees * std::atan2(y, x); - Blonlat[1] = radians_to_degrees * std::asin(z); + Blonlat[0] = util::radians_to_degrees * std::atan2(y, x); + Blonlat[1] = util::radians_to_degrees * std::asin(z); } -} // namespace geometry -} // namespace grit +} // namespace grit::geometry diff --git a/src/grit/geometry/Sphere.h b/src/grit/geometry/Sphere.h index c7fd5bb56..bdbb46e6b 100644 --- a/src/grit/geometry/Sphere.h +++ b/src/grit/geometry/Sphere.h @@ -12,13 +12,10 @@ #pragma once +#include "grit/types.h" -namespace grit { -namespace geometry { - -struct Point2; -struct Point3; +namespace grit::geometry { struct Sphere { @@ -58,5 +55,4 @@ struct Sphere { }; -} // namespace geometry -} // namespace grit +} // namespace grit::geometry diff --git a/src/grit/geometry/SphereT.h b/src/grit/geometry/SphereT.h index d3b08f596..05544011f 100644 --- a/src/grit/geometry/SphereT.h +++ b/src/grit/geometry/SphereT.h @@ -16,8 +16,7 @@ #include "grit/geometry/Sphere.h" -namespace grit { -namespace geometry { +namespace grit::geometry { /// Definition of a sphere parametrised with a geodetic datum @@ -78,5 +77,4 @@ struct SphereT { }; -} // namespace geometry -} // namespace grit +} // namespace grit::geometry diff --git a/src/grit/geometry/UnitSphere.h b/src/grit/geometry/UnitSphere.h index 5eab2a669..12b95a651 100644 --- a/src/grit/geometry/UnitSphere.h +++ b/src/grit/geometry/UnitSphere.h @@ -15,8 +15,7 @@ #include "grit/geometry/SphereT.h" -namespace grit { -namespace geometry { +namespace grit::geometry { /// Definition of a unit datum @@ -29,5 +28,4 @@ struct DatumUnit { using UnitSphere = SphereT; -} // namespace geometry -} // namespace grit +} // namespace grit::geometry diff --git a/src/grit/types.h b/src/grit/types.h index e63b63b18..568b51836 100644 --- a/src/grit/types.h +++ b/src/grit/types.h @@ -19,7 +19,9 @@ namespace grit { using Point2 = std::array; -using Point3 = std::array; +struct Point3 : std::array { + static double distance2(const Point3& a, const Point3& b) { return 0.; } +}; } // namespace grit diff --git a/src/grit/util/gaussian_latitudes.cc b/src/grit/util/gaussian_latitudes.cc index b3340fded..fe472bb85 100644 --- a/src/grit/util/gaussian_latitudes.cc +++ b/src/grit/util/gaussian_latitudes.cc @@ -10,12 +10,11 @@ */ -#include "grit/util.h" - #include #include #include #include +#include namespace grit::util { diff --git a/src/grit/util/linspace.cc b/src/grit/util/linspace.cc index 95cc41a6e..36c8b4fab 100644 --- a/src/grit/util/linspace.cc +++ b/src/grit/util/linspace.cc @@ -11,8 +11,7 @@ #include - -#include "grit/util.h" +#include namespace grit::util { diff --git a/src/grit/geometry/EllipsoidOfRevolution.cc b/src/grit/util/spherical_to_cartesian.cc similarity index 69% rename from src/grit/geometry/EllipsoidOfRevolution.cc rename to src/grit/util/spherical_to_cartesian.cc index 1899dab00..01d4dbbbb 100644 --- a/src/grit/geometry/EllipsoidOfRevolution.cc +++ b/src/grit/util/spherical_to_cartesian.cc @@ -10,28 +10,27 @@ */ -#include "grit/geometry/EllipsoidOfRevolution.h" - #include #include +#include "grit/types.h" +#include "grit/util.h" + -namespace grit { -namespace geometry { +namespace grit::geometry { -void EllipsoidOfRevolution::convertSphericalToCartesian(const double& a, const double& b, const Point2& Alonlat, - Point3& B, double height) { +void spherical_to_cartesian(Point3& B, double lon, double lat, double a, double b, double height) { assert(a > 0.); assert(b > 0.); - assert(-90. <= Alonlat[1] && Alonlat[1] <= 90. && "Invalid latitude"); + assert(-90. <= lat && lat <= 90. && "Invalid latitude"); // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) - const double lambda_deg = util::normalise_longitude_to_minimum(Alonlat[0], -180.); - const double lambda = degrees_to_radians * lambda_deg; - const double phi = degrees_to_radians * Alonlat[1]; + const double lambda_deg = util::normalise_longitude_to_minimum(lon, -180.); + const double lambda = util::degrees_to_radians * lambda_deg; + const double phi = util::degrees_to_radians * lat; const double sin_phi = std::sin(phi); const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); @@ -46,5 +45,4 @@ void EllipsoidOfRevolution::convertSphericalToCartesian(const double& a, const d } -} // namespace geometry -} // namespace grit +} // namespace grit::geometry From 32172ea82184ad28d7ba221edc7d78325030b1c2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 Mar 2023 14:23:32 +0100 Subject: [PATCH 110/737] figure --- src/grit/Figure.cc | 10 ++++++++-- src/grit/Figure.h | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/grit/Figure.cc b/src/grit/Figure.cc index dc2f5ac33..63b1698aa 100644 --- a/src/grit/Figure.cc +++ b/src/grit/Figure.cc @@ -25,8 +25,14 @@ Figure::Figure(double R) : Figure(R, R) {} Figure::Figure(double a, double b) : a_(a), b_(b), R_(util::approximately_equal(a, b) ? a : std::numeric_limits::signaling_NaN()) { - assert(a > 0. && "Figure::a > 0."); - assert(b > 0. && "Figure::b > 0."); + assert(0. < a && "Figure: 0. < a"); + assert(0. < b && "Figure: 0. < b"); +} + + +double Figure::R() const { + assert(sphere() && "Figure::R"); + return R_; } diff --git a/src/grit/Figure.h b/src/grit/Figure.h index 130769b67..717bd6874 100644 --- a/src/grit/Figure.h +++ b/src/grit/Figure.h @@ -43,7 +43,7 @@ class Figure { bool sphere() const { return R_ == R_; } double a() const { return a_; } double b() const { return b_; } - double R() const { return R_; } + double R() const; // -- Overridden methods // None From deff0f209ce931ad1371e567a22dd1241273fb8d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 Mar 2023 14:55:49 +0100 Subject: [PATCH 111/737] figure --- src/grit/CMakeLists.txt | 2 +- src/grit/Figure.cc | 1 + src/grit/Iterator.h | 4 ++-- src/grit/geometry/Sphere.cc | 29 ++++++++++++++++++----------- src/grit/types.h | 2 ++ 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 2a4a7ebb6..a51abfb75 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -5,7 +5,6 @@ add_library(grit SHARED Figure.h Iterator.cc Iterator.h - types.h Projection.cc Projection.h Scanner.cc @@ -18,6 +17,7 @@ add_library(grit SHARED geometry/Sphere.h geometry/SphereT.h geometry/UnitSphere.h + types.h util.cc util.h util/arange.cc diff --git a/src/grit/Figure.cc b/src/grit/Figure.cc index 63b1698aa..2abb9c9d4 100644 --- a/src/grit/Figure.cc +++ b/src/grit/Figure.cc @@ -13,6 +13,7 @@ #include "grit/Figure.h" #include +#include #include "grit/util.h" diff --git a/src/grit/Iterator.h b/src/grit/Iterator.h index 46d6edef1..83cc81c75 100644 --- a/src/grit/Iterator.h +++ b/src/grit/Iterator.h @@ -28,7 +28,7 @@ namespace grit { struct Iterator { - Iterator() {} + Iterator() = default; Iterator(const Iterator&) = delete; Iterator(Iterator&&) = delete; @@ -43,7 +43,7 @@ struct Iterator { return false; } - size_t pos_; + size_t pos_ = 0; std::unique_ptr scanner_; std::vector transformation_; diff --git a/src/grit/geometry/Sphere.cc b/src/grit/geometry/Sphere.cc index 2ae5cd54c..219ef678b 100644 --- a/src/grit/geometry/Sphere.cc +++ b/src/grit/geometry/Sphere.cc @@ -30,8 +30,6 @@ inline double squared(double x) { double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { - using namespace std; - /* * Δσ = atan( ((cos(ϕ2) * sin(Δλ))^2 + (cos(ϕ1) * sin(ϕ2) - sin(ϕ1) * cos(ϕ2) * cos(Δλ))^2) / * (sin(ϕ1) * sin(ϕ2) + cos(ϕ1) * cos(ϕ2) * cos(Δλ)) ) @@ -55,16 +53,16 @@ double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { const double phi2 = util::degrees_to_radians * Blonlat[1]; const double lambda = util::degrees_to_radians * (Blonlat[0] - Alonlat[0]); - const double cos_phi1 = cos(phi1); - const double sin_phi1 = sin(phi1); - const double cos_phi2 = cos(phi2); - const double sin_phi2 = sin(phi2); - const double cos_lambda = cos(lambda); - const double sin_lambda = sin(lambda); + const double cos_phi1 = std::cos(phi1); + const double sin_phi1 = std::sin(phi1); + const double cos_phi2 = std::cos(phi2); + const double sin_phi2 = std::sin(phi2); + const double cos_lambda = std::cos(lambda); + const double sin_lambda = std::sin(lambda); - const double angle = - atan2(sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), - sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); + const double angle = atan2( + std::sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), + sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); if (util::approximately_equal(angle, 0.)) { return 0.; @@ -74,6 +72,7 @@ double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { return angle; } + double Sphere::centralAngle(const double& radius, const Point3& A, const Point3& B) { assert(radius > 0.); @@ -90,19 +89,23 @@ double Sphere::centralAngle(const double& radius, const Point3& A, const Point3& return angle; } + double Sphere::distance(const double& radius, const Point2& Alonlat, const Point2& Blonlat) { return radius * centralAngle(Alonlat, Blonlat); } + double Sphere::distance(const double& radius, const Point3& A, const Point3& B) { return radius * centralAngle(radius, A, B); } + double Sphere::area(const double& radius) { assert(radius > 0.); return 4. * M_PI * radius * radius; } + double Sphere::area(const double& radius, const Point2& WestNorth, const Point2& EastSouth) { assert(radius > 0.); @@ -128,12 +131,14 @@ double Sphere::area(const double& radius, const Point2& WestNorth, const Point2& return area(radius) * latitude_fraction * longitude_fraction; } + double Sphere::greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clon) { GreatCircle gc(Alonlat, Blonlat); auto lat = gc.latitude(Clon); return lat.size() == 1 ? lat[0] : std::numeric_limits::signaling_NaN(); } + void Sphere::greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clat, double& Clon1, double& Clon2) { GreatCircle gc(Alonlat, Blonlat); @@ -143,6 +148,7 @@ void Sphere::greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Poin Clon2 = lon.size() > 1 ? lon[1] : std::numeric_limits::signaling_NaN(); } + void Sphere::convertSphericalToCartesian(const double& radius, const Point2& Alonlat, Point3& B, double height) { assert(radius > 0.); assert(-90. <= Alonlat[1] && Alonlat[1] <= 90. && "Invalid latitude"); @@ -174,6 +180,7 @@ void Sphere::convertSphericalToCartesian(const double& radius, const Point2& Alo B[2] = (radius + height) * sin_phi; } + void Sphere::convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat) { assert(radius > 0.); diff --git a/src/grit/types.h b/src/grit/types.h index 568b51836..934452301 100644 --- a/src/grit/types.h +++ b/src/grit/types.h @@ -19,6 +19,8 @@ namespace grit { using Point2 = std::array; + + struct Point3 : std::array { static double distance2(const Point3& a, const Point3& b) { return 0.; } }; From 6fe155f4d42a20d906282da2312aae87ab52adef Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 Mar 2023 14:56:06 +0100 Subject: [PATCH 112/737] bounding box --- src/grit/CMakeLists.txt | 2 + src/grit/geometry/BoundingBox.cc | 200 +++++++++++++++++++++++++++++++ src/grit/geometry/BoundingBox.h | 156 ++++++++++++++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 src/grit/geometry/BoundingBox.cc create mode 100644 src/grit/geometry/BoundingBox.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index a51abfb75..fe85ecf0a 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -11,6 +11,8 @@ add_library(grit SHARED Scanner.h Transformation.cc Transformation.h + geometry/BoundingBox.cc + geometry/BoundingBox.h geometry/GreatCircle.cc geometry/GreatCircle.h geometry/Sphere.cc diff --git a/src/grit/geometry/BoundingBox.cc b/src/grit/geometry/BoundingBox.cc new file mode 100644 index 000000000..f3c2745fb --- /dev/null +++ b/src/grit/geometry/BoundingBox.cc @@ -0,0 +1,200 @@ +/* + * (C) Copyright 1996- 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 "mir/util/BoundingBox.h" + +#include +#include + +#include "eckit/types/FloatCompare.h" +#include "eckit/utils/MD5.h" + +#include "mir/api/MIRJob.h" +#include "mir/param/MIRParametrisation.h" +#include "mir/util/Exceptions.h" +#include "mir/util/Grib.h" + + +namespace mir::util { + + +static double get(const param::MIRParametrisation& param, const char* key) { + double value = 0.; + ASSERT(param.get(key, value)); + return value; +} + + +BoundingBox::BoundingBox() : + north_(Latitude::NORTH_POLE), west_(Longitude::GREENWICH), south_(Latitude::SOUTH_POLE), east_(Longitude::GLOBE) {} + + +BoundingBox::BoundingBox(const Latitude& north, const Longitude& west, const Latitude& south, const Longitude& east) : + north_(north), west_(west), south_(south), east_(east) { + if (west_ != east_) { + auto eastNormalised = east_.normalise(west_); + if (eastNormalised == west_) { + eastNormalised += Longitude::GLOBE; + } + east_ = eastNormalised; + } + + ASSERT(west_ <= east_ && east_ <= west_ + Longitude::GLOBE); + ASSERT(Latitude::SOUTH_POLE <= south_ && south_ <= north_ && north_ <= Latitude::NORTH_POLE); +} + + +BoundingBox::BoundingBox(const param::MIRParametrisation& param) : + BoundingBox(get(param, "north"), get(param, "west"), get(param, "south"), get(param, "east")) {} + + +BoundingBox::BoundingBox(const BoundingBox&) = default; + + +bool BoundingBox::operator==(const BoundingBox& other) const { + return (north_ == other.north_) && (south_ == other.south_) && (west_ == other.west_) && (east_ == other.east_); +} + + +BoundingBox& BoundingBox::operator=(const BoundingBox& other) = default; + + +BoundingBox::~BoundingBox() = default; + + +void BoundingBox::print(std::ostream& out) const { + out << "BoundingBox[" + << "north=" << north_ << ",west=" << west_ << ",south=" << south_ << ",east=" << east_ << "]"; +} + + +void BoundingBox::fillGrib(grib_info& info) const { + // Warning: scanning mode not considered + info.grid.latitudeOfFirstGridPointInDegrees = north_.value(); + info.grid.longitudeOfFirstGridPointInDegrees = west_.value(); + info.grid.latitudeOfLastGridPointInDegrees = south_.value(); + info.grid.longitudeOfLastGridPointInDegrees = east_.value(); + + info.extra_set("expandBoundingBox", 1L); +} + + +void BoundingBox::hash(eckit::MD5& md5) const { + md5.add(north_); + md5.add(west_); + md5.add(south_); + md5.add(east_); +} + + +void BoundingBox::fillJob(api::MIRJob& job) const { + job.set("area", north_.value(), west_.value(), south_.value(), east_.value()); +} + + +bool BoundingBox::isPeriodicWestEast() const { + return (west_ != east_) && (west_ == east_.normalise(west_)); +} + + +bool BoundingBox::contains(const PointLatLon& p) const { + return contains(p.lat(), p.lon()); +} + + +bool BoundingBox::contains(const Point2& p) const { + // notice the order + return contains(p[0], p[1]); +} + + +bool BoundingBox::contains(const Latitude& lat, const Longitude& lon) const { + return (lat <= north_) && (lat >= south_) && (lon.normalise(west_) <= east_); +} + + +bool BoundingBox::contains(const BoundingBox& other) const { + + if (other.empty()) { + return contains(other.south(), other.west()); + } + + // check for West/East range (if non-periodic), then other's corners + if (east_ - west_ < other.east() - other.west() || east_ < other.east().normalise(west_)) { + return false; + } + + return contains(other.north(), other.west()) && contains(other.north(), other.east()) && + contains(other.south(), other.west()) && contains(other.south(), other.east()); +} + + +bool BoundingBox::intersects(BoundingBox& other) const { + + Latitude n = std::min(north_, other.north_); + Latitude s = std::max(south_, other.south_); + + bool intersectsSN = s <= n; + if (!intersectsSN) { + n = s; + } + + if (isPeriodicWestEast() && other.isPeriodicWestEast()) { + other = {n, other.west_, s, other.east_}; + return intersectsSN; + } + + Longitude w = std::min(west_, other.west_); + Longitude e = w; + + auto intersect = [](const BoundingBox& a, const BoundingBox& b, Longitude& w, Longitude& e) { + bool p = a.isPeriodicWestEast(); + if (p || b.isPeriodicWestEast()) { + w = (p ? b : a).west_; + e = (p ? b : a).east_; + return true; + } + + Longitude ref = b.west_.normalise(a.west_); + Longitude w_ = std::max(a.west_, ref); + Longitude e_ = std::min(a.east_, b.east_.normalise(ref)); + + if (w_ <= e_) { + w = w_; + e = e_; + return true; + } + return false; + }; + + bool intersectsWE = west_ <= other.west_ ? intersect(*this, other, w, e) || intersect(other, *this, w, e) + : intersect(other, *this, w, e) || intersect(*this, other, w, e); + + ASSERT(w <= e); + other = {n, w, s, e}; + + return intersectsSN && intersectsWE; +} + + +bool BoundingBox::empty() const { + return !eckit::types::is_strictly_greater(north_.value(), south_.value()) || + !eckit::types::is_strictly_greater(east_.value(), west_.value()); +} + + +void BoundingBox::makeName(std::ostream& out) const { + out << "-" << north_ << ":" << west_ << ":" << south_ << ":" << east_; +} + + +} // namespace mir::util diff --git a/src/grit/geometry/BoundingBox.h b/src/grit/geometry/BoundingBox.h new file mode 100644 index 000000000..f81fa196b --- /dev/null +++ b/src/grit/geometry/BoundingBox.h @@ -0,0 +1,156 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "mir/util/Types.h" + + +struct grib_info; +namespace eckit { +class MD5; +} +namespace mir { +namespace api { +class MIRJob; +} +namespace param { +class MIRParametrisation; +} +} // namespace mir + + +namespace mir::util { + + +class BoundingBox { +public: + // -- Exceptions + // None + + // -- Constructors + + BoundingBox(); + BoundingBox(const Latitude& north, const Longitude& west, const Latitude& south, const Longitude& east); + BoundingBox(const param::MIRParametrisation&); + BoundingBox(const BoundingBox&); + + // -- Destructor + + virtual ~BoundingBox(); + + // -- Convertors + // None + + // -- Operators + + BoundingBox& operator=(const BoundingBox&); + + bool operator==(const BoundingBox&) const; + + bool operator!=(const BoundingBox& other) const { return !operator==(other); } + + // -- Methods + + // DON'T IMPLEMENT SETTERS + + const Latitude& north() const { return north_; } + + const Longitude& west() const { return west_; } + + const Latitude& south() const { return south_; } + + const Longitude& east() const { return east_; } + + bool isPeriodicWestEast() const; + + bool contains(const PointLatLon&) const; + + bool contains(const Point2&) const; + + bool contains(const Latitude&, const Longitude&) const; + + bool contains(const BoundingBox&) const; + + bool intersects(BoundingBox&) const; + + bool empty() const; + + void fillGrib(grib_info&) const; + + void fillJob(api::MIRJob&) const; + + void hash(eckit::MD5&) const; + + void makeName(std::ostream&) const; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + virtual void print(std::ostream&) const; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None + +private: + // -- Members + + Latitude north_; + Longitude west_; + Latitude south_; + Longitude east_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + + friend std::ostream& operator<<(std::ostream& s, const BoundingBox& p) { + p.print(s); + return s; + } +}; + + +} // namespace mir::util From 99bf34824fdc93e6e53568e8eef7dda80cbdf00d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 Mar 2023 15:22:25 +0100 Subject: [PATCH 113/737] bounding box --- src/grit/geometry/BoundingBox.cc | 128 +++++++------------------------ src/grit/geometry/BoundingBox.h | 80 ++++++------------- 2 files changed, 50 insertions(+), 158 deletions(-) diff --git a/src/grit/geometry/BoundingBox.cc b/src/grit/geometry/BoundingBox.cc index f3c2745fb..a66a6cfd4 100644 --- a/src/grit/geometry/BoundingBox.cc +++ b/src/grit/geometry/BoundingBox.cc @@ -10,115 +10,44 @@ */ -#include "mir/util/BoundingBox.h" +#include "grit/geometry/BoundingBox.h" #include -#include +#include -#include "eckit/types/FloatCompare.h" -#include "eckit/utils/MD5.h" +#include "grit/util.h" -#include "mir/api/MIRJob.h" -#include "mir/param/MIRParametrisation.h" -#include "mir/util/Exceptions.h" -#include "mir/util/Grib.h" +namespace grit::geometry { -namespace mir::util { - -static double get(const param::MIRParametrisation& param, const char* key) { - double value = 0.; - ASSERT(param.get(key, value)); - return value; -} - - -BoundingBox::BoundingBox() : - north_(Latitude::NORTH_POLE), west_(Longitude::GREENWICH), south_(Latitude::SOUTH_POLE), east_(Longitude::GLOBE) {} - - -BoundingBox::BoundingBox(const Latitude& north, const Longitude& west, const Latitude& south, const Longitude& east) : +BoundingBox::BoundingBox(double north, double west, double south, double east) : north_(north), west_(west), south_(south), east_(east) { if (west_ != east_) { - auto eastNormalised = east_.normalise(west_); + auto eastNormalised = util::normalise_longitude_to_minimum(east, west); if (eastNormalised == west_) { - eastNormalised += Longitude::GLOBE; + eastNormalised += 360.; } east_ = eastNormalised; } - ASSERT(west_ <= east_ && east_ <= west_ + Longitude::GLOBE); - ASSERT(Latitude::SOUTH_POLE <= south_ && south_ <= north_ && north_ <= Latitude::NORTH_POLE); + assert(west_ <= east_ && east_ <= west_ + 360. && "BoundingBox: longitude range"); + assert(-90. <= south_ && south_ <= north_ && north_ <= 90. && "BoundingBox: latitude range"); } -BoundingBox::BoundingBox(const param::MIRParametrisation& param) : - BoundingBox(get(param, "north"), get(param, "west"), get(param, "south"), get(param, "east")) {} - - -BoundingBox::BoundingBox(const BoundingBox&) = default; - - bool BoundingBox::operator==(const BoundingBox& other) const { return (north_ == other.north_) && (south_ == other.south_) && (west_ == other.west_) && (east_ == other.east_); } -BoundingBox& BoundingBox::operator=(const BoundingBox& other) = default; - - -BoundingBox::~BoundingBox() = default; - - -void BoundingBox::print(std::ostream& out) const { - out << "BoundingBox[" - << "north=" << north_ << ",west=" << west_ << ",south=" << south_ << ",east=" << east_ << "]"; -} - - -void BoundingBox::fillGrib(grib_info& info) const { - // Warning: scanning mode not considered - info.grid.latitudeOfFirstGridPointInDegrees = north_.value(); - info.grid.longitudeOfFirstGridPointInDegrees = west_.value(); - info.grid.latitudeOfLastGridPointInDegrees = south_.value(); - info.grid.longitudeOfLastGridPointInDegrees = east_.value(); - - info.extra_set("expandBoundingBox", 1L); -} - - -void BoundingBox::hash(eckit::MD5& md5) const { - md5.add(north_); - md5.add(west_); - md5.add(south_); - md5.add(east_); -} - - -void BoundingBox::fillJob(api::MIRJob& job) const { - job.set("area", north_.value(), west_.value(), south_.value(), east_.value()); -} - - bool BoundingBox::isPeriodicWestEast() const { - return (west_ != east_) && (west_ == east_.normalise(west_)); + return (west_ != east_) && (west_ == util::normalise_longitude_to_minimum(east_, west_)); } -bool BoundingBox::contains(const PointLatLon& p) const { - return contains(p.lat(), p.lon()); -} - - -bool BoundingBox::contains(const Point2& p) const { - // notice the order - return contains(p[0], p[1]); -} - - -bool BoundingBox::contains(const Latitude& lat, const Longitude& lon) const { - return (lat <= north_) && (lat >= south_) && (lon.normalise(west_) <= east_); +bool BoundingBox::contains(double lat, double lon) const { + return (lat <= north_) && (lat >= south_) && (util::normalise_longitude_to_minimum(lon, west_) <= east_); } @@ -129,7 +58,8 @@ bool BoundingBox::contains(const BoundingBox& other) const { } // check for West/East range (if non-periodic), then other's corners - if (east_ - west_ < other.east() - other.west() || east_ < other.east().normalise(west_)) { + if (east_ - west_ < other.east() - other.west() || + east_ < util::normalise_longitude_to_minimum(other.east(), west_)) { return false; } @@ -139,9 +69,8 @@ bool BoundingBox::contains(const BoundingBox& other) const { bool BoundingBox::intersects(BoundingBox& other) const { - - Latitude n = std::min(north_, other.north_); - Latitude s = std::max(south_, other.south_); + auto n = std::min(north_, other.north_); + auto s = std::max(south_, other.south_); bool intersectsSN = s <= n; if (!intersectsSN) { @@ -153,10 +82,10 @@ bool BoundingBox::intersects(BoundingBox& other) const { return intersectsSN; } - Longitude w = std::min(west_, other.west_); - Longitude e = w; + auto w = std::min(west_, other.west_); + auto e = w; - auto intersect = [](const BoundingBox& a, const BoundingBox& b, Longitude& w, Longitude& e) { + auto intersect = [](const BoundingBox& a, const BoundingBox& b, double& w, double& e) { bool p = a.isPeriodicWestEast(); if (p || b.isPeriodicWestEast()) { w = (p ? b : a).west_; @@ -164,22 +93,23 @@ bool BoundingBox::intersects(BoundingBox& other) const { return true; } - Longitude ref = b.west_.normalise(a.west_); - Longitude w_ = std::max(a.west_, ref); - Longitude e_ = std::min(a.east_, b.east_.normalise(ref)); + auto ref = util::normalise_longitude_to_minimum(b.west_, a.west_); + auto w_ = std::max(a.west_, ref); + auto e_ = std::min(a.east_, util::normalise_longitude_to_minimum(b.east_, ref)); if (w_ <= e_) { w = w_; e = e_; return true; } + return false; }; bool intersectsWE = west_ <= other.west_ ? intersect(*this, other, w, e) || intersect(other, *this, w, e) : intersect(other, *this, w, e) || intersect(*this, other, w, e); - ASSERT(w <= e); + assert(w <= e && "BoundingBox::intersects: longitude range"); other = {n, w, s, e}; return intersectsSN && intersectsWE; @@ -187,14 +117,8 @@ bool BoundingBox::intersects(BoundingBox& other) const { bool BoundingBox::empty() const { - return !eckit::types::is_strictly_greater(north_.value(), south_.value()) || - !eckit::types::is_strictly_greater(east_.value(), west_.value()); -} - - -void BoundingBox::makeName(std::ostream& out) const { - out << "-" << north_ << ":" << west_ << ":" << south_ << ":" << east_; + return util::approximately_equal(north_, south_) || util::approximately_equal(west_, east_); } -} // namespace mir::util +} // namespace grit::geometry diff --git a/src/grit/geometry/BoundingBox.h b/src/grit/geometry/BoundingBox.h index f81fa196b..6dc97e97d 100644 --- a/src/grit/geometry/BoundingBox.h +++ b/src/grit/geometry/BoundingBox.h @@ -12,26 +12,8 @@ #pragma once -#include -#include "mir/util/Types.h" - - -struct grib_info; -namespace eckit { -class MD5; -} -namespace mir { -namespace api { -class MIRJob; -} -namespace param { -class MIRParametrisation; -} -} // namespace mir - - -namespace mir::util { +namespace grit::geometry { class BoundingBox { @@ -41,21 +23,26 @@ class BoundingBox { // -- Constructors - BoundingBox(); - BoundingBox(const Latitude& north, const Longitude& west, const Latitude& south, const Longitude& east); - BoundingBox(const param::MIRParametrisation&); - BoundingBox(const BoundingBox&); + BoundingBox(double north, double west, double south, double east); + + BoundingBox() : BoundingBox(90., 0., -90., 360.) {} + + BoundingBox(const BoundingBox&) = default; + + BoundingBox(BoundingBox&&) = default; // -- Destructor - virtual ~BoundingBox(); + virtual ~BoundingBox() = default; // -- Convertors // None // -- Operators - BoundingBox& operator=(const BoundingBox&); + BoundingBox& operator=(const BoundingBox&) = default; + + BoundingBox& operator=(BoundingBox&&) = default; bool operator==(const BoundingBox&) const; @@ -63,23 +50,17 @@ class BoundingBox { // -- Methods - // DON'T IMPLEMENT SETTERS + double north() const { return north_; } - const Latitude& north() const { return north_; } + double west() const { return west_; } - const Longitude& west() const { return west_; } + double south() const { return south_; } - const Latitude& south() const { return south_; } - - const Longitude& east() const { return east_; } + double east() const { return east_; } bool isPeriodicWestEast() const; - bool contains(const PointLatLon&) const; - - bool contains(const Point2&) const; - - bool contains(const Latitude&, const Longitude&) const; + bool contains(double lat, double lon) const; bool contains(const BoundingBox&) const; @@ -87,14 +68,6 @@ class BoundingBox { bool empty() const; - void fillGrib(grib_info&) const; - - void fillJob(api::MIRJob&) const; - - void hash(eckit::MD5&) const; - - void makeName(std::ostream&) const; - // -- Overridden methods // None @@ -109,8 +82,7 @@ class BoundingBox { // None // -- Methods - - virtual void print(std::ostream&) const; + // None // -- Overridden methods // None @@ -127,10 +99,10 @@ class BoundingBox { private: // -- Members - Latitude north_; - Longitude west_; - Latitude south_; - Longitude east_; + double north_; + double west_; + double south_; + double east_; // -- Methods // None @@ -145,12 +117,8 @@ class BoundingBox { // None // -- Friends - - friend std::ostream& operator<<(std::ostream& s, const BoundingBox& p) { - p.print(s); - return s; - } + // None }; -} // namespace mir::util +} // namespace grit::geometry From f499cb3eb5cffc0b2f865d225b0c00f68f1b31f5 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 Mar 2023 15:32:06 +0100 Subject: [PATCH 114/737] bounding box --- src/grit/CMakeLists.txt | 1 + src/grit/types.cc | 26 ++++++++++++++++++++++++++ src/grit/types.h | 13 ++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/grit/types.cc diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index fe85ecf0a..03e2d0d82 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -19,6 +19,7 @@ add_library(grit SHARED geometry/Sphere.h geometry/SphereT.h geometry/UnitSphere.h + types.cc types.h util.cc util.h diff --git a/src/grit/types.cc b/src/grit/types.cc new file mode 100644 index 000000000..79b49fa38 --- /dev/null +++ b/src/grit/types.cc @@ -0,0 +1,26 @@ +/* + * (C) Copyright 1996- 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 "grit/types.h" + +#include + + +namespace grit { + + +PointLatLon::PointLatLon(double lat, double lon) : array{lat, lon} { + assert(-90. <= lat && lat <= 90.); +} + + +} // namespace grit diff --git a/src/grit/types.h b/src/grit/types.h index 934452301..5560500dd 100644 --- a/src/grit/types.h +++ b/src/grit/types.h @@ -21,8 +21,19 @@ namespace grit { using Point2 = std::array; +struct PointLatLon : std::array { + PointLatLon(double lat, double lon); + + double lat() const { return operator[](0); } + double lon() const { return operator[](1); } +}; + + struct Point3 : std::array { - static double distance2(const Point3& a, const Point3& b) { return 0.; } + static double distance2(const Point3& a, const Point3& b) { + const array d{a[0] - b[0], a[1] - b[1], a[2] - b[2]}; + return d[0] * d[0] + d[2] * d[1] + d[2] * d[2]; + } }; From d0727c33c2ce42c2658a89e956a2dd88a02c06fe Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 Mar 2023 15:48:42 +0100 Subject: [PATCH 115/737] bounding box --- src/grit/geometry/BoundingBox.cc | 26 ++++++++++++-------------- src/grit/geometry/BoundingBox.h | 2 +- src/grit/types.h | 3 +-- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/grit/geometry/BoundingBox.cc b/src/grit/geometry/BoundingBox.cc index a66a6cfd4..68289bbeb 100644 --- a/src/grit/geometry/BoundingBox.cc +++ b/src/grit/geometry/BoundingBox.cc @@ -24,11 +24,8 @@ namespace grit::geometry { BoundingBox::BoundingBox(double north, double west, double south, double east) : north_(north), west_(west), south_(south), east_(east) { if (west_ != east_) { - auto eastNormalised = util::normalise_longitude_to_minimum(east, west); - if (eastNormalised == west_) { - eastNormalised += 360.; - } - east_ = eastNormalised; + auto e = util::normalise_longitude_to_minimum(east, west); + east_ = e == west_ ? (e + 360.) : e; } assert(west_ <= east_ && east_ <= west_ + 360. && "BoundingBox: longitude range"); @@ -36,35 +33,36 @@ BoundingBox::BoundingBox(double north, double west, double south, double east) : } +BoundingBox::BoundingBox() : BoundingBox(90., 0., -90., 360.) {} + + bool BoundingBox::operator==(const BoundingBox& other) const { - return (north_ == other.north_) && (south_ == other.south_) && (west_ == other.west_) && (east_ == other.east_); + return north_ == other.north_ && south_ == other.south_ && west_ == other.west_ && east_ == other.east_; } bool BoundingBox::isPeriodicWestEast() const { - return (west_ != east_) && (west_ == util::normalise_longitude_to_minimum(east_, west_)); + return west_ != east_ && west_ == util::normalise_longitude_to_minimum(east_, west_); } bool BoundingBox::contains(double lat, double lon) const { - return (lat <= north_) && (lat >= south_) && (util::normalise_longitude_to_minimum(lon, west_) <= east_); + return lat <= north_ && lat >= south_ && util::normalise_longitude_to_minimum(lon, west_) <= east_; } bool BoundingBox::contains(const BoundingBox& other) const { - if (other.empty()) { - return contains(other.south(), other.west()); + return contains(other.south_, other.west_); } // check for West/East range (if non-periodic), then other's corners - if (east_ - west_ < other.east() - other.west() || - east_ < util::normalise_longitude_to_minimum(other.east(), west_)) { + if (east_ - west_ < other.east_ - other.west_ || east_ < util::normalise_longitude_to_minimum(other.east_, west_)) { return false; } - return contains(other.north(), other.west()) && contains(other.north(), other.east()) && - contains(other.south(), other.west()) && contains(other.south(), other.east()); + return contains(other.north_, other.west_) && contains(other.north_, other.east_) && + contains(other.south_, other.west_) && contains(other.south_, other.east_); } diff --git a/src/grit/geometry/BoundingBox.h b/src/grit/geometry/BoundingBox.h index 6dc97e97d..0b77fb351 100644 --- a/src/grit/geometry/BoundingBox.h +++ b/src/grit/geometry/BoundingBox.h @@ -25,7 +25,7 @@ class BoundingBox { BoundingBox(double north, double west, double south, double east); - BoundingBox() : BoundingBox(90., 0., -90., 360.) {} + BoundingBox(); BoundingBox(const BoundingBox&) = default; diff --git a/src/grit/types.h b/src/grit/types.h index 5560500dd..2096ac6e7 100644 --- a/src/grit/types.h +++ b/src/grit/types.h @@ -31,8 +31,7 @@ struct PointLatLon : std::array { struct Point3 : std::array { static double distance2(const Point3& a, const Point3& b) { - const array d{a[0] - b[0], a[1] - b[1], a[2] - b[2]}; - return d[0] * d[0] + d[2] * d[1] + d[2] * d[2]; + return (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2]); } }; From e264d224c7a575391be8d66cc1f1d832ddaa2c99 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 Mar 2023 00:47:03 +0100 Subject: [PATCH 116/737] bounding box --- src/grit/geometry/BoundingBox.cc | 12 ++++ src/grit/geometry/BoundingBox.h | 2 + src/grit/geometry/GreatCircle.cc | 32 ++++----- src/grit/geometry/GreatCircle.h | 6 +- src/grit/geometry/Sphere.cc | 86 ++++++++----------------- src/grit/geometry/Sphere.h | 22 +++---- src/grit/geometry/SphereT.h | 34 ++++------ src/grit/types.h | 15 +++-- src/grit/util/spherical_to_cartesian.cc | 6 +- 9 files changed, 95 insertions(+), 120 deletions(-) diff --git a/src/grit/geometry/BoundingBox.cc b/src/grit/geometry/BoundingBox.cc index 68289bbeb..14f058d5d 100644 --- a/src/grit/geometry/BoundingBox.cc +++ b/src/grit/geometry/BoundingBox.cc @@ -15,6 +15,7 @@ #include #include +#include "grit/geometry/Sphere.h" #include "grit/util.h" @@ -119,4 +120,15 @@ bool BoundingBox::empty() const { } +double BoundingBox::area(double radius) const { + double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); + assert(0. <= lonf && lonf <= 1.); + + double latf = 0.5 * (std::sin(util::degrees_to_radians * north_) - std::sin(util::degrees_to_radians * south_)); + assert(0. <= latf && latf <= 1.); + + return Sphere::area(radius) * latf * lonf; +} + + } // namespace grit::geometry diff --git a/src/grit/geometry/BoundingBox.h b/src/grit/geometry/BoundingBox.h index 0b77fb351..bf8db0c73 100644 --- a/src/grit/geometry/BoundingBox.h +++ b/src/grit/geometry/BoundingBox.h @@ -68,6 +68,8 @@ class BoundingBox { bool empty() const; + double area(double radius) const; + // -- Overridden methods // None diff --git a/src/grit/geometry/GreatCircle.cc b/src/grit/geometry/GreatCircle.cc index e4e5cde72..966f6b41a 100644 --- a/src/grit/geometry/GreatCircle.cc +++ b/src/grit/geometry/GreatCircle.cc @@ -27,15 +27,15 @@ static bool pole(double lat) { } -GreatCircle::GreatCircle(const Point2& Alonlat, const Point2& Blonlat) : A_(Alonlat), B_(Blonlat) { - const bool Apole = pole(A_[1]); - const bool Bpole = pole(B_[1]); - const double lon12_deg = util::normalise_longitude_to_minimum(A_[0] - B_[0], -180.); +GreatCircle::GreatCircle(const PointLatLon& A, const PointLatLon& B) : A_(A), B_(B) { + const bool Apole = pole(A_.lat); + const bool Bpole = pole(B_.lat); + const double lon12_deg = util::normalise_longitude_to_minimum(A_.lon - B_.lon, -180.); const bool lon_same = Apole || Bpole || util::approximately_equal(lon12_deg, 0.); const bool lon_opposite = Apole || Bpole || util::approximately_equal(std::abs(lon12_deg), 180.); - const bool lat_same = util::approximately_equal(A_[1], B_[1]); - const bool lat_opposite = util::approximately_equal(A_[1], -B_[1]); + const bool lat_same = util::approximately_equal(A_.lat, B_.lat); + const bool lat_opposite = util::approximately_equal(A_.lat, -B_.lat); assert(!(lat_same && lon_same) && !(lat_opposite && lon_opposite) && "Great circle cannot be defined by points collinear with the centre"); @@ -49,11 +49,11 @@ std::vector GreatCircle::latitude(double lon) const { return {}; } - const double lat1 = util::degrees_to_radians * A_[1]; - const double lat2 = util::degrees_to_radians * B_[1]; - const double lambda1p = util::degrees_to_radians * (lon - A_[0]); - const double lambda2p = util::degrees_to_radians * (lon - B_[0]); - const double lambda = util::degrees_to_radians * util::normalise_longitude_to_minimum(B_[0] - A_[0], -180.); + const double lat1 = util::degrees_to_radians * A_.lat; + const double lat2 = util::degrees_to_radians * B_.lat; + const double lambda1p = util::degrees_to_radians * (lon - A_.lon); + const double lambda2p = util::degrees_to_radians * (lon - B_.lon); + const double lambda = util::degrees_to_radians * util::normalise_longitude_to_minimum(B_.lon - A_.lon, -180.); double lat = std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); @@ -63,7 +63,7 @@ std::vector GreatCircle::latitude(double lon) const { std::vector GreatCircle::longitude(double lat) const { if (crossesPoles()) { - const double lon = pole(A_[1]) ? B_[0] : A_[0]; + const double lon = pole(A_.lat) ? B_.lon : A_.lon; if (pole(lat)) { return {lon}; } @@ -71,10 +71,10 @@ std::vector GreatCircle::longitude(double lat) const { return {lon, lon + 180.}; } - const double lon12 = util::degrees_to_radians * util::normalise_longitude_to_minimum(A_[0] - B_[0], -180.); - const double lon1 = util::degrees_to_radians * A_[0]; - const double lat1 = util::degrees_to_radians * A_[1]; - const double lat2 = util::degrees_to_radians * B_[1]; + const double lon12 = util::degrees_to_radians * util::normalise_longitude_to_minimum(A_.lon - B_.lon, -180.); + const double lon1 = util::degrees_to_radians * A_.lon; + const double lat1 = util::degrees_to_radians * A_.lat; + const double lat2 = util::degrees_to_radians * B_.lat; const double lat3 = util::degrees_to_radians * lat; const double X = std::sin(lat1) * std::cos(lat2) * std::sin(lon12); diff --git a/src/grit/geometry/GreatCircle.h b/src/grit/geometry/GreatCircle.h index 848f75763..ec0dd1c12 100644 --- a/src/grit/geometry/GreatCircle.h +++ b/src/grit/geometry/GreatCircle.h @@ -24,7 +24,7 @@ namespace grit::geometry { class GreatCircle { public: /// Great circle given two points in geographic coordinates - GreatCircle(const Point2&, const Point2&); + GreatCircle(const PointLatLon&, const PointLatLon&); /// Great circle latitude given longitude, see http://www.edwilliams.org/avform.htm#Int std::vector latitude(double lon) const; @@ -35,8 +35,8 @@ class GreatCircle { bool crossesPoles() const { return crossesPoles_; } private: - const Point2 A_; - const Point2 B_; + const PointLatLon A_; + const PointLatLon B_; bool crossesPoles_; }; diff --git a/src/grit/geometry/Sphere.cc b/src/grit/geometry/Sphere.cc index 219ef678b..5d91251a8 100644 --- a/src/grit/geometry/Sphere.cc +++ b/src/grit/geometry/Sphere.cc @@ -29,7 +29,7 @@ inline double squared(double x) { } -double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { +double Sphere::centralAngle(const PointLatLon& A, const PointLatLon& B) { /* * Δσ = atan( ((cos(ϕ2) * sin(Δλ))^2 + (cos(ϕ1) * sin(ϕ2) - sin(ϕ1) * cos(ϕ2) * cos(Δλ))^2) / * (sin(ϕ1) * sin(ϕ2) + cos(ϕ1) * cos(ϕ2) * cos(Δλ)) ) @@ -46,12 +46,9 @@ double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { * } */ - assert(-90. <= Alonlat[1] && Alonlat[1] <= 90. && "Invalid latitude"); - assert(-90. <= Blonlat[1] && Blonlat[1] <= 90. && "Invalid latitude"); - - const double phi1 = util::degrees_to_radians * Alonlat[1]; - const double phi2 = util::degrees_to_radians * Blonlat[1]; - const double lambda = util::degrees_to_radians * (Blonlat[0] - Alonlat[0]); + const double phi1 = util::degrees_to_radians * A.lat; + const double phi2 = util::degrees_to_radians * B.lat; + const double lambda = util::degrees_to_radians * (B.lon - A.lon); const double cos_phi1 = std::cos(phi1); const double sin_phi1 = std::sin(phi1); @@ -90,8 +87,8 @@ double Sphere::centralAngle(const double& radius, const Point3& A, const Point3& } -double Sphere::distance(const double& radius, const Point2& Alonlat, const Point2& Blonlat) { - return radius * centralAngle(Alonlat, Blonlat); +double Sphere::distance(const double& radius, const PointLatLon& A, const PointLatLon& B) { + return radius * centralAngle(A, B); } @@ -106,52 +103,25 @@ double Sphere::area(const double& radius) { } -double Sphere::area(const double& radius, const Point2& WestNorth, const Point2& EastSouth) { - assert(radius > 0.); - - // Set longitude fraction - double W = WestNorth[0]; - double E = util::normalise_longitude_to_minimum(EastSouth[0], W); - double longitude_range( - util::approximately_equal(W, E) && !util::approximately_equal(EastSouth[0], WestNorth[0]) ? 360. : E - W); - assert(longitude_range <= 360.); - - double longitude_fraction = longitude_range / 360.; - - // Set latitude fraction - double N = WestNorth[1]; - double S = EastSouth[1]; - assert(-90. <= N && N <= 90.); - assert(-90. <= S && S <= 90.); - assert(N >= S); - - double latitude_fraction = 0.5 * (std::sin(util::degrees_to_radians * N) - std::sin(util::degrees_to_radians * S)); - - // Calculate area - return area(radius) * latitude_fraction * longitude_fraction; -} - - -double Sphere::greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clon) { - GreatCircle gc(Alonlat, Blonlat); - auto lat = gc.latitude(Clon); - return lat.size() == 1 ? lat[0] : std::numeric_limits::signaling_NaN(); +double Sphere::greatCircleLatitudeGivenLongitude(const PointLatLon& A, const PointLatLon& B, const double& lon) { + GreatCircle gc(A, B); + auto lats = gc.latitude(lon); + return lats.size() == 1 ? lats[0] : std::numeric_limits::signaling_NaN(); } -void Sphere::greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clat, - double& Clon1, double& Clon2) { - GreatCircle gc(Alonlat, Blonlat); - auto lon = gc.longitude(Clat); +void Sphere::greatCircleLongitudeGivenLatitude(const PointLatLon& A, const PointLatLon& B, const double& lat, + double& lon1, double& lon2) { + GreatCircle gc(A, B); + auto lons = gc.longitude(lat); - Clon1 = lon.size() > 0 ? lon[0] : std::numeric_limits::signaling_NaN(); - Clon2 = lon.size() > 1 ? lon[1] : std::numeric_limits::signaling_NaN(); + lon1 = lons.size() > 0 ? lons[0] : std::numeric_limits::signaling_NaN(); + lon2 = lons.size() > 1 ? lons[1] : std::numeric_limits::signaling_NaN(); } -void Sphere::convertSphericalToCartesian(const double& radius, const Point2& Alonlat, Point3& B, double height) { +void Sphere::convertSphericalToCartesian(const double& radius, const PointLatLon& A, Point3& B, double height) { assert(radius > 0.); - assert(-90. <= Alonlat[1] && Alonlat[1] <= 90. && "Invalid latitude"); /* * See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates @@ -166,32 +136,32 @@ void Sphere::convertSphericalToCartesian(const double& radius, const Point2& Alo * poles and quadrants. */ - const double lambda_deg = util::normalise_longitude_to_minimum(Alonlat[0], -180.); + const double lambda_deg = util::normalise_longitude_to_minimum(A.lon, -180.); const double lambda = util::degrees_to_radians * lambda_deg; - const double phi = util::degrees_to_radians * Alonlat[1]; + const double phi = util::degrees_to_radians * A.lat; const double sin_phi = std::sin(phi); const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); - B[0] = (radius + height) * cos_phi * cos_lambda; - B[1] = (radius + height) * cos_phi * sin_lambda; - B[2] = (radius + height) * sin_phi; + B.x = (radius + height) * cos_phi * cos_lambda; + B.y = (radius + height) * cos_phi * sin_lambda; + B.z = (radius + height) * sin_phi; } -void Sphere::convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat) { +void Sphere::convertCartesianToSpherical(const double& radius, const Point3& A, PointLatLon& B) { assert(radius > 0.); // numerical conditioning for both z (poles) and y - const double x = A[0]; - const double y = util::approximately_equal(A[1], 0.) ? 0. : A[1]; - const double z = std::min(radius, std::max(-radius, A[2])) / radius; + const double x = A.x; + const double y = util::approximately_equal(A.y, 0.) ? 0. : A.y; + const double z = std::min(radius, std::max(-radius, A.z)) / radius; - Blonlat[0] = util::radians_to_degrees * std::atan2(y, x); - Blonlat[1] = util::radians_to_degrees * std::asin(z); + B.lon = util::radians_to_degrees * std::atan2(y, x); + B.lat = util::radians_to_degrees * std::asin(z); } diff --git a/src/grit/geometry/Sphere.h b/src/grit/geometry/Sphere.h index bdbb46e6b..85a0251f2 100644 --- a/src/grit/geometry/Sphere.h +++ b/src/grit/geometry/Sphere.h @@ -20,38 +20,34 @@ namespace grit::geometry { struct Sphere { /// Great-circle central angle between two points (latitude/longitude coordinates) in radians - static double centralAngle(const Point2& Alonlat, const Point2& Blonlat); + static double centralAngle(const PointLatLon&, const PointLatLon&); /// Great-circle central angle between two points (Cartesian coordinates) in radians - static double centralAngle(const double& radius, const Point3& A, const Point3& B); + static double centralAngle(const double& radius, const Point3&, const Point3&); /// Great-circle distance between two points (latitude/longitude coordinates) in metres - static double distance(const double& radius, const Point2& Alonlat, const Point2& Blonlat); + static double distance(const double& radius, const PointLatLon&, const PointLatLon&); /// Great-circle distance between two points (Cartesian coordinates) in metres - static double distance(const double& radius, const Point3& A, const Point3& B); + static double distance(const double& radius, const Point3&, const Point3&); /// Surface area in square metres static double area(const double& radius); - /// Surface area between parallels and meridians defined by two points (longitude/latitude - /// coordinates) in square metres - static double area(const double& radius, const Point2& Alonlat, const Point2& Blonlat); - // Great-circle intermediate latitude provided two circle points (A, B) and intermediate // longitude (C) in degrees - static double greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clon); + static double greatCircleLatitudeGivenLongitude(const PointLatLon&, const PointLatLon&, const double& lon); // Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate // latitude (C) in degrees - static void greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clat, - double& Clon1, double& Clon2); + static void greatCircleLongitudeGivenLatitude(const PointLatLon&, const PointLatLon&, const double& lat, + double& lon1, double& lon2); // Convert spherical coordinates to Cartesian - static void convertSphericalToCartesian(const double& radius, const Point2& Alonlat, Point3& B, double height = 0.); + static void convertSphericalToCartesian(const double& radius, const PointLatLon&, Point3&, double height = 0.); // Convert Cartesian coordinates to spherical - static void convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat); + static void convertCartesianToSpherical(const double& radius, const Point3&, PointLatLon&); }; diff --git a/src/grit/geometry/SphereT.h b/src/grit/geometry/SphereT.h index 05544011f..cf02776c9 100644 --- a/src/grit/geometry/SphereT.h +++ b/src/grit/geometry/SphereT.h @@ -27,9 +27,7 @@ struct SphereT { inline static double radius() { return DATUM::radius(); } /// Great-circle central angle between two points (longitude/latitude coordinates) in radians - inline static double centralAngle(const Point2& Alonlat, const Point2& Blonlat) { - return Sphere::centralAngle(Alonlat, Blonlat); - } + inline static double centralAngle(const PointLatLon& A, const PointLatLon& B) { return Sphere::centralAngle(A, B); } /// Great-circle central angle between two points (Cartesian coordinates) in radians inline static double centralAngle(const Point3& A, const Point3& B) { @@ -37,8 +35,8 @@ struct SphereT { } /// Great-circle distance between two points (longitude/latitude coordinates) in metres - inline static double distance(const Point2& Alonlat, const Point2& Blonlat) { - return Sphere::distance(DATUM::radius(), Alonlat, Blonlat); + inline static double distance(const PointLatLon& A, const PointLatLon& B) { + return Sphere::distance(DATUM::radius(), A, B); } /// Great-circle distance between two points (Cartesian coordinates) in metres @@ -47,32 +45,26 @@ struct SphereT { /// Surface area in square metres inline static double area() { return Sphere::area(DATUM::radius()); } - /// Surface area between parallels and meridians defined by two points (longitude/latitude coordinates) in square - /// metres - inline static double area(const Point2& WestNorth, const Point2& EastSouth) { - return Sphere::area(DATUM::radius(), WestNorth, EastSouth); - } - // Great-circle intermediate latitude provided two circle points (A, B) and intermediate longitude (C) in degrees - inline static double greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, - const double& Clon) { - return Sphere::greatCircleLatitudeGivenLongitude(Alonlat, Blonlat, Clon); + inline static double greatCircleLatitudeGivenLongitude(const PointLatLon& A, const PointLatLon& B, + const double& lon) { + return Sphere::greatCircleLatitudeGivenLongitude(A, B, lon); } // Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate latitude (C) in degrees - inline static void greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, - const double& Clat, double& Clon1, double& Clon2) { - return Sphere::greatCircleLongitudeGivenLatitude(Alonlat, Blonlat, Clat, Clon1, Clon2); + inline static void greatCircleLongitudeGivenLatitude(const PointLatLon& A, const PointLatLon& B, const double& lat, + double& lon1, double& lon2) { + return Sphere::greatCircleLongitudeGivenLatitude(A, B, lat, lon1, lon2); } // Convert spherical coordinates to Cartesian - inline static void convertSphericalToCartesian(const Point2& Alonlat, Point3& B, double height = 0.) { - Sphere::convertSphericalToCartesian(DATUM::radius(), Alonlat, B, height); + inline static void convertSphericalToCartesian(const PointLatLon& A, Point3& B, double height = 0.) { + Sphere::convertSphericalToCartesian(DATUM::radius(), A, B, height); } // Convert Cartesian coordinates to spherical - inline static void convertCartesianToSpherical(const Point3& A, Point2& Blonlat) { - Sphere::convertCartesianToSpherical(DATUM::radius(), A, Blonlat); + inline static void convertCartesianToSpherical(const Point3& A, PointLatLon& B) { + Sphere::convertCartesianToSpherical(DATUM::radius(), A, B); } }; diff --git a/src/grit/types.h b/src/grit/types.h index 2096ac6e7..0ff4d02db 100644 --- a/src/grit/types.h +++ b/src/grit/types.h @@ -18,21 +18,24 @@ namespace grit { -using Point2 = std::array; - - struct PointLatLon : std::array { PointLatLon(double lat, double lon); - double lat() const { return operator[](0); } - double lon() const { return operator[](1); } + double& lat = operator[](0); + double& lon = operator[](1); }; struct Point3 : std::array { + using array::array; + static double distance2(const Point3& a, const Point3& b) { - return (a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]) + (a[2] - b[2]) * (a[2] - b[2]); + return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z); } + + double& x = operator[](0); + double& y = operator[](1); + double& z = operator[](2); }; diff --git a/src/grit/util/spherical_to_cartesian.cc b/src/grit/util/spherical_to_cartesian.cc index 01d4dbbbb..d0936406b 100644 --- a/src/grit/util/spherical_to_cartesian.cc +++ b/src/grit/util/spherical_to_cartesian.cc @@ -39,9 +39,9 @@ void spherical_to_cartesian(Point3& B, double lon, double lat, double a, double const double N_phi = a * a / std::sqrt(a * a * cos_phi * cos_phi + b * b * sin_phi * sin_phi); - B[0] = (N_phi + height) * cos_phi * cos_lambda; - B[1] = (N_phi + height) * cos_phi * sin_lambda; - B[2] = (N_phi * (b * b) / (a * a) + height) * sin_phi; + B.x = (N_phi + height) * cos_phi * cos_lambda; + B.y = (N_phi + height) * cos_phi * sin_lambda; + B.z = (N_phi * (b * b) / (a * a) + height) * sin_phi; } From 8106116ae5e582cdde517b2af66b03be834159e6 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 Mar 2023 09:00:38 +0100 Subject: [PATCH 117/737] figure --- src/grit/geometry/Sphere.cc | 40 ++++++++++--------------------------- src/grit/geometry/Sphere.h | 21 ++++++------------- src/grit/geometry/SphereT.h | 20 ++++--------------- src/grit/types.h | 2 +- 4 files changed, 21 insertions(+), 62 deletions(-) diff --git a/src/grit/geometry/Sphere.cc b/src/grit/geometry/Sphere.cc index 5d91251a8..e6c8f8cf4 100644 --- a/src/grit/geometry/Sphere.cc +++ b/src/grit/geometry/Sphere.cc @@ -15,9 +15,7 @@ #include #include #include -#include -#include "grit/geometry/GreatCircle.h" #include "grit/util.h" @@ -70,7 +68,7 @@ double Sphere::centralAngle(const PointLatLon& A, const PointLatLon& B) { } -double Sphere::centralAngle(const double& radius, const Point3& A, const Point3& B) { +double Sphere::centralAngle(double radius, const Point3& A, const Point3& B) { assert(radius > 0.); // Δσ = 2 * asin( chord / 2 ) @@ -83,44 +81,28 @@ double Sphere::centralAngle(const double& radius, const Point3& A, const Point3& const double chord = std::sqrt(d2) / radius; const double angle = std::asin(chord * 0.5) * 2.; + assert(angle > 0.); return angle; } -double Sphere::distance(const double& radius, const PointLatLon& A, const PointLatLon& B) { +double Sphere::distance(double radius, const PointLatLon& A, const PointLatLon& B) { return radius * centralAngle(A, B); } -double Sphere::distance(const double& radius, const Point3& A, const Point3& B) { +double Sphere::distance(double radius, const Point3& A, const Point3& B) { return radius * centralAngle(radius, A, B); } -double Sphere::area(const double& radius) { +double Sphere::area(double radius) { assert(radius > 0.); return 4. * M_PI * radius * radius; } -double Sphere::greatCircleLatitudeGivenLongitude(const PointLatLon& A, const PointLatLon& B, const double& lon) { - GreatCircle gc(A, B); - auto lats = gc.latitude(lon); - return lats.size() == 1 ? lats[0] : std::numeric_limits::signaling_NaN(); -} - - -void Sphere::greatCircleLongitudeGivenLatitude(const PointLatLon& A, const PointLatLon& B, const double& lat, - double& lon1, double& lon2) { - GreatCircle gc(A, B); - auto lons = gc.longitude(lat); - - lon1 = lons.size() > 0 ? lons[0] : std::numeric_limits::signaling_NaN(); - lon2 = lons.size() > 1 ? lons[1] : std::numeric_limits::signaling_NaN(); -} - - -void Sphere::convertSphericalToCartesian(const double& radius, const PointLatLon& A, Point3& B, double height) { +Point3 Sphere::convertSphericalToCartesian(double radius, const PointLatLon& A, double height) { assert(radius > 0.); /* @@ -145,13 +127,12 @@ void Sphere::convertSphericalToCartesian(const double& radius, const PointLatLon const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); - B.x = (radius + height) * cos_phi * cos_lambda; - B.y = (radius + height) * cos_phi * sin_lambda; - B.z = (radius + height) * sin_phi; + return {(radius + height) * cos_phi * cos_lambda, (radius + height) * cos_phi * sin_lambda, + (radius + height) * sin_phi}; } -void Sphere::convertCartesianToSpherical(const double& radius, const Point3& A, PointLatLon& B) { +PointLatLon Sphere::convertCartesianToSpherical(double radius, const Point3& A) { assert(radius > 0.); // numerical conditioning for both z (poles) and y @@ -160,8 +141,7 @@ void Sphere::convertCartesianToSpherical(const double& radius, const Point3& A, const double y = util::approximately_equal(A.y, 0.) ? 0. : A.y; const double z = std::min(radius, std::max(-radius, A.z)) / radius; - B.lon = util::radians_to_degrees * std::atan2(y, x); - B.lat = util::radians_to_degrees * std::asin(z); + return {util::radians_to_degrees * std::atan2(y, x), util::radians_to_degrees * std::asin(z)}; } diff --git a/src/grit/geometry/Sphere.h b/src/grit/geometry/Sphere.h index 85a0251f2..9e38bfd26 100644 --- a/src/grit/geometry/Sphere.h +++ b/src/grit/geometry/Sphere.h @@ -23,31 +23,22 @@ struct Sphere { static double centralAngle(const PointLatLon&, const PointLatLon&); /// Great-circle central angle between two points (Cartesian coordinates) in radians - static double centralAngle(const double& radius, const Point3&, const Point3&); + static double centralAngle(double radius, const Point3&, const Point3&); /// Great-circle distance between two points (latitude/longitude coordinates) in metres - static double distance(const double& radius, const PointLatLon&, const PointLatLon&); + static double distance(double radius, const PointLatLon&, const PointLatLon&); /// Great-circle distance between two points (Cartesian coordinates) in metres - static double distance(const double& radius, const Point3&, const Point3&); + static double distance(double radius, const Point3&, const Point3&); /// Surface area in square metres - static double area(const double& radius); - - // Great-circle intermediate latitude provided two circle points (A, B) and intermediate - // longitude (C) in degrees - static double greatCircleLatitudeGivenLongitude(const PointLatLon&, const PointLatLon&, const double& lon); - - // Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate - // latitude (C) in degrees - static void greatCircleLongitudeGivenLatitude(const PointLatLon&, const PointLatLon&, const double& lat, - double& lon1, double& lon2); + static double area(double radius); // Convert spherical coordinates to Cartesian - static void convertSphericalToCartesian(const double& radius, const PointLatLon&, Point3&, double height = 0.); + static Point3 convertSphericalToCartesian(double radius, const PointLatLon&, double height = 0.); // Convert Cartesian coordinates to spherical - static void convertCartesianToSpherical(const double& radius, const Point3&, PointLatLon&); + static PointLatLon convertCartesianToSpherical(double radius, const Point3&); }; diff --git a/src/grit/geometry/SphereT.h b/src/grit/geometry/SphereT.h index cf02776c9..93f944ef2 100644 --- a/src/grit/geometry/SphereT.h +++ b/src/grit/geometry/SphereT.h @@ -45,26 +45,14 @@ struct SphereT { /// Surface area in square metres inline static double area() { return Sphere::area(DATUM::radius()); } - // Great-circle intermediate latitude provided two circle points (A, B) and intermediate longitude (C) in degrees - inline static double greatCircleLatitudeGivenLongitude(const PointLatLon& A, const PointLatLon& B, - const double& lon) { - return Sphere::greatCircleLatitudeGivenLongitude(A, B, lon); - } - - // Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate latitude (C) in degrees - inline static void greatCircleLongitudeGivenLatitude(const PointLatLon& A, const PointLatLon& B, const double& lat, - double& lon1, double& lon2) { - return Sphere::greatCircleLongitudeGivenLatitude(A, B, lat, lon1, lon2); - } - // Convert spherical coordinates to Cartesian - inline static void convertSphericalToCartesian(const PointLatLon& A, Point3& B, double height = 0.) { - Sphere::convertSphericalToCartesian(DATUM::radius(), A, B, height); + inline static Point3 convertSphericalToCartesian(const PointLatLon& P, double height = 0.) { + return Sphere::convertSphericalToCartesian(DATUM::radius(), P, height); } // Convert Cartesian coordinates to spherical - inline static void convertCartesianToSpherical(const Point3& A, PointLatLon& B) { - Sphere::convertCartesianToSpherical(DATUM::radius(), A, B); + inline static PointLatLon convertCartesianToSpherical(const Point3& P) { + return Sphere::convertCartesianToSpherical(DATUM::radius(), P); } }; diff --git a/src/grit/types.h b/src/grit/types.h index 0ff4d02db..fd5b41696 100644 --- a/src/grit/types.h +++ b/src/grit/types.h @@ -27,7 +27,7 @@ struct PointLatLon : std::array { struct Point3 : std::array { - using array::array; + Point3(double x, double y, double z) : array{x, y, z} {} static double distance2(const Point3& a, const Point3& b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z); From 90cb95ff97232f3dd60e14b046f3d02ec701c360 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 Mar 2023 11:02:18 +0100 Subject: [PATCH 118/737] iterator --- src/grit/CMakeLists.txt | 5 ++- src/grit/Figure.h | 38 +++++++++++++++-- src/grit/Iterator.cc | 23 ++++++++++- src/grit/Iterator.h | 81 ++++++++++++++++++++++++++++++------- src/grit/Scanner.cc | 5 +++ src/grit/Scanner.h | 77 ++++++++++++++++++++++++++++++++--- src/grit/figure/Sphere.cc | 56 +++++++++++++++++++++++++ src/grit/figure/Sphere.h | 81 +++++++++++++++++++++++++++++++++++++ src/grit/figure/Spheroid.cc | 56 +++++++++++++++++++++++++ src/grit/figure/Spheroid.h | 81 +++++++++++++++++++++++++++++++++++++ src/grit/geometry/SphereT.h | 60 --------------------------- 11 files changed, 478 insertions(+), 85 deletions(-) create mode 100644 src/grit/figure/Sphere.cc create mode 100644 src/grit/figure/Sphere.h create mode 100644 src/grit/figure/Spheroid.cc create mode 100644 src/grit/figure/Spheroid.h delete mode 100644 src/grit/geometry/SphereT.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 03e2d0d82..17a01c4c2 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -11,13 +11,16 @@ add_library(grit SHARED Scanner.h Transformation.cc Transformation.h + figure/Sphere.cc + figure/Sphere.h + figure/Spheroid.cc + figure/Spheroid.h geometry/BoundingBox.cc geometry/BoundingBox.h geometry/GreatCircle.cc geometry/GreatCircle.h geometry/Sphere.cc geometry/Sphere.h - geometry/SphereT.h geometry/UnitSphere.h types.cc types.h diff --git a/src/grit/Figure.h b/src/grit/Figure.h index 717bd6874..c7e991135 100644 --- a/src/grit/Figure.h +++ b/src/grit/Figure.h @@ -12,6 +12,8 @@ #pragma once +#include "grit/types.h" + namespace grit { @@ -29,8 +31,12 @@ class Figure { explicit Figure(double R); explicit Figure(double a, double b); + Figure(const Figure&) = default; + Figure(Figure&&) = default; + // -- Destructor - // None + + virtual ~Figure() = default; // -- Convertors // None @@ -38,6 +44,9 @@ class Figure { // -- Operators // None + Figure& operator=(const Figure&) = default; + Figure& operator=(Figure&&) = default; + // -- Methods bool sphere() const { return R_ == R_; } @@ -45,6 +54,27 @@ class Figure { double b() const { return b_; } double R() const; + /// Great-circle central angle between two points (latitude/longitude coordinates) in radians + virtual double angle(const PointLatLon&, const PointLatLon&) const = 0; + + /// Great-circle central angle between two points (Cartesian coordinates) in radians + virtual double angle(const Point3&, const Point3&) const = 0; + + /// Great-circle distance between two points (latitude/longitude coordinates) in metres + virtual double distance(const PointLatLon&, const PointLatLon&) const = 0; + + /// Great-circle distance between two points (Cartesian coordinates) in metres + virtual double distance(const Point3&, const Point3&) const = 0; + + /// Surface area in square metres + virtual double area() const = 0; + + // Convert spherical coordinates to Cartesian + virtual Point3 ll_to_xyz(const PointLatLon&, double height) const = 0; + + // Convert Cartesian coordinates to spherical + virtual PointLatLon xyz_to_ll(const Point3&) const = 0; + // -- Overridden methods // None @@ -73,9 +103,9 @@ class Figure { private: // -- Members - const double a_; - const double b_; - const double R_; + double a_; + double b_; + double R_; // -- Methods // None diff --git a/src/grit/Iterator.cc b/src/grit/Iterator.cc index 708ba706d..89e5043db 100644 --- a/src/grit/Iterator.cc +++ b/src/grit/Iterator.cc @@ -12,5 +12,26 @@ #include "grit/Iterator.h" +#include -namespace grit {} // namespace grit +#include "grit/Figure.h" +#include "grit/Scanner.h" +#include "grit/Transformation.h" + + +namespace grit { + + +Iterator::Iterator(Scanner* scanner, Figure* figure, Transformation* transformation) : + scanner_(scanner), figure_(figure), transformation_(transformation) { + assert(bool(scanner) && "Iterator: bool(scanner)"); + assert(bool(figure) && "Iterator: bool(figure)"); +} + + +bool Iterator::operator++() { + return ++(*scanner_); +} + + +} // namespace grit diff --git a/src/grit/Iterator.h b/src/grit/Iterator.h index 83cc81c75..1b81c8322 100644 --- a/src/grit/Iterator.h +++ b/src/grit/Iterator.h @@ -10,11 +10,7 @@ */ -#include #include -#include - -#include "grit/Figure.h" namespace grit { @@ -27,8 +23,17 @@ struct Transformation; namespace grit { -struct Iterator { - Iterator() = default; +class Iterator { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + Iterator(Scanner* scanner, Figure* figure, Transformation* transformation); Iterator(const Iterator&) = delete; Iterator(Iterator&&) = delete; @@ -36,18 +41,66 @@ struct Iterator { Iterator& operator=(const Iterator&) = delete; Iterator& operator=(Iterator&&) = delete; + // -- Destructor + virtual ~Iterator() = delete; - bool operator++() { - pos_++; - return false; - } + // -- Convertors + // None + + // -- Operators + + bool operator++(); + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + std::unique_ptr scanner_; + std::unique_ptr
figure_; + std::unique_ptr transformation_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None - size_t pos_ = 0; + // -- Class methods + // None - std::unique_ptr scanner_; - std::vector transformation_; - // Figure figure_; + // -- Friends + // None }; diff --git a/src/grit/Scanner.cc b/src/grit/Scanner.cc index 14654ef64..c2618598e 100644 --- a/src/grit/Scanner.cc +++ b/src/grit/Scanner.cc @@ -16,6 +16,11 @@ namespace grit { +bool Scanner::operator++() { + return false; +} + + #if 0 Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) diff --git a/src/grit/Scanner.h b/src/grit/Scanner.h index c2c54cb30..55391ff28 100644 --- a/src/grit/Scanner.h +++ b/src/grit/Scanner.h @@ -13,14 +13,81 @@ namespace grit { -struct Scanner { - Scanner(const Scanner&) = default; - Scanner(Scanner&&) = default; +class Scanner { +public: + // -- Types + // None - Scanner& operator=(const Scanner&) = default; - Scanner& operator=(Scanner&&) = default; + // -- Exceptions + // None + + // -- Constructors + + Scanner(); + + Scanner(const Scanner&) = delete; + Scanner(Scanner&&) = delete; + + Scanner& operator=(const Scanner&) = delete; + Scanner& operator=(Scanner&&) = delete; + + // -- Destructor virtual ~Scanner() = default; + + // -- Convertors + // None + + // -- Operators + + virtual bool operator++(); + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None }; diff --git a/src/grit/figure/Sphere.cc b/src/grit/figure/Sphere.cc new file mode 100644 index 000000000..c4adbfdbe --- /dev/null +++ b/src/grit/figure/Sphere.cc @@ -0,0 +1,56 @@ +/* + * (C) Copyright 1996- 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 "grit/figure/Sphere.h" + +#include "grit/geometry/Sphere.h" + + +namespace grit::figure { + + +double Sphere::angle(const PointLatLon& A, const PointLatLon& B) const { + return geometry::Sphere::centralAngle(A, B); +} + + +double Sphere::angle(const Point3& A, const Point3& B) const { + return geometry::Sphere::centralAngle(R(), A, B); +} + + +double Sphere::distance(const PointLatLon& A, const PointLatLon& B) const { + return geometry::Sphere::distance(R(), A, B); +} + + +double Sphere::distance(const Point3& A, const Point3& B) const { + return geometry::Sphere::distance(R(), A, B); +} + + +double Sphere::area() const { + return geometry::Sphere::area(R()); +} + + +Point3 Sphere::ll_to_xyz(const PointLatLon& P, double height) const { + return geometry::Sphere::convertSphericalToCartesian(R(), P, height); +} + + +PointLatLon Sphere::xyz_to_ll(const Point3& P) const { + return geometry::Sphere::convertCartesianToSpherical(R(), P); +} + + +} // namespace grit::figure diff --git a/src/grit/figure/Sphere.h b/src/grit/figure/Sphere.h new file mode 100644 index 000000000..14bdadf11 --- /dev/null +++ b/src/grit/figure/Sphere.h @@ -0,0 +1,81 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/Figure.h" + + +namespace grit::figure { + + +class Sphere final : public Figure { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit Sphere(double R) : Figure(R) {} + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + double angle(const PointLatLon&, const PointLatLon&) const override; + double angle(const Point3&, const Point3&) const override; + double distance(const PointLatLon&, const PointLatLon&) const override; + double distance(const Point3&, const Point3&) const override; + double area() const override; + Point3 ll_to_xyz(const PointLatLon&, double height) const override; + PointLatLon xyz_to_ll(const Point3&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + +} // namespace grit::figure diff --git a/src/grit/figure/Spheroid.cc b/src/grit/figure/Spheroid.cc new file mode 100644 index 000000000..be260d308 --- /dev/null +++ b/src/grit/figure/Spheroid.cc @@ -0,0 +1,56 @@ +/* + * (C) Copyright 1996- 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 "grit/figure/Spheroid.h" + +#include + + +namespace grit::figure { + + +double Spheroid::angle(const PointLatLon& A, const PointLatLon& B) const { + assert(false && "Not implemented: Spheroid::angle"); +} + + +double Spheroid::angle(const Point3& A, const Point3& B) const { + assert(false && "Not implemented: Spheroid::angle"); +} + + +double Spheroid::distance(const PointLatLon& A, const PointLatLon& B) const { + assert(false && "Not implemented: Spheroid::distance"); +} + + +double Spheroid::distance(const Point3& A, const Point3& B) const { + assert(false && "Not implemented: Spheroid::distance"); +} + + +double Spheroid::area() const { + assert(false && "Not implemented: Spheroid::area"); +} + + +Point3 Spheroid::ll_to_xyz(const PointLatLon& P, double height) const { + assert(false && "Not implemented: Spheroid::ll_to_xyz"); +} + + +PointLatLon Spheroid::xyz_to_ll(const Point3& P) const { + assert(false && "Not implemented: Spheroid::xyz_to_ll"); +} + + +} // namespace grit::figure diff --git a/src/grit/figure/Spheroid.h b/src/grit/figure/Spheroid.h new file mode 100644 index 000000000..4ee1cd300 --- /dev/null +++ b/src/grit/figure/Spheroid.h @@ -0,0 +1,81 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/Figure.h" + + +namespace grit::figure { + + +class Spheroid final : public Figure { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit Spheroid(double a, double b) : Figure(a, b) {} + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + double angle(const PointLatLon&, const PointLatLon&) const override; + double angle(const Point3&, const Point3&) const override; + double distance(const PointLatLon&, const PointLatLon&) const override; + double distance(const Point3&, const Point3&) const override; + double area() const override; + Point3 ll_to_xyz(const PointLatLon&, double height) const override; + PointLatLon xyz_to_ll(const Point3&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + +} // namespace grit::figure diff --git a/src/grit/geometry/SphereT.h b/src/grit/geometry/SphereT.h deleted file mode 100644 index 93f944ef2..000000000 --- a/src/grit/geometry/SphereT.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - - -#include "grit/geometry/Sphere.h" - - -namespace grit::geometry { - - -/// Definition of a sphere parametrised with a geodetic datum -template -struct SphereT { - - /// Sphere radius in metres - inline static double radius() { return DATUM::radius(); } - - /// Great-circle central angle between two points (longitude/latitude coordinates) in radians - inline static double centralAngle(const PointLatLon& A, const PointLatLon& B) { return Sphere::centralAngle(A, B); } - - /// Great-circle central angle between two points (Cartesian coordinates) in radians - inline static double centralAngle(const Point3& A, const Point3& B) { - return Sphere::centralAngle(DATUM::radius(), A, B); - } - - /// Great-circle distance between two points (longitude/latitude coordinates) in metres - inline static double distance(const PointLatLon& A, const PointLatLon& B) { - return Sphere::distance(DATUM::radius(), A, B); - } - - /// Great-circle distance between two points (Cartesian coordinates) in metres - inline static double distance(const Point3& A, const Point3& B) { return Sphere::distance(DATUM::radius(), A, B); } - - /// Surface area in square metres - inline static double area() { return Sphere::area(DATUM::radius()); } - - // Convert spherical coordinates to Cartesian - inline static Point3 convertSphericalToCartesian(const PointLatLon& P, double height = 0.) { - return Sphere::convertSphericalToCartesian(DATUM::radius(), P, height); - } - - // Convert Cartesian coordinates to spherical - inline static PointLatLon convertCartesianToSpherical(const Point3& P) { - return Sphere::convertCartesianToSpherical(DATUM::radius(), P); - } -}; - - -} // namespace grit::geometry From c78c92a3a7c8d2399117588e3e6f60814687833c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 Mar 2023 11:34:23 +0100 Subject: [PATCH 119/737] exception --- src/grit/CMakeLists.txt | 1 + src/grit/Figure.cc | 8 +-- src/grit/Iterator.cc | 7 +-- src/grit/Projection.cc | 4 +- src/grit/Projection.h | 84 ++++++++++++++++++++++++- src/grit/Scanner.cc | 5 -- src/grit/Scanner.h | 2 +- src/grit/exception.h | 27 ++++++++ src/grit/figure/Spheroid.cc | 17 ++--- src/grit/geometry/BoundingBox.cc | 12 ++-- src/grit/geometry/GreatCircle.cc | 6 +- src/grit/geometry/Sphere.cc | 14 ++--- src/grit/types.cc | 4 +- src/grit/util/spherical_to_cartesian.cc | 8 +-- src/tools/grit-grib.cc | 22 +++---- 15 files changed, 164 insertions(+), 57 deletions(-) create mode 100644 src/grit/exception.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 17a01c4c2..cf85c6a53 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -11,6 +11,7 @@ add_library(grit SHARED Scanner.h Transformation.cc Transformation.h + exception.h figure/Sphere.cc figure/Sphere.h figure/Spheroid.cc diff --git a/src/grit/Figure.cc b/src/grit/Figure.cc index 2abb9c9d4..8f595294f 100644 --- a/src/grit/Figure.cc +++ b/src/grit/Figure.cc @@ -12,9 +12,9 @@ #include "grit/Figure.h" -#include #include +#include "grit/exception.h" #include "grit/util.h" @@ -26,13 +26,13 @@ Figure::Figure(double R) : Figure(R, R) {} Figure::Figure(double a, double b) : a_(a), b_(b), R_(util::approximately_equal(a, b) ? a : std::numeric_limits::signaling_NaN()) { - assert(0. < a && "Figure: 0. < a"); - assert(0. < b && "Figure: 0. < b"); + ASSERT(0. < a); + ASSERT(0. < b); } double Figure::R() const { - assert(sphere() && "Figure::R"); + ASSERT(sphere()); return R_; } diff --git a/src/grit/Iterator.cc b/src/grit/Iterator.cc index 89e5043db..82f79ea82 100644 --- a/src/grit/Iterator.cc +++ b/src/grit/Iterator.cc @@ -12,11 +12,10 @@ #include "grit/Iterator.h" -#include - #include "grit/Figure.h" #include "grit/Scanner.h" #include "grit/Transformation.h" +#include "grit/exception.h" namespace grit { @@ -24,8 +23,8 @@ namespace grit { Iterator::Iterator(Scanner* scanner, Figure* figure, Transformation* transformation) : scanner_(scanner), figure_(figure), transformation_(transformation) { - assert(bool(scanner) && "Iterator: bool(scanner)"); - assert(bool(figure) && "Iterator: bool(figure)"); + ASSERT(bool(scanner)); + ASSERT(bool(figure)); } diff --git a/src/grit/Projection.cc b/src/grit/Projection.cc index 7f8b737ff..a94feb665 100644 --- a/src/grit/Projection.cc +++ b/src/grit/Projection.cc @@ -10,7 +10,9 @@ */ -#include "grit/Transformation.h" +#include "grit/Projection.h" + +// #include <> namespace grit {} // namespace grit diff --git a/src/grit/Projection.h b/src/grit/Projection.h index 3642101d6..c1b0e5ff2 100644 --- a/src/grit/Projection.h +++ b/src/grit/Projection.h @@ -10,10 +10,92 @@ */ +#pragma once + +#include "grit/types.h" + + namespace grit { -struct Projection {}; +class Projection { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + Projection() noexcept = default; + + Projection(const Projection&) = default; + Projection(Projection&&) = default; + + // -- Destructor + + virtual ~Projection() = default; + + // -- Convertors + // None + + // -- Operators + + Projection& operator=(const Projection&) = default; + Projection& operator=(Projection&&) = default; + + // -- Methods + + virtual Point3 direct(const PointLatLon&) const; + virtual Point3 inverse(const Point3&) const; + virtual PointLatLon to_(const PointLatLon&) const; + virtual PointLatLon to_(const Point3&) const; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; } // namespace grit diff --git a/src/grit/Scanner.cc b/src/grit/Scanner.cc index c2618598e..14654ef64 100644 --- a/src/grit/Scanner.cc +++ b/src/grit/Scanner.cc @@ -16,11 +16,6 @@ namespace grit { -bool Scanner::operator++() { - return false; -} - - #if 0 Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) diff --git a/src/grit/Scanner.h b/src/grit/Scanner.h index 55391ff28..188a3bbe4 100644 --- a/src/grit/Scanner.h +++ b/src/grit/Scanner.h @@ -40,7 +40,7 @@ class Scanner { // -- Operators - virtual bool operator++(); + virtual bool operator++() = 0; // -- Methods // None diff --git a/src/grit/exception.h b/src/grit/exception.h new file mode 100644 index 000000000..4bb99dd17 --- /dev/null +++ b/src/grit/exception.h @@ -0,0 +1,27 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + + +namespace grit { + + +#define ASSERT assert +#define ASSERT_MSG(x, y) assert((x) && (y)) +#define NOTIMP throw std::runtime_error("Not implemented") + + +} // namespace grit diff --git a/src/grit/figure/Spheroid.cc b/src/grit/figure/Spheroid.cc index be260d308..7f2b917c1 100644 --- a/src/grit/figure/Spheroid.cc +++ b/src/grit/figure/Spheroid.cc @@ -12,44 +12,45 @@ #include "grit/figure/Spheroid.h" -#include + +#include "grit/exception.h" namespace grit::figure { double Spheroid::angle(const PointLatLon& A, const PointLatLon& B) const { - assert(false && "Not implemented: Spheroid::angle"); + NOTIMP; } double Spheroid::angle(const Point3& A, const Point3& B) const { - assert(false && "Not implemented: Spheroid::angle"); + NOTIMP; } double Spheroid::distance(const PointLatLon& A, const PointLatLon& B) const { - assert(false && "Not implemented: Spheroid::distance"); + NOTIMP; } double Spheroid::distance(const Point3& A, const Point3& B) const { - assert(false && "Not implemented: Spheroid::distance"); + NOTIMP; } double Spheroid::area() const { - assert(false && "Not implemented: Spheroid::area"); + NOTIMP; } Point3 Spheroid::ll_to_xyz(const PointLatLon& P, double height) const { - assert(false && "Not implemented: Spheroid::ll_to_xyz"); + NOTIMP; } PointLatLon Spheroid::xyz_to_ll(const Point3& P) const { - assert(false && "Not implemented: Spheroid::xyz_to_ll"); + NOTIMP; } diff --git a/src/grit/geometry/BoundingBox.cc b/src/grit/geometry/BoundingBox.cc index 14f058d5d..ac073e874 100644 --- a/src/grit/geometry/BoundingBox.cc +++ b/src/grit/geometry/BoundingBox.cc @@ -13,8 +13,8 @@ #include "grit/geometry/BoundingBox.h" #include -#include +#include "grit/exception.h" #include "grit/geometry/Sphere.h" #include "grit/util.h" @@ -29,8 +29,8 @@ BoundingBox::BoundingBox(double north, double west, double south, double east) : east_ = e == west_ ? (e + 360.) : e; } - assert(west_ <= east_ && east_ <= west_ + 360. && "BoundingBox: longitude range"); - assert(-90. <= south_ && south_ <= north_ && north_ <= 90. && "BoundingBox: latitude range"); + ASSERT_MSG(west_ <= east_ && east_ <= west_ + 360., "BoundingBox: longitude range"); + ASSERT_MSG(-90. <= south_ && south_ <= north_ && north_ <= 90., "BoundingBox: latitude range"); } @@ -108,7 +108,7 @@ bool BoundingBox::intersects(BoundingBox& other) const { bool intersectsWE = west_ <= other.west_ ? intersect(*this, other, w, e) || intersect(other, *this, w, e) : intersect(other, *this, w, e) || intersect(*this, other, w, e); - assert(w <= e && "BoundingBox::intersects: longitude range"); + ASSERT_MSG(w <= e, "BoundingBox::intersects: longitude range"); other = {n, w, s, e}; return intersectsSN && intersectsWE; @@ -122,10 +122,10 @@ bool BoundingBox::empty() const { double BoundingBox::area(double radius) const { double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); - assert(0. <= lonf && lonf <= 1.); + ASSERT(0. <= lonf && lonf <= 1.); double latf = 0.5 * (std::sin(util::degrees_to_radians * north_) - std::sin(util::degrees_to_radians * south_)); - assert(0. <= latf && latf <= 1.); + ASSERT(0. <= latf && latf <= 1.); return Sphere::area(radius) * latf * lonf; } diff --git a/src/grit/geometry/GreatCircle.cc b/src/grit/geometry/GreatCircle.cc index 966f6b41a..37aa5e5e4 100644 --- a/src/grit/geometry/GreatCircle.cc +++ b/src/grit/geometry/GreatCircle.cc @@ -12,10 +12,10 @@ #include "grit/geometry/GreatCircle.h" -#include #include #include +#include "grit/exception.h" #include "grit/util.h" @@ -37,8 +37,8 @@ GreatCircle::GreatCircle(const PointLatLon& A, const PointLatLon& B) : A_(A), B_ const bool lat_same = util::approximately_equal(A_.lat, B_.lat); const bool lat_opposite = util::approximately_equal(A_.lat, -B_.lat); - assert(!(lat_same && lon_same) && !(lat_opposite && lon_opposite) && - "Great circle cannot be defined by points collinear with the centre"); + ASSERT_MSG(!(lat_same && lon_same) && !(lat_opposite && lon_opposite), + "Great circle cannot be defined by points collinear with the centre"); crossesPoles_ = lon_same || lon_opposite; } diff --git a/src/grit/geometry/Sphere.cc b/src/grit/geometry/Sphere.cc index e6c8f8cf4..90c771b7b 100644 --- a/src/grit/geometry/Sphere.cc +++ b/src/grit/geometry/Sphere.cc @@ -13,9 +13,9 @@ #include "grit/geometry/Sphere.h" #include -#include #include +#include "grit/exception.h" #include "grit/util.h" @@ -63,13 +63,13 @@ double Sphere::centralAngle(const PointLatLon& A, const PointLatLon& B) { return 0.; } - assert(angle > 0.); + ASSERT(angle > 0.); return angle; } double Sphere::centralAngle(double radius, const Point3& A, const Point3& B) { - assert(radius > 0.); + ASSERT(radius > 0.); // Δσ = 2 * asin( chord / 2 ) @@ -81,7 +81,7 @@ double Sphere::centralAngle(double radius, const Point3& A, const Point3& B) { const double chord = std::sqrt(d2) / radius; const double angle = std::asin(chord * 0.5) * 2.; - assert(angle > 0.); + ASSERT(angle > 0.); return angle; } @@ -97,13 +97,13 @@ double Sphere::distance(double radius, const Point3& A, const Point3& B) { double Sphere::area(double radius) { - assert(radius > 0.); + ASSERT(radius > 0.); return 4. * M_PI * radius * radius; } Point3 Sphere::convertSphericalToCartesian(double radius, const PointLatLon& A, double height) { - assert(radius > 0.); + ASSERT(radius > 0.); /* * See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates @@ -133,7 +133,7 @@ Point3 Sphere::convertSphericalToCartesian(double radius, const PointLatLon& A, PointLatLon Sphere::convertCartesianToSpherical(double radius, const Point3& A) { - assert(radius > 0.); + ASSERT(radius > 0.); // numerical conditioning for both z (poles) and y diff --git a/src/grit/types.cc b/src/grit/types.cc index 79b49fa38..f2b7a7472 100644 --- a/src/grit/types.cc +++ b/src/grit/types.cc @@ -12,14 +12,14 @@ #include "grit/types.h" -#include +#include "grit/exception.h" namespace grit { PointLatLon::PointLatLon(double lat, double lon) : array{lat, lon} { - assert(-90. <= lat && lat <= 90.); + ASSERT_MSG(-90. <= lat && lat <= 90., "PointLatLon: invalid latitude"); } diff --git a/src/grit/util/spherical_to_cartesian.cc b/src/grit/util/spherical_to_cartesian.cc index d0936406b..d6763cd44 100644 --- a/src/grit/util/spherical_to_cartesian.cc +++ b/src/grit/util/spherical_to_cartesian.cc @@ -10,9 +10,9 @@ */ -#include #include +#include "grit/exception.h" #include "grit/types.h" #include "grit/util.h" @@ -21,9 +21,9 @@ namespace grit::geometry { void spherical_to_cartesian(Point3& B, double lon, double lat, double a, double b, double height) { - assert(a > 0.); - assert(b > 0.); - assert(-90. <= lat && lat <= 90. && "Invalid latitude"); + ASSERT(a > 0.); + ASSERT(b > 0.); + ASSERT_MSG(-90. <= lat && lat <= 90., "Invalid latitude"); // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) diff --git a/src/tools/grit-grib.cc b/src/tools/grit-grib.cc index 14f9bca0c..d43ab399c 100644 --- a/src/tools/grit-grib.cc +++ b/src/tools/grit-grib.cc @@ -12,13 +12,13 @@ #include "eccodes.h" -#include #include #include #include #include #include +#include "grit/exception.h" #include "grit/grit.h" @@ -56,7 +56,7 @@ struct grib_type : std::unique_ptr } double value = 0; - assert(CODES_SUCCESS == codes_get_double(get(), key.c_str(), &value)); + ASSERT(CODES_SUCCESS == codes_get_double(get(), key.c_str(), &value)); cache_double[key] = value; return value; @@ -68,7 +68,7 @@ struct grib_type : std::unique_ptr } long value = 0; - assert(CODES_SUCCESS == codes_get_long(get(), key.c_str(), &value)); + ASSERT(CODES_SUCCESS == codes_get_long(get(), key.c_str(), &value)); cache_long[key] = value; return value; @@ -76,14 +76,14 @@ struct grib_type : std::unique_ptr size_t get_size_t(const std::string& key) const { auto value = get_long(key); - assert(value >= 0); + ASSERT(value >= 0); return static_cast(value); } std::string get_string(const std::string& key) const { char mesg[1024]; auto length = sizeof(mesg); - assert(CODES_SUCCESS == codes_get_string(get(), key.c_str(), mesg, &length)); + ASSERT(CODES_SUCCESS == codes_get_string(get(), key.c_str(), mesg, &length)); const std::string value(mesg); cache_string[key] = value; @@ -94,7 +94,7 @@ struct grib_type : std::unique_ptr mutable std::map cache_long; mutable std::map cache_string; - explicit grib_type(codes_handle* h) : t(h, &codes_handle_delete) { assert(*this); } + explicit grib_type(codes_handle* h) : t(h, &codes_handle_delete) { ASSERT(*this); } std::string type() const { return get_string("gridType"); } @@ -113,8 +113,8 @@ struct grib_type : std::unique_ptr using t = std::unique_ptr; explicit iterator(codes_handle* h) : t(codes_grib_iterator_new(h, 0, &err), &codes_grib_iterator_delete) { - assert(CODES_SUCCESS == err); - assert(*this); + ASSERT(CODES_SUCCESS == err); + ASSERT(*this); } bool next() { return codes_grib_iterator_next(get(), &lat, &lon, &value) > 0; } @@ -132,10 +132,10 @@ struct grib_type : std::unique_ptr void test_grib_iterator(codes_handle* h) { - assert(h != nullptr); + ASSERT(h != nullptr); // long bitmapPresent = 0; - // assert(CODES_SUCCESS == codes_get_long(h, "bitmapPresent", &bitmapPresent)); + // ASSERT(CODES_SUCCESS == codes_get_long(h, "bitmapPresent", &bitmapPresent)); } @@ -149,7 +149,7 @@ int main(int argc, const char* argv[]) { for (int i = 1; i < argc; ++i) { auto* in = std::fopen(argv[i], "rb"); - assert(in != nullptr && "unable to open file"); + ASSERT(in != nullptr && "unable to open file"); int err = 0; for (codes_handle* h = nullptr; nullptr != (h = codes_handle_new_from_file(nullptr, in, PRODUCT_GRIB, &err));) { From adc333a5ec2afc65ba89acd39a5fd18eec090716 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 Mar 2023 11:52:50 +0100 Subject: [PATCH 120/737] figure --- src/grit/CMakeLists.txt | 5 +- src/grit/figure/Sphere.cc | 8 +-- src/grit/geometry/Sphere.cc | 54 +++++------------- src/grit/geometry/Sphere.h | 8 +-- .../Spheroid.cc} | 36 ++++++++---- src/grit/geometry/Spheroid.h | 57 +++++++++++++++++++ 6 files changed, 107 insertions(+), 61 deletions(-) rename src/grit/{util/spherical_to_cartesian.cc => geometry/Spheroid.cc} (50%) create mode 100644 src/grit/geometry/Spheroid.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index cf85c6a53..97e39110a 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -22,6 +22,8 @@ add_library(grit SHARED geometry/GreatCircle.h geometry/Sphere.cc geometry/Sphere.h + geometry/Spheroid.cc + geometry/Spheroid.h geometry/UnitSphere.h types.cc types.h @@ -29,8 +31,7 @@ add_library(grit SHARED util.h util/arange.cc util/gaussian_latitudes.cc - util/linspace.cc - util/spherical_to_cartesian.cc) + util/linspace.cc) target_include_directories(grit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") diff --git a/src/grit/figure/Sphere.cc b/src/grit/figure/Sphere.cc index c4adbfdbe..bb7589a61 100644 --- a/src/grit/figure/Sphere.cc +++ b/src/grit/figure/Sphere.cc @@ -19,12 +19,12 @@ namespace grit::figure { double Sphere::angle(const PointLatLon& A, const PointLatLon& B) const { - return geometry::Sphere::centralAngle(A, B); + return geometry::Sphere::angle(A, B); } double Sphere::angle(const Point3& A, const Point3& B) const { - return geometry::Sphere::centralAngle(R(), A, B); + return geometry::Sphere::angle(R(), A, B); } @@ -44,12 +44,12 @@ double Sphere::area() const { Point3 Sphere::ll_to_xyz(const PointLatLon& P, double height) const { - return geometry::Sphere::convertSphericalToCartesian(R(), P, height); + return geometry::Sphere::ll_to_xyz(R(), P, height); } PointLatLon Sphere::xyz_to_ll(const Point3& P) const { - return geometry::Sphere::convertCartesianToSpherical(R(), P); + return geometry::Sphere::xyz_to_ll(R(), P); } diff --git a/src/grit/geometry/Sphere.cc b/src/grit/geometry/Sphere.cc index 90c771b7b..36ae3c79e 100644 --- a/src/grit/geometry/Sphere.cc +++ b/src/grit/geometry/Sphere.cc @@ -16,6 +16,7 @@ #include #include "grit/exception.h" +#include "grit/geometry/Spheroid.h" #include "grit/util.h" @@ -27,7 +28,7 @@ inline double squared(double x) { } -double Sphere::centralAngle(const PointLatLon& A, const PointLatLon& B) { +double Sphere::angle(const PointLatLon& A, const PointLatLon& B) { /* * Δσ = atan( ((cos(ϕ2) * sin(Δλ))^2 + (cos(ϕ1) * sin(ϕ2) - sin(ϕ1) * cos(ϕ2) * cos(Δλ))^2) / * (sin(ϕ1) * sin(ϕ2) + cos(ϕ1) * cos(ϕ2) * cos(Δλ)) ) @@ -55,20 +56,20 @@ double Sphere::centralAngle(const PointLatLon& A, const PointLatLon& B) { const double cos_lambda = std::cos(lambda); const double sin_lambda = std::sin(lambda); - const double angle = atan2( + const double sigma = atan2( std::sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); - if (util::approximately_equal(angle, 0.)) { + if (util::approximately_equal(sigma, 0.)) { return 0.; } - ASSERT(angle > 0.); - return angle; + ASSERT(sigma > 0.); + return sigma; } -double Sphere::centralAngle(double radius, const Point3& A, const Point3& B) { +double Sphere::angle(double radius, const Point3& A, const Point3& B) { ASSERT(radius > 0.); // Δσ = 2 * asin( chord / 2 ) @@ -79,20 +80,20 @@ double Sphere::centralAngle(double radius, const Point3& A, const Point3& B) { } const double chord = std::sqrt(d2) / radius; - const double angle = std::asin(chord * 0.5) * 2.; + const double sigma = std::asin(chord * 0.5) * 2.; - ASSERT(angle > 0.); - return angle; + ASSERT(sigma > 0.); + return sigma; } double Sphere::distance(double radius, const PointLatLon& A, const PointLatLon& B) { - return radius * centralAngle(A, B); + return radius * angle(A, B); } double Sphere::distance(double radius, const Point3& A, const Point3& B) { - return radius * centralAngle(radius, A, B); + return radius * angle(radius, A, B); } @@ -102,37 +103,12 @@ double Sphere::area(double radius) { } -Point3 Sphere::convertSphericalToCartesian(double radius, const PointLatLon& A, double height) { - ASSERT(radius > 0.); - - /* - * See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates - * numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line). - * - * cos α = sqrt( 1 - sin^2 α) is better conditioned than explicit cos α, and - * coupled with λ in [-180°, 180°[ the accuracy of the trigonometric - * functions is the same (before converting/multiplying its angle argument - * to radian) and explicitly chosing -180° over 180° for longitude. - * - * These three conditionings combined project very accurately to the sphere - * poles and quadrants. - */ - - const double lambda_deg = util::normalise_longitude_to_minimum(A.lon, -180.); - const double lambda = util::degrees_to_radians * lambda_deg; - const double phi = util::degrees_to_radians * A.lat; - - const double sin_phi = std::sin(phi); - const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); - const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; - const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); - - return {(radius + height) * cos_phi * cos_lambda, (radius + height) * cos_phi * sin_lambda, - (radius + height) * sin_phi}; +Point3 Sphere::ll_to_xyz(double radius, const PointLatLon& P, double height) { + return Spheroid::ll_to_xyz(radius, radius, P, height); } -PointLatLon Sphere::convertCartesianToSpherical(double radius, const Point3& A) { +PointLatLon Sphere::xyz_to_ll(double radius, const Point3& A) { ASSERT(radius > 0.); // numerical conditioning for both z (poles) and y diff --git a/src/grit/geometry/Sphere.h b/src/grit/geometry/Sphere.h index 9e38bfd26..0ea063479 100644 --- a/src/grit/geometry/Sphere.h +++ b/src/grit/geometry/Sphere.h @@ -20,10 +20,10 @@ namespace grit::geometry { struct Sphere { /// Great-circle central angle between two points (latitude/longitude coordinates) in radians - static double centralAngle(const PointLatLon&, const PointLatLon&); + static double angle(const PointLatLon&, const PointLatLon&); /// Great-circle central angle between two points (Cartesian coordinates) in radians - static double centralAngle(double radius, const Point3&, const Point3&); + static double angle(double radius, const Point3&, const Point3&); /// Great-circle distance between two points (latitude/longitude coordinates) in metres static double distance(double radius, const PointLatLon&, const PointLatLon&); @@ -35,10 +35,10 @@ struct Sphere { static double area(double radius); // Convert spherical coordinates to Cartesian - static Point3 convertSphericalToCartesian(double radius, const PointLatLon&, double height = 0.); + static Point3 ll_to_xyz(double radius, const PointLatLon&, double height); // Convert Cartesian coordinates to spherical - static PointLatLon convertCartesianToSpherical(double radius, const Point3&); + static PointLatLon xyz_to_ll(double radius, const Point3&); }; diff --git a/src/grit/util/spherical_to_cartesian.cc b/src/grit/geometry/Spheroid.cc similarity index 50% rename from src/grit/util/spherical_to_cartesian.cc rename to src/grit/geometry/Spheroid.cc index d6763cd44..480151949 100644 --- a/src/grit/util/spherical_to_cartesian.cc +++ b/src/grit/geometry/Spheroid.cc @@ -10,38 +10,50 @@ */ +#include "grit/geometry/Spheroid.h" + #include #include "grit/exception.h" -#include "grit/types.h" #include "grit/util.h" namespace grit::geometry { -void spherical_to_cartesian(Point3& B, double lon, double lat, double a, double b, double height) { +Point3 Spheroid::ll_to_xyz(double a, double b, const PointLatLon& P, double height) { ASSERT(a > 0.); ASSERT(b > 0.); - ASSERT_MSG(-90. <= lat && lat <= 90., "Invalid latitude"); - - // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates - // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) - const double lambda_deg = util::normalise_longitude_to_minimum(lon, -180.); + /* + * See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates + * numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) + * + * cos α = sqrt( 1 - sin^2 α) is better conditioned than explicit cos α, and + * coupled with λ in [-180°, 180°[ the accuracy of the trigonometric + * functions is the same (before converting/multiplying its angle argument + * to radian) and explicitly chosing -180° over 180° for longitude. + * + * These three conditionings combined project very accurately to the sphere + * poles and quadrants. + */ + + const double lambda_deg = util::normalise_longitude_to_minimum(P.lon, -180.); const double lambda = util::degrees_to_radians * lambda_deg; - const double phi = util::degrees_to_radians * lat; + const double phi = util::degrees_to_radians * P.lat; const double sin_phi = std::sin(phi); const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); - const double N_phi = a * a / std::sqrt(a * a * cos_phi * cos_phi + b * b * sin_phi * sin_phi); + if (util::approximately_equal(a, b)) { + return {(a + height) * cos_phi * cos_lambda, (a + height) * cos_phi * sin_lambda, (a + height) * sin_phi}; + } - B.x = (N_phi + height) * cos_phi * cos_lambda; - B.y = (N_phi + height) * cos_phi * sin_lambda; - B.z = (N_phi * (b * b) / (a * a) + height) * sin_phi; + const double N_phi = a * a / std::sqrt(a * a * cos_phi * cos_phi + b * b * sin_phi * sin_phi); + return {(N_phi + height) * cos_phi * cos_lambda, (N_phi + height) * cos_phi * sin_lambda, + (N_phi * (b * b) / (a * a) + height) * sin_phi}; } diff --git a/src/grit/geometry/Spheroid.h b/src/grit/geometry/Spheroid.h new file mode 100644 index 000000000..9fbbf96c6 --- /dev/null +++ b/src/grit/geometry/Spheroid.h @@ -0,0 +1,57 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/types.h" + + +namespace grit::geometry { + + +struct Spheroid { +#if 0 + /// Great-circle central angle between two points (latitude/longitude coordinates) in radians + static double angle(const PointLatLon&, const PointLatLon&); +#endif + +#if 0 + /// Great-circle central angle between two points (Cartesian coordinates) in radians + static double angle(double a, double b, const Point3&, const Point3&); +#endif + +#if 0 + /// Great-circle distance between two points (latitude/longitude coordinates) in metres + static double distance(double a, double b, const PointLatLon&, const PointLatLon&); +#endif + +#if 0 + /// Great-circle distance between two points (Cartesian coordinates) in metres + static double distance(double a, double b, const Point3&, const Point3&); +#endif + +#if 0 + /// Surface area in square metres + static double area(double a, double b); +#endif + + // Convert spherical coordinates to Cartesian + static Point3 ll_to_xyz(double a, double b, const PointLatLon&, double height); + +#if 0 + // Convert Cartesian coordinates to spherical + static PointLatLon xyz_to_ll(double a, double b, const Point3&); +#endif +}; + + +} // namespace grit::geometry From 82911e69baaffccf9be1f360b70a8d19af8c4bbd Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 Mar 2023 18:29:54 +0100 Subject: [PATCH 121/737] pl --- src/grit/CMakeLists.txt | 3 + src/grit/exception.h | 3 + src/grit/pl/Classical.cc | 1378 ++++++++++++++++++++++++++++++++++++++ src/grit/pl/Classical.h | 78 +++ src/grit/pl/Pl.h | 101 +++ 5 files changed, 1563 insertions(+) create mode 100644 src/grit/pl/Classical.cc create mode 100644 src/grit/pl/Classical.h create mode 100644 src/grit/pl/Pl.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 97e39110a..23363874f 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -25,6 +25,9 @@ add_library(grit SHARED geometry/Spheroid.cc geometry/Spheroid.h geometry/UnitSphere.h + pl/Classical.cc + pl/Classical.h + pl/Pl.h types.cc types.h util.cc diff --git a/src/grit/exception.h b/src/grit/exception.h index 4bb99dd17..a78f7a6c1 100644 --- a/src/grit/exception.h +++ b/src/grit/exception.h @@ -24,4 +24,7 @@ namespace grit { #define NOTIMP throw std::runtime_error("Not implemented") +using std::runtime_error; + + } // namespace grit diff --git a/src/grit/pl/Classical.cc b/src/grit/pl/Classical.cc new file mode 100644 index 000000000..e9630d7d3 --- /dev/null +++ b/src/grit/pl/Classical.cc @@ -0,0 +1,1378 @@ +/* + * (C) Copyright 1996- 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 "grit/pl/Classical.h" + +#include +#include + +#include "grit/exception.h" + + +namespace grit::pl { + + +static const std::map __N{ + {16, {20, 27, 32, 40, 45, 48, 60, 60, 64, 64, 64, 64, 64, 64, 64, 64}}, + {24, {20, 25, 36, 40, 45, 48, 54, 60, 64, 72, 80, 80, 90, 90, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96}}, + {32, {20, 27, 36, 40, 45, 50, 60, 64, 72, 75, 80, 90, 90, 96, 100, 108, + 108, 120, 120, 120, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}}, + {48, {20, 25, 36, 40, 45, 50, 60, 60, 72, 75, 80, 90, 96, 100, 108, 120, + 120, 120, 128, 135, 144, 144, 160, 160, 160, 160, 160, 180, 180, 180, 180, 180, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192}}, + {64, {20, 25, 36, 40, 45, 54, 60, 64, 72, 75, 80, 90, 96, 100, 108, 120, 120, 125, 135, 135, 144, 150, + 160, 160, 180, 180, 180, 180, 192, 192, 200, 200, 216, 216, 216, 216, 225, 225, 225, 240, 240, 240, 240, 243, + 250, 250, 250, 250, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256}}, + {80, {18, 25, 36, 40, 45, 54, 60, 64, 72, 72, 80, 90, 96, 100, 108, 120, 120, 128, 135, 144, + 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 200, 216, 216, 216, 225, 225, 240, 240, 240, 256, + 256, 256, 256, 288, 288, 288, 288, 288, 288, 288, 288, 288, 300, 300, 300, 300, 320, 320, 320, 320, + 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320}}, + {96, {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 96, 100, 108, 120, 120, 125, 135, 144, + 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 200, 216, 216, 225, 225, 240, 240, 240, 250, 250, + 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, 320, 320, 324, 360, 360, 360, + 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 375, 375, 375, 384, 384, 384, 384, 384, + 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384}}, + {128, {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 90, 100, 108, 120, 120, 125, 128, 144, 144, 150, + 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 240, 250, 250, 256, 270, 270, 288, 288, + 288, 300, 300, 320, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, 400, + 400, 400, 400, 405, 432, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 450, 480, 480, 480, 480, 480, 480, + 480, 480, 480, 480, 486, 486, 486, 500, 500, 500, 500, 500, 500, 500, 512, 512, 512, 512, 512, 512, 512, 512, + 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512}}, + {160, + {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 90, 96, 108, 120, 120, 125, 128, 135, 144, 150, 160, + 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, + 320, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, 375, 375, 384, 384, 400, 400, 400, 405, 432, 432, 432, + 432, 432, 450, 450, 450, 450, 480, 480, 480, 480, 480, 480, 480, 500, 500, 500, 500, 500, 512, 512, 540, 540, 540, + 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, 600, 600, 600, 600, + 600, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, + 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640}}, + {200, + {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, + 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, + 320, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, 375, 375, 384, 400, 400, 400, 400, 432, 432, 432, 432, 432, + 450, 450, 450, 480, 480, 480, 480, 480, 480, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, 540, 540, 576, 576, + 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, 600, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 648, 648, + 675, 675, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, + 729, 750, 750, 750, 750, 750, 750, 750, 750, 768, 768, 768, 768, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, + 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, + 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800}}, + {256, + {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, + 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 243, 250, + 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, + 486, 500, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, + 600, 600, 600, 640, 640, 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 675, 720, + 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, 750, 750, 750, 750, 768, 768, 768, 768, + 800, 800, 800, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, + 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 972, 972, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + 1000, 1000, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, + 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024}}, + {320, + {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, + 135, 144, 144, 150, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 240, 250, + 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, + 600, 640, 640, 640, 640, 640, 640, 640, 648, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, + 720, 720, 720, 720, 729, 750, 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, + 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, + 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 972, 972, 1000, + 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, + 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, + 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, + 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1215, 1215, 1215, 1215, 1280, + 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, + 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, + 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, + 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280}}, + {400, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, + 128, 144, 144, 150, 160, 160, 180, 180, 192, 192, 200, 200, 216, 216, 225, 240, 240, 240, 250, + 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, + 640, 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, + 720, 729, 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, + 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, + 960, 960, 960, 960, 960, 960, 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, + 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, + 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, + 1200, 1215, 1215, 1215, 1215, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, + 1280, 1280, 1296, 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, + 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, 1458, 1458, 1458, 1500, + 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1536, 1536, 1536, + 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, + 1600}}, + {512, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 100, 108, 120, 125, + 128, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, + 250, 256, 270, 270, 288, 288, 288, 300, 320, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 640, + 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, + 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, + 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1280, 1280, 1280, 1280, 1280, 1280, + 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, + 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1458, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1536, 1536, 1536, + 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, + 1600, 1600, 1620, 1620, 1620, 1620, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, + 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, + 1800, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, + 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, + 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 1944, 1944, 1944, 1944, 1944, 1944, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, 2025, 2025, 2025, 2025, + 2025, 2025, 2025, 2025, 2025, 2025, 2025, 2025, 2025, 2025, 2025, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048}}, + {576, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 100, 108, 120, 120, + 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, + 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, 640, + 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, + 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, + 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, + 1280, 1280, 1280, 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, + 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1620, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, + 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, + 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 1944, + 1944, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, + 2025, 2025, 2025, 2025, 2025, 2025, 2025, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2187, 2187, 2187, 2187, 2187, 2187, 2187, 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, + 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, + 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304}}, + {640, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 90, 96, 100, 108, 120, 120, + 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 243, + 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, 640, + 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, + 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, + 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, + 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, + 1280, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, 1500, 1500, 1500, 1500, + 1500, 1500, 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, + 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, + 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, + 1944, 1944, 1944, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, + 2025, 2025, 2025, 2025, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2187, 2187, 2187, 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, + 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2430, 2430, 2430, 2430, 2430, 2430, + 2430, 2430, 2430, 2430, 2430, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, + 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, + 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, + 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, + 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, + 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, + 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, + 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560}}, + {800, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 80, 90, 90, 96, 100, 108, 120, 120, + 125, 128, 135, 144, 150, 160, 160, 180, 180, 192, 192, 200, 200, 216, 216, 225, 240, 240, 240, + 250, 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 375, + 375, 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 486, + 500, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 625, + 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, + 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, + 1200, 1200, 1200, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, + 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1536, 1536, + 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, + 1620, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, + 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, + 1944, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, + 2025, 2025, 2048, 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, 2187, 2187, 2187, 2187, 2187, 2250, 2250, + 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2430, 2430, 2430, 2430, 2500, 2500, 2500, 2500, + 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2560, 2560, 2560, 2560, 2560, + 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, 2592, 2592, 2592, 2592, 2592, 2700, + 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, + 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2916, 2916, 2916, 2916, 2916, 2916, 2916, 2916, + 2916, 2916, 2916, 2916, 2916, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, + 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, + 3000, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, + 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, + 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, + 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3200, 3200, 3200, 3200, 3200, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, + 3200, 3200}}, + {1024, + {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, + 125, 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, + 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, + 375, 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, + 486, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, + 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 750, 750, 750, 750, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, + 1200, 1215, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1350, 1350, + 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1536, 1536, 1536, 1536, 1536, + 1536, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, + 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, + 1875, 1875, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, 2025, 2048, 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, 2187, 2187, + 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2304, 2304, 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2430, 2430, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, + 2500, 2500, 2500, 2500, 2500, 2500, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, + 2592, 2592, 2592, 2592, 2592, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, + 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2916, 2916, 2916, 2916, 2916, 2916, 2916, 2916, 3000, 3000, + 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, + 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, + 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3456, 3456, 3456, + 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, + 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, + 3645, 3645, 3645, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, + 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, + 3750, 3750, 3750, 3750, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, + 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, + 3840, 3840, 3840, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, + 3888, 3888, 3888, 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4050, 4050, 4050, 4050, 4050, + 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, + 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4096, 4096, 4096, 4096, + 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, + 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, + 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, + 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, + 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, + 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096}}, + {1280, + {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, + 120, 125, 135, 135, 144, 144, 160, 160, 180, 180, 180, 192, 200, 200, 216, 216, 225, 240, 240, + 240, 250, 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, + 375, 375, 375, 384, 400, 400, 400, 432, 432, 432, 432, 432, 450, 450, 480, 480, 480, 480, 480, + 486, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, + 625, 625, 625, 625, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, + 1200, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1296, 1350, 1350, + 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, + 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, + 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, + 2000, 2025, 2025, 2025, 2025, 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, + 2250, 2250, 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2430, 2430, + 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2560, 2560, 2560, 2560, 2560, 2560, + 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, 2592, 2592, 2592, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, + 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2916, 2916, 2916, 2916, 2916, 2916, 3000, 3000, 3000, 3000, 3000, + 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, 3072, 3072, 3072, 3072, 3072, + 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3240, + 3240, 3240, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, + 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3750, 3750, 3750, 3750, 3750, 3750, + 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3840, + 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, + 3840, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4096, 4096, 4096, 4096, + 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4374, 4374, 4374, 4374, 4374, 4374, + 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, + 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, + 4860, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5120, 5120}}, + {1600, + {18, 25, 32, 40, 45, 50, 54, 60, 72, 72, 75, 80, 90, 90, 96, 100, 108, 120, 120, + 120, 125, 128, 135, 144, 144, 150, 160, 160, 162, 180, 180, 180, 192, 192, 216, 216, 225, 240, + 240, 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, + 360, 375, 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, + 480, 486, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, + 600, 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, + 1200, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1350, 1350, 1350, + 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, + 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, + 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, + 2025, 2025, 2025, 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, + 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2430, 2430, 2500, 2500, 2500, 2500, 2500, + 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, + 2592, 2592, 2592, 2592, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, + 2700, 2700, 2700, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2916, 2916, 2916, + 2916, 2916, 2916, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3072, + 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, + 3125, 3125, 3125, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, + 3240, 3240, 3240, 3240, 3240, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, + 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3645, 3645, 3645, 3645, + 3645, 3645, 3645, 3645, 3645, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, + 3750, 3750, 3750, 3750, 3750, 3750, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, + 3840, 3840, 3840, 3840, 3840, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4050, + 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, + 4374, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, + 5184, 5184, 5184, 5184, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, + 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, + 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, + 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 6000, + 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, + 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, + 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, + 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, + 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, + 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 6144, 6144, 6144, 6144, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, + 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, + 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, + 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400}}, + {2000, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, + 120, 125, 135, 135, 144, 144, 150, 160, 160, 180, 180, 180, 180, 192, 192, 192, 200, 216, 216, + 216, 225, 240, 240, 243, 250, 256, 270, 270, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, + 360, 360, 375, 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, + 480, 486, 500, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, + 600, 625, 625, 625, 625, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, + 720, 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, + 1200, 1215, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1296, 1350, 1350, + 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, + 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, + 1920, 1920, 1920, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, + 2025, 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, + 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2430, 2430, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, + 2500, 2500, 2500, 2500, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, 2592, 2592, + 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2916, 2916, 2916, 2916, 2916, 2916, 3000, 3000, 3000, + 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, 3072, 3072, 3072, 3072, 3072, + 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3200, 3200, 3200, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3375, 3375, 3375, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, + 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, + 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, + 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 4000, 4000, 4000, + 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4050, 4050, + 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4860, 4860, + 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5760, + 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, + 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, + 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, + 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, + 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, + 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 6144, 6144, 6144, 6144, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, + 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6480, 6480, 6480, 6480, + 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6561, 6561, + 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6561, + 6561, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, + 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, + 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6912, 6912, + 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, + 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, + 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, + 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, + 7290, 7290, 7290, 7290, 7290, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7680, 7680, 7680, + 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, + 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, + 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, + 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000}}, + {4000, + {18, 24, 32, 40, 45, 48, 54, 60, 64, 72, 75, 80, 90, 90, 96, 100, + 108, 108, 120, 120, 125, 128, 135, 135, 144, 150, 150, 160, 160, 180, 180, 180, + 180, 192, 192, 192, 200, 216, 216, 216, 216, 225, 225, 240, 240, 240, 243, 250, + 256, 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, 320, + 324, 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, 400, + 400, 400, 405, 405, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 480, 480, + 480, 480, 480, 480, 486, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, 540, + 540, 540, 576, 576, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, 600, 600, + 625, 625, 625, 625, 625, 625, 640, 640, 640, 648, 648, 675, 675, 675, 675, 675, + 675, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, 750, + 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, 800, 810, 810, + 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, + 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, + 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, + 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1152, + 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1215, 1250, + 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, + 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, + 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1620, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, + 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, 1875, + 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, 1920, + 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, 2025, 2025, 2025, 2048, + 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, + 2187, 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, + 2250, 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2500, 2500, 2500, 2500, 2500, + 2500, 2500, 2500, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, 2700, 2700, 2700, + 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2916, 2916, 2916, 2916, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, + 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3375, 3375, 3375, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3456, 3456, + 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3645, 3645, 3645, 3645, 3645, + 3645, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, + 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3888, 3888, 3888, + 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4050, 4050, 4050, 4050, 4050, 4050, 4096, 4096, 4096, 4096, 4096, 4096, 4096, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4374, + 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, 4608, 4608, 4608, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, + 5760, 5760, 5760, 5760, 5760, 5760, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, + 5832, 5832, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, + 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6075, 6075, 6075, 6075, + 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 6144, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, + 6250, 6250, 6250, 6250, 6250, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6480, 6480, 6480, 6480, + 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6561, 6561, 6561, 6561, 6561, 6561, 6561, + 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, + 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, + 6750, 6750, 6750, 6750, 6750, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, + 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, + 6912, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, + 7776, 7776, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8100, 8100, 8100, 8100, 8100, 8100, + 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8748, 8748, 8748, 8748, + 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9216, 9216, 9216, + 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, + 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, + 9216, 9216, 9216, 9216, 9216, 9216, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, + 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, + 9375, 9375, 9375, 9375, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, + 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, + 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, + 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, + 9720, 9720, 9720, 9720, 9720, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10125, 10125, 10125, + 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, + 10125, 10125, 10125, 10125, 10125, 10125, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, + 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10368, 10368, + 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, + 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, + 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, + 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, + 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, + 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, + 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10935, 10935, + 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, + 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 11250, 11250, 11250, 11250, 11250, + 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, + 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, + 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, + 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, + 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, + 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, + 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, + 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11664, 11664, 11664, + 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, + 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 12000, 12000, + 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, + 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, + 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, + 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, + 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, + 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, + 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12288, 12288, 12288, 12288, + 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, + 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12500, 12500, 12500, + 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, + 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, + 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, + 12500, 12500, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, + 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, + 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, + 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, + 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, + 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, + 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, + 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 13122, 13122, 13122, 13122, 13122, 13122, + 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, + 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, + 13122, 13122, 13122, 13122, 13122, 13122, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, + 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, + 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, + 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, + 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, + 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, + 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, + 13500, 13500, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, + 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, + 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, + 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, + 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, + 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14580, 14580, + 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, + 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, + 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, + 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, + 14580, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, + 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, + 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, + 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, + 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, + 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, + 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, + 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, + 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, + 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, + 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000}}, + {8000, + {16, 24, 30, 36, 40, 45, 54, 60, 64, 72, 72, 75, 81, 90, 90, 96, + 100, 108, 120, 120, 120, 125, 128, 135, 144, 144, 150, 160, 160, 160, 180, 180, + 180, 180, 192, 192, 192, 200, 216, 216, 216, 216, 225, 225, 240, 240, 240, 243, + 250, 250, 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, + 320, 324, 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, + 400, 400, 400, 405, 405, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 480, + 480, 480, 480, 480, 480, 480, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, + 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, + 600, 625, 625, 625, 625, 625, 625, 640, 640, 640, 640, 648, 675, 675, 675, 675, + 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, + 750, 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, 800, 800, + 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, + 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 960, 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, + 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, + 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, + 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1280, + 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, + 1500, 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1620, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, + 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, + 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, + 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, 2025, 2025, 2025, 2048, + 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, + 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, + 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2430, 2430, 2430, 2430, 2500, + 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2560, + 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, + 2592, 2592, 2592, 2592, 2592, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, + 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2916, 2916, 2916, 2916, 2916, 2916, + 2916, 2916, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, + 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, + 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, + 3125, 3125, 3125, 3125, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, + 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, + 3456, 3456, 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, + 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, + 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3840, 3840, 3840, 3840, 3840, 3840, 3840, + 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3888, + 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4000, 4000, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, + 4050, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4860, 4860, 4860, 4860, 4860, 4860, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, + 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 6000, 6000, 6000, 6000, 6000, 6000, 6000, + 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6075, 6075, + 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6250, + 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6561, 6561, 6561, 6561, 6561, + 6561, 6561, 6561, 6561, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, + 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6912, 6912, 6912, + 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, + 6912, 6912, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, + 7290, 7290, 7290, 7290, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7776, 7776, 7776, 7776, 7776, 7776, + 7776, 7776, 7776, 7776, 7776, 7776, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, + 8100, 8100, 8100, 8100, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, + 9000, 9000, 9000, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, + 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, + 9216, 9216, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, + 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9600, 9600, 9600, 9600, 9600, 9600, + 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, + 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9720, 9720, 9720, 9720, 9720, 9720, + 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, + 10000, 10000, 10000, 10000, 10000, 10000, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, + 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10240, 10240, 10240, 10240, 10240, 10240, 10240, + 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10240, 10368, 10368, 10368, 10368, 10368, + 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10368, 10800, 10800, + 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, + 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, + 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, + 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10800, 10935, + 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, 10935, + 10935, 10935, 10935, 10935, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, + 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, + 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, 11250, + 11250, 11250, 11250, 11250, 11250, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, + 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, + 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11520, 11664, 11664, + 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, 11664, + 11664, 11664, 11664, 11664, 11664, 11664, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, + 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, + 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, + 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12000, 12150, 12150, 12150, 12150, 12150, 12150, + 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, 12150, + 12150, 12150, 12150, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, + 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12288, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, + 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, + 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12500, 12800, 12800, 12800, 12800, 12800, 12800, + 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, + 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, + 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12800, 12960, 12960, 12960, 12960, 12960, 12960, + 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, 12960, + 12960, 12960, 12960, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, + 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13122, 13500, 13500, + 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, + 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, + 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, + 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13500, 13824, 13824, 13824, + 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, + 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, + 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, 13824, + 13824, 13824, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, 14400, + 14400, 14400, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, + 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, 14580, + 14580, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, + 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, 15360, + 15360, 15360, 15360, 15360, 15360, 15360, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, + 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, 15552, + 15552, 15552, 15552, 15552, 15552, 15552, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, 15625, + 15625, 15625, 15625, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, + 16000, 16000, 16000, 16000, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, + 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, + 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16200, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16875, 16875, 16875, 16875, 16875, 16875, 16875, + 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, + 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, + 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, + 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, + 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, 16875, + 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, + 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, + 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, + 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, + 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17280, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, + 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, + 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, 17496, + 17496, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, + 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, + 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, + 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, + 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, + 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18000, 18225, 18225, 18225, + 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, + 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18225, + 18225, 18225, 18225, 18225, 18225, 18225, 18225, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, + 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, + 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432, 18750, 18750, 18750, 18750, + 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, + 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, + 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, + 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 18750, 19200, 19200, 19200, 19200, 19200, 19200, 19200, + 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, + 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, + 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, + 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, + 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19200, 19440, 19440, + 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, + 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, + 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19440, 19683, 19683, 19683, + 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, + 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, + 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 19683, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, + 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20000, 20250, 20250, 20250, 20250, 20250, 20250, + 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, + 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, + 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20250, 20480, 20480, 20480, 20480, + 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, + 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, + 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20480, 20736, 20736, 20736, 20736, 20736, + 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, + 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, + 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 20736, 21600, + 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, + 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, + 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, + 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, + 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, + 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, + 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, + 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, + 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, + 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, + 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, 21600, + 21600, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, + 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, + 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, + 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 21870, 22500, 22500, 22500, 22500, 22500, + 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, + 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, + 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, + 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, + 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, + 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, + 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, + 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, 22500, + 22500, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, + 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, + 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, + 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, + 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, + 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, + 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, + 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23040, 23328, 23328, 23328, 23328, 23328, 23328, + 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, + 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, + 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, + 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 23328, 24000, 24000, 24000, 24000, 24000, + 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, + 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, + 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, + 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, + 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, + 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, + 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, + 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, + 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, 24000, + 24000, 24000, 24000, 24000, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, + 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, + 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, + 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, + 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24300, 24576, 24576, 24576, + 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, + 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, + 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, + 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, 24576, + 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, + 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, + 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, + 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, + 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, + 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, + 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25000, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, + 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, + 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, + 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, + 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, + 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, + 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, + 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, + 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, + 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, 25600, + 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, + 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, + 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, + 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, + 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, 25920, + 25920, 25920, 25920, 25920, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, + 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, + 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, + 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, + 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, + 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 26244, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, + 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27000, 27648, + 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, + 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, + 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, + 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, + 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, + 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, + 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, + 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, + 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, + 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, + 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, + 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, 27648, + 27648, 27648, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, + 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, + 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, + 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, + 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, + 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, + 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, + 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, + 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, + 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28125, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, 28800, + 28800, 28800, 28800, 28800, 28800, 28800, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, + 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, + 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, + 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, + 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, + 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, + 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, + 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, + 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 29160, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, + 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30000, 30375, + 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, + 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, + 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, + 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, + 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, + 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, + 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, + 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, + 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, + 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, + 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, 30375, + 30375, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, + 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, + 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, + 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, + 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, + 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, + 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, + 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, + 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, + 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, + 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, + 30720, 30720, 30720, 30720, 30720, 30720, 30720, 30720, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, 31104, + 31104, 31104, 31104, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, + 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, + 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, + 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, + 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, + 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, + 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 31250, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, + 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000, 32000}}, +}; + + +const Pl::pl_type& Classical::pl(size_t N) { + static Classical pls; + + const auto& pl = pls.get_pl(N); + ASSERT(pl.size() == 2 * N); + + return pl; +} + + +const Pl::pl_type& Classical::get_pl(size_t N) const { + ASSERT(N > 0); + + static std::map __cache; + if (auto pl = __cache.find(N); pl != __cache.end()) { + return pl->second; + } + + const auto& pl_half = get_pl_half(N); + ASSERT(pl_half.size() == N); + + pl_type pl(N * 2); + + auto p = pl_half.begin(); + for (size_t i = 0, j = 2 * N - 1; i < N; ++i, --j) { + pl[i] = pl[j] = *p++; + } + + __cache[N] = std::move(pl); + return __cache[N]; +} + + +const Pl::pl_type& Classical::get_pl_half(size_t N) const { + if (auto pl = __N.find(N); pl != __N.end()) { + ASSERT(pl->second.size() == N); + return pl->second; + } + + throw runtime_error("Classical::get_pl_half: unknown N=" + std::to_string(N)); +} + + +} // namespace grit::pl diff --git a/src/grit/pl/Classical.h b/src/grit/pl/Classical.h new file mode 100644 index 000000000..3f573ec32 --- /dev/null +++ b/src/grit/pl/Classical.h @@ -0,0 +1,78 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/pl/Pl.h" + + +namespace grit::pl { + + +class Classical final : public Pl { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + static const pl_type& pl(size_t N); + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Constructors + + Classical() = default; + + // -- Destructor + // None + + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + const pl_type& get_pl(size_t N) const override; + const pl_type& get_pl_half(size_t N) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::pl diff --git a/src/grit/pl/Pl.h b/src/grit/pl/Pl.h new file mode 100644 index 000000000..8bd7add63 --- /dev/null +++ b/src/grit/pl/Pl.h @@ -0,0 +1,101 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + + +namespace grit::pl { + + +class Pl { +public: + // -- Types + + using pl_value_type = long; + using pl_type = std::vector; + + // -- Exceptions + // None + + // -- Constructors + + Pl() = default; + Pl(const Pl&) = delete; + Pl(Pl&&) = delete; + + // -- Destructor + + virtual ~Pl() = default; + + // -- Convertors + // None + + // -- Operators + + Pl& operator=(const Pl&) = delete; + Pl& operator=(Pl&&) = delete; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + virtual const pl_type& get_pl(size_t N) const = 0; + virtual const pl_type& get_pl_half(size_t N) const = 0; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::pl From 31561b3d1b9fdfe983767bca87a252dd1713e6f8 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 Mar 2023 18:46:27 +0100 Subject: [PATCH 122/737] pl --- src/grit/CMakeLists.txt | 2 + src/grit/pl/Octahedral.cc | 59 +++++++++++++++++++++++++++++ src/grit/pl/Octahedral.h | 78 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 src/grit/pl/Octahedral.cc create mode 100644 src/grit/pl/Octahedral.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 23363874f..171c3f060 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -27,6 +27,8 @@ add_library(grit SHARED geometry/UnitSphere.h pl/Classical.cc pl/Classical.h + pl/Octahedral.cc + pl/Octahedral.h pl/Pl.h types.cc types.h diff --git a/src/grit/pl/Octahedral.cc b/src/grit/pl/Octahedral.cc new file mode 100644 index 000000000..45c319fe3 --- /dev/null +++ b/src/grit/pl/Octahedral.cc @@ -0,0 +1,59 @@ +/* + * (C) Copyright 1996- 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 "grit/pl/Octahedral.h" + +#include + +#include "grit/exception.h" + + +namespace grit::pl { + + +const Pl::pl_type& Octahedral::pl(size_t N) { + static Octahedral pls; + + const auto& pl = pls.get_pl(N); + ASSERT(pl.size() == 2 * N); + + return pl; +} + + +const Pl::pl_type& Octahedral::get_pl(size_t N) const { + ASSERT(N > 0); + + static std::map __cache; + if (auto pl = __cache.find(N); pl != __cache.end()) { + return pl->second; + } + + pl_type pl(N * 2); + + pl_value_type p = 20; + for (size_t i = 0, j = 2 * N - 1; i < N; ++i, --j) { + pl[i] = pl[j] = p; + p += 4; + } + + __cache[N] = std::move(pl); + return __cache[N]; +} + + +const Pl::pl_type& Octahedral::get_pl_half(size_t N) const { + NOTIMP; +} + + +} // namespace grit::pl diff --git a/src/grit/pl/Octahedral.h b/src/grit/pl/Octahedral.h new file mode 100644 index 000000000..5ed166430 --- /dev/null +++ b/src/grit/pl/Octahedral.h @@ -0,0 +1,78 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/pl/Pl.h" + + +namespace grit::pl { + + +class Octahedral final : public Pl { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + static const pl_type& pl(size_t N); + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Constructors + + Octahedral() = default; + + // -- Destructor + // None + + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + const pl_type& get_pl(size_t N) const override; + const pl_type& get_pl_half(size_t N) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::pl From d0587bb73896c81d00dd9f660e52ebc601d15c34 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 Mar 2023 18:59:33 +0100 Subject: [PATCH 123/737] pl --- tests/CMakeLists.txt | 1 + tests/pl.cc | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/pl.cc diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index af355ef6e..2bba8b127 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,7 @@ include(CTest) foreach(name + pl util) add_executable(test_${name} ${name}.cc) target_link_libraries(test_${name} grit) diff --git a/tests/pl.cc b/tests/pl.cc new file mode 100644 index 000000000..2468f31bf --- /dev/null +++ b/tests/pl.cc @@ -0,0 +1,35 @@ +/* + * (C) Copyright 1996- 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 + +#include "grit/pl/Classical.h" +#include "grit/pl/Octahedral.h" + + +template +std::ostream& operator<<(std::ostream& out, const std::vector& v) { + const auto* sep = ""; + for (const auto& value : v) { + out << sep << value; + sep = ", "; + } + return out; +} + + +int main(int argc, const char* argv[]) { + std::cout << grit::pl::Classical::pl(16) << std::endl; + std::cout << grit::pl::Classical::pl(16) << std::endl; + std::cout << grit::pl::Octahedral::pl(16) << std::endl; + std::cout << grit::pl::Octahedral::pl(16) << std::endl; +} From bd5f02b96cc27b18d2057a0c2af71220f5fccf4c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 Mar 2023 23:42:56 +0100 Subject: [PATCH 124/737] pl --- src/grit/CMakeLists.txt | 10 +- src/grit/pl/Classical.h | 78 -------------- src/grit/pl/Octahedral.h | 78 -------------- src/grit/pl/Pl.h | 101 ------------------ src/grit/util.h | 16 ++- .../reduced_gaussian_classical_pl.cc} | 44 +++----- .../reduced_gaussian_octahedral_pl.cc} | 27 ++--- src/grit/util/regular_gaussian_pl.cc | 29 +++++ tests/CMakeLists.txt | 1 - tests/pl.cc | 35 ------ tests/util.cc | 10 +- 11 files changed, 72 insertions(+), 357 deletions(-) delete mode 100644 src/grit/pl/Classical.h delete mode 100644 src/grit/pl/Octahedral.h delete mode 100644 src/grit/pl/Pl.h rename src/grit/{pl/Classical.cc => util/reduced_gaussian_classical_pl.cc} (99%) rename src/grit/{pl/Octahedral.cc => util/reduced_gaussian_octahedral_pl.cc} (66%) create mode 100644 src/grit/util/regular_gaussian_pl.cc delete mode 100644 tests/pl.cc diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 171c3f060..88be29dab 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -25,18 +25,16 @@ add_library(grit SHARED geometry/Spheroid.cc geometry/Spheroid.h geometry/UnitSphere.h - pl/Classical.cc - pl/Classical.h - pl/Octahedral.cc - pl/Octahedral.h - pl/Pl.h types.cc types.h util.cc util.h util/arange.cc util/gaussian_latitudes.cc - util/linspace.cc) + util/linspace.cc + util/reduced_gaussian_classical_pl.cc + util/reduced_gaussian_octahedral_pl.cc + util/regular_gaussian_pl.cc) target_include_directories(grit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") diff --git a/src/grit/pl/Classical.h b/src/grit/pl/Classical.h deleted file mode 100644 index 3f573ec32..000000000 --- a/src/grit/pl/Classical.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "grit/pl/Pl.h" - - -namespace grit::pl { - - -class Classical final : public Pl { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - static const pl_type& pl(size_t N); - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Constructors - - Classical() = default; - - // -- Destructor - // None - - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - const pl_type& get_pl(size_t N) const override; - const pl_type& get_pl_half(size_t N) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace grit::pl diff --git a/src/grit/pl/Octahedral.h b/src/grit/pl/Octahedral.h deleted file mode 100644 index 5ed166430..000000000 --- a/src/grit/pl/Octahedral.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "grit/pl/Pl.h" - - -namespace grit::pl { - - -class Octahedral final : public Pl { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - static const pl_type& pl(size_t N); - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Constructors - - Octahedral() = default; - - // -- Destructor - // None - - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - const pl_type& get_pl(size_t N) const override; - const pl_type& get_pl_half(size_t N) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace grit::pl diff --git a/src/grit/pl/Pl.h b/src/grit/pl/Pl.h deleted file mode 100644 index 8bd7add63..000000000 --- a/src/grit/pl/Pl.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include - - -namespace grit::pl { - - -class Pl { -public: - // -- Types - - using pl_value_type = long; - using pl_type = std::vector; - - // -- Exceptions - // None - - // -- Constructors - - Pl() = default; - Pl(const Pl&) = delete; - Pl(Pl&&) = delete; - - // -- Destructor - - virtual ~Pl() = default; - - // -- Convertors - // None - - // -- Operators - - Pl& operator=(const Pl&) = delete; - Pl& operator=(Pl&&) = delete; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - - virtual const pl_type& get_pl(size_t N) const = 0; - virtual const pl_type& get_pl_half(size_t N) const = 0; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace grit::pl diff --git a/src/grit/util.h b/src/grit/util.h index aa73a2d15..86ce1af42 100644 --- a/src/grit/util.h +++ b/src/grit/util.h @@ -30,10 +30,10 @@ bool approximately_equal(T x, T y, T eps = std::numeric_limits::epsilon()) { }; -static const double degrees_to_radians = M_PI / 180.; +static constexpr double degrees_to_radians = M_PI / 180.; -static const double radians_to_degrees = 180. * M_1_PI; +static constexpr double radians_to_degrees = 180. * M_1_PI; std::vector arange(double start, double stop, double step); @@ -53,4 +53,16 @@ double normalise_longitude_to_minimum(double lon, double minimum); double normalise_longitude_to_maximum(double lon, double maximum); +using pl_type = std::vector; + + +const pl_type& reduced_gaussian_classical_pl(size_t N); + + +const pl_type& reduced_gaussian_octahedral_pl(size_t N); + + +pl_type::value_type regular_gaussian_pl(size_t N); + + } // namespace grit::util diff --git a/src/grit/pl/Classical.cc b/src/grit/util/reduced_gaussian_classical_pl.cc similarity index 99% rename from src/grit/pl/Classical.cc rename to src/grit/util/reduced_gaussian_classical_pl.cc index e9630d7d3..fde084881 100644 --- a/src/grit/pl/Classical.cc +++ b/src/grit/util/reduced_gaussian_classical_pl.cc @@ -10,18 +10,18 @@ */ -#include "grit/pl/Classical.h" - #include #include +#include #include "grit/exception.h" +#include "grit/util.h" -namespace grit::pl { +namespace grit::util { -static const std::map __N{ +static const std::map __classical_pls{ {16, {20, 27, 32, 40, 45, 48, 60, 60, 64, 64, 64, 64, 64, 64, 64, 64}}, {24, {20, 25, 36, 40, 45, 48, 54, 60, 64, 72, 80, 80, 90, 90, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96}}, {32, {20, 27, 36, 40, 45, 50, 60, 64, 72, 75, 80, 90, 90, 96, 100, 108, @@ -1332,30 +1332,24 @@ static const std::map __N{ }; -const Pl::pl_type& Classical::pl(size_t N) { - static Classical pls; - - const auto& pl = pls.get_pl(N); - ASSERT(pl.size() == 2 * N); - - return pl; -} - - -const Pl::pl_type& Classical::get_pl(size_t N) const { +const pl_type& reduced_gaussian_classical_pl(size_t N) { ASSERT(N > 0); - static std::map __cache; + static std::map __cache; if (auto pl = __cache.find(N); pl != __cache.end()) { return pl->second; } - const auto& pl_half = get_pl_half(N); - ASSERT(pl_half.size() == N); + auto pl_half = __classical_pls.find(N); + if (pl_half == __classical_pls.end()) { + throw runtime_error("reduced_gaussian_classical_pl: unknown N=" + std::to_string(N)); + } + + ASSERT(pl_half->second.size() == N); pl_type pl(N * 2); - auto p = pl_half.begin(); + auto p = pl_half->second.begin(); for (size_t i = 0, j = 2 * N - 1; i < N; ++i, --j) { pl[i] = pl[j] = *p++; } @@ -1365,14 +1359,4 @@ const Pl::pl_type& Classical::get_pl(size_t N) const { } -const Pl::pl_type& Classical::get_pl_half(size_t N) const { - if (auto pl = __N.find(N); pl != __N.end()) { - ASSERT(pl->second.size() == N); - return pl->second; - } - - throw runtime_error("Classical::get_pl_half: unknown N=" + std::to_string(N)); -} - - -} // namespace grit::pl +} // namespace grit::util diff --git a/src/grit/pl/Octahedral.cc b/src/grit/util/reduced_gaussian_octahedral_pl.cc similarity index 66% rename from src/grit/pl/Octahedral.cc rename to src/grit/util/reduced_gaussian_octahedral_pl.cc index 45c319fe3..12bf3b432 100644 --- a/src/grit/pl/Octahedral.cc +++ b/src/grit/util/reduced_gaussian_octahedral_pl.cc @@ -10,27 +10,17 @@ */ -#include "grit/pl/Octahedral.h" - #include +#include #include "grit/exception.h" +#include "grit/util.h" -namespace grit::pl { - - -const Pl::pl_type& Octahedral::pl(size_t N) { - static Octahedral pls; +namespace grit::util { - const auto& pl = pls.get_pl(N); - ASSERT(pl.size() == 2 * N); - - return pl; -} - -const Pl::pl_type& Octahedral::get_pl(size_t N) const { +const pl_type& reduced_gaussian_octahedral_pl(size_t N) { ASSERT(N > 0); static std::map __cache; @@ -40,7 +30,7 @@ const Pl::pl_type& Octahedral::get_pl(size_t N) const { pl_type pl(N * 2); - pl_value_type p = 20; + pl_type::value_type p = 20; for (size_t i = 0, j = 2 * N - 1; i < N; ++i, --j) { pl[i] = pl[j] = p; p += 4; @@ -51,9 +41,4 @@ const Pl::pl_type& Octahedral::get_pl(size_t N) const { } -const Pl::pl_type& Octahedral::get_pl_half(size_t N) const { - NOTIMP; -} - - -} // namespace grit::pl +} // namespace grit::util diff --git a/src/grit/util/regular_gaussian_pl.cc b/src/grit/util/regular_gaussian_pl.cc new file mode 100644 index 000000000..945d6cd6c --- /dev/null +++ b/src/grit/util/regular_gaussian_pl.cc @@ -0,0 +1,29 @@ +/* + * (C) Copyright 1996- 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 + +#include "grit/exception.h" +#include "grit/util.h" + + +namespace grit::util { + + +pl_type::value_type regular_gaussian_pl(size_t N) { + ASSERT(N > 0); + + return 4 * N; +} + + +} // namespace grit::util diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2bba8b127..af355ef6e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,7 +1,6 @@ include(CTest) foreach(name - pl util) add_executable(test_${name} ${name}.cc) target_link_libraries(test_${name} grit) diff --git a/tests/pl.cc b/tests/pl.cc deleted file mode 100644 index 2468f31bf..000000000 --- a/tests/pl.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - * (C) Copyright 1996- 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 - -#include "grit/pl/Classical.h" -#include "grit/pl/Octahedral.h" - - -template -std::ostream& operator<<(std::ostream& out, const std::vector& v) { - const auto* sep = ""; - for (const auto& value : v) { - out << sep << value; - sep = ", "; - } - return out; -} - - -int main(int argc, const char* argv[]) { - std::cout << grit::pl::Classical::pl(16) << std::endl; - std::cout << grit::pl::Classical::pl(16) << std::endl; - std::cout << grit::pl::Octahedral::pl(16) << std::endl; - std::cout << grit::pl::Octahedral::pl(16) << std::endl; -} diff --git a/tests/util.cc b/tests/util.cc index 1f6973421..98ed4c2c0 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -60,15 +60,10 @@ class iterable_t : public std::vector { using vector::vector; iterator begin() { return {*this, 0}; } - iterator end() { return {*this, this->size()}; } - const_iterator cbegin() const { return {*this, 0}; } - const_iterator cend() const { return {*this, this->size()}; } - const_iterator begin() const { return cbegin(); } - const_iterator end() const { return cend(); } }; @@ -80,6 +75,11 @@ int main(int argc, char* argv[]) { // std::cout << grit::util::normalise_longitude_to_maximum(0.,0.) << std::endl; // std::cout << grit::util::normalise_longitude_to_minimum(0.,0.) << std::endl; + std::cout << grit::util::reduced_gaussian_classical_pl(16) << std::endl; + std::cout << grit::util::reduced_gaussian_classical_pl(16) << std::endl; + std::cout << grit::util::reduced_gaussian_octahedral_pl(16) << std::endl; + std::cout << grit::util::reduced_gaussian_octahedral_pl(16) << std::endl; + #if 0 iterable_t it{1, 2, 3, 4}; From 1d4386635791e5cf97a148df4bfe0f3a4f018bf0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 11 Apr 2023 09:40:51 +0100 Subject: [PATCH 125/737] pl --- src/grit/types.h | 4 ++++ src/grit/util.h | 5 ++--- src/grit/util/reduced_gaussian_classical_pl.cc | 2 +- src/grit/util/reduced_gaussian_octahedral_pl.cc | 2 +- src/grit/util/regular_gaussian_pl.cc | 4 ++-- 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/grit/types.h b/src/grit/types.h index fd5b41696..be2d184b5 100644 --- a/src/grit/types.h +++ b/src/grit/types.h @@ -13,6 +13,7 @@ #pragma once #include +#include namespace grit { @@ -39,4 +40,7 @@ struct Point3 : std::array { }; +using pl_type = std::vector; + + } // namespace grit diff --git a/src/grit/util.h b/src/grit/util.h index 86ce1af42..1558395e2 100644 --- a/src/grit/util.h +++ b/src/grit/util.h @@ -18,6 +18,8 @@ #include #include +#include "grit/types.h" + namespace grit::util { @@ -53,9 +55,6 @@ double normalise_longitude_to_minimum(double lon, double minimum); double normalise_longitude_to_maximum(double lon, double maximum); -using pl_type = std::vector; - - const pl_type& reduced_gaussian_classical_pl(size_t N); diff --git a/src/grit/util/reduced_gaussian_classical_pl.cc b/src/grit/util/reduced_gaussian_classical_pl.cc index fde084881..aad7901b7 100644 --- a/src/grit/util/reduced_gaussian_classical_pl.cc +++ b/src/grit/util/reduced_gaussian_classical_pl.cc @@ -15,7 +15,7 @@ #include #include "grit/exception.h" -#include "grit/util.h" +#include "grit/types.h" namespace grit::util { diff --git a/src/grit/util/reduced_gaussian_octahedral_pl.cc b/src/grit/util/reduced_gaussian_octahedral_pl.cc index 12bf3b432..604163d64 100644 --- a/src/grit/util/reduced_gaussian_octahedral_pl.cc +++ b/src/grit/util/reduced_gaussian_octahedral_pl.cc @@ -14,7 +14,7 @@ #include #include "grit/exception.h" -#include "grit/util.h" +#include "grit/types.h" namespace grit::util { diff --git a/src/grit/util/regular_gaussian_pl.cc b/src/grit/util/regular_gaussian_pl.cc index 945d6cd6c..26b3009b0 100644 --- a/src/grit/util/regular_gaussian_pl.cc +++ b/src/grit/util/regular_gaussian_pl.cc @@ -13,7 +13,7 @@ #include #include "grit/exception.h" -#include "grit/util.h" +#include "grit/types.h" namespace grit::util { @@ -22,7 +22,7 @@ namespace grit::util { pl_type::value_type regular_gaussian_pl(size_t N) { ASSERT(N > 0); - return 4 * N; + return static_cast(4 * N); } From b75a8f26e3b5d40fa89d48ca1aa2cd766ee6de1c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 11 Apr 2023 11:51:26 +0100 Subject: [PATCH 126/737] pl --- src/grit/util.cc | 6 ++++++ src/grit/util.h | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/grit/util.cc b/src/grit/util.cc index e84ebe6fb..474ecd54b 100644 --- a/src/grit/util.cc +++ b/src/grit/util.cc @@ -16,6 +16,12 @@ namespace grit::util { +template <> +pl_type pl_convert(const pl_type& pl) { + return pl; +} + + double normalise_longitude_to_minimum(double lon, double minimum) { while (lon < minimum) { lon += 360.; diff --git a/src/grit/util.h b/src/grit/util.h index 1558395e2..c3319afbd 100644 --- a/src/grit/util.h +++ b/src/grit/util.h @@ -32,6 +32,21 @@ bool approximately_equal(T x, T y, T eps = std::numeric_limits::epsilon()) { }; +template +pl_type pl_convert(const T& pl) { + ASSERT(!pl.empty()); + + pl_type _pl(pl.size()); + std::transform(pl.begin(), pl.end(), _pl.begin(), + [](typename T::value_type p) { return static_cast(p); }); + return std::move(_pl); +} + + +template <> +pl_type pl_convert(const pl_type&); + + static constexpr double degrees_to_radians = M_PI / 180.; From 621b9585b4918d38b3a956c00ee4b11d3f9efa44 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 11 Apr 2023 14:51:19 +0100 Subject: [PATCH 127/737] pl --- src/grit/CMakeLists.txt | 6 +++--- src/grit/util.h | 6 +++--- ...d_gaussian_classical_pl.cc => reduced_classical_pl.cc} | 4 ++-- ...gaussian_octahedral_pl.cc => reduced_octahedral_pl.cc} | 2 +- src/grit/util/{regular_gaussian_pl.cc => regular_pl.cc} | 2 +- tests/util.cc | 8 ++++---- 6 files changed, 14 insertions(+), 14 deletions(-) rename src/grit/util/{reduced_gaussian_classical_pl.cc => reduced_classical_pl.cc} (99%) rename src/grit/util/{reduced_gaussian_octahedral_pl.cc => reduced_octahedral_pl.cc} (94%) rename src/grit/util/{regular_gaussian_pl.cc => regular_pl.cc} (91%) diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 88be29dab..64b913429 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -32,9 +32,9 @@ add_library(grit SHARED util/arange.cc util/gaussian_latitudes.cc util/linspace.cc - util/reduced_gaussian_classical_pl.cc - util/reduced_gaussian_octahedral_pl.cc - util/regular_gaussian_pl.cc) + util/reduced_classical_pl.cc + util/reduced_octahedral_pl.cc + util/regular_pl.cc) target_include_directories(grit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") diff --git a/src/grit/util.h b/src/grit/util.h index c3319afbd..cc6cc0efa 100644 --- a/src/grit/util.h +++ b/src/grit/util.h @@ -70,13 +70,13 @@ double normalise_longitude_to_minimum(double lon, double minimum); double normalise_longitude_to_maximum(double lon, double maximum); -const pl_type& reduced_gaussian_classical_pl(size_t N); +const pl_type& reduced_classical_pl(size_t N); -const pl_type& reduced_gaussian_octahedral_pl(size_t N); +const pl_type& reduced_octahedral_pl(size_t N); -pl_type::value_type regular_gaussian_pl(size_t N); +pl_type::value_type regular_pl(size_t N); } // namespace grit::util diff --git a/src/grit/util/reduced_gaussian_classical_pl.cc b/src/grit/util/reduced_classical_pl.cc similarity index 99% rename from src/grit/util/reduced_gaussian_classical_pl.cc rename to src/grit/util/reduced_classical_pl.cc index aad7901b7..ff4285ed2 100644 --- a/src/grit/util/reduced_gaussian_classical_pl.cc +++ b/src/grit/util/reduced_classical_pl.cc @@ -1332,7 +1332,7 @@ static const std::map __classical_pls{ }; -const pl_type& reduced_gaussian_classical_pl(size_t N) { +const pl_type& reduced_classical_pl(size_t N) { ASSERT(N > 0); static std::map __cache; @@ -1342,7 +1342,7 @@ const pl_type& reduced_gaussian_classical_pl(size_t N) { auto pl_half = __classical_pls.find(N); if (pl_half == __classical_pls.end()) { - throw runtime_error("reduced_gaussian_classical_pl: unknown N=" + std::to_string(N)); + throw runtime_error("reduced_classical_pl: unknown N=" + std::to_string(N)); } ASSERT(pl_half->second.size() == N); diff --git a/src/grit/util/reduced_gaussian_octahedral_pl.cc b/src/grit/util/reduced_octahedral_pl.cc similarity index 94% rename from src/grit/util/reduced_gaussian_octahedral_pl.cc rename to src/grit/util/reduced_octahedral_pl.cc index 604163d64..2033e0244 100644 --- a/src/grit/util/reduced_gaussian_octahedral_pl.cc +++ b/src/grit/util/reduced_octahedral_pl.cc @@ -20,7 +20,7 @@ namespace grit::util { -const pl_type& reduced_gaussian_octahedral_pl(size_t N) { +const pl_type& reduced_octahedral_pl(size_t N) { ASSERT(N > 0); static std::map __cache; diff --git a/src/grit/util/regular_gaussian_pl.cc b/src/grit/util/regular_pl.cc similarity index 91% rename from src/grit/util/regular_gaussian_pl.cc rename to src/grit/util/regular_pl.cc index 26b3009b0..7332e226b 100644 --- a/src/grit/util/regular_gaussian_pl.cc +++ b/src/grit/util/regular_pl.cc @@ -19,7 +19,7 @@ namespace grit::util { -pl_type::value_type regular_gaussian_pl(size_t N) { +pl_type::value_type regular_pl(size_t N) { ASSERT(N > 0); return static_cast(4 * N); diff --git a/tests/util.cc b/tests/util.cc index 98ed4c2c0..c5eca4c36 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -75,10 +75,10 @@ int main(int argc, char* argv[]) { // std::cout << grit::util::normalise_longitude_to_maximum(0.,0.) << std::endl; // std::cout << grit::util::normalise_longitude_to_minimum(0.,0.) << std::endl; - std::cout << grit::util::reduced_gaussian_classical_pl(16) << std::endl; - std::cout << grit::util::reduced_gaussian_classical_pl(16) << std::endl; - std::cout << grit::util::reduced_gaussian_octahedral_pl(16) << std::endl; - std::cout << grit::util::reduced_gaussian_octahedral_pl(16) << std::endl; + std::cout << grit::util::reduced_classical_pl(16) << std::endl; + std::cout << grit::util::reduced_classical_pl(16) << std::endl; + std::cout << grit::util::reduced_octahedral_pl(16) << std::endl; + std::cout << grit::util::reduced_octahedral_pl(16) << std::endl; #if 0 iterable_t it{1, 2, 3, 4}; From a63adc8ccde24f471e07674c0ce42e46550f3a2a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 11 Apr 2023 15:28:02 +0100 Subject: [PATCH 128/737] util --- src/grit/Figure.cc | 2 +- src/grit/geometry/BoundingBox.cc | 2 +- src/grit/geometry/GreatCircle.cc | 16 ++++++++-------- src/grit/geometry/Sphere.cc | 6 +++--- src/grit/geometry/Spheroid.cc | 2 +- src/grit/util.h | 2 +- src/grit/util/arange.cc | 2 +- 7 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/grit/Figure.cc b/src/grit/Figure.cc index 8f595294f..4c88f6b90 100644 --- a/src/grit/Figure.cc +++ b/src/grit/Figure.cc @@ -25,7 +25,7 @@ Figure::Figure(double R) : Figure(R, R) {} Figure::Figure(double a, double b) : - a_(a), b_(b), R_(util::approximately_equal(a, b) ? a : std::numeric_limits::signaling_NaN()) { + a_(a), b_(b), R_(util::is_approximately_equal(a, b) ? a : std::numeric_limits::signaling_NaN()) { ASSERT(0. < a); ASSERT(0. < b); } diff --git a/src/grit/geometry/BoundingBox.cc b/src/grit/geometry/BoundingBox.cc index ac073e874..f01c50a58 100644 --- a/src/grit/geometry/BoundingBox.cc +++ b/src/grit/geometry/BoundingBox.cc @@ -116,7 +116,7 @@ bool BoundingBox::intersects(BoundingBox& other) const { bool BoundingBox::empty() const { - return util::approximately_equal(north_, south_) || util::approximately_equal(west_, east_); + return util::is_approximately_equal(north_, south_) || util::is_approximately_equal(west_, east_); } diff --git a/src/grit/geometry/GreatCircle.cc b/src/grit/geometry/GreatCircle.cc index 37aa5e5e4..6d4475c81 100644 --- a/src/grit/geometry/GreatCircle.cc +++ b/src/grit/geometry/GreatCircle.cc @@ -23,7 +23,7 @@ namespace grit::geometry { static bool pole(double lat) { - return util::approximately_equal(std::abs(lat), 90.); + return util::is_approximately_equal(std::abs(lat), 90.); } @@ -32,10 +32,10 @@ GreatCircle::GreatCircle(const PointLatLon& A, const PointLatLon& B) : A_(A), B_ const bool Bpole = pole(B_.lat); const double lon12_deg = util::normalise_longitude_to_minimum(A_.lon - B_.lon, -180.); - const bool lon_same = Apole || Bpole || util::approximately_equal(lon12_deg, 0.); - const bool lon_opposite = Apole || Bpole || util::approximately_equal(std::abs(lon12_deg), 180.); - const bool lat_same = util::approximately_equal(A_.lat, B_.lat); - const bool lat_opposite = util::approximately_equal(A_.lat, -B_.lat); + const bool lon_same = Apole || Bpole || util::is_approximately_equal(lon12_deg, 0.); + const bool lon_opposite = Apole || Bpole || util::is_approximately_equal(std::abs(lon12_deg), 180.); + const bool lat_same = util::is_approximately_equal(A_.lat, B_.lat); + const bool lat_opposite = util::is_approximately_equal(A_.lat, -B_.lat); ASSERT_MSG(!(lat_same && lon_same) && !(lat_opposite && lon_opposite), "Great circle cannot be defined by points collinear with the centre"); @@ -80,18 +80,18 @@ std::vector GreatCircle::longitude(double lat) const { const double X = std::sin(lat1) * std::cos(lat2) * std::sin(lon12); const double Y = std::sin(lat1) * std::cos(lat2) * std::cos(lon12) - std::cos(lat1) * std::sin(lat2); - if (util::approximately_equal(X, 0.) && util::approximately_equal(Y, 0.)) { + if (util::is_approximately_equal(X, 0.) && util::is_approximately_equal(Y, 0.)) { return {}; // parallel (that is, equator) } const double lon0 = lon1 + std::atan2(Y, X); const double C = std::cos(lat1) * std::cos(lat2) * std::tan(lat3) * std::sin(lon12) / std::sqrt(X * X + Y * Y); - if (util::approximately_equal(C, -1.)) { + if (util::is_approximately_equal(C, -1.)) { return {util::radians_to_degrees * (lon0 + M_PI)}; } - if (util::approximately_equal(C, 1.)) { + if (util::is_approximately_equal(C, 1.)) { return {util::radians_to_degrees * lon0}; } diff --git a/src/grit/geometry/Sphere.cc b/src/grit/geometry/Sphere.cc index 36ae3c79e..4dfa76104 100644 --- a/src/grit/geometry/Sphere.cc +++ b/src/grit/geometry/Sphere.cc @@ -60,7 +60,7 @@ double Sphere::angle(const PointLatLon& A, const PointLatLon& B) { std::sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); - if (util::approximately_equal(sigma, 0.)) { + if (util::is_approximately_equal(sigma, 0.)) { return 0.; } @@ -75,7 +75,7 @@ double Sphere::angle(double radius, const Point3& A, const Point3& B) { // Δσ = 2 * asin( chord / 2 ) const double d2 = Point3::distance2(A, B); - if (util::approximately_equal(d2, 0.)) { + if (util::is_approximately_equal(d2, 0.)) { return 0.; } @@ -114,7 +114,7 @@ PointLatLon Sphere::xyz_to_ll(double radius, const Point3& A) { // numerical conditioning for both z (poles) and y const double x = A.x; - const double y = util::approximately_equal(A.y, 0.) ? 0. : A.y; + const double y = util::is_approximately_equal(A.y, 0.) ? 0. : A.y; const double z = std::min(radius, std::max(-radius, A.z)) / radius; return {util::radians_to_degrees * std::atan2(y, x), util::radians_to_degrees * std::asin(z)}; diff --git a/src/grit/geometry/Spheroid.cc b/src/grit/geometry/Spheroid.cc index 480151949..6d4c0ed34 100644 --- a/src/grit/geometry/Spheroid.cc +++ b/src/grit/geometry/Spheroid.cc @@ -47,7 +47,7 @@ Point3 Spheroid::ll_to_xyz(double a, double b, const PointLatLon& P, double heig const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); - if (util::approximately_equal(a, b)) { + if (util::is_approximately_equal(a, b)) { return {(a + height) * cos_phi * cos_lambda, (a + height) * cos_phi * sin_lambda, (a + height) * sin_phi}; } diff --git a/src/grit/util.h b/src/grit/util.h index cc6cc0efa..3dbbe0c99 100644 --- a/src/grit/util.h +++ b/src/grit/util.h @@ -25,7 +25,7 @@ namespace grit::util { template -bool approximately_equal(T x, T y, T eps = std::numeric_limits::epsilon()) { +bool is_approximately_equal(T x, T y, T eps = std::numeric_limits::epsilon()) { auto min = std::min(std::abs(x), std::abs(y)); return std::abs(min) == 0. ? std::abs(x - y) < eps : std::abs(x - y) / std::max(std::numeric_limits::min(), min) < eps; diff --git a/src/grit/util/arange.cc b/src/grit/util/arange.cc index 9db500ffb..c3cb36fea 100644 --- a/src/grit/util/arange.cc +++ b/src/grit/util/arange.cc @@ -21,7 +21,7 @@ namespace grit::util { std::vector arange(double start, double stop, double step) { - if (approximately_equal(step, 0.) || approximately_equal(start, stop) || (stop - start) * step < 0.) { + if (is_approximately_equal(step, 0.) || is_approximately_equal(start, stop) || (stop - start) * step < 0.) { std::vector l(1, start); return l; } From 7c1ddbe562c1747aae981738d849b36c6ae31e0d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 12 Apr 2023 17:39:08 +0100 Subject: [PATCH 129/737] util --- src/grit/CMakeLists.txt | 1 + src/grit/util.h | 3 +++ src/grit/util/arange.cc | 4 --- src/grit/util/monotonic_crop.cc | 46 +++++++++++++++++++++++++++++++++ tests/util.cc | 16 ++++++------ 5 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 src/grit/util/monotonic_crop.cc diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 64b913429..8e44ac2dd 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -32,6 +32,7 @@ add_library(grit SHARED util/arange.cc util/gaussian_latitudes.cc util/linspace.cc + util/monotonic_crop.cc util/reduced_classical_pl.cc util/reduced_octahedral_pl.cc util/regular_pl.cc) diff --git a/src/grit/util.h b/src/grit/util.h index 3dbbe0c99..861d662ce 100644 --- a/src/grit/util.h +++ b/src/grit/util.h @@ -62,6 +62,9 @@ std::vector linspace(double start, double stop, size_t num, bool endpoin std::vector gaussian_latitudes(size_t N, bool increasing); +std::vector monotonic_crop(std::vector&, double min, double max, double eps); + + /// @return longitude in degree within range [minimum, minimum + 360[ double normalise_longitude_to_minimum(double lon, double minimum); diff --git a/src/grit/util/arange.cc b/src/grit/util/arange.cc index c3cb36fea..d620e812a 100644 --- a/src/grit/util/arange.cc +++ b/src/grit/util/arange.cc @@ -10,10 +10,6 @@ */ -#include -#include -#include - #include "grit/util.h" diff --git a/src/grit/util/monotonic_crop.cc b/src/grit/util/monotonic_crop.cc new file mode 100644 index 000000000..8b54cad82 --- /dev/null +++ b/src/grit/util/monotonic_crop.cc @@ -0,0 +1,46 @@ +/* + * (C) Copyright 1996- 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 "grit/exception.h" +#include "grit/util.h" + + +namespace grit::util { + + +std::vector monotonic_crop(std::vector& values, double min, double max, double eps) { + ASSERT(!values.empty()); + ASSERT(min <= max); + + const bool increasing = values.front() <= values.back(); + + if (max < values.back()) { + max = values.back(); + } + else if (max <= values.front()) { + auto it = std::lower_bound(values.rbegin(), values.rend(), max); + max = *it; + } + + if (min > values.front()) { + min = values.front(); + } + else if (min >= values.back()) { + auto it = std::lower_bound(values.begin(), values.end(), min, [](double l1, double l2) { return l1 > l2; }); + min = *it; + } + + ASSERT(min <= max); +} + + +} // namespace grit::util diff --git a/tests/util.cc b/tests/util.cc index c5eca4c36..870db4f26 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -69,18 +69,18 @@ class iterable_t : public std::vector { int main(int argc, char* argv[]) { - // std::cout << grit::util::linspace(1, 2, 2, true) << std::endl; - // std::cout << grit::util::arange(1, 2, 0.5) << std::endl; - // std::cout << grit::util::gaussian_latitudes(64, false) << std::endl; - // std::cout << grit::util::normalise_longitude_to_maximum(0.,0.) << std::endl; - // std::cout << grit::util::normalise_longitude_to_minimum(0.,0.) << std::endl; - +#if 0 + std::cout << grit::util::linspace(1, 2, 2, true) << std::endl; + std::cout << grit::util::arange(1, 2, 0.5) << std::endl; + std::cout << grit::util::gaussian_latitudes(64, false) << std::endl; + std::cout << grit::util::normalise_longitude_to_maximum(0., 360.) << std::endl; + std::cout << grit::util::normalise_longitude_to_minimum(0., -360.) << std::endl; +#elif 0 std::cout << grit::util::reduced_classical_pl(16) << std::endl; std::cout << grit::util::reduced_classical_pl(16) << std::endl; std::cout << grit::util::reduced_octahedral_pl(16) << std::endl; std::cout << grit::util::reduced_octahedral_pl(16) << std::endl; - -#if 0 +#else iterable_t it{1, 2, 3, 4}; for (const auto& v : it) { From 8e98cd016ce08155520dcd55669ba63bf53fb255 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 13 Apr 2023 11:10:04 +0100 Subject: [PATCH 130/737] util --- src/grit/util.h | 2 +- src/grit/util/monotonic_crop.cc | 5 ++++- tests/util.cc | 7 ++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/grit/util.h b/src/grit/util.h index 861d662ce..bdc281aea 100644 --- a/src/grit/util.h +++ b/src/grit/util.h @@ -62,7 +62,7 @@ std::vector linspace(double start, double stop, size_t num, bool endpoin std::vector gaussian_latitudes(size_t N, bool increasing); -std::vector monotonic_crop(std::vector&, double min, double max, double eps); +std::vector monotonic_crop(const std::vector&, double min, double max, double eps); /// @return longitude in degree within range [minimum, minimum + 360[ diff --git a/src/grit/util/monotonic_crop.cc b/src/grit/util/monotonic_crop.cc index 8b54cad82..c3308900c 100644 --- a/src/grit/util/monotonic_crop.cc +++ b/src/grit/util/monotonic_crop.cc @@ -17,7 +17,7 @@ namespace grit::util { -std::vector monotonic_crop(std::vector& values, double min, double max, double eps) { +std::vector monotonic_crop(const std::vector& values, double min, double max, double eps) { ASSERT(!values.empty()); ASSERT(min <= max); @@ -40,6 +40,9 @@ std::vector monotonic_crop(std::vector& values, double min, doub } ASSERT(min <= max); + + // FIXME + return values; } diff --git a/tests/util.cc b/tests/util.cc index 870db4f26..6734a04be 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -80,7 +80,7 @@ int main(int argc, char* argv[]) { std::cout << grit::util::reduced_classical_pl(16) << std::endl; std::cout << grit::util::reduced_octahedral_pl(16) << std::endl; std::cout << grit::util::reduced_octahedral_pl(16) << std::endl; -#else +#elif 0 iterable_t it{1, 2, 3, 4}; for (const auto& v : it) { @@ -88,5 +88,10 @@ int main(int argc, char* argv[]) { } std::cout << std::accumulate(it.begin(), it.end(), 0) << std::endl; +#else + std::vector values1{4., 3., 2., 1.}; + std::vector values2{1., 2., 3., 4.}; + + std::cout << grit::util::monotonic_crop(values1, 2., 3., 0.) << std::endl; #endif } From ee9ff34e7c1d07ca4274fe0a882840c20d9fb6ae Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 13 Apr 2023 11:23:04 +0100 Subject: [PATCH 131/737] util --- src/grit/util/monotonic_crop.cc | 17 +++++++++++++++-- tests/util.cc | 4 ++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/grit/util/monotonic_crop.cc b/src/grit/util/monotonic_crop.cc index c3308900c..8d6e37285 100644 --- a/src/grit/util/monotonic_crop.cc +++ b/src/grit/util/monotonic_crop.cc @@ -10,6 +10,9 @@ */ +#include +#include + #include "grit/exception.h" #include "grit/util.h" @@ -28,7 +31,10 @@ std::vector monotonic_crop(const std::vector& values, double min } else if (max <= values.front()) { auto it = std::lower_bound(values.rbegin(), values.rend(), max); - max = *it; + + std::cout << "max it: " << std::distance(values.rbegin(), it) << std::endl; + + max = *it; } if (min > values.front()) { @@ -36,11 +42,18 @@ std::vector monotonic_crop(const std::vector& values, double min } else if (min >= values.back()) { auto it = std::lower_bound(values.begin(), values.end(), min, [](double l1, double l2) { return l1 > l2; }); - min = *it; + + std::cout << "min it: " << std::distance(values.begin(), it) << std::endl; + + min = *it; } ASSERT(min <= max); + + std::cout << "min: " << min << '\n' << "max: " << max << std::endl; + + // FIXME return values; } diff --git a/tests/util.cc b/tests/util.cc index 6734a04be..c6cdd332c 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -89,8 +89,8 @@ int main(int argc, char* argv[]) { std::cout << std::accumulate(it.begin(), it.end(), 0) << std::endl; #else - std::vector values1{4., 3., 2., 1.}; - std::vector values2{1., 2., 3., 4.}; + std::vector values1{6., 5., 4., 3., 2., 1.}; + std::vector values2{1., 2., 3., 4., 5., 6.}; std::cout << grit::util::monotonic_crop(values1, 2., 3., 0.) << std::endl; #endif From 6cb84582c237c7364248d0508ff0c076e46fbe06 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 13 Apr 2023 12:18:23 +0100 Subject: [PATCH 132/737] util --- src/grit/util/monotonic_crop.cc | 40 +++++++++++---------------------- tests/util.cc | 6 +++-- 2 files changed, 17 insertions(+), 29 deletions(-) diff --git a/src/grit/util/monotonic_crop.cc b/src/grit/util/monotonic_crop.cc index 8d6e37285..02f14748e 100644 --- a/src/grit/util/monotonic_crop.cc +++ b/src/grit/util/monotonic_crop.cc @@ -10,6 +10,7 @@ */ +#include #include #include @@ -21,41 +22,26 @@ namespace grit::util { std::vector monotonic_crop(const std::vector& values, double min, double max, double eps) { - ASSERT(!values.empty()); - ASSERT(min <= max); - - const bool increasing = values.front() <= values.back(); - - if (max < values.back()) { - max = values.back(); + if (values.empty() || min > max) { + return {}; } - else if (max <= values.front()) { - auto it = std::lower_bound(values.rbegin(), values.rend(), max); - std::cout << "max it: " << std::distance(values.rbegin(), it) << std::endl; - - max = *it; - } + ASSERT(!values.empty() && min <= max); - if (min > values.front()) { - min = values.front(); - } - else if (min >= values.back()) { - auto it = std::lower_bound(values.begin(), values.end(), min, [](double l1, double l2) { return l1 > l2; }); + auto lt = [eps](double a, double b) { return a < b && (0. == eps || !is_approximately_equal(a, b, eps)); }; - std::cout << "min it: " << std::distance(values.begin(), it) << std::endl; + if (values.size() == 1 || values.front() < values.back()) { + // monotonically increasing + ASSERT(std::is_sorted(values.begin(), values.end())); - min = *it; + return {std::lower_bound(values.begin(), values.end(), min, lt), + std::upper_bound(values.begin(), values.end(), max, lt)}; } - ASSERT(min <= max); - - - std::cout << "min: " << min << '\n' << "max: " << max << std::endl; - + // monotonically decreasing + ASSERT(std::is_sorted(values.rbegin(), values.rend())); - // FIXME - return values; + return {}; // FIXME } diff --git a/tests/util.cc b/tests/util.cc index c6cdd332c..8912ad193 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -89,9 +89,11 @@ int main(int argc, char* argv[]) { std::cout << std::accumulate(it.begin(), it.end(), 0) << std::endl; #else - std::vector values1{6., 5., 4., 3., 2., 1.}; - std::vector values2{1., 2., 3., 4., 5., 6.}; + std::vector values1{1., 2., 3., 4., 5., 6.}; + std::vector values2{6., 5., 4., 3., 2., 1.}; + std::cout << grit::util::monotonic_crop({1.}, 1., 1., 0.) << std::endl; std::cout << grit::util::monotonic_crop(values1, 2., 3., 0.) << std::endl; + std::cout << grit::util::monotonic_crop(values2, 2., 3., 0.) << std::endl; #endif } From 56843ffb1500757d186039b97b5ee5aca1319c14 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 13 Apr 2023 12:27:28 +0100 Subject: [PATCH 133/737] util --- src/grit/util/monotonic_crop.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/grit/util/monotonic_crop.cc b/src/grit/util/monotonic_crop.cc index 02f14748e..078e1aae2 100644 --- a/src/grit/util/monotonic_crop.cc +++ b/src/grit/util/monotonic_crop.cc @@ -11,8 +11,6 @@ #include -#include -#include #include "grit/exception.h" #include "grit/util.h" @@ -26,22 +24,24 @@ std::vector monotonic_crop(const std::vector& values, double min return {}; } - ASSERT(!values.empty() && min <= max); - auto lt = [eps](double a, double b) { return a < b && (0. == eps || !is_approximately_equal(a, b, eps)); }; - - if (values.size() == 1 || values.front() < values.back()) { - // monotonically increasing + // monotonically increasing + const auto increasing = values.size() == 1 || values.front() < values.back(); + if (increasing) { ASSERT(std::is_sorted(values.begin(), values.end())); + auto lt = [eps](double a, double b) { return a < b && (0. == eps || !is_approximately_equal(a, b, eps)); }; return {std::lower_bound(values.begin(), values.end(), min, lt), std::upper_bound(values.begin(), values.end(), max, lt)}; } + // monotonically decreasing ASSERT(std::is_sorted(values.rbegin(), values.rend())); - return {}; // FIXME + auto gt = [eps](double a, double b) { return a > b && (0. == eps || !is_approximately_equal(a, b, eps)); }; + return {std::lower_bound(values.begin(), values.end(), max, gt), + std::upper_bound(values.begin(), values.end(), min, gt)}; } From 113359146129f000bbfff2ef8b5d526823c8872c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 13 Apr 2023 12:34:41 +0100 Subject: [PATCH 134/737] util --- src/grit/util/monotonic_crop.cc | 2 +- tests/util.cc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/grit/util/monotonic_crop.cc b/src/grit/util/monotonic_crop.cc index 078e1aae2..f07eafded 100644 --- a/src/grit/util/monotonic_crop.cc +++ b/src/grit/util/monotonic_crop.cc @@ -36,7 +36,7 @@ std::vector monotonic_crop(const std::vector& values, double min } - // monotonically decreasing + // monotonically non-increasing ASSERT(std::is_sorted(values.rbegin(), values.rend())); auto gt = [eps](double a, double b) { return a > b && (0. == eps || !is_approximately_equal(a, b, eps)); }; diff --git a/tests/util.cc b/tests/util.cc index 8912ad193..d727a9e17 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -93,6 +93,7 @@ int main(int argc, char* argv[]) { std::vector values2{6., 5., 4., 3., 2., 1.}; std::cout << grit::util::monotonic_crop({1.}, 1., 1., 0.) << std::endl; + std::cout << grit::util::monotonic_crop({1., 1., 1.}, 1., 2., 0.) << std::endl; std::cout << grit::util::monotonic_crop(values1, 2., 3., 0.) << std::endl; std::cout << grit::util::monotonic_crop(values2, 2., 3., 0.) << std::endl; #endif From 25237fc12d13cbc55542a2fd72228f90f9a1dc23 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 13 Apr 2023 17:17:27 +0100 Subject: [PATCH 135/737] util --- tests/util.cc | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/util.cc b/tests/util.cc index d727a9e17..edbd8dfe6 100644 --- a/tests/util.cc +++ b/tests/util.cc @@ -11,7 +11,6 @@ #include -#include #include "grit/util.h" @@ -81,14 +80,6 @@ int main(int argc, char* argv[]) { std::cout << grit::util::reduced_octahedral_pl(16) << std::endl; std::cout << grit::util::reduced_octahedral_pl(16) << std::endl; #elif 0 - iterable_t it{1, 2, 3, 4}; - - for (const auto& v : it) { - std::cout << v << std::endl; - } - - std::cout << std::accumulate(it.begin(), it.end(), 0) << std::endl; -#else std::vector values1{1., 2., 3., 4., 5., 6.}; std::vector values2{6., 5., 4., 3., 2., 1.}; From 76080720a691fb06441e4567a178a796531437c4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 13 Apr 2023 17:27:29 +0100 Subject: [PATCH 136/737] iterator --- src/grit/Scanner.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/grit/Scanner.h b/src/grit/Scanner.h index 188a3bbe4..e7290a0e6 100644 --- a/src/grit/Scanner.h +++ b/src/grit/Scanner.h @@ -10,6 +10,9 @@ */ +#include + + namespace grit { @@ -23,7 +26,7 @@ class Scanner { // -- Constructors - Scanner(); + Scanner() = default; Scanner(const Scanner&) = delete; Scanner(Scanner&&) = delete; @@ -43,7 +46,8 @@ class Scanner { virtual bool operator++() = 0; // -- Methods - // None + + virtual size_t size() const = 0; // -- Overridden methods // None From 0f1b87b97eb16e2551417e96c18c2a6db8d08a9b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 13 Apr 2023 17:28:50 +0100 Subject: [PATCH 137/737] iterator --- src/grit/types.h | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/grit/types.h b/src/grit/types.h index be2d184b5..339f9fb30 100644 --- a/src/grit/types.h +++ b/src/grit/types.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include @@ -27,10 +28,18 @@ struct PointLatLon : std::array { }; -struct Point3 : std::array { - Point3(double x, double y, double z) : array{x, y, z} {} +struct PointXY : std::array { + PointXY(double x, double y); - static double distance2(const Point3& a, const Point3& b) { + double& x = operator[](0); + double& y = operator[](1); +}; + + +struct PointXYZ : std::array { + PointXYZ(double x, double y, double z) : array{x, y, z} {} + + static double distance2(const PointXYZ& a, const PointXYZ& b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z); } @@ -40,6 +49,15 @@ struct Point3 : std::array { }; +using Point2 = PointXY; + + +using Point3 = PointXYZ; + + +using Point = std::variant; + + using pl_type = std::vector; From 0c695a067a186389a3bd9053a9b605b8120f00ae Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 13 Apr 2023 17:41:09 +0100 Subject: [PATCH 138/737] iterator --- src/grit/Iterator.cc | 10 +++++-- src/grit/Iterator.h | 62 ++++++++++++++++++++++++++++++++------------ 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/src/grit/Iterator.cc b/src/grit/Iterator.cc index 82f79ea82..8f50887c2 100644 --- a/src/grit/Iterator.cc +++ b/src/grit/Iterator.cc @@ -23,8 +23,8 @@ namespace grit { Iterator::Iterator(Scanner* scanner, Figure* figure, Transformation* transformation) : scanner_(scanner), figure_(figure), transformation_(transformation) { - ASSERT(bool(scanner)); - ASSERT(bool(figure)); + ASSERT(scanner_); + ASSERT(figure_); } @@ -33,4 +33,10 @@ bool Iterator::operator++() { } +size_t Iterator::size() const { + ASSERT(scanner_); + return scanner_->size(); +} + + } // namespace grit diff --git a/src/grit/Iterator.h b/src/grit/Iterator.h index 1b81c8322..c8542cc3f 100644 --- a/src/grit/Iterator.h +++ b/src/grit/Iterator.h @@ -12,6 +12,8 @@ #include +#include "grit/types.h" + namespace grit { struct Figure; @@ -23,10 +25,43 @@ struct Transformation; namespace grit { -class Iterator { +class Iterator final { public: // -- Types - // None + + using value_type = Point; + +private: + // -- Types + + template + struct iterator_t { + X& cnt; + size_t pos; + + bool operator!=(const iterator_t& other) const { return &cnt != &other.cnt || pos != other.pos; } + + iterator_t& operator++() { + pos++; + return *this; + } + + iterator_t operator++(int) { + auto old = *this; + operator++(); + return old; + } + + typename X::value_type& operator*() { return cnt.at(pos); } + + const typename X::value_type& operator*() const { return cnt.at(pos); } + }; + +public: + // -- Types + + using iterator = iterator_t; + using const_iterator = iterator_t; // -- Exceptions // None @@ -43,7 +78,7 @@ class Iterator { // -- Destructor - virtual ~Iterator() = delete; + ~Iterator() = delete; // -- Convertors // None @@ -51,25 +86,20 @@ class Iterator { // -- Operators bool operator++(); + bool operator++(int) { return operator++(); } // -- Methods - // None - // -- Overridden methods - // None - - // -- Class members - // None + size_t size() const; - // -- Class methods - // None + iterator begin() { return {*this, 0}; } + iterator end() { return {*this, this->size()}; } -protected: - // -- Members - // None + const_iterator cbegin() const { return {*this, 0}; } + const_iterator cend() const { return {*this, this->size()}; } - // -- Methods - // None + const_iterator begin() const { return cbegin(); } + const_iterator end() const { return cend(); } // -- Overridden methods // None From 2f3a80f95859090a8f559a95269eb6f52180324b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 13 Apr 2023 17:51:35 +0100 Subject: [PATCH 139/737] projection --- src/grit/Figure.h | 8 ++++---- src/grit/Projection.h | 6 +++--- src/grit/figure/Sphere.cc | 8 ++++---- src/grit/figure/Sphere.h | 8 ++++---- src/grit/figure/Spheroid.cc | 8 ++++---- src/grit/figure/Spheroid.h | 8 ++++---- src/grit/geometry/Sphere.cc | 10 +++++----- src/grit/geometry/Sphere.h | 8 ++++---- src/grit/geometry/Spheroid.cc | 2 +- src/grit/geometry/Spheroid.h | 8 ++++---- src/grit/types.h | 6 ------ 11 files changed, 37 insertions(+), 43 deletions(-) diff --git a/src/grit/Figure.h b/src/grit/Figure.h index c7e991135..d79dc32b1 100644 --- a/src/grit/Figure.h +++ b/src/grit/Figure.h @@ -58,22 +58,22 @@ class Figure { virtual double angle(const PointLatLon&, const PointLatLon&) const = 0; /// Great-circle central angle between two points (Cartesian coordinates) in radians - virtual double angle(const Point3&, const Point3&) const = 0; + virtual double angle(const PointXYZ&, const PointXYZ&) const = 0; /// Great-circle distance between two points (latitude/longitude coordinates) in metres virtual double distance(const PointLatLon&, const PointLatLon&) const = 0; /// Great-circle distance between two points (Cartesian coordinates) in metres - virtual double distance(const Point3&, const Point3&) const = 0; + virtual double distance(const PointXYZ&, const PointXYZ&) const = 0; /// Surface area in square metres virtual double area() const = 0; // Convert spherical coordinates to Cartesian - virtual Point3 ll_to_xyz(const PointLatLon&, double height) const = 0; + virtual PointXYZ ll_to_xyz(const PointLatLon&, double height) const = 0; // Convert Cartesian coordinates to spherical - virtual PointLatLon xyz_to_ll(const Point3&) const = 0; + virtual PointLatLon xyz_to_ll(const PointXYZ&) const = 0; // -- Overridden methods // None diff --git a/src/grit/Projection.h b/src/grit/Projection.h index c1b0e5ff2..cb5b901c5 100644 --- a/src/grit/Projection.h +++ b/src/grit/Projection.h @@ -47,10 +47,10 @@ class Projection { // -- Methods - virtual Point3 direct(const PointLatLon&) const; - virtual Point3 inverse(const Point3&) const; + virtual PointXYZ direct(const PointLatLon&) const; + virtual PointXYZ inverse(const PointXYZ&) const; virtual PointLatLon to_(const PointLatLon&) const; - virtual PointLatLon to_(const Point3&) const; + virtual PointLatLon to_(const PointXYZ&) const; // -- Overridden methods // None diff --git a/src/grit/figure/Sphere.cc b/src/grit/figure/Sphere.cc index bb7589a61..3f182f535 100644 --- a/src/grit/figure/Sphere.cc +++ b/src/grit/figure/Sphere.cc @@ -23,7 +23,7 @@ double Sphere::angle(const PointLatLon& A, const PointLatLon& B) const { } -double Sphere::angle(const Point3& A, const Point3& B) const { +double Sphere::angle(const PointXYZ& A, const PointXYZ& B) const { return geometry::Sphere::angle(R(), A, B); } @@ -33,7 +33,7 @@ double Sphere::distance(const PointLatLon& A, const PointLatLon& B) const { } -double Sphere::distance(const Point3& A, const Point3& B) const { +double Sphere::distance(const PointXYZ& A, const PointXYZ& B) const { return geometry::Sphere::distance(R(), A, B); } @@ -43,12 +43,12 @@ double Sphere::area() const { } -Point3 Sphere::ll_to_xyz(const PointLatLon& P, double height) const { +PointXYZ Sphere::ll_to_xyz(const PointLatLon& P, double height) const { return geometry::Sphere::ll_to_xyz(R(), P, height); } -PointLatLon Sphere::xyz_to_ll(const Point3& P) const { +PointLatLon Sphere::xyz_to_ll(const PointXYZ& P) const { return geometry::Sphere::xyz_to_ll(R(), P); } diff --git a/src/grit/figure/Sphere.h b/src/grit/figure/Sphere.h index 14bdadf11..cfbc70406 100644 --- a/src/grit/figure/Sphere.h +++ b/src/grit/figure/Sphere.h @@ -45,12 +45,12 @@ class Sphere final : public Figure { // -- Overridden methods double angle(const PointLatLon&, const PointLatLon&) const override; - double angle(const Point3&, const Point3&) const override; + double angle(const PointXYZ&, const PointXYZ&) const override; double distance(const PointLatLon&, const PointLatLon&) const override; - double distance(const Point3&, const Point3&) const override; + double distance(const PointXYZ&, const PointXYZ&) const override; double area() const override; - Point3 ll_to_xyz(const PointLatLon&, double height) const override; - PointLatLon xyz_to_ll(const Point3&) const override; + PointXYZ ll_to_xyz(const PointLatLon&, double height) const override; + PointLatLon xyz_to_ll(const PointXYZ&) const override; // -- Class members // None diff --git a/src/grit/figure/Spheroid.cc b/src/grit/figure/Spheroid.cc index 7f2b917c1..16fda1f58 100644 --- a/src/grit/figure/Spheroid.cc +++ b/src/grit/figure/Spheroid.cc @@ -24,7 +24,7 @@ double Spheroid::angle(const PointLatLon& A, const PointLatLon& B) const { } -double Spheroid::angle(const Point3& A, const Point3& B) const { +double Spheroid::angle(const PointXYZ& A, const PointXYZ& B) const { NOTIMP; } @@ -34,7 +34,7 @@ double Spheroid::distance(const PointLatLon& A, const PointLatLon& B) const { } -double Spheroid::distance(const Point3& A, const Point3& B) const { +double Spheroid::distance(const PointXYZ& A, const PointXYZ& B) const { NOTIMP; } @@ -44,12 +44,12 @@ double Spheroid::area() const { } -Point3 Spheroid::ll_to_xyz(const PointLatLon& P, double height) const { +PointXYZ Spheroid::ll_to_xyz(const PointLatLon& P, double height) const { NOTIMP; } -PointLatLon Spheroid::xyz_to_ll(const Point3& P) const { +PointLatLon Spheroid::xyz_to_ll(const PointXYZ& P) const { NOTIMP; } diff --git a/src/grit/figure/Spheroid.h b/src/grit/figure/Spheroid.h index 4ee1cd300..e0c9589ac 100644 --- a/src/grit/figure/Spheroid.h +++ b/src/grit/figure/Spheroid.h @@ -45,12 +45,12 @@ class Spheroid final : public Figure { // -- Overridden methods double angle(const PointLatLon&, const PointLatLon&) const override; - double angle(const Point3&, const Point3&) const override; + double angle(const PointXYZ&, const PointXYZ&) const override; double distance(const PointLatLon&, const PointLatLon&) const override; - double distance(const Point3&, const Point3&) const override; + double distance(const PointXYZ&, const PointXYZ&) const override; double area() const override; - Point3 ll_to_xyz(const PointLatLon&, double height) const override; - PointLatLon xyz_to_ll(const Point3&) const override; + PointXYZ ll_to_xyz(const PointLatLon&, double height) const override; + PointLatLon xyz_to_ll(const PointXYZ&) const override; // -- Class members // None diff --git a/src/grit/geometry/Sphere.cc b/src/grit/geometry/Sphere.cc index 4dfa76104..cb00b3c4d 100644 --- a/src/grit/geometry/Sphere.cc +++ b/src/grit/geometry/Sphere.cc @@ -69,12 +69,12 @@ double Sphere::angle(const PointLatLon& A, const PointLatLon& B) { } -double Sphere::angle(double radius, const Point3& A, const Point3& B) { +double Sphere::angle(double radius, const PointXYZ& A, const PointXYZ& B) { ASSERT(radius > 0.); // Δσ = 2 * asin( chord / 2 ) - const double d2 = Point3::distance2(A, B); + const double d2 = PointXYZ::distance2(A, B); if (util::is_approximately_equal(d2, 0.)) { return 0.; } @@ -92,7 +92,7 @@ double Sphere::distance(double radius, const PointLatLon& A, const PointLatLon& } -double Sphere::distance(double radius, const Point3& A, const Point3& B) { +double Sphere::distance(double radius, const PointXYZ& A, const PointXYZ& B) { return radius * angle(radius, A, B); } @@ -103,12 +103,12 @@ double Sphere::area(double radius) { } -Point3 Sphere::ll_to_xyz(double radius, const PointLatLon& P, double height) { +PointXYZ Sphere::ll_to_xyz(double radius, const PointLatLon& P, double height) { return Spheroid::ll_to_xyz(radius, radius, P, height); } -PointLatLon Sphere::xyz_to_ll(double radius, const Point3& A) { +PointLatLon Sphere::xyz_to_ll(double radius, const PointXYZ& A) { ASSERT(radius > 0.); // numerical conditioning for both z (poles) and y diff --git a/src/grit/geometry/Sphere.h b/src/grit/geometry/Sphere.h index 0ea063479..05ba24598 100644 --- a/src/grit/geometry/Sphere.h +++ b/src/grit/geometry/Sphere.h @@ -23,22 +23,22 @@ struct Sphere { static double angle(const PointLatLon&, const PointLatLon&); /// Great-circle central angle between two points (Cartesian coordinates) in radians - static double angle(double radius, const Point3&, const Point3&); + static double angle(double radius, const PointXYZ&, const PointXYZ&); /// Great-circle distance between two points (latitude/longitude coordinates) in metres static double distance(double radius, const PointLatLon&, const PointLatLon&); /// Great-circle distance between two points (Cartesian coordinates) in metres - static double distance(double radius, const Point3&, const Point3&); + static double distance(double radius, const PointXYZ&, const PointXYZ&); /// Surface area in square metres static double area(double radius); // Convert spherical coordinates to Cartesian - static Point3 ll_to_xyz(double radius, const PointLatLon&, double height); + static PointXYZ ll_to_xyz(double radius, const PointLatLon&, double height); // Convert Cartesian coordinates to spherical - static PointLatLon xyz_to_ll(double radius, const Point3&); + static PointLatLon xyz_to_ll(double radius, const PointXYZ&); }; diff --git a/src/grit/geometry/Spheroid.cc b/src/grit/geometry/Spheroid.cc index 6d4c0ed34..45da8732d 100644 --- a/src/grit/geometry/Spheroid.cc +++ b/src/grit/geometry/Spheroid.cc @@ -21,7 +21,7 @@ namespace grit::geometry { -Point3 Spheroid::ll_to_xyz(double a, double b, const PointLatLon& P, double height) { +PointXYZ Spheroid::ll_to_xyz(double a, double b, const PointLatLon& P, double height) { ASSERT(a > 0.); ASSERT(b > 0.); diff --git a/src/grit/geometry/Spheroid.h b/src/grit/geometry/Spheroid.h index 9fbbf96c6..63cd5de4b 100644 --- a/src/grit/geometry/Spheroid.h +++ b/src/grit/geometry/Spheroid.h @@ -26,7 +26,7 @@ struct Spheroid { #if 0 /// Great-circle central angle between two points (Cartesian coordinates) in radians - static double angle(double a, double b, const Point3&, const Point3&); + static double angle(double a, double b, const PointXYZ&, const PointXYZ&); #endif #if 0 @@ -36,7 +36,7 @@ struct Spheroid { #if 0 /// Great-circle distance between two points (Cartesian coordinates) in metres - static double distance(double a, double b, const Point3&, const Point3&); + static double distance(double a, double b, const PointXYZ&, const PointXYZ&); #endif #if 0 @@ -45,11 +45,11 @@ struct Spheroid { #endif // Convert spherical coordinates to Cartesian - static Point3 ll_to_xyz(double a, double b, const PointLatLon&, double height); + static PointXYZ ll_to_xyz(double a, double b, const PointLatLon&, double height); #if 0 // Convert Cartesian coordinates to spherical - static PointLatLon xyz_to_ll(double a, double b, const Point3&); + static PointLatLon xyz_to_ll(double a, double b, const PointXYZ&); #endif }; diff --git a/src/grit/types.h b/src/grit/types.h index 339f9fb30..131ff35ce 100644 --- a/src/grit/types.h +++ b/src/grit/types.h @@ -49,12 +49,6 @@ struct PointXYZ : std::array { }; -using Point2 = PointXY; - - -using Point3 = PointXYZ; - - using Point = std::variant; From 6a1e49f464a0ff002b02ea95dc4eeac4fae02ff6 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 13 Apr 2023 17:57:18 +0100 Subject: [PATCH 140/737] projection --- src/grit/Projection.cc | 105 ++++++++++++++++++++++++++++++++++++- src/grit/Projection.h | 6 +-- src/grit/Transformation.cc | 105 +------------------------------------ src/grit/Transformation.h | 82 ++++++++++++++++++++++++++++- 4 files changed, 188 insertions(+), 110 deletions(-) diff --git a/src/grit/Projection.cc b/src/grit/Projection.cc index a94feb665..0e662a6cb 100644 --- a/src/grit/Projection.cc +++ b/src/grit/Projection.cc @@ -15,4 +15,107 @@ // #include <> -namespace grit {} // namespace grit +namespace grit { + + +#if 0 +- mercator: + double DiInMetres + double DjInMetres + double LaDInDegrees + double latitudeOfFirstPointInDegrees + double longitudeOfFirstPointInDegrees + double projectionOrientationInDegrees + size_t n_i + size_t n_j +- polar_stereographic: + double DiInMetres + double DjInMetres + double LaDInDegrees + double latitudeOfFirstPointInDegrees + double longitudeOfFirstPointInDegrees + double projectionOrientationInDegrees + flags projectionCentreFlag + size_t n_i + size_t n_j +- lambert: + double DiInMetres + double DjInMetres + double LaDInDegrees + double Latin1InDegrees + double Latin2InDegrees + double LoVInDegrees + double latitudeOfFirstPointInDegrees + double latitudeOfSouthernPoleInDegrees + double longitudeOfFirstPointInDegrees + double longitudeOfSouthernPoleInDegrees + flags projectionCentreFlag + size_t n_i + size_t n_j +- albers: + double DiInMetres + double DjInMetres + double LaDInDegrees + double Latin1InDegrees + double Latin2InDegrees + double LoVInDegrees + double latitudeOfFirstPointInDegrees + double latitudeOfSouthernPoleInDegrees + double longitudeOfFirstPointInDegrees + double longitudeOfSouthernPoleInDegrees + flags projectionCentreFlag + size_t n_i + size_t n_j +- space_view: + double DiInMetres + double DjInMetres + double altitudeFromEarthCentreInMetres + double latitudeOfSubSatellitePointInDegrees + double longitudeOfSubSatellitePointInDegrees + double projectionOrientationInDegrees + double xOriginOfSectorImageInMetres + double xSubSatellitePointInMetres + double yOriginOfSectorImageInMetres + double ySubSatellitePointInMetres + size_t n_i + size_t n_j +- lambert_azimuthal_equal_area: + double DiInMetres + double DjInMetres + double centralLongitudeInDegrees + double latitudeOfFirstPointInDegrees + double longitudeOfFirstPointInDegrees + double standardParallelInDegrees +- equatorial_azimuthal_equidistant: + double DiInMetres + double DjInMetres + double latitudeOfTangencyPointInDegrees + double longitudeOfTangencyPointInDegrees + flags projectionCentreFlag +- unstructured_grid (grib2/localConcepts/[centre:s]/unstructuredGrid*): + string unstructuredGridSubtype = undefined/T/U/V/W/F (numberOfGridInReference) + string unstructuredGridType = undefined/ORCA2/ORCA1/ORCA025/ORCA12/eORCA1/eORCA025/eORCA12 (numberOfGridInReference) + string uuidOfHGrid +- irregular_latlon + +Projection, rotation, shape (grib2/template.3.(rotation|shape_of_the_earth).def) +- projSourceString, projTargetString, projString=projTargetString + + double latitudeOfSouthernPoleInDegrees + double longitudeOfSouthernPoleInDegrees + double angleOfRotationInDegrees + + bool is_oblate + double majorAxisInMetres + double minorAxisInMetres + double radiusInMetres + +Projection centre (grib2/tables/30/3.5.table) + 1 0 North Pole is on the projection plane + 1 1 South Pole is on the projection plane + 2 0 Only one projection centre is used + 2 1 Projection is bipolar and symmetric +#endif + + +} // namespace grit diff --git a/src/grit/Projection.h b/src/grit/Projection.h index cb5b901c5..99eddfeec 100644 --- a/src/grit/Projection.h +++ b/src/grit/Projection.h @@ -47,10 +47,8 @@ class Projection { // -- Methods - virtual PointXYZ direct(const PointLatLon&) const; - virtual PointXYZ inverse(const PointXYZ&) const; - virtual PointLatLon to_(const PointLatLon&) const; - virtual PointLatLon to_(const PointXYZ&) const; + virtual Point direct(const Point&) const = 0; + virtual Point inverse(const Point&) const = 0; // -- Overridden methods // None diff --git a/src/grit/Transformation.cc b/src/grit/Transformation.cc index 64c718fc4..7f8b737ff 100644 --- a/src/grit/Transformation.cc +++ b/src/grit/Transformation.cc @@ -13,107 +13,4 @@ #include "grit/Transformation.h" -namespace grit { - - -#if 0 -- mercator: - double DiInMetres - double DjInMetres - double LaDInDegrees - double latitudeOfFirstPointInDegrees - double longitudeOfFirstPointInDegrees - double projectionOrientationInDegrees - size_t n_i - size_t n_j -- polar_stereographic: - double DiInMetres - double DjInMetres - double LaDInDegrees - double latitudeOfFirstPointInDegrees - double longitudeOfFirstPointInDegrees - double projectionOrientationInDegrees - flags projectionCentreFlag - size_t n_i - size_t n_j -- lambert: - double DiInMetres - double DjInMetres - double LaDInDegrees - double Latin1InDegrees - double Latin2InDegrees - double LoVInDegrees - double latitudeOfFirstPointInDegrees - double latitudeOfSouthernPoleInDegrees - double longitudeOfFirstPointInDegrees - double longitudeOfSouthernPoleInDegrees - flags projectionCentreFlag - size_t n_i - size_t n_j -- albers: - double DiInMetres - double DjInMetres - double LaDInDegrees - double Latin1InDegrees - double Latin2InDegrees - double LoVInDegrees - double latitudeOfFirstPointInDegrees - double latitudeOfSouthernPoleInDegrees - double longitudeOfFirstPointInDegrees - double longitudeOfSouthernPoleInDegrees - flags projectionCentreFlag - size_t n_i - size_t n_j -- space_view: - double DiInMetres - double DjInMetres - double altitudeFromEarthCentreInMetres - double latitudeOfSubSatellitePointInDegrees - double longitudeOfSubSatellitePointInDegrees - double projectionOrientationInDegrees - double xOriginOfSectorImageInMetres - double xSubSatellitePointInMetres - double yOriginOfSectorImageInMetres - double ySubSatellitePointInMetres - size_t n_i - size_t n_j -- lambert_azimuthal_equal_area: - double DiInMetres - double DjInMetres - double centralLongitudeInDegrees - double latitudeOfFirstPointInDegrees - double longitudeOfFirstPointInDegrees - double standardParallelInDegrees -- equatorial_azimuthal_equidistant: - double DiInMetres - double DjInMetres - double latitudeOfTangencyPointInDegrees - double longitudeOfTangencyPointInDegrees - flags projectionCentreFlag -- unstructured_grid (grib2/localConcepts/[centre:s]/unstructuredGrid*): - string unstructuredGridSubtype = undefined/T/U/V/W/F (numberOfGridInReference) - string unstructuredGridType = undefined/ORCA2/ORCA1/ORCA025/ORCA12/eORCA1/eORCA025/eORCA12 (numberOfGridInReference) - string uuidOfHGrid -- irregular_latlon - -Projection, rotation, shape (grib2/template.3.(rotation|shape_of_the_earth).def) -- projSourceString, projTargetString, projString=projTargetString - - double latitudeOfSouthernPoleInDegrees - double longitudeOfSouthernPoleInDegrees - double angleOfRotationInDegrees - - bool is_oblate - double majorAxisInMetres - double minorAxisInMetres - double radiusInMetres - -Projection centre (grib2/tables/30/3.5.table) - 1 0 North Pole is on the projection plane - 1 1 South Pole is on the projection plane - 2 0 Only one projection centre is used - 2 1 Projection is bipolar and symmetric -#endif - - -} // namespace grit +namespace grit {} // namespace grit diff --git a/src/grit/Transformation.h b/src/grit/Transformation.h index e76e2ef5c..e7b7c0cf9 100644 --- a/src/grit/Transformation.h +++ b/src/grit/Transformation.h @@ -10,10 +10,90 @@ */ +#pragma once + +#include "grit/types.h" + + namespace grit { -struct Transformation {}; +class Transformation { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + Transformation() noexcept = default; + + Transformation(const Transformation&) = default; + Transformation(Transformation&&) = default; + + // -- Destructor + + virtual ~Transformation() = default; + + // -- Convertors + // None + + // -- Operators + + Transformation& operator=(const Transformation&) = default; + Transformation& operator=(Transformation&&) = default; + + virtual Point operator()(const Point&) const = 0; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; } // namespace grit From bcc55c87f97d0f6677ba701e7fed4006aa896a63 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 13 Apr 2023 23:18:48 +0100 Subject: [PATCH 141/737] iterator --- src/grit/Projection.cc | 95 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/src/grit/Projection.cc b/src/grit/Projection.cc index 0e662a6cb..79ac43dd8 100644 --- a/src/grit/Projection.cc +++ b/src/grit/Projection.cc @@ -98,6 +98,101 @@ namespace grit { string uuidOfHGrid - irregular_latlon + +// to instantiate ecCodes iterators +- regular_gg: + - latitudeFirstInDegrees, longitudeFirstInDegrees + - latitudeLastInDegrees + - DiInDegrees + - Ni + - Nj + - N + - iScansNegatively, jScansPositively +- reduced_gg: + - latitudeOfFirstGridPointInDegrees, longitudeOfFirstGridPointInDegrees + - latitudeOfLastGridPointInDegrees, longitudeOfLastGridPointInDegrees + - N + - pl + - Nj +- lambert_azimuthal_equal_area: + - latitudeOfFirstGridPointInDegrees, longitudeOfFirstGridPointInDegrees + - radius + - Nx + - Ny + - standardParallelInDegrees + - centralLongitudeInDegrees + - Dx + - Dy + - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning +- lambert: + - latitudeOfFirstGridPointInDegrees, longitudeOfFirstGridPointInDegrees + - radius + - Nx + - Ny + - LoVInDegrees + - LaDInDegrees + - Latin1InDegrees + - Latin2InDegrees + - DxInMetres + - DyInMetres + - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning +- regular_ll, rotated_ll: + - latitudeFirstInDegrees, longitudeFirstInDegrees + - DiInDegrees + - Ni + - Nj + - DjInDegrees + - isRotatedGrid + - angleOfRotation, latitudeOfSouthernPoleInDegrees, longitudeOfSouthernPoleInDegrees + - iScansNegatively, jScansPositively, jPointsAreConsecutive +- reduced_ll: + - latitudeFirstInDegrees, longitudeFirstInDegrees + - latitudeLastInDegrees, longitudeLastInDegrees + - Nj + - DjInDegrees + - pl +- mercator: + - latitudeOfFirstGridPointInDegrees, longitudeOfFirstGridPointInDegrees + - latitudeOfLastGridPointInDegrees, longitudeOfLastGridPointInDegrees + - radius + - Ni + - Nj + - LaDInDegrees + - orientationOfTheGridInDegrees + - DiInMetres + - DjInMetres + - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning +- polar_stereographic: + - latitudeOfFirstGridPointInDegrees, longitudeOfFirstGridPointInDegrees + - radius + - Nx + - Ny + - southPoleOnProjectionPlane + - orientationOfTheGridInDegrees + - LaDInDegrees + - DxInMetres + - DyInMetres + - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning +- space_view: + - radius + - earthIsOblate + - earthMajorAxis + - earthMinorAxis + - Nx + - Ny + - latitudeOfSubSatellitePointInDegrees + - longitudeOfSubSatellitePointInDegrees + - dx + - dy + - XpInGridLengths + - YpInGridLengths + - orientationOfTheGridInDegrees + - NrInRadiusOfEarthScaled + - Xo + - Yo + - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning + + Projection, rotation, shape (grib2/template.3.(rotation|shape_of_the_earth).def) - projSourceString, projTargetString, projString=projTargetString From 46388b8413bb5f39b46f05e04c15f557933331a6 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 14 Apr 2023 00:03:25 +0100 Subject: [PATCH 142/737] iterator --- src/grit/geometry/Sphere.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grit/geometry/Sphere.cc b/src/grit/geometry/Sphere.cc index cb00b3c4d..88350d136 100644 --- a/src/grit/geometry/Sphere.cc +++ b/src/grit/geometry/Sphere.cc @@ -117,7 +117,7 @@ PointLatLon Sphere::xyz_to_ll(double radius, const PointXYZ& A) { const double y = util::is_approximately_equal(A.y, 0.) ? 0. : A.y; const double z = std::min(radius, std::max(-radius, A.z)) / radius; - return {util::radians_to_degrees * std::atan2(y, x), util::radians_to_degrees * std::asin(z)}; + return {util::radians_to_degrees * std::asin(z), util::radians_to_degrees * std::atan2(y, x)}; } From bc922355ff0d3794073323438e062fd53acbdbf1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 14 Apr 2023 11:06:09 +0100 Subject: [PATCH 143/737] types --- src/grit/types.cc | 22 ++++++++++++++++++++++ src/grit/types.h | 12 ++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/grit/types.cc b/src/grit/types.cc index f2b7a7472..1a61d960d 100644 --- a/src/grit/types.cc +++ b/src/grit/types.cc @@ -12,6 +12,8 @@ #include "grit/types.h" +#include + #include "grit/exception.h" @@ -23,4 +25,24 @@ PointLatLon::PointLatLon(double lat, double lon) : array{lat, lon} { } +std::ostream& operator<<(std::ostream& out, const Point& P) { + if (std::holds_alternative(P)) { + const auto& Q = std::get(P); + return out << '{' << Q.lat << ", " << Q.lon << '}'; + } + + if (std::holds_alternative(P)) { + const auto& Q = std::get(P); + return out << '{' << Q.x << ", " << Q.y << '}'; + } + + if (std::holds_alternative(P)) { + const auto& Q = std::get(P); + return out << '{' << Q.x << ", " << Q.y << ", " << Q.z << '}'; + } + + NOTIMP; +} + + } // namespace grit diff --git a/src/grit/types.h b/src/grit/types.h index 131ff35ce..b25a2d49e 100644 --- a/src/grit/types.h +++ b/src/grit/types.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include #include @@ -28,6 +29,14 @@ struct PointLatLon : std::array { }; +struct PointLonLat : std::array { + PointLonLat(double lon, double lat); + + double& lon = operator[](0); + double& lat = operator[](1); +}; + + struct PointXY : std::array { PointXY(double x, double y); @@ -52,6 +61,9 @@ struct PointXYZ : std::array { using Point = std::variant; +std::ostream& operator<<(std::ostream&, const Point&); + + using pl_type = std::vector; From 54517ccd9d9930f884e5757eff7c61dedf6ffca8 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 14 Apr 2023 11:12:55 +0100 Subject: [PATCH 144/737] projection --- src/grit/CMakeLists.txt | 2 + src/grit/projection/Rotation.cc | 38 ++++++++++++++++ src/grit/projection/Rotation.h | 77 +++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 src/grit/projection/Rotation.cc create mode 100644 src/grit/projection/Rotation.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 8e44ac2dd..0055cb50a 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -25,6 +25,8 @@ add_library(grit SHARED geometry/Spheroid.cc geometry/Spheroid.h geometry/UnitSphere.h + projection/Rotation.cc + projection/Rotation.h types.cc types.h util.cc diff --git a/src/grit/projection/Rotation.cc b/src/grit/projection/Rotation.cc new file mode 100644 index 000000000..02fb4e89f --- /dev/null +++ b/src/grit/projection/Rotation.cc @@ -0,0 +1,38 @@ +/* + * (C) Copyright 1996- 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 "grit/projection/Rotation.h" + +#include "grit/exception.h" + + +namespace grit::projection { + + +Rotation::Rotation() = default; + + +Point grit::projection::Rotation::direct(const Point& p) const { + ASSERT(std::holds_alternative(p)); + + NOTIMP; +} + + +Point grit::projection::Rotation::inverse(const Point& p) const { + ASSERT(std::holds_alternative(p)); + + NOTIMP; +} + + +} // namespace grit::projection diff --git a/src/grit/projection/Rotation.h b/src/grit/projection/Rotation.h new file mode 100644 index 000000000..54c56e477 --- /dev/null +++ b/src/grit/projection/Rotation.h @@ -0,0 +1,77 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/Projection.h" + + +namespace grit::projection { + + +class Rotation final : public Projection { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + Rotation(); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + Point direct(const Point&) const override; + Point inverse(const Point&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::projection From a47ab3b2ed27e0b9bea5168d80d0059127860acf Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 14 Apr 2023 11:13:00 +0100 Subject: [PATCH 145/737] projection --- tests/CMakeLists.txt | 1 + tests/projection.cc | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/projection.cc diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index af355ef6e..334931e46 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,7 @@ include(CTest) foreach(name + projection util) add_executable(test_${name} ${name}.cc) target_link_libraries(test_${name} grit) diff --git a/tests/projection.cc b/tests/projection.cc new file mode 100644 index 000000000..d23057d1b --- /dev/null +++ b/tests/projection.cc @@ -0,0 +1,24 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "grit/Projection.h" +#include "grit/projection/Rotation.h" + + +int main(int argc, char* argv[]) { + std::unique_ptr proj(new grit::projection::Rotation()); + + std::cout << proj->direct(grit::PointLatLon{1, 1}) << std::endl; +} From 9e694563680797eedef8424c985456c9b4136ab1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 14 Apr 2023 14:23:03 +0100 Subject: [PATCH 146/737] projection --- src/grit/projection/Rotation.cc | 74 ++++++++++++++++++++++++++++++--- src/grit/projection/Rotation.h | 57 +++++++++++++++++++++++-- src/grit/types.h | 49 ++++++++++++++++++---- tests/projection.cc | 39 ++++++++++++++++- 4 files changed, 200 insertions(+), 19 deletions(-) diff --git a/src/grit/projection/Rotation.cc b/src/grit/projection/Rotation.cc index 02fb4e89f..dadf8c164 100644 --- a/src/grit/projection/Rotation.cc +++ b/src/grit/projection/Rotation.cc @@ -12,26 +12,90 @@ #include "grit/projection/Rotation.h" +#include + #include "grit/exception.h" +#include "grit/geometry/Sphere.h" +#include "grit/util.h" namespace grit::projection { -Rotation::Rotation() = default; +inline PointLatLon rotate(const Rotation::MatrixXYZ& R, const PointLatLon& p) { + return geometry::Sphere::xyz_to_ll(1., R * geometry::Sphere::ll_to_xyz(1., p, 0.)); +} + + +Rotation::Rotation(PointLatLon south_pole, double angle) : angle_(util::normalise_longitude_to_minimum(angle, 0.)) { + const auto theta = -(south_pole.lat + 90.) * util::degrees_to_radians; + const auto phi = -(south_pole.lon) * util::degrees_to_radians; + + const auto sin_theta = std::sin(theta); + const auto cos_theta = std::cos(theta); + const auto sin_phi = std::sin(phi); + const auto cos_phi = std::cos(phi); + + auto eq = [](double a, double b) { return util::is_approximately_equal(a, b, 1.e-12); }; + if (eq(sin_theta, 0) && eq(cos_theta, 1)) { + rotation_ = eq(angle_, 0) && eq(sin_phi, 0) && eq(cos_phi, 1) ? rotation_type::UNROTATED : rotation_type::ANGLE; + return; + } + + rotation_ = rotation_type::ANGLE_VECTOR; + + // Rotate: rotate by ϑ (y-axis, along the rotated Greenwich meridian), then by φ (z-axis) + // q = Rz * Ry * p = [ cosφ sinφ ] * [ cosϑ sinϑ ] * p = [ cosϑ.cosφ sinφ sinϑ.cosφ ] * p + // [ -sinφ cosφ ] [ 1 ] [ -cosϑ.sinφ cosφ -sinϑ.sinφ ] + // [ 1 ] [ -sinϑ cosϑ ] [ -sinϑ cosϑ ] + R_ = {cos_theta * cos_phi, sin_phi, sin_theta * cos_phi, + -cos_theta * sin_phi, cos_phi, -sin_theta * sin_phi, + -sin_theta, 0., cos_theta}; + + // Un-rotate (the reverse): + // p = Ry * Rz * q = [ cosϑ -sinϑ ] * [ cosφ -sinφ ] * q = [ cosϑ.cosφ -cosϑ.sinφ -sinϑ ] * q + // [ 1 ] [ sinφ cosφ ] [ sinφ cosφ ] + // [ sinϑ cosϑ ] [ 1 ] [ sinϑ.cosφ -sinϑ.sinφ cosϑ ] + U_ = {cos_theta * cos_phi, -cos_theta * sin_phi, -sin_theta, sin_phi, cos_phi, 0., + sin_theta * cos_phi, -sin_theta * sin_phi, cos_theta}; +} Point grit::projection::Rotation::direct(const Point& p) const { ASSERT(std::holds_alternative(p)); - NOTIMP; + if (rotation_ == rotation_type::ANGLE) { + auto q = std::get(p); + q.lon -= angle_; + return q; + } + + if (rotation_ == rotation_type::ANGLE_VECTOR) { + auto q = std::get(p); + q.lon -= angle_; + return rotate(R_, q); + } + + return p; } -Point grit::projection::Rotation::inverse(const Point& p) const { - ASSERT(std::holds_alternative(p)); +Point grit::projection::Rotation::inverse(const Point& q) const { + ASSERT(std::holds_alternative(q)); + + if (rotation_ == rotation_type::ANGLE) { + auto p = std::get(q); + p.lon += angle_; + return p; + } + + if (rotation_ == rotation_type::ANGLE_VECTOR) { + auto p = rotate(U_, std::get(q)); + p.lon += angle_; + return p; + } - NOTIMP; + return q; } diff --git a/src/grit/projection/Rotation.h b/src/grit/projection/Rotation.h index 54c56e477..35734461a 100644 --- a/src/grit/projection/Rotation.h +++ b/src/grit/projection/Rotation.h @@ -12,23 +12,60 @@ #pragma once +#include + #include "grit/Projection.h" namespace grit::projection { +/// Compute coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle class Rotation final : public Projection { public: // -- Types - // None + + struct MatrixXYZ : std::array { + MatrixXYZ() : array{1, 0, 0, 0, 1, 0, 0, 0, 1} {} + + MatrixXYZ(double xx, double xy, double xz, double yx, double yy, double yz, double zx, double zy, double zz) : + array{xx, xy, xz, yx, yy, yz, zx, zy, zz} {} + + MatrixXYZ(const MatrixXYZ& other) : array(other) {} + MatrixXYZ(MatrixXYZ&& other) : array(other) {} + + ~MatrixXYZ() = default; + + MatrixXYZ& operator=(const MatrixXYZ& other) { + array::operator=(other); + return *this; + } + MatrixXYZ& operator=(MatrixXYZ&& other) { + array::operator=(other); + return *this; + } + + double& xx = operator[](0); + double& xy = operator[](1); + double& xz = operator[](2); + double& yx = operator[](3); + double& yy = operator[](4); + double& yz = operator[](5); + double& zx = operator[](6); + double& zy = operator[](7); + double& zz = operator[](8); + + PointXYZ operator*(const PointXYZ& p) const { + return {xx * p.x + xy * p.y + xz * p.z, yx * p.x + yy * p.y + yz * p.z, zx * p.x + zy * p.y + zz * p.z}; + } + }; // -- Exceptions // None // -- Constructors - Rotation(); + Rotation(PointLatLon south_pole, double angle); // -- Destructor // None @@ -52,8 +89,22 @@ class Rotation final : public Projection { // None private: + // -- Types + + enum class rotation_type + { + UNROTATED, + ANGLE, + ANGLE_VECTOR + }; + // -- Members - // None + + rotation_type rotation_ = rotation_type::UNROTATED; + + MatrixXYZ R_; + MatrixXYZ U_; + double angle_ = 0.; // -- Methods // None diff --git a/src/grit/types.h b/src/grit/types.h index b25a2d49e..48020d209 100644 --- a/src/grit/types.h +++ b/src/grit/types.h @@ -23,22 +23,40 @@ namespace grit { struct PointLatLon : std::array { PointLatLon(double lat, double lon); + PointLatLon(const PointLatLon& other) : array(other) {} + PointLatLon(PointLatLon&& other) : array(other) {} + ~PointLatLon() = default; - double& lat = operator[](0); - double& lon = operator[](1); -}; - + PointLatLon& operator=(const PointLatLon& other) { + array::operator=(other); + return *this; + } -struct PointLonLat : std::array { - PointLonLat(double lon, double lat); + PointLatLon& operator=(PointLatLon&& other) { + array::operator=(other); + return *this; + } - double& lon = operator[](0); - double& lat = operator[](1); + double& lat = operator[](0); + double& lon = operator[](1); }; struct PointXY : std::array { - PointXY(double x, double y); + PointXY(double x, double y) : array{x, y} {} + PointXY(const PointXY& other) : array(other) {} + PointXY(PointXY&& other) : array(other) {} + ~PointXY() = default; + + PointXY& operator=(const PointXY& other) { + array::operator=(other); + return *this; + } + + PointXY& operator=(PointXY&& other) { + array::operator=(other); + return *this; + } double& x = operator[](0); double& y = operator[](1); @@ -47,6 +65,19 @@ struct PointXY : std::array { struct PointXYZ : std::array { PointXYZ(double x, double y, double z) : array{x, y, z} {} + PointXYZ(const PointXYZ& other) : array(other) {} + PointXYZ(PointXYZ&& other) : array(other) {} + ~PointXYZ() = default; + + PointXYZ& operator=(const PointXYZ& other) { + array::operator=(other); + return *this; + } + + PointXYZ& operator=(PointXYZ&& other) { + array::operator=(other); + return *this; + } static double distance2(const PointXYZ& a, const PointXYZ& b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z); diff --git a/tests/projection.cc b/tests/projection.cc index d23057d1b..90b77a7f9 100644 --- a/tests/projection.cc +++ b/tests/projection.cc @@ -18,7 +18,42 @@ int main(int argc, char* argv[]) { - std::unique_ptr proj(new grit::projection::Rotation()); + { + std::unique_ptr unrotated(new grit::projection::Rotation({-90., 0.}, 0.)); - std::cout << proj->direct(grit::PointLatLon{1, 1}) << std::endl; + const grit::PointLatLon a(1, 1); + auto b = unrotated->direct(a); + auto c = unrotated->inverse(b); + auto e = unrotated->inverse(a); + auto f = unrotated->direct(e); + + std::cout << "unrotated: " << a << " -> " << b << " -> " << c << std::endl; + std::cout << "unrotated: " << a << " -> " << e << " -> " << f << std::endl; + } + + { + std::unique_ptr angle_only(new grit::projection::Rotation({-90., 0.}, 10.)); + + const grit::PointLatLon a(1, 1); + auto b = angle_only->direct(a); + auto c = angle_only->inverse(b); + auto e = angle_only->inverse(a); + auto f = angle_only->direct(e); + + std::cout << "angle_only: " << a << " -> " << b << " -> " << c << std::endl; + std::cout << "angle_only: " << a << " -> " << e << " -> " << f << std::endl; + } + + { + std::unique_ptr angle_vector(new grit::projection::Rotation({-89., 1.}, 10.)); + + const grit::PointLatLon a(1, 1); + auto b = angle_vector->direct(a); + auto c = angle_vector->inverse(b); + auto e = angle_vector->inverse(a); + auto f = angle_vector->direct(e); + + std::cout << "angle_vector: " << a << " -> " << b << " -> " << c << std::endl; + std::cout << "angle_vector: " << a << " -> " << e << " -> " << f << std::endl; + } } From 39c723713793f09e388c308642099d88d52e1f71 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 19 Apr 2023 18:25:18 +0100 Subject: [PATCH 147/737] projection --- src/grit/util.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/grit/util.cc b/src/grit/util.cc index 474ecd54b..2cc077825 100644 --- a/src/grit/util.cc +++ b/src/grit/util.cc @@ -44,4 +44,16 @@ double normalise_longitude_to_maximum(double lon, double maximum) { } +void normalise_latitude_and_longitude(double& lat, double& lon, double lon_minimum) { + lat = normalise_longitude_to_minimum(lat, -90.); + + if (lat > 90.) { + lat -= 180.; + lon += 180.; + } + + lon = normalise_longitude_to_minimum(lon, lon_minimum); +} + + } // namespace grit::util From 09e2e4c4f1ea5bed7436b26e2b86ca33d177ffd8 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 20 Apr 2023 12:21:57 +0100 Subject: [PATCH 148/737] types --- src/grit/CMakeLists.txt | 4 + src/grit/projection/Rotation.cc | 40 ++--- src/grit/projection/Rotation.h | 7 +- src/grit/types.cc | 35 +---- src/grit/types.h | 86 ++--------- src/grit/types/MatrixXYZ.h | 101 ++++++++++++ src/grit/types/PointLatLon.h | 115 ++++++++++++++ src/grit/types/PointXY.h | 86 +++++++++++ src/grit/types/PointXYZ.h | 91 +++++++++++ src/grit/util.cc | 12 -- tests/CMakeLists.txt | 1 + tests/projection.cc | 44 +----- tests/projection_rotation.cc | 264 ++++++++++++++++++++++++++++++++ 13 files changed, 707 insertions(+), 179 deletions(-) create mode 100644 src/grit/types/MatrixXYZ.h create mode 100644 src/grit/types/PointLatLon.h create mode 100644 src/grit/types/PointXY.h create mode 100644 src/grit/types/PointXYZ.h create mode 100644 tests/projection_rotation.cc diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 0055cb50a..3c17e4610 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -29,6 +29,10 @@ add_library(grit SHARED projection/Rotation.h types.cc types.h + types/MatrixXYZ.h + types/PointLatLon.h + types/PointXY.h + types/PointXYZ.h util.cc util.h util/arange.cc diff --git a/src/grit/projection/Rotation.cc b/src/grit/projection/Rotation.cc index dadf8c164..7f9afb1d9 100644 --- a/src/grit/projection/Rotation.cc +++ b/src/grit/projection/Rotation.cc @@ -22,14 +22,10 @@ namespace grit::projection { -inline PointLatLon rotate(const Rotation::MatrixXYZ& R, const PointLatLon& p) { - return geometry::Sphere::xyz_to_ll(1., R * geometry::Sphere::ll_to_xyz(1., p, 0.)); -} - - -Rotation::Rotation(PointLatLon south_pole, double angle) : angle_(util::normalise_longitude_to_minimum(angle, 0.)) { - const auto theta = -(south_pole.lat + 90.) * util::degrees_to_radians; - const auto phi = -(south_pole.lon) * util::degrees_to_radians; +Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : + angle_(util::normalise_longitude_to_minimum(angle, 0.)) { + const auto theta = -(south_pole_lat + 90.) * util::degrees_to_radians; + const auto phi = -(south_pole_lon)*util::degrees_to_radians; const auto sin_theta = std::sin(theta); const auto cos_theta = std::cos(theta); @@ -61,36 +57,32 @@ Rotation::Rotation(PointLatLon south_pole, double angle) : angle_(util::normalis } -Point grit::projection::Rotation::direct(const Point& p) const { - ASSERT(std::holds_alternative(p)); - +PointLatLon Rotation::direct(const PointLatLon& p) const { if (rotation_ == rotation_type::ANGLE) { - auto q = std::get(p); + auto q = p; q.lon -= angle_; return q; } if (rotation_ == rotation_type::ANGLE_VECTOR) { - auto q = std::get(p); + auto q = p; q.lon -= angle_; - return rotate(R_, q); + return geometry::Sphere::xyz_to_ll(1., R_ * geometry::Sphere::ll_to_xyz(1., q, 0.)); } return p; } -Point grit::projection::Rotation::inverse(const Point& q) const { - ASSERT(std::holds_alternative(q)); - +PointLatLon Rotation::inverse(const PointLatLon& q) const { if (rotation_ == rotation_type::ANGLE) { - auto p = std::get(q); + auto p = q; p.lon += angle_; return p; } if (rotation_ == rotation_type::ANGLE_VECTOR) { - auto p = rotate(U_, std::get(q)); + auto p = geometry::Sphere::xyz_to_ll(1., U_ * geometry::Sphere::ll_to_xyz(1., q, 0.)); p.lon += angle_; return p; } @@ -99,4 +91,14 @@ Point grit::projection::Rotation::inverse(const Point& q) const { } +Point Rotation::direct(const Point& p) const { + return direct(std::get(p)); +} + + +Point Rotation::inverse(const Point& q) const { + return inverse(std::get(q)); +} + + } // namespace grit::projection diff --git a/src/grit/projection/Rotation.h b/src/grit/projection/Rotation.h index 35734461a..4f4086f99 100644 --- a/src/grit/projection/Rotation.h +++ b/src/grit/projection/Rotation.h @@ -65,7 +65,7 @@ class Rotation final : public Projection { // -- Constructors - Rotation(PointLatLon south_pole, double angle); + Rotation(double south_pole_lat, double south_pole_lon, double angle); // -- Destructor // None @@ -77,7 +77,10 @@ class Rotation final : public Projection { // None // -- Methods - // None + + bool rotated() const { return rotation_ != rotation_type::UNROTATED; } + PointLatLon direct(const PointLatLon&) const; + PointLatLon inverse(const PointLatLon&) const; // -- Overridden methods // None diff --git a/src/grit/types.cc b/src/grit/types.cc index 1a61d960d..e69d4aab1 100644 --- a/src/grit/types.cc +++ b/src/grit/types.cc @@ -12,37 +12,12 @@ #include "grit/types.h" -#include - #include "grit/exception.h" -namespace grit { - - -PointLatLon::PointLatLon(double lat, double lon) : array{lat, lon} { - ASSERT_MSG(-90. <= lat && lat <= 90., "PointLatLon: invalid latitude"); +std::ostream& operator<<(std::ostream& out, const grit::Point& p) { + return std::holds_alternative(p) ? out << std::get(p) + : std::holds_alternative(p) ? out << std::get(p) + : std::holds_alternative(p) ? out << std::get(p) + : NOTIMP; } - - -std::ostream& operator<<(std::ostream& out, const Point& P) { - if (std::holds_alternative(P)) { - const auto& Q = std::get(P); - return out << '{' << Q.lat << ", " << Q.lon << '}'; - } - - if (std::holds_alternative(P)) { - const auto& Q = std::get(P); - return out << '{' << Q.x << ", " << Q.y << '}'; - } - - if (std::holds_alternative(P)) { - const auto& Q = std::get(P); - return out << '{' << Q.x << ", " << Q.y << ", " << Q.z << '}'; - } - - NOTIMP; -} - - -} // namespace grit diff --git a/src/grit/types.h b/src/grit/types.h index 48020d209..d6edd2c1b 100644 --- a/src/grit/types.h +++ b/src/grit/types.h @@ -12,90 +12,28 @@ #pragma once -#include -#include +#include #include #include +#include "grit/types/PointLatLon.h" +#include "grit/types/PointXY.h" +#include "grit/types/PointXYZ.h" -namespace grit { - - -struct PointLatLon : std::array { - PointLatLon(double lat, double lon); - PointLatLon(const PointLatLon& other) : array(other) {} - PointLatLon(PointLatLon&& other) : array(other) {} - ~PointLatLon() = default; - - PointLatLon& operator=(const PointLatLon& other) { - array::operator=(other); - return *this; - } - - PointLatLon& operator=(PointLatLon&& other) { - array::operator=(other); - return *this; - } - - double& lat = operator[](0); - double& lon = operator[](1); -}; - - -struct PointXY : std::array { - PointXY(double x, double y) : array{x, y} {} - PointXY(const PointXY& other) : array(other) {} - PointXY(PointXY&& other) : array(other) {} - ~PointXY() = default; - - PointXY& operator=(const PointXY& other) { - array::operator=(other); - return *this; - } - - PointXY& operator=(PointXY&& other) { - array::operator=(other); - return *this; - } - - double& x = operator[](0); - double& y = operator[](1); -}; - -struct PointXYZ : std::array { - PointXYZ(double x, double y, double z) : array{x, y, z} {} - PointXYZ(const PointXYZ& other) : array(other) {} - PointXYZ(PointXYZ&& other) : array(other) {} - ~PointXYZ() = default; - - PointXYZ& operator=(const PointXYZ& other) { - array::operator=(other); - return *this; - } - - PointXYZ& operator=(PointXYZ&& other) { - array::operator=(other); - return *this; - } - - static double distance2(const PointXYZ& a, const PointXYZ& b) { - return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z); - } - - double& x = operator[](0); - double& y = operator[](1); - double& z = operator[](2); -}; - - -using Point = std::variant; +namespace grit { -std::ostream& operator<<(std::ostream&, const Point&); +using PointLatLon = types::PointLatLon; +using PointXY = types::PointXY; +using PointXYZ = types::PointXYZ; +using Point = std::variant; using pl_type = std::vector; } // namespace grit + + +std::ostream& operator<<(std::ostream&, const grit::Point&); diff --git a/src/grit/types/MatrixXYZ.h b/src/grit/types/MatrixXYZ.h new file mode 100644 index 000000000..05376e14f --- /dev/null +++ b/src/grit/types/MatrixXYZ.h @@ -0,0 +1,101 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + +#include "grit/types/PointXYZ.h" + + +namespace grit::types { + + +template +class MatrixXYZ final : protected std::array { +private: + // -- Types + + using P = std::array; + +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + MatrixXYZ() : P{1, 0, 0, 0, 1, 0, 0, 0, 1} {} + MatrixXYZ(T xx, T xy, T xz, T yx, T yy, T yz, T zx, T zy, T zz) : P{xx, xy, xz, yx, yy, yz, zx, zy, zz} {} + MatrixXYZ(const MatrixXYZ& other) : P(other) {} + MatrixXYZ(MatrixXYZ&& other) : P(other) {} + + // -- Destructor + + ~MatrixXYZ() = default; + + // -- Convertors + // None + + // -- Operators + + MatrixXYZ& operator=(const MatrixXYZ& other) { + P::operator=(other); + return *this; + } + + MatrixXYZ& operator=(MatrixXYZ&& other) { + P::operator=(other); + return *this; + } + + PointXYZ operator*(const PointXYZ& p) const { + return {xx * p.x + xy * p.y + xz * p.z, yx * p.x + yy * p.y + yz * p.z, zx * p.x + zy * p.y + zz * p.z}; + } + + // -- Members + + T& xx = P::operator[](0); + T& xy = P::operator[](1); + T& xz = P::operator[](2); + T& yx = P::operator[](3); + T& yy = P::operator[](4); + T& yz = P::operator[](5); + T& zx = P::operator[](6); + T& zy = P::operator[](7); + T& zz = P::operator[](8); + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + + friend std::ostream& operator<<(std::ostream& out, const MatrixXYZ& m) { + return out << "{{" << m.xx << ", " << m.xy << ", " << m.xz << "}, {" << m.yx << ", " << m.yy << ", " << m.yz + << "}, {" << m.zx << ", " << m.zy << ", " << m.zz << "}}"; + } +}; + + +} // namespace grit::types diff --git a/src/grit/types/PointLatLon.h b/src/grit/types/PointLatLon.h new file mode 100644 index 000000000..1e1bcbe65 --- /dev/null +++ b/src/grit/types/PointLatLon.h @@ -0,0 +1,115 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + +#include "grit/exception.h" + + +namespace grit::types { + + +template +class PointLatLon final : protected std::array { +private: + // -- Types + + using P = std::array; + +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + PointLatLon(T lat, T lon) : P{lat, lon} { ASSERT_MSG(-90. <= lat && lat <= 90., "PointLatLon: invalid latitude"); } + PointLatLon(const PointLatLon& other) : P(other) {} + PointLatLon(PointLatLon&& other) : P(other) {} + + // -- Destructor + + ~PointLatLon() = default; + + // -- Convertors + // None + + // -- Operators + + PointLatLon& operator=(const PointLatLon& other) { + P::operator=(other); + return *this; + } + + PointLatLon& operator=(PointLatLon&& other) { + P::operator=(other); + return *this; + } + + bool operator==(const PointLatLon& other) const { + return P(make_normalised(lat, lon)) == P(make_normalised(other.lat, other.lon)); + } + + bool operator!=(const PointLatLon& other) const { return !operator==(other); } + + // -- Members + + T& lat = P::operator[](0); + T& lon = P::operator[](1); + + // -- Methods + + static PointLatLon make_normalised(T lat, T lon) { + auto normal = [](double a, double minimum) { + while (a < minimum) { + a += 360.; + } + while (a >= minimum + 360.) { + a -= 360.; + } + + return a; + }; + + lat = normal(lat, -90.); + + if (lat > 90.) { + lat -= 180.; + lon += 180.; + } + + return {lat, lat == -90. || lat == 90. ? 0. : normal(lon, 0.)}; + } + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + + friend std::ostream& operator<<(std::ostream& out, const PointLatLon& p) { + return out << '{' << p.lat << ", " << p.lon << '}'; + } +}; + + +} // namespace grit::types diff --git a/src/grit/types/PointXY.h b/src/grit/types/PointXY.h new file mode 100644 index 000000000..f8fe1ec30 --- /dev/null +++ b/src/grit/types/PointXY.h @@ -0,0 +1,86 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + + +namespace grit::types { + + +template +class PointXY final : protected std::array { +private: + // -- Types + + using P = std::array; + +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + PointXY(T x, T y) : P{x, y} {} + PointXY(const PointXY& other) : P(other) {} + PointXY(PointXY&& other) : P(other) {} + + // -- Destructor + + ~PointXY() = default; + + // -- Convertors + // None + + // -- Operators + + PointXY& operator=(const PointXY& other) { + P::operator=(other); + return *this; + } + + PointXY& operator=(PointXY&& other) { + P::operator=(other); + return *this; + } + + // -- Members + + T& x = P::operator[](0); + T& y = P::operator[](1); + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + + friend std::ostream& operator<<(std::ostream& out, const PointXY& p) { + return out << '{' << p.x << ", " << p.y << '}'; + } +}; + + +} // namespace grit::types diff --git a/src/grit/types/PointXYZ.h b/src/grit/types/PointXYZ.h new file mode 100644 index 000000000..815e42b10 --- /dev/null +++ b/src/grit/types/PointXYZ.h @@ -0,0 +1,91 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + + +namespace grit::types { + + +template +class PointXYZ final : protected std::array { +private: + // -- Types + + using P = std::array; + +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + PointXYZ(T x, T y, T z) : P{x, y, z} {} + PointXYZ(const PointXYZ& other) : P(other) {} + PointXYZ(PointXYZ&& other) : P(other) {} + + // -- Destructor + + ~PointXYZ() = default; + + // -- Convertors + // None + + // -- Operators + + PointXYZ& operator=(const PointXYZ& other) { + P::operator=(other); + return *this; + } + + PointXYZ& operator=(PointXYZ&& other) { + P::operator=(other); + return *this; + } + + + // -- Members + + T& x = P::operator[](0); + T& y = P::operator[](1); + T& z = P::operator[](2); + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + + static T distance2(const PointXYZ& a, const PointXYZ& b) { + return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z); + } + + // -- Friends + + friend std::ostream& operator<<(std::ostream& out, const PointXYZ& p) { + return out << '{' << p.x << ", " << p.y << ", " << p.z << '}'; + } +}; + + +} // namespace grit::types diff --git a/src/grit/util.cc b/src/grit/util.cc index 2cc077825..474ecd54b 100644 --- a/src/grit/util.cc +++ b/src/grit/util.cc @@ -44,16 +44,4 @@ double normalise_longitude_to_maximum(double lon, double maximum) { } -void normalise_latitude_and_longitude(double& lat, double& lon, double lon_minimum) { - lat = normalise_longitude_to_minimum(lat, -90.); - - if (lat > 90.) { - lat -= 180.; - lon += 180.; - } - - lon = normalise_longitude_to_minimum(lon, lon_minimum); -} - - } // namespace grit::util diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 334931e46..3e6dcd7fb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,6 +2,7 @@ include(CTest) foreach(name projection + projection_rotation util) add_executable(test_${name} ${name}.cc) target_link_libraries(test_${name} grit) diff --git a/tests/projection.cc b/tests/projection.cc index 90b77a7f9..eb98c755a 100644 --- a/tests/projection.cc +++ b/tests/projection.cc @@ -13,47 +13,7 @@ #include #include -#include "grit/Projection.h" -#include "grit/projection/Rotation.h" +// #include "grit/Projection.h" -int main(int argc, char* argv[]) { - { - std::unique_ptr unrotated(new grit::projection::Rotation({-90., 0.}, 0.)); - - const grit::PointLatLon a(1, 1); - auto b = unrotated->direct(a); - auto c = unrotated->inverse(b); - auto e = unrotated->inverse(a); - auto f = unrotated->direct(e); - - std::cout << "unrotated: " << a << " -> " << b << " -> " << c << std::endl; - std::cout << "unrotated: " << a << " -> " << e << " -> " << f << std::endl; - } - - { - std::unique_ptr angle_only(new grit::projection::Rotation({-90., 0.}, 10.)); - - const grit::PointLatLon a(1, 1); - auto b = angle_only->direct(a); - auto c = angle_only->inverse(b); - auto e = angle_only->inverse(a); - auto f = angle_only->direct(e); - - std::cout << "angle_only: " << a << " -> " << b << " -> " << c << std::endl; - std::cout << "angle_only: " << a << " -> " << e << " -> " << f << std::endl; - } - - { - std::unique_ptr angle_vector(new grit::projection::Rotation({-89., 1.}, 10.)); - - const grit::PointLatLon a(1, 1); - auto b = angle_vector->direct(a); - auto c = angle_vector->inverse(b); - auto e = angle_vector->inverse(a); - auto f = angle_vector->direct(e); - - std::cout << "angle_vector: " << a << " -> " << b << " -> " << c << std::endl; - std::cout << "angle_vector: " << a << " -> " << e << " -> " << f << std::endl; - } -} +int main(int argc, char* argv[]) {} diff --git a/tests/projection_rotation.cc b/tests/projection_rotation.cc new file mode 100644 index 000000000..253536a53 --- /dev/null +++ b/tests/projection_rotation.cc @@ -0,0 +1,264 @@ +/* + * (C) Copyright 1996- 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 +#include +#include +#include + +#include "grit/Projection.h" +#include "grit/exception.h" +#include "grit/projection/Rotation.h" +#include "grit/util.h" + + +using grit::PointLatLon; +using grit::projection::Rotation; + +static const PointLatLon SP{-90., 0.}; +static const PointLatLon NP{90., 180.}; + + +bool equivalent(const PointLatLon& a, const PointLatLon& b) { + auto f = [=](double lon) { return 10. + std::cos(lon * grit::util::degrees_to_radians); }; + auto eq = [](double a, double b) { return grit::util::is_approximately_equal(a, b, 1e-5); }; + + auto ok = (eq(a.lat, 90.) && eq(b.lat, 90.)) || (eq(a.lat, -90.) && eq(b.lat, -90.)) || + eq(a.lat, b.lat) && eq(f(a.lon), f(b.lon)); + + std::cout << a << " <=> " << b << " ? " << ok << std::endl; + return ok; +} + + +void eqv(const Rotation& rot, const PointLatLon& a, const PointLatLon& b) { + auto bn = rot.direct(a); + auto bok = equivalent(bn, b); + // std::cout << a << " -> " << bn << " == " << b << " ? " << bok << std::endl; + + auto an = rot.inverse(b); + auto aok = equivalent(an, a); + // std::cout << b << " <- " << an << " == " << a << " ? " << aok << std::endl; + + ASSERT(aok && bok); +} + + +int main(int argc, char* argv[]) { + { + std::unique_ptr unrotated(new Rotation(-90., 0., 0.)); + + const PointLatLon a(1, 1); + auto b = unrotated->direct(a); + auto c = unrotated->inverse(b); + auto e = unrotated->inverse(a); + auto f = unrotated->direct(e); + + std::cout << "unrotated: " << a << " -> " << b << " -> " << c << std::endl; + std::cout << "unrotated: " << a << " -> " << e << " -> " << f << std::endl; + } + + { + std::unique_ptr angle_only(new Rotation(-90., 0., 10.)); + + const PointLatLon a(1, 1); + auto b = angle_only->direct(a); + auto c = angle_only->inverse(b); + auto e = angle_only->inverse(a); + auto f = angle_only->direct(e); + + std::cout << "angle_only: " << a << " -> " << b << " -> " << c << std::endl; + std::cout << "angle_only: " << a << " -> " << e << " -> " << f << std::endl; + } + + { + std::unique_ptr angle_vector(new Rotation(-89., 1., 10.)); + + const PointLatLon a(1, 1); + auto b = angle_vector->direct(a); + auto c = angle_vector->inverse(b); + auto e = angle_vector->inverse(a); + auto f = angle_vector->direct(e); + + std::cout << "angle_vector: " << a << " -> " << b << " -> " << c << std::endl; + std::cout << "angle_vector: " << a << " -> " << e << " -> " << f << std::endl; + } + + { + const int nx = 12; + const int ny = 6; + + + Rotation rot(-133.3, 2., + 180.); // NP (lat, lon) = (46.7, 2., 180.) (SP cannot be expressed canonically for the same point) + + const PointLatLon ref[]{ + {-46.7, -178.}, + {-16.7, -178.}, + {13.3, -178.}, + {43.3, -178.}, + {73.3, -178.}, + {76.7, 2.}, + {46.7, 2.}, + {-46.7, -178.}, + {-19.46929, -162.62343}, + {8.65459, -152.02366}, + {36.43683, -139.57464}, + {61.43199, -113.10894}, + {68.00825, -39.88245}, + {46.7, 2.}, + {-46.7, -178.}, + {-27.31067, -148.83443}, + {-3.837, -129.26346}, + {20.05422, -110.79116}, + {41.36507, -85.87917}, + {53.29508, -44.42496}, + {46.7, 2.}, + {-46.7, -178.}, + {-39.07002, -137.90794}, + {-21.33906, -109.60146}, + {0., -88.}, + {21.33906, -66.39854}, + {39.07002, -38.09206}, + {46.7, 2.}, + {-46.7, -178.}, + {-53.29508, -131.57504}, + {-41.36507, -90.12083}, + {-20.05422, -65.20884}, + {3.837, -46.73654}, + {27.31067, -27.16557}, + {46.7, 2.}, + {-46.7, -178.}, + {-68.00825, -136.11755}, + {-61.43199, -62.89106}, + {-36.43683, -36.42536}, + {-8.65459, -23.97634}, + {19.46929, -13.37657}, + {46.7, 2.}, + {-46.7, -178.}, + {-76.7, -178.}, + {-73.3, 2.}, + {-43.3, 2.}, + {-13.3, 2.}, + {16.7, 2.}, + {46.7, 2.}, + {-46.7, -178.}, + {-68.00825, 140.11755}, + {-61.43199, 66.89106}, + {-36.43683, 40.42536}, + {-8.65459, 27.97634}, + {19.46929, 17.37657}, + {46.7, 2.}, + {-46.7, -178.}, + {-53.29508, 135.57504}, + {-41.36507, 94.12083}, + {-20.05422, 69.20884}, + {3.837, 50.73654}, + {27.31067, 31.16557}, + {46.7, 2.}, + {-46.7, -178.}, + {-39.07002, 141.90794}, + {-21.33906, 113.60146}, + {0., 92.}, + {21.33906, 70.39854}, + {39.07002, 42.09206}, + {46.7, 2.}, + {-46.7, -178.}, + {-27.31067, 152.83443}, + {-3.837, 133.26346}, + {20.05422, 114.79116}, + {41.36507, 89.87917}, + {53.29508, 48.42496}, + {46.7, 2.}, + {-46.7, -178.}, + {-19.46929, 166.62343}, + {8.65459, 156.02366}, + {36.43683, 143.57464}, + {61.43199, 117.10894}, + {68.00825, 43.88245}, + {46.7, 2.}, + }; + + for (int i = 0, jglo = 0; i < nx; i++) { + for (int j = 0; j < ny + 1; j++, jglo++) { + double lon = static_cast(i) * 360. / static_cast(nx); + double lat = static_cast(j - ny / 2) * 90. / static_cast(ny / 2); + PointLatLon p0(lat, lon); + auto p1 = rot.direct(p0); + auto p2 = rot.inverse(p1); + ASSERT(equivalent(p2, p0)); + ASSERT(equivalent(p1, ref[jglo])); + } + } + } + + + { + for (const auto& p : {SP, NP, PointLatLon{-89.9, 0.}, PointLatLon{89.9, 0.}}) { + Rotation rotation(p.lat, p.lon, 0.); + ASSERT(rotation.rotated() == (p != SP)); + } + } + + + { + using P = PointLatLon; + using PQ = std::pair; + + Rotation unrotated(SP.lat, SP.lon, 0.); + ASSERT(not unrotated.rotated()); + + for (const auto& p : {P{90., 0.}, P{0., 0.}, P{25., 270.}, P{45., -180.}}) { + eqv(unrotated, p, p); + } + + Rotation angle_only(SP.lat, SP.lon, -180.); + ASSERT(angle_only.rotated()); + + for (const auto& p : {P{90., 0.}, P{0., 0.}, P{25., 270.}, P{45., -180.}}) { + eqv(angle_only, p, {p.lat, p.lon - 180.}); + } + + Rotation rotation(-40., 4., 0.); + ASSERT(rotation.rotated()); + + eqv(rotation, {90., 0.}, {40., -176.}); + // eqv(rotation, {0., 0.}, {-50., -176.}); + // eqv(rotation, {45., -180.}, {85., -176.}); + +#if 0 + Config config; + config.set("north_pole", std::vector{-176, 40}); + Rotation rotation(config); + Log::info() << rotation << std::endl; + + EXPECT(rotation.rotated()); + + PointLonLat p, r; + + p = {0., 90.}; + r = {-176., 40.}; + EXPECT_EQUIVALENT(rotation.rotate(p), r); + EXPECT_EQUIVALENT(rotation.unrotate(r), p); + + p = {0., 0.}; + r = {-176., -50.}; + EXPECT_EQUIVALENT(rotation.rotate(p), r); + EXPECT_EQUIVALENT(rotation.unrotate(r), p); + + p = {-180., 45.}; + r = {-176., 85.}; + EXPECT_EQUIVALENT(rotation.rotate(p), r); + EXPECT_EQUIVALENT(rotation.unrotate(r), p); +#endif + } +} From 07f82243e898409b6849be016dcd3e467e870a6e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 20 Apr 2023 21:57:43 +0100 Subject: [PATCH 149/737] types --- src/grit/Projection.h | 4 +- src/grit/projection/Rotation.cc | 12 +- src/grit/projection/Rotation.h | 8 +- src/grit/types/PointLatLon.h | 42 ++++--- tests/CMakeLists.txt | 1 + tests/projection_rotation.cc | 195 ++++++++++---------------------- tests/types.cc | 38 +++++++ 7 files changed, 137 insertions(+), 163 deletions(-) create mode 100644 tests/types.cc diff --git a/src/grit/Projection.h b/src/grit/Projection.h index 99eddfeec..ab4b77e68 100644 --- a/src/grit/Projection.h +++ b/src/grit/Projection.h @@ -47,8 +47,8 @@ class Projection { // -- Methods - virtual Point direct(const Point&) const = 0; - virtual Point inverse(const Point&) const = 0; + virtual Point fwd(const Point&) const = 0; + virtual Point inv(const Point&) const = 0; // -- Overridden methods // None diff --git a/src/grit/projection/Rotation.cc b/src/grit/projection/Rotation.cc index 7f9afb1d9..53947cc2c 100644 --- a/src/grit/projection/Rotation.cc +++ b/src/grit/projection/Rotation.cc @@ -57,7 +57,7 @@ Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : } -PointLatLon Rotation::direct(const PointLatLon& p) const { +PointLatLon Rotation::fwd(const PointLatLon& p) const { if (rotation_ == rotation_type::ANGLE) { auto q = p; q.lon -= angle_; @@ -74,7 +74,7 @@ PointLatLon Rotation::direct(const PointLatLon& p) const { } -PointLatLon Rotation::inverse(const PointLatLon& q) const { +PointLatLon Rotation::inv(const PointLatLon& q) const { if (rotation_ == rotation_type::ANGLE) { auto p = q; p.lon += angle_; @@ -91,13 +91,13 @@ PointLatLon Rotation::inverse(const PointLatLon& q) const { } -Point Rotation::direct(const Point& p) const { - return direct(std::get(p)); +Point Rotation::fwd(const Point& p) const { + return fwd(std::get(p)); } -Point Rotation::inverse(const Point& q) const { - return inverse(std::get(q)); +Point Rotation::inv(const Point& q) const { + return inv(std::get(q)); } diff --git a/src/grit/projection/Rotation.h b/src/grit/projection/Rotation.h index 4f4086f99..6a906abde 100644 --- a/src/grit/projection/Rotation.h +++ b/src/grit/projection/Rotation.h @@ -79,8 +79,8 @@ class Rotation final : public Projection { // -- Methods bool rotated() const { return rotation_ != rotation_type::UNROTATED; } - PointLatLon direct(const PointLatLon&) const; - PointLatLon inverse(const PointLatLon&) const; + PointLatLon fwd(const PointLatLon&) const; + PointLatLon inv(const PointLatLon&) const; // -- Overridden methods // None @@ -114,8 +114,8 @@ class Rotation final : public Projection { // -- Overridden methods - Point direct(const Point&) const override; - Point inverse(const Point&) const override; + Point fwd(const Point&) const override; + Point inv(const Point&) const override; // -- Class members // None diff --git a/src/grit/types/PointLatLon.h b/src/grit/types/PointLatLon.h index 1e1bcbe65..df3156ff5 100644 --- a/src/grit/types/PointLatLon.h +++ b/src/grit/types/PointLatLon.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include #include "grit/exception.h" @@ -28,6 +29,20 @@ class PointLatLon final : protected std::array { using P = std::array; + // -- Class methods + + static T normal(double a, double minimum) { + while (a < minimum) { + a += 360.; + } + + while (a >= minimum + 360.) { + a -= 360.; + } + + return a; + }; + public: // -- Types // None @@ -60,12 +75,16 @@ class PointLatLon final : protected std::array { return *this; } - bool operator==(const PointLatLon& other) const { - return P(make_normalised(lat, lon)) == P(make_normalised(other.lat, other.lon)); - } + bool operator==(const PointLatLon& other) const { return lat == other.lat && normal(other.lon, lon) == lon; } bool operator!=(const PointLatLon& other) const { return !operator==(other); } + bool is_approximately_equal(const PointLatLon& other, T eps) const { + const auto dlon = normal(other.lon, lon) - lon; + return std::abs(lat - other.lat) < eps && + (std::abs(lat - 90.) < eps || std::abs(lat + 90.) < eps || dlon < eps || dlon - 360. < eps); + }; + // -- Members T& lat = P::operator[](0); @@ -73,28 +92,19 @@ class PointLatLon final : protected std::array { // -- Methods - static PointLatLon make_normalised(T lat, T lon) { - auto normal = [](double a, double minimum) { - while (a < minimum) { - a += 360.; - } - while (a >= minimum + 360.) { - a -= 360.; - } - - return a; - }; - + static PointLatLon make(T lat, T lon) { lat = normal(lat, -90.); if (lat > 90.) { - lat -= 180.; + lat = 180. - lat; lon += 180.; } return {lat, lat == -90. || lat == 90. ? 0. : normal(lon, 0.)}; } + PointLatLon antipode() const { return make(lat + 180., lon); } + // -- Overridden methods // None diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3e6dcd7fb..b95d57c77 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,6 +3,7 @@ include(CTest) foreach(name projection projection_rotation + types util) add_executable(test_${name} ${name}.cc) target_link_libraries(test_${name} grit) diff --git a/tests/projection_rotation.cc b/tests/projection_rotation.cc index 253536a53..d9c6fa896 100644 --- a/tests/projection_rotation.cc +++ b/tests/projection_rotation.cc @@ -10,97 +10,45 @@ */ -#include #include -#include -#include -#include "grit/Projection.h" #include "grit/exception.h" #include "grit/projection/Rotation.h" -#include "grit/util.h" - - -using grit::PointLatLon; -using grit::projection::Rotation; - -static const PointLatLon SP{-90., 0.}; -static const PointLatLon NP{90., 180.}; - - -bool equivalent(const PointLatLon& a, const PointLatLon& b) { - auto f = [=](double lon) { return 10. + std::cos(lon * grit::util::degrees_to_radians); }; - auto eq = [](double a, double b) { return grit::util::is_approximately_equal(a, b, 1e-5); }; - - auto ok = (eq(a.lat, 90.) && eq(b.lat, 90.)) || (eq(a.lat, -90.) && eq(b.lat, -90.)) || - eq(a.lat, b.lat) && eq(f(a.lon), f(b.lon)); - - std::cout << a << " <=> " << b << " ? " << ok << std::endl; - return ok; -} - - -void eqv(const Rotation& rot, const PointLatLon& a, const PointLatLon& b) { - auto bn = rot.direct(a); - auto bok = equivalent(bn, b); - // std::cout << a << " -> " << bn << " == " << b << " ? " << bok << std::endl; - - auto an = rot.inverse(b); - auto aok = equivalent(an, a); - // std::cout << b << " <- " << an << " == " << a << " ? " << aok << std::endl; - - ASSERT(aok && bok); -} int main(int argc, char* argv[]) { - { - std::unique_ptr unrotated(new Rotation(-90., 0., 0.)); + using grit::PointLatLon; + using grit::projection::Rotation; - const PointLatLon a(1, 1); - auto b = unrotated->direct(a); - auto c = unrotated->inverse(b); - auto e = unrotated->inverse(a); - auto f = unrotated->direct(e); - - std::cout << "unrotated: " << a << " -> " << b << " -> " << c << std::endl; - std::cout << "unrotated: " << a << " -> " << e << " -> " << f << std::endl; - } { - std::unique_ptr angle_only(new Rotation(-90., 0., 10.)); - - const PointLatLon a(1, 1); - auto b = angle_only->direct(a); - auto c = angle_only->inverse(b); - auto e = angle_only->inverse(a); - auto f = angle_only->direct(e); - - std::cout << "angle_only: " << a << " -> " << b << " -> " << c << std::endl; - std::cout << "angle_only: " << a << " -> " << e << " -> " << f << std::endl; + const PointLatLon p(1, 1); + + for (const auto& rotation : { + Rotation(-90., 0., 0.), + Rotation(-90., 0., 10.), + Rotation(-89., 1., 0.), + Rotation(-89., 1., 10.), + Rotation(90., 180., 0.), + Rotation(90., 180., 10.), + Rotation(-89.9, 0., 0.), + Rotation(-89.9, 0., 10.), + Rotation(89.9, 0., 0.), + Rotation(89.9, 0., 10.), + Rotation(1., 1., 0.), + Rotation(1., 1., 10.), + }) { + ASSERT(p.is_approximately_equal(rotation.inv(rotation.fwd(p)), 1e-5)); + ASSERT(p.is_approximately_equal(rotation.fwd(rotation.inv(p)), 1e-5)); + } } - { - std::unique_ptr angle_vector(new Rotation(-89., 1., 10.)); - - const PointLatLon a(1, 1); - auto b = angle_vector->direct(a); - auto c = angle_vector->inverse(b); - auto e = angle_vector->inverse(a); - auto f = angle_vector->direct(e); - - std::cout << "angle_vector: " << a << " -> " << b << " -> " << c << std::endl; - std::cout << "angle_vector: " << a << " -> " << e << " -> " << f << std::endl; - } { - const int nx = 12; - const int ny = 6; - - - Rotation rot(-133.3, 2., - 180.); // NP (lat, lon) = (46.7, 2., 180.) (SP cannot be expressed canonically for the same point) + const int Ni = 12; + const int Nj = 3; + Rotation rot(-46.7, 182., 0.); const PointLatLon ref[]{ {-46.7, -178.}, {-16.7, -178.}, @@ -188,77 +136,54 @@ int main(int argc, char* argv[]) { {46.7, 2.}, }; - for (int i = 0, jglo = 0; i < nx; i++) { - for (int j = 0; j < ny + 1; j++, jglo++) { - double lon = static_cast(i) * 360. / static_cast(nx); - double lat = static_cast(j - ny / 2) * 90. / static_cast(ny / 2); - PointLatLon p0(lat, lon); - auto p1 = rot.direct(p0); - auto p2 = rot.inverse(p1); - ASSERT(equivalent(p2, p0)); - ASSERT(equivalent(p1, ref[jglo])); + for (int i = 0, k = 0; i < Ni; i++) { + for (int j = 0; j < 2 * Nj + 1; j++, k++) { + PointLatLon a(static_cast(j - Nj) * 90. / static_cast(Nj), + static_cast(i) * 360. / static_cast(Ni)); + auto b = rot.fwd(a); + ASSERT(b.is_approximately_equal(ref[k], 1.e-5)); + ASSERT(a.is_approximately_equal(rot.inv(b), 1.e-5)); } } } { - for (const auto& p : {SP, NP, PointLatLon{-89.9, 0.}, PointLatLon{89.9, 0.}}) { - Rotation rotation(p.lat, p.lon, 0.); - ASSERT(rotation.rotated() == (p != SP)); - } - } + const Rotation unrotated(-90., 0., 0.); + const Rotation angle_only(-90., 0., -180.); + const Rotation rotation(-40., 4., 180.); - - { - using P = PointLatLon; - using PQ = std::pair; - - Rotation unrotated(SP.lat, SP.lon, 0.); ASSERT(not unrotated.rotated()); - - for (const auto& p : {P{90., 0.}, P{0., 0.}, P{25., 270.}, P{45., -180.}}) { - eqv(unrotated, p, p); - } - - Rotation angle_only(SP.lat, SP.lon, -180.); ASSERT(angle_only.rotated()); - - for (const auto& p : {P{90., 0.}, P{0., 0.}, P{25., 270.}, P{45., -180.}}) { - eqv(angle_only, p, {p.lat, p.lon - 180.}); - } - - Rotation rotation(-40., 4., 0.); ASSERT(rotation.rotated()); - eqv(rotation, {90., 0.}, {40., -176.}); - // eqv(rotation, {0., 0.}, {-50., -176.}); - // eqv(rotation, {45., -180.}, {85., -176.}); - -#if 0 - Config config; - config.set("north_pole", std::vector{-176, 40}); - Rotation rotation(config); - Log::info() << rotation << std::endl; + const PointLatLon p[] = {{90., 0.}, {0., 0.}, {25., 270.}, {45., -180.}}; - EXPECT(rotation.rotated()); - - PointLonLat p, r; - - p = {0., 90.}; - r = {-176., 40.}; - EXPECT_EQUIVALENT(rotation.rotate(p), r); - EXPECT_EQUIVALENT(rotation.unrotate(r), p); - - p = {0., 0.}; - r = {-176., -50.}; - EXPECT_EQUIVALENT(rotation.rotate(p), r); - EXPECT_EQUIVALENT(rotation.unrotate(r), p); + struct test_t { + const Rotation& rotation; + const PointLatLon a; + const PointLatLon b; + }; - p = {-180., 45.}; - r = {-176., 85.}; - EXPECT_EQUIVALENT(rotation.rotate(p), r); - EXPECT_EQUIVALENT(rotation.unrotate(r), p); -#endif + for (const auto& test : { + test_t{unrotated, p[0], p[0]}, + test_t{unrotated, p[1], p[1]}, + test_t{unrotated, p[2], p[2]}, + test_t{unrotated, p[3], p[3]}, + test_t{angle_only, p[0], {p[0].lat, p[0].lon - 180.}}, + test_t{angle_only, p[1], {p[1].lat, p[1].lon - 180.}}, + test_t{angle_only, p[2], {p[2].lat, p[2].lon - 180.}}, + test_t{angle_only, p[3], {p[3].lat, p[3].lon - 180.}}, + test_t{rotation, p[0], {40., -176.}}, + test_t{rotation, p[1], {-50., -176.}}, + test_t{rotation, p[2], {15.762700, 113.657357}}, + test_t{rotation, p[3], {85., -176.}}, + }) { + auto b = test.rotation.fwd(test.a); + ASSERT(b.is_approximately_equal(test.b, 1e-5)); + + auto a = test.rotation.inv(b); + ASSERT(a.is_approximately_equal(test.a, 1e-5)); + } } } diff --git a/tests/types.cc b/tests/types.cc new file mode 100644 index 000000000..38da777cd --- /dev/null +++ b/tests/types.cc @@ -0,0 +1,38 @@ +/* + * (C) Copyright 1996- 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 + +#include "grit/exception.h" +#include "grit/types.h" + + +int main(int argc, char* argv[]) { + using grit::PointLatLon; + + PointLatLon p(90., 1); + + std::cout << "p: " << p << std::endl; + std::cout << "p: " << PointLatLon::make(p.lat, p.lon) << std::endl; + std::cout << "p: " << (p == PointLatLon(90., 50.)) << std::endl; + + PointLatLon q(-90., 1.); + std::cout << "q: " << q << std::endl; + std::cout << "~q: " << q.antipode() << std::endl; + std::cout << "~~q: " << q.antipode().antipode() << std::endl; + + auto r(PointLatLon::make(-91., -10.)); + ASSERT(r == r.antipode().antipode()); + + ASSERT(PointLatLon(-30.000000000000018, -59.99999999999996).is_approximately_equal({-30, 300}, 1e-5)); + ASSERT(PointLatLon(-46.7, -178.00000000000003).is_approximately_equal({-46.7, -178.}, 1e-5)); +} From 80e3bb5b339f6455f266bf89c6e7d24ff939a93b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 21 Apr 2023 17:56:18 +0100 Subject: [PATCH 150/737] projection --- src/grit/projection/Rotation.cc | 117 +++++++++++++++++--------------- src/grit/projection/Rotation.h | 64 ++++------------- tests/projection_rotation.cc | 15 ++++ 3 files changed, 92 insertions(+), 104 deletions(-) diff --git a/src/grit/projection/Rotation.cc b/src/grit/projection/Rotation.cc index 53947cc2c..7c28c179e 100644 --- a/src/grit/projection/Rotation.cc +++ b/src/grit/projection/Rotation.cc @@ -13,91 +13,98 @@ #include "grit/projection/Rotation.h" #include +#include -#include "grit/exception.h" #include "grit/geometry/Sphere.h" +#include "grit/types/MatrixXYZ.h" #include "grit/util.h" namespace grit::projection { -Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : - angle_(util::normalise_longitude_to_minimum(angle, 0.)) { +Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : rotated_(true) { + using M = types::MatrixXYZ; + + struct No final : Rotate { + PointLatLon operator()(const PointLatLon& p) const override { return p; } + }; + + struct Angle final : Rotate { + explicit Angle(double angle) : angle_(angle) {} + PointLatLon operator()(const PointLatLon& p) const override { return {p.lat, p.lon + angle_}; } + const double angle_; + }; + + struct Matrix final : Rotate { + explicit Matrix(M&& R) : R_(R) {} + PointLatLon operator()(const PointLatLon& p) const override { + return geometry::Sphere::xyz_to_ll(1., R_ * geometry::Sphere::ll_to_xyz(1., p, 0.)); + } + const M R_; + }; + + const auto alpha = angle * util::degrees_to_radians; const auto theta = -(south_pole_lat + 90.) * util::degrees_to_radians; const auto phi = -(south_pole_lon)*util::degrees_to_radians; - const auto sin_theta = std::sin(theta); - const auto cos_theta = std::cos(theta); - const auto sin_phi = std::sin(phi); - const auto cos_phi = std::cos(phi); - - auto eq = [](double a, double b) { return util::is_approximately_equal(a, b, 1.e-12); }; - if (eq(sin_theta, 0) && eq(cos_theta, 1)) { - rotation_ = eq(angle_, 0) && eq(sin_phi, 0) && eq(cos_phi, 1) ? rotation_type::UNROTATED : rotation_type::ANGLE; + const auto ca = std::cos(alpha); + const auto ct = std::cos(theta); + const auto cp = std::cos(phi); + + if (util::is_approximately_equal(ct, 1., 1.e-12)) { + if (util::is_approximately_equal(ca * cp, 1., 1.e-12)) { + fwd_ = std::make_unique(); + inv_ = std::make_unique(); + rotated_ = false; + return; + } + + auto a = util::normalise_longitude_to_minimum(angle - south_pole_lon, -180.); + fwd_ = std::make_unique(-a); + inv_ = std::make_unique(a); return; } - rotation_ = rotation_type::ANGLE_VECTOR; - - // Rotate: rotate by ϑ (y-axis, along the rotated Greenwich meridian), then by φ (z-axis) - // q = Rz * Ry * p = [ cosφ sinφ ] * [ cosϑ sinϑ ] * p = [ cosϑ.cosφ sinφ sinϑ.cosφ ] * p - // [ -sinφ cosφ ] [ 1 ] [ -cosϑ.sinφ cosφ -sinϑ.sinφ ] - // [ 1 ] [ -sinϑ cosϑ ] [ -sinϑ cosϑ ] - R_ = {cos_theta * cos_phi, sin_phi, sin_theta * cos_phi, - -cos_theta * sin_phi, cos_phi, -sin_theta * sin_phi, - -sin_theta, 0., cos_theta}; - - // Un-rotate (the reverse): - // p = Ry * Rz * q = [ cosϑ -sinϑ ] * [ cosφ -sinφ ] * q = [ cosϑ.cosφ -cosϑ.sinφ -sinϑ ] * q - // [ 1 ] [ sinφ cosφ ] [ sinφ cosφ ] - // [ sinϑ cosϑ ] [ 1 ] [ sinϑ.cosφ -sinϑ.sinφ cosϑ ] - U_ = {cos_theta * cos_phi, -cos_theta * sin_phi, -sin_theta, sin_phi, cos_phi, 0., - sin_theta * cos_phi, -sin_theta * sin_phi, cos_theta}; + const auto sa = std::sin(alpha); + const auto st = std::sin(theta); + const auto sp = std::sin(phi); + + // Rotate: rotate by α, then ϑ (y-axis, along the rotated Greenwich meridian), then φ (z-axis) + // q = Rz Ry Ra p = [ cosφ sinφ ] [ cosϑ sinϑ ] [ cosα sinα ] p + // [ -sinφ cosφ ] [ 1 ] [ -sinα cosα ] + // [ 1 ] [ -sinϑ cosϑ ] [ 1 ] + fwd_ = std::make_unique(M{ca * cp * ct - sa * sp, sa * cp * ct + ca * sp, cp * st, // + -sa * cp - ca * ct * sp, ca * cp - sa * ct * sp, -sp * st, // + -ca * st, -sa * st, ct}); + + // Un-rotate (rotate by -φ, -ϑ, -α): + // p = Ra Ry Rz q = [ cosα -sinα ] [ cosϑ -sinϑ ] [ cosφ -sinφ ] q + // [ sinα cosα ] [ 1 ] [ sinφ cosφ ] + // [ 1 ] [ sinϑ cosϑ ] [ 1 ] + inv_ = std::make_unique(M{ca * cp * ct - sa * sp, -sa * cp - ca * ct * sp, -ca * st, // + sa * cp * ct + ca * sp, ca * cp - sa * ct * sp, -sa * st, // + cp * st, -sp * st, ct}); } PointLatLon Rotation::fwd(const PointLatLon& p) const { - if (rotation_ == rotation_type::ANGLE) { - auto q = p; - q.lon -= angle_; - return q; - } - - if (rotation_ == rotation_type::ANGLE_VECTOR) { - auto q = p; - q.lon -= angle_; - return geometry::Sphere::xyz_to_ll(1., R_ * geometry::Sphere::ll_to_xyz(1., q, 0.)); - } - - return p; + return (*fwd_)(p); } PointLatLon Rotation::inv(const PointLatLon& q) const { - if (rotation_ == rotation_type::ANGLE) { - auto p = q; - p.lon += angle_; - return p; - } - - if (rotation_ == rotation_type::ANGLE_VECTOR) { - auto p = geometry::Sphere::xyz_to_ll(1., U_ * geometry::Sphere::ll_to_xyz(1., q, 0.)); - p.lon += angle_; - return p; - } - - return q; + return (*inv_)(q); } Point Rotation::fwd(const Point& p) const { - return fwd(std::get(p)); + return (*fwd_)(std::get(p)); } Point Rotation::inv(const Point& q) const { - return inv(std::get(q)); + return (*inv_)(std::get(q)); } diff --git a/src/grit/projection/Rotation.h b/src/grit/projection/Rotation.h index 6a906abde..9b731b487 100644 --- a/src/grit/projection/Rotation.h +++ b/src/grit/projection/Rotation.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include "grit/Projection.h" @@ -25,39 +25,16 @@ class Rotation final : public Projection { public: // -- Types - struct MatrixXYZ : std::array { - MatrixXYZ() : array{1, 0, 0, 0, 1, 0, 0, 0, 1} {} - - MatrixXYZ(double xx, double xy, double xz, double yx, double yy, double yz, double zx, double zy, double zz) : - array{xx, xy, xz, yx, yy, yz, zx, zy, zz} {} - - MatrixXYZ(const MatrixXYZ& other) : array(other) {} - MatrixXYZ(MatrixXYZ&& other) : array(other) {} - - ~MatrixXYZ() = default; - - MatrixXYZ& operator=(const MatrixXYZ& other) { - array::operator=(other); - return *this; - } - MatrixXYZ& operator=(MatrixXYZ&& other) { - array::operator=(other); - return *this; - } - - double& xx = operator[](0); - double& xy = operator[](1); - double& xz = operator[](2); - double& yx = operator[](3); - double& yy = operator[](4); - double& yz = operator[](5); - double& zx = operator[](6); - double& zy = operator[](7); - double& zz = operator[](8); - - PointXYZ operator*(const PointXYZ& p) const { - return {xx * p.x + xy * p.y + xz * p.z, yx * p.x + yy * p.y + yz * p.z, zx * p.x + zy * p.y + zz * p.z}; - } + struct Rotate { + Rotate() = default; + virtual ~Rotate() = default; + + Rotate(const Rotate&) = delete; + Rotate(Rotate&&) = delete; + void operator=(const Rotate&) = delete; + void operator=(Rotate&&) = delete; + + virtual PointLatLon operator()(const PointLatLon&) const = 0; }; // -- Exceptions @@ -78,7 +55,7 @@ class Rotation final : public Projection { // -- Methods - bool rotated() const { return rotation_ != rotation_type::UNROTATED; } + bool rotated() const { return rotated_; } PointLatLon fwd(const PointLatLon&) const; PointLatLon inv(const PointLatLon&) const; @@ -92,22 +69,11 @@ class Rotation final : public Projection { // None private: - // -- Types - - enum class rotation_type - { - UNROTATED, - ANGLE, - ANGLE_VECTOR - }; - // -- Members - rotation_type rotation_ = rotation_type::UNROTATED; - - MatrixXYZ R_; - MatrixXYZ U_; - double angle_ = 0.; + std::unique_ptr fwd_; + std::unique_ptr inv_; + bool rotated_; // -- Methods // None diff --git a/tests/projection_rotation.cc b/tests/projection_rotation.cc index d9c6fa896..a8af7f33b 100644 --- a/tests/projection_rotation.cc +++ b/tests/projection_rotation.cc @@ -21,6 +21,21 @@ int main(int argc, char* argv[]) { using grit::projection::Rotation; + { + PointLatLon SP{-90., 0.}; + double delta[] = {-720., -360., 0., 360., 720.}; + + for (double angle : delta) { + for (double dlat : delta) { + for (double dlon : delta) { + Rotation rotation(SP.lat + dlat, SP.lon + dlon, angle); + std::cout << rotation.rotated() << std::endl; + } + } + } + } + + { const PointLatLon p(1, 1); From b8621a0ab33a87e3599698c97b766a8908aee5d9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 21 Apr 2023 18:05:48 +0100 Subject: [PATCH 151/737] projection --- tests/projection_rotation.cc | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/tests/projection_rotation.cc b/tests/projection_rotation.cc index a8af7f33b..153e4c85d 100644 --- a/tests/projection_rotation.cc +++ b/tests/projection_rotation.cc @@ -23,13 +23,23 @@ int main(int argc, char* argv[]) { { PointLatLon SP{-90., 0.}; - double delta[] = {-720., -360., 0., 360., 720.}; - - for (double angle : delta) { - for (double dlat : delta) { - for (double dlon : delta) { - Rotation rotation(SP.lat + dlat, SP.lon + dlon, angle); - std::cout << rotation.rotated() << std::endl; + double delta1[] = {-720., -360., 0., 360., 720.}; + double delta2[] = {-1., 1.}; + + for (double d1 : delta1) { + for (double d2 : delta1) { + for (double d3 : delta1) { + Rotation rotation(SP.lat + d1, SP.lon + d2, d3); + ASSERT(not rotation.rotated()); + + for (double d4 : delta2) { + for (double d5 : delta2) { + for (double d6 : delta2) { + Rotation rotation(SP.lat + d1 + d4, SP.lon + d2 + d5, d3 + d6); + ASSERT(rotation.rotated()); + } + } + } } } } From f9cb8709fa896aa62ae750d5869956fd93ccac0e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 24 Apr 2023 09:50:13 +0100 Subject: [PATCH 152/737] projection --- src/grit/CMakeLists.txt | 2 - src/grit/Iterator.cc | 7 +-- src/grit/Iterator.h | 6 +-- src/grit/Transformation.cc | 16 ------ src/grit/Transformation.h | 99 -------------------------------------- 5 files changed, 7 insertions(+), 123 deletions(-) delete mode 100644 src/grit/Transformation.cc delete mode 100644 src/grit/Transformation.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 3c17e4610..ba12185a4 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -9,8 +9,6 @@ add_library(grit SHARED Projection.h Scanner.cc Scanner.h - Transformation.cc - Transformation.h exception.h figure/Sphere.cc figure/Sphere.h diff --git a/src/grit/Iterator.cc b/src/grit/Iterator.cc index 8f50887c2..42d03c82b 100644 --- a/src/grit/Iterator.cc +++ b/src/grit/Iterator.cc @@ -13,18 +13,19 @@ #include "grit/Iterator.h" #include "grit/Figure.h" +#include "grit/Projection.h" #include "grit/Scanner.h" -#include "grit/Transformation.h" #include "grit/exception.h" namespace grit { -Iterator::Iterator(Scanner* scanner, Figure* figure, Transformation* transformation) : - scanner_(scanner), figure_(figure), transformation_(transformation) { +Iterator::Iterator(Scanner* scanner, Figure* figure, Projection* projection) : + scanner_(scanner), figure_(figure), projection_(projection) { ASSERT(scanner_); ASSERT(figure_); + ASSERT(projection_); } diff --git a/src/grit/Iterator.h b/src/grit/Iterator.h index c8542cc3f..c05cd00a2 100644 --- a/src/grit/Iterator.h +++ b/src/grit/Iterator.h @@ -17,8 +17,8 @@ namespace grit { struct Figure; +struct Projection; struct Scanner; -struct Transformation; } // namespace grit @@ -68,7 +68,7 @@ class Iterator final { // -- Constructors - Iterator(Scanner* scanner, Figure* figure, Transformation* transformation); + Iterator(Scanner*, Figure*, Projection*); Iterator(const Iterator&) = delete; Iterator(Iterator&&) = delete; @@ -115,7 +115,7 @@ class Iterator final { std::unique_ptr scanner_; std::unique_ptr
figure_; - std::unique_ptr transformation_; + std::unique_ptr projection_; // -- Methods // None diff --git a/src/grit/Transformation.cc b/src/grit/Transformation.cc deleted file mode 100644 index 7f8b737ff..000000000 --- a/src/grit/Transformation.cc +++ /dev/null @@ -1,16 +0,0 @@ -/* - * (C) Copyright 1996- 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 "grit/Transformation.h" - - -namespace grit {} // namespace grit diff --git a/src/grit/Transformation.h b/src/grit/Transformation.h deleted file mode 100644 index e7b7c0cf9..000000000 --- a/src/grit/Transformation.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "grit/types.h" - - -namespace grit { - - -class Transformation { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - Transformation() noexcept = default; - - Transformation(const Transformation&) = default; - Transformation(Transformation&&) = default; - - // -- Destructor - - virtual ~Transformation() = default; - - // -- Convertors - // None - - // -- Operators - - Transformation& operator=(const Transformation&) = default; - Transformation& operator=(Transformation&&) = default; - - virtual Point operator()(const Point&) const = 0; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace grit From f7118eac467510023f15f5c1785c0efca1de00dd Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 24 Apr 2023 09:56:20 +0100 Subject: [PATCH 153/737] projection --- src/grit/projection/Rotation.cc | 36 +++++------------------ src/grit/projection/Rotation.h | 8 ++--- tests/projection_rotation.cc | 52 +++++++-------------------------- 3 files changed, 22 insertions(+), 74 deletions(-) diff --git a/src/grit/projection/Rotation.cc b/src/grit/projection/Rotation.cc index 7c28c179e..e5f91eaff 100644 --- a/src/grit/projection/Rotation.cc +++ b/src/grit/projection/Rotation.cc @@ -53,19 +53,17 @@ Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : const auto cp = std::cos(phi); if (util::is_approximately_equal(ct, 1., 1.e-12)) { - if (util::is_approximately_equal(ca * cp, 1., 1.e-12)) { - fwd_ = std::make_unique(); - inv_ = std::make_unique(); - rotated_ = false; - return; - } + angle = util::normalise_longitude_to_minimum(angle - south_pole_lon, -180.); + rotated_ = !util::is_approximately_equal(angle, 0., 1.e-12); - auto a = util::normalise_longitude_to_minimum(angle - south_pole_lon, -180.); - fwd_ = std::make_unique(-a); - inv_ = std::make_unique(a); + fwd_.reset(rotated_ ? static_cast(new Angle(-angle)) : new No); + inv_.reset(rotated_ ? static_cast(new Angle(angle)) : new No); return; } + // FIXME this supports either angle-based or matrix-based rotation (but not both); + // Implementing as Euler angles rotation matrix (ideal, but reordering Rz Ry Ra) changes the existing unit test + const auto sa = std::sin(alpha); const auto st = std::sin(theta); const auto sp = std::sin(phi); @@ -88,24 +86,4 @@ Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : } -PointLatLon Rotation::fwd(const PointLatLon& p) const { - return (*fwd_)(p); -} - - -PointLatLon Rotation::inv(const PointLatLon& q) const { - return (*inv_)(q); -} - - -Point Rotation::fwd(const Point& p) const { - return (*fwd_)(std::get(p)); -} - - -Point Rotation::inv(const Point& q) const { - return (*inv_)(std::get(q)); -} - - } // namespace grit::projection diff --git a/src/grit/projection/Rotation.h b/src/grit/projection/Rotation.h index 9b731b487..63d42c011 100644 --- a/src/grit/projection/Rotation.h +++ b/src/grit/projection/Rotation.h @@ -56,8 +56,8 @@ class Rotation final : public Projection { // -- Methods bool rotated() const { return rotated_; } - PointLatLon fwd(const PointLatLon&) const; - PointLatLon inv(const PointLatLon&) const; + PointLatLon fwd(const PointLatLon& p) const { return (*fwd_)(p); } + PointLatLon inv(const PointLatLon& q) const { return (*inv_)(q); } // -- Overridden methods // None @@ -80,8 +80,8 @@ class Rotation final : public Projection { // -- Overridden methods - Point fwd(const Point&) const override; - Point inv(const Point&) const override; + Point fwd(const Point& p) const override { return (*fwd_)(std::get(p)); } + Point inv(const Point& q) const override { return (*inv_)(std::get(q)); } // -- Class members // None diff --git a/tests/projection_rotation.cc b/tests/projection_rotation.cc index 153e4c85d..5c9429751 100644 --- a/tests/projection_rotation.cc +++ b/tests/projection_rotation.cc @@ -21,50 +21,20 @@ int main(int argc, char* argv[]) { using grit::projection::Rotation; - { - PointLatLon SP{-90., 0.}; - double delta1[] = {-720., -360., 0., 360., 720.}; - double delta2[] = {-1., 1.}; - - for (double d1 : delta1) { - for (double d2 : delta1) { - for (double d3 : delta1) { - Rotation rotation(SP.lat + d1, SP.lon + d2, d3); - ASSERT(not rotation.rotated()); - - for (double d4 : delta2) { - for (double d5 : delta2) { - for (double d6 : delta2) { - Rotation rotation(SP.lat + d1 + d4, SP.lon + d2 + d5, d3 + d6); - ASSERT(rotation.rotated()); - } - } - } - } - } - } - } - - { const PointLatLon p(1, 1); + int delta[] = {-360, -180, -1, 0, 1, 90, 91, 180}; - for (const auto& rotation : { - Rotation(-90., 0., 0.), - Rotation(-90., 0., 10.), - Rotation(-89., 1., 0.), - Rotation(-89., 1., 10.), - Rotation(90., 180., 0.), - Rotation(90., 180., 10.), - Rotation(-89.9, 0., 0.), - Rotation(-89.9, 0., 10.), - Rotation(89.9, 0., 0.), - Rotation(89.9, 0., 10.), - Rotation(1., 1., 0.), - Rotation(1., 1., 10.), - }) { - ASSERT(p.is_approximately_equal(rotation.inv(rotation.fwd(p)), 1e-5)); - ASSERT(p.is_approximately_equal(rotation.fwd(rotation.inv(p)), 1e-5)); + for (auto a : delta) { + for (auto b : delta) { + for (auto c : delta) { + Rotation rot(-90. + static_cast(a), 0. + static_cast(b), static_cast(c)); + ASSERT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); + + ASSERT(p.is_approximately_equal(rot.inv(rot.fwd(p)), 1e-5)); + ASSERT(p.is_approximately_equal(rot.fwd(rot.inv(p)), 1e-5)); + } + } } } From 189f4179f65060bae387947b7398b2cc39464e4f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 24 Apr 2023 10:08:54 +0100 Subject: [PATCH 154/737] util --- src/grit/util.h | 4 +++- src/grit/util/monotonic_crop.cc | 5 ++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/grit/util.h b/src/grit/util.h index bdc281aea..0d87b77d5 100644 --- a/src/grit/util.h +++ b/src/grit/util.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "grit/types.h" @@ -62,7 +63,8 @@ std::vector linspace(double start, double stop, size_t num, bool endpoin std::vector gaussian_latitudes(size_t N, bool increasing); -std::vector monotonic_crop(const std::vector&, double min, double max, double eps); +std::pair::const_iterator, std::vector::const_iterator> monotonic_crop( + const std::vector&, double min, double max, double eps); /// @return longitude in degree within range [minimum, minimum + 360[ diff --git a/src/grit/util/monotonic_crop.cc b/src/grit/util/monotonic_crop.cc index f07eafded..e10674cca 100644 --- a/src/grit/util/monotonic_crop.cc +++ b/src/grit/util/monotonic_crop.cc @@ -10,8 +10,6 @@ */ -#include - #include "grit/exception.h" #include "grit/util.h" @@ -19,7 +17,8 @@ namespace grit::util { -std::vector monotonic_crop(const std::vector& values, double min, double max, double eps) { +std::pair::const_iterator, std::vector::const_iterator> monotonic_crop( + const std::vector& values, double min, double max, double eps) { if (values.empty() || min > max) { return {}; } From b64e3a20896e1d288cc567fa05ea6bbfb1270a39 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 24 Apr 2023 10:18:36 +0100 Subject: [PATCH 155/737] figure --- src/grit/CMakeLists.txt | 4 -- src/grit/figure/Sphere.cc | 56 ------------------------ src/grit/figure/Sphere.h | 81 ----------------------------------- src/grit/figure/Spheroid.cc | 57 ------------------------ src/grit/figure/Spheroid.h | 81 ----------------------------------- src/grit/geometry/Spheroid.cc | 32 +++++++++++++- src/grit/geometry/Spheroid.h | 12 ------ 7 files changed, 30 insertions(+), 293 deletions(-) delete mode 100644 src/grit/figure/Sphere.cc delete mode 100644 src/grit/figure/Sphere.h delete mode 100644 src/grit/figure/Spheroid.cc delete mode 100644 src/grit/figure/Spheroid.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index ba12185a4..635a4a0ba 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -10,10 +10,6 @@ add_library(grit SHARED Scanner.cc Scanner.h exception.h - figure/Sphere.cc - figure/Sphere.h - figure/Spheroid.cc - figure/Spheroid.h geometry/BoundingBox.cc geometry/BoundingBox.h geometry/GreatCircle.cc diff --git a/src/grit/figure/Sphere.cc b/src/grit/figure/Sphere.cc deleted file mode 100644 index 3f182f535..000000000 --- a/src/grit/figure/Sphere.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * (C) Copyright 1996- 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 "grit/figure/Sphere.h" - -#include "grit/geometry/Sphere.h" - - -namespace grit::figure { - - -double Sphere::angle(const PointLatLon& A, const PointLatLon& B) const { - return geometry::Sphere::angle(A, B); -} - - -double Sphere::angle(const PointXYZ& A, const PointXYZ& B) const { - return geometry::Sphere::angle(R(), A, B); -} - - -double Sphere::distance(const PointLatLon& A, const PointLatLon& B) const { - return geometry::Sphere::distance(R(), A, B); -} - - -double Sphere::distance(const PointXYZ& A, const PointXYZ& B) const { - return geometry::Sphere::distance(R(), A, B); -} - - -double Sphere::area() const { - return geometry::Sphere::area(R()); -} - - -PointXYZ Sphere::ll_to_xyz(const PointLatLon& P, double height) const { - return geometry::Sphere::ll_to_xyz(R(), P, height); -} - - -PointLatLon Sphere::xyz_to_ll(const PointXYZ& P) const { - return geometry::Sphere::xyz_to_ll(R(), P); -} - - -} // namespace grit::figure diff --git a/src/grit/figure/Sphere.h b/src/grit/figure/Sphere.h deleted file mode 100644 index cfbc70406..000000000 --- a/src/grit/figure/Sphere.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "grit/Figure.h" - - -namespace grit::figure { - - -class Sphere final : public Figure { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit Sphere(double R) : Figure(R) {} - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - - double angle(const PointLatLon&, const PointLatLon&) const override; - double angle(const PointXYZ&, const PointXYZ&) const override; - double distance(const PointLatLon&, const PointLatLon&) const override; - double distance(const PointXYZ&, const PointXYZ&) const override; - double area() const override; - PointXYZ ll_to_xyz(const PointLatLon&, double height) const override; - PointLatLon xyz_to_ll(const PointXYZ&) const override; - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - -} // namespace grit::figure diff --git a/src/grit/figure/Spheroid.cc b/src/grit/figure/Spheroid.cc deleted file mode 100644 index 16fda1f58..000000000 --- a/src/grit/figure/Spheroid.cc +++ /dev/null @@ -1,57 +0,0 @@ -/* - * (C) Copyright 1996- 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 "grit/figure/Spheroid.h" - - -#include "grit/exception.h" - - -namespace grit::figure { - - -double Spheroid::angle(const PointLatLon& A, const PointLatLon& B) const { - NOTIMP; -} - - -double Spheroid::angle(const PointXYZ& A, const PointXYZ& B) const { - NOTIMP; -} - - -double Spheroid::distance(const PointLatLon& A, const PointLatLon& B) const { - NOTIMP; -} - - -double Spheroid::distance(const PointXYZ& A, const PointXYZ& B) const { - NOTIMP; -} - - -double Spheroid::area() const { - NOTIMP; -} - - -PointXYZ Spheroid::ll_to_xyz(const PointLatLon& P, double height) const { - NOTIMP; -} - - -PointLatLon Spheroid::xyz_to_ll(const PointXYZ& P) const { - NOTIMP; -} - - -} // namespace grit::figure diff --git a/src/grit/figure/Spheroid.h b/src/grit/figure/Spheroid.h deleted file mode 100644 index e0c9589ac..000000000 --- a/src/grit/figure/Spheroid.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "grit/Figure.h" - - -namespace grit::figure { - - -class Spheroid final : public Figure { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit Spheroid(double a, double b) : Figure(a, b) {} - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - - double angle(const PointLatLon&, const PointLatLon&) const override; - double angle(const PointXYZ&, const PointXYZ&) const override; - double distance(const PointLatLon&, const PointLatLon&) const override; - double distance(const PointXYZ&, const PointXYZ&) const override; - double area() const override; - PointXYZ ll_to_xyz(const PointLatLon&, double height) const override; - PointLatLon xyz_to_ll(const PointXYZ&) const override; - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - -} // namespace grit::figure diff --git a/src/grit/geometry/Spheroid.cc b/src/grit/geometry/Spheroid.cc index 45da8732d..4f132750e 100644 --- a/src/grit/geometry/Spheroid.cc +++ b/src/grit/geometry/Spheroid.cc @@ -12,8 +12,6 @@ #include "grit/geometry/Spheroid.h" -#include - #include "grit/exception.h" #include "grit/util.h" @@ -21,6 +19,31 @@ namespace grit::geometry { +double Spheroid::angle(const PointLatLon& A, const PointLatLon& B) { + NOTIMP; +} + + +double Spheroid::angle(double a, double b, const PointXYZ& A, const PointXYZ& B) { + NOTIMP; +} + + +double Spheroid::distance(double a, double b, const PointLatLon& A, const PointLatLon& B) { + NOTIMP; +} + + +double Spheroid::distance(double a, double b, const PointXYZ& A, const PointXYZ& B) { + NOTIMP; +} + + +double Spheroid::area(double a, double b) { + NOTIMP; +} + + PointXYZ Spheroid::ll_to_xyz(double a, double b, const PointLatLon& P, double height) { ASSERT(a > 0.); ASSERT(b > 0.); @@ -57,4 +80,9 @@ PointXYZ Spheroid::ll_to_xyz(double a, double b, const PointLatLon& P, double he } +PointLatLon Spheroid::xyz_to_ll(double a, double b, const PointXYZ& A) { + NOTIMP; +} + + } // namespace grit::geometry diff --git a/src/grit/geometry/Spheroid.h b/src/grit/geometry/Spheroid.h index 63cd5de4b..b796e3a89 100644 --- a/src/grit/geometry/Spheroid.h +++ b/src/grit/geometry/Spheroid.h @@ -19,38 +19,26 @@ namespace grit::geometry { struct Spheroid { -#if 0 /// Great-circle central angle between two points (latitude/longitude coordinates) in radians static double angle(const PointLatLon&, const PointLatLon&); -#endif -#if 0 /// Great-circle central angle between two points (Cartesian coordinates) in radians static double angle(double a, double b, const PointXYZ&, const PointXYZ&); -#endif -#if 0 /// Great-circle distance between two points (latitude/longitude coordinates) in metres static double distance(double a, double b, const PointLatLon&, const PointLatLon&); -#endif -#if 0 /// Great-circle distance between two points (Cartesian coordinates) in metres static double distance(double a, double b, const PointXYZ&, const PointXYZ&); -#endif -#if 0 /// Surface area in square metres static double area(double a, double b); -#endif // Convert spherical coordinates to Cartesian static PointXYZ ll_to_xyz(double a, double b, const PointLatLon&, double height); -#if 0 // Convert Cartesian coordinates to spherical static PointLatLon xyz_to_ll(double a, double b, const PointXYZ&); -#endif }; From b4080fc70d6bd806b2f3974871cae25916db1499 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 24 Apr 2023 10:27:50 +0100 Subject: [PATCH 156/737] types --- src/grit/types/MatrixXYZ.h | 21 +++++++++++++++++++-- tests/types.cc | 12 ++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/grit/types/MatrixXYZ.h b/src/grit/types/MatrixXYZ.h index 05376e14f..9a2dd7d8e 100644 --- a/src/grit/types/MatrixXYZ.h +++ b/src/grit/types/MatrixXYZ.h @@ -15,6 +15,7 @@ #include #include +#include "grit/exception.h" #include "grit/types/PointXYZ.h" @@ -37,7 +38,6 @@ class MatrixXYZ final : protected std::array { // -- Constructors - MatrixXYZ() : P{1, 0, 0, 0, 1, 0, 0, 0, 1} {} MatrixXYZ(T xx, T xy, T xz, T yx, T yy, T yz, T zx, T zy, T zz) : P{xx, xy, xz, yx, yy, yz, zx, zy, zz} {} MatrixXYZ(const MatrixXYZ& other) : P(other) {} MatrixXYZ(MatrixXYZ&& other) : P(other) {} @@ -65,6 +65,13 @@ class MatrixXYZ final : protected std::array { return {xx * p.x + xy * p.y + xz * p.z, yx * p.x + yy * p.y + yz * p.z, zx * p.x + zy * p.y + zz * p.z}; } + MatrixXYZ operator*(const MatrixXYZ& M) const { + return { + xx * M.xx + xy * M.yx + xz * M.zx, xx * M.xy + xy * M.yy + xz * M.zy, xx * M.xz + xy * M.yz + xz * M.zz, + yx * M.xx + yy * M.yx + yz * M.zx, yx * M.xy + yy * M.yy + yz * M.zy, yx * M.xz + yy * M.yz + yz * M.zz, + zx * M.xx + zy * M.yx + zz * M.zx, zx * M.xy + zy * M.yy + zz * M.zy, zx * M.xz + zy * M.yz + zz * M.zz}; + } + // -- Members T& xx = P::operator[](0); @@ -78,7 +85,17 @@ class MatrixXYZ final : protected std::array { T& zz = P::operator[](8); // -- Methods - // None + + static MatrixXYZ identity() { return {1, 0, 0, 0, 1, 0, 0, 0, 1}; } + + MatrixXYZ inverse() const { + auto det = xx * (yy * zz - yz * zy) - xy * (yx * zz - yz * zx) + xz * (yx * zy - yy * zx); + ASSERT_MSG(det != 0, "MatrixXYZ: singular matrix"); + + return {(yy * zz - yz * zy) / det, (xz * zy - xy * zz) / det, (xy * yz - xz * yy) / det, + (yz * zx - yx * zz) / det, (xx * zz - xz * zx) / det, (xz * yx - xx * yz) / det, + (yx * zy - yy * zx) / det, (xy * zx - xx * zy) / det, (xx * yy - xy * yx) / det}; + } // -- Overridden methods // None diff --git a/tests/types.cc b/tests/types.cc index 38da777cd..a3f9fe264 100644 --- a/tests/types.cc +++ b/tests/types.cc @@ -14,6 +14,7 @@ #include "grit/exception.h" #include "grit/types.h" +#include "grit/types/MatrixXYZ.h" int main(int argc, char* argv[]) { @@ -35,4 +36,15 @@ int main(int argc, char* argv[]) { ASSERT(PointLatLon(-30.000000000000018, -59.99999999999996).is_approximately_equal({-30, 300}, 1e-5)); ASSERT(PointLatLon(-46.7, -178.00000000000003).is_approximately_equal({-46.7, -178.}, 1e-5)); + + + { + using MatrixXYZ = grit::types::MatrixXYZ; + MatrixXYZ M{1, 2, 3, // + 4, 5, 6, // + 7, 8, 1}; + const auto W = M.inverse(); + std::cout << "M M^-1=" << (M * W) << std::endl; + std::cout << "M^-1 M=" << (W * M) << std::endl; + } } From 2a5c7fc9728dfaf2828d731d3be6da13da382491 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 24 Apr 2023 14:39:31 +0100 Subject: [PATCH 157/737] util --- src/grit/CMakeLists.txt | 1 + src/grit/util/Mutex.h | 58 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/grit/util/Mutex.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 635a4a0ba..7e465678c 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -29,6 +29,7 @@ add_library(grit SHARED types/PointXYZ.h util.cc util.h + util/Mutex.h util/arange.cc util/gaussian_latitudes.cc util/linspace.cc diff --git a/src/grit/util/Mutex.h b/src/grit/util/Mutex.h new file mode 100644 index 000000000..70a8d34e1 --- /dev/null +++ b/src/grit/util/Mutex.h @@ -0,0 +1,58 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#undef grit_ECKIT_THREADS + +#if defined(grit_ECKIT_THREADS) +#include "eckit/thread/AutoLock.h" +#include "eckit/thread/Mutex.h" +#else +#include +#endif + + +namespace grit::util { + + +#if defined(grit_ECKIT_THREADS) + + +using recursive_mutex = eckit::Mutex; + +template +using lock_guard = typename eckit::AutoLock; + +struct once_flag { + pthread_once_t once_ = PTHREAD_ONCE_INIT; +}; + +template +inline void call_once(once_flag& flag, Callable&& fun) { + pthread_once(&(flag.once_), fun); +} + + +#else + + +using std::call_once; +using std::lock_guard; +using std::once_flag; +using std::recursive_mutex; + + +#endif + + +} // namespace grit::util From 0174bc91014bdecf00e45b78b57c3b09a492ab38 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 24 Apr 2023 14:39:48 +0100 Subject: [PATCH 158/737] util --- src/grit/CMakeLists.txt | 1 + src/grit/exception.h | 12 ++++++------ src/grit/log.h | 26 ++++++++++++++++++++++++++ src/grit/util/gaussian_latitudes.cc | 7 ++++--- src/grit/util/reduced_classical_pl.cc | 2 +- 5 files changed, 38 insertions(+), 10 deletions(-) create mode 100644 src/grit/log.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 7e465678c..ddeae31ae 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -19,6 +19,7 @@ add_library(grit SHARED geometry/Spheroid.cc geometry/Spheroid.h geometry/UnitSphere.h + log.h projection/Rotation.cc projection/Rotation.h types.cc diff --git a/src/grit/exception.h b/src/grit/exception.h index a78f7a6c1..491ce8af6 100644 --- a/src/grit/exception.h +++ b/src/grit/exception.h @@ -16,15 +16,15 @@ #include -namespace grit { +namespace grit::exception { -#define ASSERT assert -#define ASSERT_MSG(x, y) assert((x) && (y)) -#define NOTIMP throw std::runtime_error("Not implemented") +using std::runtime_error; -using std::runtime_error; +} -} // namespace grit +#define ASSERT assert +#define ASSERT_MSG(x, y) assert((x) && (y)) +#define NOTIMP throw ::grit::exception::runtime_error("Not implemented") diff --git a/src/grit/log.h b/src/grit/log.h new file mode 100644 index 000000000..ab3a399c7 --- /dev/null +++ b/src/grit/log.h @@ -0,0 +1,26 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + + +namespace grit { + + +auto& error = std::cerr; +auto& warn = std::cout; +auto& info = std::clog; + + +} // namespace grit diff --git a/src/grit/util/gaussian_latitudes.cc b/src/grit/util/gaussian_latitudes.cc index fe472bb85..a3fdb2917 100644 --- a/src/grit/util/gaussian_latitudes.cc +++ b/src/grit/util/gaussian_latitudes.cc @@ -12,10 +12,11 @@ #include #include -#include #include #include +#include "grit/exception.h" + namespace grit::util { @@ -80,8 +81,8 @@ std::vector gaussian_latitudes(size_t N, bool increasing) { } if (!converged) { - throw std::runtime_error("Could not calculate latitude within accuracy/iterations: " + std::to_string(eps) + - "/" + std::to_string(Nmax)); + throw exception::runtime_error("Could not calculate latitude within accuracy/iterations: " + + std::to_string(eps) + "/" + std::to_string(Nmax)); } // Convert colatitude [rad] to latitude [degree], symmetry diff --git a/src/grit/util/reduced_classical_pl.cc b/src/grit/util/reduced_classical_pl.cc index ff4285ed2..4fee162ac 100644 --- a/src/grit/util/reduced_classical_pl.cc +++ b/src/grit/util/reduced_classical_pl.cc @@ -1342,7 +1342,7 @@ const pl_type& reduced_classical_pl(size_t N) { auto pl_half = __classical_pls.find(N); if (pl_half == __classical_pls.end()) { - throw runtime_error("reduced_classical_pl: unknown N=" + std::to_string(N)); + throw exception::runtime_error("reduced_classical_pl: unknown N=" + std::to_string(N)); } ASSERT(pl_half->second.size() == N); From afa0bbca152b2e19ff3b79e77ed4c9b47cf76e45 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 24 Apr 2023 14:53:00 +0100 Subject: [PATCH 159/737] figure --- src/grit/Figure.cc | 61 ++++++++++++++++++++++++++++++++++++++++++++++ src/grit/Figure.h | 35 ++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) diff --git a/src/grit/Figure.cc b/src/grit/Figure.cc index 4c88f6b90..7da898ef5 100644 --- a/src/grit/Figure.cc +++ b/src/grit/Figure.cc @@ -13,9 +13,13 @@ #include "grit/Figure.h" #include +#include +#include #include "grit/exception.h" +#include "grit/log.h" #include "grit/util.h" +#include "grit/util/Mutex.h" namespace grit { @@ -37,4 +41,61 @@ double Figure::R() const { } +static util::once_flag __once; +static util::recursive_mutex* __mutex = nullptr; +static std::map* __factories = nullptr; + + +static void __init() { + __mutex = new util::recursive_mutex(); + __factories = new std::map(); +} + + +FigureFactory::FigureFactory(const FigureFactory::key_type& key) : key_(key) { + util::call_once(__once, __init); + util::lock_guard lock(*__mutex); + + if (auto f = __factories->find(key); f != __factories->end()) { + throw exception::runtime_error("FigureFactory: duplicate '" + key + "'"); + } + + (*__factories)[key] = this; +} + + +FigureFactory::~FigureFactory() { + util::lock_guard lock(*__mutex); + + if (__factories != nullptr) { + __factories->erase(key_); + } +} + + +Figure* FigureFactory::build(const FigureFactory::key_type& key) { + util::call_once(__once, __init); + util::lock_guard lock(*__mutex); + + if (auto f = __factories->find(key); f != __factories->end()) { + return f->second->make(); + } + + list(error << "FigureFactory: unknown '" << key << "', choices are: "); + throw exception::runtime_error("FigureFactory: unknown '" + key + "'"); +} + + +void FigureFactory::list(std::ostream& out) { + util::call_once(__once, __init); + util::lock_guard lock(*__mutex); + + const char* sep = ""; + for (const auto& j : *__factories) { + out << sep << j.first; + sep = ", "; + } +} + + } // namespace grit diff --git a/src/grit/Figure.h b/src/grit/Figure.h index d79dc32b1..9c3543595 100644 --- a/src/grit/Figure.h +++ b/src/grit/Figure.h @@ -12,6 +12,10 @@ #pragma once +#include +#include + + #include "grit/types.h" @@ -124,4 +128,35 @@ class Figure { }; +struct FigureFactory { + using key_type = std::string; + + Figure* build(const key_type&); + static void list(std::ostream&); + + FigureFactory(const FigureFactory&) = delete; + FigureFactory(FigureFactory&&) = delete; + FigureFactory& operator=(const FigureFactory&) = delete; + FigureFactory& operator=(FigureFactory&&) = delete; + + virtual Figure* make() = 0; + +protected: + explicit FigureFactory(const key_type&); + virtual ~FigureFactory(); + +private: + const key_type key_; +}; + + +template +class FigureBuilder final : public FigureFactory { + Figure* make() override { return new T; } + +public: + explicit FigureBuilder(const FigureFactory::key_type& key) : FigureFactory(key) {} +}; + + } // namespace grit From 15be8b1b5685e85181140710e30d8238bd80c6c9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 24 Apr 2023 16:39:11 +0100 Subject: [PATCH 160/737] figure --- src/grit/CMakeLists.txt | 4 ++ src/grit/Figure.cc | 17 ------ src/grit/Figure.h | 17 ++---- src/grit/figure/Sphere.cc | 61 ++++++++++++++++++++ src/grit/figure/Sphere.h | 110 +++++++++++++++++++++++++++++++++++ src/grit/figure/Spheroid.cc | 74 ++++++++++++++++++++++++ src/grit/figure/Spheroid.h | 111 ++++++++++++++++++++++++++++++++++++ 7 files changed, 366 insertions(+), 28 deletions(-) create mode 100644 src/grit/figure/Sphere.cc create mode 100644 src/grit/figure/Sphere.h create mode 100644 src/grit/figure/Spheroid.cc create mode 100644 src/grit/figure/Spheroid.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index ddeae31ae..e4360b074 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -10,6 +10,10 @@ add_library(grit SHARED Scanner.cc Scanner.h exception.h + figure/Sphere.cc + figure/Sphere.h + figure/Spheroid.cc + figure/Spheroid.h geometry/BoundingBox.cc geometry/BoundingBox.h geometry/GreatCircle.cc diff --git a/src/grit/Figure.cc b/src/grit/Figure.cc index 7da898ef5..baae123e4 100644 --- a/src/grit/Figure.cc +++ b/src/grit/Figure.cc @@ -18,29 +18,12 @@ #include "grit/exception.h" #include "grit/log.h" -#include "grit/util.h" #include "grit/util/Mutex.h" namespace grit { -Figure::Figure(double R) : Figure(R, R) {} - - -Figure::Figure(double a, double b) : - a_(a), b_(b), R_(util::is_approximately_equal(a, b) ? a : std::numeric_limits::signaling_NaN()) { - ASSERT(0. < a); - ASSERT(0. < b); -} - - -double Figure::R() const { - ASSERT(sphere()); - return R_; -} - - static util::once_flag __once; static util::recursive_mutex* __mutex = nullptr; static std::map* __factories = nullptr; diff --git a/src/grit/Figure.h b/src/grit/Figure.h index 9c3543595..eefe42f0d 100644 --- a/src/grit/Figure.h +++ b/src/grit/Figure.h @@ -32,9 +32,7 @@ class Figure { // -- Constructors - explicit Figure(double R); - explicit Figure(double a, double b); - + Figure() = default; Figure(const Figure&) = default; Figure(Figure&&) = default; @@ -53,10 +51,10 @@ class Figure { // -- Methods - bool sphere() const { return R_ == R_; } - double a() const { return a_; } - double b() const { return b_; } - double R() const; + virtual bool sphere() const = 0; + virtual double a() const = 0; + virtual double b() const = 0; + virtual double R() const = 0; /// Great-circle central angle between two points (latitude/longitude coordinates) in radians virtual double angle(const PointLatLon&, const PointLatLon&) const = 0; @@ -106,10 +104,7 @@ class Figure { private: // -- Members - - double a_; - double b_; - double R_; + // None // -- Methods // None diff --git a/src/grit/figure/Sphere.cc b/src/grit/figure/Sphere.cc new file mode 100644 index 000000000..796a3e4a4 --- /dev/null +++ b/src/grit/figure/Sphere.cc @@ -0,0 +1,61 @@ +/* + * (C) Copyright 1996- 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 "grit/figure/Sphere.h" + +#include "grit/exception.h" + + +namespace grit::figure { + + +Sphere::Sphere(double R) : R_(R) { + ASSERT(0. < R); +} + + +double Sphere::angle(const PointLatLon& A, const PointLatLon& B) const { + NOTIMP; +} + + +double Sphere::angle(const PointXYZ& A, const PointXYZ& B) const { + NOTIMP; +} + + +double Sphere::distance(const PointLatLon& A, const PointLatLon& B) const { + NOTIMP; +} + + +double Sphere::distance(const PointXYZ& A, const PointXYZ& B) const { + NOTIMP; +} + + +double Sphere::area() const { + NOTIMP; +} + + +PointXYZ Sphere::ll_to_xyz(const PointLatLon& P, double height) const { + NOTIMP; +} + + +PointLatLon Sphere::xyz_to_ll(const PointXYZ& P) const { + NOTIMP; +} + + +} // namespace grit::figure diff --git a/src/grit/figure/Sphere.h b/src/grit/figure/Sphere.h new file mode 100644 index 000000000..49bad24e3 --- /dev/null +++ b/src/grit/figure/Sphere.h @@ -0,0 +1,110 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/Figure.h" + + +namespace grit::figure { + + +class Sphere final : public Figure { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit Sphere(double R); + Sphere(const Sphere&) = default; + Sphere(Sphere&&) = default; + + // -- Destructor + + ~Sphere() override = default; + + // -- Convertors + // None + + // -- Operators + + Sphere& operator=(const Sphere&) = default; + Sphere& operator=(Sphere&&) = default; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + bool sphere() const override { return true; } + double a() const override { return R_; } + double b() const override { return R_; } + double R() const override { return R_; } + + double angle(const PointLatLon&, const PointLatLon&) const override; + double angle(const PointXYZ&, const PointXYZ&) const override; + double distance(const PointLatLon&, const PointLatLon&) const override; + double distance(const PointXYZ&, const PointXYZ&) const override; + double area() const override; + + PointXYZ ll_to_xyz(const PointLatLon&, double height) const override; + PointLatLon xyz_to_ll(const PointXYZ&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + double R_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::figure diff --git a/src/grit/figure/Spheroid.cc b/src/grit/figure/Spheroid.cc new file mode 100644 index 000000000..aa8611d0c --- /dev/null +++ b/src/grit/figure/Spheroid.cc @@ -0,0 +1,74 @@ +/* + * (C) Copyright 1996- 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 "grit/figure/Spheroid.h" + +#include "grit/exception.h" +#include "grit/util.h" + + +namespace grit::figure { + + +Spheroid::Spheroid(double a, double b) : a_(a), b_(b) { + ASSERT(0. < a); + ASSERT(0. < b); +} + + +bool Spheroid::sphere() const { + return util::is_approximately_equal(a_, b_); +} + + +double Spheroid::R() const { + ASSERT_MSG("Spheroid::R", sphere()); + return a_; +} + + +double Spheroid::angle(const PointLatLon& A, const PointLatLon& B) const { + NOTIMP; +} + + +double Spheroid::angle(const PointXYZ& A, const PointXYZ& B) const { + NOTIMP; +} + + +double Spheroid::distance(const PointLatLon& A, const PointLatLon& B) const { + NOTIMP; +} + + +double Spheroid::distance(const PointXYZ& A, const PointXYZ& B) const { + NOTIMP; +} + + +double Spheroid::area() const { + NOTIMP; +} + + +PointXYZ Spheroid::ll_to_xyz(const PointLatLon& P, double height) const { + NOTIMP; +} + + +PointLatLon Spheroid::xyz_to_ll(const PointXYZ& P) const { + NOTIMP; +} + + +} // namespace grit::figure diff --git a/src/grit/figure/Spheroid.h b/src/grit/figure/Spheroid.h new file mode 100644 index 000000000..81e103349 --- /dev/null +++ b/src/grit/figure/Spheroid.h @@ -0,0 +1,111 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/Figure.h" + + +namespace grit::figure { + + +class Spheroid final : public Figure { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + Spheroid(double a, double b); + Spheroid(const Spheroid&) = default; + Spheroid(Spheroid&&) = default; + + // -- Destructor + + ~Spheroid() override = default; + + // -- Convertors + // None + + // -- Operators + + Spheroid& operator=(const Spheroid&) = default; + Spheroid& operator=(Spheroid&&) = default; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + bool sphere() const override; + double a() const override { return a_; } + double b() const override { return b_; } + double R() const override; + + double angle(const PointLatLon&, const PointLatLon&) const override; + double angle(const PointXYZ&, const PointXYZ&) const override; + double distance(const PointLatLon&, const PointLatLon&) const override; + double distance(const PointXYZ&, const PointXYZ&) const override; + double area() const override; + + PointXYZ ll_to_xyz(const PointLatLon&, double height) const override; + PointLatLon xyz_to_ll(const PointXYZ&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + double a_; + double b_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::figure From 87fad7dfa45f891506bf1897af9ad1a4c89f548b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 24 Apr 2023 16:47:13 +0100 Subject: [PATCH 161/737] figure --- src/grit/Figure.h | 2 +- src/grit/figure/Sphere.cc | 17 +++++++++-------- src/grit/figure/Sphere.h | 2 +- src/grit/figure/Spheroid.cc | 17 +++++++++-------- src/grit/figure/Spheroid.h | 2 +- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/grit/Figure.h b/src/grit/Figure.h index eefe42f0d..8623aa53e 100644 --- a/src/grit/Figure.h +++ b/src/grit/Figure.h @@ -72,7 +72,7 @@ class Figure { virtual double area() const = 0; // Convert spherical coordinates to Cartesian - virtual PointXYZ ll_to_xyz(const PointLatLon&, double height) const = 0; + virtual PointXYZ ll_to_xyz(const PointLatLon&) const = 0; // Convert Cartesian coordinates to spherical virtual PointLatLon xyz_to_ll(const PointXYZ&) const = 0; diff --git a/src/grit/figure/Sphere.cc b/src/grit/figure/Sphere.cc index 796a3e4a4..d84a84f96 100644 --- a/src/grit/figure/Sphere.cc +++ b/src/grit/figure/Sphere.cc @@ -13,6 +13,7 @@ #include "grit/figure/Sphere.h" #include "grit/exception.h" +#include "grit/geometry/Sphere.h" namespace grit::figure { @@ -24,37 +25,37 @@ Sphere::Sphere(double R) : R_(R) { double Sphere::angle(const PointLatLon& A, const PointLatLon& B) const { - NOTIMP; + return geometry::Sphere::angle(A, B); } double Sphere::angle(const PointXYZ& A, const PointXYZ& B) const { - NOTIMP; + return geometry::Sphere::angle(R_, A, B); } double Sphere::distance(const PointLatLon& A, const PointLatLon& B) const { - NOTIMP; + return geometry::Sphere::distance(R_, A, B); } double Sphere::distance(const PointXYZ& A, const PointXYZ& B) const { - NOTIMP; + return geometry::Sphere::distance(R_, A, B); } double Sphere::area() const { - NOTIMP; + return geometry::Sphere::area(R_); } -PointXYZ Sphere::ll_to_xyz(const PointLatLon& P, double height) const { - NOTIMP; +PointXYZ Sphere::ll_to_xyz(const PointLatLon& P) const { + return geometry::Sphere::ll_to_xyz(R_, P, 0.); } PointLatLon Sphere::xyz_to_ll(const PointXYZ& P) const { - NOTIMP; + return geometry::Sphere::xyz_to_ll(R_, P); } diff --git a/src/grit/figure/Sphere.h b/src/grit/figure/Sphere.h index 49bad24e3..7620091cd 100644 --- a/src/grit/figure/Sphere.h +++ b/src/grit/figure/Sphere.h @@ -76,7 +76,7 @@ class Sphere final : public Figure { double distance(const PointXYZ&, const PointXYZ&) const override; double area() const override; - PointXYZ ll_to_xyz(const PointLatLon&, double height) const override; + PointXYZ ll_to_xyz(const PointLatLon&) const override; PointLatLon xyz_to_ll(const PointXYZ&) const override; // -- Class members diff --git a/src/grit/figure/Spheroid.cc b/src/grit/figure/Spheroid.cc index aa8611d0c..65cde0796 100644 --- a/src/grit/figure/Spheroid.cc +++ b/src/grit/figure/Spheroid.cc @@ -13,6 +13,7 @@ #include "grit/figure/Spheroid.h" #include "grit/exception.h" +#include "grit/geometry/Spheroid.h" #include "grit/util.h" @@ -37,37 +38,37 @@ double Spheroid::R() const { double Spheroid::angle(const PointLatLon& A, const PointLatLon& B) const { - NOTIMP; + return geometry::Spheroid::angle(A, B); } double Spheroid::angle(const PointXYZ& A, const PointXYZ& B) const { - NOTIMP; + return geometry::Spheroid::angle(a_, b_, A, B); } double Spheroid::distance(const PointLatLon& A, const PointLatLon& B) const { - NOTIMP; + return geometry::Spheroid::distance(a_, b_, A, B); } double Spheroid::distance(const PointXYZ& A, const PointXYZ& B) const { - NOTIMP; + return geometry::Spheroid::distance(a_, b_, A, B); } double Spheroid::area() const { - NOTIMP; + return geometry::Spheroid::area(a_, b_); } -PointXYZ Spheroid::ll_to_xyz(const PointLatLon& P, double height) const { - NOTIMP; +PointXYZ Spheroid::ll_to_xyz(const PointLatLon& P) const { + return geometry::Spheroid::ll_to_xyz(a_, b_, P, 0.); } PointLatLon Spheroid::xyz_to_ll(const PointXYZ& P) const { - NOTIMP; + return geometry::Spheroid::xyz_to_ll(a_, b_, P); } diff --git a/src/grit/figure/Spheroid.h b/src/grit/figure/Spheroid.h index 81e103349..b9cd136d3 100644 --- a/src/grit/figure/Spheroid.h +++ b/src/grit/figure/Spheroid.h @@ -76,7 +76,7 @@ class Spheroid final : public Figure { double distance(const PointXYZ&, const PointXYZ&) const override; double area() const override; - PointXYZ ll_to_xyz(const PointLatLon&, double height) const override; + PointXYZ ll_to_xyz(const PointLatLon&) const override; PointLatLon xyz_to_ll(const PointXYZ&) const override; // -- Class members From da547b0dd6a12e884a90fb256741a2df343929bf Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 24 Apr 2023 17:16:33 +0100 Subject: [PATCH 162/737] figure --- src/tools/grit-grib.cc | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/tools/grit-grib.cc b/src/tools/grit-grib.cc index d43ab399c..c1a48be85 100644 --- a/src/tools/grit-grib.cc +++ b/src/tools/grit-grib.cc @@ -19,6 +19,8 @@ #include #include "grit/exception.h" +#include "grit/figure/Sphere.h" +#include "grit/figure/Spheroid.h" #include "grit/grit.h" @@ -144,6 +146,51 @@ struct test; static const std::map __builders{}; +namespace GRIB { + + +grit::Figure* make_figure(long code) { + // Code table 3.2 – Shape of the reference system + + switch (code) { + case 0: + return new grit::figure::Sphere(6367470.); + case 1: + // Earth assumed spherical with radius specified (in m) by data producer + NOTIMP; + case 2: + return new grit::figure::Spheroid(6378160., 6356775.); + case 3: + // Earth assumed oblate spheroid with major and minor axes specified (in km) by data producer + NOTIMP; + case 4: + return new grit::figure::Spheroid(6378137., 6356752.314); + case 5: + return new grit::figure::Spheroid(6378137., 6356752.314140347); + case 6: + return new grit::figure::Sphere(6371229.); + case 7: + // Earth assumed oblate spheroid with major or minor axes specified (in m) by data producer + NOTIMP; + case 8: + return new grit::figure::Sphere(6371200.); + case 9: + return new grit::figure::Spheroid(6377563.396, 6356256.909); + case 10: + // Earth model assumed WGS84 with corrected geomagnetic coordinates (latitude and longitude) defined by + // Gustafsson et al., 1992 + NOTIMP; + case 11: + return new grit::figure::Sphere(695990000.); + default: + NOTIMP; + } +} + + +} // namespace GRIB + + int main(int argc, const char* argv[]) { From 11340bee84189f17000b84a96813effd530d8c61 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 25 Apr 2023 09:51:59 +0100 Subject: [PATCH 163/737] figure --- src/grit/CMakeLists.txt | 6 -- src/grit/Figure.cc | 84 ------------------- src/grit/Figure.h | 157 ------------------------------------ src/grit/Iterator.cc | 5 +- src/grit/Iterator.h | 4 +- src/grit/figure/Sphere.cc | 62 -------------- src/grit/figure/Sphere.h | 110 ------------------------- src/grit/figure/Spheroid.cc | 75 ----------------- src/grit/figure/Spheroid.h | 111 ------------------------- 9 files changed, 2 insertions(+), 612 deletions(-) delete mode 100644 src/grit/Figure.cc delete mode 100644 src/grit/Figure.h delete mode 100644 src/grit/figure/Sphere.cc delete mode 100644 src/grit/figure/Sphere.h delete mode 100644 src/grit/figure/Spheroid.cc delete mode 100644 src/grit/figure/Spheroid.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index e4360b074..cc58358e4 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -1,8 +1,6 @@ configure_file(grit.h.in grit.h) add_library(grit SHARED - Figure.cc - Figure.h Iterator.cc Iterator.h Projection.cc @@ -10,10 +8,6 @@ add_library(grit SHARED Scanner.cc Scanner.h exception.h - figure/Sphere.cc - figure/Sphere.h - figure/Spheroid.cc - figure/Spheroid.h geometry/BoundingBox.cc geometry/BoundingBox.h geometry/GreatCircle.cc diff --git a/src/grit/Figure.cc b/src/grit/Figure.cc deleted file mode 100644 index baae123e4..000000000 --- a/src/grit/Figure.cc +++ /dev/null @@ -1,84 +0,0 @@ -/* - * (C) Copyright 1996- 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 "grit/Figure.h" - -#include -#include -#include - -#include "grit/exception.h" -#include "grit/log.h" -#include "grit/util/Mutex.h" - - -namespace grit { - - -static util::once_flag __once; -static util::recursive_mutex* __mutex = nullptr; -static std::map* __factories = nullptr; - - -static void __init() { - __mutex = new util::recursive_mutex(); - __factories = new std::map(); -} - - -FigureFactory::FigureFactory(const FigureFactory::key_type& key) : key_(key) { - util::call_once(__once, __init); - util::lock_guard lock(*__mutex); - - if (auto f = __factories->find(key); f != __factories->end()) { - throw exception::runtime_error("FigureFactory: duplicate '" + key + "'"); - } - - (*__factories)[key] = this; -} - - -FigureFactory::~FigureFactory() { - util::lock_guard lock(*__mutex); - - if (__factories != nullptr) { - __factories->erase(key_); - } -} - - -Figure* FigureFactory::build(const FigureFactory::key_type& key) { - util::call_once(__once, __init); - util::lock_guard lock(*__mutex); - - if (auto f = __factories->find(key); f != __factories->end()) { - return f->second->make(); - } - - list(error << "FigureFactory: unknown '" << key << "', choices are: "); - throw exception::runtime_error("FigureFactory: unknown '" + key + "'"); -} - - -void FigureFactory::list(std::ostream& out) { - util::call_once(__once, __init); - util::lock_guard lock(*__mutex); - - const char* sep = ""; - for (const auto& j : *__factories) { - out << sep << j.first; - sep = ", "; - } -} - - -} // namespace grit diff --git a/src/grit/Figure.h b/src/grit/Figure.h deleted file mode 100644 index 8623aa53e..000000000 --- a/src/grit/Figure.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include - - -#include "grit/types.h" - - -namespace grit { - - -class Figure { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - Figure() = default; - Figure(const Figure&) = default; - Figure(Figure&&) = default; - - // -- Destructor - - virtual ~Figure() = default; - - // -- Convertors - // None - - // -- Operators - // None - - Figure& operator=(const Figure&) = default; - Figure& operator=(Figure&&) = default; - - // -- Methods - - virtual bool sphere() const = 0; - virtual double a() const = 0; - virtual double b() const = 0; - virtual double R() const = 0; - - /// Great-circle central angle between two points (latitude/longitude coordinates) in radians - virtual double angle(const PointLatLon&, const PointLatLon&) const = 0; - - /// Great-circle central angle between two points (Cartesian coordinates) in radians - virtual double angle(const PointXYZ&, const PointXYZ&) const = 0; - - /// Great-circle distance between two points (latitude/longitude coordinates) in metres - virtual double distance(const PointLatLon&, const PointLatLon&) const = 0; - - /// Great-circle distance between two points (Cartesian coordinates) in metres - virtual double distance(const PointXYZ&, const PointXYZ&) const = 0; - - /// Surface area in square metres - virtual double area() const = 0; - - // Convert spherical coordinates to Cartesian - virtual PointXYZ ll_to_xyz(const PointLatLon&) const = 0; - - // Convert Cartesian coordinates to spherical - virtual PointLatLon xyz_to_ll(const PointXYZ&) const = 0; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -struct FigureFactory { - using key_type = std::string; - - Figure* build(const key_type&); - static void list(std::ostream&); - - FigureFactory(const FigureFactory&) = delete; - FigureFactory(FigureFactory&&) = delete; - FigureFactory& operator=(const FigureFactory&) = delete; - FigureFactory& operator=(FigureFactory&&) = delete; - - virtual Figure* make() = 0; - -protected: - explicit FigureFactory(const key_type&); - virtual ~FigureFactory(); - -private: - const key_type key_; -}; - - -template -class FigureBuilder final : public FigureFactory { - Figure* make() override { return new T; } - -public: - explicit FigureBuilder(const FigureFactory::key_type& key) : FigureFactory(key) {} -}; - - -} // namespace grit diff --git a/src/grit/Iterator.cc b/src/grit/Iterator.cc index 42d03c82b..7fa59b0fa 100644 --- a/src/grit/Iterator.cc +++ b/src/grit/Iterator.cc @@ -12,7 +12,6 @@ #include "grit/Iterator.h" -#include "grit/Figure.h" #include "grit/Projection.h" #include "grit/Scanner.h" #include "grit/exception.h" @@ -21,10 +20,8 @@ namespace grit { -Iterator::Iterator(Scanner* scanner, Figure* figure, Projection* projection) : - scanner_(scanner), figure_(figure), projection_(projection) { +Iterator::Iterator(Scanner* scanner, Projection* projection) : scanner_(scanner), projection_(projection) { ASSERT(scanner_); - ASSERT(figure_); ASSERT(projection_); } diff --git a/src/grit/Iterator.h b/src/grit/Iterator.h index c05cd00a2..471cc9aed 100644 --- a/src/grit/Iterator.h +++ b/src/grit/Iterator.h @@ -16,7 +16,6 @@ namespace grit { -struct Figure; struct Projection; struct Scanner; } // namespace grit @@ -68,7 +67,7 @@ class Iterator final { // -- Constructors - Iterator(Scanner*, Figure*, Projection*); + Iterator(Scanner*, Projection*); Iterator(const Iterator&) = delete; Iterator(Iterator&&) = delete; @@ -114,7 +113,6 @@ class Iterator final { // -- Members std::unique_ptr scanner_; - std::unique_ptr
figure_; std::unique_ptr projection_; // -- Methods diff --git a/src/grit/figure/Sphere.cc b/src/grit/figure/Sphere.cc deleted file mode 100644 index d84a84f96..000000000 --- a/src/grit/figure/Sphere.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* - * (C) Copyright 1996- 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 "grit/figure/Sphere.h" - -#include "grit/exception.h" -#include "grit/geometry/Sphere.h" - - -namespace grit::figure { - - -Sphere::Sphere(double R) : R_(R) { - ASSERT(0. < R); -} - - -double Sphere::angle(const PointLatLon& A, const PointLatLon& B) const { - return geometry::Sphere::angle(A, B); -} - - -double Sphere::angle(const PointXYZ& A, const PointXYZ& B) const { - return geometry::Sphere::angle(R_, A, B); -} - - -double Sphere::distance(const PointLatLon& A, const PointLatLon& B) const { - return geometry::Sphere::distance(R_, A, B); -} - - -double Sphere::distance(const PointXYZ& A, const PointXYZ& B) const { - return geometry::Sphere::distance(R_, A, B); -} - - -double Sphere::area() const { - return geometry::Sphere::area(R_); -} - - -PointXYZ Sphere::ll_to_xyz(const PointLatLon& P) const { - return geometry::Sphere::ll_to_xyz(R_, P, 0.); -} - - -PointLatLon Sphere::xyz_to_ll(const PointXYZ& P) const { - return geometry::Sphere::xyz_to_ll(R_, P); -} - - -} // namespace grit::figure diff --git a/src/grit/figure/Sphere.h b/src/grit/figure/Sphere.h deleted file mode 100644 index 7620091cd..000000000 --- a/src/grit/figure/Sphere.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "grit/Figure.h" - - -namespace grit::figure { - - -class Sphere final : public Figure { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit Sphere(double R); - Sphere(const Sphere&) = default; - Sphere(Sphere&&) = default; - - // -- Destructor - - ~Sphere() override = default; - - // -- Convertors - // None - - // -- Operators - - Sphere& operator=(const Sphere&) = default; - Sphere& operator=(Sphere&&) = default; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - bool sphere() const override { return true; } - double a() const override { return R_; } - double b() const override { return R_; } - double R() const override { return R_; } - - double angle(const PointLatLon&, const PointLatLon&) const override; - double angle(const PointXYZ&, const PointXYZ&) const override; - double distance(const PointLatLon&, const PointLatLon&) const override; - double distance(const PointXYZ&, const PointXYZ&) const override; - double area() const override; - - PointXYZ ll_to_xyz(const PointLatLon&) const override; - PointLatLon xyz_to_ll(const PointXYZ&) const override; - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - double R_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace grit::figure diff --git a/src/grit/figure/Spheroid.cc b/src/grit/figure/Spheroid.cc deleted file mode 100644 index 65cde0796..000000000 --- a/src/grit/figure/Spheroid.cc +++ /dev/null @@ -1,75 +0,0 @@ -/* - * (C) Copyright 1996- 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 "grit/figure/Spheroid.h" - -#include "grit/exception.h" -#include "grit/geometry/Spheroid.h" -#include "grit/util.h" - - -namespace grit::figure { - - -Spheroid::Spheroid(double a, double b) : a_(a), b_(b) { - ASSERT(0. < a); - ASSERT(0. < b); -} - - -bool Spheroid::sphere() const { - return util::is_approximately_equal(a_, b_); -} - - -double Spheroid::R() const { - ASSERT_MSG("Spheroid::R", sphere()); - return a_; -} - - -double Spheroid::angle(const PointLatLon& A, const PointLatLon& B) const { - return geometry::Spheroid::angle(A, B); -} - - -double Spheroid::angle(const PointXYZ& A, const PointXYZ& B) const { - return geometry::Spheroid::angle(a_, b_, A, B); -} - - -double Spheroid::distance(const PointLatLon& A, const PointLatLon& B) const { - return geometry::Spheroid::distance(a_, b_, A, B); -} - - -double Spheroid::distance(const PointXYZ& A, const PointXYZ& B) const { - return geometry::Spheroid::distance(a_, b_, A, B); -} - - -double Spheroid::area() const { - return geometry::Spheroid::area(a_, b_); -} - - -PointXYZ Spheroid::ll_to_xyz(const PointLatLon& P) const { - return geometry::Spheroid::ll_to_xyz(a_, b_, P, 0.); -} - - -PointLatLon Spheroid::xyz_to_ll(const PointXYZ& P) const { - return geometry::Spheroid::xyz_to_ll(a_, b_, P); -} - - -} // namespace grit::figure diff --git a/src/grit/figure/Spheroid.h b/src/grit/figure/Spheroid.h deleted file mode 100644 index b9cd136d3..000000000 --- a/src/grit/figure/Spheroid.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "grit/Figure.h" - - -namespace grit::figure { - - -class Spheroid final : public Figure { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - Spheroid(double a, double b); - Spheroid(const Spheroid&) = default; - Spheroid(Spheroid&&) = default; - - // -- Destructor - - ~Spheroid() override = default; - - // -- Convertors - // None - - // -- Operators - - Spheroid& operator=(const Spheroid&) = default; - Spheroid& operator=(Spheroid&&) = default; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - bool sphere() const override; - double a() const override { return a_; } - double b() const override { return b_; } - double R() const override; - - double angle(const PointLatLon&, const PointLatLon&) const override; - double angle(const PointXYZ&, const PointXYZ&) const override; - double distance(const PointLatLon&, const PointLatLon&) const override; - double distance(const PointXYZ&, const PointXYZ&) const override; - double area() const override; - - PointXYZ ll_to_xyz(const PointLatLon&) const override; - PointLatLon xyz_to_ll(const PointXYZ&) const override; - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - double a_; - double b_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace grit::figure From c8e307f8001b77d9043f25fc5ffdca4970b26ada Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 25 Apr 2023 09:57:31 +0100 Subject: [PATCH 164/737] projection --- src/grit/Projection.cc | 64 +++++++++++++++++++++++++++++++++++++++++- src/grit/Projection.h | 34 ++++++++++++++++++++++ src/tools/grit-grib.cc | 4 +-- 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/src/grit/Projection.cc b/src/grit/Projection.cc index 79ac43dd8..efc1a4048 100644 --- a/src/grit/Projection.cc +++ b/src/grit/Projection.cc @@ -12,7 +12,12 @@ #include "grit/Projection.h" -// #include <> +#include +#include + +#include "grit/exception.h" +#include "grit/log.h" +#include "grit/util/Mutex.h" namespace grit { @@ -213,4 +218,61 @@ Projection centre (grib2/tables/30/3.5.table) #endif +static util::once_flag __once; +static util::recursive_mutex* __mutex = nullptr; +static std::map* __factories = nullptr; + + +static void __init() { + __mutex = new util::recursive_mutex(); + __factories = new std::map(); +} + + +Projection* ProjectionFactory::build(const ProjectionFactory::key_type& key) { + util::call_once(__once, __init); + util::lock_guard lock(*__mutex); + + if (auto f = __factories->find(key); f != __factories->end()) { + return f->second->make(); + } + + list(error << "ProjectionFactory: unknown '" << key << "', choices are: "); + throw exception::runtime_error("ProjectionFactory: unknown '" + key + "'"); +} + + +void ProjectionFactory::list(std::ostream& out) { + util::call_once(__once, __init); + util::lock_guard lock(*__mutex); + + const char* sep = ""; + for (const auto& j : *__factories) { + out << sep << j.first; + sep = ", "; + } +} + + +ProjectionFactory::ProjectionFactory(const ProjectionFactory::key_type& key) : key_(key) { + util::call_once(__once, __init); + util::lock_guard lock(*__mutex); + + if (auto f = __factories->find(key); f != __factories->end()) { + throw exception::runtime_error("ProjectionFactory: duplicate '" + key + "'"); + } + + (*__factories)[key] = this; +} + + +ProjectionFactory::~ProjectionFactory() { + util::lock_guard lock(*__mutex); + + if (__factories != nullptr) { + __factories->erase(key_); + } +} + + } // namespace grit diff --git a/src/grit/Projection.h b/src/grit/Projection.h index ab4b77e68..b7705bd74 100644 --- a/src/grit/Projection.h +++ b/src/grit/Projection.h @@ -12,6 +12,9 @@ #pragma once +#include +#include + #include "grit/types.h" @@ -96,4 +99,35 @@ class Projection { }; +struct ProjectionFactory { + using key_type = std::string; + + Projection* build(const key_type&); + static void list(std::ostream&); + + ProjectionFactory(const ProjectionFactory&) = delete; + ProjectionFactory(ProjectionFactory&&) = delete; + ProjectionFactory& operator=(const ProjectionFactory&) = delete; + ProjectionFactory& operator=(ProjectionFactory&&) = delete; + + virtual Projection* make() = 0; + +protected: + explicit ProjectionFactory(const key_type&); + virtual ~ProjectionFactory(); + +private: + const key_type key_; +}; + + +template +class ProjectionBuilder final : public ProjectionFactory { + Projection* make() override { return new T; } + +public: + explicit ProjectionBuilder(const ProjectionFactory::key_type& key) : ProjectionFactory(key) {} +}; + + } // namespace grit diff --git a/src/tools/grit-grib.cc b/src/tools/grit-grib.cc index c1a48be85..5dbc9fc23 100644 --- a/src/tools/grit-grib.cc +++ b/src/tools/grit-grib.cc @@ -19,8 +19,6 @@ #include #include "grit/exception.h" -#include "grit/figure/Sphere.h" -#include "grit/figure/Spheroid.h" #include "grit/grit.h" @@ -149,6 +147,7 @@ static const std::map __builders{}; namespace GRIB { +#if 0 grit::Figure* make_figure(long code) { // Code table 3.2 – Shape of the reference system @@ -186,6 +185,7 @@ grit::Figure* make_figure(long code) { NOTIMP; } } +#endif } // namespace GRIB From 7415a0095a677fb3aef8ca8a8fd0b56dddfe6f28 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 25 Apr 2023 11:52:51 +0100 Subject: [PATCH 165/737] projection --- src/grit/CMakeLists.txt | 2 + src/grit/projection/LatLonToXYZ.cc | 54 +++++++++++++++++ src/grit/projection/LatLonToXYZ.h | 96 ++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/projection_ll_to_xyz.cc | 47 +++++++++++++++ 5 files changed, 200 insertions(+) create mode 100644 src/grit/projection/LatLonToXYZ.cc create mode 100644 src/grit/projection/LatLonToXYZ.h create mode 100644 tests/projection_ll_to_xyz.cc diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index cc58358e4..427f0875a 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -18,6 +18,8 @@ add_library(grit SHARED geometry/Spheroid.h geometry/UnitSphere.h log.h + projection/LatLonToXYZ.cc + projection/LatLonToXYZ.h projection/Rotation.cc projection/Rotation.h types.cc diff --git a/src/grit/projection/LatLonToXYZ.cc b/src/grit/projection/LatLonToXYZ.cc new file mode 100644 index 000000000..a61200e5c --- /dev/null +++ b/src/grit/projection/LatLonToXYZ.cc @@ -0,0 +1,54 @@ +/* + * (C) Copyright 1996- 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 "grit/projection/LatLonToXYZ.h" + +#include "grit/geometry/Sphere.h" +#include "grit/geometry/Spheroid.h" +#include "grit/util.h" + + +namespace grit::projection { + + +LatLonToXYZ::LatLonToXYZ(double a, double b) { + ASSERT(0. < a); + ASSERT(0. < b); + + struct LatLonToSphereXYZ final : Implementation { + using S = geometry::Sphere; + const double R_; + + explicit LatLonToSphereXYZ(double R) : R_(R) {} + PointXYZ operator()(const PointLatLon& p) const override { return S::ll_to_xyz(R_, p, 0.); } + PointLatLon operator()(const PointXYZ& q) const override { return S::xyz_to_ll(R_, q); } + }; + + struct LatLonToSpheroidXYZ final : Implementation { + using S = geometry::Spheroid; + const double a_; + const double b_; + + explicit LatLonToSpheroidXYZ(double a, double b) : a_(a), b_(b) {} + PointXYZ operator()(const PointLatLon& p) const override { return S::ll_to_xyz(a_, b_, p, 0.); } + PointLatLon operator()(const PointXYZ& q) const override { NOTIMP; } + }; + + impl_.reset(util::is_approximately_equal(a, b) ? static_cast(new LatLonToSphereXYZ(a)) + : new LatLonToSpheroidXYZ(a, b)); +} + + +LatLonToXYZ::LatLonToXYZ(double R) : LatLonToXYZ(R, R) {} + + +} // namespace grit::projection diff --git a/src/grit/projection/LatLonToXYZ.h b/src/grit/projection/LatLonToXYZ.h new file mode 100644 index 000000000..6da19a2cc --- /dev/null +++ b/src/grit/projection/LatLonToXYZ.h @@ -0,0 +1,96 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "grit/Projection.h" + + +namespace grit::projection { + + +/// Compute coordinates of a point on a sphere or spheroid, in [x, y, z] +class LatLonToXYZ final : public Projection { +public: + // -- Exceptions + // None + + // -- Constructors + + LatLonToXYZ(double a, double b); + explicit LatLonToXYZ(double R); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + PointXYZ fwd(const PointLatLon& p) const { return (*impl_)(p); } + PointLatLon inv(const PointXYZ& q) const { return (*impl_)(q); } + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Types + + struct Implementation { + Implementation() = default; + virtual ~Implementation() = default; + + Implementation(const Implementation&) = delete; + Implementation(Implementation&&) = delete; + void operator=(const Implementation&) = delete; + void operator=(Implementation&&) = delete; + + virtual PointXYZ operator()(const PointLatLon&) const = 0; + virtual PointLatLon operator()(const PointXYZ&) const = 0; + }; + + // -- Members + + std::unique_ptr impl_; + + // -- Methods + // None + + // -- Overridden methods + + Point fwd(const Point& p) const override { return (*impl_)(std::get(p)); } + Point inv(const Point& q) const override { return (*impl_)(std::get(q)); } + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::projection diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b95d57c77..b8644b250 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,6 +2,7 @@ include(CTest) foreach(name projection + projection_ll_to_xyz projection_rotation types util) diff --git a/tests/projection_ll_to_xyz.cc b/tests/projection_ll_to_xyz.cc new file mode 100644 index 000000000..fa5ab5f26 --- /dev/null +++ b/tests/projection_ll_to_xyz.cc @@ -0,0 +1,47 @@ +/* + * (C) Copyright 1996- 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 + +#include "grit/exception.h" +#include "grit/projection/LatLonToXYZ.h" + + +int main(int argc, char* argv[]) { + using grit::PointLatLon; + using grit::projection::LatLonToXYZ; + + const PointLatLon p(1., 723.); + + + { + LatLonToXYZ to_xyz(1.); + + auto q = to_xyz.fwd(p); + auto r = to_xyz.inv(q); + std::cout << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; + + ASSERT(p.is_approximately_equal(r, 1e-12)); + } + + + { + LatLonToXYZ to_xyz_ab(3., 2.); // oblate + LatLonToXYZ to_xyz_ba(2., 3.); // problate + + for (const auto& lon : {0., 90., 180., 270.}) { + PointLatLon p{0., lon}; + std::cout << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) + << ", p_ba(x,y,z): " << to_xyz_ba.fwd(p) << std::endl; + } + } +} From 221ce70a700d7e14d6b6107aa35f64ba45d69c80 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 25 Apr 2023 16:27:55 +0100 Subject: [PATCH 166/737] param --- src/grit/CMakeLists.txt | 3 + src/grit/Parametrisation.h | 117 +++++++++++++++++++++ src/grit/param/Map.cc | 203 +++++++++++++++++++++++++++++++++++++ src/grit/param/Map.h | 121 ++++++++++++++++++++++ tests/CMakeLists.txt | 1 + tests/param.cc | 39 +++++++ 6 files changed, 484 insertions(+) create mode 100644 src/grit/Parametrisation.h create mode 100644 src/grit/param/Map.cc create mode 100644 src/grit/param/Map.h create mode 100644 tests/param.cc diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 427f0875a..09ed2808a 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -1,6 +1,7 @@ configure_file(grit.h.in grit.h) add_library(grit SHARED + Parametrisation.h Iterator.cc Iterator.h Projection.cc @@ -18,6 +19,8 @@ add_library(grit SHARED geometry/Spheroid.h geometry/UnitSphere.h log.h + param/Map.cc + param/Map.h projection/LatLonToXYZ.cc projection/LatLonToXYZ.h projection/Rotation.cc diff --git a/src/grit/Parametrisation.h b/src/grit/Parametrisation.h new file mode 100644 index 000000000..4d5ce53a7 --- /dev/null +++ b/src/grit/Parametrisation.h @@ -0,0 +1,117 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + + +namespace grit { + + +class Parametrisation { +public: + // -- Types + + using key_type = std::string; + + // -- Exceptions + // None + + // -- Constructors + + Parametrisation() = default; + Parametrisation(const Parametrisation&) = delete; + Parametrisation(Parametrisation&&) = delete; + + // -- Destructor + + virtual ~Parametrisation() = default; + + // -- Convertors + // None + + // -- Operators + + Parametrisation& operator=(const Parametrisation&) = delete; + Parametrisation& operator=(Parametrisation&&) = delete; + + // -- Methods + + virtual bool has(const key_type&) const = 0; + + virtual bool get(const key_type&, bool&) const = 0; + virtual bool get(const key_type&, int&) const = 0; + virtual bool get(const key_type&, unsigned int&) const = 0; + virtual bool get(const key_type&, long&) const = 0; + virtual bool get(const key_type&, unsigned long&) const = 0; + virtual bool get(const key_type&, float&) const = 0; + virtual bool get(const key_type&, double&) const = 0; + virtual bool get(const key_type&, std::string&) const = 0; + + virtual bool get(const key_type&, std::vector&) const = 0; + virtual bool get(const key_type&, std::vector&) const = 0; + virtual bool get(const key_type&, std::vector&) const = 0; + virtual bool get(const key_type&, std::vector&) const = 0; + virtual bool get(const key_type&, std::vector&) const = 0; + virtual bool get(const key_type&, std::vector&) const = 0; + virtual bool get(const key_type&, std::vector&) const = 0; + virtual bool get(const key_type&, std::vector&) const = 0; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit diff --git a/src/grit/param/Map.cc b/src/grit/param/Map.cc new file mode 100644 index 000000000..21cb127bb --- /dev/null +++ b/src/grit/param/Map.cc @@ -0,0 +1,203 @@ +/* + * (C) Copyright 1996- 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 "grit/param/Map.h" + +#include + +#include "grit/exception.h" + + +namespace grit::param { + + +Map::Map(const container_type& other) : map_(other) {} + + +bool Map::has(const key_type& key) const { + return map_.find(key) != map_.end(); +} + + +template +bool __get(const Map::container_type& map, std::size_t idx, const Map::key_type& key, T& value) { + if (auto it = map.find(key); it != map.end()) { + ASSERT(it->second.index() == idx); + value = std::get(it->second); + return true; + } + + return false; +} + + +void Map::set(const key_type& key, const bool& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const int& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const unsigned int& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const long& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const unsigned long& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const float& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const double& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const std::string& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const std::vector& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const std::vector& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const std::vector& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const std::vector& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const std::vector& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const std::vector& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const std::vector& value) { + map_[key] = value; +} + + +void Map::set(const key_type& key, const std::vector& value) { + map_[key] = value; +} + + +bool Map::get(const key_type& key, bool& value) const { + return __get(map_, 0, key, value); +} + + +bool Map::get(const key_type& key, int& value) const { + return __get(map_, 1, key, value); +} + + +bool Map::get(const key_type& key, unsigned int& value) const { + return __get(map_, 2, key, value); +} + + +bool Map::get(const key_type& key, long& value) const { + return __get(map_, 3, key, value); +} + + +bool Map::get(const key_type& key, unsigned long& value) const { + return __get(map_, 4, key, value); +} + + +bool Map::get(const key_type& key, float& value) const { + return __get(map_, 5, key, value); +} + + +bool Map::get(const key_type& key, double& value) const { + return __get(map_, 6, key, value); +} + + +bool Map::get(const key_type& key, std::string& value) const { + return __get(map_, 7, key, value); +} + + +bool Map::get(const key_type& key, std::vector& value) const { + return __get>(map_, 8, key, value); +} + + +bool Map::get(const key_type& key, std::vector& value) const { + return __get>(map_, 9, key, value); +} + + +bool Map::get(const key_type& key, std::vector& value) const { + return __get>(map_, 0, key, value); +} + + +bool Map::get(const key_type& key, std::vector& value) const { + return __get>(map_, 11, key, value); +} + + +bool Map::get(const key_type& key, std::vector& value) const { + return __get>(map_, 12, key, value); +} + + +bool Map::get(const key_type& key, std::vector& value) const { + return __get>(map_, 13, key, value); +} + + +bool Map::get(const key_type& key, std::vector& value) const { + return __get>(map_, 14, key, value); +} + + +bool Map::get(const key_type& key, std::vector& value) const { + return __get>(map_, 15, key, value); +} + + +} // namespace grit::param diff --git a/src/grit/param/Map.h b/src/grit/param/Map.h new file mode 100644 index 000000000..cf76f74b7 --- /dev/null +++ b/src/grit/param/Map.h @@ -0,0 +1,121 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + +#include "grit/Parametrisation.h" + + +namespace grit::param { + + +class Map final : public Parametrisation { +public: + // -- Types + + using value_type = + std::variant, + std::vector, std::vector, std::vector, std::vector, + std::vector, std::vector, std::vector>; + + using container_type = std::map; + + // -- Exceptions + // None + + // -- Constructors + + explicit Map(const container_type& = {}); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + void set(const key_type&, const bool&); + void set(const key_type&, const int&); + void set(const key_type&, const unsigned int&); + void set(const key_type&, const long&); + void set(const key_type&, const unsigned long&); + void set(const key_type&, const float&); + void set(const key_type&, const double&); + void set(const key_type&, const std::string&); + + void set(const key_type&, const std::vector&); + void set(const key_type&, const std::vector&); + void set(const key_type&, const std::vector&); + void set(const key_type&, const std::vector&); + void set(const key_type&, const std::vector&); + void set(const key_type&, const std::vector&); + void set(const key_type&, const std::vector&); + void set(const key_type&, const std::vector&); + + // -- Overridden methods + + bool has(const key_type&) const override; + + bool get(const key_type&, bool&) const override; + bool get(const key_type&, int&) const override; + bool get(const key_type&, unsigned int&) const override; + bool get(const key_type&, long&) const override; + bool get(const key_type&, unsigned long&) const override; + bool get(const key_type&, float&) const override; + bool get(const key_type&, double&) const override; + bool get(const key_type&, std::string&) const override; + + bool get(const key_type&, std::vector&) const override; + bool get(const key_type&, std::vector&) const override; + bool get(const key_type&, std::vector&) const override; + bool get(const key_type&, std::vector&) const override; + bool get(const key_type&, std::vector&) const override; + bool get(const key_type&, std::vector&) const override; + bool get(const key_type&, std::vector&) const override; + bool get(const key_type&, std::vector&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + container_type map_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::param diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b8644b250..ddc2322b9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,6 +1,7 @@ include(CTest) foreach(name + param projection projection_ll_to_xyz projection_rotation diff --git a/tests/param.cc b/tests/param.cc new file mode 100644 index 000000000..f4cb03c25 --- /dev/null +++ b/tests/param.cc @@ -0,0 +1,39 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "grit/exception.h" +#include "grit/param/Map.h" + + +int main(int argc, char* argv[]) { + std::unique_ptr param(new grit::param::Map({{"a", -123}, {"b", "B"}, {"c", 123UL}})); + + int a = 0; + ASSERT(param->get("a", a)); + std::cout << "a: '" << a << "'" << std::endl; + + std::string b; + ASSERT(param->get("b", b)); + std::cout << "b: '" << b << "'" << std::endl; + + size_t c = 0; + ASSERT(param->get("c", c)); + std::cout << "c: '" << c << "'" << std::endl; + + int d = 321; + dynamic_cast(param.get())->set("b", d); + ASSERT(param->get("b", d)); + std::cout << "d: '" << d << "'" << std::endl; +} From 1fcd2ca2b2b4bd88cbe3b8d5a1097a1e009ced0c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 25 Apr 2023 21:39:59 +0100 Subject: [PATCH 167/737] grib --- src/tools/grit-grib.cc | 495 ++++++++++++++++++++++++++++------------- tests/reduced_ll.grib1 | Bin 0 -> 3470 bytes tests/regular_gg.grib1 | Bin 0 -> 108 bytes 3 files changed, 343 insertions(+), 152 deletions(-) create mode 100644 tests/reduced_ll.grib1 create mode 100644 tests/regular_gg.grib1 diff --git a/src/tools/grit-grib.cc b/src/tools/grit-grib.cc index 5dbc9fc23..c5b25a5be 100644 --- a/src/tools/grit-grib.cc +++ b/src/tools/grit-grib.cc @@ -12,21 +12,18 @@ #include "eccodes.h" +#include #include #include -#include #include #include +#include +#include "grit/Parametrisation.h" #include "grit/exception.h" #include "grit/grit.h" - - -#if 0 -static const std::map __types{ - {"regular_ll", nullptr} -}; -#endif +#include "grit/param/Map.h" +#include "grit/types.h" #if 0 @@ -45,150 +42,345 @@ static const std::map __types{ #endif -struct grib_type : std::unique_ptr { +#if 0 +grit::Figure* make_figure(long code) { + // Code table 3.2 – Shape of the reference system + + switch (code) { + case 0: + return new grit::figure::Sphere(6367470.); + case 1: + // Earth assumed spherical with radius specified (in m) by data producer + NOTIMP; + case 2: + return new grit::figure::Spheroid(6378160., 6356775.); + case 3: + // Earth assumed oblate spheroid with major and minor axes specified (in km) by data producer + NOTIMP; + case 4: + return new grit::figure::Spheroid(6378137., 6356752.314); + case 5: + return new grit::figure::Spheroid(6378137., 6356752.314140347); + case 6: + return new grit::figure::Sphere(6371229.); + case 7: + // Earth assumed oblate spheroid with major or minor axes specified (in m) by data producer + NOTIMP; + case 8: + return new grit::figure::Sphere(6371200.); + case 9: + return new grit::figure::Spheroid(6377563.396, 6356256.909); + case 10: + // Earth model assumed WGS84 with corrected geomagnetic coordinates (latitude and longitude) defined by + // Gustafsson et al., 1992 + NOTIMP; + case 11: + return new grit::figure::Sphere(695990000.); + default: + NOTIMP; + } +} +#endif + + +class GribParametrisation final : public grit::Parametrisation, + std::unique_ptr { +private: + // -- Types + using t = std::unique_ptr; - bool get_bool(const std::string& key) const { return get_long(key) != 0L; } +public: + // -- Exceptions + // None - double get_double(const std::string& key) const { - if (auto value = cache_double.find(key); value != cache_double.end()) { - return value->second; - } + // -- Constructors - double value = 0; - ASSERT(CODES_SUCCESS == codes_get_double(get(), key.c_str(), &value)); + explicit GribParametrisation(codes_handle* h) : t(h, &codes_handle_delete) { ASSERT(*this); } + + // -- Destructor + // None + + // -- Convertors + // None - cache_double[key] = value; + // -- Operators + // None + + // -- Methods + + template + T get(const key_type& key) const { + auto value = T(); + ASSERT(get(key, value)); return value; } - long get_long(const std::string& key) const { - if (auto value = cache_long.find(key); value != cache_long.end()) { - return value->second; + // -- Overridden methods + + bool has(const key_type& key) const override { return 0 != codes_is_defined(t::get(), key.c_str()); } + + bool get(const key_type& key, bool& value) const override { + if (long another = 0; get(key, another)) { + value = another != 0; + return true; } - long value = 0; - ASSERT(CODES_SUCCESS == codes_get_long(get(), key.c_str(), &value)); + return false; + } - cache_long[key] = value; - return value; + bool get(const key_type& key, int& value) const override { + if (long another = 0; get(key, another)) { + value = static_cast(another); + return true; + } + + return false; + } + + bool get(const key_type& key, unsigned int& value) const override { + if (long another = 0; get(key, another) && 0 <= another) { + value = static_cast(another); + return true; + } + + return false; + } + + bool get(const key_type& key, long& value) const override { + if (cache_.get(key, value)) { + return true; + } + + if (CODES_SUCCESS == codes_get_long(t::get(), key.c_str(), &value)) { + cache_.set(key, value); + return true; + } + + return false; + } + + bool get(const key_type& key, unsigned long& value) const override { + if (long another = 0; get(key, another) && 0 <= another) { + value = static_cast(another); + return true; + } + + return false; + } + + bool get(const key_type& key, float& value) const override { + if (double another = 0; get(key, another)) { + value = static_cast(another); + return true; + } + + return false; } - size_t get_size_t(const std::string& key) const { - auto value = get_long(key); - ASSERT(value >= 0); - return static_cast(value); + bool get(const key_type& key, double& value) const override { + if (cache_.get(key, value)) { + return true; + } + + if (CODES_SUCCESS == codes_get_double(t::get(), key.c_str(), &value)) { + cache_.set(key, value); + return true; + } + + return false; } - std::string get_string(const std::string& key) const { + bool get(const key_type& key, std::string& value) const override { + if (cache_.get(key, value)) { + return true; + } + char mesg[1024]; - auto length = sizeof(mesg); - ASSERT(CODES_SUCCESS == codes_get_string(get(), key.c_str(), mesg, &length)); - const std::string value(mesg); + if (auto length = sizeof(mesg); CODES_SUCCESS == codes_get_string(t::get(), key.c_str(), mesg, &length)) { + value = mesg; + cache_.set(key, value); + return true; + } - cache_string[key] = value; - return value; + return false; } - mutable std::map cache_double; - mutable std::map cache_long; - mutable std::map cache_string; + bool get(const key_type& key, std::vector& value) const override { + if (std::vector another; get(key, another)) { + value.resize(another.size()); + std::transform(another.begin(), another.end(), value.begin(), [](long v) { return v != 0; }); + return true; + } + + return false; + } - explicit grib_type(codes_handle* h) : t(h, &codes_handle_delete) { ASSERT(*this); } + bool get(const key_type& key, std::vector& value) const override { + if (std::vector another; get(key, another)) { + value.resize(another.size()); + std::transform(another.begin(), another.end(), value.begin(), [](long v) { return static_cast(v); }); + return true; + } - std::string type() const { return get_string("gridType"); } + return false; + } + + bool get(const key_type& key, std::vector& value) const override { + if (std::vector another; get(key, another)) { + value.resize(another.size()); + std::transform(another.begin(), another.end(), value.begin(), [](long v) { + ASSERT(0 <= v); + return static_cast(v); + }); + return true; + } + return false; + } + + bool get(const key_type& key, std::vector& value) const override { + if (cache_.get(key, value)) { + return true; + } + + if (size_t size = 0; CODES_SUCCESS == codes_get_size(t::get(), key.c_str(), &size)) { + std::vector another(size); + if (CODES_SUCCESS == codes_get_long_array(t::get(), key.c_str(), another.data(), &size)) { + value.swap(another); + cache_.set(key, value); + return true; + } + } + + return false; + } + + bool get(const key_type& key, std::vector& value) const override { + if (std::vector another; get(key, another)) { + value.resize(another.size()); + std::transform(another.begin(), another.end(), value.begin(), [](long v) { + ASSERT(0 <= v); + return static_cast(v); + }); + return true; + } + + return false; + } + + bool get(const key_type& key, std::vector& value) const override { + if (cache_.get(key, value)) { + return true; + } + + if (size_t size = 0; CODES_SUCCESS == codes_get_size(t::get(), key.c_str(), &size)) { + std::vector another(size); + if (CODES_SUCCESS == codes_get_float_array(t::get(), key.c_str(), another.data(), &size)) { + value.swap(another); + cache_.set(key, value); + return true; + } + } + + return false; + } + + bool get(const key_type& key, std::vector& value) const override { + if (cache_.get(key, value)) { + return true; + } + + if (size_t size = 0; CODES_SUCCESS == codes_get_size(t::get(), key.c_str(), &size)) { + std::vector another(size); + if (CODES_SUCCESS == codes_get_double_array(t::get(), key.c_str(), another.data(), &size)) { + value.swap(another); + cache_.set(key, value); + return true; + } + } + + return false; + } + + bool get(const key_type& key, std::vector& value) const override { NOTIMP; } + + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + mutable grit::param::Map cache_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None + +#if 0 + std::string type() const { return get_string("gridType"); } + size_t Ni() const { return get_size_t("Ni"); } size_t Nj() const { return get_size_t("Nj"); } - + double i_start() const { return get_double("longitudeOfFirstGridPointInDegrees"); } - double i_step() const { return get_double("iDirectionIncrementInDegrees"); } - double i_stop() const { return get_double("longitudeOfLastGridPointInDegrees"); } - + double i_step() const { return get_double("iDirectionIncrementInDegrees"); } + double i_stop() const { return get_double("longitudeOfLastGridPointInDegrees"); } + double j_start() const { return get_double("latitudeOfFirstGridPointInDegrees"); } - double j_step() const { return get_double("jDirectionIncrementInDegrees"); } - double j_stop() const { return get_double("latitudeOfLastGridPointInDegrees"); } - + double j_step() const { return get_double("jDirectionIncrementInDegrees"); } + double j_stop() const { return get_double("latitudeOfLastGridPointInDegrees"); } + struct iterator : std::unique_ptr { using t = std::unique_ptr; - + explicit iterator(codes_handle* h) : t(codes_grib_iterator_new(h, 0, &err), &codes_grib_iterator_delete) { ASSERT(CODES_SUCCESS == err); ASSERT(*this); } - + bool next() { return codes_grib_iterator_next(get(), &lat, &lon, &value) > 0; } - + friend std::ostream& operator<<(std::ostream& out, const iterator& it) { return (out << "- lat=" << it.lat << " lon=" << it.lon << " value=" << it.value); } - + int err = 0; double lat = 0; double lon = 0; double value = 0; }; +#endif }; -void test_grib_iterator(codes_handle* h) { - ASSERT(h != nullptr); - - // long bitmapPresent = 0; - // ASSERT(CODES_SUCCESS == codes_get_long(h, "bitmapPresent", &bitmapPresent)); -} - +template +std::ostream& operator<<(std::ostream& out, const std::vector& vec) { + const auto* s = ""; -struct test; - -static const std::map __builders{}; - - -namespace GRIB { - - -#if 0 -grit::Figure* make_figure(long code) { - // Code table 3.2 – Shape of the reference system - - switch (code) { - case 0: - return new grit::figure::Sphere(6367470.); - case 1: - // Earth assumed spherical with radius specified (in m) by data producer - NOTIMP; - case 2: - return new grit::figure::Spheroid(6378160., 6356775.); - case 3: - // Earth assumed oblate spheroid with major and minor axes specified (in km) by data producer - NOTIMP; - case 4: - return new grit::figure::Spheroid(6378137., 6356752.314); - case 5: - return new grit::figure::Spheroid(6378137., 6356752.314140347); - case 6: - return new grit::figure::Sphere(6371229.); - case 7: - // Earth assumed oblate spheroid with major or minor axes specified (in m) by data producer - NOTIMP; - case 8: - return new grit::figure::Sphere(6371200.); - case 9: - return new grit::figure::Spheroid(6377563.396, 6356256.909); - case 10: - // Earth model assumed WGS84 with corrected geomagnetic coordinates (latitude and longitude) defined by - // Gustafsson et al., 1992 - NOTIMP; - case 11: - return new grit::figure::Sphere(695990000.); - default: - NOTIMP; + out << '{'; + for (const auto& v : vec) { + out << s << v; + s = ", "; } -} -#endif - -} // namespace GRIB + return out << '}'; +} int main(int argc, const char* argv[]) { @@ -200,7 +392,7 @@ int main(int argc, const char* argv[]) { int err = 0; for (codes_handle* h = nullptr; nullptr != (h = codes_handle_new_from_file(nullptr, in, PRODUCT_GRIB, &err));) { - grib_type grib(h); + GribParametrisation grib(h); #if 0 int n = 0; @@ -210,55 +402,54 @@ int main(int argc, const char* argv[]) { std::cout.flush(); #endif - auto type = grib.type(); + std::string type; + ASSERT(grib.get("gridType", type)); std::cout << "type: '" << type << "'" << std::endl; + if (grib.has("pl")) { + std::cout << "pl: '" << grib.get("pl") << "'" << std::endl; + } + if (type == "regular_ll") { - struct regular_ll_args { // also, rotated_ll - size_t n_i; - double i_start; - double i_stop; - double i_step; - size_t n_j; - double j_start; - double j_stop; - double j_step; - }; - - regular_ll_args args{grib.Ni(), grib.i_start(), grib.i_stop(), grib.i_step(), - grib.Nj(), grib.j_start(), grib.j_stop(), grib.j_step()}; - - - // struct regular_gg_args { // also, rotated_gg - // size_t n; - // size_t n_i; - // double i_start; - // double i_stop; - // double j_start; - // double j_stop; - // }; - - - // struct reduced_gg_args { // also, reduced_rotated_gg - // size_t n; - // std::vector n_i; - // double i_start; - // double i_stop; - // double i_step; - // double j_start; - // double j_stop; - // double j_step; - // }; - - - // struct reduced_ll_args { - // std::vector n_i; - // double i_start; - // double i_stop; - // double i_step; - // double j_start; - // double j_stop; - // double j_step; + // struct regular_ll_args { // also, rotated_ll + // size_t n_i; + // double i_start; + // double i_stop; + // double i_step; + // size_t n_j; + // double j_start; + // double j_stop; + // double j_step; + // };`` + // + // struct regular_gg_args { // also, rotated_gg + // size_t n; + // size_t n_i; + // double i_start; + // double i_stop; + // double j_start; + // double j_stop; + // }; + // + // struct reduced_gg_args { // also, reduced_rotated_gg + // size_t n; + // std::vector n_i; + // double i_start; + // double i_stop; + // double i_step; + // double j_start; + // double j_stop; + // double j_step; + // }; + // + // struct reduced_ll_args { + // std::vector n_i; + // double i_start; + // double i_stop; + // double i_step; + // double j_start; + // double j_stop; + // double j_step; }; } diff --git a/tests/reduced_ll.grib1 b/tests/reduced_ll.grib1 new file mode 100644 index 0000000000000000000000000000000000000000..60cfabd08b36e16a3280969f2a93ad4c6bdae596 GIT binary patch literal 3470 zcmbuCe?+BU9>>pfp7WgN{LF0nCK+jyktBD&(k2;K(zY2%k|b@Ck&z_VNZPa`8CTMd zBpKI8GLmE@8OcbJBuTE3E6Hqy^?p5nYxsL5 zvEvRQC1V{&KZgJFl8`_7!VvsK5kh{!pa1a2J-K3B7lOZxf!eoL> zlL(n33uKwBl6A60cF6&Wk{CH77v!4Uk_U%6!bx*7oNOo0DR7FN5~th=I@L~{)9AD~ z?aoW5+v#)qondFx8FSt_(@w;ha~7OsXU*Agwwzt(z==9B=ghfuuAN)wfl?}H8qJ{D zG>;b0Vp>AWX^>Xa7qo#k({}ojcGEuEPlxCT4buraMc>moxCT<#h--OX}y+U2cyXatGXDchnto-?`In z#GP{&++}ywU3WL#9e3Y7a*y3p_uT#N#@#zN!5C94on^5cmd^@VfR(ZeR>^8u9cy6C ztc`WDSFD%4W`pbvd&|bzB%5I$*gRWgpV%7PU|VdL9k3{iu`_nTuGkH`X9X zmbdF2cu_CroqFfqcQ5YUc?nLr;AuRAXY*X1&kK2gm+}f;$*cJb-oTrA8}Hy-l#df5YGM zcl>?-$p7k}_-Fowf91#hJO4pYA%qd>B2zpSx#F295&=;v%0*CAiCR%78bz~c6CI*U zbc;UGF9yXMF)GHygqRXDA|mF*N3kS6i8ZkU=iCN9L4h>JV%Ac^Es z$tN;HX2~3xCktee49HShE`zd4*2p^9Ae&^XY?qz#mF$syvR@9$VL2+pa$HWzY587$ zkn?guF3A4}5il|vNuNKsj`lMFX zXSJa=)wbGI`|40d)v-EJXX;#Csw)*&x9VOcG}T-you<=urq0$mI#=iG0$rp7x2BStL;AHI&_nu-9@SwzrYH2Ip4KxuqG$EIUeJqr zS+D3d{aJ75O}(Xe^qxM@hdQc{bxfb?Z~9zc>MMP%Z}gqM*9k)nGr|~?X3|ZD$udt( zj>$9mroa@LV)LshF=eLQJU2m8Wok^VsWbJa(KMMB(`wpHhk0qbOt>iE9`R{w3W8XR@)j|YhTzpTW=d|qiwRyw#ByEHrsAHY^Qx` zyX-65ZF_95?Xw~K8tJzKcF+#lVf)68*iq!I4cjq0ZYPj;cG6DSX*+|ww-NgRnYD9v z-hMK~9k~ zYoFYR~a3b{@tZsYbQm0Npj?^3z9$vmWzut*w82?6#~VQG&6uu>6ezelD0 z9*oP+r2XOZB<=srAO6dqzb*NDfBzQh=Qk6-eOLb5cV|DJCiQH|r$io~`SJN5&mws$ zkLQy-smC)*o?h}4lc)K3uE`Tlo^<+)3SN z@@6+vx4ea-b}1sC3f4^!a81b7h! zH%7saVQ^#sJPCm-J>W|hIMV^%w1PWL;7>g`R0|$eflJT9r!sKrSMaI`+{y>Pa=@`H z@GKqUV!$_Ms7`=)ci`SN_;(2oegh9<;9?YfJOC$mz{^c=^E3Fl0*)?%r}N-y1bm$a zXD7hhFu3~${2c&?L*Q{YxZDXow}I15;B_6iT@8K*!SOQiJOHj2fbY5Bd^UKW4(==P zpQ;49;1->5g>E=UN1UK5qUel$bjLP2WCLBYicVQVx6GqsBIueabj}#MX9OKIh%O4D zle*DO9q6bQbX5a7s}|iAM2D53%L3@MXXv&ZbX+F7&Y<&{BJv&`7)KXgq7zTijbG7` z`{>GTbmls`a|Io`fG+)jPMt=#j-z8o(Y1r<+&*;gD|B!>y0{6QT!(J1LPwXQs{`ol z0(5r{Iy?hiuF&a3JfPp>==lru{Rw(MivHh&2W-Lz*5Cz8@Pj#c!VG+20^TqRe;9;E z^uZ^(;1zA~i$-`xEqo&g?{sUYk4rjT5yPUvbj^HvoaGDLc z%?cc60j?8)^Gw2h!f>D=xKIdA^a^g&21jayE7ii8p2M9=;82BdsT?>}2HZ;cj3?k) zaX8ln+$#nLJA{jE!^zg+X3KE2dAQmPoNWT`HUftmfXns3={n$c&2YRIaJ@=6Un$(L z5Du6N7t8=)1*cvDju?k4p2HbqaK{5U9F<4{+j1xba&! z@*rHf7tY)XcW#D5*TJPL;nbyY>q0no4qQ7O&duBe{5uX0KZlPW!^`*K=bP~KRrvY> zygdSce+Q2rh0hPb>wDn$9q{}n_Soi~#@u literal 0 HcmV?d00001 diff --git a/tests/regular_gg.grib1 b/tests/regular_gg.grib1 new file mode 100644 index 0000000000000000000000000000000000000000..3bca954e594550c452f25f4f726d89d1535f59c5 GIT binary patch literal 108 zcmZ<{@^oTg$YEq)Flk7d{=Z>5kR{3}#lrxkK|mBj!AV9&CKg5m0|P^_hyufZ7KR1} f2gYy Date: Wed, 26 Apr 2023 09:07:33 +0100 Subject: [PATCH 168/737] util --- src/grit/CMakeLists.txt | 1 + src/grit/log.cc | 27 +++++++++++++++++++++++++++ src/grit/log.h | 9 +++++---- 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 src/grit/log.cc diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 09ed2808a..d4d62bf4f 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -18,6 +18,7 @@ add_library(grit SHARED geometry/Spheroid.cc geometry/Spheroid.h geometry/UnitSphere.h + log.cc log.h param/Map.cc param/Map.h diff --git a/src/grit/log.cc b/src/grit/log.cc new file mode 100644 index 000000000..c6dcb5d17 --- /dev/null +++ b/src/grit/log.cc @@ -0,0 +1,27 @@ +/* + * (C) Copyright 1996- 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 + +#include "grit/log.h" + + +namespace grit { + + +std::ostream& error = std::cerr; +std::ostream& warn = std::cout; +std::ostream& info = std::clog; +std::ostream& log = std::clog; + + +} // namespace grit diff --git a/src/grit/log.h b/src/grit/log.h index ab3a399c7..1c2060471 100644 --- a/src/grit/log.h +++ b/src/grit/log.h @@ -12,15 +12,16 @@ #pragma once -#include +#include namespace grit { -auto& error = std::cerr; -auto& warn = std::cout; -auto& info = std::clog; +extern std::ostream& error; +extern std::ostream& warn; +extern std::ostream& info; +extern std::ostream& log; } // namespace grit From 5927b749569d189902355356fed36a9ccb0c464d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 26 Apr 2023 09:07:44 +0100 Subject: [PATCH 169/737] util --- src/grit/types/PointXY.h | 4 ++++ src/grit/types/PointXYZ.h | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/grit/types/PointXY.h b/src/grit/types/PointXY.h index f8fe1ec30..b268acffa 100644 --- a/src/grit/types/PointXY.h +++ b/src/grit/types/PointXY.h @@ -58,6 +58,10 @@ class PointXY final : protected std::array { return *this; } + bool is_approximately_equal(const PointXY& other, T eps) const { + return std::abs(x - other.x) < eps && std::abs(y - other.y) < eps; + }; + // -- Members T& x = P::operator[](0); diff --git a/src/grit/types/PointXYZ.h b/src/grit/types/PointXYZ.h index 815e42b10..e1191df77 100644 --- a/src/grit/types/PointXYZ.h +++ b/src/grit/types/PointXYZ.h @@ -58,6 +58,9 @@ class PointXYZ final : protected std::array { return *this; } + bool is_approximately_equal(const PointXYZ& other, T eps) const { + return std::abs(x - other.x) < eps && std::abs(y - other.y) < eps && std::abs(z - other.z) < eps; + }; // -- Members From 803418a4d807ad0841649e845ea2a5af71884365 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 26 Apr 2023 09:08:30 +0100 Subject: [PATCH 170/737] scanner --- src/grit/Scanner.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/grit/Scanner.h b/src/grit/Scanner.h index e7290a0e6..500bc4dbd 100644 --- a/src/grit/Scanner.h +++ b/src/grit/Scanner.h @@ -26,14 +26,9 @@ class Scanner { // -- Constructors - Scanner() = default; - Scanner(const Scanner&) = delete; Scanner(Scanner&&) = delete; - Scanner& operator=(const Scanner&) = delete; - Scanner& operator=(Scanner&&) = delete; - // -- Destructor virtual ~Scanner() = default; @@ -43,6 +38,9 @@ class Scanner { // -- Operators + Scanner& operator=(const Scanner&) = delete; + Scanner& operator=(Scanner&&) = delete; + virtual bool operator++() = 0; // -- Methods From 11d501436284ad07f8abad958e404b29770bab5b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 26 Apr 2023 09:08:10 +0100 Subject: [PATCH 171/737] projection --- src/grit/Projection.cc | 4 ++-- src/grit/Projection.h | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/grit/Projection.cc b/src/grit/Projection.cc index efc1a4048..901504da4 100644 --- a/src/grit/Projection.cc +++ b/src/grit/Projection.cc @@ -229,12 +229,12 @@ static void __init() { } -Projection* ProjectionFactory::build(const ProjectionFactory::key_type& key) { +Projection* ProjectionFactory::build(const ProjectionFactory::key_type& key, const Parametrisation& param) { util::call_once(__once, __init); util::lock_guard lock(*__mutex); if (auto f = __factories->find(key); f != __factories->end()) { - return f->second->make(); + return f->second->make(param); } list(error << "ProjectionFactory: unknown '" << key << "', choices are: "); diff --git a/src/grit/Projection.h b/src/grit/Projection.h index b7705bd74..e517f7e5d 100644 --- a/src/grit/Projection.h +++ b/src/grit/Projection.h @@ -18,6 +18,11 @@ #include "grit/types.h" +namespace grit { +class Parametrisation; +} + + namespace grit { @@ -102,7 +107,7 @@ class Projection { struct ProjectionFactory { using key_type = std::string; - Projection* build(const key_type&); + Projection* build(const key_type&, const Parametrisation&); static void list(std::ostream&); ProjectionFactory(const ProjectionFactory&) = delete; @@ -110,7 +115,7 @@ struct ProjectionFactory { ProjectionFactory& operator=(const ProjectionFactory&) = delete; ProjectionFactory& operator=(ProjectionFactory&&) = delete; - virtual Projection* make() = 0; + virtual Projection* make(const Parametrisation&) = 0; protected: explicit ProjectionFactory(const key_type&); @@ -123,7 +128,7 @@ struct ProjectionFactory { template class ProjectionBuilder final : public ProjectionFactory { - Projection* make() override { return new T; } + Projection* make(const Parametrisation& param) override { return new T(param); } public: explicit ProjectionBuilder(const ProjectionFactory::key_type& key) : ProjectionFactory(key) {} From 2bd386c6c5230a69fbe59beabbc88f8b36d7a40f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 26 Apr 2023 09:32:01 +0100 Subject: [PATCH 172/737] projection --- src/grit/CMakeLists.txt | 1 + src/grit/Parametrisation.cc | 115 ++++++++++++++++++++++++++++++++++++ src/grit/Parametrisation.h | 20 +++++++ 3 files changed, 136 insertions(+) create mode 100644 src/grit/Parametrisation.cc diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index d4d62bf4f..2f610f937 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -1,6 +1,7 @@ configure_file(grit.h.in grit.h) add_library(grit SHARED + Parametrisation.cc Parametrisation.h Iterator.cc Iterator.h diff --git a/src/grit/Parametrisation.cc b/src/grit/Parametrisation.cc new file mode 100644 index 000000000..e3cb5d510 --- /dev/null +++ b/src/grit/Parametrisation.cc @@ -0,0 +1,115 @@ +/* + * (C) Copyright 1996- 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 "grit/Parametrisation.h" + +#include "grit/exception.h" + + +namespace grit { + + +namespace { + + +template +T __get(const Parametrisation& param, const Parametrisation::key_type& key) { + auto value = T(); + ASSERT(param.get(key, value)); + return value; +} + + +} // namespace + + +bool Parametrisation::get_bool(const Parametrisation::key_type& key) const { + return __get(*this, key); +} + + +int Parametrisation::get_int(const Parametrisation::key_type& key) const { + return __get(*this, key); +} + + +unsigned int Parametrisation::get_unsigned_int(const Parametrisation::key_type& key) const { + return __get(*this, key); +} + + +long Parametrisation::get_long(const Parametrisation::key_type& key) const { + return __get(*this, key); +} + + +unsigned long Parametrisation::get_unsigned_long(const Parametrisation::key_type& key) const { + return __get(*this, key); +} + + +float Parametrisation::get_float(const Parametrisation::key_type& key) const { + return __get(*this, key); +} + + +double Parametrisation::get_double(const Parametrisation::key_type& key) const { + return __get(*this, key); +} + + +std::string Parametrisation::get_string(const Parametrisation::key_type& key) const { + return __get(*this, key); +} + + +std::vector Parametrisation::get_vector_bool(const Parametrisation::key_type& key) const { + return __get>(*this, key); +} + + +std::vector Parametrisation::get_vector_int(const Parametrisation::key_type& key) const { + return __get>(*this, key); +} + + +std::vector Parametrisation::get_vector_unsigned_int(const Parametrisation::key_type& key) const { + return __get>(*this, key); +} + + +std::vector Parametrisation::get_vector_long(const Parametrisation::key_type& key) const { + return __get>(*this, key); +} + + +std::vector Parametrisation::get_vector_unsigned_long(const Parametrisation::key_type& key) const { + return __get>(*this, key); +} + + +std::vector Parametrisation::get_vector_float(const Parametrisation::key_type& key) const { + return __get>(*this, key); +} + + +std::vector Parametrisation::get_vector_double(const Parametrisation::key_type& key) const { + return __get>(*this, key); +} + + +std::vector Parametrisation::get_vector_string(const Parametrisation::key_type& key) const { + return __get>(*this, key); +} + + +}; // namespace grit diff --git a/src/grit/Parametrisation.h b/src/grit/Parametrisation.h index 4d5ce53a7..3591c7ef8 100644 --- a/src/grit/Parametrisation.h +++ b/src/grit/Parametrisation.h @@ -15,6 +15,8 @@ #include #include +#include "grit/exception.h" + namespace grit { @@ -68,6 +70,24 @@ class Parametrisation { virtual bool get(const key_type&, std::vector&) const = 0; virtual bool get(const key_type&, std::vector&) const = 0; + bool get_bool(const key_type&) const; + int get_int(const key_type&) const; + unsigned int get_unsigned_int(const key_type&) const; + long get_long(const key_type&) const; + unsigned long get_unsigned_long(const key_type&) const; + float get_float(const key_type&) const; + double get_double(const key_type&) const; + std::string get_string(const key_type&) const; + + std::vector get_vector_bool(const key_type&) const; + std::vector get_vector_int(const key_type&) const; + std::vector get_vector_unsigned_int(const key_type&) const; + std::vector get_vector_long(const key_type&) const; + std::vector get_vector_unsigned_long(const key_type&) const; + std::vector get_vector_float(const key_type&) const; + std::vector get_vector_double(const key_type&) const; + std::vector get_vector_string(const key_type&) const; + // -- Overridden methods // None From 2d43ecd4050cd8e077b863cbe2c914df54e1e087 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 26 Apr 2023 09:37:31 +0100 Subject: [PATCH 173/737] projection --- src/grit/CMakeLists.txt | 1 + src/grit/projection/PROJ.cc | 123 +++++++++++++++++++++++ src/grit/projection/PROJ.h | 195 ++++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 6 ++ tests/projection_proj.cc | 52 ++++++++++ 5 files changed, 377 insertions(+) create mode 100644 src/grit/projection/PROJ.cc create mode 100644 src/grit/projection/PROJ.h create mode 100644 tests/projection_proj.cc diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 2f610f937..bc7ed0067 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -47,6 +47,7 @@ add_library(grit SHARED target_include_directories(grit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") if(TARGET PROJ::proj) + target_sources(grit PRIVATE projection/PROJ.cc projection/PROJ.h) target_link_libraries(grit PROJ::proj) endif() diff --git a/src/grit/projection/PROJ.cc b/src/grit/projection/PROJ.cc new file mode 100644 index 000000000..b56a8af19 --- /dev/null +++ b/src/grit/projection/PROJ.cc @@ -0,0 +1,123 @@ +/* + * (C) Copyright 1996- 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 "grit/projection/PROJ.h" + +#include "grit/exception.h" + + +namespace grit::projection { + + +PROJ::PROJ(const std::string& source, const std::string& target) : + proj_(nullptr), ctx_(PJ_DEFAULT_CTX), source_(source), target_(target) { + ASSERT(!source.empty()); + + // projection, normalised + pj_t p(proj_create_crs_to_crs(ctx_.get(), source_.c_str(), target_.c_str(), nullptr)); + ASSERT(p); + + proj_.reset(proj_normalize_for_visualization(ctx_.get(), p.get())); + ASSERT(proj_); +} + + +std::string PROJ::ellipsoid() const { + pj_t identity(proj_create_crs_to_crs(ctx_.get(), target_.c_str(), target_.c_str(), nullptr)); + pj_t proj(proj_get_target_crs(ctx_.get(), identity.get())); + + if (pj_t ellipsoid(proj_get_ellipsoid(ctx_.get(), proj.get())); ellipsoid) { + double a = 0; + double b = 0; + ASSERT(proj_ellipsoid_get_parameters(ctx_.get(), ellipsoid.get(), &a, &b, nullptr, nullptr)); + ASSERT(0 < b && b <= a); + return b < a ? "+proj=lonlat +a=" + std::to_string(a) + " +b=" + std::to_string(b) + : "+proj=lonlat +R=" + std::to_string(a); + } + + // EPSG:4326 -> WGS84 (lat,lon), EPSG:4978 -> WGS84 (x,y,z) + return "EPSG:4326"; +} + + +template +PJ_COORD __from(const T&) { + NOTIMP; +} + + +template <> +PJ_COORD __from(const PointLatLon& p) { + return proj_coord(p.lon, p.lat, 0, 0); +} + + +template <> +PJ_COORD __from(const PointXY& p) { + return proj_coord(p.x, p.y, 0, 0); +} + + +template <> +PJ_COORD __from(const PointXYZ& p) { + return proj_coord(p.x, p.y, p.z, 0); +} + + +template +T __to(const PJ_COORD&) { + NOTIMP; +} + + +template <> +PointLatLon __to(const PJ_COORD& c) { + return PointLatLon::make(c.enu.n, c.enu.e); +} + + +template <> +PointXY __to(const PJ_COORD& c) { + return {c.xy.x, c.xy.y}; +} + + +template <> +PointXYZ __to(const PJ_COORD& c) { + return {c.xyz.x, c.xyz.y, c.xyz.z}; +} + + +template +PointTarget PROJTT::fwd(const PointSource& p) const { + return __to(proj_trans(PROJ::proj().get(), PJ_FWD, __from(p))); +} + + +template +PointSource PROJTT::inv(const PointTarget& q) const { + return __to(proj_trans(PROJ::proj().get(), PJ_INV, __from(q))); +} + + +ProjectionBuilder __PROJ_LatLon_to_LatLon("PROJ_LatLon_to_LatLon"); +ProjectionBuilder __PROJ_LatLon_to_XY("PROJ_LatLon_to_XY "); +ProjectionBuilder __PROJ_LatLon_to_XYZ("PROJ_LatLon_to_XYZ"); +ProjectionBuilder __PROJ_XY_to_LatLon("PROJ_XY_to_LatLon"); +ProjectionBuilder __PROJ_XY_to_XY("PROJ_XY_to_XY "); +ProjectionBuilder __PROJ_XY_to_XYZ("PROJ_XY_to_XYZ"); +ProjectionBuilder __PROJ_XYZ_to_LatLon("PROJ_XYZ_to_LatLon"); +ProjectionBuilder __PROJ_XYZ_to_XY("PROJ_XYZ_to_XY "); +ProjectionBuilder __PROJ_XYZ_to_XYZ("PROJ_XYZ_to_XYZ"); + + +} // namespace grit::projection diff --git a/src/grit/projection/PROJ.h b/src/grit/projection/PROJ.h new file mode 100644 index 000000000..d67f13990 --- /dev/null +++ b/src/grit/projection/PROJ.h @@ -0,0 +1,195 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include + +#include "grit/Parametrisation.h" +#include "grit/Projection.h" +#include "grit/types.h" + + +namespace grit::projection { + + +/// Compute coordinates using PROJ (base class) +class PROJ : public Projection { +public: + // -- Types + + struct pj_t : std::unique_ptr { + using t = std::unique_ptr; + explicit pj_t(PJ* ptr) : t(ptr, &proj_destroy) {} + explicit operator PJ*() const { return t::get(); } + }; + + struct ctx_t : std::unique_ptr { + using t = std::unique_ptr; + explicit ctx_t(PJ_CONTEXT* ptr) : t(ptr, &proj_context_destroy) {} + explicit operator PJ_CONTEXT*() const { return t::get(); } + }; + + // -- Exceptions + // None + + // -- Constructors + // None + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + const std::string& source() const { return source_; } + const std::string& target() const { return target_; } + std::string ellipsoid() const; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Constructors + + PROJ(const std::string& source, const std::string& target); + + // -- Members + // None + + // -- Methods + + const pj_t& proj() const { return proj_; } + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + pj_t proj_; + ctx_t ctx_; + + const std::string source_; + const std::string target_; + std::string ellipsoid_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +/// Compute coordinates using PROJ (specialization on input/output point types) +template +class PROJTT final : public PROJ { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit PROJTT(const Parametrisation& param) : PROJ(param.get_string("source"), param.get_string("target")) {} + + PROJTT(const std::string& source, const std::string& target) : PROJ(source, target) {} + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + PointTarget fwd(const PointSource&) const; + PointSource inv(const PointTarget&) const; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + Point fwd(const Point& p) const override { return {fwd(std::get(p))}; } + Point inv(const Point& q) const override { return {inv(std::get(q))}; } + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +using PROJ_LatLon_to_LatLon = PROJTT; +using PROJ_LatLon_to_XY = PROJTT; +using PROJ_LatLon_to_XYZ = PROJTT; +using PROJ_XY_to_LatLon = PROJTT; +using PROJ_XY_to_XY = PROJTT; +using PROJ_XY_to_XYZ = PROJTT; +using PROJ_XYZ_to_LatLon = PROJTT; +using PROJ_XYZ_to_XY = PROJTT; +using PROJ_XYZ_to_XYZ = PROJTT; + + +} // namespace grit::projection diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ddc2322b9..a4e0619f9 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -12,3 +12,9 @@ foreach(name add_test(test_${name} test_${name}) endforeach() +if(PROJ_FOUND) + add_executable(test_projection_proj projection_proj.cc) + target_link_libraries(test_projection_proj grit) + add_test(test_projection_proj test_projection_proj) +endif() + diff --git a/tests/projection_proj.cc b/tests/projection_proj.cc new file mode 100644 index 000000000..d773a8505 --- /dev/null +++ b/tests/projection_proj.cc @@ -0,0 +1,52 @@ +/* + * (C) Copyright 1996- 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 + +#include "grit/exception.h" +#include "grit/param/Map.h" +#include "grit/projection/PROJ.h" +#include "grit/types.h" + + +int main(int argc, char* argv[]) { + using grit::PointLatLon; + using grit::PointXY; + + const std::string string1 = "+proj=utm +zone=32 +datum=WGS84"; + const std::string string2 = "EPSG:32632"; + + + constexpr double eps = 1e-6; + + for (const auto& string : {string1, string2}) { + + grit::projection::PROJ_LatLon_to_XY projection(grit::param::Map({ + {"source", "EPSG:4326"}, + {"target", string}, + })); + + std::cout.precision(16); + + PointLatLon a{55., 12.}; + std::cout << "a: " << a << std::endl; + + auto b = projection.fwd(a); + std::cout << "b: " << b << std::endl; + + auto c = projection.inv(b); + std::cout << "c: " << c << std::endl; + + std::cout << b.is_approximately_equal({691875.632137542, 6098907.825129169}, eps) << std::endl; + std::cout << a.is_approximately_equal(projection.inv(b), eps) << std::endl; + } +} From b71dcba1120c5bacdb32df9b668dde524dee49f6 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 26 Apr 2023 13:16:31 +0100 Subject: [PATCH 174/737] projection --- src/grit/projection/PROJ.cc | 128 +++++++++++++++++------------------ src/grit/projection/PROJ.h | 126 +++++++--------------------------- src/grit/types/PointLatLon.h | 4 +- tests/projection_proj.cc | 64 ++++++++++++------ 4 files changed, 136 insertions(+), 186 deletions(-) diff --git a/src/grit/projection/PROJ.cc b/src/grit/projection/PROJ.cc index b56a8af19..b99a4fb16 100644 --- a/src/grit/projection/PROJ.cc +++ b/src/grit/projection/PROJ.cc @@ -12,13 +12,15 @@ #include "grit/projection/PROJ.h" +#include "grit/Parametrisation.h" #include "grit/exception.h" +#include "grit/types.h" namespace grit::projection { -PROJ::PROJ(const std::string& source, const std::string& target) : +PROJ::PROJ(const std::string& source, const std::string& target, double(lon_minimum)) : proj_(nullptr), ctx_(PJ_DEFAULT_CTX), source_(source), target_(target) { ASSERT(!source.empty()); @@ -28,96 +30,94 @@ PROJ::PROJ(const std::string& source, const std::string& target) : proj_.reset(proj_normalize_for_visualization(ctx_.get(), p.get())); ASSERT(proj_); -} - -std::string PROJ::ellipsoid() const { - pj_t identity(proj_create_crs_to_crs(ctx_.get(), target_.c_str(), target_.c_str(), nullptr)); - pj_t proj(proj_get_target_crs(ctx_.get(), identity.get())); + struct LatLon final : Convert { + PJ_COORD convert(const Point& p) const final { + const auto& q = std::get(p); + return proj_coord(q.lon, q.lat, 0, 0); + } - if (pj_t ellipsoid(proj_get_ellipsoid(ctx_.get(), proj.get())); ellipsoid) { - double a = 0; - double b = 0; - ASSERT(proj_ellipsoid_get_parameters(ctx_.get(), ellipsoid.get(), &a, &b, nullptr, nullptr)); - ASSERT(0 < b && b <= a); - return b < a ? "+proj=lonlat +a=" + std::to_string(a) + " +b=" + std::to_string(b) - : "+proj=lonlat +R=" + std::to_string(a); - } + Point convert(const PJ_COORD& c) const final { return PointLatLon::make(c.enu.n, c.enu.e, lon_minimum_); } - // EPSG:4326 -> WGS84 (lat,lon), EPSG:4978 -> WGS84 (x,y,z) - return "EPSG:4326"; -} + explicit LatLon(double lon_minimum) : lon_minimum_(lon_minimum) {} + const double lon_minimum_; + }; + struct XY final : Convert { + PJ_COORD convert(const Point& p) const final { + const auto& q = std::get(p); + return proj_coord(q.x, q.y, 0, 0); + } -template -PJ_COORD __from(const T&) { - NOTIMP; -} + Point convert(const PJ_COORD& c) const final { return PointXY{c.xy.x, c.xy.y}; } + }; + struct XYZ final : Convert { + PJ_COORD convert(const Point& p) const final { + const auto& q = std::get(p); + return proj_coord(q.x, q.y, q.z, 0); + } -template <> -PJ_COORD __from(const PointLatLon& p) { - return proj_coord(p.lon, p.lat, 0, 0); -} + Point convert(const PJ_COORD& c) const final { return PointXYZ{c.xy.x, c.xy.y, c.xyz.z}; } + }; + auto convert_ptr = [lon_minimum](const std::string& string) -> Convert* { + constexpr auto ctx = PJ_DEFAULT_CTX; -template <> -PJ_COORD __from(const PointXY& p) { - return proj_coord(p.x, p.y, 0, 0); -} + pj_t identity(proj_create_crs_to_crs(ctx, string.c_str(), string.c_str(), nullptr)); + pj_t crs(proj_get_target_crs(ctx, identity.get())); + pj_t cs(proj_crs_get_coordinate_system(ctx, crs.get())); + ASSERT(cs); + auto type = proj_cs_get_type(ctx, cs.get()); + auto dim = proj_cs_get_axis_count(ctx, cs.get()); -template <> -PJ_COORD __from(const PointXYZ& p) { - return proj_coord(p.x, p.y, p.z, 0); -} + return type == PJ_CS_TYPE_CARTESIAN && dim == 3 ? static_cast(new XYZ) + : type == PJ_CS_TYPE_CARTESIAN && dim == 2 ? static_cast(new XY) + : type == PJ_CS_TYPE_ELLIPSOIDAL ? static_cast(new LatLon(lon_minimum)) + : type == PJ_CS_TYPE_SPHERICAL ? static_cast(new LatLon(lon_minimum)) + : NOTIMP; + }; + from_.reset(convert_ptr(source_)); + ASSERT(from_); -template -T __to(const PJ_COORD&) { - NOTIMP; + to_.reset(convert_ptr(target_)); + ASSERT(to_); } -template <> -PointLatLon __to(const PJ_COORD& c) { - return PointLatLon::make(c.enu.n, c.enu.e); -} - +PROJ::PROJ(const Parametrisation& param) : + PROJ(param.has("source") ? param.get_string("source") : "EPSG:4326", // default to WGS 84 + param.has("target") ? param.get_string("target") : "EPSG:4326", // ... + param.has("lon_minimum") ? param.get_double("lon_minimum") : 0) {} -template <> -PointXY __to(const PJ_COORD& c) { - return {c.xy.x, c.xy.y}; -} +std::string PROJ::ellipsoid(const std::string& string) { + constexpr auto ctx = PJ_DEFAULT_CTX; -template <> -PointXYZ __to(const PJ_COORD& c) { - return {c.xyz.x, c.xyz.y, c.xyz.z}; -} + pj_t identity(proj_create_crs_to_crs(ctx, string.c_str(), string.c_str(), nullptr)); + pj_t crs(proj_get_target_crs(ctx, identity.get())); + pj_t ellipsoid(proj_get_ellipsoid(ctx, crs.get())); + ASSERT(ellipsoid); + double a = 0; + double b = 0; + ASSERT(proj_ellipsoid_get_parameters(ctx, ellipsoid.get(), &a, &b, nullptr, nullptr)); + ASSERT(0 < b && b <= a); -template -PointTarget PROJTT::fwd(const PointSource& p) const { - return __to(proj_trans(PROJ::proj().get(), PJ_FWD, __from(p))); + return b < a ? "+a=" + std::to_string(a) + " +b=" + std::to_string(b) : "+R=" + std::to_string(a); } -template -PointSource PROJTT::inv(const PointTarget& q) const { - return __to(proj_trans(PROJ::proj().get(), PJ_INV, __from(q))); +Point PROJ::fwd(const Point& p) const { + return to_->convert(proj_trans(proj_.get(), PJ_FWD, from_->convert(p))); } -ProjectionBuilder __PROJ_LatLon_to_LatLon("PROJ_LatLon_to_LatLon"); -ProjectionBuilder __PROJ_LatLon_to_XY("PROJ_LatLon_to_XY "); -ProjectionBuilder __PROJ_LatLon_to_XYZ("PROJ_LatLon_to_XYZ"); -ProjectionBuilder __PROJ_XY_to_LatLon("PROJ_XY_to_LatLon"); -ProjectionBuilder __PROJ_XY_to_XY("PROJ_XY_to_XY "); -ProjectionBuilder __PROJ_XY_to_XYZ("PROJ_XY_to_XYZ"); -ProjectionBuilder __PROJ_XYZ_to_LatLon("PROJ_XYZ_to_LatLon"); -ProjectionBuilder __PROJ_XYZ_to_XY("PROJ_XYZ_to_XY "); -ProjectionBuilder __PROJ_XYZ_to_XYZ("PROJ_XYZ_to_XYZ"); +Point PROJ::inv(const Point& q) const { + return from_->convert(proj_trans(proj_.get(), PJ_INV, to_->convert(q))); +} } // namespace grit::projection diff --git a/src/grit/projection/PROJ.h b/src/grit/projection/PROJ.h index d67f13990..909f9f9ff 100644 --- a/src/grit/projection/PROJ.h +++ b/src/grit/projection/PROJ.h @@ -16,16 +16,14 @@ #include -#include "grit/Parametrisation.h" #include "grit/Projection.h" -#include "grit/types.h" namespace grit::projection { -/// Compute coordinates using PROJ (base class) -class PROJ : public Projection { +/// Calculate coordinates using PROJ +class PROJ final : public Projection { public: // -- Types @@ -41,11 +39,26 @@ class PROJ : public Projection { explicit operator PJ_CONTEXT*() const { return t::get(); } }; + struct Convert { + Convert() = default; + virtual ~Convert() = default; + + Convert(const Convert&) = delete; + Convert(Convert&&) = delete; + void operator=(const Convert&) = delete; + void operator=(Convert&&) = delete; + + virtual PJ_COORD convert(const Point&) const = 0; + virtual Point convert(const PJ_COORD&) const = 0; + }; + // -- Exceptions // None // -- Constructors - // None + + PROJ(const std::string& source, const std::string& target, double lon_minimum = 0.); + explicit PROJ(const Parametrisation&); // -- Destructor // None @@ -60,31 +73,13 @@ class PROJ : public Projection { const std::string& source() const { return source_; } const std::string& target() const { return target_; } - std::string ellipsoid() const; - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Constructors - - PROJ(const std::string& source, const std::string& target); - - // -- Members - // None - - // -- Methods - - const pj_t& proj() const { return proj_; } + static std::string ellipsoid(const std::string& string); // -- Overridden methods - // None + + Point fwd(const Point&) const override; + Point inv(const Point&) const override; // -- Class members // None @@ -100,75 +95,15 @@ class PROJ : public Projection { const std::string source_; const std::string target_; - std::string ellipsoid_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - -/// Compute coordinates using PROJ (specialization on input/output point types) -template -class PROJTT final : public PROJ { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit PROJTT(const Parametrisation& param) : PROJ(param.get_string("source"), param.get_string("target")) {} - - PROJTT(const std::string& source, const std::string& target) : PROJ(source, target) {} - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - PointTarget fwd(const PointSource&) const; - PointSource inv(const PointTarget&) const; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None + std::unique_ptr from_; + std::unique_ptr to_; // -- Methods // None // -- Overridden methods - - Point fwd(const Point& p) const override { return {fwd(std::get(p))}; } - Point inv(const Point& q) const override { return {inv(std::get(q))}; } + // None // -- Class members // None @@ -181,15 +116,4 @@ class PROJTT final : public PROJ { }; -using PROJ_LatLon_to_LatLon = PROJTT; -using PROJ_LatLon_to_XY = PROJTT; -using PROJ_LatLon_to_XYZ = PROJTT; -using PROJ_XY_to_LatLon = PROJTT; -using PROJ_XY_to_XY = PROJTT; -using PROJ_XY_to_XYZ = PROJTT; -using PROJ_XYZ_to_LatLon = PROJTT; -using PROJ_XYZ_to_XY = PROJTT; -using PROJ_XYZ_to_XYZ = PROJTT; - - } // namespace grit::projection diff --git a/src/grit/types/PointLatLon.h b/src/grit/types/PointLatLon.h index df3156ff5..43bb726a3 100644 --- a/src/grit/types/PointLatLon.h +++ b/src/grit/types/PointLatLon.h @@ -92,7 +92,7 @@ class PointLatLon final : protected std::array { // -- Methods - static PointLatLon make(T lat, T lon) { + static PointLatLon make(T lat, T lon, T lon_minimum = 0) { lat = normal(lat, -90.); if (lat > 90.) { @@ -100,7 +100,7 @@ class PointLatLon final : protected std::array { lon += 180.; } - return {lat, lat == -90. || lat == 90. ? 0. : normal(lon, 0.)}; + return {lat, lat == -90. || lat == 90. ? 0. : normal(lon, lon_minimum)}; } PointLatLon antipode() const { return make(lat + 180., lon); } diff --git a/tests/projection_proj.cc b/tests/projection_proj.cc index d773a8505..bd4b7ae1d 100644 --- a/tests/projection_proj.cc +++ b/tests/projection_proj.cc @@ -18,35 +18,61 @@ #include "grit/types.h" -int main(int argc, char* argv[]) { - using grit::PointLatLon; - using grit::PointXY; +bool operator==(const grit::Point& p, const grit::Point& q) { + ASSERT(p.index() == q.index()); - const std::string string1 = "+proj=utm +zone=32 +datum=WGS84"; - const std::string string2 = "EPSG:32632"; + constexpr double eps = 1e-6; + return std::holds_alternative(p) + ? std::get(p).is_approximately_equal(std::get(q), eps) + : std::holds_alternative(p) + ? std::get(p).is_approximately_equal(std::get(q), eps) + : std::holds_alternative(p) + ? std::get(p).is_approximately_equal(std::get(q), eps) + : NOTIMP; +} - constexpr double eps = 1e-6; - for (const auto& string : {string1, string2}) { +int main(int argc, char* argv[]) { + std::cout.precision(14); - grit::projection::PROJ_LatLon_to_XY projection(grit::param::Map({ - {"source", "EPSG:4326"}, - {"target", string}, - })); + grit::PointLatLon a{55., 12.}; - std::cout.precision(16); + struct { + const grit::Point b; + const std::string target; + } tests[] = { + {grit::PointXY{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, + {grit::PointXY{691875.632137542, 6098907.825129169}, "EPSG:32632"}, + {a, "EPSG:4326"}, + {a, "EPSG:4979"}, + {grit::PointXYZ{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, + {grit::PointXYZ{3574529.7050235, 759789.74368715, 5219005.2599833}, "+proj=cart +R=6371229."}, + {grit::PointXYZ{3574399.5431832, 759762.07693392, 5218815.216709}, "+proj=cart +ellps=sphere"}, + {a, "+proj=latlon +ellps=sphere"}, + }; - PointLatLon a{55., 12.}; - std::cout << "a: " << a << std::endl; + for (const auto& test : tests) { + grit::projection::PROJ projection(grit::param::Map({{"source", "EPSG:4326"}, {"target", test.target}})); - auto b = projection.fwd(a); - std::cout << "b: " << b << std::endl; + std::cout << "ellipsoid: '" << grit::projection::PROJ::ellipsoid(projection.target()) << std::endl; + auto b = projection.fwd(a); auto c = projection.inv(b); - std::cout << "c: " << c << std::endl; - std::cout << b.is_approximately_equal({691875.632137542, 6098907.825129169}, eps) << std::endl; - std::cout << a.is_approximately_equal(projection.inv(b), eps) << std::endl; + std::cout << "-> a:" << a << " -> fwd(a):" << b << " -> inv(fwd(a)):" << c << std::endl; + + ASSERT(b == test.b); + ASSERT(c == a); + + grit::projection::PROJ reverse(grit::param::Map({{"source", test.target}, {"target", "EPSG:4326"}})); + + auto d = reverse.fwd(test.b); + auto e = reverse.inv(d); + + std::cout << "-> b:" << test.b << " -> fwd(b):" << d << " -> inv(fwd(b)):" << e << std::endl; + + ASSERT(d == a); + ASSERT(e == test.b); } } From 8802c28668e282350fc2a797d603747c0b5fd4a6 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 27 Apr 2023 09:38:00 +0100 Subject: [PATCH 175/737] projection --- src/grit/projection/Rotation.cc | 6 ++++++ src/grit/projection/Rotation.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/grit/projection/Rotation.cc b/src/grit/projection/Rotation.cc index e5f91eaff..8c92b1280 100644 --- a/src/grit/projection/Rotation.cc +++ b/src/grit/projection/Rotation.cc @@ -15,6 +15,7 @@ #include #include +#include "grit/Parametrisation.h" #include "grit/geometry/Sphere.h" #include "grit/types/MatrixXYZ.h" #include "grit/util.h" @@ -86,4 +87,9 @@ Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : } +Rotation::Rotation(const Parametrisation& param) : + Rotation(param.get_double("south_pole_lat"), param.get_double("south_pole_lon"), + param.has("angle") ? param.get_double("angle") : 0) {} + + } // namespace grit::projection diff --git a/src/grit/projection/Rotation.h b/src/grit/projection/Rotation.h index 63d42c011..2382389cb 100644 --- a/src/grit/projection/Rotation.h +++ b/src/grit/projection/Rotation.h @@ -43,6 +43,7 @@ class Rotation final : public Projection { // -- Constructors Rotation(double south_pole_lat, double south_pole_lon, double angle); + explicit Rotation(const Parametrisation&); // -- Destructor // None From b8c4f1f78c5c055dc67f1e6d62d24f0d15410b85 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 27 Apr 2023 10:19:03 +0100 Subject: [PATCH 176/737] projection --- src/grit/CMakeLists.txt | 2 ++ src/grit/Projection.cc | 4 ++- src/grit/Projection.h | 4 +-- src/grit/projection/LatLonToXYZ.cc | 9 +++++ src/grit/projection/LatLonToXYZ.h | 1 + src/grit/projection/PROJ.cc | 5 ++- src/grit/projection/Rotation.cc | 3 ++ src/grit/projection/Rotation.h | 28 +++++++-------- src/grit/test.cc | 28 +++++++++++++++ src/grit/test.h | 21 ++++++++++++ src/grit/types/PointLatLon.h | 4 --- tests/param.cc | 10 +++--- tests/projection.cc | 55 ++++++++++++++++++++++++++++-- tests/projection_ll_to_xyz.cc | 5 +-- tests/projection_proj.cc | 26 +++----------- tests/projection_rotation.cc | 53 ++++++++++++++-------------- tests/types.cc | 16 ++++++--- 17 files changed, 191 insertions(+), 83 deletions(-) create mode 100644 src/grit/test.cc create mode 100644 src/grit/test.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index bc7ed0067..7d6d77b66 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -27,6 +27,8 @@ add_library(grit SHARED projection/LatLonToXYZ.h projection/Rotation.cc projection/Rotation.h + test.cc + test.h types.cc types.h types/MatrixXYZ.h diff --git a/src/grit/Projection.cc b/src/grit/Projection.cc index 901504da4..c2ac915ff 100644 --- a/src/grit/Projection.cc +++ b/src/grit/Projection.cc @@ -242,7 +242,7 @@ Projection* ProjectionFactory::build(const ProjectionFactory::key_type& key, con } -void ProjectionFactory::list(std::ostream& out) { +std::ostream& ProjectionFactory::list(std::ostream& out) { util::call_once(__once, __init); util::lock_guard lock(*__mutex); @@ -251,6 +251,8 @@ void ProjectionFactory::list(std::ostream& out) { out << sep << j.first; sep = ", "; } + + return out; } diff --git a/src/grit/Projection.h b/src/grit/Projection.h index e517f7e5d..62d83a511 100644 --- a/src/grit/Projection.h +++ b/src/grit/Projection.h @@ -107,8 +107,8 @@ class Projection { struct ProjectionFactory { using key_type = std::string; - Projection* build(const key_type&, const Parametrisation&); - static void list(std::ostream&); + static Projection* build(const key_type&, const Parametrisation&); + static std::ostream& list(std::ostream&); ProjectionFactory(const ProjectionFactory&) = delete; ProjectionFactory(ProjectionFactory&&) = delete; diff --git a/src/grit/projection/LatLonToXYZ.cc b/src/grit/projection/LatLonToXYZ.cc index a61200e5c..d5ef2cf71 100644 --- a/src/grit/projection/LatLonToXYZ.cc +++ b/src/grit/projection/LatLonToXYZ.cc @@ -12,6 +12,7 @@ #include "grit/projection/LatLonToXYZ.h" +#include "grit/Parametrisation.h" #include "grit/geometry/Sphere.h" #include "grit/geometry/Spheroid.h" #include "grit/util.h" @@ -20,6 +21,9 @@ namespace grit::projection { +static ProjectionBuilder __projection("ll_to_xyz"); + + LatLonToXYZ::LatLonToXYZ(double a, double b) { ASSERT(0. < a); ASSERT(0. < b); @@ -51,4 +55,9 @@ LatLonToXYZ::LatLonToXYZ(double a, double b) { LatLonToXYZ::LatLonToXYZ(double R) : LatLonToXYZ(R, R) {} +LatLonToXYZ::LatLonToXYZ(const Parametrisation& param) : + LatLonToXYZ(param.has("R") ? param.get_double("R") : param.get_double("a"), + param.has("R") ? param.get_double("R") : param.get_double("b")) {} + + } // namespace grit::projection diff --git a/src/grit/projection/LatLonToXYZ.h b/src/grit/projection/LatLonToXYZ.h index 6da19a2cc..e78de52bd 100644 --- a/src/grit/projection/LatLonToXYZ.h +++ b/src/grit/projection/LatLonToXYZ.h @@ -30,6 +30,7 @@ class LatLonToXYZ final : public Projection { LatLonToXYZ(double a, double b); explicit LatLonToXYZ(double R); + explicit LatLonToXYZ(const Parametrisation&); // -- Destructor // None diff --git a/src/grit/projection/PROJ.cc b/src/grit/projection/PROJ.cc index b99a4fb16..b5e944c2b 100644 --- a/src/grit/projection/PROJ.cc +++ b/src/grit/projection/PROJ.cc @@ -20,7 +20,10 @@ namespace grit::projection { -PROJ::PROJ(const std::string& source, const std::string& target, double(lon_minimum)) : +static ProjectionBuilder __projection("proj"); + + +PROJ::PROJ(const std::string& source, const std::string& target, double lon_minimum) : proj_(nullptr), ctx_(PJ_DEFAULT_CTX), source_(source), target_(target) { ASSERT(!source.empty()); diff --git a/src/grit/projection/Rotation.cc b/src/grit/projection/Rotation.cc index 8c92b1280..0d5686eaf 100644 --- a/src/grit/projection/Rotation.cc +++ b/src/grit/projection/Rotation.cc @@ -24,6 +24,9 @@ namespace grit::projection { +static ProjectionBuilder __projection("rotation"); + + Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : rotated_(true) { using M = types::MatrixXYZ; diff --git a/src/grit/projection/Rotation.h b/src/grit/projection/Rotation.h index 2382389cb..1dfd1b8f0 100644 --- a/src/grit/projection/Rotation.h +++ b/src/grit/projection/Rotation.h @@ -23,20 +23,6 @@ namespace grit::projection { /// Compute coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle class Rotation final : public Projection { public: - // -- Types - - struct Rotate { - Rotate() = default; - virtual ~Rotate() = default; - - Rotate(const Rotate&) = delete; - Rotate(Rotate&&) = delete; - void operator=(const Rotate&) = delete; - void operator=(Rotate&&) = delete; - - virtual PointLatLon operator()(const PointLatLon&) const = 0; - }; - // -- Exceptions // None @@ -70,6 +56,20 @@ class Rotation final : public Projection { // None private: + // -- Types + + struct Rotate { + Rotate() = default; + virtual ~Rotate() = default; + + Rotate(const Rotate&) = delete; + Rotate(Rotate&&) = delete; + void operator=(const Rotate&) = delete; + void operator=(Rotate&&) = delete; + + virtual PointLatLon operator()(const PointLatLon&) const = 0; + }; + // -- Members std::unique_ptr fwd_; diff --git a/src/grit/test.cc b/src/grit/test.cc new file mode 100644 index 000000000..f0f43b4ac --- /dev/null +++ b/src/grit/test.cc @@ -0,0 +1,28 @@ +/* + * (C) Copyright 1996- 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 "grit/test.h" + + +bool operator==(const grit::Point& p, const grit::Point& q) { + ASSERT(p.index() == q.index()); + + constexpr double eps = 1e-6; + + return std::holds_alternative(p) + ? std::get(p).is_approximately_equal(std::get(q), eps) + : std::holds_alternative(p) + ? std::get(p).is_approximately_equal(std::get(q), eps) + : std::holds_alternative(p) + ? std::get(p).is_approximately_equal(std::get(q), eps) + : NOTIMP; +} diff --git a/src/grit/test.h b/src/grit/test.h new file mode 100644 index 000000000..5c09545ae --- /dev/null +++ b/src/grit/test.h @@ -0,0 +1,21 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/exception.h" +#include "grit/types.h" + +#define EXPECT ASSERT + + +bool operator==(const grit::Point&, const grit::Point&); diff --git a/src/grit/types/PointLatLon.h b/src/grit/types/PointLatLon.h index 43bb726a3..4157ea2b4 100644 --- a/src/grit/types/PointLatLon.h +++ b/src/grit/types/PointLatLon.h @@ -75,10 +75,6 @@ class PointLatLon final : protected std::array { return *this; } - bool operator==(const PointLatLon& other) const { return lat == other.lat && normal(other.lon, lon) == lon; } - - bool operator!=(const PointLatLon& other) const { return !operator==(other); } - bool is_approximately_equal(const PointLatLon& other, T eps) const { const auto dlon = normal(other.lon, lon) - lon; return std::abs(lat - other.lat) < eps && diff --git a/tests/param.cc b/tests/param.cc index f4cb03c25..f02b309bc 100644 --- a/tests/param.cc +++ b/tests/param.cc @@ -13,27 +13,27 @@ #include #include -#include "grit/exception.h" #include "grit/param/Map.h" +#include "grit/test.h" int main(int argc, char* argv[]) { std::unique_ptr param(new grit::param::Map({{"a", -123}, {"b", "B"}, {"c", 123UL}})); int a = 0; - ASSERT(param->get("a", a)); + EXPECT(param->get("a", a)); std::cout << "a: '" << a << "'" << std::endl; std::string b; - ASSERT(param->get("b", b)); + EXPECT(param->get("b", b)); std::cout << "b: '" << b << "'" << std::endl; size_t c = 0; - ASSERT(param->get("c", c)); + EXPECT(param->get("c", c)); std::cout << "c: '" << c << "'" << std::endl; int d = 321; dynamic_cast(param.get())->set("b", d); - ASSERT(param->get("b", d)); + EXPECT(param->get("b", d)); std::cout << "d: '" << d << "'" << std::endl; } diff --git a/tests/projection.cc b/tests/projection.cc index eb98c755a..fb0c883fd 100644 --- a/tests/projection.cc +++ b/tests/projection.cc @@ -13,7 +13,58 @@ #include #include -// #include "grit/Projection.h" +#include "grit/Projection.h" +#include "grit/param/Map.h" +#include "grit/test.h" -int main(int argc, char* argv[]) {} +int main(int argc, char* argv[]) { + using grit::Point; + using grit::PointLatLon; + using grit::PointXYZ; + using Projection = std::unique_ptr; + + Point p = PointLatLon{1, 1}; + + { + grit::param::Map param({ + {"projection", "rotation"}, + {"south_pole_lat", -91.}, + {"south_pole_lon", -361.}, + }); + + std::unique_ptr projection( + grit::ProjectionFactory::build(param.get_string("projection"), param)); + + EXPECT(p == projection->inv(projection->fwd(p))); + EXPECT(p == projection->fwd(projection->inv(p))); + } + + + { + Projection s1(grit::ProjectionFactory::build("ll_to_xyz", grit::param::Map({{"R", 1.}}))); + Projection s2(grit::ProjectionFactory::build("ll_to_xyz", grit::param::Map({{"a", 1.}, {"b", 1.}}))); + Projection s3(grit::ProjectionFactory::build("ll_to_xyz", grit::param::Map({{"a", 1.}, {"b", 0.5}}))); + + EXPECT(p == s1->inv(s1->fwd(p))); + EXPECT(p == s2->inv(s2->fwd(p))); + EXPECT(s1->fwd(p) == s2->fwd(p)); + + Point q = PointLatLon{0, 1}; + + EXPECT(s1->fwd(q) == s3->fwd(q)); + EXPECT(s2->fwd(q) == s3->fwd(q)); + + struct { + PointLatLon a; + PointXYZ b; + } tests[] = { + {{0, 0}, {1, 0, 0}}, {{0, 90}, {0, 1, 0}}, {{0, 180}, {-1, 0, 0}}, {{0, 270}, {0, -1, 0}}, + {{-90, 0}, {0, 0, -0.5}}, {{-90, 42}, {0, 0, -0.5}}, {{90, 0}, {0, 0, 0.5}}, {{90, 42}, {0, 0, 0.5}}, + }; + + for (const auto& test : tests) { + EXPECT(s3->fwd(test.a) == Point(test.b)); + } + } +} diff --git a/tests/projection_ll_to_xyz.cc b/tests/projection_ll_to_xyz.cc index fa5ab5f26..1a527befc 100644 --- a/tests/projection_ll_to_xyz.cc +++ b/tests/projection_ll_to_xyz.cc @@ -12,11 +12,12 @@ #include -#include "grit/exception.h" #include "grit/projection/LatLonToXYZ.h" +#include "grit/test.h" int main(int argc, char* argv[]) { + using grit::Point; using grit::PointLatLon; using grit::projection::LatLonToXYZ; @@ -30,7 +31,7 @@ int main(int argc, char* argv[]) { auto r = to_xyz.inv(q); std::cout << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; - ASSERT(p.is_approximately_equal(r, 1e-12)); + EXPECT(Point(p) == r); } diff --git a/tests/projection_proj.cc b/tests/projection_proj.cc index bd4b7ae1d..af1ab7634 100644 --- a/tests/projection_proj.cc +++ b/tests/projection_proj.cc @@ -12,25 +12,9 @@ #include -#include "grit/exception.h" #include "grit/param/Map.h" #include "grit/projection/PROJ.h" -#include "grit/types.h" - - -bool operator==(const grit::Point& p, const grit::Point& q) { - ASSERT(p.index() == q.index()); - - constexpr double eps = 1e-6; - - return std::holds_alternative(p) - ? std::get(p).is_approximately_equal(std::get(q), eps) - : std::holds_alternative(p) - ? std::get(p).is_approximately_equal(std::get(q), eps) - : std::holds_alternative(p) - ? std::get(p).is_approximately_equal(std::get(q), eps) - : NOTIMP; -} +#include "grit/test.h" int main(int argc, char* argv[]) { @@ -62,8 +46,8 @@ int main(int argc, char* argv[]) { std::cout << "-> a:" << a << " -> fwd(a):" << b << " -> inv(fwd(a)):" << c << std::endl; - ASSERT(b == test.b); - ASSERT(c == a); + EXPECT(b == test.b); + EXPECT(c == a); grit::projection::PROJ reverse(grit::param::Map({{"source", test.target}, {"target", "EPSG:4326"}})); @@ -72,7 +56,7 @@ int main(int argc, char* argv[]) { std::cout << "-> b:" << test.b << " -> fwd(b):" << d << " -> inv(fwd(b)):" << e << std::endl; - ASSERT(d == a); - ASSERT(e == test.b); + EXPECT(d == a); + EXPECT(e == test.b); } } diff --git a/tests/projection_rotation.cc b/tests/projection_rotation.cc index 5c9429751..db944d892 100644 --- a/tests/projection_rotation.cc +++ b/tests/projection_rotation.cc @@ -12,11 +12,12 @@ #include -#include "grit/exception.h" #include "grit/projection/Rotation.h" +#include "grit/test.h" int main(int argc, char* argv[]) { + using grit::Point; using grit::PointLatLon; using grit::projection::Rotation; @@ -29,10 +30,10 @@ int main(int argc, char* argv[]) { for (auto b : delta) { for (auto c : delta) { Rotation rot(-90. + static_cast(a), 0. + static_cast(b), static_cast(c)); - ASSERT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); + EXPECT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); - ASSERT(p.is_approximately_equal(rot.inv(rot.fwd(p)), 1e-5)); - ASSERT(p.is_approximately_equal(rot.fwd(rot.inv(p)), 1e-5)); + EXPECT(Point(p) == rot.inv(rot.fwd(p))); + EXPECT(Point(p) == rot.fwd(rot.inv(p))); } } } @@ -136,8 +137,8 @@ int main(int argc, char* argv[]) { PointLatLon a(static_cast(j - Nj) * 90. / static_cast(Nj), static_cast(i) * 360. / static_cast(Ni)); auto b = rot.fwd(a); - ASSERT(b.is_approximately_equal(ref[k], 1.e-5)); - ASSERT(a.is_approximately_equal(rot.inv(b), 1.e-5)); + EXPECT(Point(b) == ref[k]); + EXPECT(Point(a) == rot.inv(b)); } } } @@ -148,37 +149,37 @@ int main(int argc, char* argv[]) { const Rotation angle_only(-90., 0., -180.); const Rotation rotation(-40., 4., 180.); - ASSERT(not unrotated.rotated()); - ASSERT(angle_only.rotated()); - ASSERT(rotation.rotated()); + EXPECT(not unrotated.rotated()); + EXPECT(angle_only.rotated()); + EXPECT(rotation.rotated()); const PointLatLon p[] = {{90., 0.}, {0., 0.}, {25., 270.}, {45., -180.}}; - struct test_t { + struct { const Rotation& rotation; const PointLatLon a; const PointLatLon b; + } tests[] = { + {unrotated, p[0], p[0]}, + {unrotated, p[1], p[1]}, + {unrotated, p[2], p[2]}, + {unrotated, p[3], p[3]}, + {angle_only, p[0], {p[0].lat, p[0].lon - 180.}}, + {angle_only, p[1], {p[1].lat, p[1].lon - 180.}}, + {angle_only, p[2], {p[2].lat, p[2].lon - 180.}}, + {angle_only, p[3], {p[3].lat, p[3].lon - 180.}}, + {rotation, p[0], {40., -176.}}, + {rotation, p[1], {-50., -176.}}, + {rotation, p[2], {15.762700, 113.657357}}, + {rotation, p[3], {85., -176.}}, }; - for (const auto& test : { - test_t{unrotated, p[0], p[0]}, - test_t{unrotated, p[1], p[1]}, - test_t{unrotated, p[2], p[2]}, - test_t{unrotated, p[3], p[3]}, - test_t{angle_only, p[0], {p[0].lat, p[0].lon - 180.}}, - test_t{angle_only, p[1], {p[1].lat, p[1].lon - 180.}}, - test_t{angle_only, p[2], {p[2].lat, p[2].lon - 180.}}, - test_t{angle_only, p[3], {p[3].lat, p[3].lon - 180.}}, - test_t{rotation, p[0], {40., -176.}}, - test_t{rotation, p[1], {-50., -176.}}, - test_t{rotation, p[2], {15.762700, 113.657357}}, - test_t{rotation, p[3], {85., -176.}}, - }) { + for (const auto& test : tests) { auto b = test.rotation.fwd(test.a); - ASSERT(b.is_approximately_equal(test.b, 1e-5)); + EXPECT(Point(b) == test.b); auto a = test.rotation.inv(b); - ASSERT(a.is_approximately_equal(test.a, 1e-5)); + EXPECT(Point(a) == test.a); } } } diff --git a/tests/types.cc b/tests/types.cc index a3f9fe264..a8490a156 100644 --- a/tests/types.cc +++ b/tests/types.cc @@ -12,19 +12,20 @@ #include -#include "grit/exception.h" +#include "grit/test.h" #include "grit/types.h" #include "grit/types/MatrixXYZ.h" int main(int argc, char* argv[]) { + using grit::Point; using grit::PointLatLon; PointLatLon p(90., 1); std::cout << "p: " << p << std::endl; std::cout << "p: " << PointLatLon::make(p.lat, p.lon) << std::endl; - std::cout << "p: " << (p == PointLatLon(90., 50.)) << std::endl; + std::cout << "p: " << (Point(p) == PointLatLon(90., 50.)) << std::endl; PointLatLon q(-90., 1.); std::cout << "q: " << q << std::endl; @@ -32,10 +33,15 @@ int main(int argc, char* argv[]) { std::cout << "~~q: " << q.antipode().antipode() << std::endl; auto r(PointLatLon::make(-91., -10.)); - ASSERT(r == r.antipode().antipode()); + EXPECT(Point(r) == r.antipode().antipode()); - ASSERT(PointLatLon(-30.000000000000018, -59.99999999999996).is_approximately_equal({-30, 300}, 1e-5)); - ASSERT(PointLatLon(-46.7, -178.00000000000003).is_approximately_equal({-46.7, -178.}, 1e-5)); + Point a1 = PointLatLon{-30, 300}; + Point a2 = PointLatLon{-30.000000000000018, -59.99999999999996}; + EXPECT(a1 == a2); + + Point b1 = PointLatLon{-46.7, -178.}; + Point b2 = PointLatLon{-46.7, -178.00000000000003}; + EXPECT(b1 == b2); { From 46338d7d50f51c79a1201e426c513b950b01fd4a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 27 Apr 2023 11:08:13 +0100 Subject: [PATCH 177/737] cleanup --- src/grit/types/PointLatLon.h | 10 +++++----- src/grit/types/PointXY.h | 10 +++++----- src/grit/types/PointXYZ.h | 12 ++++++------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/grit/types/PointLatLon.h b/src/grit/types/PointLatLon.h index 4157ea2b4..23c15548f 100644 --- a/src/grit/types/PointLatLon.h +++ b/src/grit/types/PointLatLon.h @@ -53,8 +53,8 @@ class PointLatLon final : protected std::array { // -- Constructors PointLatLon(T lat, T lon) : P{lat, lon} { ASSERT_MSG(-90. <= lat && lat <= 90., "PointLatLon: invalid latitude"); } - PointLatLon(const PointLatLon& other) : P(other) {} - PointLatLon(PointLatLon&& other) : P(other) {} + PointLatLon(const PointLatLon& other) : P(other) {} + PointLatLon(PointLatLon&& other) : P(other) {} // -- Destructor @@ -65,17 +65,17 @@ class PointLatLon final : protected std::array { // -- Operators - PointLatLon& operator=(const PointLatLon& other) { + PointLatLon& operator=(const PointLatLon& other) { P::operator=(other); return *this; } - PointLatLon& operator=(PointLatLon&& other) { + PointLatLon& operator=(PointLatLon&& other) { P::operator=(other); return *this; } - bool is_approximately_equal(const PointLatLon& other, T eps) const { + bool is_approximately_equal(const PointLatLon& other, T eps) const { const auto dlon = normal(other.lon, lon) - lon; return std::abs(lat - other.lat) < eps && (std::abs(lat - 90.) < eps || std::abs(lat + 90.) < eps || dlon < eps || dlon - 360. < eps); diff --git a/src/grit/types/PointXY.h b/src/grit/types/PointXY.h index b268acffa..30125e99b 100644 --- a/src/grit/types/PointXY.h +++ b/src/grit/types/PointXY.h @@ -36,8 +36,8 @@ class PointXY final : protected std::array { // -- Constructors PointXY(T x, T y) : P{x, y} {} - PointXY(const PointXY& other) : P(other) {} - PointXY(PointXY&& other) : P(other) {} + PointXY(const PointXY& other) : P(other) {} + PointXY(PointXY&& other) : P(other) {} // -- Destructor @@ -48,17 +48,17 @@ class PointXY final : protected std::array { // -- Operators - PointXY& operator=(const PointXY& other) { + PointXY& operator=(const PointXY& other) { P::operator=(other); return *this; } - PointXY& operator=(PointXY&& other) { + PointXY& operator=(PointXY&& other) { P::operator=(other); return *this; } - bool is_approximately_equal(const PointXY& other, T eps) const { + bool is_approximately_equal(const PointXY& other, T eps) const { return std::abs(x - other.x) < eps && std::abs(y - other.y) < eps; }; diff --git a/src/grit/types/PointXYZ.h b/src/grit/types/PointXYZ.h index e1191df77..fd1b0eb06 100644 --- a/src/grit/types/PointXYZ.h +++ b/src/grit/types/PointXYZ.h @@ -36,8 +36,8 @@ class PointXYZ final : protected std::array { // -- Constructors PointXYZ(T x, T y, T z) : P{x, y, z} {} - PointXYZ(const PointXYZ& other) : P(other) {} - PointXYZ(PointXYZ&& other) : P(other) {} + PointXYZ(const PointXYZ& other) : P(other) {} + PointXYZ(PointXYZ&& other) : P(other) {} // -- Destructor @@ -48,17 +48,17 @@ class PointXYZ final : protected std::array { // -- Operators - PointXYZ& operator=(const PointXYZ& other) { + PointXYZ& operator=(const PointXYZ& other) { P::operator=(other); return *this; } - PointXYZ& operator=(PointXYZ&& other) { + PointXYZ& operator=(PointXYZ&& other) { P::operator=(other); return *this; } - bool is_approximately_equal(const PointXYZ& other, T eps) const { + bool is_approximately_equal(const PointXYZ& other, T eps) const { return std::abs(x - other.x) < eps && std::abs(y - other.y) < eps && std::abs(z - other.z) < eps; }; @@ -79,7 +79,7 @@ class PointXYZ final : protected std::array { // -- Class methods - static T distance2(const PointXYZ& a, const PointXYZ& b) { + static T distance2(const PointXYZ& a, const PointXYZ& b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z); } From 1c6e481d8e308dfa9feefb3287fa00fc17f17fca Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 27 Apr 2023 14:07:18 +0100 Subject: [PATCH 178/737] search --- src/grit/geometry/Sphere.cc | 6 +++--- src/grit/projection/PROJ.cc | 4 ++-- src/grit/types/MatrixXYZ.h | 38 ++++++++++++++++++------------------- src/grit/types/PointXY.h | 8 ++++---- src/grit/types/PointXYZ.h | 12 ++++++------ 5 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/grit/geometry/Sphere.cc b/src/grit/geometry/Sphere.cc index 88350d136..c7ecd86a9 100644 --- a/src/grit/geometry/Sphere.cc +++ b/src/grit/geometry/Sphere.cc @@ -113,9 +113,9 @@ PointLatLon Sphere::xyz_to_ll(double radius, const PointXYZ& A) { // numerical conditioning for both z (poles) and y - const double x = A.x; - const double y = util::is_approximately_equal(A.y, 0.) ? 0. : A.y; - const double z = std::min(radius, std::max(-radius, A.z)) / radius; + const double x = A.X; + const double y = util::is_approximately_equal(A.Y, 0.) ? 0. : A.Y; + const double z = std::min(radius, std::max(-radius, A.Z)) / radius; return {util::radians_to_degrees * std::asin(z), util::radians_to_degrees * std::atan2(y, x)}; } diff --git a/src/grit/projection/PROJ.cc b/src/grit/projection/PROJ.cc index b5e944c2b..1876e3a94 100644 --- a/src/grit/projection/PROJ.cc +++ b/src/grit/projection/PROJ.cc @@ -49,7 +49,7 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini struct XY final : Convert { PJ_COORD convert(const Point& p) const final { const auto& q = std::get(p); - return proj_coord(q.x, q.y, 0, 0); + return proj_coord(q.X, q.Y, 0, 0); } Point convert(const PJ_COORD& c) const final { return PointXY{c.xy.x, c.xy.y}; } @@ -58,7 +58,7 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini struct XYZ final : Convert { PJ_COORD convert(const Point& p) const final { const auto& q = std::get(p); - return proj_coord(q.x, q.y, q.z, 0); + return proj_coord(q.X, q.Y, q.Z, 0); } Point convert(const PJ_COORD& c) const final { return PointXYZ{c.xy.x, c.xy.y, c.xyz.z}; } diff --git a/src/grit/types/MatrixXYZ.h b/src/grit/types/MatrixXYZ.h index 9a2dd7d8e..b12a45007 100644 --- a/src/grit/types/MatrixXYZ.h +++ b/src/grit/types/MatrixXYZ.h @@ -62,39 +62,39 @@ class MatrixXYZ final : protected std::array { } PointXYZ operator*(const PointXYZ& p) const { - return {xx * p.x + xy * p.y + xz * p.z, yx * p.x + yy * p.y + yz * p.z, zx * p.x + zy * p.y + zz * p.z}; + return {XX * p.X + XY * p.Y + XZ * p.Z, YX * p.X + YY * p.Y + YZ * p.Z, ZX * p.X + ZY * p.Y + ZZ * p.Z}; } MatrixXYZ operator*(const MatrixXYZ& M) const { return { - xx * M.xx + xy * M.yx + xz * M.zx, xx * M.xy + xy * M.yy + xz * M.zy, xx * M.xz + xy * M.yz + xz * M.zz, - yx * M.xx + yy * M.yx + yz * M.zx, yx * M.xy + yy * M.yy + yz * M.zy, yx * M.xz + yy * M.yz + yz * M.zz, - zx * M.xx + zy * M.yx + zz * M.zx, zx * M.xy + zy * M.yy + zz * M.zy, zx * M.xz + zy * M.yz + zz * M.zz}; + XX * M.XX + XY * M.YX + XZ * M.ZX, XX * M.XY + XY * M.YY + XZ * M.ZY, XX * M.XZ + XY * M.YZ + XZ * M.ZZ, + YX * M.XX + YY * M.YX + YZ * M.ZX, YX * M.XY + YY * M.YY + YZ * M.ZY, YX * M.XZ + YY * M.YZ + YZ * M.ZZ, + ZX * M.XX + ZY * M.YX + ZZ * M.ZX, ZX * M.XY + ZY * M.YY + ZZ * M.ZY, ZX * M.XZ + ZY * M.YZ + ZZ * M.ZZ}; } // -- Members - T& xx = P::operator[](0); - T& xy = P::operator[](1); - T& xz = P::operator[](2); - T& yx = P::operator[](3); - T& yy = P::operator[](4); - T& yz = P::operator[](5); - T& zx = P::operator[](6); - T& zy = P::operator[](7); - T& zz = P::operator[](8); + T& XX = P::operator[](0); + T& XY = P::operator[](1); + T& XZ = P::operator[](2); + T& YX = P::operator[](3); + T& YY = P::operator[](4); + T& YZ = P::operator[](5); + T& ZX = P::operator[](6); + T& ZY = P::operator[](7); + T& ZZ = P::operator[](8); // -- Methods static MatrixXYZ identity() { return {1, 0, 0, 0, 1, 0, 0, 0, 1}; } MatrixXYZ inverse() const { - auto det = xx * (yy * zz - yz * zy) - xy * (yx * zz - yz * zx) + xz * (yx * zy - yy * zx); + auto det = XX * (YY * ZZ - YZ * ZY) - XY * (YX * ZZ - YZ * ZX) + XZ * (YX * ZY - YY * ZX); ASSERT_MSG(det != 0, "MatrixXYZ: singular matrix"); - return {(yy * zz - yz * zy) / det, (xz * zy - xy * zz) / det, (xy * yz - xz * yy) / det, - (yz * zx - yx * zz) / det, (xx * zz - xz * zx) / det, (xz * yx - xx * yz) / det, - (yx * zy - yy * zx) / det, (xy * zx - xx * zy) / det, (xx * yy - xy * yx) / det}; + return {(YY * ZZ - YZ * ZY) / det, (XZ * ZY - XY * ZZ) / det, (XY * YZ - XZ * YY) / det, + (YZ * ZX - YX * ZZ) / det, (XX * ZZ - XZ * ZX) / det, (XZ * YX - XX * YZ) / det, + (YX * ZY - YY * ZX) / det, (XY * ZX - XX * ZY) / det, (XX * YY - XY * YX) / det}; } // -- Overridden methods @@ -109,8 +109,8 @@ class MatrixXYZ final : protected std::array { // -- Friends friend std::ostream& operator<<(std::ostream& out, const MatrixXYZ& m) { - return out << "{{" << m.xx << ", " << m.xy << ", " << m.xz << "}, {" << m.yx << ", " << m.yy << ", " << m.yz - << "}, {" << m.zx << ", " << m.zy << ", " << m.zz << "}}"; + return out << "{{" << m.XX << ", " << m.XY << ", " << m.XZ << "}, {" << m.YX << ", " << m.YY << ", " << m.YZ + << "}, {" << m.ZX << ", " << m.ZY << ", " << m.ZZ << "}}"; } }; diff --git a/src/grit/types/PointXY.h b/src/grit/types/PointXY.h index 30125e99b..16b7ab1bf 100644 --- a/src/grit/types/PointXY.h +++ b/src/grit/types/PointXY.h @@ -59,13 +59,13 @@ class PointXY final : protected std::array { } bool is_approximately_equal(const PointXY& other, T eps) const { - return std::abs(x - other.x) < eps && std::abs(y - other.y) < eps; + return std::abs(X - other.X) < eps && std::abs(Y - other.Y) < eps; }; // -- Members - T& x = P::operator[](0); - T& y = P::operator[](1); + T& X = P::operator[](0); + T& Y = P::operator[](1); // -- Methods // None @@ -82,7 +82,7 @@ class PointXY final : protected std::array { // -- Friends friend std::ostream& operator<<(std::ostream& out, const PointXY& p) { - return out << '{' << p.x << ", " << p.y << '}'; + return out << '{' << p.X << ", " << p.Y << '}'; } }; diff --git a/src/grit/types/PointXYZ.h b/src/grit/types/PointXYZ.h index fd1b0eb06..a681c040d 100644 --- a/src/grit/types/PointXYZ.h +++ b/src/grit/types/PointXYZ.h @@ -59,14 +59,14 @@ class PointXYZ final : protected std::array { } bool is_approximately_equal(const PointXYZ& other, T eps) const { - return std::abs(x - other.x) < eps && std::abs(y - other.y) < eps && std::abs(z - other.z) < eps; + return std::abs(X - other.X) < eps && std::abs(Y - other.Y) < eps && std::abs(Z - other.Z) < eps; }; // -- Members - T& x = P::operator[](0); - T& y = P::operator[](1); - T& z = P::operator[](2); + T& X = P::operator[](0); + T& Y = P::operator[](1); + T& Z = P::operator[](2); // -- Methods // None @@ -80,13 +80,13 @@ class PointXYZ final : protected std::array { // -- Class methods static T distance2(const PointXYZ& a, const PointXYZ& b) { - return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z); + return (a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y) + (a.Z - b.Z) * (a.Z - b.Z); } // -- Friends friend std::ostream& operator<<(std::ostream& out, const PointXYZ& p) { - return out << '{' << p.x << ", " << p.y << ", " << p.z << '}'; + return out << '{' << p.X << ", " << p.Y << ", " << p.Z << '}'; } }; From 79417d9cbe1b3300b6e3ebcb42a42c39fedbb6b7 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 27 Apr 2023 15:56:22 +0100 Subject: [PATCH 179/737] search --- CMakeLists.txt | 9 +++++++ src/grit/CMakeLists.txt | 5 ++++ src/grit/Search.h | 54 +++++++++++++++++++++++++++++++++++++ src/grit/types/PointXY.h | 15 +++++++++-- src/grit/types/PointXYZ.h | 12 ++++++++- src/grit/util/Mutex.h | 4 +-- src/tools/CMakeLists.txt | 13 ++++++--- src/tools/grit-search.cc | 21 +++++++++++++++ tests/CMakeLists.txt | 6 +++++ tests/search.cc | 57 +++++++++++++++++++++++++++++++++++++++ 10 files changed, 187 insertions(+), 9 deletions(-) create mode 100644 src/grit/Search.h create mode 100644 src/tools/grit-search.cc create mode 100644 tests/search.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 9823d78c2..b5fdaab3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,16 +23,25 @@ endif() # dependencies (all optional) find_package(eccodes 2.29) option(REQUIRE_ECCODES "Require ecCodes") +message(STATUS "REQUIRE_ECCODES=${REQUIRE_ECCODES}, eccodes_FOUND=${eccodes_FOUND}") if(REQUIRE_ECCODES AND NOT eccodes_FOUND) message(FATAL_ERROR "eccodes_FOUND=${eccodes_FOUND}") endif() find_package(PROJ 9.2) option(REQUIRE_PROJ "Require PROJ") +message(STATUS "REQUIRE_PROJ=${REQUIRE_PROJ}, PROJ_FOUND=${PROJ_FOUND}") if(REQUIRE_PROJ AND NOT PROJ_FOUND) message(FATAL_ERROR "PROJ_FOUND=${PROJ_FOUND}") endif() +find_package(eckit) +option(REQUIRE_ECKIT "Require eckit") +message(STATUS "REQUIRE_ECKIT=${REQUIRE_ECKIT}, eckit_FOUND=${eckit_FOUND}") +if(REQUIRE_ECKIT AND NOT eckit_FOUND) + message(FATAL_ERROR "eckit_FOUND=${eckit_FOUND}") +endif() + # library/resources add_subdirectory(src) diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 7d6d77b66..348b48ae5 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -48,6 +48,11 @@ add_library(grit SHARED target_include_directories(grit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") +if(eckit_FOUND) + target_sources(grit PRIVATE Search.h) + target_link_libraries(grit eckit) +endif() + if(TARGET PROJ::proj) target_sources(grit PRIVATE projection/PROJ.cc projection/PROJ.h) target_link_libraries(grit PROJ::proj) diff --git a/src/grit/Search.h b/src/grit/Search.h new file mode 100644 index 000000000..372935705 --- /dev/null +++ b/src/grit/Search.h @@ -0,0 +1,54 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/container/KDTree.h" + +#ifdef ASSERT +#undef ASSERT +#endif + +#ifdef ASSERT_MSG +#undef ASSERT_MSG +#endif + +#ifdef NOTIMP +#undef NOTIMP +#endif + +#include "grit/types.h" + + +namespace grit { + + +namespace search { + + +template +struct Traits { + using Point = PointT; + using Payload = PayloadT; +}; + + +} // namespace search + + +using SearchXYZ = eckit::KDTreeMemory>; + + +using SearchXY = eckit::KDTreeMemory>; + + +} // namespace grit diff --git a/src/grit/types/PointXY.h b/src/grit/types/PointXY.h index 16b7ab1bf..6c72e09da 100644 --- a/src/grit/types/PointXY.h +++ b/src/grit/types/PointXY.h @@ -35,6 +35,7 @@ class PointXY final : protected std::array { // -- Constructors + PointXY() : P{0, 0} {} PointXY(T x, T y) : P{x, y} {} PointXY(const PointXY& other) : P(other) {} PointXY(PointXY&& other) : P(other) {} @@ -67,8 +68,11 @@ class PointXY final : protected std::array { T& X = P::operator[](0); T& Y = P::operator[](1); + static constexpr size_t DIMS = 2; + // -- Methods - // None + + T x(size_t dim) const { return P::at(dim); } // -- Overridden methods // None @@ -77,7 +81,14 @@ class PointXY final : protected std::array { // None // -- Class methods - // None + + static T distance(const PointXY& a, const PointXY& b, size_t dim) { return std::abs(a.x(dim) - b.x(dim)); } + + static T distance(const PointXY& a, const PointXY& b) { return std::sqrt(distance2(a, b)); } + + static T distance2(const PointXY& a, const PointXY& b) { + return (a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y); + } // -- Friends diff --git a/src/grit/types/PointXYZ.h b/src/grit/types/PointXYZ.h index a681c040d..87a0d1daf 100644 --- a/src/grit/types/PointXYZ.h +++ b/src/grit/types/PointXYZ.h @@ -13,6 +13,8 @@ #pragma once #include +#include +#include #include @@ -35,6 +37,7 @@ class PointXYZ final : protected std::array { // -- Constructors + PointXYZ() : P{0, 0, 0} {} PointXYZ(T x, T y, T z) : P{x, y, z} {} PointXYZ(const PointXYZ& other) : P(other) {} PointXYZ(PointXYZ&& other) : P(other) {} @@ -68,8 +71,11 @@ class PointXYZ final : protected std::array { T& Y = P::operator[](1); T& Z = P::operator[](2); + static constexpr size_t DIMS = 3; + // -- Methods - // None + + T x(size_t dim) const { return P::at(dim); } // -- Overridden methods // None @@ -79,6 +85,10 @@ class PointXYZ final : protected std::array { // -- Class methods + static T distance(const PointXYZ& a, const PointXYZ& b, size_t dim) { return std::abs(a.x(dim) - b.x(dim)); } + + static T distance(const PointXYZ& a, const PointXYZ& b) { return std::sqrt(distance2(a, b)); } + static T distance2(const PointXYZ& a, const PointXYZ& b) { return (a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y) + (a.Z - b.Z) * (a.Z - b.Z); } diff --git a/src/grit/util/Mutex.h b/src/grit/util/Mutex.h index 70a8d34e1..9e077c11b 100644 --- a/src/grit/util/Mutex.h +++ b/src/grit/util/Mutex.h @@ -14,7 +14,7 @@ #undef grit_ECKIT_THREADS -#if defined(grit_ECKIT_THREADS) +#ifdef grit_ECKIT_THREADS #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" #else @@ -25,7 +25,7 @@ namespace grit::util { -#if defined(grit_ECKIT_THREADS) +#ifdef grit_ECKIT_THREADS using recursive_mutex = eckit::Mutex; diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index f67b64467..8128ee903 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -1,8 +1,13 @@ +list(APPEND TOOLS + grit-version) -foreach(name - grit-version) - add_executable(${name} ${name}.cc) - target_link_libraries(${name} grit) +if(eckit_FOUND) + list(APPEND TOOLS grit-search) +endif() + +foreach(tool ${TOOLS}) + add_executable(${tool} ${tool}.cc) + target_link_libraries(${tool} grit) endforeach() if(TARGET eccodes) diff --git a/src/tools/grit-search.cc b/src/tools/grit-search.cc new file mode 100644 index 000000000..de66fc855 --- /dev/null +++ b/src/tools/grit-search.cc @@ -0,0 +1,21 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "grit/Search.h" + + +int main(int argc, const char* argv[]) { + return 0; +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a4e0619f9..265c8fda6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,3 +18,9 @@ if(PROJ_FOUND) add_test(test_projection_proj test_projection_proj) endif() +if(eckit_FOUND) + add_executable(test_search search.cc) + target_link_libraries(test_search grit eckit) + add_test(test_search test_search) +endif() + diff --git a/tests/search.cc b/tests/search.cc new file mode 100644 index 000000000..a0aa70bfe --- /dev/null +++ b/tests/search.cc @@ -0,0 +1,57 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "grit/Search.h" + + +int main(int argc, const char* argv[]) { + { + std::vector points{ + {{0, 0, 0}, 0}, + }; + + grit::SearchXYZ search; + search.build(points); + + std::cout << search.nearestNeighbour({0.1, 0, 0}) << std::endl; + std::cout << search.nearestNeighbour({0.9, 0, 0}) << std::endl; + + search.insert({{1, 0, 0}, 1}); + + std::cout << search.nearestNeighbour({0.1, 0, 0}) << std::endl; + std::cout << search.nearestNeighbour({0.9, 0, 0}) << std::endl; + } + + + { + std::vector points{ + {{0, 0}, 0}, + }; + + grit::SearchXY search; + search.build(points); + + std::cout << search.nearestNeighbour({0.1, 0}) << std::endl; + std::cout << search.nearestNeighbour({0.9, 0}) << std::endl; + + search.insert({{1, 0}, 1}); + + std::cout << search.nearestNeighbour({0.1, 0}) << std::endl; + std::cout << search.nearestNeighbour({0.9, 0}) << std::endl; + } + + + return 0; +} From 31da6c4e5b2f64b8a428d52729b0197076c34d8f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 27 Apr 2023 18:14:15 +0100 Subject: [PATCH 180/737] projection --- src/grit/CMakeLists.txt | 2 + src/grit/Projection.cc | 6 +-- src/grit/projection/LatLonToXYZ.h | 2 +- src/grit/projection/None.cc | 26 +++++++++++ src/grit/projection/None.h | 78 +++++++++++++++++++++++++++++++ src/grit/projection/Rotation.h | 2 +- tests/projection.cc | 9 ++++ 7 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 src/grit/projection/None.cc create mode 100644 src/grit/projection/None.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 348b48ae5..675b13669 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -25,6 +25,8 @@ add_library(grit SHARED param/Map.h projection/LatLonToXYZ.cc projection/LatLonToXYZ.h + projection/None.cc + projection/None.h projection/Rotation.cc projection/Rotation.h test.cc diff --git a/src/grit/Projection.cc b/src/grit/Projection.cc index c2ac915ff..e60164fb7 100644 --- a/src/grit/Projection.cc +++ b/src/grit/Projection.cc @@ -246,10 +246,10 @@ std::ostream& ProjectionFactory::list(std::ostream& out) { util::call_once(__once, __init); util::lock_guard lock(*__mutex); - const char* sep = ""; + const char* sep = "'"; for (const auto& j : *__factories) { - out << sep << j.first; - sep = ", "; + out << sep << j.first << '\''; + sep = ", '"; } return out; diff --git a/src/grit/projection/LatLonToXYZ.h b/src/grit/projection/LatLonToXYZ.h index e78de52bd..472354f5f 100644 --- a/src/grit/projection/LatLonToXYZ.h +++ b/src/grit/projection/LatLonToXYZ.h @@ -20,7 +20,7 @@ namespace grit::projection { -/// Compute coordinates of a point on a sphere or spheroid, in [x, y, z] +/// Calculate coordinates of a point on a sphere or spheroid, in [x, y, z] class LatLonToXYZ final : public Projection { public: // -- Exceptions diff --git a/src/grit/projection/None.cc b/src/grit/projection/None.cc new file mode 100644 index 000000000..7f1c34ad4 --- /dev/null +++ b/src/grit/projection/None.cc @@ -0,0 +1,26 @@ +/* + * (C) Copyright 1996- 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 "grit/projection/None.h" + + +namespace grit::projection { + + +static ProjectionBuilder __projection1(""); +static ProjectionBuilder __projection2("none"); + + +None::None(const Parametrisation&) {} + + +} // namespace grit::projection diff --git a/src/grit/projection/None.h b/src/grit/projection/None.h new file mode 100644 index 000000000..ee9739fa8 --- /dev/null +++ b/src/grit/projection/None.h @@ -0,0 +1,78 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/Projection.h" + + +namespace grit::projection { + + +class None final : public Projection { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + None() = default; + explicit None(const Parametrisation&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + Point fwd(const Point& p) const override { return p; } + Point inv(const Point& q) const override { return q; } + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::projection diff --git a/src/grit/projection/Rotation.h b/src/grit/projection/Rotation.h index 1dfd1b8f0..58e5a56b0 100644 --- a/src/grit/projection/Rotation.h +++ b/src/grit/projection/Rotation.h @@ -20,7 +20,7 @@ namespace grit::projection { -/// Compute coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle +/// Calculate coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle class Rotation final : public Projection { public: // -- Exceptions diff --git a/tests/projection.cc b/tests/projection.cc index fb0c883fd..5645436bb 100644 --- a/tests/projection.cc +++ b/tests/projection.cc @@ -24,8 +24,17 @@ int main(int argc, char* argv[]) { using grit::PointXYZ; using Projection = std::unique_ptr; + Point p = PointLatLon{1, 1}; + + { + std::unique_ptr projection(grit::ProjectionFactory::build("none", grit::param::Map{})); + EXPECT(p == projection->inv(p)); + EXPECT(p == projection->fwd(p)); + } + + { grit::param::Map param({ {"projection", "rotation"}, From fefc9c41cd329e1b4add71a56bccf9e4074f32b4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 27 Apr 2023 18:30:34 +0100 Subject: [PATCH 181/737] iterator --- tests/CMakeLists.txt | 34 ++++++++----------- tests/{param.cc => test_param.cc} | 0 tests/{projection.cc => test_projection.cc} | 0 ...to_xyz.cc => test_projection_ll_to_xyz.cc} | 0 ...ection_proj.cc => test_projection_proj.cc} | 0 ...otation.cc => test_projection_rotation.cc} | 0 tests/{search.cc => test_search.cc} | 0 tests/{types.cc => test_types.cc} | 0 tests/{util.cc => test_util.cc} | 0 9 files changed, 15 insertions(+), 19 deletions(-) rename tests/{param.cc => test_param.cc} (100%) rename tests/{projection.cc => test_projection.cc} (100%) rename tests/{projection_ll_to_xyz.cc => test_projection_ll_to_xyz.cc} (100%) rename tests/{projection_proj.cc => test_projection_proj.cc} (100%) rename tests/{projection_rotation.cc => test_projection_rotation.cc} (100%) rename tests/{search.cc => test_search.cc} (100%) rename tests/{types.cc => test_types.cc} (100%) rename tests/{util.cc => test_util.cc} (100%) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 265c8fda6..7acd79a14 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,26 +1,22 @@ -include(CTest) - -foreach(name - param - projection - projection_ll_to_xyz - projection_rotation - types - util) - add_executable(test_${name} ${name}.cc) - target_link_libraries(test_${name} grit) - add_test(test_${name} test_${name}) -endforeach() +list(APPEND TESTS + test_param + test_projection + test_projection_ll_to_xyz + test_projection_rotation + test_types + test_util) if(PROJ_FOUND) - add_executable(test_projection_proj projection_proj.cc) - target_link_libraries(test_projection_proj grit) - add_test(test_projection_proj test_projection_proj) + list(APPEND TESTS test_projection_proj) endif() if(eckit_FOUND) - add_executable(test_search search.cc) - target_link_libraries(test_search grit eckit) - add_test(test_search test_search) + list(APPEND TESTS test_search) endif() +foreach(test ${TESTS}) + add_executable(${test} ${test}.cc) + target_link_libraries(${test} grit) + add_test(${test} ${test}) +endforeach() + diff --git a/tests/param.cc b/tests/test_param.cc similarity index 100% rename from tests/param.cc rename to tests/test_param.cc diff --git a/tests/projection.cc b/tests/test_projection.cc similarity index 100% rename from tests/projection.cc rename to tests/test_projection.cc diff --git a/tests/projection_ll_to_xyz.cc b/tests/test_projection_ll_to_xyz.cc similarity index 100% rename from tests/projection_ll_to_xyz.cc rename to tests/test_projection_ll_to_xyz.cc diff --git a/tests/projection_proj.cc b/tests/test_projection_proj.cc similarity index 100% rename from tests/projection_proj.cc rename to tests/test_projection_proj.cc diff --git a/tests/projection_rotation.cc b/tests/test_projection_rotation.cc similarity index 100% rename from tests/projection_rotation.cc rename to tests/test_projection_rotation.cc diff --git a/tests/search.cc b/tests/test_search.cc similarity index 100% rename from tests/search.cc rename to tests/test_search.cc diff --git a/tests/types.cc b/tests/test_types.cc similarity index 100% rename from tests/types.cc rename to tests/test_types.cc diff --git a/tests/util.cc b/tests/test_util.cc similarity index 100% rename from tests/util.cc rename to tests/test_util.cc From 39dee0d4ed59afd3f95adb2c789b922e266aeaac Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 27 Apr 2023 18:56:36 +0100 Subject: [PATCH 182/737] iterator --- src/grit/CMakeLists.txt | 4 +- src/grit/Iterator.h | 36 +++++----- src/grit/Scanner.h | 5 +- src/grit/iterator/IteratorAggregator.h | 92 ++++++++++++++++++++++++++ src/grit/iterator/IteratorComposer.cc | 49 ++++++++++++++ src/grit/iterator/IteratorComposer.h | 88 ++++++++++++++++++++++++ 6 files changed, 251 insertions(+), 23 deletions(-) create mode 100644 src/grit/iterator/IteratorAggregator.h create mode 100644 src/grit/iterator/IteratorComposer.cc create mode 100644 src/grit/iterator/IteratorComposer.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 675b13669..250410a2d 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -3,7 +3,9 @@ configure_file(grit.h.in grit.h) add_library(grit SHARED Parametrisation.cc Parametrisation.h - Iterator.cc + iterator/IteratorAggregator.h + iterator/IteratorComposer.cc + iterator/IteratorComposer.h Iterator.h Projection.cc Projection.h diff --git a/src/grit/Iterator.h b/src/grit/Iterator.h index 471cc9aed..3c6757500 100644 --- a/src/grit/Iterator.h +++ b/src/grit/Iterator.h @@ -10,27 +10,21 @@ */ -#include +#pragma once #include "grit/types.h" namespace grit { -struct Projection; -struct Scanner; -} // namespace grit - -namespace grit { - -class Iterator final { +class Iterator { public: // -- Types using value_type = Point; -private: +protected: // -- Types template @@ -56,6 +50,10 @@ class Iterator final { const typename X::value_type& operator*() const { return cnt.at(pos); } }; + // -- Constructors + + Iterator() = default; + public: // -- Types @@ -67,29 +65,27 @@ class Iterator final { // -- Constructors - Iterator(Scanner*, Projection*); - Iterator(const Iterator&) = delete; Iterator(Iterator&&) = delete; - Iterator& operator=(const Iterator&) = delete; - Iterator& operator=(Iterator&&) = delete; - // -- Destructor - ~Iterator() = delete; + virtual ~Iterator() = default; // -- Convertors // None // -- Operators - bool operator++(); - bool operator++(int) { return operator++(); } + Iterator& operator=(const Iterator&) = delete; + Iterator& operator=(Iterator&&) = delete; + + virtual bool operator++() = 0; + virtual bool operator++(int) = 0; // -- Methods - size_t size() const; + virtual size_t size() const = 0; iterator begin() { return {*this, 0}; } iterator end() { return {*this, this->size()}; } @@ -111,9 +107,7 @@ class Iterator final { private: // -- Members - - std::unique_ptr scanner_; - std::unique_ptr projection_; + // None // -- Methods // None diff --git a/src/grit/Scanner.h b/src/grit/Scanner.h index 500bc4dbd..d60d9e722 100644 --- a/src/grit/Scanner.h +++ b/src/grit/Scanner.h @@ -10,6 +10,8 @@ */ +#pragma once + #include @@ -41,7 +43,8 @@ class Scanner { Scanner& operator=(const Scanner&) = delete; Scanner& operator=(Scanner&&) = delete; - virtual bool operator++() = 0; + virtual bool operator++() = 0; + virtual bool operator++(int) = 0; // -- Methods diff --git a/src/grit/iterator/IteratorAggregator.h b/src/grit/iterator/IteratorAggregator.h new file mode 100644 index 000000000..879b54834 --- /dev/null +++ b/src/grit/iterator/IteratorAggregator.h @@ -0,0 +1,92 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/Iterator.h" + + +namespace grit::iterator { + + +class IteratorAggregator { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + IteratorAggregator(); + + // -- Destructor + + virtual ~IteratorAggregator() = default; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::iterator diff --git a/src/grit/iterator/IteratorComposer.cc b/src/grit/iterator/IteratorComposer.cc new file mode 100644 index 000000000..3451d6574 --- /dev/null +++ b/src/grit/iterator/IteratorComposer.cc @@ -0,0 +1,49 @@ +/* + * (C) Copyright 1996- 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 "grit/iterator/IteratorComposer.h" + +#include "grit/Projection.h" +#include "grit/Scanner.h" +#include "grit/exception.h" + + +namespace grit::iterator { + + +IteratorComposer::IteratorComposer(Scanner* scanner, const std::vector& projections) : scanner_(scanner) { + ASSERT(scanner_); + + projections_.reserve(projections.size()); + for (auto* p : projections) { + ASSERT(p != nullptr); + projections_.emplace_back(p); + } +} + + +bool IteratorComposer::operator++() { + return scanner_->operator++(); +} + + +bool IteratorComposer::operator++(int) { + return scanner_->operator++(0); +} + + +size_t IteratorComposer::size() const { + return scanner_->size(); +} + + +} // namespace grit::iterator diff --git a/src/grit/iterator/IteratorComposer.h b/src/grit/iterator/IteratorComposer.h new file mode 100644 index 000000000..741ce7c24 --- /dev/null +++ b/src/grit/iterator/IteratorComposer.h @@ -0,0 +1,88 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "grit/Iterator.h" + + +namespace grit { +struct Projection; +struct Scanner; +} // namespace grit + + +namespace grit::iterator { + + +class IteratorComposer final : public Iterator { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit IteratorComposer(Scanner*, const std::vector& = {}); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + bool operator++() override; + bool operator++(int) override; + + // -- Methods + + size_t size() const override; + const std::vector> projections() const; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + std::unique_ptr scanner_; + std::vector> projections_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::iterator From 606a105675920ac799065ae523937a00db26903f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 27 Apr 2023 21:39:50 +0100 Subject: [PATCH 183/737] iterator --- src/grit/iterator/IteratorAggregator.h | 5 ++--- src/grit/iterator/IteratorComposer.cc | 2 -- src/grit/iterator/IteratorComposer.h | 10 ++++------ tests/CMakeLists.txt | 1 + tests/test_iterator.cc | 26 ++++++++++++++++++++++++++ 5 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 tests/test_iterator.cc diff --git a/src/grit/iterator/IteratorAggregator.h b/src/grit/iterator/IteratorAggregator.h index 879b54834..77f4f5d31 100644 --- a/src/grit/iterator/IteratorAggregator.h +++ b/src/grit/iterator/IteratorAggregator.h @@ -18,7 +18,7 @@ namespace grit::iterator { -class IteratorAggregator { +class IteratorAggregator final : public Iterator { public: // -- Types // None @@ -31,8 +31,7 @@ class IteratorAggregator { IteratorAggregator(); // -- Destructor - - virtual ~IteratorAggregator() = default; + // None // -- Convertors // None diff --git a/src/grit/iterator/IteratorComposer.cc b/src/grit/iterator/IteratorComposer.cc index 3451d6574..58c9c2357 100644 --- a/src/grit/iterator/IteratorComposer.cc +++ b/src/grit/iterator/IteratorComposer.cc @@ -12,8 +12,6 @@ #include "grit/iterator/IteratorComposer.h" -#include "grit/Projection.h" -#include "grit/Scanner.h" #include "grit/exception.h" diff --git a/src/grit/iterator/IteratorComposer.h b/src/grit/iterator/IteratorComposer.h index 741ce7c24..fd0c823e1 100644 --- a/src/grit/iterator/IteratorComposer.h +++ b/src/grit/iterator/IteratorComposer.h @@ -10,16 +10,14 @@ */ +#pragma once + #include #include #include "grit/Iterator.h" - - -namespace grit { -struct Projection; -struct Scanner; -} // namespace grit +#include "grit/Projection.h" +#include "grit/Scanner.h" namespace grit::iterator { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7acd79a14..fd20b2f5f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,4 +1,5 @@ list(APPEND TESTS + test_iterator test_param test_projection test_projection_ll_to_xyz diff --git a/tests/test_iterator.cc b/tests/test_iterator.cc new file mode 100644 index 000000000..5ced4c4bf --- /dev/null +++ b/tests/test_iterator.cc @@ -0,0 +1,26 @@ +/* + * (C) Copyright 1996- 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 +// #include + +#include "grit/iterator/IteratorAggregator.h" +#include "grit/iterator/IteratorComposer.h" + + +int main(int argc, const char* argv[]) { + + grit::iterator::IteratorComposer it(nullptr); + + + return 0; +} From 08c957dc55a30c31937f9944c0c1877ee947665e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 28 Apr 2023 09:50:44 +0100 Subject: [PATCH 184/737] iterator --- src/grit/Scanner.h | 4 ++++ src/grit/iterator/IteratorAggregator.h | 10 +++++++--- tests/test_iterator.cc | 14 ++++++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/grit/Scanner.h b/src/grit/Scanner.h index d60d9e722..24cf1d7b2 100644 --- a/src/grit/Scanner.h +++ b/src/grit/Scanner.h @@ -60,6 +60,10 @@ class Scanner { // None protected: + // -- Constructors + + Scanner() = default; + // -- Members // None diff --git a/src/grit/iterator/IteratorAggregator.h b/src/grit/iterator/IteratorAggregator.h index 77f4f5d31..41bf02a13 100644 --- a/src/grit/iterator/IteratorAggregator.h +++ b/src/grit/iterator/IteratorAggregator.h @@ -18,7 +18,8 @@ namespace grit::iterator { -class IteratorAggregator final : public Iterator { +template +class IteratorAggregator final : public Iterator, protected Scanner { public: // -- Types // None @@ -28,7 +29,7 @@ class IteratorAggregator final : public Iterator { // -- Constructors - IteratorAggregator(); + IteratorAggregator() = default; // -- Destructor // None @@ -75,7 +76,10 @@ class IteratorAggregator final : public Iterator { // None // -- Overridden methods - // None + + bool operator++() override { return Scanner::operator++(); } + bool operator++(int) override { return Scanner::operator++(0); } + size_t size() const override { return Scanner::size(); } // -- Class members // None diff --git a/tests/test_iterator.cc b/tests/test_iterator.cc index 5ced4c4bf..30388290a 100644 --- a/tests/test_iterator.cc +++ b/tests/test_iterator.cc @@ -11,15 +11,25 @@ #include -// #include +#include "grit/Scanner.h" +#include "grit/exception.h" #include "grit/iterator/IteratorAggregator.h" #include "grit/iterator/IteratorComposer.h" int main(int argc, const char* argv[]) { - grit::iterator::IteratorComposer it(nullptr); + grit::iterator::IteratorComposer i(nullptr); + + + struct ScannerTest : public grit::Scanner { + bool operator++() override { NOTIMP; } + bool operator++(int) override { NOTIMP; } + size_t size() const override { NOTIMP; } + }; + + grit::iterator::IteratorAggregator j; return 0; From 40e082d6dc0b1c3a09efbbea53c3ee1f6f6d1a64 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 9 May 2023 15:03:37 +0100 Subject: [PATCH 185/737] scanner --- src/grit/CMakeLists.txt | 6 +++ src/grit/Scanner.h | 3 +- src/grit/scanner/Reduced.cc | 34 ++++++++++++++ src/grit/scanner/Reduced.h | 77 ++++++++++++++++++++++++++++++++ src/grit/scanner/Regular.cc | 34 ++++++++++++++ src/grit/scanner/Regular.h | 77 ++++++++++++++++++++++++++++++++ src/grit/scanner/Unstructured.cc | 34 ++++++++++++++ src/grit/scanner/Unstructured.h | 77 ++++++++++++++++++++++++++++++++ 8 files changed, 340 insertions(+), 2 deletions(-) create mode 100644 src/grit/scanner/Reduced.cc create mode 100644 src/grit/scanner/Reduced.h create mode 100644 src/grit/scanner/Regular.cc create mode 100644 src/grit/scanner/Regular.h create mode 100644 src/grit/scanner/Unstructured.cc create mode 100644 src/grit/scanner/Unstructured.h diff --git a/src/grit/CMakeLists.txt b/src/grit/CMakeLists.txt index 250410a2d..1fc094fb1 100644 --- a/src/grit/CMakeLists.txt +++ b/src/grit/CMakeLists.txt @@ -31,6 +31,12 @@ add_library(grit SHARED projection/None.h projection/Rotation.cc projection/Rotation.h + scanner/Reduced.cc + scanner/Reduced.h + scanner/Regular.cc + scanner/Regular.h + scanner/Unstructured.cc + scanner/Unstructured.h test.cc test.h types.cc diff --git a/src/grit/Scanner.h b/src/grit/Scanner.h index 24cf1d7b2..b87003281 100644 --- a/src/grit/Scanner.h +++ b/src/grit/Scanner.h @@ -43,8 +43,7 @@ class Scanner { Scanner& operator=(const Scanner&) = delete; Scanner& operator=(Scanner&&) = delete; - virtual bool operator++() = 0; - virtual bool operator++(int) = 0; + virtual bool operator++() = 0; // -- Methods diff --git a/src/grit/scanner/Reduced.cc b/src/grit/scanner/Reduced.cc new file mode 100644 index 000000000..fc63bcaa3 --- /dev/null +++ b/src/grit/scanner/Reduced.cc @@ -0,0 +1,34 @@ +/* + * (C) Copyright 1996- 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 "grit/scanner/Reduced.h" + +// #include <> + + +namespace grit::scanner { + + +Reduced::Reduced() = default; + + +bool Reduced::operator++() { + return false; +} + + +size_t Reduced::size() const { + return 0; +} + + +} // namespace grit::scanner diff --git a/src/grit/scanner/Reduced.h b/src/grit/scanner/Reduced.h new file mode 100644 index 000000000..6231171a7 --- /dev/null +++ b/src/grit/scanner/Reduced.h @@ -0,0 +1,77 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/Scanner.h" + + +namespace grit::scanner { + + +class Reduced final : public Scanner { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + Reduced(); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + bool operator++() override; + size_t size() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::scanner diff --git a/src/grit/scanner/Regular.cc b/src/grit/scanner/Regular.cc new file mode 100644 index 000000000..bf320bea7 --- /dev/null +++ b/src/grit/scanner/Regular.cc @@ -0,0 +1,34 @@ +/* + * (C) Copyright 1996- 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 "grit/scanner/Regular.h" + +// #include <> + + +namespace grit::scanner { + + +Regular::Regular() = default; + + +bool Regular::operator++() { + return false; +} + + +size_t Regular::size() const { + return 0; +} + + +} // namespace grit::scanner diff --git a/src/grit/scanner/Regular.h b/src/grit/scanner/Regular.h new file mode 100644 index 000000000..175cbe1c9 --- /dev/null +++ b/src/grit/scanner/Regular.h @@ -0,0 +1,77 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/Scanner.h" + + +namespace grit::scanner { + + +class Regular final : public Scanner { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + Regular(); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + bool operator++() override; + size_t size() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::scanner diff --git a/src/grit/scanner/Unstructured.cc b/src/grit/scanner/Unstructured.cc new file mode 100644 index 000000000..d75ae6d58 --- /dev/null +++ b/src/grit/scanner/Unstructured.cc @@ -0,0 +1,34 @@ +/* + * (C) Copyright 1996- 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 "grit/scanner/Unstructured.h" + +// #include <> + + +namespace grit::scanner { + + +Unstructured::Unstructured() = default; + + +bool Unstructured::operator++() { + return false; +} + + +size_t Unstructured::size() const { + return 0; +} + + +} // namespace grit::scanner diff --git a/src/grit/scanner/Unstructured.h b/src/grit/scanner/Unstructured.h new file mode 100644 index 000000000..3e2209f5e --- /dev/null +++ b/src/grit/scanner/Unstructured.h @@ -0,0 +1,77 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "grit/Scanner.h" + + +namespace grit::scanner { + + +class Unstructured final : public Scanner { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + Unstructured(); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + bool operator++() override; + size_t size() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace grit::scanner From 36460e09a0ef8a808f183b7a268b4e7633d1afd4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 9 May 2023 16:58:28 +0100 Subject: [PATCH 186/737] move --- CMakeLists.txt | 78 ------- LICENSE | 201 ------------------ README.md | 2 - etc/CMakeLists.txt | 2 - etc/grit/CMakeLists.txt | 1 - share/CMakeLists.txt | 2 - share/grit/CMakeLists.txt | 1 - src/CMakeLists.txt | 5 - src/{grit => eckit/geo}/CMakeLists.txt | 0 src/{grit => eckit/geo}/Iterator.cc | 0 src/{grit => eckit/geo}/Iterator.h | 0 src/{grit => eckit/geo}/Parametrisation.cc | 0 src/{grit => eckit/geo}/Parametrisation.h | 0 src/{grit => eckit/geo}/Projection.cc | 0 src/{grit => eckit/geo}/Projection.h | 0 src/{grit => eckit/geo}/Scanner.cc | 0 src/{grit => eckit/geo}/Scanner.h | 0 src/{grit => eckit/geo}/Search.h | 0 src/{grit => eckit/geo}/exception.h | 0 .../geo}/geometry/BoundingBox.cc | 0 .../geo}/geometry/BoundingBox.h | 0 .../geo}/geometry/GreatCircle.cc | 0 .../geo}/geometry/GreatCircle.h | 0 src/{grit => eckit/geo}/geometry/Sphere.cc | 0 src/{grit => eckit/geo}/geometry/Sphere.h | 0 src/{grit => eckit/geo}/geometry/Spheroid.cc | 0 src/{grit => eckit/geo}/geometry/Spheroid.h | 0 src/{grit => eckit/geo}/geometry/UnitSphere.h | 0 src/{tools => eckit/geo}/grit-grib.cc | 0 src/{tools => eckit/geo}/grit-search.cc | 0 src/{tools => eckit/geo}/grit-version.cc | 0 src/{grit => eckit/geo}/grit.h.in | 0 .../geo}/iterator/IteratorAggregator.h | 0 .../geo}/iterator/IteratorComposer.cc | 0 .../geo}/iterator/IteratorComposer.h | 0 src/{grit => eckit/geo}/log.cc | 0 src/{grit => eckit/geo}/log.h | 0 src/{grit => eckit/geo}/param/Map.cc | 0 src/{grit => eckit/geo}/param/Map.h | 0 .../geo}/projection/LatLonToXYZ.cc | 0 .../geo}/projection/LatLonToXYZ.h | 0 src/{grit => eckit/geo}/projection/None.cc | 0 src/{grit => eckit/geo}/projection/None.h | 0 src/{grit => eckit/geo}/projection/PROJ.cc | 0 src/{grit => eckit/geo}/projection/PROJ.h | 0 .../geo}/projection/Rotation.cc | 0 src/{grit => eckit/geo}/projection/Rotation.h | 0 {tests => src/eckit/geo}/reduced_gg.grib2 | Bin {tests => src/eckit/geo}/reduced_ll.grib1 | Bin {tests => src/eckit/geo}/regular_gg.grib1 | Bin {tests => src/eckit/geo}/regular_ll.grib1 | Bin src/{grit => eckit/geo}/scanner/Reduced.cc | 0 src/{grit => eckit/geo}/scanner/Reduced.h | 0 src/{grit => eckit/geo}/scanner/Regular.cc | 0 src/{grit => eckit/geo}/scanner/Regular.h | 0 .../geo}/scanner/Unstructured.cc | 0 .../geo}/scanner/Unstructured.h | 0 src/{grit => eckit/geo}/test.cc | 0 src/{grit => eckit/geo}/test.h | 0 {tests => src/eckit/geo}/test_iterator.cc | 0 {tests => src/eckit/geo}/test_param.cc | 0 {tests => src/eckit/geo}/test_projection.cc | 0 .../eckit/geo}/test_projection_ll_to_xyz.cc | 0 .../eckit/geo}/test_projection_proj.cc | 0 .../eckit/geo}/test_projection_rotation.cc | 0 {tests => src/eckit/geo}/test_search.cc | 0 {tests => src/eckit/geo}/test_types.cc | 0 {tests => src/eckit/geo}/test_util.cc | 0 src/{grit => eckit/geo}/types.cc | 0 src/{grit => eckit/geo}/types.h | 0 src/{grit => eckit/geo}/types/MatrixXYZ.h | 0 src/{grit => eckit/geo}/types/PointLatLon.h | 0 src/{grit => eckit/geo}/types/PointXY.h | 0 src/{grit => eckit/geo}/types/PointXYZ.h | 0 src/{grit => eckit/geo}/util.cc | 0 src/{grit => eckit/geo}/util.h | 0 src/{grit => eckit/geo}/util/Mutex.h | 0 src/{grit => eckit/geo}/util/arange.cc | 0 .../geo}/util/gaussian_latitudes.cc | 0 src/{grit => eckit/geo}/util/linspace.cc | 0 .../geo}/util/monotonic_crop.cc | 0 .../geo}/util/reduced_classical_pl.cc | 0 .../geo}/util/reduced_octahedral_pl.cc | 0 src/{grit => eckit/geo}/util/regular_pl.cc | 0 src/tools/CMakeLists.txt | 17 -- tests/CMakeLists.txt | 23 -- 86 files changed, 332 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 LICENSE delete mode 100644 README.md delete mode 100644 etc/CMakeLists.txt delete mode 100644 etc/grit/CMakeLists.txt delete mode 100644 share/CMakeLists.txt delete mode 100644 share/grit/CMakeLists.txt delete mode 100644 src/CMakeLists.txt rename src/{grit => eckit/geo}/CMakeLists.txt (100%) rename src/{grit => eckit/geo}/Iterator.cc (100%) rename src/{grit => eckit/geo}/Iterator.h (100%) rename src/{grit => eckit/geo}/Parametrisation.cc (100%) rename src/{grit => eckit/geo}/Parametrisation.h (100%) rename src/{grit => eckit/geo}/Projection.cc (100%) rename src/{grit => eckit/geo}/Projection.h (100%) rename src/{grit => eckit/geo}/Scanner.cc (100%) rename src/{grit => eckit/geo}/Scanner.h (100%) rename src/{grit => eckit/geo}/Search.h (100%) rename src/{grit => eckit/geo}/exception.h (100%) rename src/{grit => eckit/geo}/geometry/BoundingBox.cc (100%) rename src/{grit => eckit/geo}/geometry/BoundingBox.h (100%) rename src/{grit => eckit/geo}/geometry/GreatCircle.cc (100%) rename src/{grit => eckit/geo}/geometry/GreatCircle.h (100%) rename src/{grit => eckit/geo}/geometry/Sphere.cc (100%) rename src/{grit => eckit/geo}/geometry/Sphere.h (100%) rename src/{grit => eckit/geo}/geometry/Spheroid.cc (100%) rename src/{grit => eckit/geo}/geometry/Spheroid.h (100%) rename src/{grit => eckit/geo}/geometry/UnitSphere.h (100%) rename src/{tools => eckit/geo}/grit-grib.cc (100%) rename src/{tools => eckit/geo}/grit-search.cc (100%) rename src/{tools => eckit/geo}/grit-version.cc (100%) rename src/{grit => eckit/geo}/grit.h.in (100%) rename src/{grit => eckit/geo}/iterator/IteratorAggregator.h (100%) rename src/{grit => eckit/geo}/iterator/IteratorComposer.cc (100%) rename src/{grit => eckit/geo}/iterator/IteratorComposer.h (100%) rename src/{grit => eckit/geo}/log.cc (100%) rename src/{grit => eckit/geo}/log.h (100%) rename src/{grit => eckit/geo}/param/Map.cc (100%) rename src/{grit => eckit/geo}/param/Map.h (100%) rename src/{grit => eckit/geo}/projection/LatLonToXYZ.cc (100%) rename src/{grit => eckit/geo}/projection/LatLonToXYZ.h (100%) rename src/{grit => eckit/geo}/projection/None.cc (100%) rename src/{grit => eckit/geo}/projection/None.h (100%) rename src/{grit => eckit/geo}/projection/PROJ.cc (100%) rename src/{grit => eckit/geo}/projection/PROJ.h (100%) rename src/{grit => eckit/geo}/projection/Rotation.cc (100%) rename src/{grit => eckit/geo}/projection/Rotation.h (100%) rename {tests => src/eckit/geo}/reduced_gg.grib2 (100%) rename {tests => src/eckit/geo}/reduced_ll.grib1 (100%) rename {tests => src/eckit/geo}/regular_gg.grib1 (100%) rename {tests => src/eckit/geo}/regular_ll.grib1 (100%) rename src/{grit => eckit/geo}/scanner/Reduced.cc (100%) rename src/{grit => eckit/geo}/scanner/Reduced.h (100%) rename src/{grit => eckit/geo}/scanner/Regular.cc (100%) rename src/{grit => eckit/geo}/scanner/Regular.h (100%) rename src/{grit => eckit/geo}/scanner/Unstructured.cc (100%) rename src/{grit => eckit/geo}/scanner/Unstructured.h (100%) rename src/{grit => eckit/geo}/test.cc (100%) rename src/{grit => eckit/geo}/test.h (100%) rename {tests => src/eckit/geo}/test_iterator.cc (100%) rename {tests => src/eckit/geo}/test_param.cc (100%) rename {tests => src/eckit/geo}/test_projection.cc (100%) rename {tests => src/eckit/geo}/test_projection_ll_to_xyz.cc (100%) rename {tests => src/eckit/geo}/test_projection_proj.cc (100%) rename {tests => src/eckit/geo}/test_projection_rotation.cc (100%) rename {tests => src/eckit/geo}/test_search.cc (100%) rename {tests => src/eckit/geo}/test_types.cc (100%) rename {tests => src/eckit/geo}/test_util.cc (100%) rename src/{grit => eckit/geo}/types.cc (100%) rename src/{grit => eckit/geo}/types.h (100%) rename src/{grit => eckit/geo}/types/MatrixXYZ.h (100%) rename src/{grit => eckit/geo}/types/PointLatLon.h (100%) rename src/{grit => eckit/geo}/types/PointXY.h (100%) rename src/{grit => eckit/geo}/types/PointXYZ.h (100%) rename src/{grit => eckit/geo}/util.cc (100%) rename src/{grit => eckit/geo}/util.h (100%) rename src/{grit => eckit/geo}/util/Mutex.h (100%) rename src/{grit => eckit/geo}/util/arange.cc (100%) rename src/{grit => eckit/geo}/util/gaussian_latitudes.cc (100%) rename src/{grit => eckit/geo}/util/linspace.cc (100%) rename src/{grit => eckit/geo}/util/monotonic_crop.cc (100%) rename src/{grit => eckit/geo}/util/reduced_classical_pl.cc (100%) rename src/{grit => eckit/geo}/util/reduced_octahedral_pl.cc (100%) rename src/{grit => eckit/geo}/util/regular_pl.cc (100%) delete mode 100644 src/tools/CMakeLists.txt delete mode 100644 tests/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index b5fdaab3b..000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,78 +0,0 @@ -# (C) Copyright 1996- 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. - - -cmake_minimum_required(VERSION 3.14 FATAL_ERROR) - -project(grit VERSION 0.0.0 LANGUAGES CXX) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) - -if(APPLE) - set(CMAKE_INSTALL_RPATH_USE_LINK_PATH ON) -endif() - - -# dependencies (all optional) -find_package(eccodes 2.29) -option(REQUIRE_ECCODES "Require ecCodes") -message(STATUS "REQUIRE_ECCODES=${REQUIRE_ECCODES}, eccodes_FOUND=${eccodes_FOUND}") -if(REQUIRE_ECCODES AND NOT eccodes_FOUND) - message(FATAL_ERROR "eccodes_FOUND=${eccodes_FOUND}") -endif() - -find_package(PROJ 9.2) -option(REQUIRE_PROJ "Require PROJ") -message(STATUS "REQUIRE_PROJ=${REQUIRE_PROJ}, PROJ_FOUND=${PROJ_FOUND}") -if(REQUIRE_PROJ AND NOT PROJ_FOUND) - message(FATAL_ERROR "PROJ_FOUND=${PROJ_FOUND}") -endif() - -find_package(eckit) -option(REQUIRE_ECKIT "Require eckit") -message(STATUS "REQUIRE_ECKIT=${REQUIRE_ECKIT}, eckit_FOUND=${eckit_FOUND}") -if(REQUIRE_ECKIT AND NOT eckit_FOUND) - message(FATAL_ERROR "eckit_FOUND=${eckit_FOUND}") -endif() - - -# library/resources -add_subdirectory(src) -add_subdirectory(etc) -add_subdirectory(share) - -macro(get_all_targets targets dir) - get_property(subdirs DIRECTORY ${dir} PROPERTY SUBDIRECTORIES) - foreach(subdir ${subdirs}) - get_all_targets(${targets} ${subdir}) - endforeach() - - get_property(current_targets DIRECTORY ${dir} PROPERTY BUILDSYSTEM_TARGETS) - list(APPEND ${targets} ${current_targets}) -endmacro() - -set(all_targets) -get_all_targets(all_targets ${CMAKE_CURRENT_SOURCE_DIR}) - -install( - TARGETS ${all_targets} - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib - PUBLIC_HEADER DESTINATION include - RUNTIME DESTINATION bin) - - -# tests -include(CTest) -if(BUILD_TESTING) - add_subdirectory(tests) -endif() - - diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9e9..000000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/README.md b/README.md deleted file mode 100644 index 9b83875b5..000000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# grit -Geospatial Grid definitions and iterators library diff --git a/etc/CMakeLists.txt b/etc/CMakeLists.txt deleted file mode 100644 index 4827d7957..000000000 --- a/etc/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(grit) - diff --git a/etc/grit/CMakeLists.txt b/etc/grit/CMakeLists.txt deleted file mode 100644 index 8b1378917..000000000 --- a/etc/grit/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt deleted file mode 100644 index 4827d7957..000000000 --- a/share/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(grit) - diff --git a/share/grit/CMakeLists.txt b/share/grit/CMakeLists.txt deleted file mode 100644 index 8b1378917..000000000 --- a/share/grit/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index bd1c6a472..000000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -include_directories(BEFORE . ${CMAKE_CURRENT_BINARY_DIR}) - -add_subdirectory(grit) -add_subdirectory(tools) - diff --git a/src/grit/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt similarity index 100% rename from src/grit/CMakeLists.txt rename to src/eckit/geo/CMakeLists.txt diff --git a/src/grit/Iterator.cc b/src/eckit/geo/Iterator.cc similarity index 100% rename from src/grit/Iterator.cc rename to src/eckit/geo/Iterator.cc diff --git a/src/grit/Iterator.h b/src/eckit/geo/Iterator.h similarity index 100% rename from src/grit/Iterator.h rename to src/eckit/geo/Iterator.h diff --git a/src/grit/Parametrisation.cc b/src/eckit/geo/Parametrisation.cc similarity index 100% rename from src/grit/Parametrisation.cc rename to src/eckit/geo/Parametrisation.cc diff --git a/src/grit/Parametrisation.h b/src/eckit/geo/Parametrisation.h similarity index 100% rename from src/grit/Parametrisation.h rename to src/eckit/geo/Parametrisation.h diff --git a/src/grit/Projection.cc b/src/eckit/geo/Projection.cc similarity index 100% rename from src/grit/Projection.cc rename to src/eckit/geo/Projection.cc diff --git a/src/grit/Projection.h b/src/eckit/geo/Projection.h similarity index 100% rename from src/grit/Projection.h rename to src/eckit/geo/Projection.h diff --git a/src/grit/Scanner.cc b/src/eckit/geo/Scanner.cc similarity index 100% rename from src/grit/Scanner.cc rename to src/eckit/geo/Scanner.cc diff --git a/src/grit/Scanner.h b/src/eckit/geo/Scanner.h similarity index 100% rename from src/grit/Scanner.h rename to src/eckit/geo/Scanner.h diff --git a/src/grit/Search.h b/src/eckit/geo/Search.h similarity index 100% rename from src/grit/Search.h rename to src/eckit/geo/Search.h diff --git a/src/grit/exception.h b/src/eckit/geo/exception.h similarity index 100% rename from src/grit/exception.h rename to src/eckit/geo/exception.h diff --git a/src/grit/geometry/BoundingBox.cc b/src/eckit/geo/geometry/BoundingBox.cc similarity index 100% rename from src/grit/geometry/BoundingBox.cc rename to src/eckit/geo/geometry/BoundingBox.cc diff --git a/src/grit/geometry/BoundingBox.h b/src/eckit/geo/geometry/BoundingBox.h similarity index 100% rename from src/grit/geometry/BoundingBox.h rename to src/eckit/geo/geometry/BoundingBox.h diff --git a/src/grit/geometry/GreatCircle.cc b/src/eckit/geo/geometry/GreatCircle.cc similarity index 100% rename from src/grit/geometry/GreatCircle.cc rename to src/eckit/geo/geometry/GreatCircle.cc diff --git a/src/grit/geometry/GreatCircle.h b/src/eckit/geo/geometry/GreatCircle.h similarity index 100% rename from src/grit/geometry/GreatCircle.h rename to src/eckit/geo/geometry/GreatCircle.h diff --git a/src/grit/geometry/Sphere.cc b/src/eckit/geo/geometry/Sphere.cc similarity index 100% rename from src/grit/geometry/Sphere.cc rename to src/eckit/geo/geometry/Sphere.cc diff --git a/src/grit/geometry/Sphere.h b/src/eckit/geo/geometry/Sphere.h similarity index 100% rename from src/grit/geometry/Sphere.h rename to src/eckit/geo/geometry/Sphere.h diff --git a/src/grit/geometry/Spheroid.cc b/src/eckit/geo/geometry/Spheroid.cc similarity index 100% rename from src/grit/geometry/Spheroid.cc rename to src/eckit/geo/geometry/Spheroid.cc diff --git a/src/grit/geometry/Spheroid.h b/src/eckit/geo/geometry/Spheroid.h similarity index 100% rename from src/grit/geometry/Spheroid.h rename to src/eckit/geo/geometry/Spheroid.h diff --git a/src/grit/geometry/UnitSphere.h b/src/eckit/geo/geometry/UnitSphere.h similarity index 100% rename from src/grit/geometry/UnitSphere.h rename to src/eckit/geo/geometry/UnitSphere.h diff --git a/src/tools/grit-grib.cc b/src/eckit/geo/grit-grib.cc similarity index 100% rename from src/tools/grit-grib.cc rename to src/eckit/geo/grit-grib.cc diff --git a/src/tools/grit-search.cc b/src/eckit/geo/grit-search.cc similarity index 100% rename from src/tools/grit-search.cc rename to src/eckit/geo/grit-search.cc diff --git a/src/tools/grit-version.cc b/src/eckit/geo/grit-version.cc similarity index 100% rename from src/tools/grit-version.cc rename to src/eckit/geo/grit-version.cc diff --git a/src/grit/grit.h.in b/src/eckit/geo/grit.h.in similarity index 100% rename from src/grit/grit.h.in rename to src/eckit/geo/grit.h.in diff --git a/src/grit/iterator/IteratorAggregator.h b/src/eckit/geo/iterator/IteratorAggregator.h similarity index 100% rename from src/grit/iterator/IteratorAggregator.h rename to src/eckit/geo/iterator/IteratorAggregator.h diff --git a/src/grit/iterator/IteratorComposer.cc b/src/eckit/geo/iterator/IteratorComposer.cc similarity index 100% rename from src/grit/iterator/IteratorComposer.cc rename to src/eckit/geo/iterator/IteratorComposer.cc diff --git a/src/grit/iterator/IteratorComposer.h b/src/eckit/geo/iterator/IteratorComposer.h similarity index 100% rename from src/grit/iterator/IteratorComposer.h rename to src/eckit/geo/iterator/IteratorComposer.h diff --git a/src/grit/log.cc b/src/eckit/geo/log.cc similarity index 100% rename from src/grit/log.cc rename to src/eckit/geo/log.cc diff --git a/src/grit/log.h b/src/eckit/geo/log.h similarity index 100% rename from src/grit/log.h rename to src/eckit/geo/log.h diff --git a/src/grit/param/Map.cc b/src/eckit/geo/param/Map.cc similarity index 100% rename from src/grit/param/Map.cc rename to src/eckit/geo/param/Map.cc diff --git a/src/grit/param/Map.h b/src/eckit/geo/param/Map.h similarity index 100% rename from src/grit/param/Map.h rename to src/eckit/geo/param/Map.h diff --git a/src/grit/projection/LatLonToXYZ.cc b/src/eckit/geo/projection/LatLonToXYZ.cc similarity index 100% rename from src/grit/projection/LatLonToXYZ.cc rename to src/eckit/geo/projection/LatLonToXYZ.cc diff --git a/src/grit/projection/LatLonToXYZ.h b/src/eckit/geo/projection/LatLonToXYZ.h similarity index 100% rename from src/grit/projection/LatLonToXYZ.h rename to src/eckit/geo/projection/LatLonToXYZ.h diff --git a/src/grit/projection/None.cc b/src/eckit/geo/projection/None.cc similarity index 100% rename from src/grit/projection/None.cc rename to src/eckit/geo/projection/None.cc diff --git a/src/grit/projection/None.h b/src/eckit/geo/projection/None.h similarity index 100% rename from src/grit/projection/None.h rename to src/eckit/geo/projection/None.h diff --git a/src/grit/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc similarity index 100% rename from src/grit/projection/PROJ.cc rename to src/eckit/geo/projection/PROJ.cc diff --git a/src/grit/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h similarity index 100% rename from src/grit/projection/PROJ.h rename to src/eckit/geo/projection/PROJ.h diff --git a/src/grit/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc similarity index 100% rename from src/grit/projection/Rotation.cc rename to src/eckit/geo/projection/Rotation.cc diff --git a/src/grit/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h similarity index 100% rename from src/grit/projection/Rotation.h rename to src/eckit/geo/projection/Rotation.h diff --git a/tests/reduced_gg.grib2 b/src/eckit/geo/reduced_gg.grib2 similarity index 100% rename from tests/reduced_gg.grib2 rename to src/eckit/geo/reduced_gg.grib2 diff --git a/tests/reduced_ll.grib1 b/src/eckit/geo/reduced_ll.grib1 similarity index 100% rename from tests/reduced_ll.grib1 rename to src/eckit/geo/reduced_ll.grib1 diff --git a/tests/regular_gg.grib1 b/src/eckit/geo/regular_gg.grib1 similarity index 100% rename from tests/regular_gg.grib1 rename to src/eckit/geo/regular_gg.grib1 diff --git a/tests/regular_ll.grib1 b/src/eckit/geo/regular_ll.grib1 similarity index 100% rename from tests/regular_ll.grib1 rename to src/eckit/geo/regular_ll.grib1 diff --git a/src/grit/scanner/Reduced.cc b/src/eckit/geo/scanner/Reduced.cc similarity index 100% rename from src/grit/scanner/Reduced.cc rename to src/eckit/geo/scanner/Reduced.cc diff --git a/src/grit/scanner/Reduced.h b/src/eckit/geo/scanner/Reduced.h similarity index 100% rename from src/grit/scanner/Reduced.h rename to src/eckit/geo/scanner/Reduced.h diff --git a/src/grit/scanner/Regular.cc b/src/eckit/geo/scanner/Regular.cc similarity index 100% rename from src/grit/scanner/Regular.cc rename to src/eckit/geo/scanner/Regular.cc diff --git a/src/grit/scanner/Regular.h b/src/eckit/geo/scanner/Regular.h similarity index 100% rename from src/grit/scanner/Regular.h rename to src/eckit/geo/scanner/Regular.h diff --git a/src/grit/scanner/Unstructured.cc b/src/eckit/geo/scanner/Unstructured.cc similarity index 100% rename from src/grit/scanner/Unstructured.cc rename to src/eckit/geo/scanner/Unstructured.cc diff --git a/src/grit/scanner/Unstructured.h b/src/eckit/geo/scanner/Unstructured.h similarity index 100% rename from src/grit/scanner/Unstructured.h rename to src/eckit/geo/scanner/Unstructured.h diff --git a/src/grit/test.cc b/src/eckit/geo/test.cc similarity index 100% rename from src/grit/test.cc rename to src/eckit/geo/test.cc diff --git a/src/grit/test.h b/src/eckit/geo/test.h similarity index 100% rename from src/grit/test.h rename to src/eckit/geo/test.h diff --git a/tests/test_iterator.cc b/src/eckit/geo/test_iterator.cc similarity index 100% rename from tests/test_iterator.cc rename to src/eckit/geo/test_iterator.cc diff --git a/tests/test_param.cc b/src/eckit/geo/test_param.cc similarity index 100% rename from tests/test_param.cc rename to src/eckit/geo/test_param.cc diff --git a/tests/test_projection.cc b/src/eckit/geo/test_projection.cc similarity index 100% rename from tests/test_projection.cc rename to src/eckit/geo/test_projection.cc diff --git a/tests/test_projection_ll_to_xyz.cc b/src/eckit/geo/test_projection_ll_to_xyz.cc similarity index 100% rename from tests/test_projection_ll_to_xyz.cc rename to src/eckit/geo/test_projection_ll_to_xyz.cc diff --git a/tests/test_projection_proj.cc b/src/eckit/geo/test_projection_proj.cc similarity index 100% rename from tests/test_projection_proj.cc rename to src/eckit/geo/test_projection_proj.cc diff --git a/tests/test_projection_rotation.cc b/src/eckit/geo/test_projection_rotation.cc similarity index 100% rename from tests/test_projection_rotation.cc rename to src/eckit/geo/test_projection_rotation.cc diff --git a/tests/test_search.cc b/src/eckit/geo/test_search.cc similarity index 100% rename from tests/test_search.cc rename to src/eckit/geo/test_search.cc diff --git a/tests/test_types.cc b/src/eckit/geo/test_types.cc similarity index 100% rename from tests/test_types.cc rename to src/eckit/geo/test_types.cc diff --git a/tests/test_util.cc b/src/eckit/geo/test_util.cc similarity index 100% rename from tests/test_util.cc rename to src/eckit/geo/test_util.cc diff --git a/src/grit/types.cc b/src/eckit/geo/types.cc similarity index 100% rename from src/grit/types.cc rename to src/eckit/geo/types.cc diff --git a/src/grit/types.h b/src/eckit/geo/types.h similarity index 100% rename from src/grit/types.h rename to src/eckit/geo/types.h diff --git a/src/grit/types/MatrixXYZ.h b/src/eckit/geo/types/MatrixXYZ.h similarity index 100% rename from src/grit/types/MatrixXYZ.h rename to src/eckit/geo/types/MatrixXYZ.h diff --git a/src/grit/types/PointLatLon.h b/src/eckit/geo/types/PointLatLon.h similarity index 100% rename from src/grit/types/PointLatLon.h rename to src/eckit/geo/types/PointLatLon.h diff --git a/src/grit/types/PointXY.h b/src/eckit/geo/types/PointXY.h similarity index 100% rename from src/grit/types/PointXY.h rename to src/eckit/geo/types/PointXY.h diff --git a/src/grit/types/PointXYZ.h b/src/eckit/geo/types/PointXYZ.h similarity index 100% rename from src/grit/types/PointXYZ.h rename to src/eckit/geo/types/PointXYZ.h diff --git a/src/grit/util.cc b/src/eckit/geo/util.cc similarity index 100% rename from src/grit/util.cc rename to src/eckit/geo/util.cc diff --git a/src/grit/util.h b/src/eckit/geo/util.h similarity index 100% rename from src/grit/util.h rename to src/eckit/geo/util.h diff --git a/src/grit/util/Mutex.h b/src/eckit/geo/util/Mutex.h similarity index 100% rename from src/grit/util/Mutex.h rename to src/eckit/geo/util/Mutex.h diff --git a/src/grit/util/arange.cc b/src/eckit/geo/util/arange.cc similarity index 100% rename from src/grit/util/arange.cc rename to src/eckit/geo/util/arange.cc diff --git a/src/grit/util/gaussian_latitudes.cc b/src/eckit/geo/util/gaussian_latitudes.cc similarity index 100% rename from src/grit/util/gaussian_latitudes.cc rename to src/eckit/geo/util/gaussian_latitudes.cc diff --git a/src/grit/util/linspace.cc b/src/eckit/geo/util/linspace.cc similarity index 100% rename from src/grit/util/linspace.cc rename to src/eckit/geo/util/linspace.cc diff --git a/src/grit/util/monotonic_crop.cc b/src/eckit/geo/util/monotonic_crop.cc similarity index 100% rename from src/grit/util/monotonic_crop.cc rename to src/eckit/geo/util/monotonic_crop.cc diff --git a/src/grit/util/reduced_classical_pl.cc b/src/eckit/geo/util/reduced_classical_pl.cc similarity index 100% rename from src/grit/util/reduced_classical_pl.cc rename to src/eckit/geo/util/reduced_classical_pl.cc diff --git a/src/grit/util/reduced_octahedral_pl.cc b/src/eckit/geo/util/reduced_octahedral_pl.cc similarity index 100% rename from src/grit/util/reduced_octahedral_pl.cc rename to src/eckit/geo/util/reduced_octahedral_pl.cc diff --git a/src/grit/util/regular_pl.cc b/src/eckit/geo/util/regular_pl.cc similarity index 100% rename from src/grit/util/regular_pl.cc rename to src/eckit/geo/util/regular_pl.cc diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt deleted file mode 100644 index 8128ee903..000000000 --- a/src/tools/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -list(APPEND TOOLS - grit-version) - -if(eckit_FOUND) - list(APPEND TOOLS grit-search) -endif() - -foreach(tool ${TOOLS}) - add_executable(${tool} ${tool}.cc) - target_link_libraries(${tool} grit) -endforeach() - -if(TARGET eccodes) - add_executable(grit-grib grit-grib.cc) - target_link_libraries(grit-grib grit eccodes) -endif() - diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt deleted file mode 100644 index fd20b2f5f..000000000 --- a/tests/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ -list(APPEND TESTS - test_iterator - test_param - test_projection - test_projection_ll_to_xyz - test_projection_rotation - test_types - test_util) - -if(PROJ_FOUND) - list(APPEND TESTS test_projection_proj) -endif() - -if(eckit_FOUND) - list(APPEND TESTS test_search) -endif() - -foreach(test ${TESTS}) - add_executable(${test} ${test}.cc) - target_link_libraries(${test} grit) - add_test(${test} ${test}) -endforeach() - From a5708efd05f51f9d3be0ab74829b4e956858398a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 9 May 2023 17:56:49 +0100 Subject: [PATCH 187/737] eckit/geo --- src/eckit/CMakeLists.txt | 1 + src/eckit/geo/exception.h | 30 ------------------ src/eckit/geo/grit-version.cc | 21 ------------ {src/eckit => tests}/geo/reduced_gg.grib2 | Bin {src/eckit => tests}/geo/reduced_ll.grib1 | Bin {src/eckit => tests}/geo/regular_gg.grib1 | Bin {src/eckit => tests}/geo/regular_ll.grib1 | Bin {src/eckit => tests}/geo/test_iterator.cc | 0 {src/eckit => tests}/geo/test_param.cc | 0 {src/eckit => tests}/geo/test_projection.cc | 0 .../geo/test_projection_ll_to_xyz.cc | 0 .../geo/test_projection_proj.cc | 0 .../geo/test_projection_rotation.cc | 0 {src/eckit => tests}/geo/test_search.cc | 0 {src/eckit => tests}/geo/test_types.cc | 0 {src/eckit => tests}/geo/test_util.cc | 0 16 files changed, 1 insertion(+), 51 deletions(-) delete mode 100644 src/eckit/geo/exception.h delete mode 100644 src/eckit/geo/grit-version.cc rename {src/eckit => tests}/geo/reduced_gg.grib2 (100%) rename {src/eckit => tests}/geo/reduced_ll.grib1 (100%) rename {src/eckit => tests}/geo/regular_gg.grib1 (100%) rename {src/eckit => tests}/geo/regular_ll.grib1 (100%) rename {src/eckit => tests}/geo/test_iterator.cc (100%) rename {src/eckit => tests}/geo/test_param.cc (100%) rename {src/eckit => tests}/geo/test_projection.cc (100%) rename {src/eckit => tests}/geo/test_projection_ll_to_xyz.cc (100%) rename {src/eckit => tests}/geo/test_projection_proj.cc (100%) rename {src/eckit => tests}/geo/test_projection_rotation.cc (100%) rename {src/eckit => tests}/geo/test_search.cc (100%) rename {src/eckit => tests}/geo/test_types.cc (100%) rename {src/eckit => tests}/geo/test_util.cc (100%) diff --git a/src/eckit/CMakeLists.txt b/src/eckit/CMakeLists.txt index 3eaf8a10c..f4df7002a 100644 --- a/src/eckit/CMakeLists.txt +++ b/src/eckit/CMakeLists.txt @@ -965,6 +965,7 @@ if( HAVE_ECKIT_SQL ) add_subdirectory( sql ) endif() +add_subdirectory( geo ) add_subdirectory( geometry ) add_subdirectory( linalg ) add_subdirectory( maths ) diff --git a/src/eckit/geo/exception.h b/src/eckit/geo/exception.h deleted file mode 100644 index 491ce8af6..000000000 --- a/src/eckit/geo/exception.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include - - -namespace grit::exception { - - -using std::runtime_error; - - -} - - -#define ASSERT assert -#define ASSERT_MSG(x, y) assert((x) && (y)) -#define NOTIMP throw ::grit::exception::runtime_error("Not implemented") diff --git a/src/eckit/geo/grit-version.cc b/src/eckit/geo/grit-version.cc deleted file mode 100644 index 39e9afb5b..000000000 --- a/src/eckit/geo/grit-version.cc +++ /dev/null @@ -1,21 +0,0 @@ -/* - * (C) Copyright 1996- 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 - -#include "grit/grit.h" - - -int main(int /*argc*/, const char* /*argv*/[]) { - std::cout << grit_VERSION_MAJOR << '.' << grit_VERSION_MINOR << '.' << grit_VERSION_PATCH << std::endl; - return 0; -} diff --git a/src/eckit/geo/reduced_gg.grib2 b/tests/geo/reduced_gg.grib2 similarity index 100% rename from src/eckit/geo/reduced_gg.grib2 rename to tests/geo/reduced_gg.grib2 diff --git a/src/eckit/geo/reduced_ll.grib1 b/tests/geo/reduced_ll.grib1 similarity index 100% rename from src/eckit/geo/reduced_ll.grib1 rename to tests/geo/reduced_ll.grib1 diff --git a/src/eckit/geo/regular_gg.grib1 b/tests/geo/regular_gg.grib1 similarity index 100% rename from src/eckit/geo/regular_gg.grib1 rename to tests/geo/regular_gg.grib1 diff --git a/src/eckit/geo/regular_ll.grib1 b/tests/geo/regular_ll.grib1 similarity index 100% rename from src/eckit/geo/regular_ll.grib1 rename to tests/geo/regular_ll.grib1 diff --git a/src/eckit/geo/test_iterator.cc b/tests/geo/test_iterator.cc similarity index 100% rename from src/eckit/geo/test_iterator.cc rename to tests/geo/test_iterator.cc diff --git a/src/eckit/geo/test_param.cc b/tests/geo/test_param.cc similarity index 100% rename from src/eckit/geo/test_param.cc rename to tests/geo/test_param.cc diff --git a/src/eckit/geo/test_projection.cc b/tests/geo/test_projection.cc similarity index 100% rename from src/eckit/geo/test_projection.cc rename to tests/geo/test_projection.cc diff --git a/src/eckit/geo/test_projection_ll_to_xyz.cc b/tests/geo/test_projection_ll_to_xyz.cc similarity index 100% rename from src/eckit/geo/test_projection_ll_to_xyz.cc rename to tests/geo/test_projection_ll_to_xyz.cc diff --git a/src/eckit/geo/test_projection_proj.cc b/tests/geo/test_projection_proj.cc similarity index 100% rename from src/eckit/geo/test_projection_proj.cc rename to tests/geo/test_projection_proj.cc diff --git a/src/eckit/geo/test_projection_rotation.cc b/tests/geo/test_projection_rotation.cc similarity index 100% rename from src/eckit/geo/test_projection_rotation.cc rename to tests/geo/test_projection_rotation.cc diff --git a/src/eckit/geo/test_search.cc b/tests/geo/test_search.cc similarity index 100% rename from src/eckit/geo/test_search.cc rename to tests/geo/test_search.cc diff --git a/src/eckit/geo/test_types.cc b/tests/geo/test_types.cc similarity index 100% rename from src/eckit/geo/test_types.cc rename to tests/geo/test_types.cc diff --git a/src/eckit/geo/test_util.cc b/tests/geo/test_util.cc similarity index 100% rename from src/eckit/geo/test_util.cc rename to tests/geo/test_util.cc From 04c430f23e2201ebc2d641e044b0f3824c6fbc7a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 9 May 2023 17:58:33 +0100 Subject: [PATCH 188/737] eckit/geo --- src/eckit/geo/CMakeLists.txt | 121 ++++++++++---------- src/eckit/geo/Iterator.cc | 10 +- src/eckit/geo/Iterator.h | 11 +- src/eckit/geo/Parametrisation.cc | 6 +- src/eckit/geo/Parametrisation.h | 4 +- src/eckit/geo/Projection.cc | 14 +-- src/eckit/geo/Projection.h | 6 +- src/eckit/geo/Scanner.cc | 4 +- src/eckit/geo/Scanner.h | 2 +- src/eckit/geo/Search.h | 17 +-- src/eckit/geo/geometry/BoundingBox.cc | 12 +- src/eckit/geo/geometry/BoundingBox.h | 4 +- src/eckit/geo/geometry/GreatCircle.cc | 10 +- src/eckit/geo/geometry/GreatCircle.h | 6 +- src/eckit/geo/geometry/Sphere.cc | 12 +- src/eckit/geo/geometry/Sphere.h | 6 +- src/eckit/geo/geometry/Spheroid.cc | 10 +- src/eckit/geo/geometry/Spheroid.h | 6 +- src/eckit/geo/geometry/UnitSphere.h | 6 +- src/eckit/geo/grit-grib.cc | 10 +- src/eckit/geo/grit-search.cc | 2 +- src/eckit/geo/iterator/IteratorAggregator.h | 6 +- src/eckit/geo/iterator/IteratorComposer.cc | 13 +-- src/eckit/geo/iterator/IteratorComposer.h | 11 +- src/eckit/geo/log.cc | 4 +- src/eckit/geo/log.h | 2 +- src/eckit/geo/param/Map.cc | 8 +- src/eckit/geo/param/Map.h | 6 +- src/eckit/geo/projection/LatLonToXYZ.cc | 14 +-- src/eckit/geo/projection/LatLonToXYZ.h | 6 +- src/eckit/geo/projection/None.cc | 6 +- src/eckit/geo/projection/None.h | 6 +- src/eckit/geo/projection/PROJ.cc | 12 +- src/eckit/geo/projection/PROJ.h | 6 +- src/eckit/geo/projection/Rotation.cc | 14 +-- src/eckit/geo/projection/Rotation.h | 6 +- src/eckit/geo/scanner/Reduced.cc | 6 +- src/eckit/geo/scanner/Reduced.h | 6 +- src/eckit/geo/scanner/Regular.cc | 6 +- src/eckit/geo/scanner/Regular.h | 6 +- src/eckit/geo/scanner/Unstructured.cc | 6 +- src/eckit/geo/scanner/Unstructured.h | 6 +- src/eckit/geo/test.cc | 21 ++-- src/eckit/geo/test.h | 8 +- src/eckit/geo/types.cc | 19 +-- src/eckit/geo/types.h | 11 +- src/eckit/geo/types/MatrixXYZ.h | 8 +- src/eckit/geo/types/PointLatLon.h | 6 +- src/eckit/geo/types/PointXY.h | 4 +- src/eckit/geo/types/PointXYZ.h | 4 +- src/eckit/geo/util.cc | 6 +- src/eckit/geo/util.h | 6 +- src/eckit/geo/util/Mutex.h | 27 +---- src/eckit/geo/util/arange.cc | 6 +- src/eckit/geo/util/gaussian_latitudes.cc | 10 +- src/eckit/geo/util/linspace.cc | 4 +- src/eckit/geo/util/monotonic_crop.cc | 8 +- src/eckit/geo/util/reduced_classical_pl.cc | 10 +- src/eckit/geo/util/reduced_octahedral_pl.cc | 8 +- src/eckit/geo/util/regular_pl.cc | 8 +- 60 files changed, 278 insertions(+), 331 deletions(-) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 1fc094fb1..474b9218c 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -1,70 +1,65 @@ -configure_file(grit.h.in grit.h) - -add_library(grit SHARED +list(APPEND eckit_geo_srcs + Iterator.h Parametrisation.cc Parametrisation.h + Projection.cc + Projection.h + Scanner.cc + Scanner.h + geometry/BoundingBox.cc + geometry/BoundingBox.h + geometry/GreatCircle.cc + geometry/GreatCircle.h + geometry/Sphere.cc + geometry/Sphere.h + geometry/Spheroid.cc + geometry/Spheroid.h + geometry/UnitSphere.h iterator/IteratorAggregator.h iterator/IteratorComposer.cc iterator/IteratorComposer.h - Iterator.h - Projection.cc - Projection.h - Scanner.cc - Scanner.h - exception.h - geometry/BoundingBox.cc - geometry/BoundingBox.h - geometry/GreatCircle.cc - geometry/GreatCircle.h - geometry/Sphere.cc - geometry/Sphere.h - geometry/Spheroid.cc - geometry/Spheroid.h - geometry/UnitSphere.h - log.cc - log.h - param/Map.cc - param/Map.h - projection/LatLonToXYZ.cc - projection/LatLonToXYZ.h - projection/None.cc - projection/None.h - projection/Rotation.cc - projection/Rotation.h - scanner/Reduced.cc - scanner/Reduced.h - scanner/Regular.cc - scanner/Regular.h - scanner/Unstructured.cc - scanner/Unstructured.h - test.cc - test.h - types.cc - types.h - types/MatrixXYZ.h - types/PointLatLon.h - types/PointXY.h - types/PointXYZ.h - util.cc - util.h - util/Mutex.h - util/arange.cc - util/gaussian_latitudes.cc - util/linspace.cc - util/monotonic_crop.cc - util/reduced_classical_pl.cc - util/reduced_octahedral_pl.cc - util/regular_pl.cc) - -target_include_directories(grit PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") - -if(eckit_FOUND) - target_sources(grit PRIVATE Search.h) - target_link_libraries(grit eckit) -endif() + log.cc + log.h + param/Map.cc + param/Map.h + projection/LatLonToXYZ.cc + projection/LatLonToXYZ.h + projection/None.cc + projection/None.h + projection/Rotation.cc + projection/Rotation.h + scanner/Reduced.cc + scanner/Reduced.h + scanner/Regular.cc + scanner/Regular.h + scanner/Unstructured.cc + scanner/Unstructured.h + test.cc + test.h + types.cc + types.h + types/MatrixXYZ.h + types/PointLatLon.h + types/PointXY.h + types/PointXYZ.h + util.cc + util.h + util/Mutex.h + util/arange.cc + util/gaussian_latitudes.cc + util/linspace.cc + util/monotonic_crop.cc + util/reduced_classical_pl.cc + util/reduced_octahedral_pl.cc + util/regular_pl.cc +) -if(TARGET PROJ::proj) - target_sources(grit PRIVATE projection/PROJ.cc projection/PROJ.h) - target_link_libraries(grit PROJ::proj) -endif() +ecbuild_add_library( + TARGET eckit_geo + TYPE SHARED + INSTALL_HEADERS ALL + HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geo + SOURCES ${eckit_geo_srcs} + PUBLIC_LIBS eckit +) diff --git a/src/eckit/geo/Iterator.cc b/src/eckit/geo/Iterator.cc index 7fa59b0fa..e10dd5910 100644 --- a/src/eckit/geo/Iterator.cc +++ b/src/eckit/geo/Iterator.cc @@ -10,14 +10,14 @@ */ -#include "grit/Iterator.h" +#include "eckit/geo/Iterator.h" -#include "grit/Projection.h" -#include "grit/Scanner.h" -#include "grit/exception.h" +#include "eckit/geo/Projection.h" +#include "eckit/geo/Scanner.h" +#include "eckit/exception/Exceptions.h" -namespace grit { +namespace eckit::geo { Iterator::Iterator(Scanner* scanner, Projection* projection) : scanner_(scanner), projection_(projection) { diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index 3c6757500..78e687355 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -12,10 +12,10 @@ #pragma once -#include "grit/types.h" +#include "eckit/geo/types.h" -namespace grit { +namespace eckit::geo { class Iterator { @@ -39,12 +39,6 @@ class Iterator { return *this; } - iterator_t operator++(int) { - auto old = *this; - operator++(); - return old; - } - typename X::value_type& operator*() { return cnt.at(pos); } const typename X::value_type& operator*() const { return cnt.at(pos); } @@ -81,7 +75,6 @@ class Iterator { Iterator& operator=(Iterator&&) = delete; virtual bool operator++() = 0; - virtual bool operator++(int) = 0; // -- Methods diff --git a/src/eckit/geo/Parametrisation.cc b/src/eckit/geo/Parametrisation.cc index e3cb5d510..cf41c3345 100644 --- a/src/eckit/geo/Parametrisation.cc +++ b/src/eckit/geo/Parametrisation.cc @@ -10,12 +10,12 @@ */ -#include "grit/Parametrisation.h" +#include "eckit/geo/Parametrisation.h" -#include "grit/exception.h" +#include "eckit/exception/Exceptions.h" -namespace grit { +namespace eckit::geo { namespace { diff --git a/src/eckit/geo/Parametrisation.h b/src/eckit/geo/Parametrisation.h index 3591c7ef8..054f77470 100644 --- a/src/eckit/geo/Parametrisation.h +++ b/src/eckit/geo/Parametrisation.h @@ -15,10 +15,8 @@ #include #include -#include "grit/exception.h" - -namespace grit { +namespace eckit::geo { class Parametrisation { diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index e60164fb7..4dab68db7 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -10,17 +10,17 @@ */ -#include "grit/Projection.h" +#include "eckit/geo/Projection.h" #include #include -#include "grit/exception.h" -#include "grit/log.h" -#include "grit/util/Mutex.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/log.h" +#include "eckit/geo/util/Mutex.h" -namespace grit { +namespace eckit::geo { #if 0 @@ -238,7 +238,7 @@ Projection* ProjectionFactory::build(const ProjectionFactory::key_type& key, con } list(error << "ProjectionFactory: unknown '" << key << "', choices are: "); - throw exception::runtime_error("ProjectionFactory: unknown '" + key + "'"); + throw BadValue("ProjectionFactory: unknown '" + key + "'"); } @@ -261,7 +261,7 @@ ProjectionFactory::ProjectionFactory(const ProjectionFactory::key_type& key) : k util::lock_guard lock(*__mutex); if (auto f = __factories->find(key); f != __factories->end()) { - throw exception::runtime_error("ProjectionFactory: duplicate '" + key + "'"); + throw BadValue("ProjectionFactory: duplicate '" + key + "'"); } (*__factories)[key] = this; diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 62d83a511..436256d04 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -15,15 +15,15 @@ #include #include -#include "grit/types.h" +#include "eckit/geo/types.h" -namespace grit { +namespace eckit::geo { class Parametrisation; } -namespace grit { +namespace eckit::geo { class Projection { diff --git a/src/eckit/geo/Scanner.cc b/src/eckit/geo/Scanner.cc index 14654ef64..abb2a2220 100644 --- a/src/eckit/geo/Scanner.cc +++ b/src/eckit/geo/Scanner.cc @@ -10,10 +10,10 @@ */ -#include "grit/Scanner.h" +#include "eckit/geo/Scanner.h" -namespace grit { +namespace eckit::geo { #if 0 diff --git a/src/eckit/geo/Scanner.h b/src/eckit/geo/Scanner.h index b87003281..5232397cd 100644 --- a/src/eckit/geo/Scanner.h +++ b/src/eckit/geo/Scanner.h @@ -15,7 +15,7 @@ #include -namespace grit { +namespace eckit::geo { class Scanner { diff --git a/src/eckit/geo/Search.h b/src/eckit/geo/Search.h index 372935705..bbb99008b 100644 --- a/src/eckit/geo/Search.h +++ b/src/eckit/geo/Search.h @@ -13,23 +13,10 @@ #pragma once #include "eckit/container/KDTree.h" +#include "eckit/geo/types.h" -#ifdef ASSERT -#undef ASSERT -#endif -#ifdef ASSERT_MSG -#undef ASSERT_MSG -#endif - -#ifdef NOTIMP -#undef NOTIMP -#endif - -#include "grit/types.h" - - -namespace grit { +namespace eckit::geo { namespace search { diff --git a/src/eckit/geo/geometry/BoundingBox.cc b/src/eckit/geo/geometry/BoundingBox.cc index f01c50a58..1d79bf929 100644 --- a/src/eckit/geo/geometry/BoundingBox.cc +++ b/src/eckit/geo/geometry/BoundingBox.cc @@ -10,16 +10,16 @@ */ -#include "grit/geometry/BoundingBox.h" +#include "eckit/geo/geometry/BoundingBox.h" #include -#include "grit/exception.h" -#include "grit/geometry/Sphere.h" -#include "grit/util.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/geometry/Sphere.h" +#include "eckit/geo/util.h" -namespace grit::geometry { +namespace eckit::geo::geometry { BoundingBox::BoundingBox(double north, double west, double south, double east) : @@ -131,4 +131,4 @@ double BoundingBox::area(double radius) const { } -} // namespace grit::geometry +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/BoundingBox.h b/src/eckit/geo/geometry/BoundingBox.h index bf8db0c73..91254a2ec 100644 --- a/src/eckit/geo/geometry/BoundingBox.h +++ b/src/eckit/geo/geometry/BoundingBox.h @@ -13,7 +13,7 @@ #pragma once -namespace grit::geometry { +namespace eckit::geo::geometry { class BoundingBox { @@ -123,4 +123,4 @@ class BoundingBox { }; -} // namespace grit::geometry +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/GreatCircle.cc b/src/eckit/geo/geometry/GreatCircle.cc index 6d4475c81..ccde3e45b 100644 --- a/src/eckit/geo/geometry/GreatCircle.cc +++ b/src/eckit/geo/geometry/GreatCircle.cc @@ -10,16 +10,16 @@ */ -#include "grit/geometry/GreatCircle.h" +#include "eckit/geo/geometry/GreatCircle.h" #include #include -#include "grit/exception.h" -#include "grit/util.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/util.h" -namespace grit::geometry { +namespace eckit::geo::geometry { static bool pole(double lat) { @@ -104,4 +104,4 @@ std::vector GreatCircle::longitude(double lat) const { } -} // namespace grit::geometry +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/GreatCircle.h b/src/eckit/geo/geometry/GreatCircle.h index ec0dd1c12..1531651c5 100644 --- a/src/eckit/geo/geometry/GreatCircle.h +++ b/src/eckit/geo/geometry/GreatCircle.h @@ -15,10 +15,10 @@ #include -#include "grit/types.h" +#include "eckit/geo/types.h" -namespace grit::geometry { +namespace eckit::geo::geometry { class GreatCircle { @@ -42,4 +42,4 @@ class GreatCircle { }; -} // namespace grit::geometry +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/Sphere.cc b/src/eckit/geo/geometry/Sphere.cc index c7ecd86a9..9222d08d4 100644 --- a/src/eckit/geo/geometry/Sphere.cc +++ b/src/eckit/geo/geometry/Sphere.cc @@ -10,17 +10,17 @@ */ -#include "grit/geometry/Sphere.h" +#include "eckit/geo/geometry/Sphere.h" #include #include -#include "grit/exception.h" -#include "grit/geometry/Spheroid.h" -#include "grit/util.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/geometry/Spheroid.h" +#include "eckit/geo/util.h" -namespace grit::geometry { +namespace eckit::geo::geometry { inline double squared(double x) { @@ -121,4 +121,4 @@ PointLatLon Sphere::xyz_to_ll(double radius, const PointXYZ& A) { } -} // namespace grit::geometry +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/Sphere.h b/src/eckit/geo/geometry/Sphere.h index 05ba24598..9bab4476a 100644 --- a/src/eckit/geo/geometry/Sphere.h +++ b/src/eckit/geo/geometry/Sphere.h @@ -12,10 +12,10 @@ #pragma once -#include "grit/types.h" +#include "eckit/geo/types.h" -namespace grit::geometry { +namespace eckit::geo::geometry { struct Sphere { @@ -42,4 +42,4 @@ struct Sphere { }; -} // namespace grit::geometry +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/Spheroid.cc b/src/eckit/geo/geometry/Spheroid.cc index 4f132750e..05a65c4d5 100644 --- a/src/eckit/geo/geometry/Spheroid.cc +++ b/src/eckit/geo/geometry/Spheroid.cc @@ -10,13 +10,13 @@ */ -#include "grit/geometry/Spheroid.h" +#include "eckit/geo/geometry/Spheroid.h" -#include "grit/exception.h" -#include "grit/util.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/util.h" -namespace grit::geometry { +namespace eckit::geo::geometry { double Spheroid::angle(const PointLatLon& A, const PointLatLon& B) { @@ -85,4 +85,4 @@ PointLatLon Spheroid::xyz_to_ll(double a, double b, const PointXYZ& A) { } -} // namespace grit::geometry +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/Spheroid.h b/src/eckit/geo/geometry/Spheroid.h index b796e3a89..290d89c85 100644 --- a/src/eckit/geo/geometry/Spheroid.h +++ b/src/eckit/geo/geometry/Spheroid.h @@ -12,10 +12,10 @@ #pragma once -#include "grit/types.h" +#include "eckit/geo/types.h" -namespace grit::geometry { +namespace eckit::geo::geometry { struct Spheroid { @@ -42,4 +42,4 @@ struct Spheroid { }; -} // namespace grit::geometry +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/UnitSphere.h b/src/eckit/geo/geometry/UnitSphere.h index 12b95a651..fcb94c494 100644 --- a/src/eckit/geo/geometry/UnitSphere.h +++ b/src/eckit/geo/geometry/UnitSphere.h @@ -12,10 +12,10 @@ #pragma once -#include "grit/geometry/SphereT.h" +#include "eckit/geo/geometry/SphereT.h" -namespace grit::geometry { +namespace eckit::geo::geometry { /// Definition of a unit datum @@ -28,4 +28,4 @@ struct DatumUnit { using UnitSphere = SphereT; -} // namespace grit::geometry +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/grit-grib.cc b/src/eckit/geo/grit-grib.cc index c5b25a5be..31f86e79f 100644 --- a/src/eckit/geo/grit-grib.cc +++ b/src/eckit/geo/grit-grib.cc @@ -19,11 +19,11 @@ #include #include -#include "grit/Parametrisation.h" -#include "grit/exception.h" -#include "grit/grit.h" -#include "grit/param/Map.h" -#include "grit/types.h" +#include "eckit/geo/Parametrisation.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/grit.h" +#include "eckit/geo/param/Map.h" +#include "eckit/geo/types.h" #if 0 diff --git a/src/eckit/geo/grit-search.cc b/src/eckit/geo/grit-search.cc index de66fc855..1afc33bb1 100644 --- a/src/eckit/geo/grit-search.cc +++ b/src/eckit/geo/grit-search.cc @@ -13,7 +13,7 @@ #include #include -#include "grit/Search.h" +#include "eckit/geo/Search.h" int main(int argc, const char* argv[]) { diff --git a/src/eckit/geo/iterator/IteratorAggregator.h b/src/eckit/geo/iterator/IteratorAggregator.h index 41bf02a13..d643c195b 100644 --- a/src/eckit/geo/iterator/IteratorAggregator.h +++ b/src/eckit/geo/iterator/IteratorAggregator.h @@ -12,10 +12,10 @@ #pragma once -#include "grit/Iterator.h" +#include "eckit/geo/Iterator.h" -namespace grit::iterator { +namespace eckit::geo::iterator { template @@ -92,4 +92,4 @@ class IteratorAggregator final : public Iterator, protected Scanner { }; -} // namespace grit::iterator +} // namespace eckit::geo::iterator diff --git a/src/eckit/geo/iterator/IteratorComposer.cc b/src/eckit/geo/iterator/IteratorComposer.cc index 58c9c2357..3b76ce8eb 100644 --- a/src/eckit/geo/iterator/IteratorComposer.cc +++ b/src/eckit/geo/iterator/IteratorComposer.cc @@ -10,12 +10,12 @@ */ -#include "grit/iterator/IteratorComposer.h" +#include "eckit/geo/iterator/IteratorComposer.h" -#include "grit/exception.h" +#include "eckit/exception/Exceptions.h" -namespace grit::iterator { +namespace eckit::geo::iterator { IteratorComposer::IteratorComposer(Scanner* scanner, const std::vector& projections) : scanner_(scanner) { @@ -34,14 +34,9 @@ bool IteratorComposer::operator++() { } -bool IteratorComposer::operator++(int) { - return scanner_->operator++(0); -} - - size_t IteratorComposer::size() const { return scanner_->size(); } -} // namespace grit::iterator +} // namespace eckit::geo::iterator diff --git a/src/eckit/geo/iterator/IteratorComposer.h b/src/eckit/geo/iterator/IteratorComposer.h index fd0c823e1..929fce29d 100644 --- a/src/eckit/geo/iterator/IteratorComposer.h +++ b/src/eckit/geo/iterator/IteratorComposer.h @@ -15,12 +15,12 @@ #include #include -#include "grit/Iterator.h" -#include "grit/Projection.h" -#include "grit/Scanner.h" +#include "eckit/geo/Iterator.h" +#include "eckit/geo/Projection.h" +#include "eckit/geo/Scanner.h" -namespace grit::iterator { +namespace eckit::geo::iterator { class IteratorComposer final : public Iterator { @@ -44,7 +44,6 @@ class IteratorComposer final : public Iterator { // -- Operators bool operator++() override; - bool operator++(int) override; // -- Methods @@ -83,4 +82,4 @@ class IteratorComposer final : public Iterator { }; -} // namespace grit::iterator +} // namespace eckit::geo::iterator diff --git a/src/eckit/geo/log.cc b/src/eckit/geo/log.cc index c6dcb5d17..e35823bbf 100644 --- a/src/eckit/geo/log.cc +++ b/src/eckit/geo/log.cc @@ -12,10 +12,10 @@ #include -#include "grit/log.h" +#include "eckit/geo/log.h" -namespace grit { +namespace eckit::geo { std::ostream& error = std::cerr; diff --git a/src/eckit/geo/log.h b/src/eckit/geo/log.h index 1c2060471..b680768d2 100644 --- a/src/eckit/geo/log.h +++ b/src/eckit/geo/log.h @@ -15,7 +15,7 @@ #include -namespace grit { +namespace eckit::geo { extern std::ostream& error; diff --git a/src/eckit/geo/param/Map.cc b/src/eckit/geo/param/Map.cc index 21cb127bb..ad94a53a6 100644 --- a/src/eckit/geo/param/Map.cc +++ b/src/eckit/geo/param/Map.cc @@ -10,14 +10,14 @@ */ -#include "grit/param/Map.h" +#include "eckit/geo/param/Map.h" #include -#include "grit/exception.h" +#include "eckit/exception/Exceptions.h" -namespace grit::param { +namespace eckit::geo::param { Map::Map(const container_type& other) : map_(other) {} @@ -200,4 +200,4 @@ bool Map::get(const key_type& key, std::vector& value) const { } -} // namespace grit::param +} // namespace eckit::geo::param diff --git a/src/eckit/geo/param/Map.h b/src/eckit/geo/param/Map.h index cf76f74b7..4a2a37ada 100644 --- a/src/eckit/geo/param/Map.h +++ b/src/eckit/geo/param/Map.h @@ -15,10 +15,10 @@ #include #include -#include "grit/Parametrisation.h" +#include "eckit/geo/Parametrisation.h" -namespace grit::param { +namespace eckit::geo::param { class Map final : public Parametrisation { @@ -118,4 +118,4 @@ class Map final : public Parametrisation { }; -} // namespace grit::param +} // namespace eckit::geo::param diff --git a/src/eckit/geo/projection/LatLonToXYZ.cc b/src/eckit/geo/projection/LatLonToXYZ.cc index d5ef2cf71..fb469bfc7 100644 --- a/src/eckit/geo/projection/LatLonToXYZ.cc +++ b/src/eckit/geo/projection/LatLonToXYZ.cc @@ -10,15 +10,15 @@ */ -#include "grit/projection/LatLonToXYZ.h" +#include "eckit/geo/projection/LatLonToXYZ.h" -#include "grit/Parametrisation.h" -#include "grit/geometry/Sphere.h" -#include "grit/geometry/Spheroid.h" -#include "grit/util.h" +#include "eckit/geo/Parametrisation.h" +#include "eckit/geo/geometry/Sphere.h" +#include "eckit/geo/geometry/Spheroid.h" +#include "eckit/geo/util.h" -namespace grit::projection { +namespace eckit::geo::projection { static ProjectionBuilder __projection("ll_to_xyz"); @@ -60,4 +60,4 @@ LatLonToXYZ::LatLonToXYZ(const Parametrisation& param) : param.has("R") ? param.get_double("R") : param.get_double("b")) {} -} // namespace grit::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LatLonToXYZ.h b/src/eckit/geo/projection/LatLonToXYZ.h index 472354f5f..dbca4082b 100644 --- a/src/eckit/geo/projection/LatLonToXYZ.h +++ b/src/eckit/geo/projection/LatLonToXYZ.h @@ -14,10 +14,10 @@ #include -#include "grit/Projection.h" +#include "eckit/geo/Projection.h" -namespace grit::projection { +namespace eckit::geo::projection { /// Calculate coordinates of a point on a sphere or spheroid, in [x, y, z] @@ -94,4 +94,4 @@ class LatLonToXYZ final : public Projection { }; -} // namespace grit::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index 7f1c34ad4..1ec7f9193 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -10,10 +10,10 @@ */ -#include "grit/projection/None.h" +#include "eckit/geo/projection/None.h" -namespace grit::projection { +namespace eckit::geo::projection { static ProjectionBuilder __projection1(""); @@ -23,4 +23,4 @@ static ProjectionBuilder __projection2("none"); None::None(const Parametrisation&) {} -} // namespace grit::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index ee9739fa8..f7ecbb8ee 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -12,10 +12,10 @@ #pragma once -#include "grit/Projection.h" +#include "eckit/geo/Projection.h" -namespace grit::projection { +namespace eckit::geo::projection { class None final : public Projection { @@ -75,4 +75,4 @@ class None final : public Projection { }; -} // namespace grit::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 1876e3a94..0c577cd1a 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -10,14 +10,14 @@ */ -#include "grit/projection/PROJ.h" +#include "eckit/geo/projection/PROJ.h" -#include "grit/Parametrisation.h" -#include "grit/exception.h" -#include "grit/types.h" +#include "eckit/geo/Parametrisation.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/types.h" -namespace grit::projection { +namespace eckit::geo::projection { static ProjectionBuilder __projection("proj"); @@ -123,4 +123,4 @@ Point PROJ::inv(const Point& q) const { } -} // namespace grit::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index 909f9f9ff..d39f3b55b 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -16,10 +16,10 @@ #include -#include "grit/Projection.h" +#include "eckit/geo/Projection.h" -namespace grit::projection { +namespace eckit::geo::projection { /// Calculate coordinates using PROJ @@ -116,4 +116,4 @@ class PROJ final : public Projection { }; -} // namespace grit::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 0d5686eaf..e008fc4c5 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -10,18 +10,18 @@ */ -#include "grit/projection/Rotation.h" +#include "eckit/geo/projection/Rotation.h" #include #include -#include "grit/Parametrisation.h" -#include "grit/geometry/Sphere.h" -#include "grit/types/MatrixXYZ.h" -#include "grit/util.h" +#include "eckit/geo/Parametrisation.h" +#include "eckit/geo/geometry/Sphere.h" +#include "eckit/geo/types/MatrixXYZ.h" +#include "eckit/geo/util.h" -namespace grit::projection { +namespace eckit::geo::projection { static ProjectionBuilder __projection("rotation"); @@ -95,4 +95,4 @@ Rotation::Rotation(const Parametrisation& param) : param.has("angle") ? param.get_double("angle") : 0) {} -} // namespace grit::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index 58e5a56b0..837c0758b 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -14,10 +14,10 @@ #include -#include "grit/Projection.h" +#include "eckit/geo/Projection.h" -namespace grit::projection { +namespace eckit::geo::projection { /// Calculate coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle @@ -95,4 +95,4 @@ class Rotation final : public Projection { }; -} // namespace grit::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/scanner/Reduced.cc b/src/eckit/geo/scanner/Reduced.cc index fc63bcaa3..feef08625 100644 --- a/src/eckit/geo/scanner/Reduced.cc +++ b/src/eckit/geo/scanner/Reduced.cc @@ -10,12 +10,12 @@ */ -#include "grit/scanner/Reduced.h" +#include "eckit/geo/scanner/Reduced.h" // #include <> -namespace grit::scanner { +namespace eckit::geo::scanner { Reduced::Reduced() = default; @@ -31,4 +31,4 @@ size_t Reduced::size() const { } -} // namespace grit::scanner +} // namespace eckit::geo::scanner diff --git a/src/eckit/geo/scanner/Reduced.h b/src/eckit/geo/scanner/Reduced.h index 6231171a7..c415cec13 100644 --- a/src/eckit/geo/scanner/Reduced.h +++ b/src/eckit/geo/scanner/Reduced.h @@ -12,10 +12,10 @@ #pragma once -#include "grit/Scanner.h" +#include "eckit/geo/Scanner.h" -namespace grit::scanner { +namespace eckit::geo::scanner { class Reduced final : public Scanner { @@ -74,4 +74,4 @@ class Reduced final : public Scanner { }; -} // namespace grit::scanner +} // namespace eckit::geo::scanner diff --git a/src/eckit/geo/scanner/Regular.cc b/src/eckit/geo/scanner/Regular.cc index bf320bea7..f87c65d79 100644 --- a/src/eckit/geo/scanner/Regular.cc +++ b/src/eckit/geo/scanner/Regular.cc @@ -10,12 +10,12 @@ */ -#include "grit/scanner/Regular.h" +#include "eckit/geo/scanner/Regular.h" // #include <> -namespace grit::scanner { +namespace eckit::geo::scanner { Regular::Regular() = default; @@ -31,4 +31,4 @@ size_t Regular::size() const { } -} // namespace grit::scanner +} // namespace eckit::geo::scanner diff --git a/src/eckit/geo/scanner/Regular.h b/src/eckit/geo/scanner/Regular.h index 175cbe1c9..dde7bf3ca 100644 --- a/src/eckit/geo/scanner/Regular.h +++ b/src/eckit/geo/scanner/Regular.h @@ -12,10 +12,10 @@ #pragma once -#include "grit/Scanner.h" +#include "eckit/geo/Scanner.h" -namespace grit::scanner { +namespace eckit::geo::scanner { class Regular final : public Scanner { @@ -74,4 +74,4 @@ class Regular final : public Scanner { }; -} // namespace grit::scanner +} // namespace eckit::geo::scanner diff --git a/src/eckit/geo/scanner/Unstructured.cc b/src/eckit/geo/scanner/Unstructured.cc index d75ae6d58..873ff1ec6 100644 --- a/src/eckit/geo/scanner/Unstructured.cc +++ b/src/eckit/geo/scanner/Unstructured.cc @@ -10,12 +10,12 @@ */ -#include "grit/scanner/Unstructured.h" +#include "eckit/geo/scanner/Unstructured.h" // #include <> -namespace grit::scanner { +namespace eckit::geo::scanner { Unstructured::Unstructured() = default; @@ -31,4 +31,4 @@ size_t Unstructured::size() const { } -} // namespace grit::scanner +} // namespace eckit::geo::scanner diff --git a/src/eckit/geo/scanner/Unstructured.h b/src/eckit/geo/scanner/Unstructured.h index 3e2209f5e..68bf30a96 100644 --- a/src/eckit/geo/scanner/Unstructured.h +++ b/src/eckit/geo/scanner/Unstructured.h @@ -12,10 +12,10 @@ #pragma once -#include "grit/Scanner.h" +#include "eckit/geo/Scanner.h" -namespace grit::scanner { +namespace eckit::geo::scanner { class Unstructured final : public Scanner { @@ -74,4 +74,4 @@ class Unstructured final : public Scanner { }; -} // namespace grit::scanner +} // namespace eckit::geo::scanner diff --git a/src/eckit/geo/test.cc b/src/eckit/geo/test.cc index f0f43b4ac..2a58d3a86 100644 --- a/src/eckit/geo/test.cc +++ b/src/eckit/geo/test.cc @@ -10,19 +10,24 @@ */ -#include "grit/test.h" +#include "eckit/geo/test.h" +#include "eckit/exception/Exceptions.h" -bool operator==(const grit::Point& p, const grit::Point& q) { +bool operator==(const eckit::geo::Point &p, const eckit::geo::Point &q) +{ ASSERT(p.index() == q.index()); constexpr double eps = 1e-6; - return std::holds_alternative(p) - ? std::get(p).is_approximately_equal(std::get(q), eps) - : std::holds_alternative(p) - ? std::get(p).is_approximately_equal(std::get(q), eps) - : std::holds_alternative(p) - ? std::get(p).is_approximately_equal(std::get(q), eps) + return std::holds_alternative(p) + ? std::get(p) + .is_approximately_equal(std::get(q), eps) + : std::holds_alternative(p) + ? std::get(p) + .is_approximately_equal(std::get(q), eps) + : std::holds_alternative(p) + ? std::get(p) + .is_approximately_equal(std::get(q), eps) : NOTIMP; } diff --git a/src/eckit/geo/test.h b/src/eckit/geo/test.h index 5c09545ae..c4f317ecf 100644 --- a/src/eckit/geo/test.h +++ b/src/eckit/geo/test.h @@ -12,10 +12,6 @@ #pragma once -#include "grit/exception.h" -#include "grit/types.h" +#include "eckit/geo/types.h" -#define EXPECT ASSERT - - -bool operator==(const grit::Point&, const grit::Point&); +bool operator==(const eckit::geo::Point &, const eckit::geo::Point &); diff --git a/src/eckit/geo/types.cc b/src/eckit/geo/types.cc index e69d4aab1..ead4fa907 100644 --- a/src/eckit/geo/types.cc +++ b/src/eckit/geo/types.cc @@ -10,14 +10,17 @@ */ -#include "grit/types.h" +#include "eckit/geo/types.h" -#include "grit/exception.h" +#include "eckit/exception/Exceptions.h" - -std::ostream& operator<<(std::ostream& out, const grit::Point& p) { - return std::holds_alternative(p) ? out << std::get(p) - : std::holds_alternative(p) ? out << std::get(p) - : std::holds_alternative(p) ? out << std::get(p) - : NOTIMP; +std::ostream &operator<<(std::ostream &out, const eckit::geo::Point &p) +{ + return std::holds_alternative(p) + ? out << std::get(p) + : std::holds_alternative(p) + ? out << std::get(p) + : std::holds_alternative(p) + ? out << std::get(p) + : NOTIMP; } diff --git a/src/eckit/geo/types.h b/src/eckit/geo/types.h index d6edd2c1b..421c2fadb 100644 --- a/src/eckit/geo/types.h +++ b/src/eckit/geo/types.h @@ -16,12 +16,12 @@ #include #include -#include "grit/types/PointLatLon.h" -#include "grit/types/PointXY.h" -#include "grit/types/PointXYZ.h" +#include "eckit/geo/types/PointLatLon.h" +#include "eckit/geo/types/PointXY.h" +#include "eckit/geo/types/PointXYZ.h" -namespace grit { +namespace eckit::geo { using PointLatLon = types::PointLatLon; @@ -35,5 +35,4 @@ using pl_type = std::vector; } // namespace grit - -std::ostream& operator<<(std::ostream&, const grit::Point&); +std::ostream &operator<<(std::ostream &, const eckit::geo::Point &); diff --git a/src/eckit/geo/types/MatrixXYZ.h b/src/eckit/geo/types/MatrixXYZ.h index b12a45007..5f6e74f6d 100644 --- a/src/eckit/geo/types/MatrixXYZ.h +++ b/src/eckit/geo/types/MatrixXYZ.h @@ -15,11 +15,11 @@ #include #include -#include "grit/exception.h" -#include "grit/types/PointXYZ.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/types/PointXYZ.h" -namespace grit::types { +namespace eckit::geo::types { template @@ -115,4 +115,4 @@ class MatrixXYZ final : protected std::array { }; -} // namespace grit::types +} // namespace eckit::geo::types diff --git a/src/eckit/geo/types/PointLatLon.h b/src/eckit/geo/types/PointLatLon.h index 23c15548f..17d434e00 100644 --- a/src/eckit/geo/types/PointLatLon.h +++ b/src/eckit/geo/types/PointLatLon.h @@ -16,10 +16,10 @@ #include #include -#include "grit/exception.h" +#include "eckit/exception/Exceptions.h" -namespace grit::types { +namespace eckit::geo::types { template @@ -118,4 +118,4 @@ class PointLatLon final : protected std::array { }; -} // namespace grit::types +} // namespace eckit::geo::types diff --git a/src/eckit/geo/types/PointXY.h b/src/eckit/geo/types/PointXY.h index 6c72e09da..490048872 100644 --- a/src/eckit/geo/types/PointXY.h +++ b/src/eckit/geo/types/PointXY.h @@ -16,7 +16,7 @@ #include -namespace grit::types { +namespace eckit::geo::types { template @@ -98,4 +98,4 @@ class PointXY final : protected std::array { }; -} // namespace grit::types +} // namespace eckit::geo::types diff --git a/src/eckit/geo/types/PointXYZ.h b/src/eckit/geo/types/PointXYZ.h index 87a0d1daf..b37f00ad4 100644 --- a/src/eckit/geo/types/PointXYZ.h +++ b/src/eckit/geo/types/PointXYZ.h @@ -18,7 +18,7 @@ #include -namespace grit::types { +namespace eckit::geo::types { template @@ -101,4 +101,4 @@ class PointXYZ final : protected std::array { }; -} // namespace grit::types +} // namespace eckit::geo::types diff --git a/src/eckit/geo/util.cc b/src/eckit/geo/util.cc index 474ecd54b..af5d59236 100644 --- a/src/eckit/geo/util.cc +++ b/src/eckit/geo/util.cc @@ -10,10 +10,10 @@ */ -#include "grit/util.h" +#include "eckit/geo/util.h" -namespace grit::util { +namespace eckit::geo::util { template <> @@ -44,4 +44,4 @@ double normalise_longitude_to_maximum(double lon, double maximum) { } -} // namespace grit::util +} // namespace eckit::geo::util diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index 0d87b77d5..22f2c8af9 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -19,10 +19,10 @@ #include #include -#include "grit/types.h" +#include "eckit/geo/types.h" -namespace grit::util { +namespace eckit::geo::util { template @@ -84,4 +84,4 @@ const pl_type& reduced_octahedral_pl(size_t N); pl_type::value_type regular_pl(size_t N); -} // namespace grit::util +} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/Mutex.h b/src/eckit/geo/util/Mutex.h index 9e077c11b..a1be56112 100644 --- a/src/eckit/geo/util/Mutex.h +++ b/src/eckit/geo/util/Mutex.h @@ -12,21 +12,11 @@ #pragma once -#undef grit_ECKIT_THREADS - -#ifdef grit_ECKIT_THREADS #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" -#else -#include -#endif - - -namespace grit::util { -#ifdef grit_ECKIT_THREADS - +namespace eckit::geo::util { using recursive_mutex = eckit::Mutex; @@ -42,17 +32,4 @@ inline void call_once(once_flag& flag, Callable&& fun) { pthread_once(&(flag.once_), fun); } - -#else - - -using std::call_once; -using std::lock_guard; -using std::once_flag; -using std::recursive_mutex; - - -#endif - - -} // namespace grit::util +} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/arange.cc b/src/eckit/geo/util/arange.cc index d620e812a..938965a64 100644 --- a/src/eckit/geo/util/arange.cc +++ b/src/eckit/geo/util/arange.cc @@ -10,10 +10,10 @@ */ -#include "grit/util.h" +#include "eckit/geo/util.h" -namespace grit::util { +namespace eckit::geo::util { std::vector arange(double start, double stop, double step) { @@ -31,4 +31,4 @@ std::vector arange(double start, double stop, double step) { } -} // namespace grit::util +} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/gaussian_latitudes.cc b/src/eckit/geo/util/gaussian_latitudes.cc index a3fdb2917..2eec53de6 100644 --- a/src/eckit/geo/util/gaussian_latitudes.cc +++ b/src/eckit/geo/util/gaussian_latitudes.cc @@ -15,10 +15,10 @@ #include #include -#include "grit/exception.h" +#include "eckit/exception/Exceptions.h" -namespace grit::util { +namespace eckit::geo::util { std::vector gaussian_latitudes(size_t N, bool increasing) { @@ -81,8 +81,8 @@ std::vector gaussian_latitudes(size_t N, bool increasing) { } if (!converged) { - throw exception::runtime_error("Could not calculate latitude within accuracy/iterations: " + - std::to_string(eps) + "/" + std::to_string(Nmax)); + throw BadValue("Could not calculate latitude within accuracy/iterations: " + + std::to_string(eps) + "/" + std::to_string(Nmax)); } // Convert colatitude [rad] to latitude [degree], symmetry @@ -96,4 +96,4 @@ std::vector gaussian_latitudes(size_t N, bool increasing) { } -} // namespace grit::util +} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/linspace.cc b/src/eckit/geo/util/linspace.cc index 36c8b4fab..5f8948a67 100644 --- a/src/eckit/geo/util/linspace.cc +++ b/src/eckit/geo/util/linspace.cc @@ -14,7 +14,7 @@ #include -namespace grit::util { +namespace eckit::geo::util { std::vector linspace(double start, double stop, size_t num, bool endpoint) { @@ -32,4 +32,4 @@ std::vector linspace(double start, double stop, size_t num, bool endpoin } -} // namespace grit::util +} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/monotonic_crop.cc b/src/eckit/geo/util/monotonic_crop.cc index e10674cca..bad1dba9b 100644 --- a/src/eckit/geo/util/monotonic_crop.cc +++ b/src/eckit/geo/util/monotonic_crop.cc @@ -10,11 +10,11 @@ */ -#include "grit/exception.h" -#include "grit/util.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/util.h" -namespace grit::util { +namespace eckit::geo::util { std::pair::const_iterator, std::vector::const_iterator> monotonic_crop( @@ -44,4 +44,4 @@ std::pair::const_iterator, std::vector::const_iterat } -} // namespace grit::util +} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/reduced_classical_pl.cc b/src/eckit/geo/util/reduced_classical_pl.cc index 4fee162ac..51c8c9aaa 100644 --- a/src/eckit/geo/util/reduced_classical_pl.cc +++ b/src/eckit/geo/util/reduced_classical_pl.cc @@ -14,11 +14,11 @@ #include #include -#include "grit/exception.h" -#include "grit/types.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/types.h" -namespace grit::util { +namespace eckit::geo::util { static const std::map __classical_pls{ @@ -1342,7 +1342,7 @@ const pl_type& reduced_classical_pl(size_t N) { auto pl_half = __classical_pls.find(N); if (pl_half == __classical_pls.end()) { - throw exception::runtime_error("reduced_classical_pl: unknown N=" + std::to_string(N)); + throw BadValue("reduced_classical_pl: unknown N=" + std::to_string(N)); } ASSERT(pl_half->second.size() == N); @@ -1359,4 +1359,4 @@ const pl_type& reduced_classical_pl(size_t N) { } -} // namespace grit::util +} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/reduced_octahedral_pl.cc b/src/eckit/geo/util/reduced_octahedral_pl.cc index 2033e0244..74c3e2174 100644 --- a/src/eckit/geo/util/reduced_octahedral_pl.cc +++ b/src/eckit/geo/util/reduced_octahedral_pl.cc @@ -13,11 +13,11 @@ #include #include -#include "grit/exception.h" -#include "grit/types.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/types.h" -namespace grit::util { +namespace eckit::geo::util { const pl_type& reduced_octahedral_pl(size_t N) { @@ -41,4 +41,4 @@ const pl_type& reduced_octahedral_pl(size_t N) { } -} // namespace grit::util +} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/regular_pl.cc b/src/eckit/geo/util/regular_pl.cc index 7332e226b..4ef43b0c1 100644 --- a/src/eckit/geo/util/regular_pl.cc +++ b/src/eckit/geo/util/regular_pl.cc @@ -12,11 +12,11 @@ #include -#include "grit/exception.h" -#include "grit/types.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/types.h" -namespace grit::util { +namespace eckit::geo::util { pl_type::value_type regular_pl(size_t N) { @@ -26,4 +26,4 @@ pl_type::value_type regular_pl(size_t N) { } -} // namespace grit::util +} // namespace eckit::geo::util From 1a94ec24f1e60b3774f73334091bc79a425b24d3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 9 May 2023 17:59:30 +0100 Subject: [PATCH 189/737] eckit/geo --- src/eckit/geo/Iterator.cc | 7 +- src/eckit/geo/Iterator.h | 4 +- src/eckit/geo/Parametrisation.cc | 2 +- src/eckit/geo/Parametrisation.h | 2 +- src/eckit/geo/Projection.cc | 5 +- src/eckit/geo/Projection.h | 5 +- src/eckit/geo/Scanner.cc | 2 +- src/eckit/geo/Scanner.h | 2 +- src/eckit/geo/Search.h | 2 +- src/eckit/geo/geometry/BoundingBox.cc | 6 +- src/eckit/geo/geometry/GreatCircle.cc | 6 +- src/eckit/geo/grit-grib.cc | 5 +- src/eckit/geo/iterator/IteratorComposer.cc | 3 +- src/eckit/geo/log.cc | 2 +- src/eckit/geo/log.h | 2 +- src/eckit/geo/param/Map.cc | 3 +- src/eckit/geo/param/Map.h | 7 +- src/eckit/geo/projection/LatLonToXYZ.cc | 9 +- src/eckit/geo/projection/PROJ.cc | 5 +- src/eckit/geo/projection/PROJ.h | 6 +- src/eckit/geo/projection/Rotation.cc | 9 +- src/eckit/geo/test.cc | 3 +- src/eckit/geo/test.h | 2 +- src/eckit/geo/types.cc | 3 +- src/eckit/geo/types.h | 4 +- src/eckit/geo/types/MatrixXYZ.h | 9 +- src/eckit/geo/types/PointLatLon.h | 12 +- src/eckit/geo/types/PointXY.h | 12 +- src/eckit/geo/types/PointXYZ.h | 12 +- src/eckit/geo/util/Mutex.h | 2 +- src/eckit/geo/util/gaussian_latitudes.cc | 3 +- src/eckit/geo/util/reduced_classical_pl.cc | 669 ++++++++++----------- 32 files changed, 416 insertions(+), 409 deletions(-) diff --git a/src/eckit/geo/Iterator.cc b/src/eckit/geo/Iterator.cc index e10dd5910..f4a025e94 100644 --- a/src/eckit/geo/Iterator.cc +++ b/src/eckit/geo/Iterator.cc @@ -12,15 +12,16 @@ #include "eckit/geo/Iterator.h" +#include "eckit/exception/Exceptions.h" #include "eckit/geo/Projection.h" #include "eckit/geo/Scanner.h" -#include "eckit/exception/Exceptions.h" namespace eckit::geo { -Iterator::Iterator(Scanner* scanner, Projection* projection) : scanner_(scanner), projection_(projection) { +Iterator::Iterator(Scanner* scanner, Projection* projection) : + scanner_(scanner), projection_(projection) { ASSERT(scanner_); ASSERT(projection_); } @@ -37,4 +38,4 @@ size_t Iterator::size() const { } -} // namespace grit +} // namespace eckit::geo diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index 78e687355..8e0b35a06 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -74,7 +74,7 @@ class Iterator { Iterator& operator=(const Iterator&) = delete; Iterator& operator=(Iterator&&) = delete; - virtual bool operator++() = 0; + virtual bool operator++() = 0; // -- Methods @@ -119,4 +119,4 @@ class Iterator { }; -} // namespace grit +} // namespace eckit::geo diff --git a/src/eckit/geo/Parametrisation.cc b/src/eckit/geo/Parametrisation.cc index cf41c3345..151781d8c 100644 --- a/src/eckit/geo/Parametrisation.cc +++ b/src/eckit/geo/Parametrisation.cc @@ -112,4 +112,4 @@ std::vector Parametrisation::get_vector_string(const Parametrisatio } -}; // namespace grit +}; // namespace eckit::geo diff --git a/src/eckit/geo/Parametrisation.h b/src/eckit/geo/Parametrisation.h index 054f77470..6552f7803 100644 --- a/src/eckit/geo/Parametrisation.h +++ b/src/eckit/geo/Parametrisation.h @@ -132,4 +132,4 @@ class Parametrisation { }; -} // namespace grit +} // namespace eckit::geo diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index 4dab68db7..e851fbb57 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -256,7 +256,8 @@ std::ostream& ProjectionFactory::list(std::ostream& out) { } -ProjectionFactory::ProjectionFactory(const ProjectionFactory::key_type& key) : key_(key) { +ProjectionFactory::ProjectionFactory(const ProjectionFactory::key_type& key) : + key_(key) { util::call_once(__once, __init); util::lock_guard lock(*__mutex); @@ -277,4 +278,4 @@ ProjectionFactory::~ProjectionFactory() { } -} // namespace grit +} // namespace eckit::geo diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 436256d04..7c02d9f96 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -131,8 +131,9 @@ class ProjectionBuilder final : public ProjectionFactory { Projection* make(const Parametrisation& param) override { return new T(param); } public: - explicit ProjectionBuilder(const ProjectionFactory::key_type& key) : ProjectionFactory(key) {} + explicit ProjectionBuilder(const ProjectionFactory::key_type& key) : + ProjectionFactory(key) {} }; -} // namespace grit +} // namespace eckit::geo diff --git a/src/eckit/geo/Scanner.cc b/src/eckit/geo/Scanner.cc index abb2a2220..4a676c5b9 100644 --- a/src/eckit/geo/Scanner.cc +++ b/src/eckit/geo/Scanner.cc @@ -51,4 +51,4 @@ Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) #endif -} // namespace grit +} // namespace eckit::geo diff --git a/src/eckit/geo/Scanner.h b/src/eckit/geo/Scanner.h index 5232397cd..5bda3cfd5 100644 --- a/src/eckit/geo/Scanner.h +++ b/src/eckit/geo/Scanner.h @@ -99,4 +99,4 @@ class Scanner { }; -} // namespace grit +} // namespace eckit::geo diff --git a/src/eckit/geo/Search.h b/src/eckit/geo/Search.h index bbb99008b..9681197f5 100644 --- a/src/eckit/geo/Search.h +++ b/src/eckit/geo/Search.h @@ -38,4 +38,4 @@ using SearchXYZ = eckit::KDTreeMemory>; using SearchXY = eckit::KDTreeMemory>; -} // namespace grit +} // namespace eckit::geo diff --git a/src/eckit/geo/geometry/BoundingBox.cc b/src/eckit/geo/geometry/BoundingBox.cc index 1d79bf929..bbd5af9f0 100644 --- a/src/eckit/geo/geometry/BoundingBox.cc +++ b/src/eckit/geo/geometry/BoundingBox.cc @@ -34,7 +34,8 @@ BoundingBox::BoundingBox(double north, double west, double south, double east) : } -BoundingBox::BoundingBox() : BoundingBox(90., 0., -90., 360.) {} +BoundingBox::BoundingBox() : + BoundingBox(90., 0., -90., 360.) {} bool BoundingBox::operator==(const BoundingBox& other) const { @@ -62,8 +63,7 @@ bool BoundingBox::contains(const BoundingBox& other) const { return false; } - return contains(other.north_, other.west_) && contains(other.north_, other.east_) && - contains(other.south_, other.west_) && contains(other.south_, other.east_); + return contains(other.north_, other.west_) && contains(other.north_, other.east_) && contains(other.south_, other.west_) && contains(other.south_, other.east_); } diff --git a/src/eckit/geo/geometry/GreatCircle.cc b/src/eckit/geo/geometry/GreatCircle.cc index ccde3e45b..31cf15cf3 100644 --- a/src/eckit/geo/geometry/GreatCircle.cc +++ b/src/eckit/geo/geometry/GreatCircle.cc @@ -27,7 +27,8 @@ static bool pole(double lat) { } -GreatCircle::GreatCircle(const PointLatLon& A, const PointLatLon& B) : A_(A), B_(B) { +GreatCircle::GreatCircle(const PointLatLon& A, const PointLatLon& B) : + A_(A), B_(B) { const bool Apole = pole(A_.lat); const bool Bpole = pole(B_.lat); const double lon12_deg = util::normalise_longitude_to_minimum(A_.lon - B_.lon, -180.); @@ -55,8 +56,7 @@ std::vector GreatCircle::latitude(double lon) const { const double lambda2p = util::degrees_to_radians * (lon - B_.lon); const double lambda = util::degrees_to_radians * util::normalise_longitude_to_minimum(B_.lon - A_.lon, -180.); - double lat = - std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); + double lat = std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); return {util::radians_to_degrees * lat}; } diff --git a/src/eckit/geo/grit-grib.cc b/src/eckit/geo/grit-grib.cc index 31f86e79f..9ff138bbd 100644 --- a/src/eckit/geo/grit-grib.cc +++ b/src/eckit/geo/grit-grib.cc @@ -19,8 +19,8 @@ #include #include -#include "eckit/geo/Parametrisation.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Parametrisation.h" #include "eckit/geo/grit.h" #include "eckit/geo/param/Map.h" #include "eckit/geo/types.h" @@ -96,7 +96,8 @@ class GribParametrisation final : public grit::Parametrisation, // -- Constructors - explicit GribParametrisation(codes_handle* h) : t(h, &codes_handle_delete) { ASSERT(*this); } + explicit GribParametrisation(codes_handle* h) : + t(h, &codes_handle_delete) { ASSERT(*this); } // -- Destructor // None diff --git a/src/eckit/geo/iterator/IteratorComposer.cc b/src/eckit/geo/iterator/IteratorComposer.cc index 3b76ce8eb..cf4cce71c 100644 --- a/src/eckit/geo/iterator/IteratorComposer.cc +++ b/src/eckit/geo/iterator/IteratorComposer.cc @@ -18,7 +18,8 @@ namespace eckit::geo::iterator { -IteratorComposer::IteratorComposer(Scanner* scanner, const std::vector& projections) : scanner_(scanner) { +IteratorComposer::IteratorComposer(Scanner* scanner, const std::vector& projections) : + scanner_(scanner) { ASSERT(scanner_); projections_.reserve(projections.size()); diff --git a/src/eckit/geo/log.cc b/src/eckit/geo/log.cc index e35823bbf..86454d535 100644 --- a/src/eckit/geo/log.cc +++ b/src/eckit/geo/log.cc @@ -24,4 +24,4 @@ std::ostream& info = std::clog; std::ostream& log = std::clog; -} // namespace grit +} // namespace eckit::geo diff --git a/src/eckit/geo/log.h b/src/eckit/geo/log.h index b680768d2..4b3138877 100644 --- a/src/eckit/geo/log.h +++ b/src/eckit/geo/log.h @@ -24,4 +24,4 @@ extern std::ostream& info; extern std::ostream& log; -} // namespace grit +} // namespace eckit::geo diff --git a/src/eckit/geo/param/Map.cc b/src/eckit/geo/param/Map.cc index ad94a53a6..0b85928d1 100644 --- a/src/eckit/geo/param/Map.cc +++ b/src/eckit/geo/param/Map.cc @@ -20,7 +20,8 @@ namespace eckit::geo::param { -Map::Map(const container_type& other) : map_(other) {} +Map::Map(const container_type& other) : + map_(other) {} bool Map::has(const key_type& key) const { diff --git a/src/eckit/geo/param/Map.h b/src/eckit/geo/param/Map.h index 4a2a37ada..5e6c3323f 100644 --- a/src/eckit/geo/param/Map.h +++ b/src/eckit/geo/param/Map.h @@ -25,10 +25,9 @@ class Map final : public Parametrisation { public: // -- Types - using value_type = - std::variant, - std::vector, std::vector, std::vector, std::vector, - std::vector, std::vector, std::vector>; + using value_type = std::variant, + std::vector, std::vector, std::vector, std::vector, + std::vector, std::vector, std::vector>; using container_type = std::map; diff --git a/src/eckit/geo/projection/LatLonToXYZ.cc b/src/eckit/geo/projection/LatLonToXYZ.cc index fb469bfc7..2bec7971b 100644 --- a/src/eckit/geo/projection/LatLonToXYZ.cc +++ b/src/eckit/geo/projection/LatLonToXYZ.cc @@ -32,7 +32,8 @@ LatLonToXYZ::LatLonToXYZ(double a, double b) { using S = geometry::Sphere; const double R_; - explicit LatLonToSphereXYZ(double R) : R_(R) {} + explicit LatLonToSphereXYZ(double R) : + R_(R) {} PointXYZ operator()(const PointLatLon& p) const override { return S::ll_to_xyz(R_, p, 0.); } PointLatLon operator()(const PointXYZ& q) const override { return S::xyz_to_ll(R_, q); } }; @@ -42,7 +43,8 @@ LatLonToXYZ::LatLonToXYZ(double a, double b) { const double a_; const double b_; - explicit LatLonToSpheroidXYZ(double a, double b) : a_(a), b_(b) {} + explicit LatLonToSpheroidXYZ(double a, double b) : + a_(a), b_(b) {} PointXYZ operator()(const PointLatLon& p) const override { return S::ll_to_xyz(a_, b_, p, 0.); } PointLatLon operator()(const PointXYZ& q) const override { NOTIMP; } }; @@ -52,7 +54,8 @@ LatLonToXYZ::LatLonToXYZ(double a, double b) { } -LatLonToXYZ::LatLonToXYZ(double R) : LatLonToXYZ(R, R) {} +LatLonToXYZ::LatLonToXYZ(double R) : + LatLonToXYZ(R, R) {} LatLonToXYZ::LatLonToXYZ(const Parametrisation& param) : diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 0c577cd1a..5af654b62 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -12,8 +12,8 @@ #include "eckit/geo/projection/PROJ.h" -#include "eckit/geo/Parametrisation.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Parametrisation.h" #include "eckit/geo/types.h" @@ -42,7 +42,8 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini Point convert(const PJ_COORD& c) const final { return PointLatLon::make(c.enu.n, c.enu.e, lon_minimum_); } - explicit LatLon(double lon_minimum) : lon_minimum_(lon_minimum) {} + explicit LatLon(double lon_minimum) : + lon_minimum_(lon_minimum) {} const double lon_minimum_; }; diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index d39f3b55b..2f1d1dbd2 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -29,13 +29,15 @@ class PROJ final : public Projection { struct pj_t : std::unique_ptr { using t = std::unique_ptr; - explicit pj_t(PJ* ptr) : t(ptr, &proj_destroy) {} + explicit pj_t(PJ* ptr) : + t(ptr, &proj_destroy) {} explicit operator PJ*() const { return t::get(); } }; struct ctx_t : std::unique_ptr { using t = std::unique_ptr; - explicit ctx_t(PJ_CONTEXT* ptr) : t(ptr, &proj_context_destroy) {} + explicit ctx_t(PJ_CONTEXT* ptr) : + t(ptr, &proj_context_destroy) {} explicit operator PJ_CONTEXT*() const { return t::get(); } }; diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index e008fc4c5..a529cba2d 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -27,7 +27,8 @@ namespace eckit::geo::projection { static ProjectionBuilder __projection("rotation"); -Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : rotated_(true) { +Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : + rotated_(true) { using M = types::MatrixXYZ; struct No final : Rotate { @@ -35,13 +36,15 @@ Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : }; struct Angle final : Rotate { - explicit Angle(double angle) : angle_(angle) {} + explicit Angle(double angle) : + angle_(angle) {} PointLatLon operator()(const PointLatLon& p) const override { return {p.lat, p.lon + angle_}; } const double angle_; }; struct Matrix final : Rotate { - explicit Matrix(M&& R) : R_(R) {} + explicit Matrix(M&& R) : + R_(R) {} PointLatLon operator()(const PointLatLon& p) const override { return geometry::Sphere::xyz_to_ll(1., R_ * geometry::Sphere::ll_to_xyz(1., p, 0.)); } diff --git a/src/eckit/geo/test.cc b/src/eckit/geo/test.cc index 2a58d3a86..94c2ff523 100644 --- a/src/eckit/geo/test.cc +++ b/src/eckit/geo/test.cc @@ -14,8 +14,7 @@ #include "eckit/exception/Exceptions.h" -bool operator==(const eckit::geo::Point &p, const eckit::geo::Point &q) -{ +bool operator==(const eckit::geo::Point& p, const eckit::geo::Point& q) { ASSERT(p.index() == q.index()); constexpr double eps = 1e-6; diff --git a/src/eckit/geo/test.h b/src/eckit/geo/test.h index c4f317ecf..38fd29eb4 100644 --- a/src/eckit/geo/test.h +++ b/src/eckit/geo/test.h @@ -14,4 +14,4 @@ #include "eckit/geo/types.h" -bool operator==(const eckit::geo::Point &, const eckit::geo::Point &); +bool operator==(const eckit::geo::Point&, const eckit::geo::Point&); diff --git a/src/eckit/geo/types.cc b/src/eckit/geo/types.cc index ead4fa907..ff0095e89 100644 --- a/src/eckit/geo/types.cc +++ b/src/eckit/geo/types.cc @@ -14,8 +14,7 @@ #include "eckit/exception/Exceptions.h" -std::ostream &operator<<(std::ostream &out, const eckit::geo::Point &p) -{ +std::ostream& operator<<(std::ostream& out, const eckit::geo::Point& p) { return std::holds_alternative(p) ? out << std::get(p) : std::holds_alternative(p) diff --git a/src/eckit/geo/types.h b/src/eckit/geo/types.h index 421c2fadb..f9a197610 100644 --- a/src/eckit/geo/types.h +++ b/src/eckit/geo/types.h @@ -33,6 +33,6 @@ using Point = std::variant; using pl_type = std::vector; -} // namespace grit +} // namespace eckit::geo -std::ostream &operator<<(std::ostream &, const eckit::geo::Point &); +std::ostream& operator<<(std::ostream&, const eckit::geo::Point&); diff --git a/src/eckit/geo/types/MatrixXYZ.h b/src/eckit/geo/types/MatrixXYZ.h index 5f6e74f6d..7f8ed6bc6 100644 --- a/src/eckit/geo/types/MatrixXYZ.h +++ b/src/eckit/geo/types/MatrixXYZ.h @@ -38,9 +38,12 @@ class MatrixXYZ final : protected std::array { // -- Constructors - MatrixXYZ(T xx, T xy, T xz, T yx, T yy, T yz, T zx, T zy, T zz) : P{xx, xy, xz, yx, yy, yz, zx, zy, zz} {} - MatrixXYZ(const MatrixXYZ& other) : P(other) {} - MatrixXYZ(MatrixXYZ&& other) : P(other) {} + MatrixXYZ(T xx, T xy, T xz, T yx, T yy, T yz, T zx, T zy, T zz) : + P{xx, xy, xz, yx, yy, yz, zx, zy, zz} {} + MatrixXYZ(const MatrixXYZ& other) : + P(other) {} + MatrixXYZ(MatrixXYZ&& other) : + P(other) {} // -- Destructor diff --git a/src/eckit/geo/types/PointLatLon.h b/src/eckit/geo/types/PointLatLon.h index 17d434e00..2a6940dc9 100644 --- a/src/eckit/geo/types/PointLatLon.h +++ b/src/eckit/geo/types/PointLatLon.h @@ -52,9 +52,12 @@ class PointLatLon final : protected std::array { // -- Constructors - PointLatLon(T lat, T lon) : P{lat, lon} { ASSERT_MSG(-90. <= lat && lat <= 90., "PointLatLon: invalid latitude"); } - PointLatLon(const PointLatLon& other) : P(other) {} - PointLatLon(PointLatLon&& other) : P(other) {} + PointLatLon(T lat, T lon) : + P{lat, lon} { ASSERT_MSG(-90. <= lat && lat <= 90., "PointLatLon: invalid latitude"); } + PointLatLon(const PointLatLon& other) : + P(other) {} + PointLatLon(PointLatLon&& other) : + P(other) {} // -- Destructor @@ -77,8 +80,7 @@ class PointLatLon final : protected std::array { bool is_approximately_equal(const PointLatLon& other, T eps) const { const auto dlon = normal(other.lon, lon) - lon; - return std::abs(lat - other.lat) < eps && - (std::abs(lat - 90.) < eps || std::abs(lat + 90.) < eps || dlon < eps || dlon - 360. < eps); + return std::abs(lat - other.lat) < eps && (std::abs(lat - 90.) < eps || std::abs(lat + 90.) < eps || dlon < eps || dlon - 360. < eps); }; // -- Members diff --git a/src/eckit/geo/types/PointXY.h b/src/eckit/geo/types/PointXY.h index 490048872..0e6b6dda0 100644 --- a/src/eckit/geo/types/PointXY.h +++ b/src/eckit/geo/types/PointXY.h @@ -35,10 +35,14 @@ class PointXY final : protected std::array { // -- Constructors - PointXY() : P{0, 0} {} - PointXY(T x, T y) : P{x, y} {} - PointXY(const PointXY& other) : P(other) {} - PointXY(PointXY&& other) : P(other) {} + PointXY() : + P{0, 0} {} + PointXY(T x, T y) : + P{x, y} {} + PointXY(const PointXY& other) : + P(other) {} + PointXY(PointXY&& other) : + P(other) {} // -- Destructor diff --git a/src/eckit/geo/types/PointXYZ.h b/src/eckit/geo/types/PointXYZ.h index b37f00ad4..0e90db0e4 100644 --- a/src/eckit/geo/types/PointXYZ.h +++ b/src/eckit/geo/types/PointXYZ.h @@ -37,10 +37,14 @@ class PointXYZ final : protected std::array { // -- Constructors - PointXYZ() : P{0, 0, 0} {} - PointXYZ(T x, T y, T z) : P{x, y, z} {} - PointXYZ(const PointXYZ& other) : P(other) {} - PointXYZ(PointXYZ&& other) : P(other) {} + PointXYZ() : + P{0, 0, 0} {} + PointXYZ(T x, T y, T z) : + P{x, y, z} {} + PointXYZ(const PointXYZ& other) : + P(other) {} + PointXYZ(PointXYZ&& other) : + P(other) {} // -- Destructor diff --git a/src/eckit/geo/util/Mutex.h b/src/eckit/geo/util/Mutex.h index a1be56112..447d12e73 100644 --- a/src/eckit/geo/util/Mutex.h +++ b/src/eckit/geo/util/Mutex.h @@ -32,4 +32,4 @@ inline void call_once(once_flag& flag, Callable&& fun) { pthread_once(&(flag.once_), fun); } -} // namespace eckit::geo::util +} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/gaussian_latitudes.cc b/src/eckit/geo/util/gaussian_latitudes.cc index 2eec53de6..4fd5a8ba6 100644 --- a/src/eckit/geo/util/gaussian_latitudes.cc +++ b/src/eckit/geo/util/gaussian_latitudes.cc @@ -38,8 +38,7 @@ std::vector gaussian_latitudes(size_t N, bool increasing) { } for (size_t j = 2; j <= i - (i % 2); j += 2) { - zfn[i - j] = zfn[i - j + 2] * static_cast((j - 1) * (2 * i - j + 2)) / - static_cast(j * (2 * i - j + 1)); + zfn[i - j] = zfn[i - j + 2] * static_cast((j - 1) * (2 * i - j + 2)) / static_cast(j * (2 * i - j + 1)); } } diff --git a/src/eckit/geo/util/reduced_classical_pl.cc b/src/eckit/geo/util/reduced_classical_pl.cc index 51c8c9aaa..00f74d991 100644 --- a/src/eckit/geo/util/reduced_classical_pl.cc +++ b/src/eckit/geo/util/reduced_classical_pl.cc @@ -24,31 +24,14 @@ namespace eckit::geo::util { static const std::map __classical_pls{ {16, {20, 27, 32, 40, 45, 48, 60, 60, 64, 64, 64, 64, 64, 64, 64, 64}}, {24, {20, 25, 36, 40, 45, 48, 54, 60, 64, 72, 80, 80, 90, 90, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96}}, - {32, {20, 27, 36, 40, 45, 50, 60, 64, 72, 75, 80, 90, 90, 96, 100, 108, - 108, 120, 120, 120, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}}, - {48, {20, 25, 36, 40, 45, 50, 60, 60, 72, 75, 80, 90, 96, 100, 108, 120, - 120, 120, 128, 135, 144, 144, 160, 160, 160, 160, 160, 180, 180, 180, 180, 180, - 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192}}, - {64, {20, 25, 36, 40, 45, 54, 60, 64, 72, 75, 80, 90, 96, 100, 108, 120, 120, 125, 135, 135, 144, 150, - 160, 160, 180, 180, 180, 180, 192, 192, 200, 200, 216, 216, 216, 216, 225, 225, 225, 240, 240, 240, 240, 243, - 250, 250, 250, 250, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256}}, - {80, {18, 25, 36, 40, 45, 54, 60, 64, 72, 72, 80, 90, 96, 100, 108, 120, 120, 128, 135, 144, - 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 200, 216, 216, 216, 225, 225, 240, 240, 240, 256, - 256, 256, 256, 288, 288, 288, 288, 288, 288, 288, 288, 288, 300, 300, 300, 300, 320, 320, 320, 320, - 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320}}, - {96, {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 96, 100, 108, 120, 120, 125, 135, 144, - 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 200, 216, 216, 225, 225, 240, 240, 240, 250, 250, - 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, 320, 320, 324, 360, 360, 360, - 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 375, 375, 375, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384}}, - {128, {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 90, 100, 108, 120, 120, 125, 128, 144, 144, 150, - 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 240, 250, 250, 256, 270, 270, 288, 288, - 288, 300, 300, 320, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, 400, - 400, 400, 400, 405, 432, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 450, 480, 480, 480, 480, 480, 480, - 480, 480, 480, 480, 486, 486, 486, 500, 500, 500, 500, 500, 500, 500, 512, 512, 512, 512, 512, 512, 512, 512, - 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512}}, + {32, {20, 27, 36, 40, 45, 50, 60, 64, 72, 75, 80, 90, 90, 96, 100, 108, 108, 120, 120, 120, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}}, + {48, {20, 25, 36, 40, 45, 50, 60, 60, 72, 75, 80, 90, 96, 100, 108, 120, 120, 120, 128, 135, 144, 144, 160, 160, 160, 160, 160, 180, 180, 180, 180, 180, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192}}, + {64, {20, 25, 36, 40, 45, 54, 60, 64, 72, 75, 80, 90, 96, 100, 108, 120, 120, 125, 135, 135, 144, 150, 160, 160, 180, 180, 180, 180, 192, 192, 200, 200, 216, 216, 216, 216, 225, 225, 225, 240, 240, 240, 240, 243, 250, 250, 250, 250, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256}}, + {80, {18, 25, 36, 40, 45, 54, 60, 64, 72, 72, 80, 90, 96, 100, 108, 120, 120, 128, 135, 144, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 200, 216, 216, 216, 225, 225, 240, 240, 240, 256, 256, 256, 256, 288, 288, 288, 288, 288, 288, 288, 288, 288, 300, 300, 300, 300, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320}}, + {96, {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 96, 100, 108, 120, 120, 125, 135, 144, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 200, 216, 216, 225, 225, 240, 240, 240, 250, 250, 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 375, 375, 375, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384}}, + {128, {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 90, 100, 108, 120, 120, 125, 128, 144, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 240, 250, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, 400, 400, 400, 400, 405, 432, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 450, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 486, 486, 486, 500, 500, 500, 500, 500, 500, 500, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512}}, {160, - {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 90, 96, 108, 120, 120, 125, 128, 135, 144, 150, 160, + {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 90, 96, 108, 120, 120, 125, 128, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, 375, 375, 384, 384, 400, 400, 400, 405, 432, 432, 432, 432, 432, 450, 450, 450, 450, 480, 480, 480, 480, 480, 480, 480, 500, 500, 500, 500, 500, 512, 512, 540, 540, 540, @@ -56,7 +39,7 @@ static const std::map __classical_pls{ 600, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640}}, {200, - {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, + {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, 375, 375, 384, 400, 400, 400, 400, 432, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 480, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, 540, 540, 576, 576, @@ -66,30 +49,30 @@ static const std::map __classical_pls{ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800}}, {256, - {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, - 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 243, 250, - 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, - 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, - 486, 500, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, - 600, 600, 600, 640, 640, 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 675, 720, - 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, 750, 750, 750, 750, 768, 768, 768, 768, - 800, 800, 800, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, - 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, - 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 972, 972, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, + 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 243, 250, + 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, + 486, 500, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, + 600, 600, 600, 640, 640, 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 675, 720, + 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, 750, 750, 750, 750, 768, 768, 768, 768, + 800, 800, 800, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, + 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 972, 972, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024}}, {320, - {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, - 135, 144, 144, 150, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 240, 250, - 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, - 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, - 500, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, - 600, 640, 640, 640, 640, 640, 640, 640, 648, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, - 720, 720, 720, 720, 729, 750, 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, - 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, - 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 972, 972, 1000, + {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, + 135, 144, 144, 150, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 240, 250, + 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, + 600, 640, 640, 640, 640, 640, 640, 640, 648, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, + 720, 720, 720, 720, 729, 750, 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, + 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, + 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, @@ -99,15 +82,15 @@ static const std::map __classical_pls{ 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280}}, {400, - {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, - 128, 144, 144, 150, 160, 160, 180, 180, 192, 192, 200, 200, 216, 216, 225, 240, 240, 240, 250, - 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, - 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, - 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, - 640, 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, - 720, 729, 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, - 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, - 960, 960, 960, 960, 960, 960, 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, + 128, 144, 144, 150, 160, 160, 180, 180, 192, 192, 200, 200, 216, 216, 225, 240, 240, 240, 250, + 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, + 640, 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, + 720, 729, 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, + 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, + 960, 960, 960, 960, 960, 960, 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1215, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, @@ -122,15 +105,15 @@ static const std::map __classical_pls{ 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600}}, {512, - {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 100, 108, 120, 125, - 128, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, - 250, 256, 270, 270, 288, 288, 288, 300, 320, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, - 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, - 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 640, - 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, - 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, - 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, - 960, 960, 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 100, 108, 120, 125, + 128, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, + 250, 256, 270, 270, 288, 288, 288, 300, 320, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 640, + 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, @@ -150,15 +133,15 @@ static const std::map __classical_pls{ 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048}}, {576, - {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 100, 108, 120, 120, - 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, - 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, - 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, - 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, 640, - 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, - 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, - 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 100, 108, 120, 120, + 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, + 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, 640, + 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, @@ -182,15 +165,15 @@ static const std::map __classical_pls{ 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304}}, {640, - {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 90, 96, 100, 108, 120, 120, - 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 243, - 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, - 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, - 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, 640, - 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, - 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, - 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 90, 96, 100, 108, 120, 120, + 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 243, + 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, 640, + 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, + 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, @@ -217,15 +200,15 @@ static const std::map __classical_pls{ 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560}}, {800, - {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 80, 90, 90, 96, 100, 108, 120, 120, - 125, 128, 135, 144, 150, 160, 160, 180, 180, 192, 192, 200, 200, 216, 216, 225, 240, 240, 240, - 250, 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 375, - 375, 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 486, - 500, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 625, - 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, - 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, - 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 80, 90, 90, 96, 100, 108, 120, 120, + 125, 128, 135, 144, 150, 160, 160, 180, 180, 192, 192, 200, 200, 216, 216, 225, 240, 240, 240, + 250, 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 375, + 375, 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 486, + 500, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 625, + 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, + 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, @@ -261,15 +244,15 @@ static const std::map __classical_pls{ 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200}}, {1024, - {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, - 125, 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, - 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, - 375, 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, - 486, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, - 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, - 729, 750, 750, 750, 750, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, - 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, + 125, 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, + 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, + 375, 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, + 486, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, + 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 750, 750, 750, 750, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, @@ -316,15 +299,15 @@ static const std::map __classical_pls{ 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096}}, {1280, - {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, - 120, 125, 135, 135, 144, 144, 160, 160, 180, 180, 180, 192, 200, 200, 216, 216, 225, 240, 240, - 240, 250, 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, - 375, 375, 375, 384, 400, 400, 400, 432, 432, 432, 432, 432, 450, 450, 480, 480, 480, 480, 480, - 486, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, - 625, 625, 625, 625, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, - 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, - 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, + 120, 125, 135, 135, 144, 144, 160, 160, 180, 180, 180, 192, 200, 200, 216, 216, 225, 240, 240, + 240, 250, 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, + 375, 375, 375, 384, 400, 400, 400, 432, 432, 432, 432, 432, 450, 450, 480, 480, 480, 480, 480, + 486, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, + 625, 625, 625, 625, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, @@ -385,15 +368,15 @@ static const std::map __classical_pls{ 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120}}, {1600, - {18, 25, 32, 40, 45, 50, 54, 60, 72, 72, 75, 80, 90, 90, 96, 100, 108, 120, 120, - 120, 125, 128, 135, 144, 144, 150, 160, 160, 162, 180, 180, 180, 192, 192, 216, 216, 225, 240, - 240, 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, - 360, 375, 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, - 480, 486, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, - 600, 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, - 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, - 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 54, 60, 72, 72, 75, 80, 90, 90, 96, 100, 108, 120, 120, + 120, 125, 128, 135, 144, 144, 150, 160, 160, 162, 180, 180, 180, 192, 192, 216, 216, 225, 240, + 240, 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, + 360, 375, 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, + 480, 486, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, + 600, 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, @@ -471,15 +454,15 @@ static const std::map __classical_pls{ 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400}}, {2000, - {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, - 120, 125, 135, 135, 144, 144, 150, 160, 160, 180, 180, 180, 180, 192, 192, 192, 200, 216, 216, - 216, 225, 240, 240, 243, 250, 256, 270, 270, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, - 360, 360, 375, 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, - 480, 486, 500, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, - 600, 625, 625, 625, 625, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, - 720, 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, - 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, + 120, 125, 135, 135, 144, 144, 150, 160, 160, 180, 180, 180, 180, 192, 192, 192, 200, 216, 216, + 216, 225, 240, 240, 243, 250, 256, 270, 270, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, + 360, 360, 375, 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, + 480, 486, 500, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, + 600, 625, 625, 625, 625, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, + 720, 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, @@ -578,113 +561,113 @@ static const std::map __classical_pls{ 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000}}, {4000, - {18, 24, 32, 40, 45, 48, 54, 60, 64, 72, 75, 80, 90, 90, 96, 100, - 108, 108, 120, 120, 125, 128, 135, 135, 144, 150, 150, 160, 160, 180, 180, 180, - 180, 192, 192, 192, 200, 216, 216, 216, 216, 225, 225, 240, 240, 240, 243, 250, - 256, 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, 320, - 324, 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, 400, - 400, 400, 405, 405, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 480, 480, - 480, 480, 480, 480, 486, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, 540, - 540, 540, 576, 576, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, 600, 600, - 625, 625, 625, 625, 625, 625, 640, 640, 640, 648, 648, 675, 675, 675, 675, 675, - 675, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, 750, - 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, 800, 810, 810, - 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, - 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, - 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, - 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1152, - 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1215, 1250, - 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, - 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, - 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, - 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, - 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, 1600, - 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1620, 1728, 1728, - 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, - 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, - 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, 1875, - 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, 1920, - 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, 2000, - 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, 2025, 2025, 2025, 2048, - 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, - 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, - 2187, 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, - 2250, 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, - 2304, 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, - 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2500, 2500, 2500, 2500, 2500, - 2500, 2500, 2500, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, 2700, 2700, 2700, - 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, 2880, 2880, 2880, 2880, 2880, - 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, - 2916, 2916, 2916, 2916, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, - 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3200, 3200, - 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3375, 3375, 3375, 3375, - 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3456, 3456, - 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, - 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3645, 3645, 3645, 3645, 3645, - 3645, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, - 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3888, 3888, 3888, - 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, - 4000, 4000, 4000, 4050, 4050, 4050, 4050, 4050, 4050, 4096, 4096, 4096, 4096, 4096, 4096, 4096, - 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, - 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4374, - 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, - 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, 4608, 4608, 4608, 4608, 4608, - 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, 4800, 4800, 4800, 4800, 4800, - 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, - 4800, 4800, 4800, 4800, 4800, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 5000, 5000, - 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, - 5000, 5000, 5000, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, - 5120, 5120, 5120, 5120, 5120, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5400, 5400, - 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, - 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5625, - 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, - 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, - 5625, 5625, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, - 5760, 5760, 5760, 5760, 5760, 5760, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, - 5832, 5832, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, - 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6075, 6075, 6075, 6075, - 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6144, 6144, 6144, 6144, 6144, 6144, 6144, - 6144, 6144, 6144, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, - 6250, 6250, 6250, 6250, 6250, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, - 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6480, 6480, 6480, 6480, - 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6561, 6561, 6561, 6561, 6561, 6561, 6561, - 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, - 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, - 6750, 6750, 6750, 6750, 6750, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, - 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, - 6912, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, - 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, - 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, - 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, - 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, - 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, - 7500, 7500, 7500, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, - 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, - 7680, 7680, 7680, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, - 7776, 7776, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, - 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, - 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8100, 8100, 8100, 8100, 8100, 8100, - 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8748, 8748, 8748, 8748, - 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, - 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, - 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, - 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9216, 9216, 9216, - 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, - 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, - 9216, 9216, 9216, 9216, 9216, 9216, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, - 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, - 9375, 9375, 9375, 9375, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, - 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, - 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, - 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, - 9720, 9720, 9720, 9720, 9720, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, + {18, 24, 32, 40, 45, 48, 54, 60, 64, 72, 75, 80, 90, 90, 96, 100, + 108, 108, 120, 120, 125, 128, 135, 135, 144, 150, 150, 160, 160, 180, 180, 180, + 180, 192, 192, 192, 200, 216, 216, 216, 216, 225, 225, 240, 240, 240, 243, 250, + 256, 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, 320, + 324, 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, 400, + 400, 400, 405, 405, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 480, 480, + 480, 480, 480, 480, 486, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, 540, + 540, 540, 576, 576, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, 600, 600, + 625, 625, 625, 625, 625, 625, 640, 640, 640, 648, 648, 675, 675, 675, 675, 675, + 675, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, 750, + 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, 800, 810, 810, + 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, + 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, + 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, + 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1152, + 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1215, 1250, + 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, + 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, + 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1620, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, + 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, 1875, + 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, 1920, + 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, 2025, 2025, 2025, 2048, + 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, + 2187, 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, + 2250, 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2500, 2500, 2500, 2500, 2500, + 2500, 2500, 2500, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, 2700, 2700, 2700, + 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2916, 2916, 2916, 2916, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, + 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3375, 3375, 3375, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3456, 3456, + 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3645, 3645, 3645, 3645, 3645, + 3645, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, + 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3888, 3888, 3888, + 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4050, 4050, 4050, 4050, 4050, 4050, 4096, 4096, 4096, 4096, 4096, 4096, 4096, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4374, + 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, 4608, 4608, 4608, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, + 5760, 5760, 5760, 5760, 5760, 5760, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, + 5832, 5832, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, + 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6075, 6075, 6075, 6075, + 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 6144, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, + 6250, 6250, 6250, 6250, 6250, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6480, 6480, 6480, 6480, + 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6561, 6561, 6561, 6561, 6561, 6561, 6561, + 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, + 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, + 6750, 6750, 6750, 6750, 6750, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, + 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, + 6912, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, + 7776, 7776, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8100, 8100, 8100, 8100, 8100, 8100, + 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8748, 8748, 8748, 8748, + 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9216, 9216, 9216, + 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, + 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, + 9216, 9216, 9216, 9216, 9216, 9216, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, + 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, + 9375, 9375, 9375, 9375, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, + 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, + 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, + 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, + 9720, 9720, 9720, 9720, 9720, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10125, 10125, 10125, @@ -829,116 +812,116 @@ static const std::map __classical_pls{ 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000}}, {8000, - {16, 24, 30, 36, 40, 45, 54, 60, 64, 72, 72, 75, 81, 90, 90, 96, - 100, 108, 120, 120, 120, 125, 128, 135, 144, 144, 150, 160, 160, 160, 180, 180, - 180, 180, 192, 192, 192, 200, 216, 216, 216, 216, 225, 225, 240, 240, 240, 243, - 250, 250, 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, - 320, 324, 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, - 400, 400, 400, 405, 405, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 480, - 480, 480, 480, 480, 480, 480, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, - 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, - 600, 625, 625, 625, 625, 625, 625, 640, 640, 640, 640, 648, 675, 675, 675, 675, - 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, - 750, 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, 800, 800, - 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, - 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 960, 960, 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, - 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, - 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, - 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, - 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1280, - 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, - 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, - 1440, 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, - 1500, 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, - 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1620, 1728, - 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, - 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, - 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, - 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, - 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, - 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, 2025, 2025, 2025, 2048, - 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, - 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, - 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, - 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, - 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, - 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2430, 2430, 2430, 2430, 2500, - 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2560, - 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, - 2592, 2592, 2592, 2592, 2592, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, - 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, - 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, - 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, - 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2916, 2916, 2916, 2916, 2916, 2916, - 2916, 2916, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, - 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, - 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, - 3125, 3125, 3125, 3125, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, - 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3375, - 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, - 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, - 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, - 3456, 3456, 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, - 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, - 3600, 3600, 3600, 3600, 3600, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, - 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, - 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3840, 3840, 3840, 3840, 3840, 3840, 3840, - 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3888, - 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, - 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, - 4000, 4000, 4000, 4000, 4000, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, - 4050, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4320, 4320, 4320, - 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, - 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, - 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, - 4320, 4320, 4320, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, - 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, - 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, - 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, - 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, - 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, - 4800, 4860, 4860, 4860, 4860, 4860, 4860, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, - 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, - 5120, 5120, 5120, 5120, 5120, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5400, 5400, 5400, 5400, - 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, - 5400, 5400, 5400, 5400, 5400, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, - 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, - 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, - 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 6000, 6000, 6000, 6000, 6000, 6000, 6000, - 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6075, 6075, - 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6250, - 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6400, 6400, 6400, - 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, - 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6561, 6561, 6561, 6561, 6561, - 6561, 6561, 6561, 6561, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, - 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6912, 6912, 6912, - 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, - 6912, 6912, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, - 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, - 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, - 7290, 7290, 7290, 7290, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, - 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, - 7500, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, - 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7776, 7776, 7776, 7776, 7776, 7776, - 7776, 7776, 7776, 7776, 7776, 7776, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, - 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, - 8000, 8000, 8000, 8000, 8000, 8000, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, - 8100, 8100, 8100, 8100, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, - 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, - 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, - 9000, 9000, 9000, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, - 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, - 9216, 9216, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, - 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9600, 9600, 9600, 9600, 9600, 9600, - 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, - 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9720, 9720, 9720, 9720, 9720, 9720, - 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 10000, 10000, 10000, 10000, + {16, 24, 30, 36, 40, 45, 54, 60, 64, 72, 72, 75, 81, 90, 90, 96, + 100, 108, 120, 120, 120, 125, 128, 135, 144, 144, 150, 160, 160, 160, 180, 180, + 180, 180, 192, 192, 192, 200, 216, 216, 216, 216, 225, 225, 240, 240, 240, 243, + 250, 250, 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, + 320, 324, 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, + 400, 400, 400, 405, 405, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 480, + 480, 480, 480, 480, 480, 480, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, + 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, + 600, 625, 625, 625, 625, 625, 625, 640, 640, 640, 640, 648, 675, 675, 675, 675, + 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, + 750, 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, 800, 800, + 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, + 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 960, 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, + 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, + 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, + 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1280, + 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, + 1500, 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1620, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, + 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, + 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, + 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, 2025, 2025, 2025, 2048, + 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, + 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, + 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2430, 2430, 2430, 2430, 2500, + 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2560, + 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, + 2592, 2592, 2592, 2592, 2592, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, + 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2916, 2916, 2916, 2916, 2916, 2916, + 2916, 2916, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, + 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, + 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, + 3125, 3125, 3125, 3125, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, + 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, + 3456, 3456, 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, + 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, + 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3840, 3840, 3840, 3840, 3840, 3840, 3840, + 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3888, + 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4000, 4000, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, + 4050, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4860, 4860, 4860, 4860, 4860, 4860, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, + 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 6000, 6000, 6000, 6000, 6000, 6000, 6000, + 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6075, 6075, + 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6250, + 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6561, 6561, 6561, 6561, 6561, + 6561, 6561, 6561, 6561, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, + 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6912, 6912, 6912, + 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, + 6912, 6912, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, + 7290, 7290, 7290, 7290, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7776, 7776, 7776, 7776, 7776, 7776, + 7776, 7776, 7776, 7776, 7776, 7776, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, + 8100, 8100, 8100, 8100, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, + 9000, 9000, 9000, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, + 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, + 9216, 9216, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, + 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9600, 9600, 9600, 9600, 9600, 9600, + 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, + 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9720, 9720, 9720, 9720, 9720, 9720, + 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, From 2bf14489d93c9715bcbc35567161666b568b6277 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 May 2023 12:20:29 +0100 Subject: [PATCH 190/737] eckit/geo --- src/eckit/geo/CMakeLists.txt | 5 ----- src/eckit/geo/Projection.cc | 38 +++++++++++++++--------------------- src/eckit/geo/grit.h.in | 4 ---- src/eckit/geo/log.cc | 27 ------------------------- src/eckit/geo/log.h | 27 ------------------------- src/eckit/geo/test.cc | 32 ------------------------------ src/eckit/geo/test.h | 17 ---------------- src/eckit/geo/types.cc | 17 ++++++++++++++++ src/eckit/geo/types.h | 2 ++ src/eckit/geo/util/Mutex.h | 35 --------------------------------- 10 files changed, 35 insertions(+), 169 deletions(-) delete mode 100644 src/eckit/geo/grit.h.in delete mode 100644 src/eckit/geo/log.cc delete mode 100644 src/eckit/geo/log.h delete mode 100644 src/eckit/geo/test.cc delete mode 100644 src/eckit/geo/test.h delete mode 100644 src/eckit/geo/util/Mutex.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 474b9218c..af4b94f48 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -18,8 +18,6 @@ list(APPEND eckit_geo_srcs iterator/IteratorAggregator.h iterator/IteratorComposer.cc iterator/IteratorComposer.h - log.cc - log.h param/Map.cc param/Map.h projection/LatLonToXYZ.cc @@ -34,8 +32,6 @@ list(APPEND eckit_geo_srcs scanner/Regular.h scanner/Unstructured.cc scanner/Unstructured.h - test.cc - test.h types.cc types.h types/MatrixXYZ.h @@ -44,7 +40,6 @@ list(APPEND eckit_geo_srcs types/PointXYZ.h util.cc util.h - util/Mutex.h util/arange.cc util/gaussian_latitudes.cc util/linspace.cc diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index e851fbb57..f78f43b60 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -16,13 +16,12 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/log.h" -#include "eckit/geo/util/Mutex.h" - +#include "eckit/log/Log.h" +#include "eckit/thread/AutoLock.h" +#include "eckit/thread/Mutex.h" namespace eckit::geo { - #if 0 - mercator: double DiInMetres @@ -217,34 +216,31 @@ Projection centre (grib2/tables/30/3.5.table) 2 1 Projection is bipolar and symmetric #endif - -static util::once_flag __once; -static util::recursive_mutex* __mutex = nullptr; +static pthread_once_t __once = PTHREAD_ONCE_INIT; +static Mutex* __mutex = nullptr; static std::map* __factories = nullptr; - static void __init() { - __mutex = new util::recursive_mutex(); + __mutex = new Mutex; __factories = new std::map(); } - -Projection* ProjectionFactory::build(const ProjectionFactory::key_type& key, const Parametrisation& param) { - util::call_once(__once, __init); - util::lock_guard lock(*__mutex); +Projection* ProjectionFactory::build(const ProjectionFactory::key_type& key, + const Parametrisation& param) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); if (auto f = __factories->find(key); f != __factories->end()) { return f->second->make(param); } - list(error << "ProjectionFactory: unknown '" << key << "', choices are: "); + list(Log::error() << "ProjectionFactory: unknown '" << key << "', choices are: "); throw BadValue("ProjectionFactory: unknown '" + key + "'"); } - std::ostream& ProjectionFactory::list(std::ostream& out) { - util::call_once(__once, __init); - util::lock_guard lock(*__mutex); + pthread_once(&__once, __init); + AutoLock lock(*__mutex); const char* sep = "'"; for (const auto& j : *__factories) { @@ -255,11 +251,10 @@ std::ostream& ProjectionFactory::list(std::ostream& out) { return out; } - ProjectionFactory::ProjectionFactory(const ProjectionFactory::key_type& key) : key_(key) { - util::call_once(__once, __init); - util::lock_guard lock(*__mutex); + pthread_once(&__once, __init); + AutoLock lock(*__mutex); if (auto f = __factories->find(key); f != __factories->end()) { throw BadValue("ProjectionFactory: duplicate '" + key + "'"); @@ -270,12 +265,11 @@ ProjectionFactory::ProjectionFactory(const ProjectionFactory::key_type& key) : ProjectionFactory::~ProjectionFactory() { - util::lock_guard lock(*__mutex); + AutoLock lock(*__mutex); if (__factories != nullptr) { __factories->erase(key_); } } - } // namespace eckit::geo diff --git a/src/eckit/geo/grit.h.in b/src/eckit/geo/grit.h.in deleted file mode 100644 index 31da02161..000000000 --- a/src/eckit/geo/grit.h.in +++ /dev/null @@ -1,4 +0,0 @@ - -#define grit_VERSION_MAJOR @grit_VERSION_MAJOR@ -#define grit_VERSION_MINOR @grit_VERSION_MINOR@ -#define grit_VERSION_PATCH @grit_VERSION_PATCH@ diff --git a/src/eckit/geo/log.cc b/src/eckit/geo/log.cc deleted file mode 100644 index 86454d535..000000000 --- a/src/eckit/geo/log.cc +++ /dev/null @@ -1,27 +0,0 @@ -/* - * (C) Copyright 1996- 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 - -#include "eckit/geo/log.h" - - -namespace eckit::geo { - - -std::ostream& error = std::cerr; -std::ostream& warn = std::cout; -std::ostream& info = std::clog; -std::ostream& log = std::clog; - - -} // namespace eckit::geo diff --git a/src/eckit/geo/log.h b/src/eckit/geo/log.h deleted file mode 100644 index 4b3138877..000000000 --- a/src/eckit/geo/log.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include - - -namespace eckit::geo { - - -extern std::ostream& error; -extern std::ostream& warn; -extern std::ostream& info; -extern std::ostream& log; - - -} // namespace eckit::geo diff --git a/src/eckit/geo/test.cc b/src/eckit/geo/test.cc deleted file mode 100644 index 94c2ff523..000000000 --- a/src/eckit/geo/test.cc +++ /dev/null @@ -1,32 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/test.h" - -#include "eckit/exception/Exceptions.h" - -bool operator==(const eckit::geo::Point& p, const eckit::geo::Point& q) { - ASSERT(p.index() == q.index()); - - constexpr double eps = 1e-6; - - return std::holds_alternative(p) - ? std::get(p) - .is_approximately_equal(std::get(q), eps) - : std::holds_alternative(p) - ? std::get(p) - .is_approximately_equal(std::get(q), eps) - : std::holds_alternative(p) - ? std::get(p) - .is_approximately_equal(std::get(q), eps) - : NOTIMP; -} diff --git a/src/eckit/geo/test.h b/src/eckit/geo/test.h deleted file mode 100644 index 38fd29eb4..000000000 --- a/src/eckit/geo/test.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/types.h" - -bool operator==(const eckit::geo::Point&, const eckit::geo::Point&); diff --git a/src/eckit/geo/types.cc b/src/eckit/geo/types.cc index ff0095e89..8eb58eb5d 100644 --- a/src/eckit/geo/types.cc +++ b/src/eckit/geo/types.cc @@ -23,3 +23,20 @@ std::ostream& operator<<(std::ostream& out, const eckit::geo::Point& p) { ? out << std::get(p) : NOTIMP; } + +bool operator==(const eckit::geo::Point& p, const eckit::geo::Point& q) { + ASSERT(p.index() == q.index()); + + constexpr double eps = 1e-6; + + return std::holds_alternative(p) + ? std::get(p) + .is_approximately_equal(std::get(q), eps) + : std::holds_alternative(p) + ? std::get(p) + .is_approximately_equal(std::get(q), eps) + : std::holds_alternative(p) + ? std::get(p) + .is_approximately_equal(std::get(q), eps) + : NOTIMP; +} diff --git a/src/eckit/geo/types.h b/src/eckit/geo/types.h index f9a197610..bd00047c9 100644 --- a/src/eckit/geo/types.h +++ b/src/eckit/geo/types.h @@ -36,3 +36,5 @@ using pl_type = std::vector; } // namespace eckit::geo std::ostream& operator<<(std::ostream&, const eckit::geo::Point&); + +bool operator==(const eckit::geo::Point&, const eckit::geo::Point&); diff --git a/src/eckit/geo/util/Mutex.h b/src/eckit/geo/util/Mutex.h deleted file mode 100644 index 447d12e73..000000000 --- a/src/eckit/geo/util/Mutex.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/thread/AutoLock.h" -#include "eckit/thread/Mutex.h" - - -namespace eckit::geo::util { - -using recursive_mutex = eckit::Mutex; - -template -using lock_guard = typename eckit::AutoLock; - -struct once_flag { - pthread_once_t once_ = PTHREAD_ONCE_INIT; -}; - -template -inline void call_once(once_flag& flag, Callable&& fun) { - pthread_once(&(flag.once_), fun); -} - -} // namespace eckit::geo::util From 846a768ab513e420e82ff25afdfb4db520cb60f7 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 May 2023 17:17:54 +0100 Subject: [PATCH 191/737] eckit/geo PROJ support --- CMakeLists.txt | 7 ++++ src/eckit/geo/CMakeLists.txt | 13 +++++- src/eckit/geo/Iterator.cc | 41 ------------------- src/eckit/geo/grit-search.cc | 21 ---------- .../grit-grib.cc => tests/geo/test_grib.cc | 0 5 files changed, 19 insertions(+), 63 deletions(-) delete mode 100644 src/eckit/geo/Iterator.cc delete mode 100644 src/eckit/geo/grit-search.cc rename src/eckit/geo/grit-grib.cc => tests/geo/test_grib.cc (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 08e5cc5dc..a1487e8ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -236,6 +236,13 @@ ecbuild_add_option( FEATURE AIO CONDITION ${AIO_FOUND} DESCRIPTION "support for asynchronous IO") +### PROJ support + +find_package( PROJ 9.2 ) +ecbuild_add_option( FEATURE PROJ + DEFAULT OFF + DESCRIPTION "support PROJ-based projections") + ### c math library, needed when including "math.h" find_package( CMath ) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index af4b94f48..1d170c07e 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -6,6 +6,7 @@ list(APPEND eckit_geo_srcs Projection.h Scanner.cc Scanner.h + Search.h geometry/BoundingBox.cc geometry/BoundingBox.h geometry/GreatCircle.cc @@ -49,12 +50,22 @@ list(APPEND eckit_geo_srcs util/regular_pl.cc ) +set(eckit_geo_include_dirs ) +set(eckit_geo_libs eckit) + +if(HAVE_PROJ) + list(APPEND eckit_geo_srcs projection/PROJ.cc projection/PROJ.h) + list(APPEND eckit_geo_libs PROJ::proj) + list(APPEND eckit_geo_include_dirs ${PROJ_INCLUDE_DIRS}) +endif() + ecbuild_add_library( TARGET eckit_geo TYPE SHARED INSTALL_HEADERS ALL HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geo SOURCES ${eckit_geo_srcs} - PUBLIC_LIBS eckit + PUBLIC_LIBS ${eckit_geo_libs} + PUBLIC_INCLUDES ${eckit_geo_include_dirs} ) diff --git a/src/eckit/geo/Iterator.cc b/src/eckit/geo/Iterator.cc deleted file mode 100644 index f4a025e94..000000000 --- a/src/eckit/geo/Iterator.cc +++ /dev/null @@ -1,41 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/Iterator.h" - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/Projection.h" -#include "eckit/geo/Scanner.h" - - -namespace eckit::geo { - - -Iterator::Iterator(Scanner* scanner, Projection* projection) : - scanner_(scanner), projection_(projection) { - ASSERT(scanner_); - ASSERT(projection_); -} - - -bool Iterator::operator++() { - return ++(*scanner_); -} - - -size_t Iterator::size() const { - ASSERT(scanner_); - return scanner_->size(); -} - - -} // namespace eckit::geo diff --git a/src/eckit/geo/grit-search.cc b/src/eckit/geo/grit-search.cc deleted file mode 100644 index 1afc33bb1..000000000 --- a/src/eckit/geo/grit-search.cc +++ /dev/null @@ -1,21 +0,0 @@ -/* - * (C) Copyright 1996- 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 -#include - -#include "eckit/geo/Search.h" - - -int main(int argc, const char* argv[]) { - return 0; -} diff --git a/src/eckit/geo/grit-grib.cc b/tests/geo/test_grib.cc similarity index 100% rename from src/eckit/geo/grit-grib.cc rename to tests/geo/test_grib.cc From d204b1b63604e5130483aba331fc2faf0dcbe770 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 May 2023 22:24:59 +0100 Subject: [PATCH 192/737] eckit::maths::Matrix3 --- src/eckit/maths/CMakeLists.txt | 3 +- .../types/MatrixXYZ.h => maths/Matrix3.h} | 35 +++++++++---------- 2 files changed, 18 insertions(+), 20 deletions(-) rename src/eckit/{geo/types/MatrixXYZ.h => maths/Matrix3.h} (77%) diff --git a/src/eckit/maths/CMakeLists.txt b/src/eckit/maths/CMakeLists.txt index 9957b5af2..6c730016b 100644 --- a/src/eckit/maths/CMakeLists.txt +++ b/src/eckit/maths/CMakeLists.txt @@ -1,8 +1,9 @@ list( APPEND eckit_maths_lib_srcs Eigen.h -Lapack.h Lapack.cc +Lapack.h Matrix.h +Matrix3.h MatrixEigen.h MatrixLapack.h ) diff --git a/src/eckit/geo/types/MatrixXYZ.h b/src/eckit/maths/Matrix3.h similarity index 77% rename from src/eckit/geo/types/MatrixXYZ.h rename to src/eckit/maths/Matrix3.h index 7f8ed6bc6..379da26ff 100644 --- a/src/eckit/geo/types/MatrixXYZ.h +++ b/src/eckit/maths/Matrix3.h @@ -16,14 +16,12 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/types/PointXYZ.h" - - -namespace eckit::geo::types { +#include "eckit/geometry/Point3.h" +namespace eckit::maths { template -class MatrixXYZ final : protected std::array { +class Matrix3 final : protected std::array { private: // -- Types @@ -38,37 +36,37 @@ class MatrixXYZ final : protected std::array { // -- Constructors - MatrixXYZ(T xx, T xy, T xz, T yx, T yy, T yz, T zx, T zy, T zz) : + Matrix3(T xx, T xy, T xz, T yx, T yy, T yz, T zx, T zy, T zz) : P{xx, xy, xz, yx, yy, yz, zx, zy, zz} {} - MatrixXYZ(const MatrixXYZ& other) : + Matrix3(const Matrix3& other) : P(other) {} - MatrixXYZ(MatrixXYZ&& other) : + Matrix3(Matrix3&& other) : P(other) {} // -- Destructor - ~MatrixXYZ() = default; + ~Matrix3() = default; // -- Convertors // None // -- Operators - MatrixXYZ& operator=(const MatrixXYZ& other) { + Matrix3& operator=(const Matrix3& other) { P::operator=(other); return *this; } - MatrixXYZ& operator=(MatrixXYZ&& other) { + Matrix3& operator=(Matrix3&& other) { P::operator=(other); return *this; } - PointXYZ operator*(const PointXYZ& p) const { + geometry::Point3 operator*(const geometry::Point3& p) const { return {XX * p.X + XY * p.Y + XZ * p.Z, YX * p.X + YY * p.Y + YZ * p.Z, ZX * p.X + ZY * p.Y + ZZ * p.Z}; } - MatrixXYZ operator*(const MatrixXYZ& M) const { + Matrix3 operator*(const Matrix3& M) const { return { XX * M.XX + XY * M.YX + XZ * M.ZX, XX * M.XY + XY * M.YY + XZ * M.ZY, XX * M.XZ + XY * M.YZ + XZ * M.ZZ, YX * M.XX + YY * M.YX + YZ * M.ZX, YX * M.XY + YY * M.YY + YZ * M.ZY, YX * M.XZ + YY * M.YZ + YZ * M.ZZ, @@ -89,11 +87,11 @@ class MatrixXYZ final : protected std::array { // -- Methods - static MatrixXYZ identity() { return {1, 0, 0, 0, 1, 0, 0, 0, 1}; } + static Matrix3 identity() { return {1, 0, 0, 0, 1, 0, 0, 0, 1}; } - MatrixXYZ inverse() const { + Matrix3 inverse() const { auto det = XX * (YY * ZZ - YZ * ZY) - XY * (YX * ZZ - YZ * ZX) + XZ * (YX * ZY - YY * ZX); - ASSERT_MSG(det != 0, "MatrixXYZ: singular matrix"); + ASSERT_MSG(det != 0, "Matrix3: singular matrix"); return {(YY * ZZ - YZ * ZY) / det, (XZ * ZY - XY * ZZ) / det, (XY * YZ - XZ * YY) / det, (YZ * ZX - YX * ZZ) / det, (XX * ZZ - XZ * ZX) / det, (XZ * YX - XX * YZ) / det, @@ -111,11 +109,10 @@ class MatrixXYZ final : protected std::array { // -- Friends - friend std::ostream& operator<<(std::ostream& out, const MatrixXYZ& m) { + friend std::ostream& operator<<(std::ostream& out, const Matrix3& m) { return out << "{{" << m.XX << ", " << m.XY << ", " << m.XZ << "}, {" << m.YX << ", " << m.YY << ", " << m.YZ << "}, {" << m.ZX << ", " << m.ZY << ", " << m.ZZ << "}}"; } }; - -} // namespace eckit::geo::types +} // namespace eckit::maths From 5ee1eed0fb700f1b83a9cc65c990e167c9fb86fb Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 May 2023 22:27:36 +0100 Subject: [PATCH 193/737] eckit::geometry::PointLonLat --- src/eckit/geometry/CMakeLists.txt | 2 + .../UnitSphere.h => geometry/PointLonLat.cc} | 24 ++++-------- .../PointLatLon.h => geometry/PointLonLat.h} | 38 +++++++++---------- 3 files changed, 29 insertions(+), 35 deletions(-) rename src/eckit/{geo/geometry/UnitSphere.h => geometry/PointLonLat.cc} (54%) rename src/eckit/{geo/types/PointLatLon.h => geometry/PointLonLat.h} (68%) diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index e428e387e..a12491420 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -9,6 +9,8 @@ Point2.cc Point2.h Point3.cc Point3.h +PointLonLat.cc +PointLonLat.h Sphere.cc Sphere.h SphereT.h diff --git a/src/eckit/geo/geometry/UnitSphere.h b/src/eckit/geometry/PointLonLat.cc similarity index 54% rename from src/eckit/geo/geometry/UnitSphere.h rename to src/eckit/geometry/PointLonLat.cc index fcb94c494..5111cf515 100644 --- a/src/eckit/geo/geometry/UnitSphere.h +++ b/src/eckit/geometry/PointLonLat.cc @@ -9,23 +9,15 @@ * does it submit to any jurisdiction. */ +#include "eckit/geometry/PointLonLat.h" -#pragma once +#include "eckit/geometry/UnitSphere.h" +#include "eckit/types/FloatCompare.h" -#include "eckit/geo/geometry/SphereT.h" +namespace eckit::geometry { +bool points_equal(const PointLonLat& a, const PointLonLat& b) { + return eckit::types::is_approximately_equal(UnitSphere::centralAngle(a, b), 0.0); +} -namespace eckit::geo::geometry { - - -/// Definition of a unit datum -struct DatumUnit { - static constexpr double radius() { return 1.; } -}; - - -/// Definition of a unit sphere -using UnitSphere = SphereT; - - -} // namespace eckit::geo::geometry +} // namespace eckit::geometry diff --git a/src/eckit/geo/types/PointLatLon.h b/src/eckit/geometry/PointLonLat.h similarity index 68% rename from src/eckit/geo/types/PointLatLon.h rename to src/eckit/geometry/PointLonLat.h index 2a6940dc9..14ce33826 100644 --- a/src/eckit/geo/types/PointLatLon.h +++ b/src/eckit/geometry/PointLonLat.h @@ -19,19 +19,18 @@ #include "eckit/exception/Exceptions.h" -namespace eckit::geo::types { +namespace eckit::geometry { -template -class PointLatLon final : protected std::array { +class PointLonLat final : protected std::array { private: // -- Types - using P = std::array; + using P = std::array; // -- Class methods - static T normal(double a, double minimum) { + static double normal(double a, double minimum) { while (a < minimum) { a += 360.; } @@ -52,45 +51,45 @@ class PointLatLon final : protected std::array { // -- Constructors - PointLatLon(T lat, T lon) : - P{lat, lon} { ASSERT_MSG(-90. <= lat && lat <= 90., "PointLatLon: invalid latitude"); } - PointLatLon(const PointLatLon& other) : + PointLonLat(double lat, double lon) : + P{lat, lon} { ASSERT_MSG(-90. <= lat && lat <= 90., "PointLonLat: invalid latitude"); } + PointLonLat(const PointLonLat& other) : P(other) {} - PointLatLon(PointLatLon&& other) : + PointLonLat(PointLonLat&& other) : P(other) {} // -- Destructor - ~PointLatLon() = default; + ~PointLonLat() = default; // -- Convertors // None // -- Operators - PointLatLon& operator=(const PointLatLon& other) { + PointLonLat& operator=(const PointLonLat& other) { P::operator=(other); return *this; } - PointLatLon& operator=(PointLatLon&& other) { + PointLonLat& operator=(PointLonLat&& other) { P::operator=(other); return *this; } - bool is_approximately_equal(const PointLatLon& other, T eps) const { + bool is_approximately_equal(const PointLonLat& other, double eps) const { const auto dlon = normal(other.lon, lon) - lon; return std::abs(lat - other.lat) < eps && (std::abs(lat - 90.) < eps || std::abs(lat + 90.) < eps || dlon < eps || dlon - 360. < eps); }; // -- Members - T& lat = P::operator[](0); - T& lon = P::operator[](1); + double& lat = P::operator[](0); + double& lon = P::operator[](1); // -- Methods - static PointLatLon make(T lat, T lon, T lon_minimum = 0) { + static PointLonLat make(double lat, double lon, double lon_minimum = 0) { lat = normal(lat, -90.); if (lat > 90.) { @@ -101,7 +100,7 @@ class PointLatLon final : protected std::array { return {lat, lat == -90. || lat == 90. ? 0. : normal(lon, lon_minimum)}; } - PointLatLon antipode() const { return make(lat + 180., lon); } + PointLonLat antipode() const { return make(lat + 180., lon); } // -- Overridden methods // None @@ -114,10 +113,11 @@ class PointLatLon final : protected std::array { // -- Friends - friend std::ostream& operator<<(std::ostream& out, const PointLatLon& p) { + friend std::ostream& operator<<(std::ostream& out, const PointLonLat& p) { return out << '{' << p.lat << ", " << p.lon << '}'; } }; +bool points_equal(const PointLonLat&, const PointLonLat&); -} // namespace eckit::geo::types +} // namespace eckit::geometry From 257797f2064ba5a72b0e8330c961286696b1ff21 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 May 2023 22:27:57 +0100 Subject: [PATCH 194/737] eckit::geometry::Point2, Point3 --- src/eckit/geo/CMakeLists.txt | 6 +- src/eckit/geo/types.cc | 29 ++++----- src/eckit/geo/types.h | 15 +++-- src/eckit/geo/types/PointXY.h | 105 -------------------------------- src/eckit/geo/types/PointXYZ.h | 108 --------------------------------- src/eckit/geometry/KPoint.h | 7 +-- src/eckit/geometry/Point2.cc | 15 +++-- src/eckit/geometry/Point2.h | 51 ++++++++++++---- src/eckit/geometry/Point3.cc | 10 +++ src/eckit/geometry/Point3.h | 52 ++++++++++++---- 10 files changed, 124 insertions(+), 274 deletions(-) delete mode 100644 src/eckit/geo/types/PointXY.h delete mode 100644 src/eckit/geo/types/PointXYZ.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 1d170c07e..fed87f3e0 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -35,10 +35,6 @@ list(APPEND eckit_geo_srcs scanner/Unstructured.h types.cc types.h - types/MatrixXYZ.h - types/PointLatLon.h - types/PointXY.h - types/PointXYZ.h util.cc util.h util/arange.cc @@ -51,7 +47,7 @@ list(APPEND eckit_geo_srcs ) set(eckit_geo_include_dirs ) -set(eckit_geo_libs eckit) +set(eckit_geo_libs eckit_geometry eckit_maths) if(HAVE_PROJ) list(APPEND eckit_geo_srcs projection/PROJ.cc projection/PROJ.h) diff --git a/src/eckit/geo/types.cc b/src/eckit/geo/types.cc index 8eb58eb5d..1443853e4 100644 --- a/src/eckit/geo/types.cc +++ b/src/eckit/geo/types.cc @@ -9,18 +9,17 @@ * does it submit to any jurisdiction. */ - #include "eckit/geo/types.h" #include "eckit/exception/Exceptions.h" std::ostream& operator<<(std::ostream& out, const eckit::geo::Point& p) { - return std::holds_alternative(p) - ? out << std::get(p) - : std::holds_alternative(p) - ? out << std::get(p) - : std::holds_alternative(p) - ? out << std::get(p) + return std::holds_alternative(p) + ? out << std::get(p) + : std::holds_alternative(p) + ? out << std::get(p) + : std::holds_alternative(p) + ? out << std::get(p) : NOTIMP; } @@ -29,14 +28,12 @@ bool operator==(const eckit::geo::Point& p, const eckit::geo::Point& q) { constexpr double eps = 1e-6; - return std::holds_alternative(p) - ? std::get(p) - .is_approximately_equal(std::get(q), eps) - : std::holds_alternative(p) - ? std::get(p) - .is_approximately_equal(std::get(q), eps) - : std::holds_alternative(p) - ? std::get(p) - .is_approximately_equal(std::get(q), eps) + return std::holds_alternative(p) + ? points_equal(std::get(p), + std::get(q)) + : std::holds_alternative(p) + ? points_equal(std::get(p), std::get(q)) + : std::holds_alternative(p) + ? points_equal(std::get(p), std::get(q)) : NOTIMP; } diff --git a/src/eckit/geo/types.h b/src/eckit/geo/types.h index bd00047c9..9010164d7 100644 --- a/src/eckit/geo/types.h +++ b/src/eckit/geo/types.h @@ -16,18 +16,17 @@ #include #include -#include "eckit/geo/types/PointLatLon.h" -#include "eckit/geo/types/PointXY.h" -#include "eckit/geo/types/PointXYZ.h" +#include "eckit/geometry/Point2.h" +#include "eckit/geometry/Point3.h" +#include "eckit/geometry/PointLonLat.h" namespace eckit::geo { - -using PointLatLon = types::PointLatLon; -using PointXY = types::PointXY; -using PointXYZ = types::PointXYZ; -using Point = std::variant; +using PointLonLat = eckit::geometry::PointLonLat; +using Point2 = eckit::geometry::Point2; +using Point3 = eckit::geometry::Point3; +using Point = std::variant; using pl_type = std::vector; diff --git a/src/eckit/geo/types/PointXY.h b/src/eckit/geo/types/PointXY.h deleted file mode 100644 index 0e6b6dda0..000000000 --- a/src/eckit/geo/types/PointXY.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include - - -namespace eckit::geo::types { - - -template -class PointXY final : protected std::array { -private: - // -- Types - - using P = std::array; - -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - PointXY() : - P{0, 0} {} - PointXY(T x, T y) : - P{x, y} {} - PointXY(const PointXY& other) : - P(other) {} - PointXY(PointXY&& other) : - P(other) {} - - // -- Destructor - - ~PointXY() = default; - - // -- Convertors - // None - - // -- Operators - - PointXY& operator=(const PointXY& other) { - P::operator=(other); - return *this; - } - - PointXY& operator=(PointXY&& other) { - P::operator=(other); - return *this; - } - - bool is_approximately_equal(const PointXY& other, T eps) const { - return std::abs(X - other.X) < eps && std::abs(Y - other.Y) < eps; - }; - - // -- Members - - T& X = P::operator[](0); - T& Y = P::operator[](1); - - static constexpr size_t DIMS = 2; - - // -- Methods - - T x(size_t dim) const { return P::at(dim); } - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - - static T distance(const PointXY& a, const PointXY& b, size_t dim) { return std::abs(a.x(dim) - b.x(dim)); } - - static T distance(const PointXY& a, const PointXY& b) { return std::sqrt(distance2(a, b)); } - - static T distance2(const PointXY& a, const PointXY& b) { - return (a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y); - } - - // -- Friends - - friend std::ostream& operator<<(std::ostream& out, const PointXY& p) { - return out << '{' << p.X << ", " << p.Y << '}'; - } -}; - - -} // namespace eckit::geo::types diff --git a/src/eckit/geo/types/PointXYZ.h b/src/eckit/geo/types/PointXYZ.h deleted file mode 100644 index 0e90db0e4..000000000 --- a/src/eckit/geo/types/PointXYZ.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include -#include -#include - - -namespace eckit::geo::types { - - -template -class PointXYZ final : protected std::array { -private: - // -- Types - - using P = std::array; - -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - PointXYZ() : - P{0, 0, 0} {} - PointXYZ(T x, T y, T z) : - P{x, y, z} {} - PointXYZ(const PointXYZ& other) : - P(other) {} - PointXYZ(PointXYZ&& other) : - P(other) {} - - // -- Destructor - - ~PointXYZ() = default; - - // -- Convertors - // None - - // -- Operators - - PointXYZ& operator=(const PointXYZ& other) { - P::operator=(other); - return *this; - } - - PointXYZ& operator=(PointXYZ&& other) { - P::operator=(other); - return *this; - } - - bool is_approximately_equal(const PointXYZ& other, T eps) const { - return std::abs(X - other.X) < eps && std::abs(Y - other.Y) < eps && std::abs(Z - other.Z) < eps; - }; - - // -- Members - - T& X = P::operator[](0); - T& Y = P::operator[](1); - T& Z = P::operator[](2); - - static constexpr size_t DIMS = 3; - - // -- Methods - - T x(size_t dim) const { return P::at(dim); } - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - - static T distance(const PointXYZ& a, const PointXYZ& b, size_t dim) { return std::abs(a.x(dim) - b.x(dim)); } - - static T distance(const PointXYZ& a, const PointXYZ& b) { return std::sqrt(distance2(a, b)); } - - static T distance2(const PointXYZ& a, const PointXYZ& b) { - return (a.X - b.X) * (a.X - b.X) + (a.Y - b.Y) * (a.Y - b.Y) + (a.Z - b.Z) * (a.Z - b.Z); - } - - // -- Friends - - friend std::ostream& operator<<(std::ostream& out, const PointXYZ& p) { - return out << '{' << p.X << ", " << p.Y << ", " << p.Z << '}'; - } -}; - - -} // namespace eckit::geo::types diff --git a/src/eckit/geometry/KPoint.h b/src/eckit/geometry/KPoint.h index 2d4aa9214..c3f381253 100644 --- a/src/eckit/geometry/KPoint.h +++ b/src/eckit/geometry/KPoint.h @@ -8,8 +8,7 @@ * does it submit to any jurisdiction. */ -#ifndef KPoint_H -#define KPoint_H +#pragma once #include #include @@ -48,7 +47,7 @@ class KPoint { double x(size_t axis) const { return x_[axis]; } - KPoint() {} + KPoint() = default; KPoint(const double* x) { std::copy(x, x + dimensions(), x_); } @@ -281,5 +280,3 @@ const size_t KPoint::DIMS; //------------------------------------------------------------------------------------------------------ } // namespace eckit::geometry - -#endif diff --git a/src/eckit/geometry/Point2.cc b/src/eckit/geometry/Point2.cc index 219ce99cc..92edebc5e 100644 --- a/src/eckit/geometry/Point2.cc +++ b/src/eckit/geometry/Point2.cc @@ -1,3 +1,13 @@ +/* + * (C) Copyright 1996- 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 #include "eckit/geometry/Point2.h" @@ -15,10 +25,7 @@ bool points_equal(const Point2& a, const Point2& b) { } Point2::operator Value() const { - std::vector pts; - pts.push_back(x_[XX]); - pts.push_back(x_[YY]); - return Value::makeList(pts); + return Value::makeList(std::vector{x_[XX], x_[YY]}); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geometry/Point2.h b/src/eckit/geometry/Point2.h index e094a0abb..0c9952542 100644 --- a/src/eckit/geometry/Point2.h +++ b/src/eckit/geometry/Point2.h @@ -1,5 +1,14 @@ -#ifndef eckit_geometry_Point2_h -#define eckit_geometry_Point2_h +/* + * (C) Copyright 1996- 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. + */ + +#pragma once #include @@ -18,30 +27,50 @@ namespace eckit::geometry { //------------------------------------------------------------------------------------------------------ class Point2 : public eckit::geometry::KPoint<2> { - typedef KPoint<2> BasePoint; + using BasePoint = KPoint<2>; public: - Point2() : - BasePoint() {} + Point2() = default; Point2(const BasePoint& p) : BasePoint(p) {} - Point2(const double* p) : + explicit Point2(const double* p) : BasePoint(p) {} - Point2(double x, double y) : - BasePoint() { + Point2(double x, double y) { x_[XX] = x; x_[YY] = y; } - double x() const { return x_[0]; } + Point2(const Point2& other) : + Point2(other.X, other.Y) {} - double y() const { return x_[1]; } + Point2(Point2&& other) : + Point2(other.X, other.Y) {} + + double x() const { return x_[XX]; } + + double y() const { return x_[YY]; } + + double& X = x_[XX]; + + double& Y = x_[YY]; double x(size_t axis) const { return eckit::geometry::KPoint<2>::x(axis); } + Point2& operator=(const Point2& other) { + x_[0] = other[0]; + x_[1] = other[1]; + return *this; + } + + Point2& operator=(Point2&& other) { + x_[0] = other[0]; + x_[1] = other[1]; + return *this; + } + double operator[](const size_t& i) const { assert(i < 2); return x_[i]; @@ -68,5 +97,3 @@ bool points_equal(const Point2&, const Point2&); //------------------------------------------------------------------------------------------------------ } // namespace eckit::geometry - -#endif diff --git a/src/eckit/geometry/Point3.cc b/src/eckit/geometry/Point3.cc index d9739198e..811bf1cd6 100644 --- a/src/eckit/geometry/Point3.cc +++ b/src/eckit/geometry/Point3.cc @@ -1,3 +1,13 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/Point3.h" #include "eckit/types/FloatCompare.h" diff --git a/src/eckit/geometry/Point3.h b/src/eckit/geometry/Point3.h index 30fa6d280..aefbe9c9d 100644 --- a/src/eckit/geometry/Point3.h +++ b/src/eckit/geometry/Point3.h @@ -1,5 +1,14 @@ -#ifndef eckit_geometry_Point3_h -#define eckit_geometry_Point3_h +/* + * (C) Copyright 1996- 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. + */ + +#pragma once #include "eckit/geometry/KPoint.h" @@ -10,26 +19,49 @@ namespace eckit::geometry { //------------------------------------------------------------------------------------------------------ class Point3 : public eckit::geometry::KPoint<3> { - - typedef KPoint<3> BasePoint; + using BasePoint = KPoint<3>; public: - Point3() : - BasePoint() {} + Point3() = default; Point3(const BasePoint& p) : BasePoint(p) {} - Point3(const double* p) : + explicit Point3(const double* p) : BasePoint(p) {} - Point3(double x, double y, double z) : - BasePoint() { + Point3(double x, double y, double z) { x_[XX] = x; x_[YY] = y; x_[ZZ] = z; } + Point3(const Point3& other) : + Point3(other.X, other.Y, other.Z) {} + + Point3(Point3&& other) : + Point3(other.X, other.Y, other.Z) {} + + double& X = x_[XX]; + + double& Y = x_[YY]; + + double& Z = x_[ZZ]; + + Point3& operator=(const Point3& other) { + x_[0] = other[0]; + x_[1] = other[1]; + x_[2] = other[2]; + return *this; + } + + Point3& operator=(Point3&& other) { + x_[0] = other[0]; + x_[1] = other[1]; + x_[2] = other[2]; + return *this; + } + double operator[](const size_t& i) const { assert(i < 3); return x_[i]; @@ -59,5 +91,3 @@ bool points_equal(const Point3&, const Point3&); //------------------------------------------------------------------------------------------------------ } // namespace eckit::geometry - -#endif From eeb9522e8b3e2799c2284b80cfcc07931e9367b4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 May 2023 22:31:25 +0100 Subject: [PATCH 195/737] eckit::geo --- src/eckit/geo/{geometry => }/BoundingBox.cc | 14 +- src/eckit/geo/{geometry => }/BoundingBox.h | 7 +- src/eckit/geo/CMakeLists.txt | 15 +-- src/eckit/geo/geometry/GreatCircle.cc | 107 --------------- src/eckit/geo/geometry/GreatCircle.h | 45 ------- src/eckit/geo/geometry/Sphere.cc | 124 ------------------ src/eckit/geo/geometry/Sphere.h | 45 ------- src/eckit/geo/geometry/Spheroid.cc | 88 ------------- src/eckit/geo/geometry/Spheroid.h | 45 ------- src/eckit/geo/projection/LatLonToXYZ.cc | 66 ---------- src/eckit/geo/projection/LonLatToXYZ.cc | 69 ++++++++++ .../{LatLonToXYZ.h => LonLatToXYZ.h} | 20 +-- 12 files changed, 90 insertions(+), 555 deletions(-) rename src/eckit/geo/{geometry => }/BoundingBox.cc (95%) rename src/eckit/geo/{geometry => }/BoundingBox.h (96%) delete mode 100644 src/eckit/geo/geometry/GreatCircle.cc delete mode 100644 src/eckit/geo/geometry/GreatCircle.h delete mode 100644 src/eckit/geo/geometry/Sphere.cc delete mode 100644 src/eckit/geo/geometry/Sphere.h delete mode 100644 src/eckit/geo/geometry/Spheroid.cc delete mode 100644 src/eckit/geo/geometry/Spheroid.h delete mode 100644 src/eckit/geo/projection/LatLonToXYZ.cc create mode 100644 src/eckit/geo/projection/LonLatToXYZ.cc rename src/eckit/geo/projection/{LatLonToXYZ.h => LonLatToXYZ.h} (77%) diff --git a/src/eckit/geo/geometry/BoundingBox.cc b/src/eckit/geo/BoundingBox.cc similarity index 95% rename from src/eckit/geo/geometry/BoundingBox.cc rename to src/eckit/geo/BoundingBox.cc index bbd5af9f0..fe8d7dfcd 100644 --- a/src/eckit/geo/geometry/BoundingBox.cc +++ b/src/eckit/geo/BoundingBox.cc @@ -9,18 +9,15 @@ * does it submit to any jurisdiction. */ - -#include "eckit/geo/geometry/BoundingBox.h" +#include "eckit/geo/BoundingBox.h" #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/geometry/Sphere.h" #include "eckit/geo/util.h" +#include "eckit/geometry/Sphere.h" - -namespace eckit::geo::geometry { - +namespace eckit::geo { BoundingBox::BoundingBox(double north, double west, double south, double east) : north_(north), west_(west), south_(south), east_(east) { @@ -127,8 +124,7 @@ double BoundingBox::area(double radius) const { double latf = 0.5 * (std::sin(util::degrees_to_radians * north_) - std::sin(util::degrees_to_radians * south_)); ASSERT(0. <= latf && latf <= 1.); - return Sphere::area(radius) * latf * lonf; + return geometry::Sphere::area(radius) * latf * lonf; } - -} // namespace eckit::geo::geometry +} // namespace eckit::geo diff --git a/src/eckit/geo/geometry/BoundingBox.h b/src/eckit/geo/BoundingBox.h similarity index 96% rename from src/eckit/geo/geometry/BoundingBox.h rename to src/eckit/geo/BoundingBox.h index 91254a2ec..0e2907f5d 100644 --- a/src/eckit/geo/geometry/BoundingBox.h +++ b/src/eckit/geo/BoundingBox.h @@ -12,9 +12,7 @@ #pragma once - -namespace eckit::geo::geometry { - +namespace eckit::geo { class BoundingBox { public: @@ -122,5 +120,4 @@ class BoundingBox { // None }; - -} // namespace eckit::geo::geometry +} // namespace eckit::geo diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index fed87f3e0..46b9d2bb5 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -1,4 +1,6 @@ list(APPEND eckit_geo_srcs + BoundingBox.cc + BoundingBox.h Iterator.h Parametrisation.cc Parametrisation.h @@ -7,22 +9,13 @@ list(APPEND eckit_geo_srcs Scanner.cc Scanner.h Search.h - geometry/BoundingBox.cc - geometry/BoundingBox.h - geometry/GreatCircle.cc - geometry/GreatCircle.h - geometry/Sphere.cc - geometry/Sphere.h - geometry/Spheroid.cc - geometry/Spheroid.h - geometry/UnitSphere.h iterator/IteratorAggregator.h iterator/IteratorComposer.cc iterator/IteratorComposer.h param/Map.cc param/Map.h - projection/LatLonToXYZ.cc - projection/LatLonToXYZ.h + projection/LonLatToXYZ.cc + projection/LonLatToXYZ.h projection/None.cc projection/None.h projection/Rotation.cc diff --git a/src/eckit/geo/geometry/GreatCircle.cc b/src/eckit/geo/geometry/GreatCircle.cc deleted file mode 100644 index 31cf15cf3..000000000 --- a/src/eckit/geo/geometry/GreatCircle.cc +++ /dev/null @@ -1,107 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/geometry/GreatCircle.h" - -#include -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/util.h" - - -namespace eckit::geo::geometry { - - -static bool pole(double lat) { - return util::is_approximately_equal(std::abs(lat), 90.); -} - - -GreatCircle::GreatCircle(const PointLatLon& A, const PointLatLon& B) : - A_(A), B_(B) { - const bool Apole = pole(A_.lat); - const bool Bpole = pole(B_.lat); - const double lon12_deg = util::normalise_longitude_to_minimum(A_.lon - B_.lon, -180.); - - const bool lon_same = Apole || Bpole || util::is_approximately_equal(lon12_deg, 0.); - const bool lon_opposite = Apole || Bpole || util::is_approximately_equal(std::abs(lon12_deg), 180.); - const bool lat_same = util::is_approximately_equal(A_.lat, B_.lat); - const bool lat_opposite = util::is_approximately_equal(A_.lat, -B_.lat); - - ASSERT_MSG(!(lat_same && lon_same) && !(lat_opposite && lon_opposite), - "Great circle cannot be defined by points collinear with the centre"); - - crossesPoles_ = lon_same || lon_opposite; -} - - -std::vector GreatCircle::latitude(double lon) const { - if (crossesPoles()) { - return {}; - } - - const double lat1 = util::degrees_to_radians * A_.lat; - const double lat2 = util::degrees_to_radians * B_.lat; - const double lambda1p = util::degrees_to_radians * (lon - A_.lon); - const double lambda2p = util::degrees_to_radians * (lon - B_.lon); - const double lambda = util::degrees_to_radians * util::normalise_longitude_to_minimum(B_.lon - A_.lon, -180.); - - double lat = std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); - return {util::radians_to_degrees * lat}; -} - - -std::vector GreatCircle::longitude(double lat) const { - if (crossesPoles()) { - const double lon = pole(A_.lat) ? B_.lon : A_.lon; - if (pole(lat)) { - return {lon}; - } - - return {lon, lon + 180.}; - } - - const double lon12 = util::degrees_to_radians * util::normalise_longitude_to_minimum(A_.lon - B_.lon, -180.); - const double lon1 = util::degrees_to_radians * A_.lon; - const double lat1 = util::degrees_to_radians * A_.lat; - const double lat2 = util::degrees_to_radians * B_.lat; - const double lat3 = util::degrees_to_radians * lat; - - const double X = std::sin(lat1) * std::cos(lat2) * std::sin(lon12); - const double Y = std::sin(lat1) * std::cos(lat2) * std::cos(lon12) - std::cos(lat1) * std::sin(lat2); - - if (util::is_approximately_equal(X, 0.) && util::is_approximately_equal(Y, 0.)) { - return {}; // parallel (that is, equator) - } - - const double lon0 = lon1 + std::atan2(Y, X); - const double C = std::cos(lat1) * std::cos(lat2) * std::tan(lat3) * std::sin(lon12) / std::sqrt(X * X + Y * Y); - - if (util::is_approximately_equal(C, -1.)) { - return {util::radians_to_degrees * (lon0 + M_PI)}; - } - - if (util::is_approximately_equal(C, 1.)) { - return {util::radians_to_degrees * lon0}; - } - - if (-1 < C && C < 1) { - const double dlon = std::acos(C); - return {util::radians_to_degrees * (lon0 - dlon + 2 * M_PI), util::radians_to_degrees * (lon0 + dlon)}; - } - - return {}; -} - - -} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/GreatCircle.h b/src/eckit/geo/geometry/GreatCircle.h deleted file mode 100644 index 1531651c5..000000000 --- a/src/eckit/geo/geometry/GreatCircle.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - - -#include - -#include "eckit/geo/types.h" - - -namespace eckit::geo::geometry { - - -class GreatCircle { -public: - /// Great circle given two points in geographic coordinates - GreatCircle(const PointLatLon&, const PointLatLon&); - - /// Great circle latitude given longitude, see http://www.edwilliams.org/avform.htm#Int - std::vector latitude(double lon) const; - - /// Great circle longitude given latitude, see http://www.edwilliams.org/avform.htm#Par - std::vector longitude(double lat) const; - - bool crossesPoles() const { return crossesPoles_; } - -private: - const PointLatLon A_; - const PointLatLon B_; - - bool crossesPoles_; -}; - - -} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/Sphere.cc b/src/eckit/geo/geometry/Sphere.cc deleted file mode 100644 index 9222d08d4..000000000 --- a/src/eckit/geo/geometry/Sphere.cc +++ /dev/null @@ -1,124 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/geometry/Sphere.h" - -#include -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/geometry/Spheroid.h" -#include "eckit/geo/util.h" - - -namespace eckit::geo::geometry { - - -inline double squared(double x) { - return x * x; -} - - -double Sphere::angle(const PointLatLon& A, const PointLatLon& B) { - /* - * Δσ = atan( ((cos(ϕ2) * sin(Δλ))^2 + (cos(ϕ1) * sin(ϕ2) - sin(ϕ1) * cos(ϕ2) * cos(Δλ))^2) / - * (sin(ϕ1) * sin(ϕ2) + cos(ϕ1) * cos(ϕ2) * cos(Δλ)) ) - * - * @article{doi:10.1179/sre.1975.23.176.88, - * author = {T. Vincenty}, - * title = {Direct and Inverse Solutions of Geodesics on the Ellipsoid With Application of Nested Equations}, - * journal = {Survey Review}, - * volume = {23}, - * number = {176}, - * pages = {88-93}, - * year = {1975}, - * doi = {10.1179/sre.1975.23.176.88} - * } - */ - - const double phi1 = util::degrees_to_radians * A.lat; - const double phi2 = util::degrees_to_radians * B.lat; - const double lambda = util::degrees_to_radians * (B.lon - A.lon); - - const double cos_phi1 = std::cos(phi1); - const double sin_phi1 = std::sin(phi1); - const double cos_phi2 = std::cos(phi2); - const double sin_phi2 = std::sin(phi2); - const double cos_lambda = std::cos(lambda); - const double sin_lambda = std::sin(lambda); - - const double sigma = atan2( - std::sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), - sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); - - if (util::is_approximately_equal(sigma, 0.)) { - return 0.; - } - - ASSERT(sigma > 0.); - return sigma; -} - - -double Sphere::angle(double radius, const PointXYZ& A, const PointXYZ& B) { - ASSERT(radius > 0.); - - // Δσ = 2 * asin( chord / 2 ) - - const double d2 = PointXYZ::distance2(A, B); - if (util::is_approximately_equal(d2, 0.)) { - return 0.; - } - - const double chord = std::sqrt(d2) / radius; - const double sigma = std::asin(chord * 0.5) * 2.; - - ASSERT(sigma > 0.); - return sigma; -} - - -double Sphere::distance(double radius, const PointLatLon& A, const PointLatLon& B) { - return radius * angle(A, B); -} - - -double Sphere::distance(double radius, const PointXYZ& A, const PointXYZ& B) { - return radius * angle(radius, A, B); -} - - -double Sphere::area(double radius) { - ASSERT(radius > 0.); - return 4. * M_PI * radius * radius; -} - - -PointXYZ Sphere::ll_to_xyz(double radius, const PointLatLon& P, double height) { - return Spheroid::ll_to_xyz(radius, radius, P, height); -} - - -PointLatLon Sphere::xyz_to_ll(double radius, const PointXYZ& A) { - ASSERT(radius > 0.); - - // numerical conditioning for both z (poles) and y - - const double x = A.X; - const double y = util::is_approximately_equal(A.Y, 0.) ? 0. : A.Y; - const double z = std::min(radius, std::max(-radius, A.Z)) / radius; - - return {util::radians_to_degrees * std::asin(z), util::radians_to_degrees * std::atan2(y, x)}; -} - - -} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/Sphere.h b/src/eckit/geo/geometry/Sphere.h deleted file mode 100644 index 9bab4476a..000000000 --- a/src/eckit/geo/geometry/Sphere.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/types.h" - - -namespace eckit::geo::geometry { - - -struct Sphere { - /// Great-circle central angle between two points (latitude/longitude coordinates) in radians - static double angle(const PointLatLon&, const PointLatLon&); - - /// Great-circle central angle between two points (Cartesian coordinates) in radians - static double angle(double radius, const PointXYZ&, const PointXYZ&); - - /// Great-circle distance between two points (latitude/longitude coordinates) in metres - static double distance(double radius, const PointLatLon&, const PointLatLon&); - - /// Great-circle distance between two points (Cartesian coordinates) in metres - static double distance(double radius, const PointXYZ&, const PointXYZ&); - - /// Surface area in square metres - static double area(double radius); - - // Convert spherical coordinates to Cartesian - static PointXYZ ll_to_xyz(double radius, const PointLatLon&, double height); - - // Convert Cartesian coordinates to spherical - static PointLatLon xyz_to_ll(double radius, const PointXYZ&); -}; - - -} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/Spheroid.cc b/src/eckit/geo/geometry/Spheroid.cc deleted file mode 100644 index 05a65c4d5..000000000 --- a/src/eckit/geo/geometry/Spheroid.cc +++ /dev/null @@ -1,88 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/geometry/Spheroid.h" - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/util.h" - - -namespace eckit::geo::geometry { - - -double Spheroid::angle(const PointLatLon& A, const PointLatLon& B) { - NOTIMP; -} - - -double Spheroid::angle(double a, double b, const PointXYZ& A, const PointXYZ& B) { - NOTIMP; -} - - -double Spheroid::distance(double a, double b, const PointLatLon& A, const PointLatLon& B) { - NOTIMP; -} - - -double Spheroid::distance(double a, double b, const PointXYZ& A, const PointXYZ& B) { - NOTIMP; -} - - -double Spheroid::area(double a, double b) { - NOTIMP; -} - - -PointXYZ Spheroid::ll_to_xyz(double a, double b, const PointLatLon& P, double height) { - ASSERT(a > 0.); - ASSERT(b > 0.); - - /* - * See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates - * numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) - * - * cos α = sqrt( 1 - sin^2 α) is better conditioned than explicit cos α, and - * coupled with λ in [-180°, 180°[ the accuracy of the trigonometric - * functions is the same (before converting/multiplying its angle argument - * to radian) and explicitly chosing -180° over 180° for longitude. - * - * These three conditionings combined project very accurately to the sphere - * poles and quadrants. - */ - - const double lambda_deg = util::normalise_longitude_to_minimum(P.lon, -180.); - const double lambda = util::degrees_to_radians * lambda_deg; - const double phi = util::degrees_to_radians * P.lat; - - const double sin_phi = std::sin(phi); - const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); - const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; - const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); - - if (util::is_approximately_equal(a, b)) { - return {(a + height) * cos_phi * cos_lambda, (a + height) * cos_phi * sin_lambda, (a + height) * sin_phi}; - } - - const double N_phi = a * a / std::sqrt(a * a * cos_phi * cos_phi + b * b * sin_phi * sin_phi); - return {(N_phi + height) * cos_phi * cos_lambda, (N_phi + height) * cos_phi * sin_lambda, - (N_phi * (b * b) / (a * a) + height) * sin_phi}; -} - - -PointLatLon Spheroid::xyz_to_ll(double a, double b, const PointXYZ& A) { - NOTIMP; -} - - -} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/geometry/Spheroid.h b/src/eckit/geo/geometry/Spheroid.h deleted file mode 100644 index 290d89c85..000000000 --- a/src/eckit/geo/geometry/Spheroid.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/types.h" - - -namespace eckit::geo::geometry { - - -struct Spheroid { - /// Great-circle central angle between two points (latitude/longitude coordinates) in radians - static double angle(const PointLatLon&, const PointLatLon&); - - /// Great-circle central angle between two points (Cartesian coordinates) in radians - static double angle(double a, double b, const PointXYZ&, const PointXYZ&); - - /// Great-circle distance between two points (latitude/longitude coordinates) in metres - static double distance(double a, double b, const PointLatLon&, const PointLatLon&); - - /// Great-circle distance between two points (Cartesian coordinates) in metres - static double distance(double a, double b, const PointXYZ&, const PointXYZ&); - - /// Surface area in square metres - static double area(double a, double b); - - // Convert spherical coordinates to Cartesian - static PointXYZ ll_to_xyz(double a, double b, const PointLatLon&, double height); - - // Convert Cartesian coordinates to spherical - static PointLatLon xyz_to_ll(double a, double b, const PointXYZ&); -}; - - -} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/projection/LatLonToXYZ.cc b/src/eckit/geo/projection/LatLonToXYZ.cc deleted file mode 100644 index 2bec7971b..000000000 --- a/src/eckit/geo/projection/LatLonToXYZ.cc +++ /dev/null @@ -1,66 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/projection/LatLonToXYZ.h" - -#include "eckit/geo/Parametrisation.h" -#include "eckit/geo/geometry/Sphere.h" -#include "eckit/geo/geometry/Spheroid.h" -#include "eckit/geo/util.h" - - -namespace eckit::geo::projection { - - -static ProjectionBuilder __projection("ll_to_xyz"); - - -LatLonToXYZ::LatLonToXYZ(double a, double b) { - ASSERT(0. < a); - ASSERT(0. < b); - - struct LatLonToSphereXYZ final : Implementation { - using S = geometry::Sphere; - const double R_; - - explicit LatLonToSphereXYZ(double R) : - R_(R) {} - PointXYZ operator()(const PointLatLon& p) const override { return S::ll_to_xyz(R_, p, 0.); } - PointLatLon operator()(const PointXYZ& q) const override { return S::xyz_to_ll(R_, q); } - }; - - struct LatLonToSpheroidXYZ final : Implementation { - using S = geometry::Spheroid; - const double a_; - const double b_; - - explicit LatLonToSpheroidXYZ(double a, double b) : - a_(a), b_(b) {} - PointXYZ operator()(const PointLatLon& p) const override { return S::ll_to_xyz(a_, b_, p, 0.); } - PointLatLon operator()(const PointXYZ& q) const override { NOTIMP; } - }; - - impl_.reset(util::is_approximately_equal(a, b) ? static_cast(new LatLonToSphereXYZ(a)) - : new LatLonToSpheroidXYZ(a, b)); -} - - -LatLonToXYZ::LatLonToXYZ(double R) : - LatLonToXYZ(R, R) {} - - -LatLonToXYZ::LatLonToXYZ(const Parametrisation& param) : - LatLonToXYZ(param.has("R") ? param.get_double("R") : param.get_double("a"), - param.has("R") ? param.get_double("R") : param.get_double("b")) {} - - -} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc new file mode 100644 index 000000000..3f5dcade7 --- /dev/null +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -0,0 +1,69 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/projection/LonLatToXYZ.h" + +#include "eckit/geo/Parametrisation.h" +#include "eckit/geo/util.h" +#include "eckit/geometry/EllipsoidOfRevolution.h" +#include "eckit/geometry/Sphere.h" + +namespace eckit::geo::projection { + +static ProjectionBuilder __projection("ll_to_xyz"); + + +LonLatToXYZ::LonLatToXYZ(double a, double b) { + ASSERT(0. < a); + ASSERT(0. < b); + + struct LonLatToSphereXYZ final : Implementation { + using S = geometry::Sphere; + const double R_; + + explicit LonLatToSphereXYZ(double R) : + R_(R) {} + Point3 operator()(const PointLonLat& p) const override { + return S::convertSphericalToCartesian(R_, p, 0.); + } + PointLonLat operator()(const Point3& q) const override { + return S::convertCartesianToSpherical(R_, q); + } + }; + + struct LonLatToSpheroidXYZ final : Implementation { + using S = geometry::EllipsoidOfRevolution; + const double a_; + const double b_; + + explicit LonLatToSpheroidXYZ(double a, double b) : + a_(a), b_(b) {} + Point3 operator()(const PointLonLat& p) const override { + return S::convertSphericalToCartesian(a_, b_, p, 0.); + } + PointLonLat operator()(const Point3& q) const override { NOTIMP; } + }; + + impl_.reset(util::is_approximately_equal(a, b) ? static_cast(new LonLatToSphereXYZ(a)) + : new LonLatToSpheroidXYZ(a, b)); +} + + +LonLatToXYZ::LonLatToXYZ(double R) : + LonLatToXYZ(R, R) {} + + +LonLatToXYZ::LonLatToXYZ(const Parametrisation& param) : + LonLatToXYZ(param.has("R") ? param.get_double("R") : param.get_double("a"), + param.has("R") ? param.get_double("R") : param.get_double("b")) {} + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LatLonToXYZ.h b/src/eckit/geo/projection/LonLatToXYZ.h similarity index 77% rename from src/eckit/geo/projection/LatLonToXYZ.h rename to src/eckit/geo/projection/LonLatToXYZ.h index dbca4082b..b8f18b4df 100644 --- a/src/eckit/geo/projection/LatLonToXYZ.h +++ b/src/eckit/geo/projection/LonLatToXYZ.h @@ -21,16 +21,16 @@ namespace eckit::geo::projection { /// Calculate coordinates of a point on a sphere or spheroid, in [x, y, z] -class LatLonToXYZ final : public Projection { +class LonLatToXYZ final : public Projection { public: // -- Exceptions // None // -- Constructors - LatLonToXYZ(double a, double b); - explicit LatLonToXYZ(double R); - explicit LatLonToXYZ(const Parametrisation&); + LonLatToXYZ(double a, double b); + explicit LonLatToXYZ(double R); + explicit LonLatToXYZ(const Parametrisation&); // -- Destructor // None @@ -43,8 +43,8 @@ class LatLonToXYZ final : public Projection { // -- Methods - PointXYZ fwd(const PointLatLon& p) const { return (*impl_)(p); } - PointLatLon inv(const PointXYZ& q) const { return (*impl_)(q); } + Point3 fwd(const PointLonLat& p) const { return (*impl_)(p); } + PointLonLat inv(const Point3& q) const { return (*impl_)(q); } // -- Overridden methods // None @@ -67,8 +67,8 @@ class LatLonToXYZ final : public Projection { void operator=(const Implementation&) = delete; void operator=(Implementation&&) = delete; - virtual PointXYZ operator()(const PointLatLon&) const = 0; - virtual PointLatLon operator()(const PointXYZ&) const = 0; + virtual Point3 operator()(const PointLonLat&) const = 0; + virtual PointLonLat operator()(const Point3&) const = 0; }; // -- Members @@ -80,8 +80,8 @@ class LatLonToXYZ final : public Projection { // -- Overridden methods - Point fwd(const Point& p) const override { return (*impl_)(std::get(p)); } - Point inv(const Point& q) const override { return (*impl_)(std::get(q)); } + Point fwd(const Point& p) const override { return (*impl_)(std::get(p)); } + Point inv(const Point& q) const override { return (*impl_)(std::get(q)); } // -- Class members // None From 538afc566c78d1acdc192097f750b567e510ba2a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 May 2023 22:32:08 +0100 Subject: [PATCH 196/737] eckit::geo::Search2, Search3 --- src/eckit/geo/Search.h | 14 ++++---------- tests/geo/test_search.cc | 6 +++--- tests/geometry/test_kdtree.cc | 2 +- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/eckit/geo/Search.h b/src/eckit/geo/Search.h index 9681197f5..23d85b30e 100644 --- a/src/eckit/geo/Search.h +++ b/src/eckit/geo/Search.h @@ -13,29 +13,23 @@ #pragma once #include "eckit/container/KDTree.h" -#include "eckit/geo/types.h" - +#include "eckit/geometry/Point2.h" +#include "eckit/geometry/Point3.h" namespace eckit::geo { - namespace search { - template struct Traits { using Point = PointT; using Payload = PayloadT; }; - } // namespace search +using Search3 = KDTreeMemory>; -using SearchXYZ = eckit::KDTreeMemory>; - - -using SearchXY = eckit::KDTreeMemory>; - +using Search2 = KDTreeMemory>; } // namespace eckit::geo diff --git a/tests/geo/test_search.cc b/tests/geo/test_search.cc index a0aa70bfe..52216d5fb 100644 --- a/tests/geo/test_search.cc +++ b/tests/geo/test_search.cc @@ -13,7 +13,7 @@ #include #include -#include "grit/Search.h" +#include "eckit/geo/Search.h" int main(int argc, const char* argv[]) { @@ -22,7 +22,7 @@ int main(int argc, const char* argv[]) { {{0, 0, 0}, 0}, }; - grit::SearchXYZ search; + eckit::geo::Search3 search; search.build(points); std::cout << search.nearestNeighbour({0.1, 0, 0}) << std::endl; @@ -40,7 +40,7 @@ int main(int argc, const char* argv[]) { {{0, 0}, 0}, }; - grit::SearchXY search; + eckit::geo::Search2 search; search.build(points); std::cout << search.nearestNeighbour({0.1, 0}) << std::endl; diff --git a/tests/geometry/test_kdtree.cc b/tests/geometry/test_kdtree.cc index 3b33e54c2..a64a801d6 100644 --- a/tests/geometry/test_kdtree.cc +++ b/tests/geometry/test_kdtree.cc @@ -124,7 +124,7 @@ CASE("test_eckit_container_kdtree_constructor") { typedef KDTreeMemory Tree; Tree kd; - typedef Tree::PointType Point; + using Point = Tree::PointType; std::vector points; From 7388c30bb6f1058c57cb88d57bc61161e3c88ded Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 May 2023 22:33:49 +0100 Subject: [PATCH 197/737] eckit::geometry::GreatCircle --- src/eckit/geometry/GreatCircle.cc | 32 ++++++++++++++--------------- src/eckit/geometry/GreatCircle.h | 9 ++++---- tests/geometry/test_great_circle.cc | 24 ++++++++-------------- 3 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/eckit/geometry/GreatCircle.cc b/src/eckit/geometry/GreatCircle.cc index abc71a318..4a99169c8 100644 --- a/src/eckit/geometry/GreatCircle.cc +++ b/src/eckit/geometry/GreatCircle.cc @@ -45,19 +45,19 @@ static bool pole(const double lat) { //---------------------------------------------------------------------------------------------------------------------- -GreatCircle::GreatCircle(const Point2& Alonlat, const Point2& Blonlat) : +GreatCircle::GreatCircle(const PointLonLat& Alonlat, const PointLonLat& Blonlat) : A_(Alonlat), B_(Blonlat) { using namespace std; using types::is_approximately_equal; - const bool Apole = pole(A_[1]); - const bool Bpole = pole(B_[1]); - const double lon12_deg = normalise_longitude(A_[0] - B_[0], -180); + const bool Apole = pole(A_.lat); + const bool Bpole = pole(B_.lat); + const double lon12_deg = normalise_longitude(A_.lon - B_.lon, -180); const bool lon_same = Apole || Bpole || is_approximately_equal(lon12_deg, 0.); const bool lon_opposite = Apole || Bpole || is_approximately_equal(abs(lon12_deg), 180.); - const bool lat_same = is_approximately_equal(A_[1], B_[1]); - const bool lat_opposite = is_approximately_equal(A_[1], -B_[1]); + const bool lat_same = is_approximately_equal(A_.lat, B_.lat); + const bool lat_opposite = is_approximately_equal(A_.lat, -B_.lat); if ((lat_same && lon_same) || (lat_opposite && lon_opposite)) { ostringstream oss; @@ -76,11 +76,11 @@ std::vector GreatCircle::latitude(double lon) const { return {}; } - const double lat1 = degrees_to_radians * A_[1]; - const double lat2 = degrees_to_radians * B_[1]; - const double lambda1p = degrees_to_radians * (lon - A_[0]); - const double lambda2p = degrees_to_radians * (lon - B_[0]); - const double lambda = degrees_to_radians * normalise_longitude(B_[0] - A_[0], -180); + const double lat1 = degrees_to_radians * A_.lat; + const double lat2 = degrees_to_radians * B_.lat; + const double lambda1p = degrees_to_radians * (lon - A_.lon); + const double lambda2p = degrees_to_radians * (lon - B_.lon); + const double lambda = degrees_to_radians * normalise_longitude(B_.lon - A_.lon, -180); double lat = atan((tan(lat2) * sin(lambda1p) - tan(lat1) * sin(lambda2p)) / (sin(lambda))); return {radians_to_degrees * lat}; @@ -91,14 +91,14 @@ std::vector GreatCircle::longitude(double lat) const { using types::is_approximately_equal; if (crossesPoles()) { - const double lon = pole(A_[1]) ? B_[0] : A_[0]; + const double lon = pole(A_.lat) ? B_.lon : A_.lon; return pole(lat) ? vector{lon} : vector{lon, lon + 180}; } - const double lon12 = degrees_to_radians * normalise_longitude(A_[0] - B_[0], -180); - const double lon1 = degrees_to_radians * A_[0]; - const double lat1 = degrees_to_radians * A_[1]; - const double lat2 = degrees_to_radians * B_[1]; + const double lon12 = degrees_to_radians * normalise_longitude(A_.lon - B_.lon, -180); + const double lon1 = degrees_to_radians * A_.lon; + const double lat1 = degrees_to_radians * A_.lat; + const double lat2 = degrees_to_radians * B_.lat; const double lat3 = degrees_to_radians * lat; const double X = sin(lat1) * cos(lat2) * sin(lon12); diff --git a/src/eckit/geometry/GreatCircle.h b/src/eckit/geometry/GreatCircle.h index 6d38f9c20..818e0a45d 100644 --- a/src/eckit/geometry/GreatCircle.h +++ b/src/eckit/geometry/GreatCircle.h @@ -12,7 +12,8 @@ #define GreatCircle_H #include -#include "eckit/geometry/Point2.h" + +#include "eckit/geometry/PointLonLat.h" //------------------------------------------------------------------------------------------------------ @@ -23,7 +24,7 @@ namespace eckit::geometry { class GreatCircle { public: /// Great circle given two points in geographic coordinates - GreatCircle(const Point2&, const Point2&); + GreatCircle(const PointLonLat&, const PointLonLat&); /// Great circle latitude given longitude, see http://www.edwilliams.org/avform.htm#Int std::vector latitude(double lon) const; @@ -34,8 +35,8 @@ class GreatCircle { bool crossesPoles() const; private: - const Point2 A_; - const Point2 B_; + const PointLonLat A_; + const PointLonLat B_; bool crossesPoles_; }; diff --git a/tests/geometry/test_great_circle.cc b/tests/geometry/test_great_circle.cc index d2af045de..4049930fd 100644 --- a/tests/geometry/test_great_circle.cc +++ b/tests/geometry/test_great_circle.cc @@ -13,20 +13,13 @@ #include #include "eckit/geometry/GreatCircle.h" -#include "eckit/geometry/Point2.h" +#include "eckit/geometry/PointLonLat.h" #include "eckit/testing/Test.h" namespace eckit::test { using namespace geometry; -struct PointLonLat : Point2 { - PointLonLat(double x, double y) : - Point2(x, y) {} - const double& lon() const { return x_[0]; } - const double& lat() const { return x_[1]; } -}; - // ----------------------------------------------------------------------------- // test great circles @@ -108,12 +101,13 @@ CASE("test great circles intersections") { const PointLonLat mid(-159.18, -6.81); - auto lats = gc.latitude(mid.lon()); - EXPECT(lats.size() == 1 && is_approximately_equal(lats[0], mid.lat(), 0.01)); + auto lats = gc.latitude(mid.lon); + EXPECT(lats.size() == 1 && is_approximately_equal(lats[0], mid.lat, 0.01)); - auto lons = gc.longitude(mid.lat()); + auto lons = gc.longitude(mid.lat); EXPECT(lons.size() == 2); - EXPECT(is_approximately_equal_longitude(lons[0], mid.lon(), 0.01) || is_approximately_equal_longitude(lons[1], mid.lon(), 0.01)); + EXPECT(is_approximately_equal_longitude(lons[0], mid.lon, 0.01) + || is_approximately_equal_longitude(lons[1], mid.lon, 0.01)); } SECTION("mal-formed great circle") { @@ -126,11 +120,11 @@ CASE("test great circles intersections") { EXPECT_THROWS_AS(GreatCircle(A, B), BadValue); - if (is_approximately_pole(A.lat())) { + if (is_approximately_pole(A.lat)) { for (double lon1_gc : longitudes) { for (double lon2_gc : longitudes) { - EXPECT_THROWS_AS(GreatCircle({lon1_gc, A.lat()}, {lon2_gc, A.lat()}), BadValue); - EXPECT_THROWS_AS(GreatCircle({lon1_gc, B.lat()}, {lon2_gc, B.lat()}), BadValue); + EXPECT_THROWS_AS(GreatCircle({lon1_gc, A.lat}, {lon2_gc, A.lat}), BadValue); + EXPECT_THROWS_AS(GreatCircle({lon1_gc, B.lat}, {lon2_gc, B.lat}), BadValue); } } } From 617cdf31fb8da1ab558a1336cb9cee44a0dd7147 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 May 2023 22:34:15 +0100 Subject: [PATCH 198/737] eckit::geometry::Sphere, EllipsoidOfRevolution --- src/eckit/geometry/EllipsoidOfRevolution.cc | 22 +-- src/eckit/geometry/EllipsoidOfRevolution.h | 8 +- src/eckit/geometry/Sphere.cc | 87 ++++++------ src/eckit/geometry/Sphere.h | 41 +++--- src/eckit/geometry/SphereT.h | 44 +++--- tests/geometry/test_sphere.cc | 143 +++++++++----------- 6 files changed, 168 insertions(+), 177 deletions(-) diff --git a/src/eckit/geometry/EllipsoidOfRevolution.cc b/src/eckit/geometry/EllipsoidOfRevolution.cc index b2caddd42..d1fec9d28 100644 --- a/src/eckit/geometry/EllipsoidOfRevolution.cc +++ b/src/eckit/geometry/EllipsoidOfRevolution.cc @@ -16,8 +16,8 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Point2.h" #include "eckit/geometry/Point3.h" +#include "eckit/geometry/PointLonLat.h" //---------------------------------------------------------------------------------------------------------------------- @@ -47,24 +47,26 @@ static std::streamsize max_digits10 = 15 + 3; //---------------------------------------------------------------------------------------------------------------------- -void EllipsoidOfRevolution::convertSphericalToCartesian(const double& a, const double& b, const Point2& Alonlat, - Point3& B, double height) { +Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, + double b, + const PointLonLat& A, + double height) { ASSERT(a > 0.); ASSERT(b > 0.); - if (!(-90. <= Alonlat[1] && Alonlat[1] <= 90.)) { + if (!(-90. <= A.lat && A.lat <= 90.)) { std::ostringstream oss; oss.precision(max_digits10); - oss << "Invalid latitude " << Alonlat[1]; + oss << "Invalid latitude " << A.lat; throw BadValue(oss.str(), Here()); } // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) - const double lambda_deg = normalise_longitude(Alonlat[0], -180.); + const double lambda_deg = normalise_longitude(A.lon, -180.); const double lambda = degrees_to_radians * lambda_deg; - const double phi = degrees_to_radians * Alonlat[1]; + const double phi = degrees_to_radians * A.lat; const double sin_phi = std::sin(phi); const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); @@ -73,9 +75,9 @@ void EllipsoidOfRevolution::convertSphericalToCartesian(const double& a, const d const double N_phi = a * a / std::sqrt(a * a * cos_phi * cos_phi + b * b * sin_phi * sin_phi); - B[0] = (N_phi + height) * cos_phi * cos_lambda; - B[1] = (N_phi + height) * cos_phi * sin_lambda; - B[2] = (N_phi * (b * b) / (a * a) + height) * sin_phi; + return {(N_phi + height) * cos_phi * cos_lambda, + (N_phi + height) * cos_phi * sin_lambda, + (N_phi * (b * b) / (a * a) + height) * sin_phi}; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geometry/EllipsoidOfRevolution.h b/src/eckit/geometry/EllipsoidOfRevolution.h index 4ef6b4f58..a9ce7936f 100644 --- a/src/eckit/geometry/EllipsoidOfRevolution.h +++ b/src/eckit/geometry/EllipsoidOfRevolution.h @@ -17,15 +17,17 @@ namespace eckit::geometry { //------------------------------------------------------------------------------------------------------ -class Point2; +class PointLonLat; class Point3; //------------------------------------------------------------------------------------------------------ struct EllipsoidOfRevolution { // Convert elliptic coordinates to Cartesian - static void convertSphericalToCartesian(const double& radiusA, const double& radiusB, const Point2& Alonlat, - Point3& B, double height = 0.); + static Point3 convertSphericalToCartesian(double a, + double b, + const PointLonLat&, + double height = 0.); }; //------------------------------------------------------------------------------------------------------ diff --git a/src/eckit/geometry/Sphere.cc b/src/eckit/geometry/Sphere.cc index d69e98df3..ca02f71ad 100644 --- a/src/eckit/geometry/Sphere.cc +++ b/src/eckit/geometry/Sphere.cc @@ -18,8 +18,8 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geometry/GreatCircle.h" -#include "eckit/geometry/Point2.h" #include "eckit/geometry/Point3.h" +#include "eckit/geometry/PointLonLat.h" #include "eckit/types/FloatCompare.h" //---------------------------------------------------------------------------------------------------------------------- @@ -28,7 +28,7 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- -static double normalise_longitude(double a, const double& minimum) { +static double normalise_longitude(double a, double minimum) { while (a < minimum) { a += 360; } @@ -50,7 +50,7 @@ inline double squared(double x) { //---------------------------------------------------------------------------------------------------------------------- -double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { +double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { using namespace std; /* @@ -69,23 +69,23 @@ double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { * } */ - if (!(-90. <= Alonlat[1] && Alonlat[1] <= 90.)) { + if (!(-90. <= A.lat && A.lat <= 90.)) { ostringstream oss; oss.precision(max_digits10); - oss << "Invalid latitude " << Alonlat[1]; + oss << "Invalid latitude " << A.lat; throw BadValue(oss.str(), Here()); } - if (!(-90. <= Blonlat[1] && Blonlat[1] <= 90.)) { + if (!(-90. <= B.lat && B.lat <= 90.)) { ostringstream oss; oss.precision(max_digits10); - oss << "Invalid latitude " << Blonlat[1]; + oss << "Invalid latitude " << B.lat; throw BadValue(oss.str(), Here()); } - const double phi1 = degrees_to_radians * Alonlat[1]; - const double phi2 = degrees_to_radians * Blonlat[1]; - const double lambda = degrees_to_radians * (Blonlat[0] - Alonlat[0]); + const double phi1 = degrees_to_radians * A.lat; + const double phi2 = degrees_to_radians * B.lat; + const double lambda = degrees_to_radians * (B.lon - A.lon); const double cos_phi1 = cos(phi1); const double sin_phi1 = sin(phi1); @@ -105,7 +105,7 @@ double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat) { return angle; } -double Sphere::centralAngle(const double& radius, const Point3& A, const Point3& B) { +double Sphere::centralAngle(double radius, const Point3& A, const Point3& B) { ASSERT(radius > 0.); // Δσ = 2 * asin( chord / 2 ) @@ -121,38 +121,37 @@ double Sphere::centralAngle(const double& radius, const Point3& A, const Point3& return angle; } -double Sphere::distance(const double& radius, const Point2& Alonlat, const Point2& Blonlat) { - return radius * centralAngle(Alonlat, Blonlat); +double Sphere::distance(double radius, const PointLonLat& A, const PointLonLat& B) { + return radius * centralAngle(A, B); } -double Sphere::distance(const double& radius, const Point3& A, const Point3& B) { +double Sphere::distance(double radius, const Point3& A, const Point3& B) { return radius * centralAngle(radius, A, B); } -double Sphere::area(const double& radius) { +double Sphere::area(double radius) { ASSERT(radius > 0.); return 4. * M_PI * radius * radius; } -double Sphere::area(const double& radius, const Point2& WestNorth, const Point2& EastSouth) { +double Sphere::area(double radius, const PointLonLat& WestNorth, const PointLonLat& EastSouth) { ASSERT(radius > 0.); // Set longitude fraction - double W = WestNorth[0]; - double E = normalise_longitude(EastSouth[0], W); - double longitude_range( - types::is_approximately_equal(W, E) && !types::is_approximately_equal(EastSouth[0], WestNorth[0]) ? 360. - : E - W); + double W = WestNorth.lon; + double E = normalise_longitude(EastSouth.lon, W); + double longitude_range(types::is_approximately_equal(W, E) + && !types::is_approximately_equal(EastSouth.lon, WestNorth.lon) + ? 360. + : E - W); ASSERT(longitude_range <= 360.); double longitude_fraction = longitude_range / 360.; // Set latitude fraction - double N = WestNorth[1]; - double S = EastSouth[1]; - ASSERT(-90. <= N && N <= 90.); - ASSERT(-90. <= S && S <= 90.); - ASSERT(N >= S); + double N = WestNorth.lat; + double S = EastSouth.lat; + ASSERT(-90. <= S && S <= N && N <= 90.); double latitude_fraction = 0.5 * (std::sin(degrees_to_radians * N) - std::sin(degrees_to_radians * S)); @@ -160,28 +159,30 @@ double Sphere::area(const double& radius, const Point2& WestNorth, const Point2& return area(radius) * latitude_fraction * longitude_fraction; } -double Sphere::greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clon) { - GreatCircle gc(Alonlat, Blonlat); +double Sphere::greatCircleLatitudeGivenLongitude(const PointLonLat& A, + const PointLonLat& B, + double Clon) { + GreatCircle gc(A, B); auto lat = gc.latitude(Clon); return lat.size() == 1 ? lat[0] : std::numeric_limits::signaling_NaN(); } -void Sphere::greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clat, - double& Clon1, double& Clon2) { - GreatCircle gc(Alonlat, Blonlat); +void Sphere::greatCircleLongitudeGivenLatitude( + const PointLonLat& A, const PointLonLat& B, double Clat, double& Clon1, double& Clon2) { + GreatCircle gc(A, B); auto lon = gc.longitude(Clat); Clon1 = lon.size() > 0 ? lon[0] : std::numeric_limits::signaling_NaN(); Clon2 = lon.size() > 1 ? lon[1] : std::numeric_limits::signaling_NaN(); } -void Sphere::convertSphericalToCartesian(const double& radius, const Point2& Alonlat, Point3& B, double height) { +Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, double height) { ASSERT(radius > 0.); - if (!(-90. <= Alonlat[1] && Alonlat[1] <= 90.)) { + if (!(-90. <= A.lat && A.lat <= 90.)) { std::ostringstream oss; oss.precision(max_digits10); - oss << "Invalid latitude " << Alonlat[1]; + oss << "Invalid latitude " << A.lat; throw BadValue(oss.str(), Here()); } @@ -198,21 +199,22 @@ void Sphere::convertSphericalToCartesian(const double& radius, const Point2& Alo * poles and quadrants. */ - const double lambda_deg = normalise_longitude(Alonlat[0], -180.); + const double lambda_deg = normalise_longitude(A.lon, -180.); const double lambda = degrees_to_radians * lambda_deg; - const double phi = degrees_to_radians * Alonlat[1]; + const double phi = degrees_to_radians * A.lat; const double sin_phi = std::sin(phi); const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; - const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); + const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) + : std::sqrt(1. - sin_lambda * sin_lambda); - B[0] = (radius + height) * cos_phi * cos_lambda; - B[1] = (radius + height) * cos_phi * sin_lambda; - B[2] = (radius + height) * sin_phi; + return {(radius + height) * cos_phi * cos_lambda, + (radius + height) * cos_phi * sin_lambda, + (radius + height) * sin_phi}; } -void Sphere::convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat) { +PointLonLat Sphere::convertCartesianToSpherical(double radius, const Point3& A) { ASSERT(radius > 0.); // numerical conditioning for both z (poles) and y @@ -221,8 +223,7 @@ void Sphere::convertCartesianToSpherical(const double& radius, const Point3& A, const double y = types::is_approximately_equal(A[1], 0.) ? 0. : A[1]; const double z = std::min(radius, std::max(-radius, A[2])) / radius; - Blonlat[0] = radians_to_degrees * std::atan2(y, x); - Blonlat[1] = radians_to_degrees * std::asin(z); + return {radians_to_degrees * std::atan2(y, x), radians_to_degrees * std::asin(z)}; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geometry/Sphere.h b/src/eckit/geometry/Sphere.h index 4b29fe206..65f3e91c8 100644 --- a/src/eckit/geometry/Sphere.h +++ b/src/eckit/geometry/Sphere.h @@ -17,45 +17,46 @@ namespace eckit::geometry { //------------------------------------------------------------------------------------------------------ -class Point2; +class PointLonLat; class Point3; //------------------------------------------------------------------------------------------------------ struct Sphere { /// Great-circle central angle between two points (latitude/longitude coordinates) in radians - static double centralAngle(const Point2& Alonlat, const Point2& Blonlat); + static double centralAngle(const PointLonLat&, const PointLonLat&); /// Great-circle central angle between two points (Cartesian coordinates) in radians - static double centralAngle(const double& radius, const Point3& A, const Point3& B); + static double centralAngle(double radius, const Point3& A, const Point3& B); /// Great-circle distance between two points (latitude/longitude coordinates) in metres - static double distance(const double& radius, const Point2& Alonlat, const Point2& Blonlat); + static double distance(double radius, const PointLonLat&, const PointLonLat&); /// Great-circle distance between two points (Cartesian coordinates) in metres - static double distance(const double& radius, const Point3& A, const Point3& B); + static double distance(double radius, const Point3& A, const Point3& B); /// Surface area in square metres - static double area(const double& radius); + static double area(double radius); - /// Surface area between parallels and meridians defined by two points (longitude/latitude - /// coordinates) in square metres - static double area(const double& radius, const Point2& Alonlat, const Point2& Blonlat); + /// Surface area between parallels and meridians defined by two points (longitude/latitude coordinates) in square metres + static double area(double radius, const PointLonLat& WestNorth, const PointLonLat& EastSouth); - // Great-circle intermediate latitude provided two circle points (A, B) and intermediate - // longitude (C) in degrees - static double greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clon); + /// Great-circle intermediate latitude provided two circle points (A, B) and intermediate longitude (C) in degrees + static double greatCircleLatitudeGivenLongitude(const PointLonLat&, + const PointLonLat&, + double Clon); - // Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate - // latitude (C) in degrees - static void greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clat, - double& Clon1, double& Clon2); + /// Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate latitude (C) in degrees + static void greatCircleLongitudeGivenLatitude( + const PointLonLat&, const PointLonLat&, double Clat, double& Clon1, double& Clon2); - // Convert spherical coordinates to Cartesian - static void convertSphericalToCartesian(const double& radius, const Point2& Alonlat, Point3& B, double height = 0.); + /// Convert spherical coordinates to Cartesian + static Point3 convertSphericalToCartesian(double radius, + const PointLonLat&, + double height = 0.); - // Convert Cartesian coordinates to spherical - static void convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat); + /// Convert Cartesian coordinates to spherical + static PointLonLat convertCartesianToSpherical(double radius, const Point3&); }; //------------------------------------------------------------------------------------------------------ diff --git a/src/eckit/geometry/SphereT.h b/src/eckit/geometry/SphereT.h index dedc9cbd5..c96ece659 100644 --- a/src/eckit/geometry/SphereT.h +++ b/src/eckit/geometry/SphereT.h @@ -11,6 +11,8 @@ #ifndef SphereT_H #define SphereT_H +#include "eckit/geometry/Point3.h" +#include "eckit/geometry/PointLonLat.h" #include "eckit/geometry/Sphere.h" //------------------------------------------------------------------------------------------------------ @@ -27,8 +29,8 @@ struct SphereT { inline static double radius() { return DATUM::radius(); } /// Great-circle central angle between two points (longitude/latitude coordinates) in radians - inline static double centralAngle(const Point2& Alonlat, const Point2& Blonlat) { - return Sphere::centralAngle(Alonlat, Blonlat); + inline static double centralAngle(const PointLonLat& A, const PointLonLat& B) { + return Sphere::centralAngle(A, B); } /// Great-circle central angle between two points (Cartesian coordinates) in radians @@ -37,8 +39,8 @@ struct SphereT { } /// Great-circle distance between two points (longitude/latitude coordinates) in metres - inline static double distance(const Point2& Alonlat, const Point2& Blonlat) { - return Sphere::distance(DATUM::radius(), Alonlat, Blonlat); + inline static double distance(const PointLonLat& A, const PointLonLat& B) { + return Sphere::distance(DATUM::radius(), A, B); } /// Great-circle distance between two points (Cartesian coordinates) in metres @@ -47,32 +49,32 @@ struct SphereT { /// Surface area in square metres inline static double area() { return Sphere::area(DATUM::radius()); } - /// Surface area between parallels and meridians defined by two points (longitude/latitude coordinates) in square - /// metres - inline static double area(const Point2& WestNorth, const Point2& EastSouth) { + /// Surface area between parallels and meridians defined by two points (longitude/latitude coordinates) in square metres + inline static double area(const PointLonLat& WestNorth, const PointLonLat& EastSouth) { return Sphere::area(DATUM::radius(), WestNorth, EastSouth); } - // Great-circle intermediate latitude provided two circle points (A, B) and intermediate longitude (C) in degrees - inline static double greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, - const double& Clon) { - return Sphere::greatCircleLatitudeGivenLongitude(Alonlat, Blonlat, Clon); + /// Great-circle intermediate latitude provided two circle points (A, B) and intermediate longitude (C) in degrees + inline static double greatCircleLatitudeGivenLongitude(const PointLonLat& A, + const PointLonLat& B, + double Clon) { + return Sphere::greatCircleLatitudeGivenLongitude(A, B, Clon); } - // Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate latitude (C) in degrees - inline static void greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, - const double& Clat, double& Clon1, double& Clon2) { - return Sphere::greatCircleLongitudeGivenLatitude(Alonlat, Blonlat, Clat, Clon1, Clon2); + /// Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate latitude (C) in degrees + inline static void greatCircleLongitudeGivenLatitude( + const PointLonLat& A, const PointLonLat& B, double Clat, double& Clon1, double& Clon2) { + return Sphere::greatCircleLongitudeGivenLatitude(A, B, Clat, Clon1, Clon2); } - // Convert spherical coordinates to Cartesian - inline static void convertSphericalToCartesian(const Point2& Alonlat, Point3& B, double height = 0.) { - Sphere::convertSphericalToCartesian(DATUM::radius(), Alonlat, B, height); + /// Convert spherical coordinates to Cartesian + inline static Point3 convertSphericalToCartesian(const PointLonLat& A, double height = 0.) { + return Sphere::convertSphericalToCartesian(DATUM::radius(), A, height); } - // Convert Cartesian coordinates to spherical - inline static void convertCartesianToSpherical(const Point3& A, Point2& Blonlat) { - Sphere::convertCartesianToSpherical(DATUM::radius(), A, Blonlat); + /// Convert Cartesian coordinates to spherical + inline static PointLonLat convertCartesianToSpherical(const Point3& A) { + return Sphere::convertCartesianToSpherical(DATUM::radius(), A); } }; diff --git a/tests/geometry/test_sphere.cc b/tests/geometry/test_sphere.cc index ab2a940e1..46a0ea2ac 100644 --- a/tests/geometry/test_sphere.cc +++ b/tests/geometry/test_sphere.cc @@ -11,8 +11,8 @@ #include #include -#include "eckit/geometry/Point2.h" #include "eckit/geometry/Point3.h" +#include "eckit/geometry/PointLonLat.h" #include "eckit/geometry/SphereT.h" #include "eckit/geometry/UnitSphere.h" #include "eckit/testing/Test.h" @@ -21,19 +21,6 @@ namespace eckit::test { using namespace geometry; -struct PointLonLat : Point2 { - PointLonLat(double x, double y) : - Point2(x, y) {} - const double& lon() const { return x_[0]; } - const double& lat() const { return x_[1]; } -}; - -struct PointXYZ : Point3 { - const double& x() const { return x_[0]; } - const double& y() const { return x_[1]; } - const double& z() const { return x_[2]; } -}; - // set sphere struct DatumTwoUnits { static double radius() { return 2.; } @@ -56,22 +43,20 @@ CASE("test unit sphere radius") { CASE("test unit sphere north pole") { const PointLonLat ll1(0., 90.); - PointXYZ p; - UnitSphere::convertSphericalToCartesian(ll1, p); + auto p = UnitSphere::convertSphericalToCartesian(ll1); - EXPECT(p.x() == 0); - EXPECT(p.y() == 0); - EXPECT(p.z() == R); + EXPECT(p.X == 0); + EXPECT(p.Y == 0); + EXPECT(p.Z == R); } CASE("test unit sphere south pole") { const PointLonLat ll1(0., -90.); - PointXYZ p; - UnitSphere::convertSphericalToCartesian(ll1, p); + auto p = UnitSphere::convertSphericalToCartesian(ll1); - EXPECT(p.x() == 0); - EXPECT(p.y() == 0); - EXPECT(p.z() == -R); + EXPECT(p.X == 0); + EXPECT(p.Y == 0); + EXPECT(p.Z == -R); } // ----------------------------------------------------------------------------- @@ -80,57 +65,55 @@ CASE("test unit sphere south pole") { CASE("test unit sphere lon 0") { const PointLonLat ll1(0., 0.); const PointLonLat ll2(-360., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); - EXPECT(p.x() == R); - EXPECT(p.y() == 0); - EXPECT(p.z() == 0); + EXPECT(p.X == R); + EXPECT(p.Y == 0); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(points_equal(p, q)); } CASE("test unit sphere lon 90") { const PointLonLat ll1(90., 0.); const PointLonLat ll2(-270., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); - EXPECT(p.x() == 0); - EXPECT(p.y() == R); - EXPECT(p.z() == 0); + EXPECT(p.X == 0); + EXPECT(p.Y == R); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(points_equal(p, q)); } CASE("test unit sphere lon 180") { const PointLonLat ll1(180., 0.); const PointLonLat ll2(-180., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(p.x() == -R); - EXPECT(p.y() == 0); - EXPECT(p.z() == 0); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); + + EXPECT(p.X == -R); + EXPECT(p.Y == 0); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(points_equal(p, q)); } CASE("test unit sphere lon 270") { const PointLonLat ll1(270., 0.); const PointLonLat ll2(-90., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(p.x() == 0); - EXPECT(p.y() == -R); - EXPECT(p.z() == 0); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(p.X == 0); + EXPECT(p.Y == -R); + EXPECT(p.Z == 0); + + EXPECT(points_equal(p, q)); } @@ -142,57 +125,57 @@ const double L = R * std::sqrt(2) / 2.; CASE("test unit sphere lon 45") { const PointLonLat ll1(45., 0.); const PointLonLat ll2(-315., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(eckit::types::is_approximately_equal(p.x(), L)); - EXPECT(eckit::types::is_approximately_equal(p.y(), L)); - EXPECT(p.z() == 0); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); + + EXPECT(eckit::types::is_approximately_equal(p.X, L)); + EXPECT(eckit::types::is_approximately_equal(p.Y, L)); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(points_equal(p, q)); } CASE("test unit sphere lon 135") { const PointLonLat ll1(135., 0.); const PointLonLat ll2(-225., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(eckit::types::is_approximately_equal(p.x(), -L)); - EXPECT(eckit::types::is_approximately_equal(p.y(), L)); - EXPECT(p.z() == 0); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); + + EXPECT(eckit::types::is_approximately_equal(p.X, -L)); + EXPECT(eckit::types::is_approximately_equal(p.Y, L)); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(points_equal(p, q)); } CASE("test unit sphere lon 225") { const PointLonLat ll1(225., 0.); const PointLonLat ll2(-135., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(eckit::types::is_approximately_equal(p.x(), -L)); - EXPECT(eckit::types::is_approximately_equal(p.y(), -L)); - EXPECT(p.z() == 0); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(eckit::types::is_approximately_equal(p.X, -L)); + EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); + EXPECT(p.Z == 0); + + EXPECT(points_equal(p, q)); } CASE("test unit sphere lon 315") { const PointLonLat ll1(315., 0.); const PointLonLat ll2(-45., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(eckit::types::is_approximately_equal(p.x(), L)); - EXPECT(eckit::types::is_approximately_equal(p.y(), -L)); - EXPECT(p.z() == 0); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); + + EXPECT(eckit::types::is_approximately_equal(p.X, L)); + EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(points_equal(p, q)); } // ----------------------------------------------------------------------------- From 7af4ce6bc54a40836255cf7f96a66e1dcb4658b4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 May 2023 22:36:46 +0100 Subject: [PATCH 199/737] eckit::geometry::PointLonLat --- src/eckit/geo/projection/PROJ.cc | 20 ++++++++++---------- src/eckit/geo/projection/Rotation.cc | 18 ++++++++---------- src/eckit/geo/projection/Rotation.h | 10 +++++----- tests/geo/test_projection.cc | 10 ++++++++-- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 5af654b62..93feb9c3c 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -34,35 +34,35 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini proj_.reset(proj_normalize_for_visualization(ctx_.get(), p.get())); ASSERT(proj_); - struct LatLon final : Convert { + struct LonLat final : Convert { PJ_COORD convert(const Point& p) const final { - const auto& q = std::get(p); + const auto& q = std::get(p); return proj_coord(q.lon, q.lat, 0, 0); } - Point convert(const PJ_COORD& c) const final { return PointLatLon::make(c.enu.n, c.enu.e, lon_minimum_); } + Point convert(const PJ_COORD& c) const final { return PointLonLat::make(c.enu.n, c.enu.e, lon_minimum_); } - explicit LatLon(double lon_minimum) : + explicit LonLat(double lon_minimum) : lon_minimum_(lon_minimum) {} const double lon_minimum_; }; struct XY final : Convert { PJ_COORD convert(const Point& p) const final { - const auto& q = std::get(p); + const auto& q = std::get(p); return proj_coord(q.X, q.Y, 0, 0); } - Point convert(const PJ_COORD& c) const final { return PointXY{c.xy.x, c.xy.y}; } + Point convert(const PJ_COORD& c) const final { return Point2{c.xy.x, c.xy.y}; } }; struct XYZ final : Convert { PJ_COORD convert(const Point& p) const final { - const auto& q = std::get(p); + const auto& q = std::get(p); return proj_coord(q.X, q.Y, q.Z, 0); } - Point convert(const PJ_COORD& c) const final { return PointXYZ{c.xy.x, c.xy.y, c.xyz.z}; } + Point convert(const PJ_COORD& c) const final { return Point3{c.xy.x, c.xy.y, c.xyz.z}; } }; auto convert_ptr = [lon_minimum](const std::string& string) -> Convert* { @@ -78,8 +78,8 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini return type == PJ_CS_TYPE_CARTESIAN && dim == 3 ? static_cast(new XYZ) : type == PJ_CS_TYPE_CARTESIAN && dim == 2 ? static_cast(new XY) - : type == PJ_CS_TYPE_ELLIPSOIDAL ? static_cast(new LatLon(lon_minimum)) - : type == PJ_CS_TYPE_SPHERICAL ? static_cast(new LatLon(lon_minimum)) + : type == PJ_CS_TYPE_ELLIPSOIDAL ? static_cast(new LonLat(lon_minimum)) + : type == PJ_CS_TYPE_SPHERICAL ? static_cast(new LonLat(lon_minimum)) : NOTIMP; }; diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index a529cba2d..1aaf726ef 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -16,37 +16,36 @@ #include #include "eckit/geo/Parametrisation.h" -#include "eckit/geo/geometry/Sphere.h" -#include "eckit/geo/types/MatrixXYZ.h" #include "eckit/geo/util.h" - +#include "eckit/geometry/UnitSphere.h" +#include "eckit/maths/Matrix3.h" namespace eckit::geo::projection { - static ProjectionBuilder __projection("rotation"); Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : rotated_(true) { - using M = types::MatrixXYZ; + using M = maths::Matrix3; struct No final : Rotate { - PointLatLon operator()(const PointLatLon& p) const override { return p; } + PointLonLat operator()(const PointLonLat& p) const override { return p; } }; struct Angle final : Rotate { explicit Angle(double angle) : angle_(angle) {} - PointLatLon operator()(const PointLatLon& p) const override { return {p.lat, p.lon + angle_}; } + PointLonLat operator()(const PointLonLat& p) const override { return {p.lat, p.lon + angle_}; } const double angle_; }; struct Matrix final : Rotate { explicit Matrix(M&& R) : R_(R) {} - PointLatLon operator()(const PointLatLon& p) const override { - return geometry::Sphere::xyz_to_ll(1., R_ * geometry::Sphere::ll_to_xyz(1., p, 0.)); + PointLonLat operator()(const PointLonLat& p) const override { + return geometry::UnitSphere::convertCartesianToSpherical( + R_ * geometry::UnitSphere::convertSphericalToCartesian(p)); } const M R_; }; @@ -97,5 +96,4 @@ Rotation::Rotation(const Parametrisation& param) : Rotation(param.get_double("south_pole_lat"), param.get_double("south_pole_lon"), param.has("angle") ? param.get_double("angle") : 0) {} - } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index 837c0758b..9e971985e 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -43,8 +43,8 @@ class Rotation final : public Projection { // -- Methods bool rotated() const { return rotated_; } - PointLatLon fwd(const PointLatLon& p) const { return (*fwd_)(p); } - PointLatLon inv(const PointLatLon& q) const { return (*inv_)(q); } + PointLonLat fwd(const PointLonLat& p) const { return (*fwd_)(p); } + PointLonLat inv(const PointLonLat& q) const { return (*inv_)(q); } // -- Overridden methods // None @@ -67,7 +67,7 @@ class Rotation final : public Projection { void operator=(const Rotate&) = delete; void operator=(Rotate&&) = delete; - virtual PointLatLon operator()(const PointLatLon&) const = 0; + virtual PointLonLat operator()(const PointLonLat&) const = 0; }; // -- Members @@ -81,8 +81,8 @@ class Rotation final : public Projection { // -- Overridden methods - Point fwd(const Point& p) const override { return (*fwd_)(std::get(p)); } - Point inv(const Point& q) const override { return (*inv_)(std::get(q)); } + Point fwd(const Point& p) const override { return (*fwd_)(std::get(p)); } + Point inv(const Point& q) const override { return (*inv_)(std::get(q)); } // -- Class members // None diff --git a/tests/geo/test_projection.cc b/tests/geo/test_projection.cc index 5645436bb..6e24c9f80 100644 --- a/tests/geo/test_projection.cc +++ b/tests/geo/test_projection.cc @@ -68,8 +68,14 @@ int main(int argc, char* argv[]) { PointLatLon a; PointXYZ b; } tests[] = { - {{0, 0}, {1, 0, 0}}, {{0, 90}, {0, 1, 0}}, {{0, 180}, {-1, 0, 0}}, {{0, 270}, {0, -1, 0}}, - {{-90, 0}, {0, 0, -0.5}}, {{-90, 42}, {0, 0, -0.5}}, {{90, 0}, {0, 0, 0.5}}, {{90, 42}, {0, 0, 0.5}}, + {{0, 0}, {1, 0, 0}}, + {{0, 90}, {0, 1, 0}}, + {{0, 180}, {-1, 0, 0}}, + {{0, 270}, {0, -1, 0}}, + {{-90, 0}, {0, 0, -0.5}}, + {{-90, 42}, {0, 0, -0.5}}, + {{90, 0}, {0, 0, 0.5}}, + {{90, 42}, {0, 0, 0.5}}, }; for (const auto& test : tests) { From c120ec43ebfbb1d410708c73f81e66630bd3e82c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 May 2023 22:36:54 +0100 Subject: [PATCH 200/737] eckit::geo --- src/eckit/geo/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index 22f2c8af9..cca5c2833 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -40,7 +40,7 @@ pl_type pl_convert(const T& pl) { pl_type _pl(pl.size()); std::transform(pl.begin(), pl.end(), _pl.begin(), [](typename T::value_type p) { return static_cast(p); }); - return std::move(_pl); + return _pl; } From 874f2d5ab6e02aaa750cf33b4ddcf84121657cc6 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 11 May 2023 11:28:56 +0100 Subject: [PATCH 201/737] eckit::geo::Search2, Search3, SearchLonLat --- src/eckit/geo/Search.h | 49 ++++++++++++++++++++++++++++++++++++++-- tests/geo/test_search.cc | 4 ++-- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/eckit/geo/Search.h b/src/eckit/geo/Search.h index 23d85b30e..5a0701b21 100644 --- a/src/eckit/geo/Search.h +++ b/src/eckit/geo/Search.h @@ -13,23 +13,68 @@ #pragma once #include "eckit/container/KDTree.h" +#include "eckit/container/sptree/SPValue.h" #include "eckit/geometry/Point2.h" #include "eckit/geometry/Point3.h" +#include "eckit/geometry/PointLonLat.h" +#include "eckit/geometry/UnitSphere.h" + namespace eckit::geo { -namespace search { +namespace search { template struct Traits { using Point = PointT; using Payload = PayloadT; }; - } // namespace search + using Search3 = KDTreeMemory>; + using Search2 = KDTreeMemory>; + +struct SearchLonLat : Search3 { + using Point = geometry::PointLonLat; + using Value = SPValue, KDMemory>>; + + using Search3::Search3; + + void insert(const SearchLonLat::Value& value) { + Search3::insert({convert(value.point()), value.payload()}); + } + + template + void build(ITER begin, ITER end) { + for (auto it = begin; it != end; ++it) { + insert(*it); + } + } + + template + void build(Container& c) { + build(c.begin(), c.end()); + } + + NodeInfo nearestNeighbour(const Point& p) { return Search3::nearestNeighbour(convert(p)); } + + NodeList findInSphere(const Point& p, double radius) { + return Search3::findInSphere(convert(p), radius); + } + + NodeList kNearestNeighbours(const Point& p, size_t k) { + return Search3::kNearestNeighbours(convert(p), k); + } + +private: + static Search3::Point convert(const Point& p) { + return geometry::UnitSphere::convertSphericalToCartesian(p); + } +}; + + } // namespace eckit::geo diff --git a/tests/geo/test_search.cc b/tests/geo/test_search.cc index 52216d5fb..d0672b506 100644 --- a/tests/geo/test_search.cc +++ b/tests/geo/test_search.cc @@ -18,7 +18,7 @@ int main(int argc, const char* argv[]) { { - std::vector points{ + std::vector points{ {{0, 0, 0}, 0}, }; @@ -36,7 +36,7 @@ int main(int argc, const char* argv[]) { { - std::vector points{ + std::vector points{ {{0, 0}, 0}, }; From 879e5f5e5183a0b35ed4dfb1901aabfd9bf685d9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 11 May 2023 11:29:45 +0100 Subject: [PATCH 202/737] eckit::geo --- src/eckit/geo/BoundingBox.cc | 4 ++++ src/eckit/geo/BoundingBox.h | 3 +++ src/eckit/geo/Projection.cc | 7 +++++++ src/eckit/geo/projection/LonLatToXYZ.cc | 3 +++ src/eckit/geo/projection/Rotation.cc | 3 +++ src/eckit/geo/types.cc | 4 ++++ src/eckit/geo/types.h | 3 +++ 7 files changed, 27 insertions(+) diff --git a/src/eckit/geo/BoundingBox.cc b/src/eckit/geo/BoundingBox.cc index fe8d7dfcd..7d5ad1be4 100644 --- a/src/eckit/geo/BoundingBox.cc +++ b/src/eckit/geo/BoundingBox.cc @@ -9,6 +9,7 @@ * does it submit to any jurisdiction. */ + #include "eckit/geo/BoundingBox.h" #include @@ -17,8 +18,10 @@ #include "eckit/geo/util.h" #include "eckit/geometry/Sphere.h" + namespace eckit::geo { + BoundingBox::BoundingBox(double north, double west, double south, double east) : north_(north), west_(west), south_(south), east_(east) { if (west_ != east_) { @@ -127,4 +130,5 @@ double BoundingBox::area(double radius) const { return geometry::Sphere::area(radius) * latf * lonf; } + } // namespace eckit::geo diff --git a/src/eckit/geo/BoundingBox.h b/src/eckit/geo/BoundingBox.h index 0e2907f5d..3cc7c9f2d 100644 --- a/src/eckit/geo/BoundingBox.h +++ b/src/eckit/geo/BoundingBox.h @@ -12,8 +12,10 @@ #pragma once + namespace eckit::geo { + class BoundingBox { public: // -- Exceptions @@ -120,4 +122,5 @@ class BoundingBox { // None }; + } // namespace eckit::geo diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index f78f43b60..af623db03 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -20,8 +20,10 @@ #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" + namespace eckit::geo { + #if 0 - mercator: double DiInMetres @@ -216,6 +218,7 @@ Projection centre (grib2/tables/30/3.5.table) 2 1 Projection is bipolar and symmetric #endif + static pthread_once_t __once = PTHREAD_ONCE_INIT; static Mutex* __mutex = nullptr; static std::map* __factories = nullptr; @@ -225,6 +228,7 @@ static void __init() { __factories = new std::map(); } + Projection* ProjectionFactory::build(const ProjectionFactory::key_type& key, const Parametrisation& param) { pthread_once(&__once, __init); @@ -238,6 +242,7 @@ Projection* ProjectionFactory::build(const ProjectionFactory::key_type& key, throw BadValue("ProjectionFactory: unknown '" + key + "'"); } + std::ostream& ProjectionFactory::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); @@ -251,6 +256,7 @@ std::ostream& ProjectionFactory::list(std::ostream& out) { return out; } + ProjectionFactory::ProjectionFactory(const ProjectionFactory::key_type& key) : key_(key) { pthread_once(&__once, __init); @@ -272,4 +278,5 @@ ProjectionFactory::~ProjectionFactory() { } } + } // namespace eckit::geo diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc index 3f5dcade7..c38df926a 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -17,8 +17,10 @@ #include "eckit/geometry/EllipsoidOfRevolution.h" #include "eckit/geometry/Sphere.h" + namespace eckit::geo::projection { + static ProjectionBuilder __projection("ll_to_xyz"); @@ -66,4 +68,5 @@ LonLatToXYZ::LonLatToXYZ(const Parametrisation& param) : LonLatToXYZ(param.has("R") ? param.get_double("R") : param.get_double("a"), param.has("R") ? param.get_double("R") : param.get_double("b")) {} + } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 1aaf726ef..6d3bda0f9 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -20,8 +20,10 @@ #include "eckit/geometry/UnitSphere.h" #include "eckit/maths/Matrix3.h" + namespace eckit::geo::projection { + static ProjectionBuilder __projection("rotation"); @@ -96,4 +98,5 @@ Rotation::Rotation(const Parametrisation& param) : Rotation(param.get_double("south_pole_lat"), param.get_double("south_pole_lon"), param.has("angle") ? param.get_double("angle") : 0) {} + } // namespace eckit::geo::projection diff --git a/src/eckit/geo/types.cc b/src/eckit/geo/types.cc index 1443853e4..fc728ecac 100644 --- a/src/eckit/geo/types.cc +++ b/src/eckit/geo/types.cc @@ -9,10 +9,13 @@ * does it submit to any jurisdiction. */ + #include "eckit/geo/types.h" + #include "eckit/exception/Exceptions.h" + std::ostream& operator<<(std::ostream& out, const eckit::geo::Point& p) { return std::holds_alternative(p) ? out << std::get(p) @@ -23,6 +26,7 @@ std::ostream& operator<<(std::ostream& out, const eckit::geo::Point& p) { : NOTIMP; } + bool operator==(const eckit::geo::Point& p, const eckit::geo::Point& q) { ASSERT(p.index() == q.index()); diff --git a/src/eckit/geo/types.h b/src/eckit/geo/types.h index 9010164d7..d55865436 100644 --- a/src/eckit/geo/types.h +++ b/src/eckit/geo/types.h @@ -23,6 +23,7 @@ namespace eckit::geo { + using PointLonLat = eckit::geometry::PointLonLat; using Point2 = eckit::geometry::Point2; using Point3 = eckit::geometry::Point3; @@ -34,6 +35,8 @@ using pl_type = std::vector; } // namespace eckit::geo + std::ostream& operator<<(std::ostream&, const eckit::geo::Point&); + bool operator==(const eckit::geo::Point&, const eckit::geo::Point&); From 7d66bbe1b788b04710a6ce5e101ccfd3ede25304 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 11 May 2023 11:30:04 +0100 Subject: [PATCH 203/737] eckit::geo --- src/eckit/geo/iterator/IteratorAggregator.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/eckit/geo/iterator/IteratorAggregator.h b/src/eckit/geo/iterator/IteratorAggregator.h index d643c195b..bbeddb56c 100644 --- a/src/eckit/geo/iterator/IteratorAggregator.h +++ b/src/eckit/geo/iterator/IteratorAggregator.h @@ -78,7 +78,6 @@ class IteratorAggregator final : public Iterator, protected Scanner { // -- Overridden methods bool operator++() override { return Scanner::operator++(); } - bool operator++(int) override { return Scanner::operator++(0); } size_t size() const override { return Scanner::size(); } // -- Class members From 056f1508e29ce71c07598d335f7c52206a0dbc3c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 11 May 2023 11:30:34 +0100 Subject: [PATCH 204/737] eckit::geo --- tests/CMakeLists.txt | 3 +- tests/geo/CMakeLists.txt | 22 +++ tests/geo/test_iterator.cc | 18 +-- tests/geo/test_param.cc | 9 +- tests/geo/test_projection.cc | 60 +++---- tests/geo/test_projection_ll_to_xyz.cc | 21 ++- tests/geo/test_projection_proj.cc | 31 ++-- tests/geo/test_projection_rotation.cc | 211 ++++++++++++------------- tests/geo/test_types.cc | 43 ++--- tests/geo/test_util.cc | 34 ++-- 10 files changed, 241 insertions(+), 211 deletions(-) create mode 100644 tests/geo/CMakeLists.txt diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1f3742eec..e959e5e87 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory( config ) add_subdirectory( container ) add_subdirectory( exception ) add_subdirectory( filesystem ) +add_subdirectory( geo ) add_subdirectory( geometry ) add_subdirectory( io ) add_subdirectory( large_file ) @@ -14,12 +15,12 @@ add_subdirectory( option ) add_subdirectory( parser ) add_subdirectory( runtime ) add_subdirectory( serialisation ) +add_subdirectory( system ) add_subdirectory( testing ) add_subdirectory( thread ) add_subdirectory( types ) add_subdirectory( utils ) add_subdirectory( value ) -add_subdirectory( system ) if( HAVE_ECKIT_SQL ) add_subdirectory( sql ) diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt new file mode 100644 index 000000000..65a3eb217 --- /dev/null +++ b/tests/geo/CMakeLists.txt @@ -0,0 +1,22 @@ +foreach( _test + #grib + iterator + param + projection + projection_ll_to_xyz + projection_proj + projection_rotation + search + types + util + ) + ecbuild_add_test( + TARGET eckit_test_geo_${_test} + SOURCES test_${_test}.cc + LIBS eckit_geo ) + + + + + +endforeach() diff --git a/tests/geo/test_iterator.cc b/tests/geo/test_iterator.cc index 30388290a..aafe6f715 100644 --- a/tests/geo/test_iterator.cc +++ b/tests/geo/test_iterator.cc @@ -12,25 +12,21 @@ #include -#include "grit/Scanner.h" -#include "grit/exception.h" -#include "grit/iterator/IteratorAggregator.h" -#include "grit/iterator/IteratorComposer.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/Scanner.h" +#include "eckit/geo/iterator/IteratorAggregator.h" +#include "eckit/geo/iterator/IteratorComposer.h" int main(int argc, const char* argv[]) { + eckit::geo::iterator::IteratorComposer i(nullptr); - grit::iterator::IteratorComposer i(nullptr); - - - struct ScannerTest : public grit::Scanner { + struct ScannerTest : public eckit::geo::Scanner { bool operator++() override { NOTIMP; } - bool operator++(int) override { NOTIMP; } size_t size() const override { NOTIMP; } }; - grit::iterator::IteratorAggregator j; - + eckit::geo::iterator::IteratorAggregator j; return 0; } diff --git a/tests/geo/test_param.cc b/tests/geo/test_param.cc index f02b309bc..211c00cd7 100644 --- a/tests/geo/test_param.cc +++ b/tests/geo/test_param.cc @@ -13,12 +13,13 @@ #include #include -#include "grit/param/Map.h" -#include "grit/test.h" +#include "eckit/geo/param/Map.h" +#include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - std::unique_ptr param(new grit::param::Map({{"a", -123}, {"b", "B"}, {"c", 123UL}})); + std::unique_ptr param( + new eckit::geo::param::Map({{"a", -123}, {"b", "B"}, {"c", 123UL}})); int a = 0; EXPECT(param->get("a", a)); @@ -33,7 +34,7 @@ int main(int argc, char* argv[]) { std::cout << "c: '" << c << "'" << std::endl; int d = 321; - dynamic_cast(param.get())->set("b", d); + dynamic_cast(param.get())->set("b", d); EXPECT(param->get("b", d)); std::cout << "d: '" << d << "'" << std::endl; } diff --git a/tests/geo/test_projection.cc b/tests/geo/test_projection.cc index 6e24c9f80..3a47e84ef 100644 --- a/tests/geo/test_projection.cc +++ b/tests/geo/test_projection.cc @@ -13,69 +13,71 @@ #include #include -#include "grit/Projection.h" -#include "grit/param/Map.h" -#include "grit/test.h" +#include "eckit/geo/Projection.h" +#include "eckit/geo/param/Map.h" +#include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using grit::Point; - using grit::PointLatLon; - using grit::PointXYZ; - using Projection = std::unique_ptr; - - - Point p = PointLatLon{1, 1}; + using eckit::geo::Point; + using eckit::geo::Point3; + using eckit::geo::PointLonLat; + using Projection = std::unique_ptr; + Point p = PointLonLat{1, 1}; { - std::unique_ptr projection(grit::ProjectionFactory::build("none", grit::param::Map{})); + std::unique_ptr projection( + eckit::geo::ProjectionFactory::build("none", eckit::geo::param::Map{})); EXPECT(p == projection->inv(p)); EXPECT(p == projection->fwd(p)); } - { - grit::param::Map param({ + eckit::geo::param::Map param({ {"projection", "rotation"}, {"south_pole_lat", -91.}, {"south_pole_lon", -361.}, }); - std::unique_ptr projection( - grit::ProjectionFactory::build(param.get_string("projection"), param)); + std::unique_ptr projection( + eckit::geo::ProjectionFactory::build(param.get_string("projection"), param)); EXPECT(p == projection->inv(projection->fwd(p))); EXPECT(p == projection->fwd(projection->inv(p))); } - { - Projection s1(grit::ProjectionFactory::build("ll_to_xyz", grit::param::Map({{"R", 1.}}))); - Projection s2(grit::ProjectionFactory::build("ll_to_xyz", grit::param::Map({{"a", 1.}, {"b", 1.}}))); - Projection s3(grit::ProjectionFactory::build("ll_to_xyz", grit::param::Map({{"a", 1.}, {"b", 0.5}}))); + Projection s1( + eckit::geo::ProjectionFactory::build("ll_to_xyz", eckit::geo::param::Map({{"R", 1.}}))); + Projection s2( + eckit::geo::ProjectionFactory::build("ll_to_xyz", + eckit::geo::param::Map({{"a", 1.}, {"b", 1.}}))); + Projection s3( + eckit::geo::ProjectionFactory::build("ll_to_xyz", + eckit::geo::param::Map({{"a", 1.}, {"b", 0.5}}))); EXPECT(p == s1->inv(s1->fwd(p))); EXPECT(p == s2->inv(s2->fwd(p))); EXPECT(s1->fwd(p) == s2->fwd(p)); - Point q = PointLatLon{0, 1}; + Point q = PointLonLat{1, 0}; EXPECT(s1->fwd(q) == s3->fwd(q)); EXPECT(s2->fwd(q) == s3->fwd(q)); struct { - PointLatLon a; - PointXYZ b; + PointLonLat a; + Point3 b; } tests[] = { {{0, 0}, {1, 0, 0}}, - {{0, 90}, {0, 1, 0}}, - {{0, 180}, {-1, 0, 0}}, - {{0, 270}, {0, -1, 0}}, - {{-90, 0}, {0, 0, -0.5}}, - {{-90, 42}, {0, 0, -0.5}}, - {{90, 0}, {0, 0, 0.5}}, - {{90, 42}, {0, 0, 0.5}}, + {{90, 0}, {0, 1, 0}}, + {{180, 0}, {-1, 0, 0}}, + {{270, 0}, {0, -1, 0}}, + {{0, -90}, {0, 0, -0.5}}, + {{42, -90}, {0, 0, -0.5}}, + {{0, 90}, {0, 0, 0.5}}, + {{42, 90}, {0, 0, 0.5}}, }; for (const auto& test : tests) { diff --git a/tests/geo/test_projection_ll_to_xyz.cc b/tests/geo/test_projection_ll_to_xyz.cc index 1a527befc..506ec04b4 100644 --- a/tests/geo/test_projection_ll_to_xyz.cc +++ b/tests/geo/test_projection_ll_to_xyz.cc @@ -12,20 +12,19 @@ #include -#include "grit/projection/LatLonToXYZ.h" -#include "grit/test.h" +#include "eckit/geo/projection/LonLatToXYZ.h" +#include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using grit::Point; - using grit::PointLatLon; - using grit::projection::LatLonToXYZ; - - const PointLatLon p(1., 723.); + using eckit::geo::Point; + using eckit::geo::PointLonLat; + using eckit::geo::projection::LonLatToXYZ; + const PointLonLat p(1., 723.); { - LatLonToXYZ to_xyz(1.); + LonLatToXYZ to_xyz(1.); auto q = to_xyz.fwd(p); auto r = to_xyz.inv(q); @@ -36,11 +35,11 @@ int main(int argc, char* argv[]) { { - LatLonToXYZ to_xyz_ab(3., 2.); // oblate - LatLonToXYZ to_xyz_ba(2., 3.); // problate + LonLatToXYZ to_xyz_ab(3., 2.); // oblate + LonLatToXYZ to_xyz_ba(2., 3.); // problate for (const auto& lon : {0., 90., 180., 270.}) { - PointLatLon p{0., lon}; + PointLonLat p{0., lon}; std::cout << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) << ", p_ba(x,y,z): " << to_xyz_ba.fwd(p) << std::endl; } diff --git a/tests/geo/test_projection_proj.cc b/tests/geo/test_projection_proj.cc index af1ab7634..dae3942cb 100644 --- a/tests/geo/test_projection_proj.cc +++ b/tests/geo/test_projection_proj.cc @@ -12,34 +12,38 @@ #include -#include "grit/param/Map.h" -#include "grit/projection/PROJ.h" -#include "grit/test.h" +#include "eckit/geo/param/Map.h" +#include "eckit/geo/projection/PROJ.h" +#include "eckit/testing/Test.h" int main(int argc, char* argv[]) { std::cout.precision(14); - grit::PointLatLon a{55., 12.}; + eckit::geo::PointLonLat a{12., 55.}; struct { - const grit::Point b; + const eckit::geo::Point b; const std::string target; } tests[] = { - {grit::PointXY{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, - {grit::PointXY{691875.632137542, 6098907.825129169}, "EPSG:32632"}, + {eckit::geo::Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, + {eckit::geo::Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, {a, "EPSG:4326"}, {a, "EPSG:4979"}, - {grit::PointXYZ{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, - {grit::PointXYZ{3574529.7050235, 759789.74368715, 5219005.2599833}, "+proj=cart +R=6371229."}, - {grit::PointXYZ{3574399.5431832, 759762.07693392, 5218815.216709}, "+proj=cart +ellps=sphere"}, + {eckit::geo::Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, + {eckit::geo::Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, + "+proj=cart +R=6371229."}, + {eckit::geo::Point3{3574399.5431832, 759762.07693392, 5218815.216709}, + "+proj=cart +ellps=sphere"}, {a, "+proj=latlon +ellps=sphere"}, }; for (const auto& test : tests) { - grit::projection::PROJ projection(grit::param::Map({{"source", "EPSG:4326"}, {"target", test.target}})); + eckit::geo::projection::PROJ projection( + eckit::geo::param::Map({{"source", "EPSG:4326"}, {"target", test.target}})); - std::cout << "ellipsoid: '" << grit::projection::PROJ::ellipsoid(projection.target()) << std::endl; + std::cout << "ellipsoid: '" << eckit::geo::projection::PROJ::ellipsoid(projection.target()) + << std::endl; auto b = projection.fwd(a); auto c = projection.inv(b); @@ -49,7 +53,8 @@ int main(int argc, char* argv[]) { EXPECT(b == test.b); EXPECT(c == a); - grit::projection::PROJ reverse(grit::param::Map({{"source", test.target}, {"target", "EPSG:4326"}})); + eckit::geo::projection::PROJ reverse( + eckit::geo::param::Map({{"source", test.target}, {"target", "EPSG:4326"}})); auto d = reverse.fwd(test.b); auto e = reverse.inv(d); diff --git a/tests/geo/test_projection_rotation.cc b/tests/geo/test_projection_rotation.cc index db944d892..0ec2798c2 100644 --- a/tests/geo/test_projection_rotation.cc +++ b/tests/geo/test_projection_rotation.cc @@ -12,18 +12,17 @@ #include -#include "grit/projection/Rotation.h" -#include "grit/test.h" +#include "eckit/geo/projection/Rotation.h" +#include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using grit::Point; - using grit::PointLatLon; - using grit::projection::Rotation; - + using eckit::geo::Point; + using eckit::geo::PointLonLat; + using eckit::geo::projection::Rotation; { - const PointLatLon p(1, 1); + const PointLonLat p(1, 1); int delta[] = {-360, -180, -1, 0, 1, 90, 91, 180}; for (auto a : delta) { @@ -39,103 +38,102 @@ int main(int argc, char* argv[]) { } } - { const int Ni = 12; const int Nj = 3; Rotation rot(-46.7, 182., 0.); - const PointLatLon ref[]{ - {-46.7, -178.}, - {-16.7, -178.}, - {13.3, -178.}, - {43.3, -178.}, - {73.3, -178.}, - {76.7, 2.}, - {46.7, 2.}, - {-46.7, -178.}, - {-19.46929, -162.62343}, - {8.65459, -152.02366}, - {36.43683, -139.57464}, - {61.43199, -113.10894}, - {68.00825, -39.88245}, - {46.7, 2.}, - {-46.7, -178.}, - {-27.31067, -148.83443}, - {-3.837, -129.26346}, - {20.05422, -110.79116}, - {41.36507, -85.87917}, - {53.29508, -44.42496}, - {46.7, 2.}, - {-46.7, -178.}, - {-39.07002, -137.90794}, - {-21.33906, -109.60146}, - {0., -88.}, - {21.33906, -66.39854}, - {39.07002, -38.09206}, - {46.7, 2.}, - {-46.7, -178.}, - {-53.29508, -131.57504}, - {-41.36507, -90.12083}, - {-20.05422, -65.20884}, - {3.837, -46.73654}, - {27.31067, -27.16557}, - {46.7, 2.}, - {-46.7, -178.}, - {-68.00825, -136.11755}, - {-61.43199, -62.89106}, - {-36.43683, -36.42536}, - {-8.65459, -23.97634}, - {19.46929, -13.37657}, - {46.7, 2.}, - {-46.7, -178.}, - {-76.7, -178.}, - {-73.3, 2.}, - {-43.3, 2.}, - {-13.3, 2.}, - {16.7, 2.}, - {46.7, 2.}, - {-46.7, -178.}, - {-68.00825, 140.11755}, - {-61.43199, 66.89106}, - {-36.43683, 40.42536}, - {-8.65459, 27.97634}, - {19.46929, 17.37657}, - {46.7, 2.}, - {-46.7, -178.}, - {-53.29508, 135.57504}, - {-41.36507, 94.12083}, - {-20.05422, 69.20884}, - {3.837, 50.73654}, - {27.31067, 31.16557}, - {46.7, 2.}, - {-46.7, -178.}, - {-39.07002, 141.90794}, - {-21.33906, 113.60146}, - {0., 92.}, - {21.33906, 70.39854}, - {39.07002, 42.09206}, - {46.7, 2.}, - {-46.7, -178.}, - {-27.31067, 152.83443}, - {-3.837, 133.26346}, - {20.05422, 114.79116}, - {41.36507, 89.87917}, - {53.29508, 48.42496}, - {46.7, 2.}, - {-46.7, -178.}, - {-19.46929, 166.62343}, - {8.65459, 156.02366}, - {36.43683, 143.57464}, - {61.43199, 117.10894}, - {68.00825, 43.88245}, - {46.7, 2.}, + const PointLonLat ref[]{ + {-178., -46.7}, + {-178., -16.7}, + {-178., 13.3}, + {-178., 43.3}, + {-178., 73.3}, + {2., 76.7}, + {2., 46.7}, + {-178., -46.7}, + {-162.62343, -19.46929}, + {-152.02366, 8.65459}, + {-139.57464, 36.43683}, + {-113.10894, 61.43199}, + {-39.88245, 68.00825}, + {2., 46.7}, + {-178., -46.7}, + {-148.83443, -27.31067}, + {-129.26346, -3.837}, + {-110.79116, 20.05422}, + {-85.87917, 41.36507}, + {-44.42496, 53.29508}, + {2., 46.7}, + {-178., -46.7}, + {-137.90794, -39.07002}, + {-109.60146, -21.33906}, + {-88., 0.}, + {-66.39854, 21.33906}, + {-38.09206, 39.07002}, + {2., 46.7}, + {-178., -46.7}, + {-131.57504, -53.29508}, + {-90.12083, -41.36507}, + {-65.20884, -20.05422}, + {-46.73654, 3.837}, + {-27.16557, 27.31067}, + {2., 46.7}, + {-178., -46.7}, + {-136.11755, -68.00825}, + {-62.89106, -61.43199}, + {-36.42536, -36.43683}, + {-23.97634, -8.65459}, + {-13.37657, 19.46929}, + {2., 46.7}, + {-178., -46.7}, + {-178., -76.7}, + {2., -73.3}, + {2., -43.3}, + {2., -13.3}, + {2., 16.7}, + {2., 46.7}, + {-178., -46.7}, + {140.11755, -68.00825}, + {66.89106, -61.43199}, + {40.42536, -36.43683}, + {27.97634, -8.65459}, + {17.37657, 19.46929}, + {2., 46.7}, + {-178., -46.7}, + {135.57504, -53.29508}, + {94.12083, -41.36507}, + {69.20884, -20.05422}, + {50.73654, 3.837}, + {31.16557, 27.31067}, + {2., 46.7}, + {-178., -46.7}, + {141.90794, -39.07002}, + {113.60146, -21.33906}, + {92., 0.}, + {70.39854, 21.33906}, + {42.09206, 39.07002}, + {2., 46.7}, + {-178., -46.7}, + {152.83443, -27.31067}, + {133.26346, -3.837}, + {114.79116, 20.05422}, + {89.87917, 41.36507}, + {48.42496, 53.29508}, + {2., 46.7}, + {-178., -46.7}, + {166.62343, -19.46929}, + {156.02366, 8.65459}, + {143.57464, 36.43683}, + {117.10894, 61.43199}, + {43.88245, 68.00825}, + {2., 46.7}, }; for (int i = 0, k = 0; i < Ni; i++) { for (int j = 0; j < 2 * Nj + 1; j++, k++) { - PointLatLon a(static_cast(j - Nj) * 90. / static_cast(Nj), - static_cast(i) * 360. / static_cast(Ni)); + PointLonLat a(static_cast(i) * 360. / static_cast(Ni), + static_cast(j - Nj) * 90. / static_cast(Nj)); auto b = rot.fwd(a); EXPECT(Point(b) == ref[k]); EXPECT(Point(a) == rot.inv(b)); @@ -143,7 +141,6 @@ int main(int argc, char* argv[]) { } } - { const Rotation unrotated(-90., 0., 0.); const Rotation angle_only(-90., 0., -180.); @@ -153,25 +150,25 @@ int main(int argc, char* argv[]) { EXPECT(angle_only.rotated()); EXPECT(rotation.rotated()); - const PointLatLon p[] = {{90., 0.}, {0., 0.}, {25., 270.}, {45., -180.}}; + const PointLonLat p[] = {{0., 90.}, {0., 0.}, {270., 25.}, {-180., 45.}}; struct { const Rotation& rotation; - const PointLatLon a; - const PointLatLon b; + const PointLonLat a; + const PointLonLat b; } tests[] = { {unrotated, p[0], p[0]}, {unrotated, p[1], p[1]}, {unrotated, p[2], p[2]}, {unrotated, p[3], p[3]}, - {angle_only, p[0], {p[0].lat, p[0].lon - 180.}}, - {angle_only, p[1], {p[1].lat, p[1].lon - 180.}}, - {angle_only, p[2], {p[2].lat, p[2].lon - 180.}}, - {angle_only, p[3], {p[3].lat, p[3].lon - 180.}}, - {rotation, p[0], {40., -176.}}, - {rotation, p[1], {-50., -176.}}, - {rotation, p[2], {15.762700, 113.657357}}, - {rotation, p[3], {85., -176.}}, + {angle_only, p[0], {p[0].lon - 180., p[0].lat}}, + {angle_only, p[1], {p[1].lon - 180., p[1].lat}}, + {angle_only, p[2], {p[2].lon - 180., p[2].lat}}, + {angle_only, p[3], {p[3].lon - 180., p[3].lat}}, + {rotation, p[0], {-176., 40.}}, + {rotation, p[1], {-176., -50.}}, + {rotation, p[2], {113.657357, 15.762700}}, + {rotation, p[3], {-176., 85.}}, }; for (const auto& test : tests) { diff --git a/tests/geo/test_types.cc b/tests/geo/test_types.cc index a8490a156..59d2ec27e 100644 --- a/tests/geo/test_types.cc +++ b/tests/geo/test_types.cc @@ -12,43 +12,48 @@ #include -#include "grit/test.h" -#include "grit/types.h" -#include "grit/types/MatrixXYZ.h" +#include "eckit/geo/types.h" +#include "eckit/maths/Matrix3.h" +#include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using grit::Point; - using grit::PointLatLon; + using eckit::geo::Point; + using eckit::geo::PointLonLat; - PointLatLon p(90., 1); + PointLonLat p(1, 90.); std::cout << "p: " << p << std::endl; - std::cout << "p: " << PointLatLon::make(p.lat, p.lon) << std::endl; - std::cout << "p: " << (Point(p) == PointLatLon(90., 50.)) << std::endl; + std::cout << "p: " << PointLonLat::make(p.lon, p.lat) << std::endl; + std::cout << "p: " << (Point(p) == PointLonLat(50., 90.)) << std::endl; - PointLatLon q(-90., 1.); + PointLonLat q(1., -90.); std::cout << "q: " << q << std::endl; std::cout << "~q: " << q.antipode() << std::endl; std::cout << "~~q: " << q.antipode().antipode() << std::endl; - auto r(PointLatLon::make(-91., -10.)); + auto r(PointLonLat::make(-10., -91.)); EXPECT(Point(r) == r.antipode().antipode()); - Point a1 = PointLatLon{-30, 300}; - Point a2 = PointLatLon{-30.000000000000018, -59.99999999999996}; + Point a1 = PointLonLat{300, -30}; + Point a2 = PointLonLat{-59.99999999999996, -30.000000000000018}; EXPECT(a1 == a2); - Point b1 = PointLatLon{-46.7, -178.}; - Point b2 = PointLatLon{-46.7, -178.00000000000003}; + Point b1 = PointLonLat{-178., -46.7}; + Point b2 = PointLonLat{-178.00000000000003, -46.7}; EXPECT(b1 == b2); - { - using MatrixXYZ = grit::types::MatrixXYZ; - MatrixXYZ M{1, 2, 3, // - 4, 5, 6, // - 7, 8, 1}; + using Matrix3 = eckit::maths::Matrix3; + Matrix3 M{1, + 2, + 3, // + 4, + 5, + 6, // + 7, + 8, + 1}; const auto W = M.inverse(); std::cout << "M M^-1=" << (M * W) << std::endl; std::cout << "M^-1 M=" << (W * M) << std::endl; diff --git a/tests/geo/test_util.cc b/tests/geo/test_util.cc index edbd8dfe6..383df4315 100644 --- a/tests/geo/test_util.cc +++ b/tests/geo/test_util.cc @@ -11,8 +11,9 @@ #include +#include -#include "grit/util.h" +#include "eckit/geo/util.h" template @@ -51,7 +52,6 @@ struct iterator_t { class iterable_t : public std::vector { - using iterator = iterator_t; using const_iterator = iterator_t; @@ -68,24 +68,26 @@ class iterable_t : public std::vector { int main(int argc, char* argv[]) { + using namespace eckit::geo::util; + #if 0 - std::cout << grit::util::linspace(1, 2, 2, true) << std::endl; - std::cout << grit::util::arange(1, 2, 0.5) << std::endl; - std::cout << grit::util::gaussian_latitudes(64, false) << std::endl; - std::cout << grit::util::normalise_longitude_to_maximum(0., 360.) << std::endl; - std::cout << grit::util::normalise_longitude_to_minimum(0., -360.) << std::endl; -#elif 0 - std::cout << grit::util::reduced_classical_pl(16) << std::endl; - std::cout << grit::util::reduced_classical_pl(16) << std::endl; - std::cout << grit::util::reduced_octahedral_pl(16) << std::endl; - std::cout << grit::util::reduced_octahedral_pl(16) << std::endl; + std::cout << linspace(1, 2, 2, true) << std::endl; + std::cout << arange(1, 2, 0.5) << std::endl; + std::cout << gaussian_latitudes(64, false) << std::endl; + std::cout << normalise_longitude_to_maximum(0., 360.) << std::endl; + std::cout << normalise_longitude_to_minimum(0., -360.) << std::endl; +#elif 1 + std::cout << reduced_classical_pl(16) << std::endl; + std::cout << reduced_classical_pl(16) << std::endl; + std::cout << reduced_octahedral_pl(16) << std::endl; + std::cout << reduced_octahedral_pl(16) << std::endl; #elif 0 std::vector values1{1., 2., 3., 4., 5., 6.}; std::vector values2{6., 5., 4., 3., 2., 1.}; - std::cout << grit::util::monotonic_crop({1.}, 1., 1., 0.) << std::endl; - std::cout << grit::util::monotonic_crop({1., 1., 1.}, 1., 2., 0.) << std::endl; - std::cout << grit::util::monotonic_crop(values1, 2., 3., 0.) << std::endl; - std::cout << grit::util::monotonic_crop(values2, 2., 3., 0.) << std::endl; + std::cout << monotonic_crop({1.}, 1., 1., 0.) << std::endl; + std::cout << monotonic_crop({1., 1., 1.}, 1., 2., 0.) << std::endl; + std::cout << monotonic_crop(values1, 2., 3., 0.) << std::endl; + std::cout << monotonic_crop(values2, 2., 3., 0.) << std::endl; #endif } From 219e2d5c83f020b126d8f9a22a1a2f897d89bc32 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 11 May 2023 12:29:22 +0100 Subject: [PATCH 205/737] eckit::geo GRIB testing (just for prototyping) --- CMakeLists.txt | 3 +++ tests/geo/CMakeLists.txt | 12 +++++++----- tests/geo/test_grib.cc | 27 ++++++++++++--------------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a1487e8ed..8f64cd245 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -243,6 +243,9 @@ ecbuild_add_option( FEATURE PROJ DEFAULT OFF DESCRIPTION "support PROJ-based projections") +### ecCodes +ecbuild_add_option( FEATURE ECCODES REQUIRED_PACKAGES eccodes DESCRIPTION "FIXME: remove" ) + ### c math library, needed when including "math.h" find_package( CMath ) diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 65a3eb217..3f9716ead 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -1,5 +1,4 @@ foreach( _test - #grib iterator param projection @@ -14,9 +13,12 @@ foreach( _test TARGET eckit_test_geo_${_test} SOURCES test_${_test}.cc LIBS eckit_geo ) +endforeach() +if(HAVE_ECCODES) + ecbuild_add_test( + TARGET eckit_test_geo_grib + SOURCES test_grib.cc + LIBS eckit_geo eccodes) +endif() - - - -endforeach() diff --git a/tests/geo/test_grib.cc b/tests/geo/test_grib.cc index 9ff138bbd..c9f960925 100644 --- a/tests/geo/test_grib.cc +++ b/tests/geo/test_grib.cc @@ -21,7 +21,6 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Parametrisation.h" -#include "eckit/geo/grit.h" #include "eckit/geo/param/Map.h" #include "eckit/geo/types.h" @@ -43,39 +42,39 @@ #if 0 -grit::Figure* make_figure(long code) { +eckit::geo::Figure* make_figure(long code) { // Code table 3.2 – Shape of the reference system switch (code) { case 0: - return new grit::figure::Sphere(6367470.); + return new eckit::geo::figure::Sphere(6367470.); case 1: // Earth assumed spherical with radius specified (in m) by data producer NOTIMP; case 2: - return new grit::figure::Spheroid(6378160., 6356775.); + return new eckit::geo::figure::Spheroid(6378160., 6356775.); case 3: // Earth assumed oblate spheroid with major and minor axes specified (in km) by data producer NOTIMP; case 4: - return new grit::figure::Spheroid(6378137., 6356752.314); + return new eckit::geo::figure::Spheroid(6378137., 6356752.314); case 5: - return new grit::figure::Spheroid(6378137., 6356752.314140347); + return new eckit::geo::figure::Spheroid(6378137., 6356752.314140347); case 6: - return new grit::figure::Sphere(6371229.); + return new eckit::geo::figure::Sphere(6371229.); case 7: // Earth assumed oblate spheroid with major or minor axes specified (in m) by data producer NOTIMP; case 8: - return new grit::figure::Sphere(6371200.); + return new eckit::geo::figure::Sphere(6371200.); case 9: - return new grit::figure::Spheroid(6377563.396, 6356256.909); + return new eckit::geo::figure::Spheroid(6377563.396, 6356256.909); case 10: // Earth model assumed WGS84 with corrected geomagnetic coordinates (latitude and longitude) defined by // Gustafsson et al., 1992 NOTIMP; case 11: - return new grit::figure::Sphere(695990000.); + return new eckit::geo::figure::Sphere(695990000.); default: NOTIMP; } @@ -83,7 +82,7 @@ grit::Figure* make_figure(long code) { #endif -class GribParametrisation final : public grit::Parametrisation, +class GribParametrisation final : public eckit::geo::Parametrisation, std::unique_ptr { private: // -- Types @@ -316,7 +315,7 @@ class GribParametrisation final : public grit::Parametrisation, private: // -- Members - mutable grit::param::Map cache_; + mutable eckit::geo::param::Map cache_; // -- Methods // None @@ -385,8 +384,6 @@ std::ostream& operator<<(std::ostream& out, const std::vector& vec) { int main(int argc, const char* argv[]) { - - for (int i = 1; i < argc; ++i) { auto* in = std::fopen(argv[i], "rb"); ASSERT(in != nullptr && "unable to open file"); @@ -408,7 +405,7 @@ int main(int argc, const char* argv[]) { std::cout << "type: '" << type << "'" << std::endl; if (grib.has("pl")) { - std::cout << "pl: '" << grib.get("pl") << "'" << std::endl; + std::cout << "pl: '" << grib.get("pl") << "'" << std::endl; } if (type == "regular_ll") { From 59c10a8e9edf2dba4d9499299c7fc709afc6ec24 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 11 May 2023 14:34:54 +0100 Subject: [PATCH 206/737] eckit::MappedConfiguration --- src/eckit/CMakeLists.txt | 2 + src/eckit/config/MappedConfiguration.cc | 227 ++++++++++++++++++++++++ src/eckit/config/MappedConfiguration.h | 136 ++++++++++++++ src/eckit/geo/CMakeLists.txt | 4 - src/eckit/geo/Parametrisation.cc | 115 ------------ src/eckit/geo/Parametrisation.h | 135 -------------- src/eckit/geo/Projection.cc | 2 +- src/eckit/geo/Projection.h | 10 +- src/eckit/geo/param/Map.cc | 204 --------------------- src/eckit/geo/param/Map.h | 120 ------------- src/eckit/geo/projection/LonLatToXYZ.cc | 8 +- src/eckit/geo/projection/LonLatToXYZ.h | 2 +- src/eckit/geo/projection/None.cc | 2 +- src/eckit/geo/projection/None.h | 2 +- src/eckit/geo/projection/PROJ.cc | 10 +- src/eckit/geo/projection/PROJ.h | 2 +- src/eckit/geo/projection/Rotation.cc | 8 +- src/eckit/geo/projection/Rotation.h | 2 +- tests/geo/test_grib.cc | 109 ++++++------ tests/geo/test_param.cc | 8 +- tests/geo/test_projection.cc | 27 ++- tests/geo/test_projection_proj.cc | 8 +- 22 files changed, 460 insertions(+), 683 deletions(-) create mode 100644 src/eckit/config/MappedConfiguration.cc create mode 100644 src/eckit/config/MappedConfiguration.h delete mode 100644 src/eckit/geo/Parametrisation.cc delete mode 100644 src/eckit/geo/Parametrisation.h delete mode 100644 src/eckit/geo/param/Map.cc delete mode 100644 src/eckit/geo/param/Map.h diff --git a/src/eckit/CMakeLists.txt b/src/eckit/CMakeLists.txt index f4df7002a..f75f49c5e 100644 --- a/src/eckit/CMakeLists.txt +++ b/src/eckit/CMakeLists.txt @@ -354,6 +354,8 @@ config/LibEcKit.cc config/LibEcKit.h config/LocalConfiguration.cc config/LocalConfiguration.h +config/MappedConfiguration.cc +config/MappedConfiguration.h config/Parametrisation.cc config/Parametrisation.h config/Resource.h diff --git a/src/eckit/config/MappedConfiguration.cc b/src/eckit/config/MappedConfiguration.cc new file mode 100644 index 000000000..fe2d8f3fd --- /dev/null +++ b/src/eckit/config/MappedConfiguration.cc @@ -0,0 +1,227 @@ +/* + * (C) Copyright 1996- 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 "eckit/config/MappedConfiguration.h" + +#include + +#include "eckit/value/Value.h" + +namespace eckit { + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace { + + +const eckit::Value __empty_root{}; + + +template +bool __get(const MappedConfiguration::container_type& map, const std::string& name, T& value) { + if (auto it = map.find(name); it != map.cend()) { + value = std::get(it->second); + return true; + } + return false; +} + + +std::ostream& operator<<(std::ostream& out, const MappedConfiguration::value_type& v) { + std::visit([&](auto&& arg) { out << arg; }, v); + return out; +} + + +} // namespace + + +MappedConfiguration::MappedConfiguration(const MappedConfiguration::container_type& map) : + Configuration(__empty_root), + map_(map) {} + + +MappedConfiguration::MappedConfiguration(container_type&& map) : + Configuration(__empty_root), + map_(map) {} + + +void MappedConfiguration::set(const std::string& name, std::string& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, bool& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, int& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, long& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, long long& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, std::size_t& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, float& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, double& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, std::vector& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, std::vector& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, std::vector& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, std::vector& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, std::vector& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, std::vector& value) { + map_[name] = value; +} + + +void MappedConfiguration::set(const std::string& name, std::vector& value) { + map_[name] = value; +} + + +bool MappedConfiguration::has(const std::string& name) const { + return map_.find(name) != map_.cend(); +} + + +bool MappedConfiguration::get(const std::string& name, std::string& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, bool& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, int& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, long& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, long long& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, std::size_t& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, float& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, double& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, std::vector& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, std::vector& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, std::vector& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, std::vector& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, std::vector& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, std::vector& value) const { + return __get(map_, name, value); +} + + +bool MappedConfiguration::get(const std::string& name, std::vector& value) const { + return __get(map_, name, value); +} + + +void MappedConfiguration::print(std::ostream& out) const { + out << "MappedConfiguration["; + + const auto* sep = ""; + for (const auto& nv : map_) { + out << sep << nv.first << ": " << nv.second; + sep = ", "; + } + + out << "]"; +} + + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit diff --git a/src/eckit/config/MappedConfiguration.h b/src/eckit/config/MappedConfiguration.h new file mode 100644 index 000000000..f4881a288 --- /dev/null +++ b/src/eckit/config/MappedConfiguration.h @@ -0,0 +1,136 @@ +/* + * (C) Copyright 1996- 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. + */ + +#ifndef eckit_MappedConfiguration_H +#define eckit_MappedConfiguration_H + +#include +#include + +#include "eckit/config/Configuration.h" + +namespace eckit { + +//---------------------------------------------------------------------------------------------------------------------- + +class MappedConfiguration : public Configuration { +public: + // -- Types + + using value_type = std::variant< + std::string, + bool, + int, + long, + long long, + std::size_t, + float, + double, + std::vector, + std::vector, + std::vector, + std::vector, + std::vector, + std::vector, + std::vector>; + + using container_type = std::map; + + // -- Exceptions + // None + + // -- Constructors + + explicit MappedConfiguration(const container_type& = {}); + explicit MappedConfiguration(container_type&&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + void set(const std::string&, std::string&); + void set(const std::string&, bool&); + void set(const std::string&, int&); + void set(const std::string&, long&); + void set(const std::string&, long long&); + void set(const std::string&, std::size_t&); + void set(const std::string&, float&); + void set(const std::string&, double&); + + void set(const std::string&, std::vector&); + void set(const std::string&, std::vector&); + void set(const std::string&, std::vector&); + void set(const std::string&, std::vector&); + void set(const std::string&, std::vector&); + void set(const std::string&, std::vector&); + void set(const std::string&, std::vector&); + + // -- Overridden methods + + bool has(const std::string&) const override; + + bool get(const std::string&, std::string&) const override; + bool get(const std::string&, bool&) const override; + bool get(const std::string&, int&) const override; + bool get(const std::string&, long&) const override; + bool get(const std::string&, long long&) const override; + bool get(const std::string&, std::size_t&) const override; + bool get(const std::string&, float&) const override; + bool get(const std::string&, double&) const override; + + bool get(const std::string&, std::vector&) const override; + bool get(const std::string&, std::vector&) const override; + bool get(const std::string&, std::vector&) const override; + bool get(const std::string&, std::vector&) const override; + bool get(const std::string&, std::vector&) const override; + bool get(const std::string&, std::vector&) const override; + bool get(const std::string&, std::vector&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + container_type map_; + + // -- Methods + // None + + // -- Overridden methods + + void print(std::ostream&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit + +#endif diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 46b9d2bb5..210556d41 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -2,8 +2,6 @@ list(APPEND eckit_geo_srcs BoundingBox.cc BoundingBox.h Iterator.h - Parametrisation.cc - Parametrisation.h Projection.cc Projection.h Scanner.cc @@ -12,8 +10,6 @@ list(APPEND eckit_geo_srcs iterator/IteratorAggregator.h iterator/IteratorComposer.cc iterator/IteratorComposer.h - param/Map.cc - param/Map.h projection/LonLatToXYZ.cc projection/LonLatToXYZ.h projection/None.cc diff --git a/src/eckit/geo/Parametrisation.cc b/src/eckit/geo/Parametrisation.cc deleted file mode 100644 index 151781d8c..000000000 --- a/src/eckit/geo/Parametrisation.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/Parametrisation.h" - -#include "eckit/exception/Exceptions.h" - - -namespace eckit::geo { - - -namespace { - - -template -T __get(const Parametrisation& param, const Parametrisation::key_type& key) { - auto value = T(); - ASSERT(param.get(key, value)); - return value; -} - - -} // namespace - - -bool Parametrisation::get_bool(const Parametrisation::key_type& key) const { - return __get(*this, key); -} - - -int Parametrisation::get_int(const Parametrisation::key_type& key) const { - return __get(*this, key); -} - - -unsigned int Parametrisation::get_unsigned_int(const Parametrisation::key_type& key) const { - return __get(*this, key); -} - - -long Parametrisation::get_long(const Parametrisation::key_type& key) const { - return __get(*this, key); -} - - -unsigned long Parametrisation::get_unsigned_long(const Parametrisation::key_type& key) const { - return __get(*this, key); -} - - -float Parametrisation::get_float(const Parametrisation::key_type& key) const { - return __get(*this, key); -} - - -double Parametrisation::get_double(const Parametrisation::key_type& key) const { - return __get(*this, key); -} - - -std::string Parametrisation::get_string(const Parametrisation::key_type& key) const { - return __get(*this, key); -} - - -std::vector Parametrisation::get_vector_bool(const Parametrisation::key_type& key) const { - return __get>(*this, key); -} - - -std::vector Parametrisation::get_vector_int(const Parametrisation::key_type& key) const { - return __get>(*this, key); -} - - -std::vector Parametrisation::get_vector_unsigned_int(const Parametrisation::key_type& key) const { - return __get>(*this, key); -} - - -std::vector Parametrisation::get_vector_long(const Parametrisation::key_type& key) const { - return __get>(*this, key); -} - - -std::vector Parametrisation::get_vector_unsigned_long(const Parametrisation::key_type& key) const { - return __get>(*this, key); -} - - -std::vector Parametrisation::get_vector_float(const Parametrisation::key_type& key) const { - return __get>(*this, key); -} - - -std::vector Parametrisation::get_vector_double(const Parametrisation::key_type& key) const { - return __get>(*this, key); -} - - -std::vector Parametrisation::get_vector_string(const Parametrisation::key_type& key) const { - return __get>(*this, key); -} - - -}; // namespace eckit::geo diff --git a/src/eckit/geo/Parametrisation.h b/src/eckit/geo/Parametrisation.h deleted file mode 100644 index 6552f7803..000000000 --- a/src/eckit/geo/Parametrisation.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include - - -namespace eckit::geo { - - -class Parametrisation { -public: - // -- Types - - using key_type = std::string; - - // -- Exceptions - // None - - // -- Constructors - - Parametrisation() = default; - Parametrisation(const Parametrisation&) = delete; - Parametrisation(Parametrisation&&) = delete; - - // -- Destructor - - virtual ~Parametrisation() = default; - - // -- Convertors - // None - - // -- Operators - - Parametrisation& operator=(const Parametrisation&) = delete; - Parametrisation& operator=(Parametrisation&&) = delete; - - // -- Methods - - virtual bool has(const key_type&) const = 0; - - virtual bool get(const key_type&, bool&) const = 0; - virtual bool get(const key_type&, int&) const = 0; - virtual bool get(const key_type&, unsigned int&) const = 0; - virtual bool get(const key_type&, long&) const = 0; - virtual bool get(const key_type&, unsigned long&) const = 0; - virtual bool get(const key_type&, float&) const = 0; - virtual bool get(const key_type&, double&) const = 0; - virtual bool get(const key_type&, std::string&) const = 0; - - virtual bool get(const key_type&, std::vector&) const = 0; - virtual bool get(const key_type&, std::vector&) const = 0; - virtual bool get(const key_type&, std::vector&) const = 0; - virtual bool get(const key_type&, std::vector&) const = 0; - virtual bool get(const key_type&, std::vector&) const = 0; - virtual bool get(const key_type&, std::vector&) const = 0; - virtual bool get(const key_type&, std::vector&) const = 0; - virtual bool get(const key_type&, std::vector&) const = 0; - - bool get_bool(const key_type&) const; - int get_int(const key_type&) const; - unsigned int get_unsigned_int(const key_type&) const; - long get_long(const key_type&) const; - unsigned long get_unsigned_long(const key_type&) const; - float get_float(const key_type&) const; - double get_double(const key_type&) const; - std::string get_string(const key_type&) const; - - std::vector get_vector_bool(const key_type&) const; - std::vector get_vector_int(const key_type&) const; - std::vector get_vector_unsigned_int(const key_type&) const; - std::vector get_vector_long(const key_type&) const; - std::vector get_vector_unsigned_long(const key_type&) const; - std::vector get_vector_float(const key_type&) const; - std::vector get_vector_double(const key_type&) const; - std::vector get_vector_string(const key_type&) const; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index af623db03..a2af5a901 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -230,7 +230,7 @@ static void __init() { Projection* ProjectionFactory::build(const ProjectionFactory::key_type& key, - const Parametrisation& param) { + const Configuration& param) { pthread_once(&__once, __init); AutoLock lock(*__mutex); diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 7c02d9f96..cbf004280 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -18,8 +18,8 @@ #include "eckit/geo/types.h" -namespace eckit::geo { -class Parametrisation; +namespace eckit { +class Configuration; } @@ -107,7 +107,7 @@ class Projection { struct ProjectionFactory { using key_type = std::string; - static Projection* build(const key_type&, const Parametrisation&); + static Projection* build(const key_type&, const Configuration&); static std::ostream& list(std::ostream&); ProjectionFactory(const ProjectionFactory&) = delete; @@ -115,7 +115,7 @@ struct ProjectionFactory { ProjectionFactory& operator=(const ProjectionFactory&) = delete; ProjectionFactory& operator=(ProjectionFactory&&) = delete; - virtual Projection* make(const Parametrisation&) = 0; + virtual Projection* make(const Configuration&) = 0; protected: explicit ProjectionFactory(const key_type&); @@ -128,7 +128,7 @@ struct ProjectionFactory { template class ProjectionBuilder final : public ProjectionFactory { - Projection* make(const Parametrisation& param) override { return new T(param); } + Projection* make(const Configuration& param) override { return new T(param); } public: explicit ProjectionBuilder(const ProjectionFactory::key_type& key) : diff --git a/src/eckit/geo/param/Map.cc b/src/eckit/geo/param/Map.cc deleted file mode 100644 index 0b85928d1..000000000 --- a/src/eckit/geo/param/Map.cc +++ /dev/null @@ -1,204 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/param/Map.h" - -#include - -#include "eckit/exception/Exceptions.h" - - -namespace eckit::geo::param { - - -Map::Map(const container_type& other) : - map_(other) {} - - -bool Map::has(const key_type& key) const { - return map_.find(key) != map_.end(); -} - - -template -bool __get(const Map::container_type& map, std::size_t idx, const Map::key_type& key, T& value) { - if (auto it = map.find(key); it != map.end()) { - ASSERT(it->second.index() == idx); - value = std::get(it->second); - return true; - } - - return false; -} - - -void Map::set(const key_type& key, const bool& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const int& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const unsigned int& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const long& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const unsigned long& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const float& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const double& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const std::string& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const std::vector& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const std::vector& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const std::vector& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const std::vector& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const std::vector& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const std::vector& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const std::vector& value) { - map_[key] = value; -} - - -void Map::set(const key_type& key, const std::vector& value) { - map_[key] = value; -} - - -bool Map::get(const key_type& key, bool& value) const { - return __get(map_, 0, key, value); -} - - -bool Map::get(const key_type& key, int& value) const { - return __get(map_, 1, key, value); -} - - -bool Map::get(const key_type& key, unsigned int& value) const { - return __get(map_, 2, key, value); -} - - -bool Map::get(const key_type& key, long& value) const { - return __get(map_, 3, key, value); -} - - -bool Map::get(const key_type& key, unsigned long& value) const { - return __get(map_, 4, key, value); -} - - -bool Map::get(const key_type& key, float& value) const { - return __get(map_, 5, key, value); -} - - -bool Map::get(const key_type& key, double& value) const { - return __get(map_, 6, key, value); -} - - -bool Map::get(const key_type& key, std::string& value) const { - return __get(map_, 7, key, value); -} - - -bool Map::get(const key_type& key, std::vector& value) const { - return __get>(map_, 8, key, value); -} - - -bool Map::get(const key_type& key, std::vector& value) const { - return __get>(map_, 9, key, value); -} - - -bool Map::get(const key_type& key, std::vector& value) const { - return __get>(map_, 0, key, value); -} - - -bool Map::get(const key_type& key, std::vector& value) const { - return __get>(map_, 11, key, value); -} - - -bool Map::get(const key_type& key, std::vector& value) const { - return __get>(map_, 12, key, value); -} - - -bool Map::get(const key_type& key, std::vector& value) const { - return __get>(map_, 13, key, value); -} - - -bool Map::get(const key_type& key, std::vector& value) const { - return __get>(map_, 14, key, value); -} - - -bool Map::get(const key_type& key, std::vector& value) const { - return __get>(map_, 15, key, value); -} - - -} // namespace eckit::geo::param diff --git a/src/eckit/geo/param/Map.h b/src/eckit/geo/param/Map.h deleted file mode 100644 index 5e6c3323f..000000000 --- a/src/eckit/geo/param/Map.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include - -#include "eckit/geo/Parametrisation.h" - - -namespace eckit::geo::param { - - -class Map final : public Parametrisation { -public: - // -- Types - - using value_type = std::variant, - std::vector, std::vector, std::vector, std::vector, - std::vector, std::vector, std::vector>; - - using container_type = std::map; - - // -- Exceptions - // None - - // -- Constructors - - explicit Map(const container_type& = {}); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - void set(const key_type&, const bool&); - void set(const key_type&, const int&); - void set(const key_type&, const unsigned int&); - void set(const key_type&, const long&); - void set(const key_type&, const unsigned long&); - void set(const key_type&, const float&); - void set(const key_type&, const double&); - void set(const key_type&, const std::string&); - - void set(const key_type&, const std::vector&); - void set(const key_type&, const std::vector&); - void set(const key_type&, const std::vector&); - void set(const key_type&, const std::vector&); - void set(const key_type&, const std::vector&); - void set(const key_type&, const std::vector&); - void set(const key_type&, const std::vector&); - void set(const key_type&, const std::vector&); - - // -- Overridden methods - - bool has(const key_type&) const override; - - bool get(const key_type&, bool&) const override; - bool get(const key_type&, int&) const override; - bool get(const key_type&, unsigned int&) const override; - bool get(const key_type&, long&) const override; - bool get(const key_type&, unsigned long&) const override; - bool get(const key_type&, float&) const override; - bool get(const key_type&, double&) const override; - bool get(const key_type&, std::string&) const override; - - bool get(const key_type&, std::vector&) const override; - bool get(const key_type&, std::vector&) const override; - bool get(const key_type&, std::vector&) const override; - bool get(const key_type&, std::vector&) const override; - bool get(const key_type&, std::vector&) const override; - bool get(const key_type&, std::vector&) const override; - bool get(const key_type&, std::vector&) const override; - bool get(const key_type&, std::vector&) const override; - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - container_type map_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::param diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc index c38df926a..eb2d9c7be 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -12,7 +12,7 @@ #include "eckit/geo/projection/LonLatToXYZ.h" -#include "eckit/geo/Parametrisation.h" +#include "eckit/config/Configuration.h" #include "eckit/geo/util.h" #include "eckit/geometry/EllipsoidOfRevolution.h" #include "eckit/geometry/Sphere.h" @@ -64,9 +64,9 @@ LonLatToXYZ::LonLatToXYZ(double R) : LonLatToXYZ(R, R) {} -LonLatToXYZ::LonLatToXYZ(const Parametrisation& param) : - LonLatToXYZ(param.has("R") ? param.get_double("R") : param.get_double("a"), - param.has("R") ? param.get_double("R") : param.get_double("b")) {} +LonLatToXYZ::LonLatToXYZ(const Configuration& param) : + LonLatToXYZ(param.getDouble("R", param.getDouble("a")), + param.getDouble("R", param.getDouble("b"))) {} } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LonLatToXYZ.h b/src/eckit/geo/projection/LonLatToXYZ.h index b8f18b4df..c47061fd0 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.h +++ b/src/eckit/geo/projection/LonLatToXYZ.h @@ -30,7 +30,7 @@ class LonLatToXYZ final : public Projection { LonLatToXYZ(double a, double b); explicit LonLatToXYZ(double R); - explicit LonLatToXYZ(const Parametrisation&); + explicit LonLatToXYZ(const Configuration&); // -- Destructor // None diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index 1ec7f9193..e7847db5f 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -20,7 +20,7 @@ static ProjectionBuilder __projection1(""); static ProjectionBuilder __projection2("none"); -None::None(const Parametrisation&) {} +None::None(const Configuration&) {} } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index f7ecbb8ee..1a9fc3ff5 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -29,7 +29,7 @@ class None final : public Projection { // -- Constructors None() = default; - explicit None(const Parametrisation&); + explicit None(const Configuration&); // -- Destructor // None diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 93feb9c3c..38ee50dd0 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -12,8 +12,8 @@ #include "eckit/geo/projection/PROJ.h" +#include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Parametrisation.h" #include "eckit/geo/types.h" @@ -91,10 +91,10 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini } -PROJ::PROJ(const Parametrisation& param) : - PROJ(param.has("source") ? param.get_string("source") : "EPSG:4326", // default to WGS 84 - param.has("target") ? param.get_string("target") : "EPSG:4326", // ... - param.has("lon_minimum") ? param.get_double("lon_minimum") : 0) {} +PROJ::PROJ(const Configuration& param) : + PROJ(param.getString("source", "EPSG:4326"), // default to WGS 84 + param.getString("target", "EPSG:4326"), // ... + param.getDouble("lon_minimum", 0)) {} std::string PROJ::ellipsoid(const std::string& string) { diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index 2f1d1dbd2..fe87a74c2 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -60,7 +60,7 @@ class PROJ final : public Projection { // -- Constructors PROJ(const std::string& source, const std::string& target, double lon_minimum = 0.); - explicit PROJ(const Parametrisation&); + explicit PROJ(const Configuration&); // -- Destructor // None diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 6d3bda0f9..d429c89d7 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -15,7 +15,7 @@ #include #include -#include "eckit/geo/Parametrisation.h" +#include "eckit/config/Configuration.h" #include "eckit/geo/util.h" #include "eckit/geometry/UnitSphere.h" #include "eckit/maths/Matrix3.h" @@ -94,9 +94,9 @@ Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : } -Rotation::Rotation(const Parametrisation& param) : - Rotation(param.get_double("south_pole_lat"), param.get_double("south_pole_lon"), - param.has("angle") ? param.get_double("angle") : 0) {} +Rotation::Rotation(const Configuration& param) : + Rotation(param.getDouble("south_pole_lat"), param.getDouble("south_pole_lon"), + param.getDouble("angle", 0)) {} } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index 9e971985e..a9ccd9229 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -29,7 +29,7 @@ class Rotation final : public Projection { // -- Constructors Rotation(double south_pole_lat, double south_pole_lon, double angle); - explicit Rotation(const Parametrisation&); + explicit Rotation(const Configuration&); // -- Destructor // None diff --git a/tests/geo/test_grib.cc b/tests/geo/test_grib.cc index c9f960925..cb4f14e58 100644 --- a/tests/geo/test_grib.cc +++ b/tests/geo/test_grib.cc @@ -15,14 +15,16 @@ #include #include #include +#include #include #include #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Parametrisation.h" -#include "eckit/geo/param/Map.h" +// #include "eckit/config/Configuration.h" +#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/types.h" +#include "eckit/value/Value.h" #if 0 @@ -82,20 +84,43 @@ eckit::geo::Figure* make_figure(long code) { #endif -class GribParametrisation final : public eckit::geo::Parametrisation, - std::unique_ptr { +// static eckit::Value v; +class Grib final : std::unique_ptr { private: // -- Types using t = std::unique_ptr; + using cache_key_type = std::string; + + using cache_value_type = std::variant, + std::vector, std::vector, std::vector, std::vector, + std::vector, std::vector, std::vector>; + + struct cache_type : protected std::map { + template + bool get(const key_type& key, T& value) const { + if (auto it = find(key); it != end()) { + value = std::get(it->second); + return true; + } + return false; + } + + template + void set(const key_type& key, T& value) { + operator[](key) = value; + } + }; + public: // -- Exceptions // None // -- Constructors - explicit GribParametrisation(codes_handle* h) : + explicit Grib(codes_handle* h) : + // Configuration(v), t(h, &codes_handle_delete) { ASSERT(*this); } // -- Destructor @@ -110,7 +135,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, // -- Methods template - T get(const key_type& key) const { + T get(const cache_key_type& key) const { auto value = T(); ASSERT(get(key, value)); return value; @@ -118,9 +143,9 @@ class GribParametrisation final : public eckit::geo::Parametrisation, // -- Overridden methods - bool has(const key_type& key) const override { return 0 != codes_is_defined(t::get(), key.c_str()); } + bool has(const cache_key_type& key) const /*override*/ { return 0 != codes_is_defined(t::get(), key.c_str()); } - bool get(const key_type& key, bool& value) const override { + bool get(const cache_key_type& key, bool& value) const /*override*/ { if (long another = 0; get(key, another)) { value = another != 0; return true; @@ -129,7 +154,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, return false; } - bool get(const key_type& key, int& value) const override { + bool get(const cache_key_type& key, int& value) const /*override*/ { if (long another = 0; get(key, another)) { value = static_cast(another); return true; @@ -138,16 +163,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, return false; } - bool get(const key_type& key, unsigned int& value) const override { - if (long another = 0; get(key, another) && 0 <= another) { - value = static_cast(another); - return true; - } - - return false; - } - - bool get(const key_type& key, long& value) const override { + bool get(const cache_key_type& key, long& value) const /*override*/ { if (cache_.get(key, value)) { return true; } @@ -160,7 +176,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, return false; } - bool get(const key_type& key, unsigned long& value) const override { + bool get(const cache_key_type& key, unsigned long& value) const /*override*/ { if (long another = 0; get(key, another) && 0 <= another) { value = static_cast(another); return true; @@ -169,7 +185,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, return false; } - bool get(const key_type& key, float& value) const override { + bool get(const cache_key_type& key, float& value) const /*override*/ { if (double another = 0; get(key, another)) { value = static_cast(another); return true; @@ -178,7 +194,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, return false; } - bool get(const key_type& key, double& value) const override { + bool get(const cache_key_type& key, double& value) const /*override*/ { if (cache_.get(key, value)) { return true; } @@ -191,7 +207,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, return false; } - bool get(const key_type& key, std::string& value) const override { + bool get(const cache_key_type& key, std::string& value) const /*override*/ { if (cache_.get(key, value)) { return true; } @@ -206,17 +222,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, return false; } - bool get(const key_type& key, std::vector& value) const override { - if (std::vector another; get(key, another)) { - value.resize(another.size()); - std::transform(another.begin(), another.end(), value.begin(), [](long v) { return v != 0; }); - return true; - } - - return false; - } - - bool get(const key_type& key, std::vector& value) const override { + bool get(const cache_key_type& key, std::vector& value) const /*override*/ { if (std::vector another; get(key, another)) { value.resize(another.size()); std::transform(another.begin(), another.end(), value.begin(), [](long v) { return static_cast(v); }); @@ -226,20 +232,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, return false; } - bool get(const key_type& key, std::vector& value) const override { - if (std::vector another; get(key, another)) { - value.resize(another.size()); - std::transform(another.begin(), another.end(), value.begin(), [](long v) { - ASSERT(0 <= v); - return static_cast(v); - }); - return true; - } - - return false; - } - - bool get(const key_type& key, std::vector& value) const override { + bool get(const cache_key_type& key, std::vector& value) const /*override*/ { if (cache_.get(key, value)) { return true; } @@ -256,7 +249,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, return false; } - bool get(const key_type& key, std::vector& value) const override { + bool get(const cache_key_type& key, std::vector& value) const /*override*/ { if (std::vector another; get(key, another)) { value.resize(another.size()); std::transform(another.begin(), another.end(), value.begin(), [](long v) { @@ -269,7 +262,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, return false; } - bool get(const key_type& key, std::vector& value) const override { + bool get(const cache_key_type& key, std::vector& value) const /*override*/ { if (cache_.get(key, value)) { return true; } @@ -286,7 +279,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, return false; } - bool get(const key_type& key, std::vector& value) const override { + bool get(const cache_key_type& key, std::vector& value) const /*override*/ { if (cache_.get(key, value)) { return true; } @@ -303,7 +296,7 @@ class GribParametrisation final : public eckit::geo::Parametrisation, return false; } - bool get(const key_type& key, std::vector& value) const override { NOTIMP; } + bool get(const cache_key_type& key, std::vector& value) const /*override*/ { NOTIMP; } // -- Class members @@ -315,13 +308,14 @@ class GribParametrisation final : public eckit::geo::Parametrisation, private: // -- Members - mutable eckit::geo::param::Map cache_; + mutable cache_type cache_; // -- Methods // None // -- Overridden methods - // None + + void print(std::ostream&) const /*override*/ {} // -- Class members // None @@ -331,6 +325,8 @@ class GribParametrisation final : public eckit::geo::Parametrisation, // -- Friends // None +}; + #if 0 std::string type() const { return get_string("gridType"); } @@ -366,7 +362,6 @@ class GribParametrisation final : public eckit::geo::Parametrisation, double value = 0; }; #endif -}; template @@ -390,7 +385,7 @@ int main(int argc, const char* argv[]) { int err = 0; for (codes_handle* h = nullptr; nullptr != (h = codes_handle_new_from_file(nullptr, in, PRODUCT_GRIB, &err));) { - GribParametrisation grib(h); + Grib grib(h); #if 0 int n = 0; @@ -405,7 +400,7 @@ int main(int argc, const char* argv[]) { std::cout << "type: '" << type << "'" << std::endl; if (grib.has("pl")) { - std::cout << "pl: '" << grib.get("pl") << "'" << std::endl; + // std::cout << "pl: '" << grib.get("pl") << "'" << std::endl; } if (type == "regular_ll") { diff --git a/tests/geo/test_param.cc b/tests/geo/test_param.cc index 211c00cd7..01a092a14 100644 --- a/tests/geo/test_param.cc +++ b/tests/geo/test_param.cc @@ -13,13 +13,13 @@ #include #include -#include "eckit/geo/param/Map.h" +#include "eckit/config/MappedConfiguration.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - std::unique_ptr param( - new eckit::geo::param::Map({{"a", -123}, {"b", "B"}, {"c", 123UL}})); + std::unique_ptr param( + new eckit::MappedConfiguration({{"a", -123}, {"b", "B"}, {"c", 123UL}})); int a = 0; EXPECT(param->get("a", a)); @@ -34,7 +34,7 @@ int main(int argc, char* argv[]) { std::cout << "c: '" << c << "'" << std::endl; int d = 321; - dynamic_cast(param.get())->set("b", d); + dynamic_cast(param.get())->set("b", d); EXPECT(param->get("b", d)); std::cout << "d: '" << d << "'" << std::endl; } diff --git a/tests/geo/test_projection.cc b/tests/geo/test_projection.cc index 3a47e84ef..14863d1c5 100644 --- a/tests/geo/test_projection.cc +++ b/tests/geo/test_projection.cc @@ -13,49 +13,46 @@ #include #include +#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/Projection.h" -#include "eckit/geo/param/Map.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { + using eckit::MappedConfiguration; + using eckit::geo::Point; using eckit::geo::Point3; using eckit::geo::PointLonLat; - using Projection = std::unique_ptr; + + using Projection = std::unique_ptr; + using ProjectionFactory = eckit::geo::ProjectionFactory; Point p = PointLonLat{1, 1}; { - std::unique_ptr projection( - eckit::geo::ProjectionFactory::build("none", eckit::geo::param::Map{})); + Projection projection(ProjectionFactory::build("none", MappedConfiguration{})); EXPECT(p == projection->inv(p)); EXPECT(p == projection->fwd(p)); } { - eckit::geo::param::Map param({ + MappedConfiguration param({ {"projection", "rotation"}, {"south_pole_lat", -91.}, {"south_pole_lon", -361.}, }); - std::unique_ptr projection( - eckit::geo::ProjectionFactory::build(param.get_string("projection"), param)); + Projection projection(ProjectionFactory::build(param.getString("projection"), param)); EXPECT(p == projection->inv(projection->fwd(p))); EXPECT(p == projection->fwd(projection->inv(p))); } { - Projection s1( - eckit::geo::ProjectionFactory::build("ll_to_xyz", eckit::geo::param::Map({{"R", 1.}}))); - Projection s2( - eckit::geo::ProjectionFactory::build("ll_to_xyz", - eckit::geo::param::Map({{"a", 1.}, {"b", 1.}}))); - Projection s3( - eckit::geo::ProjectionFactory::build("ll_to_xyz", - eckit::geo::param::Map({{"a", 1.}, {"b", 0.5}}))); + Projection s1(ProjectionFactory::build("ll_to_xyz", MappedConfiguration({{"R", 1.}}))); + Projection s2(ProjectionFactory::build("ll_to_xyz", MappedConfiguration({{"a", 1.}, {"b", 1.}}))); + Projection s3(ProjectionFactory::build("ll_to_xyz", MappedConfiguration({{"a", 1.}, {"b", 0.5}}))); EXPECT(p == s1->inv(s1->fwd(p))); EXPECT(p == s2->inv(s2->fwd(p))); diff --git a/tests/geo/test_projection_proj.cc b/tests/geo/test_projection_proj.cc index dae3942cb..c75ee1ca4 100644 --- a/tests/geo/test_projection_proj.cc +++ b/tests/geo/test_projection_proj.cc @@ -12,7 +12,7 @@ #include -#include "eckit/geo/param/Map.h" +#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/projection/PROJ.h" #include "eckit/testing/Test.h" @@ -39,8 +39,7 @@ int main(int argc, char* argv[]) { }; for (const auto& test : tests) { - eckit::geo::projection::PROJ projection( - eckit::geo::param::Map({{"source", "EPSG:4326"}, {"target", test.target}})); + eckit::geo::projection::PROJ projection(eckit::MappedConfiguration({{"source", "EPSG:4326"}, {"target", test.target}})); std::cout << "ellipsoid: '" << eckit::geo::projection::PROJ::ellipsoid(projection.target()) << std::endl; @@ -53,8 +52,7 @@ int main(int argc, char* argv[]) { EXPECT(b == test.b); EXPECT(c == a); - eckit::geo::projection::PROJ reverse( - eckit::geo::param::Map({{"source", test.target}, {"target", "EPSG:4326"}})); + eckit::geo::projection::PROJ reverse(eckit::MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}})); auto d = reverse.fwd(test.b); auto e = reverse.inv(d); From 0c8b13b43c84fec1cd29d07bbdfbfee8ff77b186 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 12 May 2023 09:44:49 +0100 Subject: [PATCH 207/737] eckit::geo::projection --- src/eckit/geo/projection/LonLatToXYZ.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc index eb2d9c7be..a010f94f0 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -65,8 +65,8 @@ LonLatToXYZ::LonLatToXYZ(double R) : LonLatToXYZ::LonLatToXYZ(const Configuration& param) : - LonLatToXYZ(param.getDouble("R", param.getDouble("a")), - param.getDouble("R", param.getDouble("b"))) {} + LonLatToXYZ(param.getDouble("a", param.getDouble("R", 1.)), + param.getDouble("b", param.getDouble("R", 1.))) {} } // namespace eckit::geo::projection From 32b5a2c118b282010ae1bd857232ec344d5df879 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 12 May 2023 09:45:10 +0100 Subject: [PATCH 208/737] eckit::geometry::points_equal --- src/eckit/geometry/PointLonLat.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eckit/geometry/PointLonLat.cc b/src/eckit/geometry/PointLonLat.cc index 5111cf515..1f68d2f98 100644 --- a/src/eckit/geometry/PointLonLat.cc +++ b/src/eckit/geometry/PointLonLat.cc @@ -17,7 +17,7 @@ namespace eckit::geometry { bool points_equal(const PointLonLat& a, const PointLonLat& b) { - return eckit::types::is_approximately_equal(UnitSphere::centralAngle(a, b), 0.0); + return types::is_approximately_equal(UnitSphere::centralAngle(a, b), 0.0); } } // namespace eckit::geometry From 2c538db740e6f5bc2ce3ae50725def583aeb8dcf Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 12 May 2023 09:47:37 +0100 Subject: [PATCH 209/737] eckit::geo types --- src/eckit/geo/types.cc | 30 ++++++++++---------------- src/eckit/geo/types.h | 17 +++++++++------ tests/geo/test_projection.cc | 21 +++++++++--------- tests/geo/test_projection_ll_to_xyz.cc | 2 +- tests/geo/test_projection_proj.cc | 10 +++++---- tests/geo/test_projection_rotation.cc | 13 +++++------ tests/geo/test_types.cc | 9 ++++---- 7 files changed, 51 insertions(+), 51 deletions(-) diff --git a/src/eckit/geo/types.cc b/src/eckit/geo/types.cc index fc728ecac..c0a07502f 100644 --- a/src/eckit/geo/types.cc +++ b/src/eckit/geo/types.cc @@ -12,32 +12,24 @@ #include "eckit/geo/types.h" +#include #include "eckit/exception/Exceptions.h" -std::ostream& operator<<(std::ostream& out, const eckit::geo::Point& p) { - return std::holds_alternative(p) - ? out << std::get(p) - : std::holds_alternative(p) - ? out << std::get(p) - : std::holds_alternative(p) - ? out << std::get(p) - : NOTIMP; -} +namespace eckit::geo { -bool operator==(const eckit::geo::Point& p, const eckit::geo::Point& q) { +bool points_equal(const Point& p, const Point& q) { ASSERT(p.index() == q.index()); + return std::visit([&](const auto& p, const auto& q) { return points_equal(p, q); }, p, q); +} - constexpr double eps = 1e-6; - return std::holds_alternative(p) - ? points_equal(std::get(p), - std::get(q)) - : std::holds_alternative(p) - ? points_equal(std::get(p), std::get(q)) - : std::holds_alternative(p) - ? points_equal(std::get(p), std::get(q)) - : NOTIMP; +} // namespace eckit::geo + + +std::ostream& operator<<(std::ostream& out, const eckit::geo::Point& p) { + std::visit([&](const auto& p) { out << p; }, p); + return out; } diff --git a/src/eckit/geo/types.h b/src/eckit/geo/types.h index d55865436..94c571b14 100644 --- a/src/eckit/geo/types.h +++ b/src/eckit/geo/types.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include #include @@ -24,19 +24,22 @@ namespace eckit::geo { -using PointLonLat = eckit::geometry::PointLonLat; -using Point2 = eckit::geometry::Point2; -using Point3 = eckit::geometry::Point3; +using PointLonLat = geometry::PointLonLat; +using Point2 = geometry::Point2; +using Point3 = geometry::Point3; using Point = std::variant; using pl_type = std::vector; -} // namespace eckit::geo +using geometry::points_equal; -std::ostream& operator<<(std::ostream&, const eckit::geo::Point&); +bool points_equal(const Point&, const Point&); + + +} // namespace eckit::geo -bool operator==(const eckit::geo::Point&, const eckit::geo::Point&); +std::ostream& operator<<(std::ostream&, const eckit::geo::Point&); diff --git a/tests/geo/test_projection.cc b/tests/geo/test_projection.cc index 14863d1c5..1511faea7 100644 --- a/tests/geo/test_projection.cc +++ b/tests/geo/test_projection.cc @@ -24,6 +24,7 @@ int main(int argc, char* argv[]) { using eckit::geo::Point; using eckit::geo::Point3; using eckit::geo::PointLonLat; + using eckit::geo::points_equal; using Projection = std::unique_ptr; using ProjectionFactory = eckit::geo::ProjectionFactory; @@ -32,8 +33,8 @@ int main(int argc, char* argv[]) { { Projection projection(ProjectionFactory::build("none", MappedConfiguration{})); - EXPECT(p == projection->inv(p)); - EXPECT(p == projection->fwd(p)); + EXPECT(points_equal(p, projection->inv(p))); + EXPECT(points_equal(p, projection->fwd(p))); } { @@ -45,8 +46,8 @@ int main(int argc, char* argv[]) { Projection projection(ProjectionFactory::build(param.getString("projection"), param)); - EXPECT(p == projection->inv(projection->fwd(p))); - EXPECT(p == projection->fwd(projection->inv(p))); + EXPECT(points_equal(p, projection->inv(projection->fwd(p)))); + EXPECT(points_equal(p, projection->fwd(projection->inv(p)))); } { @@ -54,14 +55,14 @@ int main(int argc, char* argv[]) { Projection s2(ProjectionFactory::build("ll_to_xyz", MappedConfiguration({{"a", 1.}, {"b", 1.}}))); Projection s3(ProjectionFactory::build("ll_to_xyz", MappedConfiguration({{"a", 1.}, {"b", 0.5}}))); - EXPECT(p == s1->inv(s1->fwd(p))); - EXPECT(p == s2->inv(s2->fwd(p))); - EXPECT(s1->fwd(p) == s2->fwd(p)); + EXPECT(points_equal(p, s1->inv(s1->fwd(p)))); + EXPECT(points_equal(p, s2->inv(s2->fwd(p)))); + EXPECT(points_equal(s1->fwd(p), s2->fwd(p))); Point q = PointLonLat{1, 0}; - EXPECT(s1->fwd(q) == s3->fwd(q)); - EXPECT(s2->fwd(q) == s3->fwd(q)); + EXPECT(points_equal(s1->fwd(q), s3->fwd(q))); + EXPECT(points_equal(s2->fwd(q), s3->fwd(q))); struct { PointLonLat a; @@ -78,7 +79,7 @@ int main(int argc, char* argv[]) { }; for (const auto& test : tests) { - EXPECT(s3->fwd(test.a) == Point(test.b)); + EXPECT(points_equal(s3->fwd(test.a), test.b)); } } } diff --git a/tests/geo/test_projection_ll_to_xyz.cc b/tests/geo/test_projection_ll_to_xyz.cc index 506ec04b4..687bdad84 100644 --- a/tests/geo/test_projection_ll_to_xyz.cc +++ b/tests/geo/test_projection_ll_to_xyz.cc @@ -30,7 +30,7 @@ int main(int argc, char* argv[]) { auto r = to_xyz.inv(q); std::cout << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; - EXPECT(Point(p) == r); + EXPECT(eckit::geo::points_equal(p, r)); } diff --git a/tests/geo/test_projection_proj.cc b/tests/geo/test_projection_proj.cc index c75ee1ca4..d9380f325 100644 --- a/tests/geo/test_projection_proj.cc +++ b/tests/geo/test_projection_proj.cc @@ -18,6 +18,8 @@ int main(int argc, char* argv[]) { + using eckit::geo::points_equal; + std::cout.precision(14); eckit::geo::PointLonLat a{12., 55.}; @@ -49,8 +51,8 @@ int main(int argc, char* argv[]) { std::cout << "-> a:" << a << " -> fwd(a):" << b << " -> inv(fwd(a)):" << c << std::endl; - EXPECT(b == test.b); - EXPECT(c == a); + EXPECT(points_equal(b, test.b)); + EXPECT(points_equal(c, a)); eckit::geo::projection::PROJ reverse(eckit::MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}})); @@ -59,7 +61,7 @@ int main(int argc, char* argv[]) { std::cout << "-> b:" << test.b << " -> fwd(b):" << d << " -> inv(fwd(b)):" << e << std::endl; - EXPECT(d == a); - EXPECT(e == test.b); + EXPECT(points_equal(d, a)); + EXPECT(points_equal(e, test.b)); } } diff --git a/tests/geo/test_projection_rotation.cc b/tests/geo/test_projection_rotation.cc index 0ec2798c2..7bef6ba7e 100644 --- a/tests/geo/test_projection_rotation.cc +++ b/tests/geo/test_projection_rotation.cc @@ -19,6 +19,7 @@ int main(int argc, char* argv[]) { using eckit::geo::Point; using eckit::geo::PointLonLat; + using eckit::geo::points_equal; using eckit::geo::projection::Rotation; { @@ -31,8 +32,8 @@ int main(int argc, char* argv[]) { Rotation rot(-90. + static_cast(a), 0. + static_cast(b), static_cast(c)); EXPECT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); - EXPECT(Point(p) == rot.inv(rot.fwd(p))); - EXPECT(Point(p) == rot.fwd(rot.inv(p))); + EXPECT(points_equal(p, rot.inv(rot.fwd(p)))); + EXPECT(points_equal(p, rot.fwd(rot.inv(p)))); } } } @@ -135,8 +136,8 @@ int main(int argc, char* argv[]) { PointLonLat a(static_cast(i) * 360. / static_cast(Ni), static_cast(j - Nj) * 90. / static_cast(Nj)); auto b = rot.fwd(a); - EXPECT(Point(b) == ref[k]); - EXPECT(Point(a) == rot.inv(b)); + EXPECT(points_equal(b, ref[k])); + EXPECT(points_equal(a, rot.inv(b))); } } } @@ -173,10 +174,10 @@ int main(int argc, char* argv[]) { for (const auto& test : tests) { auto b = test.rotation.fwd(test.a); - EXPECT(Point(b) == test.b); + EXPECT(points_equal(b, test.b)); auto a = test.rotation.inv(b); - EXPECT(Point(a) == test.a); + EXPECT(points_equal(a, test.a)); } } } diff --git a/tests/geo/test_types.cc b/tests/geo/test_types.cc index 59d2ec27e..e3e84701a 100644 --- a/tests/geo/test_types.cc +++ b/tests/geo/test_types.cc @@ -20,12 +20,13 @@ int main(int argc, char* argv[]) { using eckit::geo::Point; using eckit::geo::PointLonLat; + using eckit::geo::points_equal; PointLonLat p(1, 90.); std::cout << "p: " << p << std::endl; std::cout << "p: " << PointLonLat::make(p.lon, p.lat) << std::endl; - std::cout << "p: " << (Point(p) == PointLonLat(50., 90.)) << std::endl; + std::cout << "p: " << points_equal(p, PointLonLat(50., 90.)) << std::endl; PointLonLat q(1., -90.); std::cout << "q: " << q << std::endl; @@ -33,15 +34,15 @@ int main(int argc, char* argv[]) { std::cout << "~~q: " << q.antipode().antipode() << std::endl; auto r(PointLonLat::make(-10., -91.)); - EXPECT(Point(r) == r.antipode().antipode()); + EXPECT(points_equal(r, r.antipode().antipode())); Point a1 = PointLonLat{300, -30}; Point a2 = PointLonLat{-59.99999999999996, -30.000000000000018}; - EXPECT(a1 == a2); + EXPECT(points_equal(a1, a2)); Point b1 = PointLonLat{-178., -46.7}; Point b2 = PointLonLat{-178.00000000000003, -46.7}; - EXPECT(b1 == b2); + EXPECT(points_equal(b1, b2)); { using Matrix3 = eckit::maths::Matrix3; From 8079dd287800ee811b6f146ae7ea3685a5e7475c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 12 May 2023 11:54:59 +0100 Subject: [PATCH 210/737] eckit::geo types --- src/eckit/geo/BoundingBox.cc | 23 +++++++++++++------- src/eckit/geo/CMakeLists.txt | 4 ++-- src/eckit/geo/Iterator.h | 2 +- src/eckit/geo/{types.cc => Point.cc} | 2 +- src/eckit/geo/{types.h => Point.h} | 14 ++++-------- src/eckit/geo/Projection.h | 2 +- src/eckit/geo/projection/LonLatToXYZ.cc | 6 +++--- src/eckit/geo/projection/PROJ.cc | 1 - src/eckit/geo/projection/Rotation.cc | 15 +++++++------ src/eckit/geo/util.cc | 24 ++++++++++----------- src/eckit/geo/util.h | 24 +++++---------------- src/eckit/geo/util/arange.cc | 6 ++++-- src/eckit/geo/util/monotonic_crop.cc | 10 ++++++--- src/eckit/geo/util/reduced_classical_pl.cc | 3 +-- src/eckit/geo/util/reduced_octahedral_pl.cc | 3 +-- src/eckit/geo/util/regular_pl.cc | 4 +--- tests/geo/test_grib.cc | 1 - tests/geo/test_types.cc | 6 ++---- 18 files changed, 69 insertions(+), 81 deletions(-) rename src/eckit/geo/{types.cc => Point.cc} (96%) rename src/eckit/geo/{types.h => Point.h} (76%) diff --git a/src/eckit/geo/BoundingBox.cc b/src/eckit/geo/BoundingBox.cc index 7d5ad1be4..fe78df2e3 100644 --- a/src/eckit/geo/BoundingBox.cc +++ b/src/eckit/geo/BoundingBox.cc @@ -13,10 +13,12 @@ #include "eckit/geo/BoundingBox.h" #include +#include #include "eckit/exception/Exceptions.h" #include "eckit/geo/util.h" #include "eckit/geometry/Sphere.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo { @@ -25,7 +27,7 @@ namespace eckit::geo { BoundingBox::BoundingBox(double north, double west, double south, double east) : north_(north), west_(west), south_(south), east_(east) { if (west_ != east_) { - auto e = util::normalise_longitude_to_minimum(east, west); + auto e = util::normalise_angle_to_minimum(east, west); east_ = e == west_ ? (e + 360.) : e; } @@ -44,12 +46,12 @@ bool BoundingBox::operator==(const BoundingBox& other) const { bool BoundingBox::isPeriodicWestEast() const { - return west_ != east_ && west_ == util::normalise_longitude_to_minimum(east_, west_); + return west_ != east_ && west_ == util::normalise_angle_to_minimum(east_, west_); } bool BoundingBox::contains(double lat, double lon) const { - return lat <= north_ && lat >= south_ && util::normalise_longitude_to_minimum(lon, west_) <= east_; + return lat <= north_ && lat >= south_ && util::normalise_angle_to_minimum(lon, west_) <= east_; } @@ -59,7 +61,7 @@ bool BoundingBox::contains(const BoundingBox& other) const { } // check for West/East range (if non-periodic), then other's corners - if (east_ - west_ < other.east_ - other.west_ || east_ < util::normalise_longitude_to_minimum(other.east_, west_)) { + if (east_ - west_ < other.east_ - other.west_ || east_ < util::normalise_angle_to_minimum(other.east_, west_)) { return false; } @@ -92,9 +94,9 @@ bool BoundingBox::intersects(BoundingBox& other) const { return true; } - auto ref = util::normalise_longitude_to_minimum(b.west_, a.west_); + auto ref = util::normalise_angle_to_minimum(b.west_, a.west_); auto w_ = std::max(a.west_, ref); - auto e_ = std::min(a.east_, util::normalise_longitude_to_minimum(b.east_, ref)); + auto e_ = std::min(a.east_, util::normalise_angle_to_minimum(b.east_, ref)); if (w_ <= e_) { w = w_; @@ -116,7 +118,7 @@ bool BoundingBox::intersects(BoundingBox& other) const { bool BoundingBox::empty() const { - return util::is_approximately_equal(north_, south_) || util::is_approximately_equal(west_, east_); + return types::is_approximately_equal(north_, south_) || types::is_approximately_equal(west_, east_); } @@ -124,7 +126,12 @@ double BoundingBox::area(double radius) const { double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); ASSERT(0. <= lonf && lonf <= 1.); - double latf = 0.5 * (std::sin(util::degrees_to_radians * north_) - std::sin(util::degrees_to_radians * south_)); + constexpr auto degrees_to_radians = M_PI / 180.; + + const auto sn = std::sin(north_ * degrees_to_radians); + const auto ss = std::sin(south_ * degrees_to_radians); + + double latf = 0.5 * (sn - ss); ASSERT(0. <= latf && latf <= 1.); return geometry::Sphere::area(radius) * latf * lonf; diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 210556d41..e6118475a 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -2,6 +2,8 @@ list(APPEND eckit_geo_srcs BoundingBox.cc BoundingBox.h Iterator.h + Point.cc + Point.h Projection.cc Projection.h Scanner.cc @@ -22,8 +24,6 @@ list(APPEND eckit_geo_srcs scanner/Regular.h scanner/Unstructured.cc scanner/Unstructured.h - types.cc - types.h util.cc util.h util/arange.cc diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index 8e0b35a06..9f3216f74 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -12,7 +12,7 @@ #pragma once -#include "eckit/geo/types.h" +#include "eckit/geo/Point.h" namespace eckit::geo { diff --git a/src/eckit/geo/types.cc b/src/eckit/geo/Point.cc similarity index 96% rename from src/eckit/geo/types.cc rename to src/eckit/geo/Point.cc index c0a07502f..0f8ddd107 100644 --- a/src/eckit/geo/types.cc +++ b/src/eckit/geo/Point.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/types.h" +#include "eckit/geo/Point.h" #include diff --git a/src/eckit/geo/types.h b/src/eckit/geo/Point.h similarity index 76% rename from src/eckit/geo/types.h rename to src/eckit/geo/Point.h index 94c571b14..b574dc5f8 100644 --- a/src/eckit/geo/types.h +++ b/src/eckit/geo/Point.h @@ -14,7 +14,6 @@ #include #include -#include #include "eckit/geometry/Point2.h" #include "eckit/geometry/Point3.h" @@ -24,18 +23,13 @@ namespace eckit::geo { -using PointLonLat = geometry::PointLonLat; -using Point2 = geometry::Point2; -using Point3 = geometry::Point3; -using Point = std::variant; - - -using pl_type = std::vector; - - +using geometry::Point2; +using geometry::Point3; +using geometry::PointLonLat; using geometry::points_equal; +using Point = std::variant; bool points_equal(const Point&, const Point&); diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index cbf004280..f9b02dc90 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -15,7 +15,7 @@ #include #include -#include "eckit/geo/types.h" +#include "eckit/geo/Point.h" namespace eckit { diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc index a010f94f0..649ff0056 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -13,9 +13,9 @@ #include "eckit/geo/projection/LonLatToXYZ.h" #include "eckit/config/Configuration.h" -#include "eckit/geo/util.h" #include "eckit/geometry/EllipsoidOfRevolution.h" #include "eckit/geometry/Sphere.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo::projection { @@ -55,8 +55,8 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { PointLonLat operator()(const Point3& q) const override { NOTIMP; } }; - impl_.reset(util::is_approximately_equal(a, b) ? static_cast(new LonLatToSphereXYZ(a)) - : new LonLatToSpheroidXYZ(a, b)); + impl_.reset(types::is_approximately_equal(a, b) ? static_cast(new LonLatToSphereXYZ(a)) + : new LonLatToSpheroidXYZ(a, b)); } diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 38ee50dd0..f5aa4db07 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -14,7 +14,6 @@ #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geo/types.h" namespace eckit::geo::projection { diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index d429c89d7..8d30c8c2b 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -19,6 +19,7 @@ #include "eckit/geo/util.h" #include "eckit/geometry/UnitSphere.h" #include "eckit/maths/Matrix3.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo::projection { @@ -52,17 +53,19 @@ Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : const M R_; }; - const auto alpha = angle * util::degrees_to_radians; - const auto theta = -(south_pole_lat + 90.) * util::degrees_to_radians; - const auto phi = -(south_pole_lon)*util::degrees_to_radians; + constexpr auto degrees_to_radians = M_PI / 180.; + + const auto alpha = angle * degrees_to_radians; + const auto theta = -(south_pole_lat + 90.) * degrees_to_radians; + const auto phi = -south_pole_lon * degrees_to_radians; const auto ca = std::cos(alpha); const auto ct = std::cos(theta); const auto cp = std::cos(phi); - if (util::is_approximately_equal(ct, 1., 1.e-12)) { - angle = util::normalise_longitude_to_minimum(angle - south_pole_lon, -180.); - rotated_ = !util::is_approximately_equal(angle, 0., 1.e-12); + if (types::is_approximately_equal(ct, 1., 1.e-12)) { + angle = util::normalise_angle_to_minimum(angle - south_pole_lon, -180.); + rotated_ = !types::is_approximately_equal(angle, 0., 1.e-12); fwd_.reset(rotated_ ? static_cast(new Angle(-angle)) : new No); inv_.reset(rotated_ ? static_cast(new Angle(angle)) : new No); diff --git a/src/eckit/geo/util.cc b/src/eckit/geo/util.cc index af5d59236..d5cbc7d3e 100644 --- a/src/eckit/geo/util.cc +++ b/src/eckit/geo/util.cc @@ -22,25 +22,25 @@ pl_type pl_convert(const pl_type& pl) { } -double normalise_longitude_to_minimum(double lon, double minimum) { - while (lon < minimum) { - lon += 360.; +double normalise_angle_to_minimum(double a, double minimum) { + while (a < minimum) { + a += 360.; } - while (lon >= minimum + 360.) { - lon -= 360.; + while (a >= minimum + 360.) { + a -= 360.; } - return lon; + return a; } -double normalise_longitude_to_maximum(double lon, double maximum) { - while (lon > maximum) { - lon -= 360.; +double normalise_angle_to_maximum(double a, double maximum) { + while (a > maximum) { + a -= 360.; } - while (lon <= maximum - 360.) { - lon += 360.; + while (a <= maximum - 360.) { + a += 360.; } - return lon; + return a; } diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index cca5c2833..e6e3824e3 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -15,22 +15,14 @@ #include #include #include -#include #include #include -#include "eckit/geo/types.h" - namespace eckit::geo::util { -template -bool is_approximately_equal(T x, T y, T eps = std::numeric_limits::epsilon()) { - auto min = std::min(std::abs(x), std::abs(y)); - return std::abs(min) == 0. ? std::abs(x - y) < eps - : std::abs(x - y) / std::max(std::numeric_limits::min(), min) < eps; -}; +using pl_type = std::vector; template @@ -48,12 +40,6 @@ template <> pl_type pl_convert(const pl_type&); -static constexpr double degrees_to_radians = M_PI / 180.; - - -static constexpr double radians_to_degrees = 180. * M_1_PI; - - std::vector arange(double start, double stop, double step); @@ -67,12 +53,12 @@ std::pair::const_iterator, std::vector::const_iterat const std::vector&, double min, double max, double eps); -/// @return longitude in degree within range [minimum, minimum + 360[ -double normalise_longitude_to_minimum(double lon, double minimum); +/// @return angle [degree] within range [minimum, minimum + 360[ +double normalise_angle_to_minimum(double lon, double minimum); -/// @return longitude in degree within range ]maximum - 360, maximum] -double normalise_longitude_to_maximum(double lon, double maximum); +/// @return angle [degree] within range ]maximum - 360, maximum] +double normalise_angle_to_maximum(double lon, double maximum); const pl_type& reduced_classical_pl(size_t N); diff --git a/src/eckit/geo/util/arange.cc b/src/eckit/geo/util/arange.cc index 938965a64..095eb8fcd 100644 --- a/src/eckit/geo/util/arange.cc +++ b/src/eckit/geo/util/arange.cc @@ -10,14 +10,16 @@ */ -#include "eckit/geo/util.h" +#include + +#include "eckit/types/FloatCompare.h" namespace eckit::geo::util { std::vector arange(double start, double stop, double step) { - if (is_approximately_equal(step, 0.) || is_approximately_equal(start, stop) || (stop - start) * step < 0.) { + if (types::is_approximately_equal(step, 0.) || types::is_approximately_equal(start, stop) || (stop - start) * step < 0.) { std::vector l(1, start); return l; } diff --git a/src/eckit/geo/util/monotonic_crop.cc b/src/eckit/geo/util/monotonic_crop.cc index bad1dba9b..d636a5d14 100644 --- a/src/eckit/geo/util/monotonic_crop.cc +++ b/src/eckit/geo/util/monotonic_crop.cc @@ -10,8 +10,12 @@ */ +#include +#include +#include + #include "eckit/exception/Exceptions.h" -#include "eckit/geo/util.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo::util { @@ -29,7 +33,7 @@ std::pair::const_iterator, std::vector::const_iterat if (increasing) { ASSERT(std::is_sorted(values.begin(), values.end())); - auto lt = [eps](double a, double b) { return a < b && (0. == eps || !is_approximately_equal(a, b, eps)); }; + auto lt = [eps](double a, double b) { return a < b && (0. == eps || !types::is_approximately_equal(a, b, eps)); }; return {std::lower_bound(values.begin(), values.end(), min, lt), std::upper_bound(values.begin(), values.end(), max, lt)}; } @@ -38,7 +42,7 @@ std::pair::const_iterator, std::vector::const_iterat // monotonically non-increasing ASSERT(std::is_sorted(values.rbegin(), values.rend())); - auto gt = [eps](double a, double b) { return a > b && (0. == eps || !is_approximately_equal(a, b, eps)); }; + auto gt = [eps](double a, double b) { return a > b && (0. == eps || !types::is_approximately_equal(a, b, eps)); }; return {std::lower_bound(values.begin(), values.end(), max, gt), std::upper_bound(values.begin(), values.end(), min, gt)}; } diff --git a/src/eckit/geo/util/reduced_classical_pl.cc b/src/eckit/geo/util/reduced_classical_pl.cc index 00f74d991..46441eb54 100644 --- a/src/eckit/geo/util/reduced_classical_pl.cc +++ b/src/eckit/geo/util/reduced_classical_pl.cc @@ -12,10 +12,9 @@ #include #include -#include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/types.h" +#include "eckit/geo/util.h" namespace eckit::geo::util { diff --git a/src/eckit/geo/util/reduced_octahedral_pl.cc b/src/eckit/geo/util/reduced_octahedral_pl.cc index 74c3e2174..a6223dd22 100644 --- a/src/eckit/geo/util/reduced_octahedral_pl.cc +++ b/src/eckit/geo/util/reduced_octahedral_pl.cc @@ -11,10 +11,9 @@ #include -#include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/types.h" +#include "eckit/geo/util.h" namespace eckit::geo::util { diff --git a/src/eckit/geo/util/regular_pl.cc b/src/eckit/geo/util/regular_pl.cc index 4ef43b0c1..f6c639c84 100644 --- a/src/eckit/geo/util/regular_pl.cc +++ b/src/eckit/geo/util/regular_pl.cc @@ -10,10 +10,8 @@ */ -#include - #include "eckit/exception/Exceptions.h" -#include "eckit/geo/types.h" +#include "eckit/geo/util.h" namespace eckit::geo::util { diff --git a/tests/geo/test_grib.cc b/tests/geo/test_grib.cc index cb4f14e58..118379a8d 100644 --- a/tests/geo/test_grib.cc +++ b/tests/geo/test_grib.cc @@ -23,7 +23,6 @@ #include "eckit/exception/Exceptions.h" // #include "eckit/config/Configuration.h" #include "eckit/config/MappedConfiguration.h" -#include "eckit/geo/types.h" #include "eckit/value/Value.h" diff --git a/tests/geo/test_types.cc b/tests/geo/test_types.cc index e3e84701a..f0d88a86d 100644 --- a/tests/geo/test_types.cc +++ b/tests/geo/test_types.cc @@ -12,15 +12,13 @@ #include -#include "eckit/geo/types.h" +#include "eckit/geo/Point.h" #include "eckit/maths/Matrix3.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using eckit::geo::Point; - using eckit::geo::PointLonLat; - using eckit::geo::points_equal; + using namespace eckit::geo; PointLonLat p(1, 90.); From 69a5974aaa8f21a06c4890a473be08bb3c1f6eab Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 12 May 2023 15:19:50 +0100 Subject: [PATCH 211/737] eckit::geometry::PointLonLat --- src/eckit/geo/BoundingBox.cc | 14 +++++++------- src/eckit/geo/Projection.cc | 5 +++-- src/eckit/geo/Projection.h | 2 +- src/eckit/geo/projection/Rotation.cc | 8 ++++---- src/eckit/geo/util.cc | 22 --------------------- src/eckit/geo/util.h | 12 ++---------- src/eckit/geometry/PointLonLat.cc | 26 +++++++++++++++++++++++++ src/eckit/geometry/PointLonLat.h | 29 ++++++++-------------------- 8 files changed, 51 insertions(+), 67 deletions(-) diff --git a/src/eckit/geo/BoundingBox.cc b/src/eckit/geo/BoundingBox.cc index fe78df2e3..d05091756 100644 --- a/src/eckit/geo/BoundingBox.cc +++ b/src/eckit/geo/BoundingBox.cc @@ -16,7 +16,7 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/util.h" +#include "eckit/geo/Point.h" #include "eckit/geometry/Sphere.h" #include "eckit/types/FloatCompare.h" @@ -27,7 +27,7 @@ namespace eckit::geo { BoundingBox::BoundingBox(double north, double west, double south, double east) : north_(north), west_(west), south_(south), east_(east) { if (west_ != east_) { - auto e = util::normalise_angle_to_minimum(east, west); + auto e = PointLonLat::normalise_angle_to_minimum(east, west); east_ = e == west_ ? (e + 360.) : e; } @@ -46,12 +46,12 @@ bool BoundingBox::operator==(const BoundingBox& other) const { bool BoundingBox::isPeriodicWestEast() const { - return west_ != east_ && west_ == util::normalise_angle_to_minimum(east_, west_); + return west_ != east_ && west_ == PointLonLat::normalise_angle_to_minimum(east_, west_); } bool BoundingBox::contains(double lat, double lon) const { - return lat <= north_ && lat >= south_ && util::normalise_angle_to_minimum(lon, west_) <= east_; + return lat <= north_ && lat >= south_ && PointLonLat::normalise_angle_to_minimum(lon, west_) <= east_; } @@ -61,7 +61,7 @@ bool BoundingBox::contains(const BoundingBox& other) const { } // check for West/East range (if non-periodic), then other's corners - if (east_ - west_ < other.east_ - other.west_ || east_ < util::normalise_angle_to_minimum(other.east_, west_)) { + if (east_ - west_ < other.east_ - other.west_ || east_ < PointLonLat::normalise_angle_to_minimum(other.east_, west_)) { return false; } @@ -94,9 +94,9 @@ bool BoundingBox::intersects(BoundingBox& other) const { return true; } - auto ref = util::normalise_angle_to_minimum(b.west_, a.west_); + auto ref = PointLonLat::normalise_angle_to_minimum(b.west_, a.west_); auto w_ = std::max(a.west_, ref); - auto e_ = std::min(a.east_, util::normalise_angle_to_minimum(b.east_, ref)); + auto e_ = std::min(a.east_, PointLonLat::normalise_angle_to_minimum(b.east_, ref)); if (w_ <= e_) { w = w_; diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index a2af5a901..366e96376 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -223,6 +223,7 @@ static pthread_once_t __once = static Mutex* __mutex = nullptr; static std::map* __factories = nullptr; + static void __init() { __mutex = new Mutex; __factories = new std::map(); @@ -230,12 +231,12 @@ static void __init() { Projection* ProjectionFactory::build(const ProjectionFactory::key_type& key, - const Configuration& param) { + const Configuration& config) { pthread_once(&__once, __init); AutoLock lock(*__mutex); if (auto f = __factories->find(key); f != __factories->end()) { - return f->second->make(param); + return f->second->make(config); } list(Log::error() << "ProjectionFactory: unknown '" << key << "', choices are: "); diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index f9b02dc90..e73dbb5f2 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -128,7 +128,7 @@ struct ProjectionFactory { template class ProjectionBuilder final : public ProjectionFactory { - Projection* make(const Configuration& param) override { return new T(param); } + Projection* make(const Configuration& config) override { return new T(config); } public: explicit ProjectionBuilder(const ProjectionFactory::key_type& key) : diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 8d30c8c2b..88cb25c56 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -16,7 +16,6 @@ #include #include "eckit/config/Configuration.h" -#include "eckit/geo/util.h" #include "eckit/geometry/UnitSphere.h" #include "eckit/maths/Matrix3.h" #include "eckit/types/FloatCompare.h" @@ -53,6 +52,7 @@ Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : const M R_; }; + constexpr auto eps = 1e-12; constexpr auto degrees_to_radians = M_PI / 180.; const auto alpha = angle * degrees_to_radians; @@ -63,9 +63,9 @@ Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : const auto ct = std::cos(theta); const auto cp = std::cos(phi); - if (types::is_approximately_equal(ct, 1., 1.e-12)) { - angle = util::normalise_angle_to_minimum(angle - south_pole_lon, -180.); - rotated_ = !types::is_approximately_equal(angle, 0., 1.e-12); + if (types::is_approximately_equal(ct, 1., eps)) { + angle = PointLonLat::normalise_angle_to_minimum(angle - south_pole_lon, -180.); + rotated_ = !types::is_approximately_equal(angle, 0., eps); fwd_.reset(rotated_ ? static_cast(new Angle(-angle)) : new No); inv_.reset(rotated_ ? static_cast(new Angle(angle)) : new No); diff --git a/src/eckit/geo/util.cc b/src/eckit/geo/util.cc index d5cbc7d3e..5937054c6 100644 --- a/src/eckit/geo/util.cc +++ b/src/eckit/geo/util.cc @@ -22,26 +22,4 @@ pl_type pl_convert(const pl_type& pl) { } -double normalise_angle_to_minimum(double a, double minimum) { - while (a < minimum) { - a += 360.; - } - while (a >= minimum + 360.) { - a -= 360.; - } - return a; -} - - -double normalise_angle_to_maximum(double a, double maximum) { - while (a > maximum) { - a -= 360.; - } - while (a <= maximum - 360.) { - a += 360.; - } - return a; -} - - } // namespace eckit::geo::util diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index e6e3824e3..a39c35065 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -43,24 +43,16 @@ pl_type pl_convert(const pl_type&); std::vector arange(double start, double stop, double step); -std::vector linspace(double start, double stop, size_t num, bool endpoint); +std::vector gaussian_latitudes(size_t N, bool increasing); -std::vector gaussian_latitudes(size_t N, bool increasing); +std::vector linspace(double start, double stop, size_t num, bool endpoint); std::pair::const_iterator, std::vector::const_iterator> monotonic_crop( const std::vector&, double min, double max, double eps); -/// @return angle [degree] within range [minimum, minimum + 360[ -double normalise_angle_to_minimum(double lon, double minimum); - - -/// @return angle [degree] within range ]maximum - 360, maximum] -double normalise_angle_to_maximum(double lon, double maximum); - - const pl_type& reduced_classical_pl(size_t N); diff --git a/src/eckit/geometry/PointLonLat.cc b/src/eckit/geometry/PointLonLat.cc index 1f68d2f98..6ef284aba 100644 --- a/src/eckit/geometry/PointLonLat.cc +++ b/src/eckit/geometry/PointLonLat.cc @@ -9,15 +9,41 @@ * does it submit to any jurisdiction. */ + #include "eckit/geometry/PointLonLat.h" #include "eckit/geometry/UnitSphere.h" #include "eckit/types/FloatCompare.h" + namespace eckit::geometry { + bool points_equal(const PointLonLat& a, const PointLonLat& b) { return types::is_approximately_equal(UnitSphere::centralAngle(a, b), 0.0); } + +double PointLonLat::normalise_angle_to_minimum(double a, double minimum) { + while (a < minimum) { + a += 360.; + } + while (a >= minimum + 360.) { + a -= 360.; + } + return a; +} + + +double PointLonLat::normalise_angle_to_maximum(double a, double maximum) { + while (a > maximum) { + a -= 360.; + } + while (a <= maximum - 360.) { + a += 360.; + } + return a; +} + + } // namespace eckit::geometry diff --git a/src/eckit/geometry/PointLonLat.h b/src/eckit/geometry/PointLonLat.h index 14ce33826..a9077b7a4 100644 --- a/src/eckit/geometry/PointLonLat.h +++ b/src/eckit/geometry/PointLonLat.h @@ -28,20 +28,6 @@ class PointLonLat final : protected std::array { using P = std::array; - // -- Class methods - - static double normal(double a, double minimum) { - while (a < minimum) { - a += 360.; - } - - while (a >= minimum + 360.) { - a -= 360.; - } - - return a; - }; - public: // -- Types // None @@ -53,8 +39,10 @@ class PointLonLat final : protected std::array { PointLonLat(double lat, double lon) : P{lat, lon} { ASSERT_MSG(-90. <= lat && lat <= 90., "PointLonLat: invalid latitude"); } + PointLonLat(const PointLonLat& other) : P(other) {} + PointLonLat(PointLonLat&& other) : P(other) {} @@ -77,11 +65,6 @@ class PointLonLat final : protected std::array { return *this; } - bool is_approximately_equal(const PointLonLat& other, double eps) const { - const auto dlon = normal(other.lon, lon) - lon; - return std::abs(lat - other.lat) < eps && (std::abs(lat - 90.) < eps || std::abs(lat + 90.) < eps || dlon < eps || dlon - 360. < eps); - }; - // -- Members double& lat = P::operator[](0); @@ -89,15 +72,19 @@ class PointLonLat final : protected std::array { // -- Methods + static double normalise_angle_to_minimum(double, double minimum); + + static double normalise_angle_to_maximum(double, double maximum); + static PointLonLat make(double lat, double lon, double lon_minimum = 0) { - lat = normal(lat, -90.); + lat = normalise_angle_to_minimum(lat, -90.); if (lat > 90.) { lat = 180. - lat; lon += 180.; } - return {lat, lat == -90. || lat == 90. ? 0. : normal(lon, lon_minimum)}; + return {lat, lat == -90. || lat == 90. ? 0. : normalise_angle_to_minimum(lon, lon_minimum)}; } PointLonLat antipode() const { return make(lat + 180., lon); } From 53e590ef1b4109e15e890ced90af95fa41c22fb3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 12 May 2023 15:20:00 +0100 Subject: [PATCH 212/737] eckit::geo::Iterator --- src/eckit/geo/CMakeLists.txt | 1 + src/eckit/geo/Iterator.cc | 87 ++++++++++++++++++++++++++++++++++++ src/eckit/geo/Iterator.h | 30 +++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 src/eckit/geo/Iterator.cc diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index e6118475a..e2c28152f 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -1,6 +1,7 @@ list(APPEND eckit_geo_srcs BoundingBox.cc BoundingBox.h + Iterator.cc Iterator.h Point.cc Point.h diff --git a/src/eckit/geo/Iterator.cc b/src/eckit/geo/Iterator.cc new file mode 100644 index 000000000..1a5a0fc56 --- /dev/null +++ b/src/eckit/geo/Iterator.cc @@ -0,0 +1,87 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Iterator.h" + +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/log/Log.h" +#include "eckit/thread/AutoLock.h" +#include "eckit/thread/Mutex.h" + + +namespace eckit::geo { + + +static pthread_once_t __once = PTHREAD_ONCE_INIT; +static Mutex* __mutex = nullptr; +static std::map* __factories = nullptr; + + +static void __init() { + __mutex = new Mutex; + __factories = new std::map(); +} + + +Iterator* IteratorFactory::build(const IteratorFactory::key_type& key, const Configuration& config) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + if (auto f = __factories->find(key); f != __factories->end()) { + return f->second->make(config); + } + + list(Log::error() << "IteratorFactory: unknown '" << key << "', choices are: "); + throw BadValue("IteratorFactory: unknown '" + key + "'"); +} + + +std::ostream& IteratorFactory::list(std::ostream& out) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + const char* sep = "'"; + for (const auto& j : *__factories) { + out << sep << j.first << '\''; + sep = ", '"; + } + + return out; +} + + +IteratorFactory::IteratorFactory(const key_type& key) : + key_(key) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + if (auto f = __factories->find(key); f != __factories->end()) { + throw BadValue("IteratorFactory: duplicate '" + key + "'"); + } + + (*__factories)[key] = this; +} + + +IteratorFactory::~IteratorFactory() { + AutoLock lock(*__mutex); + + if (__factories != nullptr) { + __factories->erase(key_); + } +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index 9f3216f74..9a44e12c5 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -12,9 +12,17 @@ #pragma once +#include +#include + #include "eckit/geo/Point.h" +namespace eckit { +class Configuration; +} + + namespace eckit::geo { @@ -119,4 +127,26 @@ class Iterator { }; +struct IteratorFactory { + using key_type = std::string; + + static Iterator* build(const key_type&, const Configuration&); + static std::ostream& list(std::ostream&); + + IteratorFactory(const IteratorFactory&) = delete; + IteratorFactory(IteratorFactory&&) = delete; + IteratorFactory& operator=(const IteratorFactory&) = delete; + IteratorFactory& operator=(IteratorFactory&&) = delete; + + virtual Iterator* make(const Configuration&) = 0; + +protected: + explicit IteratorFactory(const key_type&); + virtual ~IteratorFactory(); + +private: + const key_type key_; +}; + + } // namespace eckit::geo From 4233320ac43305903eab901e56cdd3df9eda2eca Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 12 May 2023 16:23:47 +0100 Subject: [PATCH 213/737] eckit::geo::Iterator --- src/eckit/geo/CMakeLists.txt | 2 + src/eckit/geo/Iterator.h | 10 +++++ src/eckit/geo/grib/RegularLL.cc | 36 +++++++++++++++ src/eckit/geo/grib/RegularLL.h | 77 +++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+) create mode 100644 src/eckit/geo/grib/RegularLL.cc create mode 100644 src/eckit/geo/grib/RegularLL.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index e2c28152f..ef67d5a51 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -10,6 +10,8 @@ list(APPEND eckit_geo_srcs Scanner.cc Scanner.h Search.h + grib/RegularLL.cc + grib/RegularLL.h iterator/IteratorAggregator.h iterator/IteratorComposer.cc iterator/IteratorComposer.h diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index 9a44e12c5..0f7489058 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -149,4 +149,14 @@ struct IteratorFactory { }; +template +class IteratorBuilder final : public IteratorFactory { + Iterator* make(const Configuration& config) override { return new T(config); } + +public: + explicit IteratorBuilder(const IteratorFactory::key_type& key) : + IteratorFactory(key) {} +}; + + } // namespace eckit::geo diff --git a/src/eckit/geo/grib/RegularLL.cc b/src/eckit/geo/grib/RegularLL.cc new file mode 100644 index 000000000..c52db7f8b --- /dev/null +++ b/src/eckit/geo/grib/RegularLL.cc @@ -0,0 +1,36 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grib/RegularLL.h" + + +namespace eckit::geo::grib { + + +static const IteratorBuilder __iterator("regular_ll"); + + +RegularLL::RegularLL(const Configuration&) { +} + + +size_t RegularLL::size() const { + return 0; +} + + +bool RegularLL::operator++() { + return false; +} + + +} // namespace eckit::geo::grib diff --git a/src/eckit/geo/grib/RegularLL.h b/src/eckit/geo/grib/RegularLL.h new file mode 100644 index 000000000..9d9bdfa0d --- /dev/null +++ b/src/eckit/geo/grib/RegularLL.h @@ -0,0 +1,77 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Iterator.h" + + +namespace eckit::geo::grib { + + +class RegularLL : public Iterator { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit RegularLL(const Configuration&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + bool operator++() override; + size_t size() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grib From 2d8f965a96d6697574dab7cbfda61e2676960e7d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 12 May 2023 23:14:20 +0100 Subject: [PATCH 214/737] eckit::geo::concept::BoundingBox --- src/eckit/geo/CMakeLists.txt | 4 ++-- src/eckit/geo/{ => concept}/BoundingBox.cc | 6 +++--- src/eckit/geo/{ => concept}/BoundingBox.h | 19 ++----------------- 3 files changed, 7 insertions(+), 22 deletions(-) rename src/eckit/geo/{ => concept}/BoundingBox.cc (97%) rename src/eckit/geo/{ => concept}/BoundingBox.h (96%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index ef67d5a51..bb2fb4866 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -1,6 +1,4 @@ list(APPEND eckit_geo_srcs - BoundingBox.cc - BoundingBox.h Iterator.cc Iterator.h Point.cc @@ -10,6 +8,8 @@ list(APPEND eckit_geo_srcs Scanner.cc Scanner.h Search.h + concept/BoundingBox.cc + concept/BoundingBox.h grib/RegularLL.cc grib/RegularLL.h iterator/IteratorAggregator.h diff --git a/src/eckit/geo/BoundingBox.cc b/src/eckit/geo/concept/BoundingBox.cc similarity index 97% rename from src/eckit/geo/BoundingBox.cc rename to src/eckit/geo/concept/BoundingBox.cc index d05091756..c7b403c76 100644 --- a/src/eckit/geo/BoundingBox.cc +++ b/src/eckit/geo/concept/BoundingBox.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/BoundingBox.h" +#include "eckit/geo/concept/BoundingBox.h" #include #include @@ -21,7 +21,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geo { +namespace eckit::geo::concept { BoundingBox::BoundingBox(double north, double west, double south, double east) : @@ -138,4 +138,4 @@ double BoundingBox::area(double radius) const { } -} // namespace eckit::geo +} // namespace eckit::geo::concepts diff --git a/src/eckit/geo/BoundingBox.h b/src/eckit/geo/concept/BoundingBox.h similarity index 96% rename from src/eckit/geo/BoundingBox.h rename to src/eckit/geo/concept/BoundingBox.h index 3cc7c9f2d..af4d6b52f 100644 --- a/src/eckit/geo/BoundingBox.h +++ b/src/eckit/geo/concept/BoundingBox.h @@ -13,7 +13,7 @@ #pragma once -namespace eckit::geo { +namespace eckit::geo::concept { class BoundingBox { @@ -24,11 +24,8 @@ class BoundingBox { // -- Constructors BoundingBox(double north, double west, double south, double east); - BoundingBox(); - BoundingBox(const BoundingBox&) = default; - BoundingBox(BoundingBox&&) = default; // -- Destructor @@ -41,33 +38,21 @@ class BoundingBox { // -- Operators BoundingBox& operator=(const BoundingBox&) = default; - BoundingBox& operator=(BoundingBox&&) = default; - bool operator==(const BoundingBox&) const; - bool operator!=(const BoundingBox& other) const { return !operator==(other); } // -- Methods double north() const { return north_; } - double west() const { return west_; } - double south() const { return south_; } - double east() const { return east_; } - bool isPeriodicWestEast() const; - bool contains(double lat, double lon) const; - bool contains(const BoundingBox&) const; - bool intersects(BoundingBox&) const; - bool empty() const; - double area(double radius) const; // -- Overridden methods @@ -123,4 +108,4 @@ class BoundingBox { }; -} // namespace eckit::geo +} // namespace eckit::geo::concepts From b946cecc332c56c902d583071038c8f7fcde6b24 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 15 May 2023 15:30:45 +0100 Subject: [PATCH 215/737] eckit::geometry --- src/eckit/geometry/EllipsoidOfRevolution.cc | 31 ++------- src/eckit/geometry/GreatCircle.cc | 50 ++++++--------- src/eckit/geometry/Sphere.cc | 71 ++++++++------------- src/eckit/geometry/UnitSphere.h | 9 +-- 4 files changed, 50 insertions(+), 111 deletions(-) diff --git a/src/eckit/geometry/EllipsoidOfRevolution.cc b/src/eckit/geometry/EllipsoidOfRevolution.cc index d1fec9d28..24dc711e5 100644 --- a/src/eckit/geometry/EllipsoidOfRevolution.cc +++ b/src/eckit/geometry/EllipsoidOfRevolution.cc @@ -11,8 +11,7 @@ #include "eckit/geometry/EllipsoidOfRevolution.h" #include -#include -// #include // for std::numeric_limits +#include #include #include "eckit/exception/Exceptions.h" @@ -25,28 +24,6 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- -namespace { - -static double normalise_longitude(double a, const double& minimum) { - while (a < minimum) { - a += 360; - } - while (a >= minimum + 360) { - a -= 360; - } - return a; -} - -static const double degrees_to_radians = M_PI / 180.; - -static std::streamsize max_digits10 = 15 + 3; - -// C++-11: std::numeric_limits::max_digits10; - -} // namespace - -//---------------------------------------------------------------------------------------------------------------------- - Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, double b, const PointLonLat& A, @@ -56,15 +33,17 @@ Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, if (!(-90. <= A.lat && A.lat <= 90.)) { std::ostringstream oss; - oss.precision(max_digits10); + oss.precision(std::numeric_limits::max_digits10); oss << "Invalid latitude " << A.lat; throw BadValue(oss.str(), Here()); } + static const double degrees_to_radians = M_PI / 180.; + // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) - const double lambda_deg = normalise_longitude(A.lon, -180.); + const double lambda_deg = PointLonLat::normalise_angle_to_minimum(A.lon, -180.); const double lambda = degrees_to_radians * lambda_deg; const double phi = degrees_to_radians * A.lat; diff --git a/src/eckit/geometry/GreatCircle.cc b/src/eckit/geometry/GreatCircle.cc index 4a99169c8..bd895faf6 100644 --- a/src/eckit/geometry/GreatCircle.cc +++ b/src/eckit/geometry/GreatCircle.cc @@ -23,45 +23,32 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- -static double normalise_longitude(double a, const double& minimum) { - while (a < minimum) { - a += 360; - } - while (a >= minimum + 360) { - a -= 360; - } - return a; -} +using types::is_approximately_equal; static const double radians_to_degrees = 180. * M_1_PI; static const double degrees_to_radians = M_PI / 180.; -static constexpr std::streamsize max_digits10 = std::numeric_limits::max_digits10; - static bool pole(const double lat) { - return types::is_approximately_equal(std::abs(lat), 90.); + return is_approximately_equal(std::abs(lat), 90.); } //---------------------------------------------------------------------------------------------------------------------- GreatCircle::GreatCircle(const PointLonLat& Alonlat, const PointLonLat& Blonlat) : A_(Alonlat), B_(Blonlat) { - using namespace std; - using types::is_approximately_equal; - const bool Apole = pole(A_.lat); const bool Bpole = pole(B_.lat); - const double lon12_deg = normalise_longitude(A_.lon - B_.lon, -180); + const double lon12_deg = PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); const bool lon_same = Apole || Bpole || is_approximately_equal(lon12_deg, 0.); - const bool lon_opposite = Apole || Bpole || is_approximately_equal(abs(lon12_deg), 180.); + const bool lon_opposite = Apole || Bpole || is_approximately_equal(std::abs(lon12_deg), 180.); const bool lat_same = is_approximately_equal(A_.lat, B_.lat); const bool lat_opposite = is_approximately_equal(A_.lat, -B_.lat); if ((lat_same && lon_same) || (lat_opposite && lon_opposite)) { - ostringstream oss; - oss.precision(max_digits10); + std::ostringstream oss; + oss.precision(std::numeric_limits::max_digits10); oss << "Great circle cannot be defined by points collinear with the centre, " << A_ << " and " << B_; throw BadValue(oss.str(), Here()); } @@ -70,8 +57,6 @@ GreatCircle::GreatCircle(const PointLonLat& Alonlat, const PointLonLat& Blonlat) } std::vector GreatCircle::latitude(double lon) const { - using namespace std; - if (crossesPoles()) { return {}; } @@ -80,36 +65,37 @@ std::vector GreatCircle::latitude(double lon) const { const double lat2 = degrees_to_radians * B_.lat; const double lambda1p = degrees_to_radians * (lon - A_.lon); const double lambda2p = degrees_to_radians * (lon - B_.lon); - const double lambda = degrees_to_radians * normalise_longitude(B_.lon - A_.lon, -180); + const double lambda = degrees_to_radians * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, -180.); - double lat = atan((tan(lat2) * sin(lambda1p) - tan(lat1) * sin(lambda2p)) / (sin(lambda))); + double lat = std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); return {radians_to_degrees * lat}; } std::vector GreatCircle::longitude(double lat) const { - using namespace std; - using types::is_approximately_equal; - if (crossesPoles()) { const double lon = pole(A_.lat) ? B_.lon : A_.lon; - return pole(lat) ? vector{lon} : vector{lon, lon + 180}; + if (pole(lat)) { + return {lon}; + } + + return {lon, lon + 180.}; } - const double lon12 = degrees_to_radians * normalise_longitude(A_.lon - B_.lon, -180); + const double lon12 = degrees_to_radians * PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); const double lon1 = degrees_to_radians * A_.lon; const double lat1 = degrees_to_radians * A_.lat; const double lat2 = degrees_to_radians * B_.lat; const double lat3 = degrees_to_radians * lat; - const double X = sin(lat1) * cos(lat2) * sin(lon12); - const double Y = sin(lat1) * cos(lat2) * cos(lon12) - cos(lat1) * sin(lat2); + const double X = std::sin(lat1) * std::cos(lat2) * std::sin(lon12); + const double Y = std::sin(lat1) * std::cos(lat2) * std::cos(lon12) - std::cos(lat1) * std::sin(lat2); if (is_approximately_equal(X, 0.) && is_approximately_equal(Y, 0.)) { return {}; // parallel (that is, equator) } const double lon0 = lon1 + atan2(Y, X); - const double C = cos(lat1) * cos(lat2) * tan(lat3) * sin(lon12) / sqrt(X * X + Y * Y); + const double C = std::cos(lat1) * std::cos(lat2) * std::tan(lat3) * std::sin(lon12) / std::sqrt(X * X + Y * Y); if (is_approximately_equal(C, -1.)) { return {radians_to_degrees * (lon0 + M_PI)}; @@ -120,7 +106,7 @@ std::vector GreatCircle::longitude(double lat) const { } if (-1 < C && C < 1) { - const double dlon = acos(C); + const double dlon = std::acos(C); return {radians_to_degrees * (lon0 - dlon + 2 * M_PI), radians_to_degrees * (lon0 + dlon)}; } diff --git a/src/eckit/geometry/Sphere.cc b/src/eckit/geometry/Sphere.cc index ca02f71ad..1c38f4d32 100644 --- a/src/eckit/geometry/Sphere.cc +++ b/src/eckit/geometry/Sphere.cc @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -28,21 +27,20 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- -static double normalise_longitude(double a, double minimum) { - while (a < minimum) { - a += 360; - } - while (a >= minimum + 360) { - a -= 360; - } - return a; -} +using types::is_approximately_equal; -static const double radians_to_degrees = 180. * M_1_PI; +static constexpr double radians_to_degrees = 180. * M_1_PI; -static const double degrees_to_radians = M_PI / 180.; +static constexpr double degrees_to_radians = M_PI / 180.; -static constexpr std::streamsize max_digits10 = std::numeric_limits::max_digits10; +void assert_latitude(double lat) { + if (!(-90. <= lat && lat <= 90.)) { + std::ostringstream oss; + oss.precision(std::numeric_limits::max_digits10); + oss << "Invalid latitude " << lat; + throw BadValue(oss.str(), Here()); + } +} inline double squared(double x) { return x * x; @@ -51,7 +49,8 @@ inline double squared(double x) { //---------------------------------------------------------------------------------------------------------------------- double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { - using namespace std; + assert_latitude(A.lat); + assert_latitude(B.lat); /* * Δσ = atan( ((cos(ϕ2) * sin(Δλ))^2 + (cos(ϕ1) * sin(ϕ2) - sin(ϕ1) * cos(ϕ2) * cos(Δλ))^2) / @@ -69,20 +68,6 @@ double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { * } */ - if (!(-90. <= A.lat && A.lat <= 90.)) { - ostringstream oss; - oss.precision(max_digits10); - oss << "Invalid latitude " << A.lat; - throw BadValue(oss.str(), Here()); - } - - if (!(-90. <= B.lat && B.lat <= 90.)) { - ostringstream oss; - oss.precision(max_digits10); - oss << "Invalid latitude " << B.lat; - throw BadValue(oss.str(), Here()); - } - const double phi1 = degrees_to_radians * A.lat; const double phi2 = degrees_to_radians * B.lat; const double lambda = degrees_to_radians * (B.lon - A.lon); @@ -94,10 +79,10 @@ double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { const double cos_lambda = cos(lambda); const double sin_lambda = sin(lambda); - const double angle = atan2(sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), - sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); + const double angle = std::atan2(std::sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), + sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); - if (types::is_approximately_equal(angle, 0.)) { + if (is_approximately_equal(angle, 0.)) { return 0.; } @@ -111,7 +96,7 @@ double Sphere::centralAngle(double radius, const Point3& A, const Point3& B) { // Δσ = 2 * asin( chord / 2 ) const double d2 = Point3::distance2(A, B); - if (types::is_approximately_equal(d2, 0.)) { + if (is_approximately_equal(d2, 0.)) { return 0.; } @@ -136,12 +121,14 @@ double Sphere::area(double radius) { double Sphere::area(double radius, const PointLonLat& WestNorth, const PointLonLat& EastSouth) { ASSERT(radius > 0.); + assert_latitude(WestNorth.lat); + assert_latitude(EastSouth.lat); // Set longitude fraction double W = WestNorth.lon; - double E = normalise_longitude(EastSouth.lon, W); - double longitude_range(types::is_approximately_equal(W, E) - && !types::is_approximately_equal(EastSouth.lon, WestNorth.lon) + double E = PointLonLat::normalise_angle_to_minimum(EastSouth.lon, W); + double longitude_range(is_approximately_equal(W, E) + && !is_approximately_equal(EastSouth.lon, WestNorth.lon) ? 360. : E - W); ASSERT(longitude_range <= 360.); @@ -151,7 +138,7 @@ double Sphere::area(double radius, const PointLonLat& WestNorth, const PointLonL // Set latitude fraction double N = WestNorth.lat; double S = EastSouth.lat; - ASSERT(-90. <= S && S <= N && N <= 90.); + ASSERT(S <= N); double latitude_fraction = 0.5 * (std::sin(degrees_to_radians * N) - std::sin(degrees_to_radians * S)); @@ -178,13 +165,7 @@ void Sphere::greatCircleLongitudeGivenLatitude( Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, double height) { ASSERT(radius > 0.); - - if (!(-90. <= A.lat && A.lat <= 90.)) { - std::ostringstream oss; - oss.precision(max_digits10); - oss << "Invalid latitude " << A.lat; - throw BadValue(oss.str(), Here()); - } + assert_latitude(A.lat); /* * See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates @@ -199,7 +180,7 @@ Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, * poles and quadrants. */ - const double lambda_deg = normalise_longitude(A.lon, -180.); + const double lambda_deg = PointLonLat::normalise_angle_to_minimum(A.lon, -180.); const double lambda = degrees_to_radians * lambda_deg; const double phi = degrees_to_radians * A.lat; @@ -220,7 +201,7 @@ PointLonLat Sphere::convertCartesianToSpherical(double radius, const Point3& A) // numerical conditioning for both z (poles) and y const double x = A[0]; - const double y = types::is_approximately_equal(A[1], 0.) ? 0. : A[1]; + const double y = is_approximately_equal(A[1], 0.) ? 0. : A[1]; const double z = std::min(radius, std::max(-radius, A[2])) / radius; return {radians_to_degrees * std::atan2(y, x), radians_to_degrees * std::asin(z)}; diff --git a/src/eckit/geometry/UnitSphere.h b/src/eckit/geometry/UnitSphere.h index 7a567255a..2c8fc317c 100644 --- a/src/eckit/geometry/UnitSphere.h +++ b/src/eckit/geometry/UnitSphere.h @@ -21,14 +21,7 @@ namespace eckit::geometry { /// Definition of a unit datum struct DatumUnit { - - /* C++-11: - static constexpr double radius() { - return 1.; - } - */ - - static double radius() { return 1.; } + static constexpr double radius() { return 1.; } }; //------------------------------------------------------------------------------------------------------ From f82b69547a68d91388087a538aa1a82b56bfc9bb Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 15 May 2023 16:47:33 +0100 Subject: [PATCH 216/737] eckit::geo::concept --- src/eckit/geo/CMakeLists.txt | 2 + src/eckit/geo/concept/BoundingBox.cc | 158 +++++++++++++-------------- src/eckit/geo/concept/BoundingBox.h | 132 +++++++++++----------- src/eckit/geo/concept/Range.cc | 26 +++++ src/eckit/geo/concept/Range.h | 97 ++++++++++++++++ 5 files changed, 270 insertions(+), 145 deletions(-) create mode 100644 src/eckit/geo/concept/Range.cc create mode 100644 src/eckit/geo/concept/Range.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index bb2fb4866..bcb5f8377 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -10,6 +10,8 @@ list(APPEND eckit_geo_srcs Search.h concept/BoundingBox.cc concept/BoundingBox.h + concept/Range.cc + concept/Range.h grib/RegularLL.cc grib/RegularLL.h iterator/IteratorAggregator.h diff --git a/src/eckit/geo/concept/BoundingBox.cc b/src/eckit/geo/concept/BoundingBox.cc index c7b403c76..08a5dd3f4 100644 --- a/src/eckit/geo/concept/BoundingBox.cc +++ b/src/eckit/geo/concept/BoundingBox.cc @@ -24,118 +24,118 @@ namespace eckit::geo::concept { -BoundingBox::BoundingBox(double north, double west, double south, double east) : - north_(north), west_(west), south_(south), east_(east) { - if (west_ != east_) { - auto e = PointLonLat::normalise_angle_to_minimum(east, west); - east_ = e == west_ ? (e + 360.) : e; + BoundingBox::BoundingBox(double north, double west, double south, double east) : + north_(north), west_(west), south_(south), east_(east) { + if (west_ != east_) { + auto e = PointLonLat::normalise_angle_to_minimum(east, west); + east_ = e == west_ ? (e + 360.) : e; + } + + ASSERT_MSG(west_ <= east_ && east_ <= west_ + 360., "BoundingBox: longitude range"); + ASSERT_MSG(-90. <= south_ && south_ <= north_ && north_ <= 90., "BoundingBox: latitude range"); } - ASSERT_MSG(west_ <= east_ && east_ <= west_ + 360., "BoundingBox: longitude range"); - ASSERT_MSG(-90. <= south_ && south_ <= north_ && north_ <= 90., "BoundingBox: latitude range"); -} + BoundingBox::BoundingBox() : + BoundingBox(90., 0., -90., 360.) {} -BoundingBox::BoundingBox() : - BoundingBox(90., 0., -90., 360.) {} + bool BoundingBox::operator==(const BoundingBox& other) const { + return north_ == other.north_ && south_ == other.south_ && west_ == other.west_ && east_ == other.east_; + } -bool BoundingBox::operator==(const BoundingBox& other) const { - return north_ == other.north_ && south_ == other.south_ && west_ == other.west_ && east_ == other.east_; -} + bool BoundingBox::isPeriodicWestEast() const { + return west_ != east_ && west_ == PointLonLat::normalise_angle_to_minimum(east_, west_); + } -bool BoundingBox::isPeriodicWestEast() const { - return west_ != east_ && west_ == PointLonLat::normalise_angle_to_minimum(east_, west_); -} + bool BoundingBox::contains(double lat, double lon) const { + return lat <= north_ && lat >= south_ && PointLonLat::normalise_angle_to_minimum(lon, west_) <= east_; + } -bool BoundingBox::contains(double lat, double lon) const { - return lat <= north_ && lat >= south_ && PointLonLat::normalise_angle_to_minimum(lon, west_) <= east_; -} + bool BoundingBox::contains(const BoundingBox& other) const { + if (other.empty()) { + return contains(other.south_, other.west_); + } -bool BoundingBox::contains(const BoundingBox& other) const { - if (other.empty()) { - return contains(other.south_, other.west_); - } + // check for West/East range (if non-periodic), then other's corners + if (east_ - west_ < other.east_ - other.west_ || east_ < PointLonLat::normalise_angle_to_minimum(other.east_, west_)) { + return false; + } - // check for West/East range (if non-periodic), then other's corners - if (east_ - west_ < other.east_ - other.west_ || east_ < PointLonLat::normalise_angle_to_minimum(other.east_, west_)) { - return false; + return contains(other.north_, other.west_) && contains(other.north_, other.east_) && contains(other.south_, other.west_) && contains(other.south_, other.east_); } - return contains(other.north_, other.west_) && contains(other.north_, other.east_) && contains(other.south_, other.west_) && contains(other.south_, other.east_); -} - -bool BoundingBox::intersects(BoundingBox& other) const { - auto n = std::min(north_, other.north_); - auto s = std::max(south_, other.south_); + bool BoundingBox::intersects(BoundingBox & other) const { + auto n = std::min(north_, other.north_); + auto s = std::max(south_, other.south_); - bool intersectsSN = s <= n; - if (!intersectsSN) { - n = s; - } + bool intersectsSN = s <= n; + if (!intersectsSN) { + n = s; + } - if (isPeriodicWestEast() && other.isPeriodicWestEast()) { - other = {n, other.west_, s, other.east_}; - return intersectsSN; - } + if (isPeriodicWestEast() && other.isPeriodicWestEast()) { + other = {n, other.west_, s, other.east_}; + return intersectsSN; + } - auto w = std::min(west_, other.west_); - auto e = w; + auto w = std::min(west_, other.west_); + auto e = w; - auto intersect = [](const BoundingBox& a, const BoundingBox& b, double& w, double& e) { - bool p = a.isPeriodicWestEast(); - if (p || b.isPeriodicWestEast()) { - w = (p ? b : a).west_; - e = (p ? b : a).east_; - return true; - } + auto intersect = [](const BoundingBox& a, const BoundingBox& b, double& w, double& e) { + bool p = a.isPeriodicWestEast(); + if (p || b.isPeriodicWestEast()) { + w = (p ? b : a).west_; + e = (p ? b : a).east_; + return true; + } - auto ref = PointLonLat::normalise_angle_to_minimum(b.west_, a.west_); - auto w_ = std::max(a.west_, ref); - auto e_ = std::min(a.east_, PointLonLat::normalise_angle_to_minimum(b.east_, ref)); + auto ref = PointLonLat::normalise_angle_to_minimum(b.west_, a.west_); + auto w_ = std::max(a.west_, ref); + auto e_ = std::min(a.east_, PointLonLat::normalise_angle_to_minimum(b.east_, ref)); - if (w_ <= e_) { - w = w_; - e = e_; - return true; - } + if (w_ <= e_) { + w = w_; + e = e_; + return true; + } - return false; - }; + return false; + }; - bool intersectsWE = west_ <= other.west_ ? intersect(*this, other, w, e) || intersect(other, *this, w, e) - : intersect(other, *this, w, e) || intersect(*this, other, w, e); + bool intersectsWE = west_ <= other.west_ ? intersect(*this, other, w, e) || intersect(other, *this, w, e) + : intersect(other, *this, w, e) || intersect(*this, other, w, e); - ASSERT_MSG(w <= e, "BoundingBox::intersects: longitude range"); - other = {n, w, s, e}; + ASSERT_MSG(w <= e, "BoundingBox::intersects: longitude range"); + other = {n, w, s, e}; - return intersectsSN && intersectsWE; -} + return intersectsSN && intersectsWE; + } -bool BoundingBox::empty() const { - return types::is_approximately_equal(north_, south_) || types::is_approximately_equal(west_, east_); -} + bool BoundingBox::empty() const { + return types::is_approximately_equal(north_, south_) || types::is_approximately_equal(west_, east_); + } -double BoundingBox::area(double radius) const { - double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); - ASSERT(0. <= lonf && lonf <= 1.); + double BoundingBox::area(double radius) const { + double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); + ASSERT(0. <= lonf && lonf <= 1.); - constexpr auto degrees_to_radians = M_PI / 180.; + constexpr auto degrees_to_radians = M_PI / 180.; - const auto sn = std::sin(north_ * degrees_to_radians); - const auto ss = std::sin(south_ * degrees_to_radians); + const auto sn = std::sin(north_ * degrees_to_radians); + const auto ss = std::sin(south_ * degrees_to_radians); - double latf = 0.5 * (sn - ss); - ASSERT(0. <= latf && latf <= 1.); + double latf = 0.5 * (sn - ss); + ASSERT(0. <= latf && latf <= 1.); - return geometry::Sphere::area(radius) * latf * lonf; -} + return geometry::Sphere::area(radius) * latf * lonf; + } -} // namespace eckit::geo::concepts +} // namespace eckit::geo::concept diff --git a/src/eckit/geo/concept/BoundingBox.h b/src/eckit/geo/concept/BoundingBox.h index af4d6b52f..0411e79ce 100644 --- a/src/eckit/geo/concept/BoundingBox.h +++ b/src/eckit/geo/concept/BoundingBox.h @@ -16,96 +16,96 @@ namespace eckit::geo::concept { -class BoundingBox { -public: - // -- Exceptions - // None + class BoundingBox { + public: + // -- Exceptions + // None - // -- Constructors + // -- Constructors - BoundingBox(double north, double west, double south, double east); - BoundingBox(); - BoundingBox(const BoundingBox&) = default; - BoundingBox(BoundingBox&&) = default; + BoundingBox(double north, double west, double south, double east); + BoundingBox(); + BoundingBox(const BoundingBox&) = default; + BoundingBox(BoundingBox&&) = default; - // -- Destructor + // -- Destructor - virtual ~BoundingBox() = default; + virtual ~BoundingBox() = default; - // -- Convertors - // None + // -- Convertors + // None - // -- Operators + // -- Operators - BoundingBox& operator=(const BoundingBox&) = default; - BoundingBox& operator=(BoundingBox&&) = default; - bool operator==(const BoundingBox&) const; - bool operator!=(const BoundingBox& other) const { return !operator==(other); } + BoundingBox& operator=(const BoundingBox&) = default; + BoundingBox& operator=(BoundingBox&&) = default; + bool operator==(const BoundingBox&) const; + bool operator!=(const BoundingBox& other) const { return !operator==(other); } - // -- Methods + // -- Methods - double north() const { return north_; } - double west() const { return west_; } - double south() const { return south_; } - double east() const { return east_; } - bool isPeriodicWestEast() const; - bool contains(double lat, double lon) const; - bool contains(const BoundingBox&) const; - bool intersects(BoundingBox&) const; - bool empty() const; - double area(double radius) const; + double north() const { return north_; } + double west() const { return west_; } + double south() const { return south_; } + double east() const { return east_; } + bool isPeriodicWestEast() const; + bool contains(double lat, double lon) const; + bool contains(const BoundingBox&) const; + bool intersects(BoundingBox&) const; + bool empty() const; + double area(double radius) const; - // -- Overridden methods - // None + // -- Overridden methods + // None - // -- Class members - // None + // -- Class members + // None - // -- Class methods - // None + // -- Class methods + // None -protected: - // -- Members - // None + protected: + // -- Members + // None - // -- Methods - // None + // -- Methods + // None - // -- Overridden methods - // None + // -- Overridden methods + // None - // -- Class members - // None + // -- Class members + // None - // -- Class methods - // None + // -- Class methods + // None - // -- Friends - // None + // -- Friends + // None -private: - // -- Members + private: + // -- Members - double north_; - double west_; - double south_; - double east_; + double north_; + double west_; + double south_; + double east_; - // -- Methods - // None + // -- Methods + // None - // -- Overridden methods - // None + // -- Overridden methods + // None - // -- Class members - // None + // -- Class members + // None - // -- Class methods - // None + // -- Class methods + // None - // -- Friends - // None -}; + // -- Friends + // None + }; -} // namespace eckit::geo::concepts +} // namespace eckit::geo::concept diff --git a/src/eckit/geo/concept/Range.cc b/src/eckit/geo/concept/Range.cc new file mode 100644 index 000000000..d65f843b9 --- /dev/null +++ b/src/eckit/geo/concept/Range.cc @@ -0,0 +1,26 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/concept/Range.h" + +// #include <> + + +namespace eckit::geo::concept { + + + Range::Range(size_t N, double a, double b, double inc, double ref) : + N_(N) { + } + + +} // namespace eckit::geo::concept diff --git a/src/eckit/geo/concept/Range.h b/src/eckit/geo/concept/Range.h new file mode 100644 index 000000000..214cd61f0 --- /dev/null +++ b/src/eckit/geo/concept/Range.h @@ -0,0 +1,97 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + + +namespace eckit::geo::concept { + + + class Range { + public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + Range(size_t N, double a, double b, double inc, double ref); + + Range(size_t N, double a, double b, double inc) : + Range(N, a, b, inc, a) {} + + // -- Destructor + + virtual ~Range() = default; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + size_t size() const { return N_; } + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + private: + // -- Members + + const size_t N_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None + }; + + +} // namespace eckit::geo::concept From 06e6c5fecb4253b7d19a387a7e0b26f5d69c3991 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 15 May 2023 17:24:52 +0100 Subject: [PATCH 217/737] eckit::geo::concept --- src/eckit/geo/concept/Range.cc | 62 ++++++++++++++++++++++++++++++++-- src/eckit/geo/concept/Range.h | 20 +++++++---- 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/src/eckit/geo/concept/Range.cc b/src/eckit/geo/concept/Range.cc index d65f843b9..8d6eb590c 100644 --- a/src/eckit/geo/concept/Range.cc +++ b/src/eckit/geo/concept/Range.cc @@ -12,15 +12,71 @@ #include "eckit/geo/concept/Range.h" -// #include <> +#include "eckit/exception/Exceptions.h" +#include "eckit/types/Fraction.h" namespace eckit::geo::concept { - Range::Range(size_t N, double a, double b, double inc, double ref) : - N_(N) { + namespace { + + + eckit::Fraction adjust(const eckit::Fraction& target, const eckit::Fraction& inc, bool up) { + ASSERT(inc > 0); + + auto r = target / inc; + auto n = r.integralPart(); + + if (!r.integer() && (r > 0) == up) { + n += (up ? 1 : -1); + } + + return (n * inc); + } + + + } // namespace + + + Range::Range(double _a, double _b, double _inc, double _ref) { + ASSERT(_a <= _b); + ASSERT(0 <= _inc); + + const eckit::Fraction a(_a); + const eckit::Fraction b(_b); + const eckit::Fraction inc(_inc); + const eckit::Fraction ref(_ref); + + + if (inc == 0) { + b_ = a_ = a; + n_ = 1; + return; + } + + auto shift = (ref / inc).decimalPart() * inc; + a_ = shift + adjust(a - shift, inc, true); + + if (b == a) { + b_ = a_; + } + else { + + auto c = shift + adjust(b - shift, inc, false); + c = a_ + ((c - a_) / inc).integralPart() * inc; + b_ = c < a_ ? a_ : c; + } + + n_ = static_cast(((b_ - a_) / inc).integralPart() + 1); + + ASSERT(a_ <= b_); + ASSERT(n_ >= 1); } + Range::Range(double a, double b, double inc) : + Range(a, b, inc, a) {} + + } // namespace eckit::geo::concept diff --git a/src/eckit/geo/concept/Range.h b/src/eckit/geo/concept/Range.h index 214cd61f0..86ccff12c 100644 --- a/src/eckit/geo/concept/Range.h +++ b/src/eckit/geo/concept/Range.h @@ -28,10 +28,12 @@ namespace eckit::geo::concept { // -- Constructors - Range(size_t N, double a, double b, double inc, double ref); + Range(double a, double b, double inc, double ref); - Range(size_t N, double a, double b, double inc) : - Range(N, a, b, inc, a) {} + Range(double a, double b, double inc); + + Range(const Range&) = delete; + Range(Range&&) = delete; // -- Destructor @@ -41,11 +43,15 @@ namespace eckit::geo::concept { // None // -- Operators - // None + + Range& operator=(const Range&) = delete; + Range& operator=(Range&&) = delete; // -- Methods - size_t size() const { return N_; } + size_t n() const { return n_; } + double a() const { return a_; } + double b() const { return b_; } // -- Overridden methods // None @@ -75,7 +81,9 @@ namespace eckit::geo::concept { private: // -- Members - const size_t N_; + size_t n_; + double a_; + double b_; // -- Methods // None From 561016bb9e74442fa521ca9b636dda0d5ca0ec27 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 15 May 2023 17:32:53 +0100 Subject: [PATCH 218/737] eckit::geo::concept --- src/eckit/geo/concept/Range.cc | 23 ++++++++++++++--------- src/eckit/geo/concept/Range.h | 3 +-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/eckit/geo/concept/Range.cc b/src/eckit/geo/concept/Range.cc index 8d6eb590c..081abbaf1 100644 --- a/src/eckit/geo/concept/Range.cc +++ b/src/eckit/geo/concept/Range.cc @@ -19,10 +19,7 @@ namespace eckit::geo::concept { - namespace { - - - eckit::Fraction adjust(const eckit::Fraction& target, const eckit::Fraction& inc, bool up) { + static eckit::Fraction adjust(const eckit::Fraction& target, const eckit::Fraction& inc, bool up) { ASSERT(inc > 0); auto r = target / inc; @@ -36,7 +33,19 @@ namespace eckit::geo::concept { } - } // namespace + Range::Range(double _a, double _b, double _inc, double _ref, double period) : + Range(_a, _b, _inc, _ref) { + ASSERT(0 < period); + + const eckit::Fraction inc(_inc); + + if ((n_ - 1) * inc >= period) { + n_ -= 1; + ASSERT(n_ * inc == period || (n_ - 1) * inc < period); + + b_ = a_ + (n_ - 1) * inc; + } + } Range::Range(double _a, double _b, double _inc, double _ref) { @@ -75,8 +84,4 @@ namespace eckit::geo::concept { } - Range::Range(double a, double b, double inc) : - Range(a, b, inc, a) {} - - } // namespace eckit::geo::concept diff --git a/src/eckit/geo/concept/Range.h b/src/eckit/geo/concept/Range.h index 86ccff12c..f6bd067e5 100644 --- a/src/eckit/geo/concept/Range.h +++ b/src/eckit/geo/concept/Range.h @@ -28,10 +28,9 @@ namespace eckit::geo::concept { // -- Constructors + Range(double a, double b, double inc, double ref, double period); Range(double a, double b, double inc, double ref); - Range(double a, double b, double inc); - Range(const Range&) = delete; Range(Range&&) = delete; From 8cfdab9e22f32801f7f382293b2b520d18a3cce9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 15 May 2023 17:46:21 +0100 Subject: [PATCH 219/737] eckit::geo::concept --- src/eckit/geo/concept/Range.cc | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/eckit/geo/concept/Range.cc b/src/eckit/geo/concept/Range.cc index 081abbaf1..aef99c67a 100644 --- a/src/eckit/geo/concept/Range.cc +++ b/src/eckit/geo/concept/Range.cc @@ -13,6 +13,7 @@ #include "eckit/geo/concept/Range.h" #include "eckit/exception/Exceptions.h" +#include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" @@ -49,38 +50,32 @@ namespace eckit::geo::concept { Range::Range(double _a, double _b, double _inc, double _ref) { - ASSERT(_a <= _b); ASSERT(0 <= _inc); + if (types::is_approximately_equal(_inc, 0.) || types::is_approximately_equal(_a, _b)) { + a_ = b_ = _ref; + n_ = 1; + return; + } + + ASSERT(_a <= _b); // FIXME remove + const eckit::Fraction a(_a); const eckit::Fraction b(_b); const eckit::Fraction inc(_inc); const eckit::Fraction ref(_ref); - - if (inc == 0) { - b_ = a_ = a; - n_ = 1; - return; - } - auto shift = (ref / inc).decimalPart() * inc; a_ = shift + adjust(a - shift, inc, true); - if (b == a) { - b_ = a_; - } - else { - - auto c = shift + adjust(b - shift, inc, false); - c = a_ + ((c - a_) / inc).integralPart() * inc; - b_ = c < a_ ? a_ : c; - } + auto c = shift + adjust(b - shift, inc, false); + c = a_ + ((c - a_) / inc).integralPart() * inc; + b_ = c < a_ ? a_ : c; n_ = static_cast(((b_ - a_) / inc).integralPart() + 1); ASSERT(a_ <= b_); - ASSERT(n_ >= 1); + ASSERT(1 <= n_); } From 924ad5049dd184eda0d20aac57064c012720fa91 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 15 May 2023 17:50:17 +0100 Subject: [PATCH 220/737] eckit::geo::concept --- src/eckit/geo/concept/Range.cc | 34 +++++++++++++++++----------------- src/eckit/geo/concept/Range.h | 3 +++ 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/eckit/geo/concept/Range.cc b/src/eckit/geo/concept/Range.cc index aef99c67a..954f2045a 100644 --- a/src/eckit/geo/concept/Range.cc +++ b/src/eckit/geo/concept/Range.cc @@ -14,13 +14,13 @@ #include "eckit/exception/Exceptions.h" #include "eckit/types/FloatCompare.h" -#include "eckit/types/Fraction.h" namespace eckit::geo::concept { - static eckit::Fraction adjust(const eckit::Fraction& target, const eckit::Fraction& inc, bool up) { + static Fraction adjust(const Fraction& target, const Fraction& inc, bool up) + { ASSERT(inc > 0); auto r = target / inc; @@ -38,13 +38,11 @@ namespace eckit::geo::concept { Range(_a, _b, _inc, _ref) { ASSERT(0 < period); - const eckit::Fraction inc(_inc); - - if ((n_ - 1) * inc >= period) { + if ((n_ - 1) * inc_ >= period) { n_ -= 1; - ASSERT(n_ * inc == period || (n_ - 1) * inc < period); + ASSERT(n_ * inc_ == period || (n_ - 1) * inc_ < period); - b_ = a_ + (n_ - 1) * inc; + b_ = a_ + (n_ - 1) * inc_; } } @@ -55,24 +53,26 @@ namespace eckit::geo::concept { if (types::is_approximately_equal(_inc, 0.) || types::is_approximately_equal(_a, _b)) { a_ = b_ = _ref; n_ = 1; + inc_ = Fraction{0}; return; } - ASSERT(_a <= _b); // FIXME remove + ASSERT(_a <= _b); // FIXME remove + + inc_ = Fraction{_inc}; - const eckit::Fraction a(_a); - const eckit::Fraction b(_b); - const eckit::Fraction inc(_inc); - const eckit::Fraction ref(_ref); + const Fraction a(_a); + const Fraction b(_b); + const Fraction ref(_ref); - auto shift = (ref / inc).decimalPart() * inc; - a_ = shift + adjust(a - shift, inc, true); + auto shift = (ref / inc_).decimalPart() * inc_; + a_ = shift + adjust(a - shift, inc_, true); - auto c = shift + adjust(b - shift, inc, false); - c = a_ + ((c - a_) / inc).integralPart() * inc; + auto c = shift + adjust(b - shift, inc_, false); + c = a_ + ((c - a_) / inc_).integralPart() * inc_; b_ = c < a_ ? a_ : c; - n_ = static_cast(((b_ - a_) / inc).integralPart() + 1); + n_ = static_cast(((b_ - a_) / inc_).integralPart() + 1); ASSERT(a_ <= b_); ASSERT(1 <= n_); diff --git a/src/eckit/geo/concept/Range.h b/src/eckit/geo/concept/Range.h index f6bd067e5..b6b222876 100644 --- a/src/eckit/geo/concept/Range.h +++ b/src/eckit/geo/concept/Range.h @@ -14,6 +14,8 @@ #include +#include "eckit/types/Fraction.h" + namespace eckit::geo::concept { @@ -83,6 +85,7 @@ namespace eckit::geo::concept { size_t n_; double a_; double b_; + Fraction inc_; // -- Methods // None From fe81710fedfbbd9c6d539242f01e6ab853c148b1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 15 May 2023 20:36:34 +0100 Subject: [PATCH 221/737] eckit::geo::concept --- src/eckit/geo/concept/Range.cc | 37 ++++++++++++++++++++++++++++------ src/eckit/geo/concept/Range.h | 4 +++- 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/eckit/geo/concept/Range.cc b/src/eckit/geo/concept/Range.cc index 954f2045a..55c851731 100644 --- a/src/eckit/geo/concept/Range.cc +++ b/src/eckit/geo/concept/Range.cc @@ -16,11 +16,15 @@ #include "eckit/types/FloatCompare.h" +namespace eckit::geo::util { +std::vector arange(double start, double stop, double step); +} + + namespace eckit::geo::concept { - static Fraction adjust(const Fraction& target, const Fraction& inc, bool up) - { + static Fraction adjust(const Fraction& target, const Fraction& inc, bool up) { ASSERT(inc > 0); auto r = target / inc; @@ -53,11 +57,11 @@ namespace eckit::geo::concept { if (types::is_approximately_equal(_inc, 0.) || types::is_approximately_equal(_a, _b)) { a_ = b_ = _ref; n_ = 1; - inc_ = Fraction{0}; + inc_ = Fraction{0}; return; } - ASSERT(_a <= _b); // FIXME remove + ASSERT(_a <= _b); // FIXME remove inc_ = Fraction{_inc}; @@ -66,10 +70,10 @@ namespace eckit::geo::concept { const Fraction ref(_ref); auto shift = (ref / inc_).decimalPart() * inc_; - a_ = shift + adjust(a - shift, inc_, true); + a_ = shift + adjust(a - shift, inc_, true); auto c = shift + adjust(b - shift, inc_, false); - c = a_ + ((c - a_) / inc_).integralPart() * inc_; + c = a_ + ((c - a_) / inc_).integralPart() * inc_; b_ = c < a_ ? a_ : c; n_ = static_cast(((b_ - a_) / inc_).integralPart() + 1); @@ -79,4 +83,25 @@ namespace eckit::geo::concept { } + std::vector Range::to_vector() const { + if (inc_ == 0) { + std::vector l(1, a_); + return l; + } + + double step = inc_; + + const auto num = static_cast((b_ - a_) / step) + 1; + + std::vector l(num); + std::generate_n(l.begin(), num, [this, n = 0]() mutable { + auto delta_num = static_cast(n++) * inc_.numerator(); + auto delta_den = inc_.denominator(); + return a_ + static_cast(delta_num) / static_cast(delta_den); + }); + + return l; + } + + } // namespace eckit::geo::concept diff --git a/src/eckit/geo/concept/Range.h b/src/eckit/geo/concept/Range.h index b6b222876..08ad0bd38 100644 --- a/src/eckit/geo/concept/Range.h +++ b/src/eckit/geo/concept/Range.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include "eckit/types/Fraction.h" @@ -54,6 +54,8 @@ namespace eckit::geo::concept { double a() const { return a_; } double b() const { return b_; } + std::vector to_vector() const; + // -- Overridden methods // None From 275da7f6a481460353cf54100790c8ef5349e66e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 May 2023 15:43:38 +0100 Subject: [PATCH 222/737] eckit::geo --- src/eckit/geo/BoundingBox.cc | 141 +++++++++++++++++++++++++++ src/eckit/geo/BoundingBox.h | 111 +++++++++++++++++++++ src/eckit/geo/CMakeLists.txt | 98 +++++++++---------- src/eckit/geo/Range.cc | 107 ++++++++++++++++++++ src/eckit/geo/Range.h | 109 +++++++++++++++++++++ src/eckit/geo/concept/BoundingBox.cc | 141 --------------------------- src/eckit/geo/concept/BoundingBox.h | 111 --------------------- src/eckit/geo/concept/Range.cc | 107 -------------------- src/eckit/geo/concept/Range.h | 109 --------------------- 9 files changed, 517 insertions(+), 517 deletions(-) create mode 100644 src/eckit/geo/BoundingBox.cc create mode 100644 src/eckit/geo/BoundingBox.h create mode 100644 src/eckit/geo/Range.cc create mode 100644 src/eckit/geo/Range.h delete mode 100644 src/eckit/geo/concept/BoundingBox.cc delete mode 100644 src/eckit/geo/concept/BoundingBox.h delete mode 100644 src/eckit/geo/concept/Range.cc delete mode 100644 src/eckit/geo/concept/Range.h diff --git a/src/eckit/geo/BoundingBox.cc b/src/eckit/geo/BoundingBox.cc new file mode 100644 index 000000000..d05091756 --- /dev/null +++ b/src/eckit/geo/BoundingBox.cc @@ -0,0 +1,141 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/BoundingBox.h" + +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/Point.h" +#include "eckit/geometry/Sphere.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo { + + +BoundingBox::BoundingBox(double north, double west, double south, double east) : + north_(north), west_(west), south_(south), east_(east) { + if (west_ != east_) { + auto e = PointLonLat::normalise_angle_to_minimum(east, west); + east_ = e == west_ ? (e + 360.) : e; + } + + ASSERT_MSG(west_ <= east_ && east_ <= west_ + 360., "BoundingBox: longitude range"); + ASSERT_MSG(-90. <= south_ && south_ <= north_ && north_ <= 90., "BoundingBox: latitude range"); +} + + +BoundingBox::BoundingBox() : + BoundingBox(90., 0., -90., 360.) {} + + +bool BoundingBox::operator==(const BoundingBox& other) const { + return north_ == other.north_ && south_ == other.south_ && west_ == other.west_ && east_ == other.east_; +} + + +bool BoundingBox::isPeriodicWestEast() const { + return west_ != east_ && west_ == PointLonLat::normalise_angle_to_minimum(east_, west_); +} + + +bool BoundingBox::contains(double lat, double lon) const { + return lat <= north_ && lat >= south_ && PointLonLat::normalise_angle_to_minimum(lon, west_) <= east_; +} + + +bool BoundingBox::contains(const BoundingBox& other) const { + if (other.empty()) { + return contains(other.south_, other.west_); + } + + // check for West/East range (if non-periodic), then other's corners + if (east_ - west_ < other.east_ - other.west_ || east_ < PointLonLat::normalise_angle_to_minimum(other.east_, west_)) { + return false; + } + + return contains(other.north_, other.west_) && contains(other.north_, other.east_) && contains(other.south_, other.west_) && contains(other.south_, other.east_); +} + + +bool BoundingBox::intersects(BoundingBox& other) const { + auto n = std::min(north_, other.north_); + auto s = std::max(south_, other.south_); + + bool intersectsSN = s <= n; + if (!intersectsSN) { + n = s; + } + + if (isPeriodicWestEast() && other.isPeriodicWestEast()) { + other = {n, other.west_, s, other.east_}; + return intersectsSN; + } + + auto w = std::min(west_, other.west_); + auto e = w; + + auto intersect = [](const BoundingBox& a, const BoundingBox& b, double& w, double& e) { + bool p = a.isPeriodicWestEast(); + if (p || b.isPeriodicWestEast()) { + w = (p ? b : a).west_; + e = (p ? b : a).east_; + return true; + } + + auto ref = PointLonLat::normalise_angle_to_minimum(b.west_, a.west_); + auto w_ = std::max(a.west_, ref); + auto e_ = std::min(a.east_, PointLonLat::normalise_angle_to_minimum(b.east_, ref)); + + if (w_ <= e_) { + w = w_; + e = e_; + return true; + } + + return false; + }; + + bool intersectsWE = west_ <= other.west_ ? intersect(*this, other, w, e) || intersect(other, *this, w, e) + : intersect(other, *this, w, e) || intersect(*this, other, w, e); + + ASSERT_MSG(w <= e, "BoundingBox::intersects: longitude range"); + other = {n, w, s, e}; + + return intersectsSN && intersectsWE; +} + + +bool BoundingBox::empty() const { + return types::is_approximately_equal(north_, south_) || types::is_approximately_equal(west_, east_); +} + + +double BoundingBox::area(double radius) const { + double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); + ASSERT(0. <= lonf && lonf <= 1.); + + constexpr auto degrees_to_radians = M_PI / 180.; + + const auto sn = std::sin(north_ * degrees_to_radians); + const auto ss = std::sin(south_ * degrees_to_radians); + + double latf = 0.5 * (sn - ss); + ASSERT(0. <= latf && latf <= 1.); + + return geometry::Sphere::area(radius) * latf * lonf; +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/BoundingBox.h b/src/eckit/geo/BoundingBox.h new file mode 100644 index 000000000..86eb814c8 --- /dev/null +++ b/src/eckit/geo/BoundingBox.h @@ -0,0 +1,111 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + + +namespace eckit::geo { + + +class BoundingBox { +public: + // -- Exceptions + // None + + // -- Constructors + + BoundingBox(double north, double west, double south, double east); + BoundingBox(); + BoundingBox(const BoundingBox&) = default; + BoundingBox(BoundingBox&&) = default; + + // -- Destructor + + virtual ~BoundingBox() = default; + + // -- Convertors + // None + + // -- Operators + + BoundingBox& operator=(const BoundingBox&) = default; + BoundingBox& operator=(BoundingBox&&) = default; + bool operator==(const BoundingBox&) const; + bool operator!=(const BoundingBox& other) const { return !operator==(other); } + + // -- Methods + + double north() const { return north_; } + double west() const { return west_; } + double south() const { return south_; } + double east() const { return east_; } + bool isPeriodicWestEast() const; + bool contains(double lat, double lon) const; + bool contains(const BoundingBox&) const; + bool intersects(BoundingBox&) const; + bool empty() const; + double area(double radius) const; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None + +private: + // -- Members + + double north_; + double west_; + double south_; + double east_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index bcb5f8377..080569b83 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -1,61 +1,61 @@ list(APPEND eckit_geo_srcs - Iterator.cc - Iterator.h - Point.cc - Point.h - Projection.cc - Projection.h - Scanner.cc - Scanner.h - Search.h - concept/BoundingBox.cc - concept/BoundingBox.h - concept/Range.cc - concept/Range.h - grib/RegularLL.cc - grib/RegularLL.h - iterator/IteratorAggregator.h - iterator/IteratorComposer.cc - iterator/IteratorComposer.h - projection/LonLatToXYZ.cc - projection/LonLatToXYZ.h - projection/None.cc - projection/None.h - projection/Rotation.cc - projection/Rotation.h - scanner/Reduced.cc - scanner/Reduced.h - scanner/Regular.cc - scanner/Regular.h - scanner/Unstructured.cc - scanner/Unstructured.h - util.cc - util.h - util/arange.cc - util/gaussian_latitudes.cc - util/linspace.cc - util/monotonic_crop.cc - util/reduced_classical_pl.cc - util/reduced_octahedral_pl.cc - util/regular_pl.cc + BoundingBox.cc + BoundingBox.h + Iterator.cc + Iterator.h + Point.cc + Point.h + Projection.cc + Projection.h + Range.cc + Range.h + Scanner.cc + Scanner.h + Search.h + grib/RegularLL.cc + grib/RegularLL.h + iterator/IteratorAggregator.h + iterator/IteratorComposer.cc + iterator/IteratorComposer.h + projection/LonLatToXYZ.cc + projection/LonLatToXYZ.h + projection/None.cc + projection/None.h + projection/Rotation.cc + projection/Rotation.h + scanner/Reduced.cc + scanner/Reduced.h + scanner/Regular.cc + scanner/Regular.h + scanner/Unstructured.cc + scanner/Unstructured.h + util.cc + util.h + util/arange.cc + util/gaussian_latitudes.cc + util/linspace.cc + util/monotonic_crop.cc + util/reduced_classical_pl.cc + util/reduced_octahedral_pl.cc + util/regular_pl.cc ) set(eckit_geo_include_dirs ) set(eckit_geo_libs eckit_geometry eckit_maths) if(HAVE_PROJ) - list(APPEND eckit_geo_srcs projection/PROJ.cc projection/PROJ.h) - list(APPEND eckit_geo_libs PROJ::proj) - list(APPEND eckit_geo_include_dirs ${PROJ_INCLUDE_DIRS}) + list(APPEND eckit_geo_srcs projection/PROJ.cc projection/PROJ.h) + list(APPEND eckit_geo_libs PROJ::proj) + list(APPEND eckit_geo_include_dirs ${PROJ_INCLUDE_DIRS}) endif() ecbuild_add_library( - TARGET eckit_geo - TYPE SHARED - INSTALL_HEADERS ALL - HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geo - SOURCES ${eckit_geo_srcs} - PUBLIC_LIBS ${eckit_geo_libs} - PUBLIC_INCLUDES ${eckit_geo_include_dirs} + TARGET eckit_geo + TYPE SHARED + INSTALL_HEADERS ALL + HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geo + SOURCES ${eckit_geo_srcs} + PUBLIC_LIBS ${eckit_geo_libs} + PUBLIC_INCLUDES ${eckit_geo_include_dirs} ) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc new file mode 100644 index 000000000..f8b60c8b4 --- /dev/null +++ b/src/eckit/geo/Range.cc @@ -0,0 +1,107 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Range.h" + +#include "eckit/exception/Exceptions.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::util { +std::vector arange(double start, double stop, double step); +} + + +namespace eckit::geo { + + +static Fraction adjust(const Fraction& target, const Fraction& inc, bool up) { + ASSERT(inc > 0); + + auto r = target / inc; + auto n = r.integralPart(); + + if (!r.integer() && (r > 0) == up) { + n += (up ? 1 : -1); + } + + return (n * inc); +} + + +Range::Range(double _a, double _b, double _inc, double _ref, double period) : + Range(_a, _b, _inc, _ref) { + ASSERT(0 < period); + + if ((n_ - 1) * inc_ >= period) { + n_ -= 1; + ASSERT(n_ * inc_ == period || (n_ - 1) * inc_ < period); + + b_ = a_ + (n_ - 1) * inc_; + } +} + + +Range::Range(double _a, double _b, double _inc, double _ref) { + ASSERT(0 <= _inc); + + if (types::is_approximately_equal(_inc, 0.) || types::is_approximately_equal(_a, _b)) { + a_ = b_ = _ref; + n_ = 1; + inc_ = Fraction{0}; + return; + } + + ASSERT(_a <= _b); // FIXME remove + + inc_ = Fraction{_inc}; + + const Fraction a(_a); + const Fraction b(_b); + const Fraction ref(_ref); + + auto shift = (ref / inc_).decimalPart() * inc_; + a_ = shift + adjust(a - shift, inc_, true); + + auto c = shift + adjust(b - shift, inc_, false); + c = a_ + ((c - a_) / inc_).integralPart() * inc_; + b_ = c < a_ ? a_ : c; + + n_ = static_cast(((b_ - a_) / inc_).integralPart() + 1); + + ASSERT(a_ <= b_); + ASSERT(1 <= n_); +} + + +std::vector Range::to_vector() const { + if (inc_ == 0) { + std::vector l(1, a_); + return l; + } + + double step = inc_; + + const auto num = static_cast((b_ - a_) / step) + 1; + + std::vector l(num); + std::generate_n(l.begin(), num, [this, n = 0]() mutable { + auto delta_num = static_cast(n++) * inc_.numerator(); + auto delta_den = inc_.denominator(); + return a_ + static_cast(delta_num) / static_cast(delta_den); + }); + + return l; +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h new file mode 100644 index 000000000..ffcc953d1 --- /dev/null +++ b/src/eckit/geo/Range.h @@ -0,0 +1,109 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "eckit/types/Fraction.h" + + +namespace eckit::geo { + + +class Range { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + Range(double a, double b, double inc, double ref, double period); + Range(double a, double b, double inc, double ref); + + Range(const Range&) = delete; + Range(Range&&) = delete; + + // -- Destructor + + virtual ~Range() = default; + + // -- Convertors + // None + + // -- Operators + + Range& operator=(const Range&) = delete; + Range& operator=(Range&&) = delete; + + // -- Methods + + size_t n() const { return n_; } + double a() const { return a_; } + double b() const { return b_; } + + std::vector to_vector() const; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + size_t n_; + double a_; + double b_; + Fraction inc_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/concept/BoundingBox.cc b/src/eckit/geo/concept/BoundingBox.cc deleted file mode 100644 index 08a5dd3f4..000000000 --- a/src/eckit/geo/concept/BoundingBox.cc +++ /dev/null @@ -1,141 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/concept/BoundingBox.h" - -#include -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/Point.h" -#include "eckit/geometry/Sphere.h" -#include "eckit/types/FloatCompare.h" - - -namespace eckit::geo::concept { - - - BoundingBox::BoundingBox(double north, double west, double south, double east) : - north_(north), west_(west), south_(south), east_(east) { - if (west_ != east_) { - auto e = PointLonLat::normalise_angle_to_minimum(east, west); - east_ = e == west_ ? (e + 360.) : e; - } - - ASSERT_MSG(west_ <= east_ && east_ <= west_ + 360., "BoundingBox: longitude range"); - ASSERT_MSG(-90. <= south_ && south_ <= north_ && north_ <= 90., "BoundingBox: latitude range"); - } - - - BoundingBox::BoundingBox() : - BoundingBox(90., 0., -90., 360.) {} - - - bool BoundingBox::operator==(const BoundingBox& other) const { - return north_ == other.north_ && south_ == other.south_ && west_ == other.west_ && east_ == other.east_; - } - - - bool BoundingBox::isPeriodicWestEast() const { - return west_ != east_ && west_ == PointLonLat::normalise_angle_to_minimum(east_, west_); - } - - - bool BoundingBox::contains(double lat, double lon) const { - return lat <= north_ && lat >= south_ && PointLonLat::normalise_angle_to_minimum(lon, west_) <= east_; - } - - - bool BoundingBox::contains(const BoundingBox& other) const { - if (other.empty()) { - return contains(other.south_, other.west_); - } - - // check for West/East range (if non-periodic), then other's corners - if (east_ - west_ < other.east_ - other.west_ || east_ < PointLonLat::normalise_angle_to_minimum(other.east_, west_)) { - return false; - } - - return contains(other.north_, other.west_) && contains(other.north_, other.east_) && contains(other.south_, other.west_) && contains(other.south_, other.east_); - } - - - bool BoundingBox::intersects(BoundingBox & other) const { - auto n = std::min(north_, other.north_); - auto s = std::max(south_, other.south_); - - bool intersectsSN = s <= n; - if (!intersectsSN) { - n = s; - } - - if (isPeriodicWestEast() && other.isPeriodicWestEast()) { - other = {n, other.west_, s, other.east_}; - return intersectsSN; - } - - auto w = std::min(west_, other.west_); - auto e = w; - - auto intersect = [](const BoundingBox& a, const BoundingBox& b, double& w, double& e) { - bool p = a.isPeriodicWestEast(); - if (p || b.isPeriodicWestEast()) { - w = (p ? b : a).west_; - e = (p ? b : a).east_; - return true; - } - - auto ref = PointLonLat::normalise_angle_to_minimum(b.west_, a.west_); - auto w_ = std::max(a.west_, ref); - auto e_ = std::min(a.east_, PointLonLat::normalise_angle_to_minimum(b.east_, ref)); - - if (w_ <= e_) { - w = w_; - e = e_; - return true; - } - - return false; - }; - - bool intersectsWE = west_ <= other.west_ ? intersect(*this, other, w, e) || intersect(other, *this, w, e) - : intersect(other, *this, w, e) || intersect(*this, other, w, e); - - ASSERT_MSG(w <= e, "BoundingBox::intersects: longitude range"); - other = {n, w, s, e}; - - return intersectsSN && intersectsWE; - } - - - bool BoundingBox::empty() const { - return types::is_approximately_equal(north_, south_) || types::is_approximately_equal(west_, east_); - } - - - double BoundingBox::area(double radius) const { - double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); - ASSERT(0. <= lonf && lonf <= 1.); - - constexpr auto degrees_to_radians = M_PI / 180.; - - const auto sn = std::sin(north_ * degrees_to_radians); - const auto ss = std::sin(south_ * degrees_to_radians); - - double latf = 0.5 * (sn - ss); - ASSERT(0. <= latf && latf <= 1.); - - return geometry::Sphere::area(radius) * latf * lonf; - } - - -} // namespace eckit::geo::concept diff --git a/src/eckit/geo/concept/BoundingBox.h b/src/eckit/geo/concept/BoundingBox.h deleted file mode 100644 index 0411e79ce..000000000 --- a/src/eckit/geo/concept/BoundingBox.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - - -namespace eckit::geo::concept { - - - class BoundingBox { - public: - // -- Exceptions - // None - - // -- Constructors - - BoundingBox(double north, double west, double south, double east); - BoundingBox(); - BoundingBox(const BoundingBox&) = default; - BoundingBox(BoundingBox&&) = default; - - // -- Destructor - - virtual ~BoundingBox() = default; - - // -- Convertors - // None - - // -- Operators - - BoundingBox& operator=(const BoundingBox&) = default; - BoundingBox& operator=(BoundingBox&&) = default; - bool operator==(const BoundingBox&) const; - bool operator!=(const BoundingBox& other) const { return !operator==(other); } - - // -- Methods - - double north() const { return north_; } - double west() const { return west_; } - double south() const { return south_; } - double east() const { return east_; } - bool isPeriodicWestEast() const; - bool contains(double lat, double lon) const; - bool contains(const BoundingBox&) const; - bool intersects(BoundingBox&) const; - bool empty() const; - double area(double radius) const; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None - - private: - // -- Members - - double north_; - double west_; - double south_; - double east_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None - }; - - -} // namespace eckit::geo::concept diff --git a/src/eckit/geo/concept/Range.cc b/src/eckit/geo/concept/Range.cc deleted file mode 100644 index 55c851731..000000000 --- a/src/eckit/geo/concept/Range.cc +++ /dev/null @@ -1,107 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/concept/Range.h" - -#include "eckit/exception/Exceptions.h" -#include "eckit/types/FloatCompare.h" - - -namespace eckit::geo::util { -std::vector arange(double start, double stop, double step); -} - - -namespace eckit::geo::concept { - - - static Fraction adjust(const Fraction& target, const Fraction& inc, bool up) { - ASSERT(inc > 0); - - auto r = target / inc; - auto n = r.integralPart(); - - if (!r.integer() && (r > 0) == up) { - n += (up ? 1 : -1); - } - - return (n * inc); - } - - - Range::Range(double _a, double _b, double _inc, double _ref, double period) : - Range(_a, _b, _inc, _ref) { - ASSERT(0 < period); - - if ((n_ - 1) * inc_ >= period) { - n_ -= 1; - ASSERT(n_ * inc_ == period || (n_ - 1) * inc_ < period); - - b_ = a_ + (n_ - 1) * inc_; - } - } - - - Range::Range(double _a, double _b, double _inc, double _ref) { - ASSERT(0 <= _inc); - - if (types::is_approximately_equal(_inc, 0.) || types::is_approximately_equal(_a, _b)) { - a_ = b_ = _ref; - n_ = 1; - inc_ = Fraction{0}; - return; - } - - ASSERT(_a <= _b); // FIXME remove - - inc_ = Fraction{_inc}; - - const Fraction a(_a); - const Fraction b(_b); - const Fraction ref(_ref); - - auto shift = (ref / inc_).decimalPart() * inc_; - a_ = shift + adjust(a - shift, inc_, true); - - auto c = shift + adjust(b - shift, inc_, false); - c = a_ + ((c - a_) / inc_).integralPart() * inc_; - b_ = c < a_ ? a_ : c; - - n_ = static_cast(((b_ - a_) / inc_).integralPart() + 1); - - ASSERT(a_ <= b_); - ASSERT(1 <= n_); - } - - - std::vector Range::to_vector() const { - if (inc_ == 0) { - std::vector l(1, a_); - return l; - } - - double step = inc_; - - const auto num = static_cast((b_ - a_) / step) + 1; - - std::vector l(num); - std::generate_n(l.begin(), num, [this, n = 0]() mutable { - auto delta_num = static_cast(n++) * inc_.numerator(); - auto delta_den = inc_.denominator(); - return a_ + static_cast(delta_num) / static_cast(delta_den); - }); - - return l; - } - - -} // namespace eckit::geo::concept diff --git a/src/eckit/geo/concept/Range.h b/src/eckit/geo/concept/Range.h deleted file mode 100644 index 08ad0bd38..000000000 --- a/src/eckit/geo/concept/Range.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include - -#include "eckit/types/Fraction.h" - - -namespace eckit::geo::concept { - - - class Range { - public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - Range(double a, double b, double inc, double ref, double period); - Range(double a, double b, double inc, double ref); - - Range(const Range&) = delete; - Range(Range&&) = delete; - - // -- Destructor - - virtual ~Range() = default; - - // -- Convertors - // None - - // -- Operators - - Range& operator=(const Range&) = delete; - Range& operator=(Range&&) = delete; - - // -- Methods - - size_t n() const { return n_; } - double a() const { return a_; } - double b() const { return b_; } - - std::vector to_vector() const; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - private: - // -- Members - - size_t n_; - double a_; - double b_; - Fraction inc_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None - }; - - -} // namespace eckit::geo::concept From ece84c29445752e0e9d76f8f2033fe9b7bca5f59 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 May 2023 15:09:20 +0100 Subject: [PATCH 223/737] eckit::geo::scanner --- src/eckit/geo/scanner/Regular.cc | 49 ++++++++++++++++++++++++++++++-- src/eckit/geo/scanner/Regular.h | 28 +++++++++++++++--- 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/scanner/Regular.cc b/src/eckit/geo/scanner/Regular.cc index f87c65d79..3fa2328db 100644 --- a/src/eckit/geo/scanner/Regular.cc +++ b/src/eckit/geo/scanner/Regular.cc @@ -12,16 +12,61 @@ #include "eckit/geo/scanner/Regular.h" -// #include <> +#include + +#include "eckit/exception/Exceptions.h" namespace eckit::geo::scanner { -Regular::Regular() = default; +Regular::Regular(size_t ni, size_t nj, double north, double west, double we, double ns) : + ni_(ni), nj_(nj), north_(north), west_(west), we_(we), ns_(ns), i_(0), j_(0), lat_(north_), lon_(west_), count_(0), first_(true), p_(PointLonLat{0, 0}) { + latValue_ = lat_; + lonValue_ = lon_; +} + + +Regular::~Regular() { + auto count = count_ + (i_ > 0 || j_ > 0 ? 1 : 0); + ASSERT(count == ni_ * nj_); +} + + +void Regular::print(std::ostream& out) const { + out << "Regular[ni=" << ni_ << ",nj=" << nj_ << ",north=" << north_ << ",west=" << west_ + << ",we=" << we_ << ",ns=" << ns_ << ",i=" << i_ << ",j=" << j_ << ",count=" << count_ + << "]"; +} bool Regular::operator++() { + if (j_ < nj_) { + if (i_ < ni_) { + p_ = PointLonLat{lonValue_, latValue_}; + + lon_ += we_; + + if (first_) { + first_ = false; + } + else { + count_++; + } + + if (++i_ == ni_) { + j_++; + i_ = 0; + lat_ -= ns_; + lon_ = west_; + latValue_ = lat_; + } + + lonValue_ = lon_; + + return true; + } + } return false; } diff --git a/src/eckit/geo/scanner/Regular.h b/src/eckit/geo/scanner/Regular.h index dde7bf3ca..f8685963d 100644 --- a/src/eckit/geo/scanner/Regular.h +++ b/src/eckit/geo/scanner/Regular.h @@ -12,7 +12,9 @@ #pragma once +#include "eckit/geo/Point.h" #include "eckit/geo/Scanner.h" +#include "eckit/types/Fraction.h" namespace eckit::geo::scanner { @@ -28,10 +30,11 @@ class Regular final : public Scanner { // -- Constructors - Regular(); + Regular(size_t ni, size_t nj, double north, double west, double we, double ns); // -- Destructor - // None + + ~Regular() override; // -- Convertors // None @@ -53,10 +56,27 @@ class Regular final : public Scanner { private: // -- Members - // None + + size_t ni_; + size_t nj_; + Fraction north_; + Fraction west_; + Fraction we_; + Fraction ns_; + size_t i_; + size_t j_; + double latValue_; + double lonValue_; + Fraction lat_; + Fraction lon_; + size_t count_; + bool first_; + + Point p_; // -- Methods - // None + + void print(std::ostream&) const; // -- Overridden methods From 9bbac1c69cd8ba20f5c6e28dafa589a297317f44 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 May 2023 15:59:55 +0100 Subject: [PATCH 224/737] eckit::geo::scanner --- src/eckit/geo/scanner/Reduced.cc | 77 +++++++++++++++++++++++++++++++- src/eckit/geo/scanner/Reduced.h | 37 +++++++++++++-- 2 files changed, 108 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/scanner/Reduced.cc b/src/eckit/geo/scanner/Reduced.cc index feef08625..6e333c9a8 100644 --- a/src/eckit/geo/scanner/Reduced.cc +++ b/src/eckit/geo/scanner/Reduced.cc @@ -12,16 +12,89 @@ #include "eckit/geo/scanner/Reduced.h" -// #include <> +#include + +#include "eckit/exception/Exceptions.h" namespace eckit::geo::scanner { -Reduced::Reduced() = default; +Reduced::Reduced(const std::vector& latitudes, + Reduced::pl_type&& pl, + const BoundingBox& bbox, + size_t N, + size_t Nj, + size_t k) : + latitudes_(latitudes), pl_(pl), bbox_(bbox), N_(N), Ni_(0), Nj_(Nj), lat_(latitudes[k]), i_(0), j_(0), k_(k), count_(0), first_(true), p_(PointLonLat{0, 0}) { + // NOTE: latitudes_ span the globe, sorted from North-to-South, k_ positions the North + // NOTE: pl is global + ASSERT(N_ * 2 == latitudes_.size()); + ASSERT(Nj_ > 0); +} + + +void Reduced::print(std::ostream& out) const { + out << "Reduced[N=" << N_ << /*",bbox=" << bbox_ <<*/ ",Ni=" << Ni_ << ",Nj=" << Nj_ + << ",i=" << i_ << ",j=" << j_ << ",k=" << k_ << ",count=" << count_ << "]"; +} + + +size_t Reduced::index() const { + return count_; +} + + +size_t Reduced::resetToRow(size_t j) { + ASSERT(j < latitudes_.size()); + lat_ = latitudes_[j]; + + auto Ni_globe = static_cast(pl_[j]); + ASSERT(Ni_globe > 1); + + inc_ = {360, Ni_globe}; + + const auto w = Fraction{bbox_.west()}; + auto Nw = (w / inc_).integralPart(); + if (Nw * inc_ < w) { + Nw += 1; + } + + const auto e = Fraction{bbox_.east()}; + auto Ne = (e / inc_).integralPart(); + if (Ne * inc_ > e) { + Ne -= 1; + } + + lon_ = Nw * inc_; + return Nw > Ne ? 0 : std::min(static_cast(Ni_globe), static_cast(Ne - Nw + 1)); +} bool Reduced::operator++() { + while (Ni_ == 0 && j_ < Nj_) { + Ni_ = resetToRow(k_ + j_++); + } + + if (0 < Nj_ && i_ < Ni_) { + p_ = PointLonLat{lon_, lat_}; + + lon_ += inc_; + + if (first_) { + first_ = false; + } + else { + count_++; + } + + if (++i_ == Ni_) { + i_ = 0; + Ni_ = 0; + } + + return true; + } return false; } diff --git a/src/eckit/geo/scanner/Reduced.h b/src/eckit/geo/scanner/Reduced.h index c415cec13..e1e6c804b 100644 --- a/src/eckit/geo/scanner/Reduced.h +++ b/src/eckit/geo/scanner/Reduced.h @@ -12,7 +12,11 @@ #pragma once +#include "eckit/geo/BoundingBox.h" +#include "eckit/geo/Point.h" #include "eckit/geo/Scanner.h" +#include "eckit/geo/util.h" +#include "eckit/types/Fraction.h" namespace eckit::geo::scanner { @@ -21,14 +25,20 @@ namespace eckit::geo::scanner { class Reduced final : public Scanner { public: // -- Types - // None + + using pl_type = util::pl_type; // -- Exceptions // None // -- Constructors - Reduced(); + Reduced(const std::vector& latitudes, + pl_type&& pl, + const BoundingBox&, + size_t N, + size_t Nj, + size_t k); // -- Destructor // None @@ -53,10 +63,29 @@ class Reduced final : public Scanner { private: // -- Members - // None + + const std::vector& latitudes_; + const pl_type pl_; + const BoundingBox& bbox_; + const size_t N_; + size_t Ni_; + size_t Nj_; + Fraction lon_; + double lat_; + Fraction inc_; + size_t i_; + size_t j_; + size_t k_; + size_t count_; + bool first_; + + Point p_; // -- Methods - // None + + void print(std::ostream&) const; + size_t index() const; + size_t resetToRow(size_t); // -- Overridden methods From 60a411ee451b0b79320da0a5b29d28762bfc6e7e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 May 2023 16:24:17 +0100 Subject: [PATCH 225/737] eckit::geo::grib --- src/eckit/geo/CMakeLists.txt | 10 +- .../{RegularLL.cc => GribConfiguration.cc} | 21 +- src/eckit/geo/grib/GribConfiguration.h | 270 ++++++++++++++++++ src/eckit/geo/grib/RegularLL.h | 77 ----- tests/geo/test_grib.cc | 244 ---------------- 5 files changed, 287 insertions(+), 335 deletions(-) rename src/eckit/geo/grib/{RegularLL.cc => GribConfiguration.cc} (64%) create mode 100644 src/eckit/geo/grib/GribConfiguration.h delete mode 100644 src/eckit/geo/grib/RegularLL.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 080569b83..c116dc2b7 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -12,8 +12,6 @@ list(APPEND eckit_geo_srcs Scanner.cc Scanner.h Search.h - grib/RegularLL.cc - grib/RegularLL.h iterator/IteratorAggregator.h iterator/IteratorComposer.cc iterator/IteratorComposer.h @@ -59,3 +57,11 @@ ecbuild_add_library( PUBLIC_INCLUDES ${eckit_geo_include_dirs} ) +ecbuild_add_library( + TARGET eckit_geo_grib + TYPE SHARED + CONDITION HAVE_ECCODES + SOURCES grib/GribConfiguration.cc grib/GribConfiguration.h + PUBLIC_LIBS eckit_geo +) + diff --git a/src/eckit/geo/grib/RegularLL.cc b/src/eckit/geo/grib/GribConfiguration.cc similarity index 64% rename from src/eckit/geo/grib/RegularLL.cc rename to src/eckit/geo/grib/GribConfiguration.cc index c52db7f8b..651685020 100644 --- a/src/eckit/geo/grib/RegularLL.cc +++ b/src/eckit/geo/grib/GribConfiguration.cc @@ -10,27 +10,24 @@ */ -#include "eckit/geo/grib/RegularLL.h" +#include "eckit/geo/grib/GribConfiguration.h" namespace eckit::geo::grib { -static const IteratorBuilder __iterator("regular_ll"); +//RegularLL::RegularLL(const Configuration&) { +//} -RegularLL::RegularLL(const Configuration&) { -} +//size_t RegularLL::size() const { +// return 0; +//} -size_t RegularLL::size() const { - return 0; -} - - -bool RegularLL::operator++() { - return false; -} +//bool RegularLL::operator++() { +// return false; +//} } // namespace eckit::geo::grib diff --git a/src/eckit/geo/grib/GribConfiguration.h b/src/eckit/geo/grib/GribConfiguration.h new file mode 100644 index 000000000..f5fed4a46 --- /dev/null +++ b/src/eckit/geo/grib/GribConfiguration.h @@ -0,0 +1,270 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "eccodes.h" + +#include "eckit/config/Configuration.h" + + +namespace eckit::geo::grib { + + +// static eckit::Value v; + +#if 0 +class GribConfiguration final : std::unique_ptr { +private: + // -- Types + + using t = std::unique_ptr; + + using cache_key_type = std::string; + + using cache_value_type = std::variant, + std::vector, std::vector, std::vector, std::vector, + std::vector, std::vector, std::vector>; + + struct cache_type : protected std::map { + template + bool get(const key_type& key, T& value) const { + if (auto it = find(key); it != end()) { + value = std::get(it->second); + return true; + } + return false; + } + + template + void set(const key_type& key, T& value) { + operator[](key) = value; + } + }; + +public: + // -- Exceptions + // None + + // -- Constructors + + explicit GribConfiguration(codes_handle* h) : + // Configuration(v), + t(h, &codes_handle_delete) { ASSERT(*this); } + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + template + T get(const cache_key_type& key) const { + auto value = T(); + ASSERT(get(key, value)); + return value; + } + + // -- Overridden methods + + bool has(const cache_key_type& key) const /*override*/ { return 0 != codes_is_defined(t::get(), key.c_str()); } + + bool get(const cache_key_type& key, bool& value) const /*override*/ { + if (long another = 0; get(key, another)) { + value = another != 0; + return true; + } + + return false; + } + + bool get(const cache_key_type& key, int& value) const /*override*/ { + if (long another = 0; get(key, another)) { + value = static_cast(another); + return true; + } + + return false; + } + + bool get(const cache_key_type& key, long& value) const /*override*/ { + if (cache_.get(key, value)) { + return true; + } + + if (CODES_SUCCESS == codes_get_long(t::get(), key.c_str(), &value)) { + cache_.set(key, value); + return true; + } + + return false; + } + + bool get(const cache_key_type& key, unsigned long& value) const /*override*/ { + if (long another = 0; get(key, another) && 0 <= another) { + value = static_cast(another); + return true; + } + + return false; + } + + bool get(const cache_key_type& key, float& value) const /*override*/ { + if (double another = 0; get(key, another)) { + value = static_cast(another); + return true; + } + + return false; + } + + bool get(const cache_key_type& key, double& value) const /*override*/ { + if (cache_.get(key, value)) { + return true; + } + + if (CODES_SUCCESS == codes_get_double(t::get(), key.c_str(), &value)) { + cache_.set(key, value); + return true; + } + + return false; + } + + bool get(const cache_key_type& key, std::string& value) const /*override*/ { + if (cache_.get(key, value)) { + return true; + } + + char mesg[1024]; + if (auto length = sizeof(mesg); CODES_SUCCESS == codes_get_string(t::get(), key.c_str(), mesg, &length)) { + value = mesg; + cache_.set(key, value); + return true; + } + + return false; + } + + bool get(const cache_key_type& key, std::vector& value) const /*override*/ { + if (std::vector another; get(key, another)) { + value.resize(another.size()); + std::transform(another.begin(), another.end(), value.begin(), [](long v) { return static_cast(v); }); + return true; + } + + return false; + } + + bool get(const cache_key_type& key, std::vector& value) const /*override*/ { + if (cache_.get(key, value)) { + return true; + } + + if (size_t size = 0; CODES_SUCCESS == codes_get_size(t::get(), key.c_str(), &size)) { + std::vector another(size); + if (CODES_SUCCESS == codes_get_long_array(t::get(), key.c_str(), another.data(), &size)) { + value.swap(another); + cache_.set(key, value); + return true; + } + } + + return false; + } + + bool get(const cache_key_type& key, std::vector& value) const /*override*/ { + if (std::vector another; get(key, another)) { + value.resize(another.size()); + std::transform(another.begin(), another.end(), value.begin(), [](long v) { + ASSERT(0 <= v); + return static_cast(v); + }); + return true; + } + + return false; + } + + bool get(const cache_key_type& key, std::vector& value) const /*override*/ { + if (cache_.get(key, value)) { + return true; + } + + if (size_t size = 0; CODES_SUCCESS == codes_get_size(t::get(), key.c_str(), &size)) { + std::vector another(size); + if (CODES_SUCCESS == codes_get_float_array(t::get(), key.c_str(), another.data(), &size)) { + value.swap(another); + cache_.set(key, value); + return true; + } + } + + return false; + } + + bool get(const cache_key_type& key, std::vector& value) const /*override*/ { + if (cache_.get(key, value)) { + return true; + } + + if (size_t size = 0; CODES_SUCCESS == codes_get_size(t::get(), key.c_str(), &size)) { + std::vector another(size); + if (CODES_SUCCESS == codes_get_double_array(t::get(), key.c_str(), another.data(), &size)) { + value.swap(another); + cache_.set(key, value); + return true; + } + } + + return false; + } + + bool get(const cache_key_type& key, std::vector& value) const /*override*/ { NOTIMP; } + + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + mutable cache_type cache_; + + // -- Methods + // None + + // -- Overridden methods + + void print(std::ostream&) const /*override*/ {} + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + +} // namespace eckit::geo::grib diff --git a/src/eckit/geo/grib/RegularLL.h b/src/eckit/geo/grib/RegularLL.h deleted file mode 100644 index 9d9bdfa0d..000000000 --- a/src/eckit/geo/grib/RegularLL.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Iterator.h" - - -namespace eckit::geo::grib { - - -class RegularLL : public Iterator { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit RegularLL(const Configuration&); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - bool operator++() override; - size_t size() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grib diff --git a/tests/geo/test_grib.cc b/tests/geo/test_grib.cc index 118379a8d..55f83854d 100644 --- a/tests/geo/test_grib.cc +++ b/tests/geo/test_grib.cc @@ -83,250 +83,6 @@ eckit::geo::Figure* make_figure(long code) { #endif -// static eckit::Value v; -class Grib final : std::unique_ptr { -private: - // -- Types - - using t = std::unique_ptr; - - using cache_key_type = std::string; - - using cache_value_type = std::variant, - std::vector, std::vector, std::vector, std::vector, - std::vector, std::vector, std::vector>; - - struct cache_type : protected std::map { - template - bool get(const key_type& key, T& value) const { - if (auto it = find(key); it != end()) { - value = std::get(it->second); - return true; - } - return false; - } - - template - void set(const key_type& key, T& value) { - operator[](key) = value; - } - }; - -public: - // -- Exceptions - // None - - // -- Constructors - - explicit Grib(codes_handle* h) : - // Configuration(v), - t(h, &codes_handle_delete) { ASSERT(*this); } - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - template - T get(const cache_key_type& key) const { - auto value = T(); - ASSERT(get(key, value)); - return value; - } - - // -- Overridden methods - - bool has(const cache_key_type& key) const /*override*/ { return 0 != codes_is_defined(t::get(), key.c_str()); } - - bool get(const cache_key_type& key, bool& value) const /*override*/ { - if (long another = 0; get(key, another)) { - value = another != 0; - return true; - } - - return false; - } - - bool get(const cache_key_type& key, int& value) const /*override*/ { - if (long another = 0; get(key, another)) { - value = static_cast(another); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, long& value) const /*override*/ { - if (cache_.get(key, value)) { - return true; - } - - if (CODES_SUCCESS == codes_get_long(t::get(), key.c_str(), &value)) { - cache_.set(key, value); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, unsigned long& value) const /*override*/ { - if (long another = 0; get(key, another) && 0 <= another) { - value = static_cast(another); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, float& value) const /*override*/ { - if (double another = 0; get(key, another)) { - value = static_cast(another); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, double& value) const /*override*/ { - if (cache_.get(key, value)) { - return true; - } - - if (CODES_SUCCESS == codes_get_double(t::get(), key.c_str(), &value)) { - cache_.set(key, value); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, std::string& value) const /*override*/ { - if (cache_.get(key, value)) { - return true; - } - - char mesg[1024]; - if (auto length = sizeof(mesg); CODES_SUCCESS == codes_get_string(t::get(), key.c_str(), mesg, &length)) { - value = mesg; - cache_.set(key, value); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, std::vector& value) const /*override*/ { - if (std::vector another; get(key, another)) { - value.resize(another.size()); - std::transform(another.begin(), another.end(), value.begin(), [](long v) { return static_cast(v); }); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, std::vector& value) const /*override*/ { - if (cache_.get(key, value)) { - return true; - } - - if (size_t size = 0; CODES_SUCCESS == codes_get_size(t::get(), key.c_str(), &size)) { - std::vector another(size); - if (CODES_SUCCESS == codes_get_long_array(t::get(), key.c_str(), another.data(), &size)) { - value.swap(another); - cache_.set(key, value); - return true; - } - } - - return false; - } - - bool get(const cache_key_type& key, std::vector& value) const /*override*/ { - if (std::vector another; get(key, another)) { - value.resize(another.size()); - std::transform(another.begin(), another.end(), value.begin(), [](long v) { - ASSERT(0 <= v); - return static_cast(v); - }); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, std::vector& value) const /*override*/ { - if (cache_.get(key, value)) { - return true; - } - - if (size_t size = 0; CODES_SUCCESS == codes_get_size(t::get(), key.c_str(), &size)) { - std::vector another(size); - if (CODES_SUCCESS == codes_get_float_array(t::get(), key.c_str(), another.data(), &size)) { - value.swap(another); - cache_.set(key, value); - return true; - } - } - - return false; - } - - bool get(const cache_key_type& key, std::vector& value) const /*override*/ { - if (cache_.get(key, value)) { - return true; - } - - if (size_t size = 0; CODES_SUCCESS == codes_get_size(t::get(), key.c_str(), &size)) { - std::vector another(size); - if (CODES_SUCCESS == codes_get_double_array(t::get(), key.c_str(), another.data(), &size)) { - value.swap(another); - cache_.set(key, value); - return true; - } - } - - return false; - } - - bool get(const cache_key_type& key, std::vector& value) const /*override*/ { NOTIMP; } - - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - mutable cache_type cache_; - - // -- Methods - // None - - // -- Overridden methods - - void print(std::ostream&) const /*override*/ {} - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - #if 0 std::string type() const { return get_string("gridType"); } From c5d9e5ab28dad543ffce7ad68110b677ce520ccd Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 May 2023 17:02:02 +0100 Subject: [PATCH 226/737] eckit::geo::grib --- src/eckit/geo/CMakeLists.txt | 2 +- src/eckit/geo/grib/GribConfiguration.cc | 207 +++++++++++++++++- src/eckit/geo/grib/GribConfiguration.h | 273 +++++++----------------- tests/geo/CMakeLists.txt | 2 +- tests/geo/test_grib.cc | 6 +- 5 files changed, 276 insertions(+), 214 deletions(-) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index c116dc2b7..f88e3eb3e 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -62,6 +62,6 @@ ecbuild_add_library( TYPE SHARED CONDITION HAVE_ECCODES SOURCES grib/GribConfiguration.cc grib/GribConfiguration.h - PUBLIC_LIBS eckit_geo + PUBLIC_LIBS eckit_geo eccodes ) diff --git a/src/eckit/geo/grib/GribConfiguration.cc b/src/eckit/geo/grib/GribConfiguration.cc index 651685020..7e71157bc 100644 --- a/src/eckit/geo/grib/GribConfiguration.cc +++ b/src/eckit/geo/grib/GribConfiguration.cc @@ -12,22 +12,213 @@ #include "eckit/geo/grib/GribConfiguration.h" +#include "eckit/value/Value.h" + namespace eckit::geo::grib { -//RegularLL::RegularLL(const Configuration&) { -//} +static eckit::Value __root_dummy; + + +GribConfiguration::GribConfiguration(codes_handle* h) : + Configuration(__root_dummy), codes_handle_(h, &codes_handle_delete) { + ASSERT(codes_handle_); +} + + +bool GribConfiguration::has(const std::string& name) const { + return 0 != codes_is_defined(codes_handle_.get(), name.c_str()); +} + + +bool GribConfiguration::get(const std::string& name, std::string& value) const { + if (cache_.get(name, value)) { + return true; + } + + char mesg[1024]; + if (auto length = sizeof(mesg); + CODES_SUCCESS == codes_get_string(codes_handle_.get(), name.c_str(), mesg, &length)) { + value = mesg; + cache_.set(name, value); + return true; + } + + return false; +} + + +bool GribConfiguration::get(const std::string& name, bool& value) const { + if (long another = 0; get(name, another)) { + value = another != 0; + return true; + } + + return false; +} + + +bool GribConfiguration::get(const std::string& name, int& value) const { + if (long another = 0; get(name, another)) { + value = static_cast(another); + return true; + } + + return false; +} + + +bool GribConfiguration::get(const std::string& name, long& value) const { + if (cache_.get(name, value)) { + return true; + } + + if (CODES_SUCCESS == codes_get_long(codes_handle_.get(), name.c_str(), &value)) { + cache_.set(name, value); + return true; + } + + return false; +} + + +bool GribConfiguration::get(const std::string& name, long long& value) const { + NOTIMP; +} + + +bool GribConfiguration::get(const std::string& name, std::size_t& value) const { + if (long another = 0; get(name, another) && 0 <= another) { + value = static_cast(another); + return true; + } + + return false; +} + + +bool GribConfiguration::get(const std::string& name, float& value) const { + if (double another = 0; get(name, another)) { + value = static_cast(another); + return true; + } + + return false; +} + + +bool GribConfiguration::get(const std::string& name, double& value) const { + if (cache_.get(name, value)) { + return true; + } + + if (CODES_SUCCESS == codes_get_double(codes_handle_.get(), name.c_str(), &value)) { + cache_.set(name, value); + return true; + } + + return false; +} + + +bool GribConfiguration::get(const std::string& name, std::vector& value) const { + if (std::vector another; get(name, another)) { + value.resize(another.size()); + std::transform(another.begin(), another.end(), value.begin(), [](long v) { + return static_cast(v); + }); + return true; + } + + return false; +} + + +bool GribConfiguration::get(const std::string& name, std::vector& value) const { + if (cache_.get(name, value)) { + return true; + } + + if (size_t size = 0; CODES_SUCCESS == codes_get_size(codes_handle_.get(), name.c_str(), &size)) { + std::vector another(size); + if (CODES_SUCCESS + == codes_get_long_array(codes_handle_.get(), name.c_str(), another.data(), &size)) { + value.swap(another); + cache_.set(name, value); + return true; + } + } + + return false; +} + + +bool GribConfiguration::get(const std::string& name, std::vector& value) const { + NOTIMP; +} + + +bool GribConfiguration::get(const std::string& name, std::vector& value) const { + if (std::vector another; get(name, another)) { + value.resize(another.size()); + std::transform(another.begin(), another.end(), value.begin(), [](long v) { + ASSERT(0 <= v); + return static_cast(v); + }); + return true; + } + + return false; +} + + +bool GribConfiguration::get(const std::string& name, std::vector& value) const { + if (cache_.get(name, value)) { + return true; + } + + if (size_t size = 0; CODES_SUCCESS == codes_get_size(codes_handle_.get(), name.c_str(), &size)) { + std::vector another(size); + if (CODES_SUCCESS + == codes_get_float_array(codes_handle_.get(), name.c_str(), another.data(), &size)) { + value.swap(another); + cache_.set(name, value); + return true; + } + } + + return false; +} + + +bool GribConfiguration::get(const std::string& name, std::vector& value) const { + if (cache_.get(name, value)) { + return true; + } + + if (size_t size = 0; CODES_SUCCESS == codes_get_size(codes_handle_.get(), name.c_str(), &size)) { + std::vector another(size); + if (CODES_SUCCESS + == codes_get_double_array(codes_handle_.get(), name.c_str(), another.data(), &size)) { + value.swap(another); + cache_.set(name, value); + return true; + } + } + + return false; +} -//size_t RegularLL::size() const { -// return 0; -//} +bool GribConfiguration::get(const std::string& name, std::vector& value) const { + NOTIMP; +} -//bool RegularLL::operator++() { -// return false; -//} +void GribConfiguration::print(std::ostream&) const { + NOTIMP; +} } // namespace eckit::geo::grib diff --git a/src/eckit/geo/grib/GribConfiguration.h b/src/eckit/geo/grib/GribConfiguration.h index f5fed4a46..78575f5ce 100644 --- a/src/eckit/geo/grib/GribConfiguration.h +++ b/src/eckit/geo/grib/GribConfiguration.h @@ -12,257 +12,130 @@ #pragma once +#include #include #include "eccodes.h" #include "eckit/config/Configuration.h" +#include "eckit/exception/Exceptions.h" namespace eckit::geo::grib { -// static eckit::Value v; - -#if 0 -class GribConfiguration final : std::unique_ptr { +class GribConfiguration final : Configuration { private: // -- Types - - using t = std::unique_ptr; - - using cache_key_type = std::string; - - using cache_value_type = std::variant, - std::vector, std::vector, std::vector, std::vector, - std::vector, std::vector, std::vector>; - - struct cache_type : protected std::map { + + using codes_handle_type = std::unique_ptr; + + using cache_value_type = std::variant, + std::vector, + std::vector, + std::vector, + std::vector, + std::vector, + std::vector, + std::vector>; + + struct cache_type : protected std::map { template - bool get(const key_type& key, T& value) const { - if (auto it = find(key); it != end()) { + bool get(const key_type& name, T& value) const { + if (auto it = find(name); it != end()) { value = std::get(it->second); return true; } + return false; } - + template - void set(const key_type& key, T& value) { - operator[](key) = value; + void set(const key_type& name, T& value) { + operator[](name) = value; } }; - + public: // -- Exceptions // None - + // -- Constructors - - explicit GribConfiguration(codes_handle* h) : - // Configuration(v), - t(h, &codes_handle_delete) { ASSERT(*this); } - + + explicit GribConfiguration(codes_handle* h); + // -- Destructor // None - + // -- Convertors // None - + // -- Operators // None - + // -- Methods - + template - T get(const cache_key_type& key) const { + T get(const std::string& name) const { auto value = T(); - ASSERT(get(key, value)); + ASSERT(get(name, value)); return value; } - + // -- Overridden methods - - bool has(const cache_key_type& key) const /*override*/ { return 0 != codes_is_defined(t::get(), key.c_str()); } - - bool get(const cache_key_type& key, bool& value) const /*override*/ { - if (long another = 0; get(key, another)) { - value = another != 0; - return true; - } - - return false; - } - - bool get(const cache_key_type& key, int& value) const /*override*/ { - if (long another = 0; get(key, another)) { - value = static_cast(another); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, long& value) const /*override*/ { - if (cache_.get(key, value)) { - return true; - } - - if (CODES_SUCCESS == codes_get_long(t::get(), key.c_str(), &value)) { - cache_.set(key, value); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, unsigned long& value) const /*override*/ { - if (long another = 0; get(key, another) && 0 <= another) { - value = static_cast(another); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, float& value) const /*override*/ { - if (double another = 0; get(key, another)) { - value = static_cast(another); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, double& value) const /*override*/ { - if (cache_.get(key, value)) { - return true; - } - - if (CODES_SUCCESS == codes_get_double(t::get(), key.c_str(), &value)) { - cache_.set(key, value); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, std::string& value) const /*override*/ { - if (cache_.get(key, value)) { - return true; - } - - char mesg[1024]; - if (auto length = sizeof(mesg); CODES_SUCCESS == codes_get_string(t::get(), key.c_str(), mesg, &length)) { - value = mesg; - cache_.set(key, value); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, std::vector& value) const /*override*/ { - if (std::vector another; get(key, another)) { - value.resize(another.size()); - std::transform(another.begin(), another.end(), value.begin(), [](long v) { return static_cast(v); }); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, std::vector& value) const /*override*/ { - if (cache_.get(key, value)) { - return true; - } - - if (size_t size = 0; CODES_SUCCESS == codes_get_size(t::get(), key.c_str(), &size)) { - std::vector another(size); - if (CODES_SUCCESS == codes_get_long_array(t::get(), key.c_str(), another.data(), &size)) { - value.swap(another); - cache_.set(key, value); - return true; - } - } - - return false; - } - - bool get(const cache_key_type& key, std::vector& value) const /*override*/ { - if (std::vector another; get(key, another)) { - value.resize(another.size()); - std::transform(another.begin(), another.end(), value.begin(), [](long v) { - ASSERT(0 <= v); - return static_cast(v); - }); - return true; - } - - return false; - } - - bool get(const cache_key_type& key, std::vector& value) const /*override*/ { - if (cache_.get(key, value)) { - return true; - } - - if (size_t size = 0; CODES_SUCCESS == codes_get_size(t::get(), key.c_str(), &size)) { - std::vector another(size); - if (CODES_SUCCESS == codes_get_float_array(t::get(), key.c_str(), another.data(), &size)) { - value.swap(another); - cache_.set(key, value); - return true; - } - } - - return false; - } - - bool get(const cache_key_type& key, std::vector& value) const /*override*/ { - if (cache_.get(key, value)) { - return true; - } - - if (size_t size = 0; CODES_SUCCESS == codes_get_size(t::get(), key.c_str(), &size)) { - std::vector another(size); - if (CODES_SUCCESS == codes_get_double_array(t::get(), key.c_str(), another.data(), &size)) { - value.swap(another); - cache_.set(key, value); - return true; - } - } - - return false; - } - - bool get(const cache_key_type& key, std::vector& value) const /*override*/ { NOTIMP; } - - + + bool has(const std::string& name) const override; + + bool get(const std::string& name, std::string& value) const override; + bool get(const std::string& name, bool& value) const override; + bool get(const std::string& name, int& value) const override; + bool get(const std::string& name, long& value) const override; + bool get(const std::string& name, long long& value) const override; + bool get(const std::string& name, std::size_t& value) const override; + bool get(const std::string& name, float& value) const override; + bool get(const std::string& name, double& value) const override; + + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + // -- Class members // None - + // -- Class methods // None - + private: // -- Members - + + codes_handle_type codes_handle_; mutable cache_type cache_; - + // -- Methods // None - + // -- Overridden methods - - void print(std::ostream&) const /*override*/ {} - + + void print(std::ostream&) const override; + // -- Class members // None - + // -- Class methods // None - + // -- Friends // None }; diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 3f9716ead..b4f22d007 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -19,6 +19,6 @@ if(HAVE_ECCODES) ecbuild_add_test( TARGET eckit_test_geo_grib SOURCES test_grib.cc - LIBS eckit_geo eccodes) + LIBS eckit_geo_grib) endif() diff --git a/tests/geo/test_grib.cc b/tests/geo/test_grib.cc index 55f83854d..5e0ae25fa 100644 --- a/tests/geo/test_grib.cc +++ b/tests/geo/test_grib.cc @@ -21,9 +21,7 @@ #include #include "eckit/exception/Exceptions.h" -// #include "eckit/config/Configuration.h" -#include "eckit/config/MappedConfiguration.h" -#include "eckit/value/Value.h" +#include "eckit/geo/grib/GribConfiguration.h" #if 0 @@ -140,7 +138,7 @@ int main(int argc, const char* argv[]) { int err = 0; for (codes_handle* h = nullptr; nullptr != (h = codes_handle_new_from_file(nullptr, in, PRODUCT_GRIB, &err));) { - Grib grib(h); + eckit::geo::grib::GribConfiguration grib(h); #if 0 int n = 0; From 1ee5d8b697ec5c99e2b18114bac665ab80eb0247 Mon Sep 17 00:00:00 2001 From: Francois Hebert Date: Tue, 25 Apr 2023 14:31:44 -0600 Subject: [PATCH 227/737] Enable SphericalToCartesian to handle latitudes across poles --- tests/geometry/test_sphere.cc | 143 +++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 63 deletions(-) diff --git a/tests/geometry/test_sphere.cc b/tests/geometry/test_sphere.cc index 69e6656d1..4e761f8a8 100644 --- a/tests/geometry/test_sphere.cc +++ b/tests/geometry/test_sphere.cc @@ -11,8 +11,8 @@ #include #include +#include "eckit/geometry/Point2.h" #include "eckit/geometry/Point3.h" -#include "eckit/geometry/PointLonLat.h" #include "eckit/geometry/SphereT.h" #include "eckit/geometry/UnitSphere.h" #include "eckit/testing/Test.h" @@ -21,6 +21,19 @@ namespace eckit::test { using namespace geometry; +struct PointLonLat : Point2 { + PointLonLat(double x, double y) : + Point2(x, y) {} + const double& lon() const { return x_[0]; } + const double& lat() const { return x_[1]; } +}; + +struct PointXYZ : Point3 { + const double& x() const { return x_[0]; } + const double& y() const { return x_[1]; } + const double& z() const { return x_[2]; } +}; + // set sphere struct DatumTwoUnits { static double radius() { return 2.; } @@ -43,20 +56,22 @@ CASE("test unit sphere radius") { CASE("test unit sphere north pole") { const PointLonLat ll1(0., 90.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); + PointXYZ p; + UnitSphere::convertSphericalToCartesian(ll1, p); - EXPECT(p.X == 0); - EXPECT(p.Y == 0); - EXPECT(p.Z == R); + EXPECT(p.x() == 0); + EXPECT(p.y() == 0); + EXPECT(p.z() == R); } CASE("test unit sphere south pole") { const PointLonLat ll1(0., -90.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); + PointXYZ p; + UnitSphere::convertSphericalToCartesian(ll1, p); - EXPECT(p.X == 0); - EXPECT(p.Y == 0); - EXPECT(p.Z == -R); + EXPECT(p.x() == 0); + EXPECT(p.y() == 0); + EXPECT(p.z() == -R); } // ----------------------------------------------------------------------------- @@ -65,55 +80,57 @@ CASE("test unit sphere south pole") { CASE("test unit sphere lon 0") { const PointLonLat ll1(0., 0.); const PointLonLat ll2(-360., 0.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(p.X == R); - EXPECT(p.Y == 0); - EXPECT(p.Z == 0); + EXPECT(p.x() == R); + EXPECT(p.y() == 0); + EXPECT(p.z() == 0); - EXPECT(points_equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } CASE("test unit sphere lon 90") { const PointLonLat ll1(90., 0.); const PointLonLat ll2(-270., 0.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(p.X == 0); - EXPECT(p.Y == R); - EXPECT(p.Z == 0); + EXPECT(p.x() == 0); + EXPECT(p.y() == R); + EXPECT(p.z() == 0); - EXPECT(points_equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } CASE("test unit sphere lon 180") { const PointLonLat ll1(180., 0.); const PointLonLat ll2(-180., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); - - EXPECT(p.X == -R); - EXPECT(p.Y == 0); - EXPECT(p.Z == 0); + EXPECT(p.x() == -R); + EXPECT(p.y() == 0); + EXPECT(p.z() == 0); - EXPECT(points_equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } CASE("test unit sphere lon 270") { const PointLonLat ll1(270., 0.); const PointLonLat ll2(-90., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); - - EXPECT(p.X == 0); - EXPECT(p.Y == -R); - EXPECT(p.Z == 0); + EXPECT(p.x() == 0); + EXPECT(p.y() == -R); + EXPECT(p.z() == 0); - EXPECT(points_equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } @@ -125,57 +142,57 @@ const double L = R * std::sqrt(2) / 2.; CASE("test unit sphere lon 45") { const PointLonLat ll1(45., 0.); const PointLonLat ll2(-315., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); - - EXPECT(eckit::types::is_approximately_equal(p.X, L)); - EXPECT(eckit::types::is_approximately_equal(p.Y, L)); - EXPECT(p.Z == 0); + EXPECT(eckit::types::is_approximately_equal(p.x(), L)); + EXPECT(eckit::types::is_approximately_equal(p.y(), L)); + EXPECT(p.z() == 0); - EXPECT(points_equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } CASE("test unit sphere lon 135") { const PointLonLat ll1(135., 0.); const PointLonLat ll2(-225., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); - - EXPECT(eckit::types::is_approximately_equal(p.X, -L)); - EXPECT(eckit::types::is_approximately_equal(p.Y, L)); - EXPECT(p.Z == 0); + EXPECT(eckit::types::is_approximately_equal(p.x(), -L)); + EXPECT(eckit::types::is_approximately_equal(p.y(), L)); + EXPECT(p.z() == 0); - EXPECT(points_equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } CASE("test unit sphere lon 225") { const PointLonLat ll1(225., 0.); const PointLonLat ll2(-135., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); - - EXPECT(eckit::types::is_approximately_equal(p.X, -L)); - EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); - EXPECT(p.Z == 0); + EXPECT(eckit::types::is_approximately_equal(p.x(), -L)); + EXPECT(eckit::types::is_approximately_equal(p.y(), -L)); + EXPECT(p.z() == 0); - EXPECT(points_equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } CASE("test unit sphere lon 315") { const PointLonLat ll1(315., 0.); const PointLonLat ll2(-45., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); - - EXPECT(eckit::types::is_approximately_equal(p.X, L)); - EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); - EXPECT(p.Z == 0); + EXPECT(eckit::types::is_approximately_equal(p.x(), L)); + EXPECT(eckit::types::is_approximately_equal(p.y(), -L)); + EXPECT(p.z() == 0); - EXPECT(points_equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } // ----------------------------------------------------------------------------- From f2872fd9a3bb728d7fb1c8b3a236fd770a7cfe18 Mon Sep 17 00:00:00 2001 From: Francois Hebert Date: Thu, 27 Apr 2023 14:27:24 -0600 Subject: [PATCH 228/737] Improve normalisation robustness for large angles --- tests/geometry/test_sphere.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/geometry/test_sphere.cc b/tests/geometry/test_sphere.cc index 4e761f8a8..8a194e3bf 100644 --- a/tests/geometry/test_sphere.cc +++ b/tests/geometry/test_sphere.cc @@ -232,6 +232,20 @@ CASE("test unit sphere lat 290") { EXPECT(eckit::types::is_approximately_equal(p.z(), q.z())); } +CASE("test unit sphere lat 290") { + const PointLonLat ll1(15., 290.); + const PointLonLat ll2(15., -70.); + PointXYZ p, q; + + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); + + // sin(x) and sin(pi-x) are not bitwise identical + EXPECT(eckit::types::is_approximately_equal(p.x(), q.x())); + EXPECT(eckit::types::is_approximately_equal(p.y(), q.y())); + EXPECT(eckit::types::is_approximately_equal(p.z(), q.z())); +} + CASE("test unit sphere lat -120") { const PointLonLat ll1(45., -120.); const PointLonLat ll2(225., -60.); From 178601288ea9b5e530715b6ceca9be51adc8e63a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 May 2023 10:14:08 +0100 Subject: [PATCH 229/737] Added additional argument "bool normalise_angle = false" where appropriate (API change, to preserve operational behaviour), ./format-sources.sh, cleanup --- tests/geometry/test_sphere.cc | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/tests/geometry/test_sphere.cc b/tests/geometry/test_sphere.cc index 8a194e3bf..4e761f8a8 100644 --- a/tests/geometry/test_sphere.cc +++ b/tests/geometry/test_sphere.cc @@ -232,20 +232,6 @@ CASE("test unit sphere lat 290") { EXPECT(eckit::types::is_approximately_equal(p.z(), q.z())); } -CASE("test unit sphere lat 290") { - const PointLonLat ll1(15., 290.); - const PointLonLat ll2(15., -70.); - PointXYZ p, q; - - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); - - // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(eckit::types::is_approximately_equal(p.x(), q.x())); - EXPECT(eckit::types::is_approximately_equal(p.y(), q.y())); - EXPECT(eckit::types::is_approximately_equal(p.z(), q.z())); -} - CASE("test unit sphere lat -120") { const PointLonLat ll1(45., -120.); const PointLonLat ll2(225., -60.); From 8fbba0e25058ac3a90bbb64001f43707cba89646 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 15 May 2023 15:30:45 +0100 Subject: [PATCH 230/737] eckit::geometry --- src/eckit/geometry/EllipsoidOfRevolution.cc | 48 ++++--- src/eckit/geometry/Sphere.cc | 133 ++++++++++---------- 2 files changed, 88 insertions(+), 93 deletions(-) diff --git a/src/eckit/geometry/EllipsoidOfRevolution.cc b/src/eckit/geometry/EllipsoidOfRevolution.cc index 3e094f62d..24dc711e5 100644 --- a/src/eckit/geometry/EllipsoidOfRevolution.cc +++ b/src/eckit/geometry/EllipsoidOfRevolution.cc @@ -11,11 +11,12 @@ #include "eckit/geometry/EllipsoidOfRevolution.h" #include +#include +#include #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/CoordinateHelpers.h" -#include "eckit/geometry/Point2.h" #include "eckit/geometry/Point3.h" +#include "eckit/geometry/PointLonLat.h" //---------------------------------------------------------------------------------------------------------------------- @@ -23,35 +24,28 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- -namespace { - -static const double degrees_to_radians = M_PI / 180.; - -} // namespace - -//---------------------------------------------------------------------------------------------------------------------- - -void EllipsoidOfRevolution::convertSphericalToCartesian(const double& a, - const double& b, - const Point2& Alonlat, - Point3& B, - double height, - bool normalise_angle) { +Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, + double b, + const PointLonLat& A, + double height) { ASSERT(a > 0.); ASSERT(b > 0.); - // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates - // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) - - if (!normalise_angle) { - assert_latitude_range(Alonlat[1]); + if (!(-90. <= A.lat && A.lat <= 90.)) { + std::ostringstream oss; + oss.precision(std::numeric_limits::max_digits10); + oss << "Invalid latitude " << A.lat; + throw BadValue(oss.str(), Here()); } - const Point2 alonlat = canonicaliseOnSphere(Alonlat, -180.); + static const double degrees_to_radians = M_PI / 180.; + + // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates + // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) - const double lambda_deg = alonlat[0]; + const double lambda_deg = PointLonLat::normalise_angle_to_minimum(A.lon, -180.); const double lambda = degrees_to_radians * lambda_deg; - const double phi = degrees_to_radians * alonlat[1]; + const double phi = degrees_to_radians * A.lat; const double sin_phi = std::sin(phi); const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); @@ -60,9 +54,9 @@ void EllipsoidOfRevolution::convertSphericalToCartesian(const double& a, const double N_phi = a * a / std::sqrt(a * a * cos_phi * cos_phi + b * b * sin_phi * sin_phi); - B[0] = (N_phi + height) * cos_phi * cos_lambda; - B[1] = (N_phi + height) * cos_phi * sin_lambda; - B[2] = (N_phi * (b * b) / (a * a) + height) * sin_phi; + return {(N_phi + height) * cos_phi * cos_lambda, + (N_phi + height) * cos_phi * sin_lambda, + (N_phi * (b * b) / (a * a) + height) * sin_phi}; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geometry/Sphere.cc b/src/eckit/geometry/Sphere.cc index b1ac42a96..1c38f4d32 100644 --- a/src/eckit/geometry/Sphere.cc +++ b/src/eckit/geometry/Sphere.cc @@ -13,12 +13,12 @@ #include #include #include +#include #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/CoordinateHelpers.h" #include "eckit/geometry/GreatCircle.h" -#include "eckit/geometry/Point2.h" #include "eckit/geometry/Point3.h" +#include "eckit/geometry/PointLonLat.h" #include "eckit/types/FloatCompare.h" //---------------------------------------------------------------------------------------------------------------------- @@ -27,9 +27,20 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- -static const double radians_to_degrees = 180. * M_1_PI; +using types::is_approximately_equal; -static const double degrees_to_radians = M_PI / 180.; +static constexpr double radians_to_degrees = 180. * M_1_PI; + +static constexpr double degrees_to_radians = M_PI / 180.; + +void assert_latitude(double lat) { + if (!(-90. <= lat && lat <= 90.)) { + std::ostringstream oss; + oss.precision(std::numeric_limits::max_digits10); + oss << "Invalid latitude " << lat; + throw BadValue(oss.str(), Here()); + } +} inline double squared(double x) { return x * x; @@ -37,7 +48,10 @@ inline double squared(double x) { //---------------------------------------------------------------------------------------------------------------------- -double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat, bool normalise_angle) { +double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { + assert_latitude(A.lat); + assert_latitude(B.lat); + /* * Δσ = atan( ((cos(ϕ2) * sin(Δλ))^2 + (cos(ϕ1) * sin(ϕ2) - sin(ϕ1) * cos(ϕ2) * cos(Δλ))^2) / * (sin(ϕ1) * sin(ϕ2) + cos(ϕ1) * cos(ϕ2) * cos(Δλ)) ) @@ -54,31 +68,21 @@ double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat, bool n * } */ - if (!normalise_angle) { - assert_latitude_range(Alonlat[1]); - assert_latitude_range(Blonlat[1]); - } + const double phi1 = degrees_to_radians * A.lat; + const double phi2 = degrees_to_radians * B.lat; + const double lambda = degrees_to_radians * (B.lon - A.lon); - const Point2 alonlat = canonicaliseOnSphere(Alonlat); - const Point2 blonlat = canonicaliseOnSphere(Blonlat); + const double cos_phi1 = cos(phi1); + const double sin_phi1 = sin(phi1); + const double cos_phi2 = cos(phi2); + const double sin_phi2 = sin(phi2); + const double cos_lambda = cos(lambda); + const double sin_lambda = sin(lambda); - const double phi1 = degrees_to_radians * alonlat[1]; - const double phi2 = degrees_to_radians * blonlat[1]; - const double lambda = degrees_to_radians * (blonlat[0] - alonlat[0]); - - const double cos_phi1 = std::cos(phi1); - const double sin_phi1 = std::sin(phi1); - const double cos_phi2 = std::cos(phi2); - const double sin_phi2 = std::sin(phi2); - const double cos_lambda = std::cos(lambda); - const double sin_lambda = std::sin(lambda); - - const double angle = std::atan2(std::sqrt(squared(cos_phi2 * sin_lambda) - + squared(cos_phi1 * sin_phi2 - - sin_phi1 * cos_phi2 * cos_lambda)), + const double angle = std::atan2(std::sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); - if (types::is_approximately_equal(angle, 0.)) { + if (is_approximately_equal(angle, 0.)) { return 0.; } @@ -86,13 +90,13 @@ double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat, bool n return angle; } -double Sphere::centralAngle(const double& radius, const Point3& A, const Point3& B) { +double Sphere::centralAngle(double radius, const Point3& A, const Point3& B) { ASSERT(radius > 0.); // Δσ = 2 * asin( chord / 2 ) const double d2 = Point3::distance2(A, B); - if (types::is_approximately_equal(d2, 0.)) { + if (is_approximately_equal(d2, 0.)) { return 0.; } @@ -102,38 +106,39 @@ double Sphere::centralAngle(const double& radius, const Point3& A, const Point3& return angle; } -double Sphere::distance(const double& radius, const Point2& Alonlat, const Point2& Blonlat) { - return radius * centralAngle(Alonlat, Blonlat, true); +double Sphere::distance(double radius, const PointLonLat& A, const PointLonLat& B) { + return radius * centralAngle(A, B); } -double Sphere::distance(const double& radius, const Point3& A, const Point3& B) { +double Sphere::distance(double radius, const Point3& A, const Point3& B) { return radius * centralAngle(radius, A, B); } -double Sphere::area(const double& radius) { +double Sphere::area(double radius) { ASSERT(radius > 0.); return 4. * M_PI * radius * radius; } -double Sphere::area(const double& radius, const Point2& WestNorth, const Point2& EastSouth) { +double Sphere::area(double radius, const PointLonLat& WestNorth, const PointLonLat& EastSouth) { ASSERT(radius > 0.); + assert_latitude(WestNorth.lat); + assert_latitude(EastSouth.lat); // Set longitude fraction - double W = WestNorth[0]; - double E = normalise_angle(EastSouth[0], W); - double longitude_range( - types::is_approximately_equal(W, E) && !types::is_approximately_equal(EastSouth[0], WestNorth[0]) ? 360. - : E - W); + double W = WestNorth.lon; + double E = PointLonLat::normalise_angle_to_minimum(EastSouth.lon, W); + double longitude_range(is_approximately_equal(W, E) + && !is_approximately_equal(EastSouth.lon, WestNorth.lon) + ? 360. + : E - W); ASSERT(longitude_range <= 360.); double longitude_fraction = longitude_range / 360.; // Set latitude fraction - double N = WestNorth[1]; - double S = EastSouth[1]; - ASSERT(-90. <= N && N <= 90.); - ASSERT(-90. <= S && S <= 90.); - ASSERT(N >= S); + double N = WestNorth.lat; + double S = EastSouth.lat; + ASSERT(S <= N); double latitude_fraction = 0.5 * (std::sin(degrees_to_radians * N) - std::sin(degrees_to_radians * S)); @@ -141,24 +146,26 @@ double Sphere::area(const double& radius, const Point2& WestNorth, const Point2& return area(radius) * latitude_fraction * longitude_fraction; } -double Sphere::greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clon) { - GreatCircle gc(Alonlat, Blonlat); +double Sphere::greatCircleLatitudeGivenLongitude(const PointLonLat& A, + const PointLonLat& B, + double Clon) { + GreatCircle gc(A, B); auto lat = gc.latitude(Clon); return lat.size() == 1 ? lat[0] : std::numeric_limits::signaling_NaN(); } -void Sphere::greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clat, - double& Clon1, double& Clon2) { - GreatCircle gc(Alonlat, Blonlat); +void Sphere::greatCircleLongitudeGivenLatitude( + const PointLonLat& A, const PointLonLat& B, double Clat, double& Clon1, double& Clon2) { + GreatCircle gc(A, B); auto lon = gc.longitude(Clat); Clon1 = lon.size() > 0 ? lon[0] : std::numeric_limits::signaling_NaN(); Clon2 = lon.size() > 1 ? lon[1] : std::numeric_limits::signaling_NaN(); } -void Sphere::convertSphericalToCartesian( - const double& radius, const Point2& Alonlat, Point3& B, double height, bool normalise_angle) { +Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, double height) { ASSERT(radius > 0.); + assert_latitude(A.lat); /* * See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates @@ -173,37 +180,31 @@ void Sphere::convertSphericalToCartesian( * poles and quadrants. */ - if (!normalise_angle) { - assert_latitude_range(Alonlat[1]); - } - - const Point2 alonlat = canonicaliseOnSphere(Alonlat, -180.); - - const double lambda_deg = alonlat[0]; + const double lambda_deg = PointLonLat::normalise_angle_to_minimum(A.lon, -180.); const double lambda = degrees_to_radians * lambda_deg; - const double phi = degrees_to_radians * alonlat[1]; + const double phi = degrees_to_radians * A.lat; const double sin_phi = std::sin(phi); const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; - const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); + const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) + : std::sqrt(1. - sin_lambda * sin_lambda); - B[0] = (radius + height) * cos_phi * cos_lambda; - B[1] = (radius + height) * cos_phi * sin_lambda; - B[2] = (radius + height) * sin_phi; + return {(radius + height) * cos_phi * cos_lambda, + (radius + height) * cos_phi * sin_lambda, + (radius + height) * sin_phi}; } -void Sphere::convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat) { +PointLonLat Sphere::convertCartesianToSpherical(double radius, const Point3& A) { ASSERT(radius > 0.); // numerical conditioning for both z (poles) and y const double x = A[0]; - const double y = types::is_approximately_equal(A[1], 0.) ? 0. : A[1]; + const double y = is_approximately_equal(A[1], 0.) ? 0. : A[1]; const double z = std::min(radius, std::max(-radius, A[2])) / radius; - Blonlat[0] = radians_to_degrees * std::atan2(y, x); - Blonlat[1] = radians_to_degrees * std::asin(z); + return {radians_to_degrees * std::atan2(y, x), radians_to_degrees * std::asin(z)}; } //---------------------------------------------------------------------------------------------------------------------- From 85bc621412c5968d7fb066c71177c798ea9a5a83 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 5 Jun 2023 15:48:58 +0100 Subject: [PATCH 231/737] eckit::geometry, eckit::geo --- src/eckit/geometry/EllipsoidOfRevolution.cc | 13 +- src/eckit/geometry/EllipsoidOfRevolution.h | 13 +- src/eckit/geometry/Sphere.cc | 2 +- src/eckit/geometry/Sphere.h | 65 ++++---- src/eckit/geometry/SphereT.h | 64 +++---- src/eckit/geometry/UnitSphere.h | 2 +- tests/geometry/test_sphere.cc | 176 +++++++++----------- 7 files changed, 150 insertions(+), 185 deletions(-) diff --git a/src/eckit/geometry/EllipsoidOfRevolution.cc b/src/eckit/geometry/EllipsoidOfRevolution.cc index 24dc711e5..a20080836 100644 --- a/src/eckit/geometry/EllipsoidOfRevolution.cc +++ b/src/eckit/geometry/EllipsoidOfRevolution.cc @@ -26,15 +26,16 @@ namespace eckit::geometry { Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, double b, - const PointLonLat& A, - double height) { + const PointLonLat& P, + double height, + bool normalise_angle) { ASSERT(a > 0.); ASSERT(b > 0.); - if (!(-90. <= A.lat && A.lat <= 90.)) { + if (!(-90. <= P.lat && P.lat <= 90.)) { std::ostringstream oss; oss.precision(std::numeric_limits::max_digits10); - oss << "Invalid latitude " << A.lat; + oss << "Invalid latitude " << P.lat; throw BadValue(oss.str(), Here()); } @@ -43,9 +44,9 @@ Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) - const double lambda_deg = PointLonLat::normalise_angle_to_minimum(A.lon, -180.); + const double lambda_deg = PointLonLat::normalise_angle_to_minimum(P.lon, -180.); const double lambda = degrees_to_radians * lambda_deg; - const double phi = degrees_to_radians * A.lat; + const double phi = degrees_to_radians * P.lat; const double sin_phi = std::sin(phi); const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); diff --git a/src/eckit/geometry/EllipsoidOfRevolution.h b/src/eckit/geometry/EllipsoidOfRevolution.h index 7b30159ff..03a7f980b 100644 --- a/src/eckit/geometry/EllipsoidOfRevolution.h +++ b/src/eckit/geometry/EllipsoidOfRevolution.h @@ -17,19 +17,18 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- -class Point2; class Point3; +class PointLonLat; //---------------------------------------------------------------------------------------------------------------------- struct EllipsoidOfRevolution { // Convert elliptic coordinates to Cartesian - static void convertSphericalToCartesian(const double& radiusA, - const double& radiusB, - const Point2& Alonlat, - Point3& B, - double height = 0., - bool normalise_angle = false); + static Point3 convertSphericalToCartesian(double a, + double b, + const PointLonLat&, + double height = 0., + bool normalise_angle = false); }; //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geometry/Sphere.cc b/src/eckit/geometry/Sphere.cc index 1c38f4d32..106d26fc4 100644 --- a/src/eckit/geometry/Sphere.cc +++ b/src/eckit/geometry/Sphere.cc @@ -163,7 +163,7 @@ void Sphere::greatCircleLongitudeGivenLatitude( Clon2 = lon.size() > 1 ? lon[1] : std::numeric_limits::signaling_NaN(); } -Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, double height) { +Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, double height, bool normalise_angle) { ASSERT(radius > 0.); assert_latitude(A.lat); diff --git a/src/eckit/geometry/Sphere.h b/src/eckit/geometry/Sphere.h index dfc74f342..c23e6be25 100644 --- a/src/eckit/geometry/Sphere.h +++ b/src/eckit/geometry/Sphere.h @@ -8,8 +8,7 @@ * does it submit to any jurisdiction. */ -#ifndef Sphere_H -#define Sphere_H +#pragma once //---------------------------------------------------------------------------------------------------------------------- @@ -17,55 +16,47 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- -class Point2; class Point3; +class PointLonLat; //---------------------------------------------------------------------------------------------------------------------- struct Sphere { - /// Great-circle central angle between two points (latitude/longitude coordinates) in radians - static double centralAngle(const Point2& Alonlat, - const Point2& Blonlat, - bool normalise_angle = false); + /// Great-circle central angle between two points in radians + static double centralAngle(const PointLonLat&, + const PointLonLat&); /// Great-circle central angle between two points (Cartesian coordinates) in radians - static double centralAngle(const double& radius, const Point3& A, const Point3& B); + static double centralAngle(double radius, const Point3&, const Point3&); - /// Great-circle distance between two points (latitude/longitude coordinates) in metres - static double distance(const double& radius, const Point2& Alonlat, const Point2& Blonlat); + /// Great-circle distance between two points in metres + static double distance(double radius, const PointLonLat&, const PointLonLat&); /// Great-circle distance between two points (Cartesian coordinates) in metres - static double distance(const double& radius, const Point3& A, const Point3& B); + static double distance(double radius, const Point3&, const Point3&); /// Surface area in square metres - static double area(const double& radius); - - /// Surface area between parallels and meridians defined by two points (longitude/latitude - /// coordinates) in square metres - static double area(const double& radius, const Point2& Alonlat, const Point2& Blonlat); - - // Great-circle intermediate latitude provided two circle points (A, B) and intermediate - // longitude (C) in degrees - static double greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clon); - - // Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate - // latitude (C) in degrees - static void greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clat, - double& Clon1, double& Clon2); - - // Convert spherical coordinates to Cartesian - static void convertSphericalToCartesian(const double& radius, - const Point2& Alonlat, - Point3& B, - double height = 0., - bool normalise_angle = false); - - // Convert Cartesian coordinates to spherical - static void convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat); + static double area(double radius); + + /// Surface area between parallels and meridians defined by two points in square metres + static double area(double radius, const PointLonLat&, const PointLonLat&); + + // Great-circle intermediate latitude provided two circle points and intermediate longitude in degrees + static double greatCircleLatitudeGivenLongitude(const PointLonLat&, const PointLonLat&, double lon); + + // Great-circle intermediate longitude(s) provided two circle points and intermediate latitude in degrees + static void greatCircleLongitudeGivenLatitude(const PointLonLat&, const PointLonLat&, double lat, double& lon1, double& lon2); + + // Convert spherical to Cartesian coordinates + static Point3 convertSphericalToCartesian(double radius, + const PointLonLat&, + double height = 0., + bool normalise_angle = false); + + // Convert Cartesian to spherical coordinates + static PointLonLat convertCartesianToSpherical(double radius, const Point3&); }; //---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geometry - -#endif diff --git a/src/eckit/geometry/SphereT.h b/src/eckit/geometry/SphereT.h index b76e9e49c..7b2632b8b 100644 --- a/src/eckit/geometry/SphereT.h +++ b/src/eckit/geometry/SphereT.h @@ -8,9 +8,10 @@ * does it submit to any jurisdiction. */ -#ifndef SphereT_H -#define SphereT_H +#pragma once +#include "eckit/geometry/Point3.h" +#include "eckit/geometry/PointLonLat.h" #include "eckit/geometry/Sphere.h" //---------------------------------------------------------------------------------------------------------------------- @@ -19,6 +20,11 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- +class Point3; +class PointLonLat; + +//---------------------------------------------------------------------------------------------------------------------- + /// Definition of a sphere parametrised with a geodetic datum template struct SphereT { @@ -26,11 +32,10 @@ struct SphereT { /// Sphere radius in metres inline static double radius() { return DATUM::radius(); } - /// Great-circle central angle between two points (longitude/latitude coordinates) in radians - inline static double centralAngle(const Point2& Alonlat, - const Point2& Blonlat, - bool normalise_angle = false) { - return Sphere::centralAngle(Alonlat, Blonlat, normalise_angle); + /// Great-circle central angle between two points in radians + inline static double centralAngle(const PointLonLat& A, + const PointLonLat& B) { + return Sphere::centralAngle(A, B); } /// Great-circle central angle between two points (Cartesian coordinates) in radians @@ -38,9 +43,9 @@ struct SphereT { return Sphere::centralAngle(DATUM::radius(), A, B); } - /// Great-circle distance between two points (longitude/latitude coordinates) in metres - inline static double distance(const Point2& Alonlat, const Point2& Blonlat) { - return Sphere::distance(DATUM::radius(), Alonlat, Blonlat); + /// Great-circle distance between two points in metres + inline static double distance(const PointLonLat& A, const PointLonLat& B) { + return Sphere::distance(DATUM::radius(), A, B); } /// Great-circle distance between two points (Cartesian coordinates) in metres @@ -49,40 +54,35 @@ struct SphereT { /// Surface area in square metres inline static double area() { return Sphere::area(DATUM::radius()); } - /// Surface area between parallels and meridians defined by two points (longitude/latitude coordinates) in square - /// metres - inline static double area(const Point2& WestNorth, const Point2& EastSouth) { + /// Surface area between parallels and meridians defined by two points in square metres + inline static double area(const PointLonLat& WestNorth, const PointLonLat& EastSouth) { return Sphere::area(DATUM::radius(), WestNorth, EastSouth); } - // Great-circle intermediate latitude provided two circle points (A, B) and intermediate longitude (C) in degrees - inline static double greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, - const double& Clon) { - return Sphere::greatCircleLatitudeGivenLongitude(Alonlat, Blonlat, Clon); + // Great-circle intermediate latitude provided two circle points and intermediate longitude in degrees + inline static double greatCircleLatitudeGivenLongitude(const PointLonLat& A, const PointLonLat& B, double lon) { + return Sphere::greatCircleLatitudeGivenLongitude(A, B, lon); } - // Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate latitude (C) in degrees - inline static void greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, - const double& Clat, double& Clon1, double& Clon2) { - return Sphere::greatCircleLongitudeGivenLatitude(Alonlat, Blonlat, Clat, Clon1, Clon2); + // Great-circle intermediate longitude(s) provided two circle points and intermediate latitude in degrees + inline static void greatCircleLongitudeGivenLatitude(const PointLonLat& A, const PointLonLat& B, + double lat, double& lon1, double& lon2) { + return Sphere::greatCircleLongitudeGivenLatitude(A, B, lat, lon1, lon2); } - // Convert spherical coordinates to Cartesian - inline static void convertSphericalToCartesian(const Point2& Alonlat, - Point3& B, - double height = 0., - bool normalise_angle = false) { - Sphere::convertSphericalToCartesian(DATUM::radius(), Alonlat, B, height, normalise_angle); + // Convert spherical to Cartesian coordinates + inline static Point3 convertSphericalToCartesian(const PointLonLat& P, + double height = 0., + bool normalise_angle = false) { + return Sphere::convertSphericalToCartesian(DATUM::radius(), P, height, normalise_angle); } - // Convert Cartesian coordinates to spherical - inline static void convertCartesianToSpherical(const Point3& A, Point2& Blonlat) { - Sphere::convertCartesianToSpherical(DATUM::radius(), A, Blonlat); + // Convert Cartesian to spherical coordinates + inline static PointLonLat convertCartesianToSpherical(const Point3& P) { + return Sphere::convertCartesianToSpherical(DATUM::radius(), P); } }; //---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geometry - -#endif diff --git a/src/eckit/geometry/UnitSphere.h b/src/eckit/geometry/UnitSphere.h index 2c8fc317c..de4075de0 100644 --- a/src/eckit/geometry/UnitSphere.h +++ b/src/eckit/geometry/UnitSphere.h @@ -27,7 +27,7 @@ struct DatumUnit { //------------------------------------------------------------------------------------------------------ /// Definition of a unit sphere -typedef SphereT UnitSphere; +using UnitSphere = SphereT; //------------------------------------------------------------------------------------------------------ diff --git a/tests/geometry/test_sphere.cc b/tests/geometry/test_sphere.cc index 4e761f8a8..d9696b10f 100644 --- a/tests/geometry/test_sphere.cc +++ b/tests/geometry/test_sphere.cc @@ -11,8 +11,8 @@ #include #include -#include "eckit/geometry/Point2.h" #include "eckit/geometry/Point3.h" +#include "eckit/geometry/PointLonLat.h" #include "eckit/geometry/SphereT.h" #include "eckit/geometry/UnitSphere.h" #include "eckit/testing/Test.h" @@ -21,19 +21,6 @@ namespace eckit::test { using namespace geometry; -struct PointLonLat : Point2 { - PointLonLat(double x, double y) : - Point2(x, y) {} - const double& lon() const { return x_[0]; } - const double& lat() const { return x_[1]; } -}; - -struct PointXYZ : Point3 { - const double& x() const { return x_[0]; } - const double& y() const { return x_[1]; } - const double& z() const { return x_[2]; } -}; - // set sphere struct DatumTwoUnits { static double radius() { return 2.; } @@ -56,22 +43,20 @@ CASE("test unit sphere radius") { CASE("test unit sphere north pole") { const PointLonLat ll1(0., 90.); - PointXYZ p; - UnitSphere::convertSphericalToCartesian(ll1, p); + auto p = UnitSphere::convertSphericalToCartesian(ll1); - EXPECT(p.x() == 0); - EXPECT(p.y() == 0); - EXPECT(p.z() == R); + EXPECT(p.X == 0); + EXPECT(p.Y == 0); + EXPECT(p.Z == R); } CASE("test unit sphere south pole") { const PointLonLat ll1(0., -90.); - PointXYZ p; - UnitSphere::convertSphericalToCartesian(ll1, p); + auto p = UnitSphere::convertSphericalToCartesian(ll1); - EXPECT(p.x() == 0); - EXPECT(p.y() == 0); - EXPECT(p.z() == -R); + EXPECT(p.X == 0); + EXPECT(p.Y == 0); + EXPECT(p.Z == -R); } // ----------------------------------------------------------------------------- @@ -80,57 +65,53 @@ CASE("test unit sphere south pole") { CASE("test unit sphere lon 0") { const PointLonLat ll1(0., 0.); const PointLonLat ll2(-360., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); - EXPECT(p.x() == R); - EXPECT(p.y() == 0); - EXPECT(p.z() == 0); + EXPECT(p.X == R); + EXPECT(p.Y == 0); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(Point3::equal(p, q)); } CASE("test unit sphere lon 90") { const PointLonLat ll1(90., 0.); const PointLonLat ll2(-270., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); - EXPECT(p.x() == 0); - EXPECT(p.y() == R); - EXPECT(p.z() == 0); + EXPECT(p.X == 0); + EXPECT(p.Y == R); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(Point3::equal(p, q)); } CASE("test unit sphere lon 180") { const PointLonLat ll1(180., 0.); const PointLonLat ll2(-180., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); - EXPECT(p.x() == -R); - EXPECT(p.y() == 0); - EXPECT(p.z() == 0); + EXPECT(p.X == -R); + EXPECT(p.Y == 0); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(Point3::equal(p, q)); } CASE("test unit sphere lon 270") { const PointLonLat ll1(270., 0.); const PointLonLat ll2(-90., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); - EXPECT(p.x() == 0); - EXPECT(p.y() == -R); - EXPECT(p.z() == 0); + EXPECT(p.X == 0); + EXPECT(p.Y == -R); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(Point3::equal(p, q)); } @@ -142,57 +123,53 @@ const double L = R * std::sqrt(2) / 2.; CASE("test unit sphere lon 45") { const PointLonLat ll1(45., 0.); const PointLonLat ll2(-315., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); - EXPECT(eckit::types::is_approximately_equal(p.x(), L)); - EXPECT(eckit::types::is_approximately_equal(p.y(), L)); - EXPECT(p.z() == 0); + EXPECT(eckit::types::is_approximately_equal(p.X, L)); + EXPECT(eckit::types::is_approximately_equal(p.Y, L)); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(Point3::equal(p, q)); } CASE("test unit sphere lon 135") { const PointLonLat ll1(135., 0.); const PointLonLat ll2(-225., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); - EXPECT(eckit::types::is_approximately_equal(p.x(), -L)); - EXPECT(eckit::types::is_approximately_equal(p.y(), L)); - EXPECT(p.z() == 0); + EXPECT(eckit::types::is_approximately_equal(p.X, -L)); + EXPECT(eckit::types::is_approximately_equal(p.Y, L)); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(Point3::equal(p, q)); } CASE("test unit sphere lon 225") { const PointLonLat ll1(225., 0.); const PointLonLat ll2(-135., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); - EXPECT(eckit::types::is_approximately_equal(p.x(), -L)); - EXPECT(eckit::types::is_approximately_equal(p.y(), -L)); - EXPECT(p.z() == 0); + EXPECT(eckit::types::is_approximately_equal(p.X, -L)); + EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(Point3::equal(p, q)); } CASE("test unit sphere lon 315") { const PointLonLat ll1(315., 0.); const PointLonLat ll2(-45., 0.); - PointXYZ p, q; - UnitSphere::convertSphericalToCartesian(ll1, p); - UnitSphere::convertSphericalToCartesian(ll2, q); + auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto q = UnitSphere::convertSphericalToCartesian(ll2); - EXPECT(eckit::types::is_approximately_equal(p.x(), L)); - EXPECT(eckit::types::is_approximately_equal(p.y(), -L)); - EXPECT(p.z() == 0); + EXPECT(eckit::types::is_approximately_equal(p.X, L)); + EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); + EXPECT(p.Z == 0); - EXPECT(PointXYZ::equal(p, q)); + EXPECT(Point3::equal(p, q)); } // ----------------------------------------------------------------------------- @@ -201,52 +178,49 @@ CASE("test unit sphere lon 315") { CASE("test unit sphere lat 100") { const PointLonLat ll1(0., 100.); const PointLonLat ll2(180., 80.); - PointXYZ p, q; // Default behavior throws - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian(ll1, p), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian(ll1), eckit::BadValue); - UnitSphere::convertSphericalToCartesian(ll1, p, 0., true); - UnitSphere::convertSphericalToCartesian(ll2, q, 0., true); + auto p = UnitSphere::convertSphericalToCartesian(ll1, 0., true); + auto q = UnitSphere::convertSphericalToCartesian(ll2, 0., true); // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(eckit::types::is_approximately_equal(p.x(), q.x())); - EXPECT(eckit::types::is_approximately_equal(p.y(), q.y())); - EXPECT(eckit::types::is_approximately_equal(p.z(), q.z())); + EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); + EXPECT(eckit::types::is_approximately_equal(p.Y, q.Y)); + EXPECT(eckit::types::is_approximately_equal(p.Z, q.Z)); } CASE("test unit sphere lat 290") { const PointLonLat ll1(15., 290.); const PointLonLat ll2(15., -70.); - PointXYZ p, q; // Default behavior throws - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian(ll1, p), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian(ll1), eckit::BadValue); - UnitSphere::convertSphericalToCartesian(ll1, p, 0., true); - UnitSphere::convertSphericalToCartesian(ll2, q, 0., true); + auto p = UnitSphere::convertSphericalToCartesian(ll1, 0., true); + auto q = UnitSphere::convertSphericalToCartesian(ll2, 0., true); // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(eckit::types::is_approximately_equal(p.x(), q.x())); - EXPECT(eckit::types::is_approximately_equal(p.y(), q.y())); - EXPECT(eckit::types::is_approximately_equal(p.z(), q.z())); + EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); + EXPECT(eckit::types::is_approximately_equal(p.Y, q.Y)); + EXPECT(eckit::types::is_approximately_equal(p.Z, q.Z)); } CASE("test unit sphere lat -120") { const PointLonLat ll1(45., -120.); const PointLonLat ll2(225., -60.); - PointXYZ p, q; // Default behavior throws - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian(ll1, p), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian(ll1), eckit::BadValue); - UnitSphere::convertSphericalToCartesian(ll1, p, 0., true); - UnitSphere::convertSphericalToCartesian(ll2, q, 0., true); + auto p = UnitSphere::convertSphericalToCartesian(ll1, 0., true); + auto q = UnitSphere::convertSphericalToCartesian(ll2, 0., true); // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(eckit::types::is_approximately_equal(p.x(), q.x())); - EXPECT(eckit::types::is_approximately_equal(p.y(), q.y())); - EXPECT(eckit::types::is_approximately_equal(p.z(), q.z())); + EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); + EXPECT(eckit::types::is_approximately_equal(p.Y, q.Y)); + EXPECT(eckit::types::is_approximately_equal(p.Z, q.Z)); } // ----------------------------------------------------------------------------- From 0231bbc778356ed5eb31f38f0e9a86cc0f2a0649 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 5 Jun 2023 16:00:25 +0100 Subject: [PATCH 232/737] eckit::geometry, eckit::geo --- src/eckit/geometry/PointLonLat.h | 8 +-- tests/geometry/test_sphere.cc | 89 +++++++++++--------------------- 2 files changed, 33 insertions(+), 64 deletions(-) diff --git a/src/eckit/geometry/PointLonLat.h b/src/eckit/geometry/PointLonLat.h index a9077b7a4..cf0d95ecc 100644 --- a/src/eckit/geometry/PointLonLat.h +++ b/src/eckit/geometry/PointLonLat.h @@ -37,8 +37,8 @@ class PointLonLat final : protected std::array { // -- Constructors - PointLonLat(double lat, double lon) : - P{lat, lon} { ASSERT_MSG(-90. <= lat && lat <= 90., "PointLonLat: invalid latitude"); } + PointLonLat(double lon, double lat) : + P{lon, lat} { ASSERT_MSG(-90. <= lat && lat <= 90., "PointLonLat: invalid latitude"); } PointLonLat(const PointLonLat& other) : P(other) {} @@ -67,8 +67,8 @@ class PointLonLat final : protected std::array { // -- Members - double& lat = P::operator[](0); - double& lon = P::operator[](1); + double& lon = P::operator[](0); + double& lat = P::operator[](1); // -- Methods diff --git a/tests/geometry/test_sphere.cc b/tests/geometry/test_sphere.cc index d9696b10f..d21995563 100644 --- a/tests/geometry/test_sphere.cc +++ b/tests/geometry/test_sphere.cc @@ -42,8 +42,7 @@ CASE("test unit sphere radius") { // test unit sphere poles CASE("test unit sphere north pole") { - const PointLonLat ll1(0., 90.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto p = UnitSphere::convertSphericalToCartesian({0., 90.}); EXPECT(p.X == 0); EXPECT(p.Y == 0); @@ -51,8 +50,7 @@ CASE("test unit sphere north pole") { } CASE("test unit sphere south pole") { - const PointLonLat ll1(0., -90.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); + auto p = UnitSphere::convertSphericalToCartesian({0., -90.}); EXPECT(p.X == 0); EXPECT(p.Y == 0); @@ -63,10 +61,8 @@ CASE("test unit sphere south pole") { // test unit sphere quadrants CASE("test unit sphere lon 0") { - const PointLonLat ll1(0., 0.); - const PointLonLat ll2(-360., 0.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); + auto p = UnitSphere::convertSphericalToCartesian({0., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-360., 0.}); EXPECT(p.X == R); EXPECT(p.Y == 0); @@ -76,10 +72,8 @@ CASE("test unit sphere lon 0") { } CASE("test unit sphere lon 90") { - const PointLonLat ll1(90., 0.); - const PointLonLat ll2(-270., 0.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); + auto p = UnitSphere::convertSphericalToCartesian({90., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-270., 0.}); EXPECT(p.X == 0); EXPECT(p.Y == R); @@ -89,10 +83,8 @@ CASE("test unit sphere lon 90") { } CASE("test unit sphere lon 180") { - const PointLonLat ll1(180., 0.); - const PointLonLat ll2(-180., 0.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); + auto p = UnitSphere::convertSphericalToCartesian({180., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-180., 0.}); EXPECT(p.X == -R); EXPECT(p.Y == 0); @@ -102,10 +94,8 @@ CASE("test unit sphere lon 180") { } CASE("test unit sphere lon 270") { - const PointLonLat ll1(270., 0.); - const PointLonLat ll2(-90., 0.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); + auto p = UnitSphere::convertSphericalToCartesian({270., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-90., 0.}); EXPECT(p.X == 0); EXPECT(p.Y == -R); @@ -121,10 +111,8 @@ CASE("test unit sphere lon 270") { const double L = R * std::sqrt(2) / 2.; CASE("test unit sphere lon 45") { - const PointLonLat ll1(45., 0.); - const PointLonLat ll2(-315., 0.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); + auto p = UnitSphere::convertSphericalToCartesian({45., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-315., 0.}); EXPECT(eckit::types::is_approximately_equal(p.X, L)); EXPECT(eckit::types::is_approximately_equal(p.Y, L)); @@ -134,10 +122,8 @@ CASE("test unit sphere lon 45") { } CASE("test unit sphere lon 135") { - const PointLonLat ll1(135., 0.); - const PointLonLat ll2(-225., 0.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); + auto p = UnitSphere::convertSphericalToCartesian({135., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-225., 0.}); EXPECT(eckit::types::is_approximately_equal(p.X, -L)); EXPECT(eckit::types::is_approximately_equal(p.Y, L)); @@ -147,10 +133,8 @@ CASE("test unit sphere lon 135") { } CASE("test unit sphere lon 225") { - const PointLonLat ll1(225., 0.); - const PointLonLat ll2(-135., 0.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); + auto p = UnitSphere::convertSphericalToCartesian({225., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-135., 0.}); EXPECT(eckit::types::is_approximately_equal(p.X, -L)); EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); @@ -160,10 +144,8 @@ CASE("test unit sphere lon 225") { } CASE("test unit sphere lon 315") { - const PointLonLat ll1(315., 0.); - const PointLonLat ll2(-45., 0.); - auto p = UnitSphere::convertSphericalToCartesian(ll1); - auto q = UnitSphere::convertSphericalToCartesian(ll2); + auto p = UnitSphere::convertSphericalToCartesian({315., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-45., 0.}); EXPECT(eckit::types::is_approximately_equal(p.X, L)); EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); @@ -176,14 +158,11 @@ CASE("test unit sphere lon 315") { // test unit sphere with non-canonical latitudes outside [-90, 90] CASE("test unit sphere lat 100") { - const PointLonLat ll1(0., 100.); - const PointLonLat ll2(180., 80.); - // Default behavior throws - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian(ll1), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({0., 100. }), eckit::BadValue); - auto p = UnitSphere::convertSphericalToCartesian(ll1, 0., true); - auto q = UnitSphere::convertSphericalToCartesian(ll2, 0., true); + auto p = UnitSphere::convertSphericalToCartesian({0., 100. }, 0., true); + auto q = UnitSphere::convertSphericalToCartesian({180., 80.}, 0., true); // sin(x) and sin(pi-x) are not bitwise identical EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); @@ -192,14 +171,11 @@ CASE("test unit sphere lat 100") { } CASE("test unit sphere lat 290") { - const PointLonLat ll1(15., 290.); - const PointLonLat ll2(15., -70.); - // Default behavior throws - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian(ll1), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({15., 290.}), eckit::BadValue); - auto p = UnitSphere::convertSphericalToCartesian(ll1, 0., true); - auto q = UnitSphere::convertSphericalToCartesian(ll2, 0., true); + auto p = UnitSphere::convertSphericalToCartesian({15., 290.}, 0., true); + auto q = UnitSphere::convertSphericalToCartesian({15., -70.}, 0., true); // sin(x) and sin(pi-x) are not bitwise identical EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); @@ -208,14 +184,11 @@ CASE("test unit sphere lat 290") { } CASE("test unit sphere lat -120") { - const PointLonLat ll1(45., -120.); - const PointLonLat ll2(225., -60.); - // Default behavior throws - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian(ll1), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({45., -120.}), eckit::BadValue); - auto p = UnitSphere::convertSphericalToCartesian(ll1, 0., true); - auto q = UnitSphere::convertSphericalToCartesian(ll2, 0., true); + auto p = UnitSphere::convertSphericalToCartesian({45., -120.}, 0., true); + auto q = UnitSphere::convertSphericalToCartesian({225., -60.}, 0., true); // sin(x) and sin(pi-x) are not bitwise identical EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); @@ -253,12 +226,8 @@ CASE("test unit sphere area globe") { } CASE("test unit sphere area hemispheres") { - const PointLonLat ll1(-180., 90.); - const PointLonLat ll2(180., 0.); - const PointLonLat ll3(-180., 0.); - const PointLonLat ll4(180., -90.); - const double area_hemisphere_north = UnitSphere::area(ll1, ll2); - const double area_hemisphere_south = UnitSphere::area(ll3, ll4); + const double area_hemisphere_north = UnitSphere::area({-180., 90.}, {180., 0. }); + const double area_hemisphere_south = UnitSphere::area({-180., 0. }, {180., -90.}); EXPECT(area_hemisphere_north == 0.5 * UnitSphere::area()); EXPECT(area_hemisphere_north == area_hemisphere_south); From 6fee1ccfeee14f2a4ecc128a0c424cab6217eb8a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 5 Jun 2023 16:37:34 +0100 Subject: [PATCH 233/737] eckit::geometry, eckit::geo --- src/eckit/geo/projection/PROJ.cc | 2 +- src/eckit/geometry/PointLonLat.h | 14 ++++++++---- src/eckit/geometry/Sphere.cc | 21 +++++++++-------- tests/geometry/test_sphere.cc | 39 ++++++++++++++++++-------------- 4 files changed, 44 insertions(+), 32 deletions(-) diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index f5aa4db07..870e9c751 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -39,7 +39,7 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini return proj_coord(q.lon, q.lat, 0, 0); } - Point convert(const PJ_COORD& c) const final { return PointLonLat::make(c.enu.n, c.enu.e, lon_minimum_); } + Point convert(const PJ_COORD& c) const final { return PointLonLat::make(c.enu.e, c.enu.n, lon_minimum_); } explicit LonLat(double lon_minimum) : lon_minimum_(lon_minimum) {} diff --git a/src/eckit/geometry/PointLonLat.h b/src/eckit/geometry/PointLonLat.h index cf0d95ecc..e1edd6f94 100644 --- a/src/eckit/geometry/PointLonLat.h +++ b/src/eckit/geometry/PointLonLat.h @@ -38,7 +38,11 @@ class PointLonLat final : protected std::array { // -- Constructors PointLonLat(double lon, double lat) : - P{lon, lat} { ASSERT_MSG(-90. <= lat && lat <= 90., "PointLonLat: invalid latitude"); } + P{lon, lat} { + if (!(-90. <= lat && lat <= 90.)) { + throw BadValue("PointLonLat: invalid latitude"); + } + } PointLonLat(const PointLonLat& other) : P(other) {} @@ -76,7 +80,7 @@ class PointLonLat final : protected std::array { static double normalise_angle_to_maximum(double, double maximum); - static PointLonLat make(double lat, double lon, double lon_minimum = 0) { + static PointLonLat make(double lon, double lat, double lon_minimum = 0) { lat = normalise_angle_to_minimum(lat, -90.); if (lat > 90.) { @@ -84,10 +88,10 @@ class PointLonLat final : protected std::array { lon += 180.; } - return {lat, lat == -90. || lat == 90. ? 0. : normalise_angle_to_minimum(lon, lon_minimum)}; + return {lat == -90. || lat == 90. ? 0. : normalise_angle_to_minimum(lon, lon_minimum), lat}; } - PointLonLat antipode() const { return make(lat + 180., lon); } + PointLonLat antipode() const { return make(lon, lat + 180.); } // -- Overridden methods // None @@ -101,7 +105,7 @@ class PointLonLat final : protected std::array { // -- Friends friend std::ostream& operator<<(std::ostream& out, const PointLonLat& p) { - return out << '{' << p.lat << ", " << p.lon << '}'; + return out << '{' << p.lon << ", " << p.lat << '}'; } }; diff --git a/src/eckit/geometry/Sphere.cc b/src/eckit/geometry/Sphere.cc index 106d26fc4..bb738d040 100644 --- a/src/eckit/geometry/Sphere.cc +++ b/src/eckit/geometry/Sphere.cc @@ -165,7 +165,6 @@ void Sphere::greatCircleLongitudeGivenLatitude( Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, double height, bool normalise_angle) { ASSERT(radius > 0.); - assert_latitude(A.lat); /* * See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates @@ -180,15 +179,19 @@ Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, * poles and quadrants. */ - const double lambda_deg = PointLonLat::normalise_angle_to_minimum(A.lon, -180.); - const double lambda = degrees_to_radians * lambda_deg; - const double phi = degrees_to_radians * A.lat; + if (!normalise_angle) { + assert_latitude(A.lat); + } + + const auto P = PointLonLat::make(A.lon, A.lat, -180.); + const auto lambda = degrees_to_radians * P.lon; + const auto phi = degrees_to_radians * P.lat; - const double sin_phi = std::sin(phi); - const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); - const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; - const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) - : std::sqrt(1. - sin_lambda * sin_lambda); + const auto sin_phi = std::sin(phi); + const auto cos_phi = std::sqrt(1. - sin_phi * sin_phi); + const auto sin_lambda = std::abs(P.lon) < 180. ? std::sin(lambda) : 0.; + const auto cos_lambda = std::abs(P.lon) > 90. ? std::cos(lambda) + : std::sqrt(1. - sin_lambda * sin_lambda); return {(radius + height) * cos_phi * cos_lambda, (radius + height) * cos_phi * sin_lambda, diff --git a/tests/geometry/test_sphere.cc b/tests/geometry/test_sphere.cc index d21995563..a8b31a443 100644 --- a/tests/geometry/test_sphere.cc +++ b/tests/geometry/test_sphere.cc @@ -17,17 +17,19 @@ #include "eckit/geometry/UnitSphere.h" #include "eckit/testing/Test.h" -namespace eckit::test { - -using namespace geometry; +namespace eckit::tests::geometry { // set sphere struct DatumTwoUnits { static double radius() { return 2.; } }; -using TwoUnitsSphere = SphereT; +using TwoUnitsSphere = eckit::geometry::SphereT; + +using eckit::geometry::Point3; +using eckit::geometry::PointLonLat; +using eckit::geometry::UnitSphere; const double R = UnitSphere::radius(); @@ -159,10 +161,11 @@ CASE("test unit sphere lon 315") { CASE("test unit sphere lat 100") { // Default behavior throws - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({0., 100. }), eckit::BadValue); + EXPECT_THROWS_AS(PointLonLat(0., 100.), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({0., 100.}), eckit::BadValue); - auto p = UnitSphere::convertSphericalToCartesian({0., 100. }, 0., true); - auto q = UnitSphere::convertSphericalToCartesian({180., 80.}, 0., true); + auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(0., 100.), 0.); + auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(180., 80.), 0.); // sin(x) and sin(pi-x) are not bitwise identical EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); @@ -172,10 +175,11 @@ CASE("test unit sphere lat 100") { CASE("test unit sphere lat 290") { // Default behavior throws + EXPECT_THROWS_AS(PointLonLat(15., 290.), eckit::BadValue); EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({15., 290.}), eckit::BadValue); - auto p = UnitSphere::convertSphericalToCartesian({15., 290.}, 0., true); - auto q = UnitSphere::convertSphericalToCartesian({15., -70.}, 0., true); + auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., 290.), 0.); + auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., -70.), 0.); // sin(x) and sin(pi-x) are not bitwise identical EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); @@ -185,10 +189,11 @@ CASE("test unit sphere lat 290") { CASE("test unit sphere lat -120") { // Default behavior throws + EXPECT_THROWS_AS(PointLonLat(45., -120.), eckit::BadValue); EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({45., -120.}), eckit::BadValue); - auto p = UnitSphere::convertSphericalToCartesian({45., -120.}, 0., true); - auto q = UnitSphere::convertSphericalToCartesian({225., -60.}, 0., true); + auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(45., -120.), 0.); + auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(225., -60.), 0.); // sin(x) and sin(pi-x) are not bitwise identical EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); @@ -204,9 +209,9 @@ CASE("test unit sphere distances") { const PointLonLat P2(121.8, 31.4); // Shanghai // Same points with added shifts - const PointLonLat P1b(288.4, -33.); // Valparaíso + longitude shift - const PointLonLat P2b(301.8, 148.6); // Shanghai + latitude/longitude shift - const PointLonLat P2c(-58.2, -211.4); // Shanghai + latitude/longitude shift + const auto P1b = PointLonLat::make(288.4, -33.); // Valparaíso + longitude shift + const auto P2b = PointLonLat::make(301.8, 148.6); // Shanghai + latitude/longitude shift + const auto P2c = PointLonLat::make(-58.2, -211.4); // Shanghai + latitude/longitude shift const double d0 = UnitSphere::distance(P1, P2); const double d1 = UnitSphere::distance(P1b, P2); @@ -226,8 +231,8 @@ CASE("test unit sphere area globe") { } CASE("test unit sphere area hemispheres") { - const double area_hemisphere_north = UnitSphere::area({-180., 90.}, {180., 0. }); - const double area_hemisphere_south = UnitSphere::area({-180., 0. }, {180., -90.}); + const double area_hemisphere_north = UnitSphere::area({-180., 90.}, {180., 0.}); + const double area_hemisphere_south = UnitSphere::area({-180., 0.}, {180., -90.}); EXPECT(area_hemisphere_north == 0.5 * UnitSphere::area()); EXPECT(area_hemisphere_north == area_hemisphere_south); @@ -266,7 +271,7 @@ CASE("test two units sphere sub areas") { // ----------------------------------------------------------------------------- -} // namespace eckit::test +} // namespace eckit::tests::geometry int main(int argc, char** argv) { return eckit::testing::run_tests(argc, argv); From 355eba6a24eeb8c646d7238e0bf6e71662553aae Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 5 Jun 2023 16:55:56 +0100 Subject: [PATCH 234/737] eckit::geometry, eckit::geo --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f64cd245..6ecdfee60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -238,10 +238,10 @@ ecbuild_add_option( FEATURE AIO ### PROJ support -find_package( PROJ 9.2 ) ecbuild_add_option( FEATURE PROJ DEFAULT OFF - DESCRIPTION "support PROJ-based projections") + DESCRIPTION "support PROJ-based projections" + REQUIRED_PACKAGES "PROJ VERSION 9.2" ) ### ecCodes ecbuild_add_option( FEATURE ECCODES REQUIRED_PACKAGES eccodes DESCRIPTION "FIXME: remove" ) From 90403639f8c14e27f43e67e61bdcc4190a907d9b Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Fri, 23 Jun 2023 17:13:23 +0100 Subject: [PATCH 235/737] Include what you use --- src/grib_iterator_class_lambert_azimuthal_equal_area.cc | 2 +- src/grib_iterator_class_lambert_conformal.cc | 2 +- src/grib_iterator_class_polar_stereographic.cc | 2 +- src/grib_iterator_class_space_view.cc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.cc b/src/grib_iterator_class_lambert_azimuthal_equal_area.cc index f77b23afc..f9b76d702 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.cc +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.cc @@ -9,7 +9,7 @@ */ #include "grib_api_internal.h" -#include +#include /* This is used by make_class.pl diff --git a/src/grib_iterator_class_lambert_conformal.cc b/src/grib_iterator_class_lambert_conformal.cc index 8c5fed223..61e17d97c 100644 --- a/src/grib_iterator_class_lambert_conformal.cc +++ b/src/grib_iterator_class_lambert_conformal.cc @@ -9,7 +9,7 @@ */ #include "grib_api_internal.h" -#include +#include /* This is used by make_class.pl diff --git a/src/grib_iterator_class_polar_stereographic.cc b/src/grib_iterator_class_polar_stereographic.cc index 1f8b0d17b..fe1d03202 100644 --- a/src/grib_iterator_class_polar_stereographic.cc +++ b/src/grib_iterator_class_polar_stereographic.cc @@ -9,7 +9,7 @@ */ #include "grib_api_internal.h" -#include +#include /* This is used by make_class.pl diff --git a/src/grib_iterator_class_space_view.cc b/src/grib_iterator_class_space_view.cc index 70299278b..ce8294d0d 100644 --- a/src/grib_iterator_class_space_view.cc +++ b/src/grib_iterator_class_space_view.cc @@ -9,7 +9,7 @@ */ #include "grib_api_internal.h" -#include +#include /* This is used by make_class.pl From 17558db5c5888ef7dbe0eb6b3e02c1f9f11d5f64 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 24 Jun 2023 12:58:32 +0100 Subject: [PATCH 236/737] Dead code removal --- src/grib_iterator_class_space_view.cc | 80 +++++++++++++-------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/src/grib_iterator_class_space_view.cc b/src/grib_iterator_class_space_view.cc index ce8294d0d..c2e402e59 100644 --- a/src/grib_iterator_class_space_view.cc +++ b/src/grib_iterator_class_space_view.cc @@ -97,47 +97,45 @@ static int next(grib_iterator* iter, double* lat, double* lon, double* val) return 1; } -#if 0 -static void adjustBadlyEncodedEcmwfGribs(grib_handle* h, - long* nx, long* ny, double* dx, double* dy, double* xp, double* yp) -{ - /* Correct the information provided in the headers of certain satellite imagery that - * we have available. This is specific to ECMWF. - * Obtained through trial-and-error to get the best match with the coastlines. - * - * Copied from Magics GribSatelliteInterpretor::AdjustBadlyEncodedGribs() - */ - long centre = 0; - int err = grib_get_long(h, "centre", ¢re); - if (!err && centre == 98) { - int err1 = 0, err2 = 0, err3 = 0; - long satelliteIdentifier, channelNumber, functionCode; - /* These keys are defined in the ECMWF local definition 24 - Satellite image simulation */ - err1 = grib_get_long(h, "satelliteIdentifier", &satelliteIdentifier); - err2 = grib_get_long(h, "channelNumber", &channelNumber); - err3 = grib_get_long(h, "functionCode", &functionCode); - if (!err1 && !err2 && !err3) { - if (satelliteIdentifier == 54 && channelNumber == 2 && *dx == 1179) { /* Meteosat 7, channel 2 */ - *nx = *ny = 900; - *dx = *dy = 853; - *xp = *yp = 450; - } - else if (satelliteIdentifier == 54 && channelNumber == 3 && *dx == 1179) { /* Meteosat 7, channel 3 */ - *dx = *dy = 1184; - *xp = *yp = 635; - } - else if (satelliteIdentifier == 259 && channelNumber == 4 && *dx == 1185) { /* GOES-15 (West) channel 4 */ - *dx = *dy = 880; - *xp = *yp = 450; - } - else if (satelliteIdentifier == 57 && *dx == 1732) { /* MSG (Meteosat second generation), non-HRV channels */ - *dx = *dy = 1811; - *xp = *yp = 928; - } - } - } -} -#endif +// static void adjustBadlyEncodedEcmwfGribs(grib_handle* h, +// long* nx, long* ny, double* dx, double* dy, double* xp, double* yp) +// { +// /* Correct the information provided in the headers of certain satellite imagery that +// * we have available. This is specific to ECMWF. +// * Obtained through trial-and-error to get the best match with the coastlines. +// * +// * Copied from Magics GribSatelliteInterpretor::AdjustBadlyEncodedGribs() +// */ +// long centre = 0; +// int err = grib_get_long(h, "centre", ¢re); +// if (!err && centre == 98) { +// int err1 = 0, err2 = 0, err3 = 0; +// long satelliteIdentifier, channelNumber, functionCode; +// /* These keys are defined in the ECMWF local definition 24 - Satellite image simulation */ +// err1 = grib_get_long(h, "satelliteIdentifier", &satelliteIdentifier); +// err2 = grib_get_long(h, "channelNumber", &channelNumber); +// err3 = grib_get_long(h, "functionCode", &functionCode); +// if (!err1 && !err2 && !err3) { +// if (satelliteIdentifier == 54 && channelNumber == 2 && *dx == 1179) { /* Meteosat 7, channel 2 */ +// *nx = *ny = 900; +// *dx = *dy = 853; +// *xp = *yp = 450; +// } +// else if (satelliteIdentifier == 54 && channelNumber == 3 && *dx == 1179) { /* Meteosat 7, channel 3 */ +// *dx = *dy = 1184; +// *xp = *yp = 635; +// } +// else if (satelliteIdentifier == 259 && channelNumber == 4 && *dx == 1185) { /* GOES-15 (West) channel 4 */ +// *dx = *dy = 880; +// *xp = *yp = 450; +// } +// else if (satelliteIdentifier == 57 && *dx == 1732) { /* MSG (Meteosat second generation), non-HRV channels */ +// *dx = *dy = 1811; +// *xp = *yp = 928; +// } +// } +// } +// } #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ From cd1d1e9025b67ed0c05e7c2a4e3d43d5a882c8e3 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Sat, 24 Jun 2023 13:14:31 +0100 Subject: [PATCH 237/737] Dead code removal --- ...grib_iterator_class_polar_stereographic.cc | 122 +++++++++--------- 1 file changed, 60 insertions(+), 62 deletions(-) diff --git a/src/grib_iterator_class_polar_stereographic.cc b/src/grib_iterator_class_polar_stereographic.cc index fe1d03202..753649141 100644 --- a/src/grib_iterator_class_polar_stereographic.cc +++ b/src/grib_iterator_class_polar_stereographic.cc @@ -292,68 +292,66 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } y += Dy; } -#if 0 - /*standardParallel = (southPoleOnPlane == 1) ? -90 : +90;*/ - if (jPointsAreConsecutive) - { - x=xFirst; - for (i=0;i360) *lons -= 360; - lons++; - lats++; - - y+=Dy; - } - x+=Dx; - } - } - else - { - y=yFirst; - for (j=0;j360) *lons -= 360; - lons++; - lats++; - - x+=Dx; - } - y+=Dy; - } - } -#endif + +// /*standardParallel = (southPoleOnPlane == 1) ? -90 : +90;*/ +// if (jPointsAreConsecutive) +// { +// x=xFirst; +// for (i=0;i360) *lons -= 360; +// lons++; +// lats++; +// y+=Dy; +// } +// x+=Dx; +// } +// } +// else +// { +// y=yFirst; +// for (j=0;j360) *lons -= 360; +// lons++; +// lats++; +// x+=Dx; +// } +// y+=Dy; +// } +// } + iter->e = -1; /* Apply the scanning mode flags which may require data array to be transformed */ From 9ac5295dd319034e43cbdda844d55e06887fb863 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Mon, 26 Jun 2023 21:21:07 +0100 Subject: [PATCH 238/737] Rename assertion macros --- src/grib_iterator_class_lambert_conformal.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/grib_iterator_class_lambert_conformal.cc b/src/grib_iterator_class_lambert_conformal.cc index 61e17d97c..cf0000953 100644 --- a/src/grib_iterator_class_lambert_conformal.cc +++ b/src/grib_iterator_class_lambert_conformal.cc @@ -361,7 +361,7 @@ static int init_oblate(grib_handle* h, } lonRad = adjust_lon_radians(theta / ns + LoVInRadians); if (i == 0 && j == 0) { - DebugAssert(fabs(latFirstInRadians - latRad) <= EPSILON); + DEBUG_ASSERT(fabs(latFirstInRadians - latRad) <= EPSILON); } latDeg = latRad * RAD2DEG; /* Convert to degrees */ lonDeg = normalise_longitude_in_degrees(lonRad * RAD2DEG); From b1c6a88e37054be22c943941aeaf67677040b826 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 6 Jun 2023 16:11:46 +0100 Subject: [PATCH 239/737] eckit::geo::grid --- src/eckit/geo/BoundingBox.cc | 9 + src/eckit/geo/BoundingBox.h | 8 + src/eckit/geo/CMakeLists.txt | 79 ++++++ src/eckit/geo/Domain.cc | 156 +++++++++++ src/eckit/geo/Domain.h | 116 ++++++++ src/eckit/geo/Grid.cc | 184 +++++++++++++ src/eckit/geo/Grid.h | 153 +++++++++++ src/eckit/geo/Iterator.cc | 12 + src/eckit/geo/Iterator.h | 36 ++- src/eckit/geo/Point.h | 6 + src/eckit/geo/Renumber.h | 24 ++ src/eckit/geo/grib/GribConfiguration.cc | 2 +- src/eckit/geo/grid/Albers.cc | 33 +++ src/eckit/geo/grid/Albers.h | 91 +++++++ src/eckit/geo/grid/AzimuthRange.cc | 33 +++ src/eckit/geo/grid/AzimuthRange.h | 91 +++++++ src/eckit/geo/grid/Classic.cc | 43 +++ src/eckit/geo/grid/Classic.h | 90 ++++++ .../grid/EquatorialAzimuthalEquidistant.cc | 33 +++ .../geo/grid/EquatorialAzimuthalEquidistant.h | 91 +++++++ src/eckit/geo/grid/FromPL.cc | 33 +++ src/eckit/geo/grid/FromPL.h | 92 +++++++ src/eckit/geo/grid/Gaussian.cc | 124 +++++++++ src/eckit/geo/grid/Gaussian.h | 101 +++++++ src/eckit/geo/grid/GaussianIterator.cc | 113 ++++++++ src/eckit/geo/grid/GaussianIterator.h | 55 ++++ src/eckit/geo/grid/IrregularLatlon.cc | 176 ++++++++++++ src/eckit/geo/grid/IrregularLatlon.h | 108 ++++++++ src/eckit/geo/grid/Lambert.cc | 60 ++++ src/eckit/geo/grid/Lambert.h | 77 ++++++ .../geo/grid/LambertAzimuthalEqualArea.cc | 82 ++++++ .../geo/grid/LambertAzimuthalEqualArea.h | 78 ++++++ src/eckit/geo/grid/LatLon.cc | 211 +++++++++++++++ src/eckit/geo/grid/LatLon.h | 138 ++++++++++ src/eckit/geo/grid/Mercator.cc | 26 ++ src/eckit/geo/grid/Mercator.h | 74 +++++ src/eckit/geo/grid/None.cc | 38 +++ src/eckit/geo/grid/None.h | 94 +++++++ src/eckit/geo/grid/ORCA.cc | 136 ++++++++++ src/eckit/geo/grid/ORCA.h | 105 +++++++ src/eckit/geo/grid/Octahedral.cc | 43 +++ src/eckit/geo/grid/Octahedral.h | 90 ++++++ src/eckit/geo/grid/PolarStereographic.cc | 26 ++ src/eckit/geo/grid/PolarStereographic.h | 74 +++++ src/eckit/geo/grid/Reduced.cc | 256 ++++++++++++++++++ src/eckit/geo/grid/Reduced.h | 107 ++++++++ src/eckit/geo/grid/ReducedClassic.cc | 46 ++++ src/eckit/geo/grid/ReducedClassic.h | 92 +++++++ src/eckit/geo/grid/ReducedFromPL.cc | 54 ++++ src/eckit/geo/grid/ReducedFromPL.h | 94 +++++++ src/eckit/geo/grid/ReducedLL.cc | 186 +++++++++++++ src/eckit/geo/grid/ReducedLL.h | 101 +++++++ src/eckit/geo/grid/ReducedOctahedral.cc | 46 ++++ src/eckit/geo/grid/ReducedOctahedral.h | 92 +++++++ src/eckit/geo/grid/Regular.cc | 162 +++++++++++ src/eckit/geo/grid/Regular.h | 105 +++++++ src/eckit/geo/grid/RegularGG.cc | 65 +++++ src/eckit/geo/grid/RegularGG.h | 93 +++++++ src/eckit/geo/grid/RegularGrid.cc | 245 +++++++++++++++++ src/eckit/geo/grid/RegularGrid.h | 108 ++++++++ src/eckit/geo/grid/RegularLL.cc | 75 +++++ src/eckit/geo/grid/RegularLL.h | 83 ++++++ src/eckit/geo/grid/RotatedClassic.cc | 48 ++++ src/eckit/geo/grid/RotatedClassic.h | 94 +++++++ src/eckit/geo/grid/RotatedFromPL.cc | 56 ++++ src/eckit/geo/grid/RotatedFromPL.h | 95 +++++++ src/eckit/geo/grid/RotatedGG.cc | 59 ++++ src/eckit/geo/grid/RotatedGG.h | 95 +++++++ src/eckit/geo/grid/RotatedLL.cc | 78 ++++++ src/eckit/geo/grid/RotatedLL.h | 83 ++++++ src/eckit/geo/grid/RotatedOctahedral.cc | 48 ++++ src/eckit/geo/grid/RotatedOctahedral.h | 94 +++++++ src/eckit/geo/grid/SpaceView.cc | 236 ++++++++++++++++ src/eckit/geo/grid/SpaceView.h | 112 ++++++++ src/eckit/geo/grid/StretchedGG.cc | 33 +++ src/eckit/geo/grid/StretchedGG.h | 91 +++++++ src/eckit/geo/grid/StretchedLL.cc | 33 +++ src/eckit/geo/grid/StretchedLL.h | 91 +++++++ src/eckit/geo/grid/StretchedRotatedGG.cc | 33 +++ src/eckit/geo/grid/StretchedRotatedGG.h | 91 +++++++ src/eckit/geo/grid/StretchedRotatedLL.cc | 33 +++ src/eckit/geo/grid/StretchedRotatedLL.h | 91 +++++++ src/eckit/geo/grid/TransverseMercator.cc | 33 +++ src/eckit/geo/grid/TransverseMercator.h | 91 +++++++ src/eckit/geo/grid/UnstructuredGrid.cc | 215 +++++++++++++++ src/eckit/geo/grid/UnstructuredGrid.h | 121 +++++++++ 86 files changed, 7505 insertions(+), 3 deletions(-) create mode 100644 src/eckit/geo/Domain.cc create mode 100644 src/eckit/geo/Domain.h create mode 100644 src/eckit/geo/Grid.cc create mode 100644 src/eckit/geo/Grid.h create mode 100644 src/eckit/geo/Renumber.h create mode 100644 src/eckit/geo/grid/Albers.cc create mode 100644 src/eckit/geo/grid/Albers.h create mode 100644 src/eckit/geo/grid/AzimuthRange.cc create mode 100644 src/eckit/geo/grid/AzimuthRange.h create mode 100644 src/eckit/geo/grid/Classic.cc create mode 100644 src/eckit/geo/grid/Classic.h create mode 100644 src/eckit/geo/grid/EquatorialAzimuthalEquidistant.cc create mode 100644 src/eckit/geo/grid/EquatorialAzimuthalEquidistant.h create mode 100644 src/eckit/geo/grid/FromPL.cc create mode 100644 src/eckit/geo/grid/FromPL.h create mode 100644 src/eckit/geo/grid/Gaussian.cc create mode 100644 src/eckit/geo/grid/Gaussian.h create mode 100644 src/eckit/geo/grid/GaussianIterator.cc create mode 100644 src/eckit/geo/grid/GaussianIterator.h create mode 100644 src/eckit/geo/grid/IrregularLatlon.cc create mode 100644 src/eckit/geo/grid/IrregularLatlon.h create mode 100644 src/eckit/geo/grid/Lambert.cc create mode 100644 src/eckit/geo/grid/Lambert.h create mode 100644 src/eckit/geo/grid/LambertAzimuthalEqualArea.cc create mode 100644 src/eckit/geo/grid/LambertAzimuthalEqualArea.h create mode 100644 src/eckit/geo/grid/LatLon.cc create mode 100644 src/eckit/geo/grid/LatLon.h create mode 100644 src/eckit/geo/grid/Mercator.cc create mode 100644 src/eckit/geo/grid/Mercator.h create mode 100644 src/eckit/geo/grid/None.cc create mode 100644 src/eckit/geo/grid/None.h create mode 100644 src/eckit/geo/grid/ORCA.cc create mode 100644 src/eckit/geo/grid/ORCA.h create mode 100644 src/eckit/geo/grid/Octahedral.cc create mode 100644 src/eckit/geo/grid/Octahedral.h create mode 100644 src/eckit/geo/grid/PolarStereographic.cc create mode 100644 src/eckit/geo/grid/PolarStereographic.h create mode 100644 src/eckit/geo/grid/Reduced.cc create mode 100644 src/eckit/geo/grid/Reduced.h create mode 100644 src/eckit/geo/grid/ReducedClassic.cc create mode 100644 src/eckit/geo/grid/ReducedClassic.h create mode 100644 src/eckit/geo/grid/ReducedFromPL.cc create mode 100644 src/eckit/geo/grid/ReducedFromPL.h create mode 100644 src/eckit/geo/grid/ReducedLL.cc create mode 100644 src/eckit/geo/grid/ReducedLL.h create mode 100644 src/eckit/geo/grid/ReducedOctahedral.cc create mode 100644 src/eckit/geo/grid/ReducedOctahedral.h create mode 100644 src/eckit/geo/grid/Regular.cc create mode 100644 src/eckit/geo/grid/Regular.h create mode 100644 src/eckit/geo/grid/RegularGG.cc create mode 100644 src/eckit/geo/grid/RegularGG.h create mode 100644 src/eckit/geo/grid/RegularGrid.cc create mode 100644 src/eckit/geo/grid/RegularGrid.h create mode 100644 src/eckit/geo/grid/RegularLL.cc create mode 100644 src/eckit/geo/grid/RegularLL.h create mode 100644 src/eckit/geo/grid/RotatedClassic.cc create mode 100644 src/eckit/geo/grid/RotatedClassic.h create mode 100644 src/eckit/geo/grid/RotatedFromPL.cc create mode 100644 src/eckit/geo/grid/RotatedFromPL.h create mode 100644 src/eckit/geo/grid/RotatedGG.cc create mode 100644 src/eckit/geo/grid/RotatedGG.h create mode 100644 src/eckit/geo/grid/RotatedLL.cc create mode 100644 src/eckit/geo/grid/RotatedLL.h create mode 100644 src/eckit/geo/grid/RotatedOctahedral.cc create mode 100644 src/eckit/geo/grid/RotatedOctahedral.h create mode 100644 src/eckit/geo/grid/SpaceView.cc create mode 100644 src/eckit/geo/grid/SpaceView.h create mode 100644 src/eckit/geo/grid/StretchedGG.cc create mode 100644 src/eckit/geo/grid/StretchedGG.h create mode 100644 src/eckit/geo/grid/StretchedLL.cc create mode 100644 src/eckit/geo/grid/StretchedLL.h create mode 100644 src/eckit/geo/grid/StretchedRotatedGG.cc create mode 100644 src/eckit/geo/grid/StretchedRotatedGG.h create mode 100644 src/eckit/geo/grid/StretchedRotatedLL.cc create mode 100644 src/eckit/geo/grid/StretchedRotatedLL.h create mode 100644 src/eckit/geo/grid/TransverseMercator.cc create mode 100644 src/eckit/geo/grid/TransverseMercator.h create mode 100644 src/eckit/geo/grid/UnstructuredGrid.cc create mode 100644 src/eckit/geo/grid/UnstructuredGrid.h diff --git a/src/eckit/geo/BoundingBox.cc b/src/eckit/geo/BoundingBox.cc index d05091756..e6cab9064 100644 --- a/src/eckit/geo/BoundingBox.cc +++ b/src/eckit/geo/BoundingBox.cc @@ -15,6 +15,7 @@ #include #include +#include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/Point.h" #include "eckit/geometry/Sphere.h" @@ -24,6 +25,14 @@ namespace eckit::geo { +BoundingBox::BoundingBox(const Configuration& config) : + north_(config.getDouble("north")), + west_(config.getDouble("west")), + south_(config.getDouble("south")), + east_(config.getDouble("east")) { +} + + BoundingBox::BoundingBox(double north, double west, double south, double east) : north_(north), west_(west), south_(south), east_(east) { if (west_ != east_) { diff --git a/src/eckit/geo/BoundingBox.h b/src/eckit/geo/BoundingBox.h index 86eb814c8..e435cef93 100644 --- a/src/eckit/geo/BoundingBox.h +++ b/src/eckit/geo/BoundingBox.h @@ -13,6 +13,11 @@ #pragma once +namespace eckit { +class Configuration; +} + + namespace eckit::geo { @@ -23,8 +28,11 @@ class BoundingBox { // -- Constructors + BoundingBox(const Configuration&); + BoundingBox(double north, double west, double south, double east); BoundingBox(); + BoundingBox(const BoundingBox&) = default; BoundingBox(BoundingBox&&) = default; diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index f88e3eb3e..22da23e00 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -1,6 +1,10 @@ list(APPEND eckit_geo_srcs BoundingBox.cc BoundingBox.h + Domain.cc + Domain.h + Grid.cc + Grid.h Iterator.cc Iterator.h Point.cc @@ -9,9 +13,84 @@ list(APPEND eckit_geo_srcs Projection.h Range.cc Range.h + Renumber.h Scanner.cc Scanner.h Search.h + grid/Albers.cc + grid/Albers.h + grid/AzimuthRange.cc + grid/AzimuthRange.h + grid/Classic.cc + grid/Classic.h + grid/EquatorialAzimuthalEquidistant.cc + grid/EquatorialAzimuthalEquidistant.h + grid/FromPL.cc + grid/FromPL.h + grid/Gaussian.cc + grid/Gaussian.h + grid/GaussianIterator.cc + grid/GaussianIterator.h + grid/IrregularLatlon.cc + grid/IrregularLatlon.h + grid/Lambert.cc + grid/Lambert.h + grid/LambertAzimuthalEqualArea.cc + grid/LambertAzimuthalEqualArea.h + grid/LatLon.cc + grid/LatLon.h + grid/Mercator.cc + grid/Mercator.h + grid/None.cc + grid/None.h + grid/ORCA.cc + grid/ORCA.h + grid/Octahedral.cc + grid/Octahedral.h + grid/PolarStereographic.cc + grid/PolarStereographic.h + grid/Reduced.cc + grid/Reduced.h + grid/ReducedClassic.cc + grid/ReducedClassic.h + grid/ReducedFromPL.cc + grid/ReducedFromPL.h + grid/ReducedLL.cc + grid/ReducedLL.h + grid/ReducedOctahedral.cc + grid/ReducedOctahedral.h + grid/Regular.cc + grid/Regular.h + grid/RegularGG.cc + grid/RegularGG.h + grid/RegularGrid.cc + grid/RegularGrid.h + grid/RegularLL.cc + grid/RegularLL.h + grid/RotatedClassic.cc + grid/RotatedClassic.h + grid/RotatedFromPL.cc + grid/RotatedFromPL.h + grid/RotatedGG.cc + grid/RotatedGG.h + grid/RotatedLL.cc + grid/RotatedLL.h + grid/RotatedOctahedral.cc + grid/RotatedOctahedral.h + grid/SpaceView.cc + grid/SpaceView.h + grid/StretchedGG.cc + grid/StretchedGG.h + grid/StretchedLL.cc + grid/StretchedLL.h + grid/StretchedRotatedGG.cc + grid/StretchedRotatedGG.h + grid/StretchedRotatedLL.cc + grid/StretchedRotatedLL.h + grid/TransverseMercator.cc + grid/TransverseMercator.h + grid/UnstructuredGrid.cc + grid/UnstructuredGrid.h iterator/IteratorAggregator.h iterator/IteratorComposer.cc iterator/IteratorComposer.h diff --git a/src/eckit/geo/Domain.cc b/src/eckit/geo/Domain.cc new file mode 100644 index 000000000..2567a8c9f --- /dev/null +++ b/src/eckit/geo/Domain.cc @@ -0,0 +1,156 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Domain.h" + +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/Point.h" +#include "eckit/geometry/Sphere.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo { + + +Domain::Domain(double north, double west, double south, double east) : + north_(north), west_(west), south_(south), east_(east) { + if (west_ != east_) { + auto e = PointLonLat::normalise_angle_to_minimum(east, west); + east_ = e == west_ ? (e + 360.) : e; + } + + ASSERT_MSG(west_ <= east_ && east_ <= west_ + 360., "Domain: longitude range"); + ASSERT_MSG(-90. <= south_ && south_ <= north_ && north_ <= 90., "Domain: latitude range"); +} + + +Domain::Domain() : + Domain(90., 0., -90., 360.) {} + + +bool Domain::operator==(const Domain& other) const { + return north_ == other.north_ && south_ == other.south_ && west_ == other.west_ && east_ == other.east_; +} + + +bool Domain::isGlobal() const { + return includesNorthPole() && includesSouthPole() && isPeriodicWestEast(); +} + + +bool Domain::includesNorthPole() const { + return north_ == NORTH_POLE; +} + + +bool Domain::includesSouthPole() const { + return south_ == SOUTH_POLE; +} + + +bool Domain::isPeriodicWestEast() const { + return west_ != east_ && west_ == PointLonLat::normalise_angle_to_minimum(east_, west_); +} + + +bool Domain::contains(double lat, double lon) const { + return lat <= north_ && lat >= south_ && PointLonLat::normalise_angle_to_minimum(lon, west_) <= east_; +} + + +bool Domain::contains(const Domain& other) const { + if (other.empty()) { + return contains(other.south_, other.west_); + } + + // check for West/East range (if non-periodic), then other's corners + if (east_ - west_ < other.east_ - other.west_ || east_ < PointLonLat::normalise_angle_to_minimum(other.east_, west_)) { + return false; + } + + return contains(other.north_, other.west_) && contains(other.north_, other.east_) && contains(other.south_, other.west_) && contains(other.south_, other.east_); +} + + +bool Domain::intersects(Domain& other) const { + auto n = std::min(north_, other.north_); + auto s = std::max(south_, other.south_); + + bool intersectsSN = s <= n; + if (!intersectsSN) { + n = s; + } + + if (isPeriodicWestEast() && other.isPeriodicWestEast()) { + other = {n, other.west_, s, other.east_}; + return intersectsSN; + } + + auto w = std::min(west_, other.west_); + auto e = w; + + auto intersect = [](const Domain& a, const Domain& b, double& w, double& e) { + bool p = a.isPeriodicWestEast(); + if (p || b.isPeriodicWestEast()) { + w = (p ? b : a).west_; + e = (p ? b : a).east_; + return true; + } + + auto ref = PointLonLat::normalise_angle_to_minimum(b.west_, a.west_); + auto w_ = std::max(a.west_, ref); + auto e_ = std::min(a.east_, PointLonLat::normalise_angle_to_minimum(b.east_, ref)); + + if (w_ <= e_) { + w = w_; + e = e_; + return true; + } + + return false; + }; + + bool intersectsWE = west_ <= other.west_ ? intersect(*this, other, w, e) || intersect(other, *this, w, e) + : intersect(other, *this, w, e) || intersect(*this, other, w, e); + + ASSERT_MSG(w <= e, "Domain::intersects: longitude range"); + other = {n, w, s, e}; + + return intersectsSN && intersectsWE; +} + + +bool Domain::empty() const { + return types::is_approximately_equal(north_, south_) || types::is_approximately_equal(west_, east_); +} + + +double Domain::area(double radius) const { + double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); + ASSERT(0. <= lonf && lonf <= 1.); + + constexpr auto degrees_to_radians = M_PI / 180.; + + const auto sn = std::sin(north_ * degrees_to_radians); + const auto ss = std::sin(south_ * degrees_to_radians); + + double latf = 0.5 * (sn - ss); + ASSERT(0. <= latf && latf <= 1.); + + return geometry::Sphere::area(radius) * latf * lonf; +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Domain.h b/src/eckit/geo/Domain.h new file mode 100644 index 000000000..002096d65 --- /dev/null +++ b/src/eckit/geo/Domain.h @@ -0,0 +1,116 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + + +namespace eckit::geo { + + +class Domain { +public: + // -- Exceptions + // None + + // -- Constructors + + Domain(double north, double west, double south, double east); + Domain(); + Domain(const Domain&) = default; + Domain(Domain&&) = default; + + // -- Destructor + + virtual ~Domain() = default; + + // -- Convertors + // None + + // -- Operators + + Domain& operator=(const Domain&) = default; + Domain& operator=(Domain&&) = default; + bool operator==(const Domain&) const; + bool operator!=(const Domain& other) const { return !operator==(other); } + + // -- Methods + + double north() const { return north_; } + double west() const { return west_; } + double south() const { return south_; } + double east() const { return east_; } + + bool isGlobal() const; + bool includesNorthPole() const; + bool includesSouthPole() const; + bool isPeriodicWestEast() const; + + bool contains(double lat, double lon) const; + bool contains(const Domain&) const; + bool intersects(Domain&) const; + bool empty() const; + double area(double radius) const; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None + +private: + // -- Members + + double north_; + double west_; + double south_; + double east_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc new file mode 100644 index 000000000..243364b9a --- /dev/null +++ b/src/eckit/geo/Grid.cc @@ -0,0 +1,184 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Grid.h" + +#include +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/Domain.h" +#include "eckit/geo/Iterator.h" +#include "eckit/geo/grid/UnstructuredGrid.h" +#include "eckit/thread/AutoLock.h" +#include "eckit/thread/Mutex.h" + + +namespace eckit::geo { + + +Grid::Grid(const Configuration& config) : + bbox_(config) {} + + +Grid::Grid(const BoundingBox& bbox) : + bbox_(bbox) {} + + +bool Grid::isGlobal() const { + return domain().isGlobal(); +} + + +bool Grid::isPeriodicWestEast() const { + std::ostringstream os; + os << "Grid::isPeriodicWestEast() not implemented for " << *this; + throw SeriousBug(os.str()); +} + + +bool Grid::includesNorthPole() const { + std::ostringstream os; + os << "Grid::includesNorthPole() not implemented for " << *this; + throw SeriousBug(os.str()); +} + + +bool Grid::includesSouthPole() const { + std::ostringstream os; + os << "Grid::includesSouthPole() not implemented for " << *this; + throw SeriousBug(os.str()); +} + + +const Grid* Grid::croppedGrid(const BoundingBox& /*unused*/) const { + std::ostringstream os; + os << "Grid::croppedGrid() not implemented for " << *this; + throw SeriousBug(os.str()); +} + + +bool Grid::sameAs(const Grid& /*unused*/) const { + std::ostringstream os; + os << "Grid::sameAs() not implemented for " << *this; + throw SeriousBug(os.str()); +} + + +bool Grid::crop(BoundingBox& /*unused*/, Renumber& /*unused*/) const { + std::ostringstream os; + os << "Grid::crop() not implemented for " << *this; + throw SeriousBug(os.str()); +} + + +size_t Grid::numberOfPoints() const { + std::ostringstream os; + os << "Grid::numberOfPoints() not implemented for " << *this; + throw SeriousBug(os.str()); +} + + +void Grid::reorder(long /*unused*/, MIRValuesVector& /*unused*/) const { + std::ostringstream os; + os << "Grid::reorder() not implemented for " << *this; + throw SeriousBug(os.str()); +} + + +Iterator* Grid::iterator() const { + std::ostringstream os; + os << "Grid::iterator() not implemented for " << *this; + throw SeriousBug(os.str()); +} + + +Domain Grid::domain() const { + double n = includesNorthPole() ? NORTH_POLE : bbox_.north(); + double s = includesSouthPole() ? SOUTH_POLE : bbox_.south(); + double w = bbox_.west(); + double e = isPeriodicWestEast() ? bbox_.west() + GLOBE : bbox_.east(); + + return {n, w, s, e}; +} + + +const BoundingBox& Grid::boundingBox() const { + return bbox_; +} + + +static pthread_once_t __once; +static Mutex* __mutex = nullptr; +static std::map* m = nullptr; +static void __init() { + __mutex = new Mutex; + m = new std::map(); +} + + +GridFactory::GridFactory(const std::string& name) : + name_(name) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + if (m->find(name) != m->end()) { + throw SeriousBug("GridFactory: duplicate '" + name + "'"); + } + + ASSERT(m->find(name) == m->end()); + (*m)[name] = this; +} + + +GridFactory::~GridFactory() { + AutoLock lock(*__mutex); + + m->erase(name_); +} + + +const Grid* GridFactory::build(const Configuration& params) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + std::string name; + if (!params.get("gridType", name)) { + throw SeriousBug("GridFactory: cannot get 'gridType'"); + } + + Log::debug() << "GridFactory: looking for '" << name << "'" << std::endl; + + auto j = m->find(name); + if (j == m->end()) { + list(Log::error() << "GridFactory: unknown '" << name << "', choices are: "); + throw SeriousBug("GridFactory: unknown '" + name + "'"); + } + + return j->second->make(params); +} + + +void GridFactory::list(std::ostream& out) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + const char* sep = ""; + for (const auto& j : *m) { + out << sep << j.first; + sep = ", "; + } +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h new file mode 100644 index 000000000..861ed502a --- /dev/null +++ b/src/eckit/geo/Grid.h @@ -0,0 +1,153 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + +#include + +#include "eckit/config/Configuration.h" +#include "eckit/geo/BoundingBox.h" +#include "eckit/geo/Point.h" + + +namespace eckit::geo { +class Renumber; +class Domain; +class Iterator; +} // namespace eckit::geo + + +namespace eckit::geo { + + +class Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + Grid(const Configuration&); + Grid(const BoundingBox&); + + // -- Destructor + + virtual ~Grid() = default; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + virtual Iterator* iterator() const; + virtual Renumber crop(BoundingBox&) const; + virtual bool includesNorthPole() const; + virtual bool includesSouthPole() const; + virtual bool isGlobal() const; + virtual bool isPeriodicWestEast() const; + virtual bool sameAs(const Grid&) const; + virtual const BoundingBox& boundingBox() const; + virtual const Grid* croppedGrid(const BoundingBox&) const; + virtual size_t numberOfPoints() const; + virtual Domain domain() const; + virtual void print(std::ostream&) const; + virtual void reorder(long scanningMode) const; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + const BoundingBox& bbox() const { return bbox_; } + void bbox(const BoundingBox& bbox) { bbox_ = bbox; } + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + BoundingBox bbox_; + mutable std::string uniqueName_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + + friend std::ostream& operator<<(std::ostream& s, const Grid& p) { + p.print(s); + return s; + } +}; + + +class GridFactory { + std::string name_; + virtual Grid* make(const Configuration&) = 0; + + GridFactory(const GridFactory&) = delete; + GridFactory& operator=(const GridFactory&) = delete; + +protected: + GridFactory(const std::string&); + virtual ~GridFactory(); + +public: + // This is 'const' as Grid should always be immutable + static const Grid* build(const Configuration&); + static void list(std::ostream&); +}; + + +template +class GridBuilder : public GridFactory { + Grid* make(const Configuration& param) override { return new T(param); } + +public: + GridBuilder(const std::string& name) : + GridFactory(name) {} +}; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Iterator.cc b/src/eckit/geo/Iterator.cc index 1a5a0fc56..c94c3ac72 100644 --- a/src/eckit/geo/Iterator.cc +++ b/src/eckit/geo/Iterator.cc @@ -16,6 +16,7 @@ #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Projection.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -35,6 +36,17 @@ static void __init() { } +Iterator::Iterator(Projection* projection) : + projection_(projection), + valid_(true) {} + + +void Iterator::print(std::ostream& out) const { + out << "Iterator[valid?" + << valid_ << ",point=" << point_ << "]"; +} + + Iterator* IteratorFactory::build(const IteratorFactory::key_type& key, const Configuration& config) { pthread_once(&__once, __init); AutoLock lock(*__mutex); diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index 0f7489058..5411d1e4a 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include #include "eckit/geo/Point.h" @@ -20,7 +21,10 @@ namespace eckit { class Configuration; +namespace geo { +class Projection; } +} // namespace eckit namespace eckit::geo { @@ -67,6 +71,8 @@ class Iterator { // -- Constructors + Iterator(Projection* = nullptr); + Iterator(const Iterator&) = delete; Iterator(Iterator&&) = delete; @@ -75,7 +81,8 @@ class Iterator { virtual ~Iterator() = default; // -- Convertors - // None + + operator bool() { return valid_; } // -- Operators @@ -106,6 +113,27 @@ class Iterator { // -- Class methods // None +protected: + // -- Members + + Point2 point_; + std::unique_ptr projection_; + bool valid_; + + // -- Methods + + virtual void print(std::ostream&) const = 0; + virtual size_t index() const = 0; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + private: // -- Members // None @@ -123,7 +151,11 @@ class Iterator { // None // -- Friends - // None + + friend std::ostream& operator<<(std::ostream& s, const Iterator& p) { + p.print(s); + return s; + } }; diff --git a/src/eckit/geo/Point.h b/src/eckit/geo/Point.h index b574dc5f8..1bcba88ff 100644 --- a/src/eckit/geo/Point.h +++ b/src/eckit/geo/Point.h @@ -33,6 +33,12 @@ using Point = std::variant; bool points_equal(const Point&, const Point&); +constexpr double GLOBE = 360.; +constexpr double GREENWICH = 0.; +constexpr double NORTH_POLE = 90.; +constexpr double SOUTH_POLE = -90.; + + } // namespace eckit::geo diff --git a/src/eckit/geo/Renumber.h b/src/eckit/geo/Renumber.h new file mode 100644 index 000000000..e0c7c92c0 --- /dev/null +++ b/src/eckit/geo/Renumber.h @@ -0,0 +1,24 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + + +namespace eckit::geo { + + +using Renumber = std::vector; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/grib/GribConfiguration.cc b/src/eckit/geo/grib/GribConfiguration.cc index 7e71157bc..5c89f951b 100644 --- a/src/eckit/geo/grib/GribConfiguration.cc +++ b/src/eckit/geo/grib/GribConfiguration.cc @@ -18,7 +18,7 @@ namespace eckit::geo::grib { -static eckit::Value __root_dummy; +static Value __root_dummy; GribConfiguration::GribConfiguration(codes_handle* h) : diff --git a/src/eckit/geo/grid/Albers.cc b/src/eckit/geo/grid/Albers.cc new file mode 100644 index 000000000..7fdfadbba --- /dev/null +++ b/src/eckit/geo/grid/Albers.cc @@ -0,0 +1,33 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/Albers.h" + +#include + + +namespace eckit::geo::grid { + + +Albers::Albers(const Configuration& /*config*/) {} + + +void Albers::print(std::ostream& out) const { + out << "Albers[" + << "]"; +} + + +static const GridBuilder __repres("albers"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Albers.h b/src/eckit/geo/grid/Albers.h new file mode 100644 index 000000000..5f5585e86 --- /dev/null +++ b/src/eckit/geo/grid/Albers.h @@ -0,0 +1,91 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class Albers : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + Albers(const Configuration&); + Albers(const Albers&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + Albers& operator=(const Albers&) = delete; + + // -- Methods + // // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/AzimuthRange.cc b/src/eckit/geo/grid/AzimuthRange.cc new file mode 100644 index 000000000..4ce1fad4b --- /dev/null +++ b/src/eckit/geo/grid/AzimuthRange.cc @@ -0,0 +1,33 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/AzimuthRange.h" + +#include + + +namespace eckit::geo::grid { + + +AzimuthRange::AzimuthRange(const Configuration& /*config*/) {} + + +void AzimuthRange::print(std::ostream& out) const { + out << "AzimuthRange[" + << "]"; +} + + +static const GridBuilder __repres("azimuth_range"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/AzimuthRange.h b/src/eckit/geo/grid/AzimuthRange.h new file mode 100644 index 000000000..980940872 --- /dev/null +++ b/src/eckit/geo/grid/AzimuthRange.h @@ -0,0 +1,91 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class AzimuthRange : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + AzimuthRange(const Configuration&); + AzimuthRange(const AzimuthRange&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + AzimuthRange& operator=(const AzimuthRange&) = delete; + + // -- Methods + // // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Classic.cc b/src/eckit/geo/grid/Classic.cc new file mode 100644 index 000000000..e4cb5ec15 --- /dev/null +++ b/src/eckit/geo/grid/Classic.cc @@ -0,0 +1,43 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/Classic.h" + + +namespace eckit::geo::grid { + + +Classic::Classic(size_t N, const BoundingBox& box, double angularPrecision) : + Reduced(N, box, angularPrecision) { + + // adjust latitudes, longitudes and re-set bounding box + auto n = box.north(); + auto s = box.south(); + correctSouthNorth(s, n); + + setNj(pls("N" + std::to_string(N_)), s, n); + + auto w = box.west(); + auto e = box.east(); + correctWestEast(w, e); + + bbox({n, w, s, e}); +} + + +bool Classic::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && Reduced::sameAs(other); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Classic.h b/src/eckit/geo/grid/Classic.h new file mode 100644 index 000000000..7e30d1751 --- /dev/null +++ b/src/eckit/geo/grid/Classic.h @@ -0,0 +1,90 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Reduced.h" + + +namespace eckit::geo::grid { + + +class Classic : public Reduced { +public: + // -- Exceptions + // None + + // -- Constructors + + Classic(size_t, const BoundingBox& = BoundingBox(), double angularPrecision = 0); + + // -- Destructor + + virtual ~Classic() override = default; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + bool sameAs(const Grid&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.cc b/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.cc new file mode 100644 index 000000000..dd38b1384 --- /dev/null +++ b/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.cc @@ -0,0 +1,33 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/EquatorialAzimuthalEquidistant.h" + +#include + + +namespace eckit::geo::grid { + + +EquatorialAzimuthalEquidistant::EquatorialAzimuthalEquidistant(const Configuration& /*config*/) {} + + +void EquatorialAzimuthalEquidistant::print(std::ostream& out) const { + out << "EquatorialAzimuthalEquidistant[" + << "]"; +} + + +static const GridBuilder __repres("equatorial_azimuthal_equidistant"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.h b/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.h new file mode 100644 index 000000000..eb20674bc --- /dev/null +++ b/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.h @@ -0,0 +1,91 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class EquatorialAzimuthalEquidistant : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + EquatorialAzimuthalEquidistant(const Configuration&); + EquatorialAzimuthalEquidistant(const EquatorialAzimuthalEquidistant&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + EquatorialAzimuthalEquidistant& operator=(const EquatorialAzimuthalEquidistant&) = delete; + + // -- Methods + // // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/FromPL.cc b/src/eckit/geo/grid/FromPL.cc new file mode 100644 index 000000000..b4c445664 --- /dev/null +++ b/src/eckit/geo/grid/FromPL.cc @@ -0,0 +1,33 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/FromPL.h" + + +namespace eckit::geo::grid { + + +FromPL::FromPL(const Configuration& config) : + Reduced(config) {} + + +FromPL::FromPL(size_t N, const std::vector& pl, const BoundingBox& bbox, double angularPrecision) : + Reduced(N, pl, bbox, angularPrecision) {} + + +bool FromPL::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && (pls() == o->pls()) && Reduced::sameAs(other); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/FromPL.h b/src/eckit/geo/grid/FromPL.h new file mode 100644 index 000000000..ffd781b2e --- /dev/null +++ b/src/eckit/geo/grid/FromPL.h @@ -0,0 +1,92 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Reduced.h" + + +namespace eckit::geo::grid { + + +class FromPL : public Reduced { +public: + // -- Exceptions + // None + + // -- Constructors + + FromPL(const Configuration&); + FromPL(size_t, const std::vector&, const BoundingBox& = BoundingBox(), + double angularPrecision = 0); + + // -- Destructor + + virtual ~FromPL() override = default; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + bool sameAs(const Grid&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Gaussian.cc b/src/eckit/geo/grid/Gaussian.cc new file mode 100644 index 000000000..a81e8cccf --- /dev/null +++ b/src/eckit/geo/grid/Gaussian.cc @@ -0,0 +1,124 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/Gaussian.h" + +#include +#include +#include + +#include "eckit/geo/Domain.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::grid { + + +Gaussian::Gaussian(size_t N, const BoundingBox& bbox) : + Grid(bbox), N_(N), angularPrecision_(0) { + ASSERT(N_ > 0); +} + + +Gaussian::Gaussian(const Configuration& config) : + Grid(config), N_(0), angularPrecision_(0) { + + ASSERT(config.get("N", N_)); + ASSERT(N_ > 0); + + config.get("angular_precision", angularPrecision_); + ASSERT(angularPrecision_ >= 0); +} + + +Gaussian::~Gaussian() = default; + + +bool Gaussian::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && (N_ == o->N_) && (domain() == o->domain()); +} + + +bool Gaussian::includesNorthPole() const { + return bbox().north() >= latitudes().front(); +} + + +bool Gaussian::includesSouthPole() const { + return bbox().south() <= latitudes().back(); +} + + +bool Gaussian::angleApproximatelyEqual(const double& A, const double& B) const { + return angularPrecision_ > 0 ? types::is_approximately_equal(A, B, angularPrecision_) + : A == B; +} + + +void Gaussian::correctSouthNorth(double& s, double& n, bool in) const { + ASSERT(s <= n); + + const std::vector& lats = latitudes(); + ASSERT(!lats.empty()); + + const bool same(s == n); + if (n < lats.back()) { + n = lats.back(); + } + else if (in) { + auto best = std::lower_bound(lats.begin(), lats.end(), n, [this](double l1, double l2) { + if (angleApproximatelyEqual(l1, l2)) { + return false; + } + return !(l1 < l2); + }); + ASSERT(best != lats.end()); + n = *best; + } + else if (n > lats.front()) { + // extend 'outwards': don't change, it's already above the Gaussian latitudes + } + else { + auto best = std::lower_bound(lats.rbegin(), lats.rend(), n); + n = *best; + } + + if (same && in) { + s = n; + } + else if (s > lats.front()) { + s = lats.front(); + } + else if (in) { + auto best = std::lower_bound(lats.rbegin(), lats.rend(), s, [this](double l1, double l2) { + if (angleApproximatelyEqual(l1, l2)) { + return false; + } + return !(l1 > l2); + }); + ASSERT(best != lats.rend()); + s = *best; + } + else if (s < lats.back()) { + // extend 'outwards': don't change, it's already below the Gaussian latitudes + } + else { + auto best = std::lower_bound(lats.begin(), lats.end(), s, [](double l1, double l2) { return l1 > l2; }); + s = *best; + } + + ASSERT(s <= n); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Gaussian.h b/src/eckit/geo/grid/Gaussian.h new file mode 100644 index 000000000..44cc7d5c0 --- /dev/null +++ b/src/eckit/geo/grid/Gaussian.h @@ -0,0 +1,101 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class Gaussian : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + Gaussian(size_t N, const BoundingBox& = {}); + Gaussian(const Configuration&); + + // -- Destructor + + ~Gaussian() override; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + + size_t N_; + double angularPrecision_; + + // -- Methods + + const std::vector& latitudes() const; + + bool angleApproximatelyEqual(const double&, const double&) const; + + void correctSouthNorth(double& s, double& n, bool in = true) const; + + // -- Overridden methods + + bool sameAs(const Grid&) const override; + + bool includesNorthPole() const override; + bool includesSouthPole() const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/GaussianIterator.cc b/src/eckit/geo/grid/GaussianIterator.cc new file mode 100644 index 000000000..499d3be1a --- /dev/null +++ b/src/eckit/geo/grid/GaussianIterator.cc @@ -0,0 +1,113 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/GaussianIterator.h" + +#include + + +namespace eckit::geo::grid { + + +GaussianIterator::GaussianIterator(const std::vector& latitudes, std::vector&& pl, + const BoundingBox& bbox, size_t N, size_t Nj, size_t k, + const Rotation& rotation) : + Iterator(rotation), + latitudes_(latitudes), + pl_(pl), + bbox_(bbox), + N_(N), + Ni_(0), + Nj_(Nj), + i_(0), + j_(0), + k_(k), + count_(0), + first_(true) { + + // NOTE: latitudes_ span the globe, sorted from North-to-South, k_ positions the North + // NOTE: pl is global + ASSERT(N_ * 2 == latitudes_.size()); + ASSERT(Nj_ > 0); +} + + +GaussianIterator::~GaussianIterator() = default; + + +size_t GaussianIterator::resetToRow(size_t j) { + ASSERT(j < latitudes_.size()); + lat_ = latitudes_[j]; + + auto Ni_globe = pl_[j]; + ASSERT(Ni_globe > 1); + + inc_ = GLOBE.fraction() / Ni_globe; + + const auto w = bbox_.west().fraction(); + auto Nw = (w / inc_).integralPart(); + if (Nw * inc_ < w) { + Nw += 1; + } + + const auto e = bbox_.east().fraction(); + auto Ne = (e / inc_).integralPart(); + if (Ne * inc_ > e) { + Ne -= 1; + } + + lon_ = Nw * inc_; + return Nw > Ne ? 0 : std::min(size_t(Ni_globe), size_t(Ne - Nw + 1)); +} + + +void GaussianIterator::print(std::ostream& out) const { + out << "GaussianIterator["; + Iterator::print(out); + out << ",N=" << N_ << ",bbox=" << bbox_ << ",Ni=" << Ni_ << ",Nj=" << Nj_ << ",i=" << i_ << ",j=" << j_ + << ",k=" << k_ << ",count=" << count_ << "]"; +} + + +bool GaussianIterator::operator++() { + while (Ni_ == 0 && j_ < Nj_) { + Ni_ = resetToRow(k_ + j_++); + } + + if (0 < Nj_ && i_ < Ni_) { + lon_ += inc_; + + if (first_) { + first_ = false; + } + else { + count_++; + } + + if (++i_ == Ni_) { + i_ = 0; + Ni_ = 0; + } + + return true; + } + + return false; +} + + +size_t GaussianIterator::index() const { + return count_; +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/GaussianIterator.h b/src/eckit/geo/grid/GaussianIterator.h new file mode 100644 index 000000000..b47c922ba --- /dev/null +++ b/src/eckit/geo/grid/GaussianIterator.h @@ -0,0 +1,55 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "eckit/types/Fraction.h" + +#include "eckit/geo/Iterator.h" + + +namespace eckit::geo::grid { + + +class GaussianIterator : public Iterator { +public: + GaussianIterator(const std::vector& latitudes, std::vector&& pl, const BoundingBox&, size_t N, + size_t Nj, size_t k, const Rotation& = Rotation()); + ~GaussianIterator() override; + +private: + const std::vector& latitudes_; + const std::vector pl_; + const BoundingBox& bbox_; + const size_t N_; + size_t Ni_; + size_t Nj_; + Fraction lon_; + Latitude lat_; + Fraction inc_; + size_t i_; + size_t j_; + size_t k_; + size_t count_; + bool first_; + +protected: + void print(std::ostream&) const override; + bool operator++() override; + size_t index() const override; + size_t resetToRow(size_t j); +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/IrregularLatlon.cc b/src/eckit/geo/grid/IrregularLatlon.cc new file mode 100644 index 000000000..2833becad --- /dev/null +++ b/src/eckit/geo/grid/IrregularLatlon.cc @@ -0,0 +1,176 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/IrregularLatlon.h" + +#include +#include + +#include "eckit/utils/MD5.h" + +#include "eckit/geo/Iterator.h" + + +namespace eckit::geo::grid { + + +static void range(const std::vector& v, double& mn, double& mx, double& dmax) { + + ASSERT(v.size() >= 2); + + dmax = 0; + mx = v[0]; + mn = v[0]; + + for (size_t i = 1; i < v.size(); ++i) { + double d = std::abs(v[i] - v[i - 1]); + dmax = std::max(d, dmax); + mx = std::max(v[i], mx); + mn = std::min(v[i], mn); + } +} + + +IrregularLatlon::IrregularLatlon(const Configuration& config) { + + ASSERT(config.get("latitudes", latitudes_)); + range(latitudes_, south_, north_, south_north_); + + ASSERT(config.get("longitudes", longitudes_)); + range(longitudes_, west_, east_, west_east_); +} + + +IrregularLatlon::IrregularLatlon() = default; + + +IrregularLatlon::~IrregularLatlon() = default; + + +size_t IrregularLatlon::numberOfPoints() const { + return latitudes_.size() * longitudes_.size(); +} + + +void IrregularLatlon::print(std::ostream& out) const { + out << "IrregularLatlon[latitudes=" << latitudes_.size() << ",longitudes=" << longitudes_.size() << "]"; +} + + +bool IrregularLatlon::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && (latitudes_ == o->latitudes_) && (longitudes_ == o->longitudes_); +} + + +Domain IrregularLatlon::domain() const { + const auto n = includesNorthPole() ? NORTH_POLE : north_; + const auto s = includesSouthPole() ? SOUTH_POLE : south_; + const auto w = west_; + const auto e = isPeriodicWestEast() ? west_ + GLOBE : east_; + + return {n, w, s, e}; +} + + +class IrregularLatlonIterator : public Iterator { + size_t i_; + size_t ni_; + size_t j_; + size_t nj_; + size_t count_; + bool first_; + + const std::vector& latitudes_; + const std::vector& longitudes_; + + void print(std::ostream& out) const override { + out << "IrregularLatlonIterator["; + Iterator::print(out); + out << "]"; + } + + bool operator++() override { + if (j_ < nj_) { + if (i_ < ni_) { + // lat = latitudes_[j_]; + // lon = longitudes_[i_]; + + if (first_) { + first_ = false; + } + else { + count_++; + } + + if (++i_ == ni_) { + ++j_; + i_ = 0; + } + + return true; + } + } + return false; + } + + size_t index() const override { return count_; } + +public: + // TODO: Consider keeping a reference on the latitudes and bbox, to avoid copying + + IrregularLatlonIterator(const std::vector& latitudes, const std::vector& longitudes) : + i_(0), + ni_(longitudes.size()), + j_(0), + nj_(latitudes.size()), + count_(0), + first_(true), + latitudes_(latitudes), + longitudes_(longitudes) {} + + ~IrregularLatlonIterator() override { + auto count = count_ + (i_ > 0 || j_ > 0 ? 1 : 0); + ASSERT(count == ni_ * nj_); + } + + IrregularLatlonIterator(const IrregularLatlonIterator&) = delete; + IrregularLatlonIterator(IrregularLatlonIterator&&) = delete; + IrregularLatlonIterator& operator=(const IrregularLatlonIterator&) = delete; + IrregularLatlonIterator& operator=(IrregularLatlonIterator&&) = delete; +}; + + +Iterator* IrregularLatlon::iterator() const { + return new IrregularLatlonIterator(latitudes_, longitudes_); +} + + +bool IrregularLatlon::isPeriodicWestEast() const { + return (east_ - west_) + west_east_ >= GLOBE.value(); +} + + +bool IrregularLatlon::includesNorthPole() const { + return north_ + south_north_ >= NORTH_POLE.value(); +} + + +bool IrregularLatlon::includesSouthPole() const { + return south_ - south_north_ <= SOUTH_POLE.value(); +} + + +static const GridBuilder irregularLatlon("irregular_latlon"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/IrregularLatlon.h b/src/eckit/geo/grid/IrregularLatlon.h new file mode 100644 index 000000000..53c7b9132 --- /dev/null +++ b/src/eckit/geo/grid/IrregularLatlon.h @@ -0,0 +1,108 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class IrregularLatlon : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + IrregularLatlon(const Configuration&); + + // -- Destructor + + ~IrregularLatlon() override; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + IrregularLatlon(); + + // -- Members + + double south_; + double north_; + double south_north_; + + double west_; + double east_; + double west_east_; + + std::vector latitudes_; + std::vector longitudes_; + + // -- Methods + // None + + // -- Overridden methods + + size_t numberOfPoints() const override; + bool sameAs(const Grid&) const override; + Domain domain() const override; + Iterator* iterator() const override; + bool isPeriodicWestEast() const override; + bool includesNorthPole() const override; + bool includesSouthPole() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Lambert.cc b/src/eckit/geo/grid/Lambert.cc new file mode 100644 index 000000000..dad114788 --- /dev/null +++ b/src/eckit/geo/grid/Lambert.cc @@ -0,0 +1,60 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/Lambert.h" + + +namespace eckit::geo::grid { + + +static const GridBuilder __builder("lambert"); + + +Lambert::Lambert(const Configuration& param) : + RegularGrid(param, make_projection(param)) { + long edition = 0; + param.get("edition", edition); + + // GRIB1 cannot write LaD + writeLaDInDegrees_ = edition == 2; + param.get("writeLaDInDegrees", writeLaDInDegrees_); + + // GRIB2 cannot write negative longitude values + writeLonPositive_ = edition == 2; + param.get("writeLonPositive", writeLonPositive_); +} + + +Projection Lambert::make_projection(const Configuration& param) { + auto spec = make_proj_spec(param); + if (!spec.empty()) { + return spec; + } + + double LaDInDegrees; + double LoVInDegrees; + double Latin1InDegrees; + double Latin2InDegrees; + ASSERT(param.get("LaDInDegrees", LaDInDegrees)); + ASSERT(param.get("LoVInDegrees", LoVInDegrees)); + param.get("Latin1InDegrees", Latin1InDegrees = LaDInDegrees); + param.get("Latin2InDegrees", Latin2InDegrees = LaDInDegrees); + + return Configuration("type", "lambert_conformal_conic") + .set("latitude1", Latin1InDegrees) + .set("latitude2", Latin2InDegrees) + .set("latitude0", LaDInDegrees) + .set("longitude0", LoVInDegrees); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Lambert.h b/src/eckit/geo/grid/Lambert.h new file mode 100644 index 000000000..f6ad62b3b --- /dev/null +++ b/src/eckit/geo/grid/Lambert.h @@ -0,0 +1,77 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/RegularGrid.h" + + +namespace eckit::geo::grid { + + +class Lambert : public RegularGrid { +public: + // -- Exceptions + // None + + // -- Constructors + + Lambert(const Configuration&); + Lambert(const Lambert&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + Lambert& operator=(const Lambert&) = delete; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + bool writeLaDInDegrees_; + bool writeLonPositive_; + + // -- Methods + + static Projection make_projection(const Configuration&); + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/LambertAzimuthalEqualArea.cc b/src/eckit/geo/grid/LambertAzimuthalEqualArea.cc new file mode 100644 index 000000000..493c0ad25 --- /dev/null +++ b/src/eckit/geo/grid/LambertAzimuthalEqualArea.cc @@ -0,0 +1,82 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/LambertAzimuthalEqualArea.h" + +#include + +#include "eckit/geo/Iterator.h" + + +namespace eckit::geo::grid { + + +static const GridBuilder __builder("lambert_azimuthal_equal_area"); + + +LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Configuration& param) : + RegularGrid(param, make_projection(param)) {} + + +LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Projection& projection, const BoundingBox& bbox, + const LinearSpacing& x, const LinearSpacing& y, + const Shape& shape) : + RegularGrid(projection, bbox, x, y, shape) {} + + +Projection LambertAzimuthalEqualArea::make_projection(const Configuration& param) { + auto spec = make_proj_spec(param); + if (!spec.empty()) { + return spec; + } + + double standardParallel = 0.; + double centralLongitude = 0.; + double radius = 0.; + ASSERT(param.get("standardParallelInDegrees", standardParallel)); + ASSERT(param.get("centralLongitudeInDegrees", centralLongitude)); + param.get("radius", radius = Earth::radius()); + + return Configuration("type", "lambert_azimuthal_equal_area") + .set("standard_parallel", standardParallel) + .set("central_longitude", centralLongitude) + .set("radius", radius); +} + + +const Grid* LambertAzimuthalEqualArea::croppedGrid(const BoundingBox& bbox) const { + auto mm = minmax_ij(bbox); + auto Ni = x_.size(); + + auto projection = grid_.projection(); + ASSERT(projection); + + auto first = [this, projection, Ni](size_t firsti, size_t firstj) -> Point2 { + for (std::unique_ptr it(iterator()); it->next();) { + auto i = it->index() % Ni; + auto j = it->index() / Ni; + if (i == firsti && j == firstj) { + const auto& latlon = *(*it); + return projection.xy(PointLonLat{latlon[1], latlon[0]}); + } + } + throw UserError("LambertAzimuthalEqualArea::croppedGrid: cannot find first point"); + }(mm.first.i, mm.first.j); + + auto x = linspace(first.x(), std::abs(x_.step()), long(mm.second.i - mm.first.i + 1), xPlus_); + auto y = linspace(first.y(), std::abs(y_.step()), long(mm.second.j - mm.first.j + 1), yPlus_); + + return new LambertAzimuthalEqualArea(projection, bbox, x, y, shape_); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/LambertAzimuthalEqualArea.h b/src/eckit/geo/grid/LambertAzimuthalEqualArea.h new file mode 100644 index 000000000..e55a7b8f4 --- /dev/null +++ b/src/eckit/geo/grid/LambertAzimuthalEqualArea.h @@ -0,0 +1,78 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/RegularGrid.h" + + +namespace eckit::geo::grid { + + +class LambertAzimuthalEqualArea : public RegularGrid { +public: + // -- Exceptions + // None + + // -- Constructors + + LambertAzimuthalEqualArea(const Configuration&); + LambertAzimuthalEqualArea(const Projection&, const BoundingBox&, const LinearSpacing& x, + const LinearSpacing& y, const Shape&); + LambertAzimuthalEqualArea(const LambertAzimuthalEqualArea&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + LambertAzimuthalEqualArea& operator=(const LambertAzimuthalEqualArea&) = delete; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + + static Projection make_projection(const Configuration&); + + // -- Overridden methods + + const Grid* croppedGrid(const BoundingBox&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/LatLon.cc b/src/eckit/geo/grid/LatLon.cc new file mode 100644 index 000000000..3c6708ded --- /dev/null +++ b/src/eckit/geo/grid/LatLon.cc @@ -0,0 +1,211 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/LatLon.h" + +#include +#include +#include + +#include "eckit/types/FloatCompare.h" +#include "eckit/types/Fraction.h" + + +namespace eckit::geo::grid { + + +LatLon::LatLon(const Configuration& config) : + Grid(config), increments_(parametrisation), reference_(bbox_.south(), bbox_.west()), ni_(0), nj_(0) { + correctBoundingBox(bbox_, ni_, nj_, increments_, reference_); + ASSERT(ni_ != 0); + ASSERT(nj_ != 0); + + // confirm Ni/Nj from config (input) + size_t ni = 0; + size_t nj = 0; + ASSERT(config.get("Ni", ni)); + ASSERT(config.get("Nj", nj)); + + Log::debug() << "LatLon:" + "\n\t" + "(Ni, Nj) = (" + << ni_ << ", " << nj_ + << ") calculated" + "\n\t" + "(Ni, Nj) = (" + << ni << ", " << nj << ") from config" << std::endl; + + ASSERT(ni == ni_); + ASSERT(nj == nj_); +} + + +LatLon::LatLon(const Increments& increments, const BoundingBox& bbox, const PointLonLat& reference) : + Grid(bbox), increments_(increments), reference_(reference), ni_(0), nj_(0) { + correctBoundingBox(bbox_, ni_, nj_, increments_, reference_); + ASSERT(ni_ != 0); + ASSERT(nj_ != 0); +} + + +LatLon::~LatLon() = default; + + +void LatLon::reorder(long scanningMode) const { + grib_reorder(values, scanningMode, ni_, nj_); +} + + +void LatLon::print(std::ostream& out) const { + out << "LatLon[" + << "bbox=" << bbox_ << ",increments=" << increments_ << ",ni=" << ni_ << ",nj=" << nj_ << "]"; +} + + +bool LatLon::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && (bbox_ == o->bbox_) && (increments_ == o->increments_); +} + + +bool LatLon::isPeriodicWestEast() const { + + // if range West-East is within one increment (or greater than) 360 degree + double inc = increments_.west_east().longitude(); + return bbox_.east() - bbox_.west() + inc >= GLOBE; +} + + +bool LatLon::includesNorthPole() const { + + // if North latitude is within one increment from North Pole + double inc = increments_.south_north().latitude(); + return bbox_.north() + inc > NORTH_POLE; +} + + +bool LatLon::includesSouthPole() const { + + // if South latitude is within one increment from South Pole + double inc = increments_.south_north().latitude(); + return bbox_.south() - inc < SOUTH_POLE; +} + + +size_t LatLon::numberOfPoints() const { + ASSERT(ni_); + ASSERT(nj_); + return ni_ * nj_; +} + + +const LatLon* LatLon::croppedGrid(const BoundingBox& /*unused*/) const { + std::ostringstream os; + os << "LatLon::croppedGrid() not implemented for " << *this; + throw SeriousBug(os.str()); +} + + +LatLon::LatLonIterator::LatLonIterator(size_t ni, size_t nj, Latitude north, Longitude west, + const Increments& increments) : + ni_(ni), + nj_(nj), + north_(north.fraction()), + west_(west.fraction()), + we_(increments.west_east().longitude().fraction()), + ns_(increments.south_north().latitude().fraction()), + i_(0), + j_(0), + count_(0), + first_(true) { + lat_ = north_; + lon_ = west_; + latValue_ = lat_; + lonValue_ = lon_; +} + + +LatLon::LatLonIterator::~LatLonIterator() { + auto count = count_ + (i_ > 0 || j_ > 0 ? 1 : 0); + ASSERT(count == ni_ * nj_); +} + + +void LatLon::LatLonIterator::print(std::ostream& out) const { + out << "LatLonIterator[" + << "ni=" << ni_ << ",nj=" << nj_ << ",north=" << north_ << ",west=" << west_ << ",we=" << we_ << ",ns=" << ns_ + << ",i=" << i_ << ",j=" << j_ << ",count=" << count_ << "]"; +} + + +bool LatLon::LatLonIterator::next(double& lat, double& lon) { + if (j_ < nj_) { + if (i_ < ni_) { + lat = latValue_; + lon = lonValue_; + + lon_ += we_; + + if (first_) { + first_ = false; + } + else { + count_++; + } + + if (++i_ == ni_) { + j_++; + i_ = 0; + lat_ -= ns_; + lon_ = west_; + latValue_ = lat_; + } + + lonValue_ = lon_; + + return true; + } + } + return false; +} + + +void LatLon::correctBoundingBox(BoundingBox& bbox, size_t& ni, size_t& nj, const Increments& inc, + const PointLonLat& reference) { + using iterator::detail::RegularIterator; + + // Latitude/longitude ranges + RegularIterator lat{bbox.south().fraction(), bbox.north().fraction(), inc.south_north().latitude().fraction(), + reference.lat().fraction()}; + auto n = lat.b(); + auto s = lat.a(); + + nj = lat.n(); + ASSERT(nj > 0); + + RegularIterator lon{bbox.west().fraction(), bbox.east().fraction(), inc.west_east().longitude().fraction(), + reference.lon().fraction(), GLOBE.fraction()}; + auto w = lon.a(); + auto e = lon.b(); + + ni = lon.n(); + ASSERT(ni > 0); + + // checks + ASSERT(w + (ni - 1) * lon.inc() == e || ni * lon.inc() == GLOBE.fraction()); + ASSERT(s + (nj - 1) * lat.inc() == n); + + bbox = {n, w, s, e}; +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/LatLon.h b/src/eckit/geo/grid/LatLon.h new file mode 100644 index 000000000..3add6549c --- /dev/null +++ b/src/eckit/geo/grid/LatLon.h @@ -0,0 +1,138 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" +#include "eckit/types/Fraction.h" + + +namespace eckit::geo::grid { + + +class LatLon : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + LatLon(const Configuration&); + LatLon(const Increments&, const BoundingBox& = {}, const PointLonLat& reference = {0, 0}); + + // -- Destructor + + ~LatLon() override; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + size_t Ni() const { return ni_; } + + size_t Nj() const { return nj_; } + + static void correctBoundingBox(BoundingBox&, size_t& ni, size_t& nj, const Increments&, + const PointLonLat& reference = {0, 0}); + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + + const Increments increments_; + const PointLonLat reference_; + size_t ni_; + size_t nj_; + + // -- Methods + // None + + // -- Overridden methods + + void print(std::ostream&) const override; + + bool sameAs(const Grid&) const override; + + bool isPeriodicWestEast() const override; + bool includesNorthPole() const override; + bool includesSouthPole() const override; + + size_t numberOfPoints() const override; + + // -- Class members + + class LatLonIterator { + size_t ni_; + size_t nj_; + Fraction north_; + Fraction west_; + Fraction we_; + Fraction ns_; + size_t i_; + size_t j_; + Latitude latValue_; + Longitude lonValue_; + Fraction lat_; + Fraction lon_; + + protected: + size_t count_; + bool first_; + + ~LatLonIterator(); + void print(std::ostream&) const; + bool next(double&, double&); + + public: + LatLonIterator(size_t ni, size_t nj, Latitude north, Longitude west, const Increments& increments); + }; + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + void reorder(long scanningMode) const override; + + const LatLon* croppedGrid(const BoundingBox&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Mercator.cc b/src/eckit/geo/grid/Mercator.cc new file mode 100644 index 000000000..10512257b --- /dev/null +++ b/src/eckit/geo/grid/Mercator.cc @@ -0,0 +1,26 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/Mercator.h" + + +namespace eckit::geo::grid { + + +static const GridBuilder __builder("mercator"); + + +Mercator::Mercator(const Configuration& param) : + RegularGrid(param, make_proj_spec(param)) {} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Mercator.h b/src/eckit/geo/grid/Mercator.h new file mode 100644 index 000000000..f16febd81 --- /dev/null +++ b/src/eckit/geo/grid/Mercator.h @@ -0,0 +1,74 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/RegularGrid.h" + + +namespace eckit::geo::grid { + + +class Mercator : public RegularGrid { +public: + // -- Exceptions + // None + + // -- Constructors + + Mercator(const Configuration&); + Mercator(const Mercator&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + Mercator& operator=(const Mercator&) = delete; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/None.cc b/src/eckit/geo/grid/None.cc new file mode 100644 index 000000000..58204f7b5 --- /dev/null +++ b/src/eckit/geo/grid/None.cc @@ -0,0 +1,38 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/None.h" + +#include + + +namespace eckit::geo::grid { + + +None::None() = default; + + +None::None(const Configuration& /*unused*/) {} + + +None::~None() = default; + + +void None::print(std::ostream& out) const { + out << "None[]"; +} + + +static const GridBuilder builder("none"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/None.h b/src/eckit/geo/grid/None.h new file mode 100644 index 000000000..91e46d1d4 --- /dev/null +++ b/src/eckit/geo/grid/None.h @@ -0,0 +1,94 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class None : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + None(); + None(const Configuration&); + None(const None&) = delete; + + // -- Destructor + + ~None() override; + + // -- Convertors + // None + + // -- Operators + + None& operator=(const None&) = delete; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + // from Grid + void print(std::ostream&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ORCA.cc b/src/eckit/geo/grid/ORCA.cc new file mode 100644 index 000000000..e19d7efad --- /dev/null +++ b/src/eckit/geo/grid/ORCA.cc @@ -0,0 +1,136 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/ORCA.h" + +#include +#include +#include + +#include "eckit/geo/Iterator.h" + + +namespace eckit::geo::grid { + + +// order is important for makeName() +static const std::vector> grib_keys{ + {"orca_name", "unstructuredGridType"}, {"orca_arrangement", "unstructuredGridSubtype"}, {"uid", "uuidOfHGrid"}}; + + +ORCA::ORCA(const std::string& uid) : + Grid(BoundingBox() /*assumed global*/), spec_(atlas::grid::SpecRegistry::get(uid)) {} + + +ORCA::ORCA(const Configuration& param) : + ORCA([¶m]() { + std::string uid; + ASSERT(param.get("uid", uid)); + return uid; + }()) {} + + +ORCA::~ORCA() = default; + + +bool ORCA::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && spec_.getString("uid") == o->spec_.getString("uid"); +} + + +size_t ORCA::numberOfPoints() const { + return static_cast(atlasGridRef().size()); +} + + +// void ORCA::makeName(std::ostream& out) const { +// const auto* sep = ""; +// for (const auto& key : grib_keys) { +// out << sep << spec_.getString(key.first); +// sep = "_"; +// } +// } + + +void ORCA::print(std::ostream& out) const { + out << "ORCA[spec=" << spec_ << "]"; +} + + +Iterator* ORCA::iterator() const { + class ORCAIterator : public Iterator { + ::atlas::Grid grid_; // Note: needs the object because IterateLonLat uses a Grid reference + ::atlas::Grid::IterateLonLat lonlat_; + + decltype(lonlat_)::iterator it_; + decltype(lonlat_)::iterator::value_type p_; + + const size_t total_; + size_t count_; + bool first_; + + void print(std::ostream& out) const override { + out << "ORCAIterator["; + Iterator::print(out); + out << ",count=" << count_ << ",total=" << total_ << "]"; + } + + bool next(double& _lat, double& _lon) override { + if (it_.next(p_)) { + point_[0] = p_.lat(); + point_[1] = p_.lon(); + _lat = p_.lat(); + _lon = p_.lon(); + + if (first_) { + first_ = false; + } + else { + count_++; + } + + return true; + } + + ASSERT(count_ == total_); + return false; + } + + size_t index() const override { return count_; } + + public: + ORCAIterator(::atlas::Grid grid) : + grid_(grid), + lonlat_(grid.lonlat()), + it_(lonlat_.begin()), + total_(size_t(grid.size())), + count_(0), + first_(true) {} + + ~ORCAIterator() override = default; + + ORCAIterator(const ORCAIterator&) = delete; + ORCAIterator(ORCAIterator&&) = delete; + ORCAIterator& operator=(const ORCAIterator&) = delete; + ORCAIterator& operator=(ORCAIterator&&) = delete; + }; + return new ORCAIterator(atlasGridRef()); +} + + +const atlas::Grid& ORCA::atlasGridRef() const { + return grid_ ? grid_ : (grid_ = atlas::Grid(spec_)); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ORCA.h b/src/eckit/geo/grid/ORCA.h new file mode 100644 index 000000000..b029c9ee8 --- /dev/null +++ b/src/eckit/geo/grid/ORCA.h @@ -0,0 +1,105 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class ORCA : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + ORCA(const std::string& uid); + ORCA(const Configuration&); + ORCA(const ORCA&) = delete; + + // -- Destructor + + ~ORCA() override; + + // -- Convertors + // None + + // -- Operators + + ORCA& operator=(const ORCA&) = delete; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + // from Grid + void print(std::ostream&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + // from Grid + bool sameAs(const Grid&) const override; + size_t numberOfPoints() const override; + + bool includesNorthPole() const override { return true; } + bool includesSouthPole() const override { return true; } + bool isPeriodicWestEast() const override { return true; } + + Iterator* iterator() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Octahedral.cc b/src/eckit/geo/grid/Octahedral.cc new file mode 100644 index 000000000..ebce13dda --- /dev/null +++ b/src/eckit/geo/grid/Octahedral.cc @@ -0,0 +1,43 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/Octahedral.h" + + +namespace eckit::geo::grid { + + +Octahedral::Octahedral(size_t N, const BoundingBox& box, double angularPrecision) : + Reduced(N, box, angularPrecision) { + + // adjust latitudes, longitudes and re-set bounding box + auto n = bbox().north(); + auto s = bbox().south(); + correctSouthNorth(s, n); + + setNj(pls("O" + std::to_string(N_)), s, n); + + auto w = bbox().west(); + auto e = bbox().east(); + correctWestEast(w, e); + + bbox({n, w, s, e}); +} + + +bool Octahedral::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && Reduced::sameAs(other); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Octahedral.h b/src/eckit/geo/grid/Octahedral.h new file mode 100644 index 000000000..7bb187a9e --- /dev/null +++ b/src/eckit/geo/grid/Octahedral.h @@ -0,0 +1,90 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Reduced.h" + + +namespace eckit::geo::grid { + + +class Octahedral : public Reduced { +public: + // -- Exceptions + // None + + // -- Constructors + + Octahedral(size_t, const BoundingBox& = BoundingBox(), double angularPrecision = 0); + + // -- Destructor + + virtual ~Octahedral() override = default; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + bool sameAs(const Grid&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/PolarStereographic.cc b/src/eckit/geo/grid/PolarStereographic.cc new file mode 100644 index 000000000..c86946536 --- /dev/null +++ b/src/eckit/geo/grid/PolarStereographic.cc @@ -0,0 +1,26 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/PolarStereographic.h" + + +namespace eckit::geo::grid { + + +static const GridBuilder __builder("polar_stereographic"); + + +PolarStereographic::PolarStereographic(const Configuration& param) : + RegularGrid(param, make_proj_spec(param)) {} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/PolarStereographic.h b/src/eckit/geo/grid/PolarStereographic.h new file mode 100644 index 000000000..4383a658c --- /dev/null +++ b/src/eckit/geo/grid/PolarStereographic.h @@ -0,0 +1,74 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/RegularGrid.h" + + +namespace eckit::geo::grid { + + +class PolarStereographic : public RegularGrid { +public: + // -- Exceptions + // None + + // -- Constructors + + PolarStereographic(const Configuration&); + PolarStereographic(const PolarStereographic&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + PolarStereographic& operator=(const PolarStereographic&) = delete; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Reduced.cc b/src/eckit/geo/grid/Reduced.cc new file mode 100644 index 000000000..a39ad59b1 --- /dev/null +++ b/src/eckit/geo/grid/Reduced.cc @@ -0,0 +1,256 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/Reduced.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "eckit/geo/grid/GaussianIterator.h" +#include "eckit/types/Fraction.h" + + +namespace eckit::geo::grid { + + +template +std::vector pl_convert(const T& nx) { + ASSERT(!nx.empty()); + std::vector pl(nx.size()); + std::transform(nx.begin(), nx.end(), pl.begin(), [](typename T::value_type p) { return long(p); }); + return pl; +} + + +template <> +std::vector pl_convert(const std::vector& nx) { + ASSERT(!nx.empty()); + return nx; +} + + +Reduced::Reduced(const Configuration& config) : + Gaussian(config), k_(0), Nj_(N_ * 2) { + + // adjust latitudes, longitudes and re-set bounding box + auto n = bbox().north(); + auto s = bbox().south(); + correctSouthNorth(s, n); + + std::vector pl; + ASSERT(config.get("pl", pl)); + + // if pl isn't global (from file!) insert leading/trailing 0's + const auto& lats = latitudes(); + if (n < lats.front() || s > lats.back()) { + size_t k = 0; + size_t nj = 0; + for (auto lat : lats) { + if (n < lat) { + ++k; + } + else if (s <= lat) { + ASSERT(pl[nj] >= 2); + ++nj; + } + else { + break; + } + } + ASSERT(k + nj <= N_ * 2); + + if (k > 0) { + pl.reserve(N_ * 2); + pl.insert(pl.begin(), k, 0); + } + pl.resize(N_ * 2, 0); + } + + setNj(pl, s, n); + + auto w = bbox().west(); + auto e = bbox().east(); + correctWestEast(w, e); + + bbox({n, w, s, e}); +} + + +Reduced::Reduced(size_t N, const std::vector& pl, const BoundingBox& bbox, double angularPrecision) : + Gaussian(N, bbox, angularPrecision), k_(0), Nj_(N_ * 2) { + setNj(pl, bbox.south(), bbox.north()); +} + + +Reduced::Reduced(size_t N, const BoundingBox& bbox, double angularPrecision) : + Gaussian(N, bbox, angularPrecision), k_(0), Nj_(N * 2) { + // derived classes must set k_, Nj_ using this constructor +} + + +void Reduced::correctWestEast(double& w, double& e) const { + ASSERT(w <= e); + + const Fraction smallestIncrement = getSmallestIncrement(); + ASSERT(smallestIncrement > 0); + + if (angleApproximatelyEqual(GREENWICH, w) && (angleApproximatelyEqual(GLOBE - smallestIncrement, e - w) || GLOBE - smallestIncrement < e - w || (e != w && e.normalise(w) == w))) { + + w = GREENWICH; + e = GLOBE - smallestIncrement; + } + else { + + const Fraction west = w.fraction(); + const Fraction east = e.fraction(); + Fraction W = west; + Fraction E = east; + + bool first = true; + std::set NiTried; + + const auto& pl = pls(); + for (size_t j = k_; j < k_ + Nj_; ++j) { + + // crop longitude-wise, track distinct attempts + const long Ni(pl[j]); + ASSERT(Ni >= 2); + if (NiTried.insert(Ni).second) { + + Fraction inc = GLOBE.fraction() / Ni; + + Fraction::value_type Nw = (west / inc).integralPart(); + if (Nw * inc < west) { + Nw += 1; + } + + Fraction::value_type Ne = (east / inc).integralPart(); + if (Ne * inc > east || Nw + Ne == Ni) { + Ne -= 1; + } + + if (Nw <= Ne) { + ASSERT(w <= Longitude(Nw * inc)); + ASSERT(Longitude(Ne * inc) <= e); + + if (W > double(Nw * inc) || first) { + W = Nw * inc; + } + if (E < double(Ne * inc) || first) { + E = Ne * inc; + } + first = false; + } + } + } + + ASSERT(!first); + ASSERT(W <= E); + w = W; + e = E; + } +} + + +bool Reduced::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && Gaussian::sameAs(other); +} + + +Iterator* Reduced::unrotatedIterator() const { + auto pl = pls(); + return new GaussianIterator(latitudes(), std::move(pl), bbox(), N_, Nj_, k_); +} + + +Iterator* Reduced::rotatedIterator(const Rotation& rotation) const { + auto pl = pls(); + return new GaussianIterator(latitudes(), std::move(pl), bbox(), N_, Nj_, k_, rotation); +} + + +const std::vector& Reduced::pls() const { + ASSERT(pl_.size() == N_ * 2); + ASSERT(pl_.size() >= k_ + Nj_); + ASSERT(Nj_ > 0); + + return pl_; +} + + +std::vector Reduced::pls(const std::string& name) { + atlas::ReducedGaussianGrid grid(name); + ASSERT(grid); + return pl_convert(grid.nx()); +} + + +void Reduced::setNj(std::vector pl, double s, double n) { + ASSERT(0 < N_ && N_ * 2 == pl.size()); + + // position to first latitude and first/last longitude + // NOTE: latitudes() spans the globe, sorted from North-to-South, k_ positions the North + // NOTE: pl spans the globe + pl_ = pl; + k_ = 0; + Nj_ = N_ * 2; + + const auto& lats = latitudes(); + if (n < lats.front() || s > lats.back()) { + Nj_ = 0; + for (const auto& lat : lats) { + Latitude ll(lat); + if (n < ll && !angleApproximatelyEqual(n, ll)) { + ++k_; + } + else if (s < ll || angleApproximatelyEqual(s, ll)) { + ASSERT(pl[k_ + Nj_] >= 2); + ++Nj_; + } + else { + break; + } + } + } + + // check internal assumptions + pls(); +} + + +size_t Reduced::numberOfPoints() const { + if (isGlobal()) { + const auto& pl = pls(); + return size_t(std::accumulate(pl.begin(), pl.end(), 0L)); + } + + size_t total = 0; + for (const std::unique_ptr it(iterator()); it->next();) { + total++; + } + return total; +} + + +bool Reduced::isPeriodicWestEast() const { + auto inc = getSmallestIncrement(); + return bbox_.east() - bbox_.west() + inc >= GLOBE; +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Reduced.h b/src/eckit/geo/grid/Reduced.h new file mode 100644 index 000000000..0fd70e106 --- /dev/null +++ b/src/eckit/geo/grid/Reduced.h @@ -0,0 +1,107 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Gaussian.h" + + +namespace eckit::geo::grid { + + +class Reduced : public Gaussian { +public: + // -- Exceptions + // None + + // -- Constructors + + Reduced(const Configuration&); + Reduced(size_t N, const std::vector& pl, const BoundingBox& = BoundingBox(), + double angularPrecision = 0); + + // -- Destructor + + ~Reduced() override = default; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + static std::vector pls(const std::string&); + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Constructors + + Reduced(size_t N, const BoundingBox& = BoundingBox(), double angularPrecision = 0); + + // -- Members + + size_t k_; + size_t Nj_; + + // -- Methods + + const std::vector& pls() const; + + void setNj(std::vector, double s, double n); + void correctWestEast(double& w, double& e) const; + + // -- Overridden methods + + bool sameAs(const Grid&) const override; + + // from Grid + bool isPeriodicWestEast() const override; + + // -- Class members + + // -- Class methods + // None + +private: + // -- Members + + std::vector pl_; + + // -- Methods + // None + + // -- Overridden methods + + size_t numberOfPoints() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedClassic.cc b/src/eckit/geo/grid/ReducedClassic.cc new file mode 100644 index 000000000..43a206bc4 --- /dev/null +++ b/src/eckit/geo/grid/ReducedClassic.cc @@ -0,0 +1,46 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/ReducedClassic.h" + +#include + + +namespace eckit::geo::grid { + + +ReducedClassic::ReducedClassic(size_t N, const BoundingBox& bbox, double angularPrecision) : + Classic(N, bbox, angularPrecision) {} + + +void ReducedClassic::print(std::ostream& out) const { + out << "ReducedClassic[N=" << N_ << ",bbox=" << bbox() << "]"; +} + + +Iterator* ReducedClassic::iterator() const { + return unrotatedIterator(); +} + + +const Grid* ReducedClassic::croppedGrid(const BoundingBox& bbox) const { + return new ReducedClassic(N_, bbox, angularPrecision_); +} + + +bool ReducedClassic::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && Classic::sameAs(other); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedClassic.h b/src/eckit/geo/grid/ReducedClassic.h new file mode 100644 index 000000000..7e6c3bc55 --- /dev/null +++ b/src/eckit/geo/grid/ReducedClassic.h @@ -0,0 +1,92 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Classic.h" + + +namespace eckit::geo::grid { + + +class ReducedClassic : public Classic { +public: + // -- Exceptions + // None + + // -- Constructors + + ReducedClassic(size_t, const BoundingBox& = BoundingBox(), double angularPrecision = 0); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + Iterator* iterator() const override; + const Grid* croppedGrid(const BoundingBox&) const override; + bool sameAs(const Grid&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedFromPL.cc b/src/eckit/geo/grid/ReducedFromPL.cc new file mode 100644 index 000000000..d6f0f1e9d --- /dev/null +++ b/src/eckit/geo/grid/ReducedFromPL.cc @@ -0,0 +1,54 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/ReducedFromPL.h" + +#include + + +namespace eckit::geo::grid { + + +ReducedFromPL::ReducedFromPL(const Configuration& config) : + FromPL(config) {} + + +ReducedFromPL::ReducedFromPL(size_t N, const std::vector& pl, const BoundingBox& bbox, + double angularPrecision) : + FromPL(N, pl, bbox, angularPrecision) {} + + +void ReducedFromPL::print(std::ostream& out) const { + out << "ReducedFromPL[N=" << N_ << ",bbox=" << bbox() << "]"; +} + + +Iterator* ReducedFromPL::iterator() const { + return unrotatedIterator(); +} + + +const Grid* ReducedFromPL::croppedGrid(const BoundingBox& bbox) const { + return new ReducedFromPL(N_, pls(), bbox, angularPrecision_); +} + + +bool ReducedFromPL::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && FromPL::sameAs(other); +} + + +static const GridBuilder reducedFromPL("reduced_gg"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedFromPL.h b/src/eckit/geo/grid/ReducedFromPL.h new file mode 100644 index 000000000..ac0c52564 --- /dev/null +++ b/src/eckit/geo/grid/ReducedFromPL.h @@ -0,0 +1,94 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/FromPL.h" + + +namespace eckit::geo::grid { + + +class ReducedFromPL : public FromPL { +public: + // -- Exceptions + // None + + // -- Constructors + + ReducedFromPL(const Configuration&); + ReducedFromPL(size_t, const std::vector&, const BoundingBox& = BoundingBox(), + double angularPrecision = 0); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + Iterator* iterator() const override; + const Grid* croppedGrid(const BoundingBox&) const override; + bool sameAs(const Grid&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedLL.cc b/src/eckit/geo/grid/ReducedLL.cc new file mode 100644 index 000000000..5cc323fe2 --- /dev/null +++ b/src/eckit/geo/grid/ReducedLL.cc @@ -0,0 +1,186 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/ReducedLL.h" + +#include +#include +#include +#include + +#include "eckit/geo/Iterator.h" +#include "eckit/types/FloatCompare.h" +#include "eckit/types/Fraction.h" + + +namespace eckit::geo::grid { + +static bool checkPl(const std::vector& pl) { + ASSERT(!pl.empty()); + return *std::min_element(pl.begin(), pl.end()) >= 2; +} + +ReducedLL::ReducedLL(const Configuration& config) : + Grid(config) { + ASSERT(config.get("pl", pl_)); + checkPl(pl_); + + size_t Nj = 0; + ASSERT(config.get("Nj", Nj)); + ASSERT(Nj == pl_.size()); +} + +ReducedLL::~ReducedLL() = default; + +void ReducedLL::print(std::ostream& out) const { + out << "ReducedLL[bbox=" << bbox() << "]"; +} + +size_t ReducedLL::numberOfPoints() const { + size_t total = 0; + for (const auto& j : pl_) { + total += size_t(j); + } + return total; +} + +bool ReducedLL::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && (bbox() == o->bbox()) && (pl_ == o->pl_); +} + +bool ReducedLL::isPeriodicWestEast() const { + ASSERT(!pl_.empty()); + + auto maxpl = *std::max_element(pl_.begin(), pl_.end()); + ASSERT(maxpl >= 2); + + // if range West-East is within one increment (or greater than) 360 degree + const Fraction inc(360, maxpl); + return bbox().east() - bbox().west() + inc >= GLOBE; +} + +bool ReducedLL::includesNorthPole() const { + return bbox().north() == NORTH_POLE; +} + +bool ReducedLL::includesSouthPole() const { + return bbox().south() == SOUTH_POLE; +} + +class ReducedLLIterator : public Iterator { + + const std::vector& pl_; + const size_t nj_; + size_t ni_; + + const Domain domain_; + const Fraction west_; + const Fraction ew_; + Fraction inc_west_east_; + const Fraction inc_north_south_; + + Fraction latitude_; + Fraction longitude_; + + size_t i_; + size_t j_; + size_t p_; + + size_t count_; + bool first_; + bool periodic_; + + void print(std::ostream& out) const override { + out << "ReducedLLIterator["; + Iterator::print(out); + out << ",domain=" << domain_ << ",ni=" << ni_ << ",nj=" << nj_ << ",i=" << i_ << ",j=" << j_ << ",p=" << p_ + << ",count=" << count_ << "]"; + } + + bool next(double& lat, double& lon) override { + while (j_ < nj_ && i_ < ni_) { + lat = latitude_; + lon = longitude_; + + bool contains = domain_.contains(lat, lon); + if (contains && !first_) { + count_++; + } + + longitude_ += inc_west_east_; + + if (++i_ == ni_) { + ++j_; + i_ = 0; + latitude_ -= inc_north_south_; + longitude_ = west_; + + if (j_ < nj_) { + ASSERT(p_ < pl_.size()); + ni_ = size_t(pl_[p_++]); + ASSERT(ni_ > 1); + inc_west_east_ = ew_ / (ni_ - (periodic_ ? 0 : 1)); + } + } + + if (contains) { + first_ = false; + return true; + } + } + return false; + } + + size_t index() const override { return count_; } + +public: + ReducedLLIterator(const std::vector& pl, const Domain& dom) : + pl_(pl), + nj_(pl.size()), + domain_(dom), + west_(domain_.west().fraction()), + ew_((domain_.east() - domain_.west()).fraction()), + inc_north_south_((domain_.north() - domain_.south()).fraction() / Fraction(nj_ - 1)), + latitude_(domain_.north().fraction()), + longitude_(west_), + i_(0), + j_(0), + p_(0), + count_(0), + first_(true), + periodic_(dom.isPeriodicWestEast()) { + + ASSERT(nj_ > 1); + + ni_ = size_t(pl_[p_++]); + ASSERT(ni_ > 1); + inc_west_east_ = ew_ / (ni_ - (periodic_ ? 0 : 1)); + } +}; + +Iterator* ReducedLL::iterator() const { + return new ReducedLLIterator(pl_, domain()); +} + + +const Grid* mir::repres::latlon::ReducedLL::croppedGrid(const BoundingBox&) const { + std::ostringstream os; + os << "ReducedLL::croppedGrid() not supported for " << *this; + throw FunctionalityNotSupported(os.str()); +} + + +static const GridBuilder reducedLL("reduced_ll"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedLL.h b/src/eckit/geo/grid/ReducedLL.h new file mode 100644 index 000000000..3607477bf --- /dev/null +++ b/src/eckit/geo/grid/ReducedLL.h @@ -0,0 +1,101 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class ReducedLL : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + ReducedLL(const Configuration&); + + // -- Destructor + + ~ReducedLL() override; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + bool isPeriodicWestEast() const override; + bool includesNorthPole() const override; + bool includesSouthPole() const override; + + void print(std::ostream&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + std::vector pl_; + + // -- Methods + // None + + // -- Overridden methods + + Iterator* iterator() const override; + bool sameAs(const Grid&) const override; + size_t numberOfPoints() const override; + + // From Grid + const Grid* croppedGrid(const BoundingBox&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedOctahedral.cc b/src/eckit/geo/grid/ReducedOctahedral.cc new file mode 100644 index 000000000..f691e7129 --- /dev/null +++ b/src/eckit/geo/grid/ReducedOctahedral.cc @@ -0,0 +1,46 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/ReducedOctahedral.h" + +#include + + +namespace eckit::geo::grid { + + +ReducedOctahedral::ReducedOctahedral(size_t N, const BoundingBox& bbox, double angularPrecision) : + Octahedral(N, bbox, angularPrecision) {} + + +void ReducedOctahedral::print(std::ostream& out) const { + out << "ReducedOctahedral[N=" << N_ << ",bbox=" << bbox() << "]"; +} + + +Iterator* ReducedOctahedral::iterator() const { + return unrotatedIterator(); +} + + +const Grid* ReducedOctahedral::croppedGrid(const BoundingBox& bbox) const { + return new ReducedOctahedral(N_, bbox, angularPrecision_); +} + + +bool ReducedOctahedral::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && Octahedral::sameAs(other); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedOctahedral.h b/src/eckit/geo/grid/ReducedOctahedral.h new file mode 100644 index 000000000..3b50473e4 --- /dev/null +++ b/src/eckit/geo/grid/ReducedOctahedral.h @@ -0,0 +1,92 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Octahedral.h" + + +namespace eckit::geo::grid { + + +class ReducedOctahedral : public Octahedral { +public: + // -- Exceptions + // None + + // -- Constructors + + ReducedOctahedral(size_t, const BoundingBox& = BoundingBox(), double angularPrecision = 0); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + Iterator* iterator() const override; + const Grid* croppedGrid(const BoundingBox&) const override; + bool sameAs(const Grid&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc new file mode 100644 index 000000000..f15d4974d --- /dev/null +++ b/src/eckit/geo/grid/Regular.cc @@ -0,0 +1,162 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/Regular.h" + +#include "eckit/types/FloatCompare.h" +#include "eckit/types/Fraction.h" + + +namespace eckit::geo::grid { + +Regular::Regular(const Configuration& config) : + Gaussian(config), k_(0), Ni_(0), Nj_(0) { + // adjust latitudes, longitudes and re-set bounding box + auto n = bbox().north(); + auto s = bbox().south(); + correctSouthNorth(s, n); + + auto e = bbox().east(); + auto w = bbox().west(); + correctWestEast(w, e); + + bbox({n, w, s, e}); + + setNiNj(); +} + +Regular::Regular(size_t N, const BoundingBox& box, double angularPrecision) : + Gaussian(N, box, angularPrecision), k_(0), Ni_(0), Nj_(0) { + + // adjust latitudes, longitudes and re-set bounding box + auto n = box.north(); + auto s = box.south(); + correctSouthNorth(s, n); + + auto w = box.west(); + auto e = box.east(); + correctWestEast(w, e); + + bbox({n, w, s, e}); + + setNiNj(); +} + +void Regular::correctWestEast(double& w, double& e) const { + ASSERT(w <= e); + + auto inc = getSmallestIncrement(); + ASSERT(inc > 0); + + if (angleApproximatelyEqual(GREENWICH, w) && (angleApproximatelyEqual(GLOBE - inc, e - w) || GLOBE - inc < e - w || (e != w && e.normalise(w) == w))) { + + w = GREENWICH; + e = GLOBE - inc; + } + else { + + const Fraction west = w; + const Fraction east = e; + + Fraction::value_type Nw = (west / inc).integralPart(); + if (Nw * inc < west) { + Nw += 1; + } + + Fraction::value_type Ne = (east / inc).integralPart(); + if (Ne * inc > east) { + Ne -= 1; + } + + ASSERT(Nw <= Ne); + w = Nw * inc; + e = Ne * inc; + } +} + +bool Regular::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && (N_ == o->N_) && (bbox() == o->bbox()); +} + +eckit::Fraction Regular::getSmallestIncrement() const { + ASSERT(N_); + return {90, Fraction::value_type(N_)}; +} + +size_t Regular::numberOfPoints() const { + ASSERT(Ni_); + ASSERT(Nj_); + return Ni_ * Nj_; +} + +bool Regular::isPeriodicWestEast() const { + auto inc = getSmallestIncrement(); + return bbox().east() - bbox().west() + inc >= GLOBE; +} + +void Regular::setNiNj() { + ASSERT(N_); + + const auto inc = getSmallestIncrement(); + const auto& lats = latitudes(); + + double west = bbox().west(); + double east = bbox().east(); + double south = bbox().south(); + double north = bbox().north(); + + Ni_ = N_ * 4; + + if (east - west + inc < GLOBE) { + + auto w = west.fraction(); + auto Nw = (w / inc).integralPart(); + if (Nw * inc < w) { + Nw += 1; + } + + auto e = east.fraction(); + auto Ne = (e / inc).integralPart(); + if (Ne * inc > e) { + Ne -= 1; + } + + ASSERT(Ne - Nw + 1 > 0); + Ni_ = size_t(Ne - Nw + 1); + + ASSERT(2 <= Ni_ && Ni_ <= N_ * 4); + } + + k_ = 0; + Nj_ = N_ * 2; + + if (north < lats.front() || south > lats.back()) { + Nj_ = 0; + for (auto lat : lats) { + if (north < lat && !angleApproximatelyEqual(north, lat)) { + ++k_; + } + else if (south <= lat || angleApproximatelyEqual(south, lat)) { + ++Nj_; + } + else { + break; + } + } + ASSERT(Nj_ > 0); + } + + Log::debug() << "Regular::setNiNj: Ni*Nj = " << Ni_ << " * " << Nj_ << " = " << (Ni_ * Nj_) << std::endl; +} + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h new file mode 100644 index 000000000..165485570 --- /dev/null +++ b/src/eckit/geo/grid/Regular.h @@ -0,0 +1,105 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Gaussian.h" + + +namespace eckit::geo::grid { + + +class Regular : public Gaussian { +public: + // -- Exceptions + // None + + // -- Constructors + + Regular(const Configuration&); + Regular(size_t N, const BoundingBox& = BoundingBox(), double angularPrecision = 0); + + // -- Destructor + + virtual ~Regular() override = default; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Constructors + // None + + // -- Members + + size_t k_; + size_t Ni_; + size_t Nj_; + + // -- Methods + + void correctWestEast(double& w, double& e) const; + void setNiNj(); + + // -- Overridden methods + + bool sameAs(const Grid&) const override; + + // from Grid + bool isPeriodicWestEast() const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + Regular(); + + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + size_t numberOfPoints() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularGG.cc b/src/eckit/geo/grid/RegularGG.cc new file mode 100644 index 000000000..89873e771 --- /dev/null +++ b/src/eckit/geo/grid/RegularGG.cc @@ -0,0 +1,65 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/RegularGG.h" + +#include +#include +#include + +#include "eckit/geo/grid/GaussianIterator.h" + + +namespace eckit::geo::grid { + + +RegularGG::RegularGG(const Configuration& config) : + Regular(config) {} + + +RegularGG::RegularGG(size_t N, const BoundingBox& bbox, double angularPrecision) : + Regular(N, bbox, angularPrecision) {} + + +void RegularGG::print(std::ostream& out) const { + out << "RegularGG[" + "N=" + << N_ << ",Ni=" << Ni_ << ",Nj=" << Nj_ << ",bbox=" << bbox() << "]"; +} + + +bool RegularGG::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && Regular::sameAs(other); +} + + +Iterator* RegularGG::iterator() const { + std::vector pl(N_ * 2, long(4 * N_)); + return new GaussianIterator(latitudes(), std::move(pl), bbox(), N_, Nj_, k_); +} + + +const Grid* RegularGG::croppedGrid(const BoundingBox& bbox) const { + return new RegularGG(N_, bbox, angularPrecision_); +} + + +std::string RegularGG::factory() const { + return "regular_gg"; +} + + +static const GridBuilder reducedGG("regular_gg"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularGG.h b/src/eckit/geo/grid/RegularGG.h new file mode 100644 index 000000000..d27f5e80d --- /dev/null +++ b/src/eckit/geo/grid/RegularGG.h @@ -0,0 +1,93 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Regular.h" + + +namespace eckit::geo::grid { + + +class RegularGG : public Regular { +public: + // -- Exceptions + // None + + // -- Constructors + + RegularGG(const Configuration&); + RegularGG(size_t N, const BoundingBox& = BoundingBox(), double angularPrecision = 0); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + const Grid* croppedGrid(const BoundingBox&) const override; + bool sameAs(const Grid&) const override; + Iterator* iterator() const override; + std::string factory() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularGrid.cc b/src/eckit/geo/grid/RegularGrid.cc new file mode 100644 index 000000000..e080c38e7 --- /dev/null +++ b/src/eckit/geo/grid/RegularGrid.cc @@ -0,0 +1,245 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/RegularGrid.h" + +#include +#include +#include +#include +#include + +#include "eckit/config/Resource.h" +#include "eckit/geo/Iterator.h" +#include "eckit/utils/StringTools.h" + + +namespace eckit::geo::grid { + + +RegularGrid::RegularGrid(const Configuration& param, const Projection& projection) : + shape_(param), xPlus_(true), yPlus_(false), firstPointBottomLeft_(false) { + ASSERT(projection); + + auto get_long_first_key = [](const Configuration& param, const std::vector& keys) -> long { + long value = 0; + for (const auto& key : keys) { + if (param.get(key, value)) { + return value; + } + } + throw SeriousBug("RegularGrid: couldn't find any key: " + StringTools::join(", ", keys)); + }; + + long nx = get_long_first_key(param, {"numberOfPointsAlongXAxis", "Ni"}); + long ny = get_long_first_key(param, {"numberOfPointsAlongYAxis", "Nj"}); + ASSERT(nx > 0); + ASSERT(ny > 0); + + std::vector grid; + ASSERT(param.get("grid", grid)); + ASSERT_KEYWORD_GRID_SIZE(grid.size()); + + Point2 firstLL; + ASSERT(param.get("latitudeOfFirstGridPointInDegrees", firstLL[LLCOORDS::LAT])); + ASSERT(param.get("longitudeOfFirstGridPointInDegrees", firstLL[LLCOORDS::LON])); + auto first = projection.xy(firstLL); + + param.get("iScansPositively", xPlus_); // iScansPositively != 0 + param.get("jScansPositively", yPlus_); // jScansPositively == 0 + param.get("first_point_bottom_left", firstPointBottomLeft_); + + x_ = linspace(first.x(), grid[0], nx, firstPointBottomLeft_ || xPlus_); + y_ = linspace(first.y(), grid[1], ny, firstPointBottomLeft_ || yPlus_); + grid_ = {x_, y_, projection}; + + atlas::RectangularDomain range({x_.min(), x_.max()}, {y_.min(), y_.max()}, "meters"); + + auto box = projection.lonlatBoundingBox(range); + ASSERT(box); + + bbox({box.north(), box.west(), box.south(), box.east()}); +} + + +RegularGrid::RegularGrid(const Projection& projection, const BoundingBox& bbox, const LinearSpacing& x, + const LinearSpacing& y, const Shape& shape) : + Grid(bbox), + x_(x), + y_(y), + shape_(shape), + xPlus_(x.front() <= x.back()), + yPlus_(y.front() < y.back()), + firstPointBottomLeft_(false) { + grid_ = {x_, y_, projection}; + + if (!shape_.provided) { + shape_ = {grid_.projection().spec()}; + } +} + + +RegularGrid::~RegularGrid() = default; + + +RegularGrid::Configuration RegularGrid::make_proj_spec(const Configuration& param) { + std::string proj; + param.get("proj", proj); + + if (proj.empty() || !::atlas::projection::ProjectionFactory::has("proj")) { + return {}; + } + + Configuration spec("type", "proj"); + spec.set("proj", proj); + + std::string projSource; + if (param.get("projSource", projSource) && !projSource.empty()) { + spec.set("proj_source", projSource); + } + + std::string projGeocentric; + if (param.get("projGeocentric", projGeocentric) && !projGeocentric.empty()) { + spec.set("proj_geocentric", projGeocentric); + } + + return spec; +} + + +RegularGrid::LinearSpacing RegularGrid::linspace(double start, double step, long num, bool plus) { + ASSERT(step >= 0.); + return {start, start + step * double(plus ? num - 1 : 1 - num), num}; +} + + +void RegularGrid::print(std::ostream& out) const { + out << "RegularGrid[x=" << x_.spec() << ",y=" << y_.spec() << ",projection=" << grid_.projection().spec() + << ",firstPointBottomLeft=" << firstPointBottomLeft_ << ",bbox=" << bbox_ << "]"; +} + + +bool RegularGrid::crop(BoundingBox& bbox, Renumber& mapping) const { + auto mm = minmax_ij(bbox); + auto Ni = x_.size(); + auto N = (mm.second.i - mm.first.i + 1) * (mm.second.j - mm.first.j + 1); + mapping.clear(); + mapping.reserve(N); + + for (std::unique_ptr it(iterator()); it->next();) { + auto i = it->index() % Ni; + auto j = it->index() / Ni; + if (mm.first.i <= i && i <= mm.second.i && mm.first.j <= j && j <= mm.second.j) { + mapping.push_back(it->index()); + } + } + ASSERT(mapping.size() == N); + + return true; +} + + +size_t RegularGrid::numberOfPoints() const { + return x_.size() * y_.size(); +} + + +bool RegularGrid::isPeriodicWestEast() const { + return false; +} + + +bool RegularGrid::includesNorthPole() const { + return bbox_.north() == NORTH_POLE; +} + + +bool RegularGrid::includesSouthPole() const { + return bbox_.south() == SOUTH_POLE; +} + + +void RegularGrid::reorder(long /*scanningMode*/) const { + // do not reorder, iterator is doing the right thing + // FIXME this function should not be overriding to do nothing +} + + +Iterator* RegularGrid::iterator() const { + class RegularGridIterator : public Iterator { + Projection projection_; + const LinearSpacing& x_; + const LinearSpacing& y_; + PointLonLat pLonLat_; + + size_t ni_; + size_t nj_; + size_t i_; + size_t j_; + size_t count_; + + void print(std::ostream& out) const override { + out << "RegularGridIterator["; + Iterator::print(out); + out << ",i=" << i_ << ",j=" << j_ << ",count=" << count_ << "]"; + } + + bool next(double& _lat, double& _lon) override { + if (j_ < nj_ && i_ < ni_) { + pLonLat_ = projection_.lonlat({x_[i_], y_[j_]}); + _lat = lat(pLonLat_.lat()); + _lon = lon(pLonLat_.lon()); + + if (i_ > 0 || j_ > 0) { + count_++; + } + + if (++i_ == ni_) { + i_ = 0; + j_++; + } + + return true; + } + return false; + } + + size_t index() const override { return count_; } + + public: + RegularGridIterator(Projection projection, const LinearSpacing& x, const LinearSpacing& y) : + projection_(std::move(projection)), x_(x), y_(y), ni_(x.size()), nj_(y.size()), i_(0), j_(0), count_(0) {} + ~RegularGridIterator() override = default; + + RegularGridIterator(const RegularGridIterator&) = delete; + RegularGridIterator(RegularGridIterator&&) = delete; + RegularGridIterator& operator=(const RegularGridIterator&) = delete; + RegularGridIterator& operator=(RegularGridIterator&&) = delete; + }; + + return new RegularGridIterator(grid_.projection(), x_, y_); +} + + +bool RegularGrid::sameAs(const Grid& other) const { + auto name = [](const RegularGrid& repres) { + std::ostringstream str; + // repres.makeName(str); + return str.str(); + }; + + const auto* o = dynamic_cast(&other); + return (o != nullptr) && name(*this) == name(*o); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularGrid.h b/src/eckit/geo/grid/RegularGrid.h new file mode 100644 index 000000000..09412ab9c --- /dev/null +++ b/src/eckit/geo/grid/RegularGrid.h @@ -0,0 +1,108 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" +#include "eckit/geo/Projection.h" + + +namespace eckit::geo { +class LinearSpacing {}; +class Shape {}; +} // namespace eckit::geo + + +namespace eckit::geo::grid { + + +class RegularGrid : public Grid { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + RegularGrid(const Configuration&, const Projection&); + RegularGrid(const Projection&, const BoundingBox&, const LinearSpacing& x, const LinearSpacing& y, + const Shape&); + RegularGrid(const RegularGrid&) = delete; + + // -- Destructor + + ~RegularGrid() override; + + // -- Convertors + // None + + // -- Operators + + RegularGrid& operator=(const RegularGrid&) = delete; + + // -- Methods + // None + + // -- Overridden methods + + Iterator* iterator() const override; + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + + LinearSpacing x_; + LinearSpacing y_; + Shape shape_; + bool xPlus_; + bool yPlus_; + bool firstPointBottomLeft_; + + // -- Methods + + static Configuration make_proj_spec(const Configuration&); + static LinearSpacing linspace(double start, double step, long num, bool plus); + + // -- Overridden methods + + // from Grid + bool sameAs(const Grid&) const override; + + bool includesNorthPole() const override; + bool includesSouthPole() const override; + bool isPeriodicWestEast() const override; + + void reorder(long scanningMode) const override; + void print(std::ostream&) const override; + + bool crop(BoundingBox&, Renumber&) const override; + size_t numberOfPoints() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularLL.cc b/src/eckit/geo/grid/RegularLL.cc new file mode 100644 index 000000000..a343b8052 --- /dev/null +++ b/src/eckit/geo/grid/RegularLL.cc @@ -0,0 +1,75 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/RegularLL.h" + +#include + +#include "eckit/geo/Iterator.h" + + +namespace eckit::geo::grid { + +RegularLL::RegularLL(const Configuration& config) : + LatLon(config) {} + +RegularLL::RegularLL(const Increments& increments, const BoundingBox& bbox, const PointLonLat& reference) : + LatLon(increments, bbox, reference) {} + +RegularLL::~RegularLL() = default; + +Iterator* RegularLL::iterator() const { + + class RegularLLIterator : protected LatLonIterator, public Iterator { + void print(std::ostream& out) const override { + out << "RegularLLIterator["; + Iterator::print(out); + out << ","; + LatLonIterator::print(out); + out << "]"; + } + bool next(double& lat, double& lon) override { return LatLonIterator::next(lat, lon); } + + size_t index() const override { return count_; } + + public: + RegularLLIterator(size_t ni, size_t nj, Latitude north, Longitude west, const Increments& increments) : + LatLonIterator(ni, nj, north, west, increments) {} + }; + + return new RegularLLIterator(ni_, nj_, bbox_.north(), bbox_.west(), increments_); +} + +void RegularLL::print(std::ostream& out) const { + out << "RegularLL["; + LatLon::print(out); + out << "]"; +} + +bool RegularLL::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && LatLon::sameAs(other); +} + +const RegularLL* RegularLL::croppedGrid(const BoundingBox& bbox) const { + return new RegularLL(increments_, bbox, reference_); +} + +std::string RegularLL::factory() const { + return "regular_ll"; +} + + +static const GridBuilder regularLL("regular_ll"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularLL.h b/src/eckit/geo/grid/RegularLL.h new file mode 100644 index 000000000..03107d479 --- /dev/null +++ b/src/eckit/geo/grid/RegularLL.h @@ -0,0 +1,83 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/LatLon.h" + + +namespace eckit::geo::grid { + + +class RegularLL : public LatLon { +public: + // -- Exceptions + // None + + // -- Constructors + + RegularLL(const Configuration&); + RegularLL(const Increments&, const BoundingBox& = {}, const PointLonLat& reference = {0, 0}); + + // -- Destructor + + ~RegularLL() override; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + Iterator* iterator() const override; + void print(std::ostream&) const override; + + bool sameAs(const Grid&) const override; + + // From Grid + const RegularLL* croppedGrid(const BoundingBox&) const override; + + std::string factory() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedClassic.cc b/src/eckit/geo/grid/RotatedClassic.cc new file mode 100644 index 000000000..c3620e1df --- /dev/null +++ b/src/eckit/geo/grid/RotatedClassic.cc @@ -0,0 +1,48 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/RotatedClassic.h" + +#include + + +namespace eckit::geo::grid { + + +RotatedClassic::RotatedClassic(size_t N, const Rotation& rotation, const BoundingBox& bbox, + double angularPrecision) : + Classic(N, bbox, angularPrecision), rotation_(rotation) {} + + +void RotatedClassic::print(std::ostream& out) const { + out << "RotatedClassic[" + "N=" + << N_ << ",bbox=" << bbox() << ",rotation=" << rotation_ << "]"; +} + + +bool RotatedClassic::sameAs(const Grid& /*unused*/) const { + NOTIMP; +} + + +Iterator* RotatedClassic::iterator() const { + return rotatedIterator(rotation_); +} + + +const Grid* RotatedClassic::croppedGrid(const BoundingBox& bbox) const { + return new RotatedClassic(N_, rotation_, bbox, angularPrecision_); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedClassic.h b/src/eckit/geo/grid/RotatedClassic.h new file mode 100644 index 000000000..93547796c --- /dev/null +++ b/src/eckit/geo/grid/RotatedClassic.h @@ -0,0 +1,94 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Classic.h" + + +namespace eckit::geo::grid { + + +class RotatedClassic : public Classic { +public: + // -- Exceptions + // None + + // -- Constructors + + RotatedClassic(size_t, const Rotation&, const BoundingBox& = BoundingBox(), + double angularPrecision = 0); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + + Rotation rotation_; + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + Iterator* iterator() const override; + const Grid* croppedGrid(const BoundingBox&) const override; + bool sameAs(const Grid&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedFromPL.cc b/src/eckit/geo/grid/RotatedFromPL.cc new file mode 100644 index 000000000..521576612 --- /dev/null +++ b/src/eckit/geo/grid/RotatedFromPL.cc @@ -0,0 +1,56 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/RotatedFromPL.h" + +#include + + +namespace eckit::geo::grid { + + +RotatedFromPL::RotatedFromPL(const Configuration& config) : + FromPL(config), rotation_(parametrisation) {} + + +RotatedFromPL::RotatedFromPL(size_t N, const std::vector& pl, const Rotation& rotation, + const BoundingBox& bbox, double angularPrecision) : + FromPL(N, pl, bbox, angularPrecision), rotation_(rotation) {} + + +void RotatedFromPL::print(std::ostream& out) const { + out << "RotatedFromPL[" + "N=" + << N_ << ",bbox=" << bbox() << ",rotation=" << rotation_ << "]"; +} + + +bool RotatedFromPL::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && (rotation_ == o->rotation_) && FromPL::sameAs(other); +} + + +Iterator* RotatedFromPL::iterator() const { + return rotatedIterator(rotation_); +} + + +const Grid* RotatedFromPL::croppedGrid(const BoundingBox& bbox) const { + return new RotatedFromPL(N_, pls(), rotation_, bbox, angularPrecision_); +} + + +static const GridBuilder rotatedFromPL("reduced_rotated_gg"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedFromPL.h b/src/eckit/geo/grid/RotatedFromPL.h new file mode 100644 index 000000000..ca8a0a14e --- /dev/null +++ b/src/eckit/geo/grid/RotatedFromPL.h @@ -0,0 +1,95 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/FromPL.h" + + +namespace eckit::geo::grid { + + +class RotatedFromPL : public FromPL { +public: + // -- Exceptions + // None + + // -- Constructors + + RotatedFromPL(const Configuration&); + RotatedFromPL(size_t, const std::vector&, const Rotation&, + const BoundingBox& = BoundingBox(), double angularPrecision = 0); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + + Rotation rotation_; + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + Iterator* iterator() const override; + const Grid* croppedGrid(const BoundingBox&) const override; + bool sameAs(const Grid&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedGG.cc b/src/eckit/geo/grid/RotatedGG.cc new file mode 100644 index 000000000..18212b316 --- /dev/null +++ b/src/eckit/geo/grid/RotatedGG.cc @@ -0,0 +1,59 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/RotatedGG.h" + +#include +#include + +#include "eckit/geo/grid/GaussianIterator.h" + + +namespace eckit::geo::grid { + + +RotatedGG::RotatedGG(const Configuration& config) : + Regular(config), rotation_(parametrisation) {} + + +RotatedGG::RotatedGG(size_t N, const Rotation& rotation, const BoundingBox& bbox, double angularPrecision) : + Regular(N, bbox, angularPrecision), rotation_(rotation) {} + + +void RotatedGG::print(std::ostream& out) const { + out << "RotatedGG[" + "N=" + << N_ << ",Ni=" << Ni_ << ",Nj=" << Nj_ << ",bbox=" << bbox() << ",rotation=" << rotation_ << "]"; +} + + +bool RotatedGG::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && (rotation_ == o->rotation_) && Regular::sameAs(other); +} + + +Iterator* RotatedGG::iterator() const { + std::vector pl(N_ * 2, long(4 * N_)); + return new GaussianIterator(latitudes(), std::move(pl), bbox(), N_, Nj_, k_, rotation_); +} + + +const Grid* RotatedGG::croppedGrid(const BoundingBox& bbox) const { + return new RotatedGG(N_, rotation_, bbox, angularPrecision_); +} + + +static const GridBuilder rotatedGG("rotated_gg"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedGG.h b/src/eckit/geo/grid/RotatedGG.h new file mode 100644 index 000000000..a0057a122 --- /dev/null +++ b/src/eckit/geo/grid/RotatedGG.h @@ -0,0 +1,95 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Regular.h" + + +namespace eckit::geo::grid { + + +class RotatedGG : public Regular { +public: + // -- Exceptions + // None + + // -- Constructors + + RotatedGG(const Configuration&); + RotatedGG(size_t N, const Rotation&, const BoundingBox& = BoundingBox(), + double angularPrecision = 0); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + + Rotation rotation_; + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + Iterator* iterator() const override; + + const Grid* croppedGrid(const BoundingBox&) const override; + bool sameAs(const Grid&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedLL.cc b/src/eckit/geo/grid/RotatedLL.cc new file mode 100644 index 000000000..9c58d702e --- /dev/null +++ b/src/eckit/geo/grid/RotatedLL.cc @@ -0,0 +1,78 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/RotatedLL.h" + +#include + +#include "eckit/geo/Iterator.h" + + +namespace eckit::geo::grid { + +RotatedLL::RotatedLL(const Configuration& config) : + LatLon(config), rotation_(parametrisation) {} + +RotatedLL::RotatedLL(const Increments& increments, const Rotation& rotation, const BoundingBox& bbox, + const PointLonLat& reference) : + LatLon(increments, bbox, reference), rotation_(rotation) {} + +RotatedLL::~RotatedLL() = default; + +Iterator* RotatedLL::iterator() const { + + class RotatedLLIterator : protected LatLonIterator, public Iterator { + void print(std::ostream& out) const override { + out << "RotatedLLIterator["; + Iterator::print(out); + out << ","; + LatLonIterator::print(out); + out << "]"; + } + bool next(double& lat, double& lon) override { return LatLonIterator::next(lat, lon); } + + size_t index() const override { return count_; } + + public: + RotatedLLIterator(size_t ni, size_t nj, Latitude north, Longitude west, const Increments& increments, + const Rotation& rotation) : + LatLonIterator(ni, nj, north, west, increments), Iterator(rotation) {} + }; + + return new RotatedLLIterator(ni_, nj_, bbox_.north(), bbox_.west(), increments_, rotation_); +} + +void RotatedLL::print(std::ostream& out) const { + out << "RotatedLL["; + LatLon::print(out); + out << ",rotation=" << rotation_ << "]"; +} + +bool RotatedLL::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && (rotation_ == o->rotation_) && LatLon::sameAs(other); +} + +const RotatedLL* RotatedLL::croppedGrid(const BoundingBox& bbox) const { + return new RotatedLL(increments_, rotation_, bbox, reference_); +} + + +std::string RotatedLL::factory() const { + return "rotated_ll"; +} + + +static const GridBuilder rotatedLL("rotated_ll"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedLL.h b/src/eckit/geo/grid/RotatedLL.h new file mode 100644 index 000000000..0ec2d198e --- /dev/null +++ b/src/eckit/geo/grid/RotatedLL.h @@ -0,0 +1,83 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/LatLon.h" + + +namespace eckit::geo::grid { + + +class RotatedLL : public LatLon { +public: + // -- Exceptions + // None + + // -- Constructors + + RotatedLL(const Configuration&); + RotatedLL(const Increments&, const Rotation&, const BoundingBox& = {}, + const PointLonLat& reference = {0, 0}); + + // -- Destructor + + ~RotatedLL() override; + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + Rotation rotation_; + + // -- Methods + // None + + // -- Overridden methods + Iterator* iterator() const override; + void print(std::ostream&) const override; + + bool sameAs(const Grid&) const override; + + // From Grid + const RotatedLL* croppedGrid(const BoundingBox&) const override; + std::string factory() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedOctahedral.cc b/src/eckit/geo/grid/RotatedOctahedral.cc new file mode 100644 index 000000000..47fe0aaeb --- /dev/null +++ b/src/eckit/geo/grid/RotatedOctahedral.cc @@ -0,0 +1,48 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/RotatedOctahedral.h" + +#include + + +namespace eckit::geo::grid { + + +RotatedOctahedral::RotatedOctahedral(size_t N, const Rotation& rotation, const BoundingBox& bbox, + double angularPrecision) : + Octahedral(N, bbox, angularPrecision), rotation_(rotation) {} + + +void RotatedOctahedral::print(std::ostream& out) const { + out << "RotatedOctahedral[" + "N=" + << N_ << ",bbox=" << bbox() << ",rotation=" << rotation_ << "]"; +} + + +bool RotatedOctahedral::sameAs(const Grid& /*unused*/) const { + NOTIMP; +} + + +Iterator* RotatedOctahedral::iterator() const { + return rotatedIterator(rotation_); +} + + +const Grid* RotatedOctahedral::croppedGrid(const BoundingBox& bbox) const { + return new RotatedOctahedral(N_, rotation_, bbox, angularPrecision_); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedOctahedral.h b/src/eckit/geo/grid/RotatedOctahedral.h new file mode 100644 index 000000000..32b93337d --- /dev/null +++ b/src/eckit/geo/grid/RotatedOctahedral.h @@ -0,0 +1,94 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Octahedral.h" + + +namespace eckit::geo::grid { + + +class RotatedOctahedral : public Octahedral { +public: + // -- Exceptions + // None + + // -- Constructors + + RotatedOctahedral(size_t, const Rotation&, const BoundingBox& = BoundingBox(), + double angularPrecision = 0); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + + Rotation rotation_; + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + Iterator* iterator() const override; + const Grid* croppedGrid(const BoundingBox&) const override; + bool sameAs(const Grid&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/SpaceView.cc b/src/eckit/geo/grid/SpaceView.cc new file mode 100644 index 000000000..2e6aa522a --- /dev/null +++ b/src/eckit/geo/grid/SpaceView.cc @@ -0,0 +1,236 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/SpaceView.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "eckit/geo/Iterator.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::grid { + + +static const GridBuilder __builder("space_view"); + + +namespace detail { + + +template +EXTERNAL_T get(const Configuration& param, const std::string& key) { + INTERNAL_T value; + ASSERT(param.get(key, value)); + return static_cast(value); +} + + +SpaceViewInternal::SpaceViewInternal(const Configuration& param) { + auto earthIsOblate = get(param, "earthIsOblate"); + auto a = get(param, earthIsOblate ? "earthMajorAxis" : "radius"); + auto b = earthIsOblate ? get(param, "earthMinorAxis") : a; + + auto Nr = get(param, "NrInRadiusOfEarthScaled"); + ASSERT(Nr > 1.); + + auto h = (Nr - 1.) * a; + + Lop_ = get(param, "longitudeOfSubSatellitePointInDegrees"); + auto Lap = get(param, "latitudeOfSubSatellitePointInDegrees"); + ASSERT(types::is_approximately_equal(Lap, 0.)); + + // ASSERT(get(param, "orientationOfTheGridInDegrees") == 180); + + + // projection + auto proj = [](double h, double a, double b, double lon_0) { + auto _h = " +h=" + std::to_string(h); + auto _l = types::is_approximately_equal(lon_0, 0.) ? "" : " +lon_0=" + std::to_string(lon_0); + auto _e = types::is_approximately_equal(a, b) ? " +R=" + std::to_string(a) + : " +a=" + std::to_string(a) + " +b=" + std::to_string(b); + return "+proj=geos +type=crs +sweep=y" + _h + _l + _e; + }; + + projection_ = RegularGrid::Configuration("type", "proj").set("proj", proj(h, a, b, Lop_)); + projectionGreenwich_ = RegularGrid::Configuration("type", "proj").set("proj", proj(h, a, b, 0)); + + // (x, y) space + Nx_ = get(param, "Nx"); + ASSERT(1 < Nx_); + + auto ip = get(param, "iScansPositively"); + auto xp = get(param, "XpInGridLengths"); + auto dx = get(param, "dx"); + ASSERT(dx > 0); + + auto rx = 2. * std::asin(1. / Nr) / dx * h; // (height factor is PROJ-specific) + + (ip ? xa_ : xb_) = rx * (-xp); + (ip ? xb_ : xa_) = rx * (-xp + double(Nx_ - 1)); + + Ny_ = get(param, "Ny"); + ASSERT(1 < Ny_); + + auto jp = get(param, "jScansPositively"); + auto yp = get(param, "YpInGridLengths"); + auto dy = get(param, "dy"); + ASSERT(dy > 0); + + auto ry = 2. * std::asin(1. / Nr) / dy * h; // (height factor is PROJ-specific) + + (jp ? ya_ : yb_) = ry * (-yp); + (jp ? yb_ : ya_) = ry * (-yp + double(Ny_ - 1)); + + + // longest element diagonal, a multiple of a reference central element diagonal (avoiding distortion) + LongestElementDiagonal_ = 20. * Earth::distance(projection_.lonlat({-rx / 2, ry / 2}), projection_.lonlat({rx / 2, -ry / 2})); + ASSERT(0. < LongestElementDiagonal_); + + + // bounding box +#if 1 + // [1] page 25, solution of s_d^2=0, restrained at x=0 (lon) and y=0 (lat). Note: uses a, b, height defined there + auto eps_ll = 1e-6; + + auto n = 90. - radian_to_degree(0.151347) + eps_ll; + auto s = -n; + + auto e = 90. - radian_to_degree(0.151853) + eps_ll + Lop_; + auto w = 2. * Lop_ - e; +#else + auto geometric_maximum = [](double x_min, double x_eps, const std::function& f, + double f_eps = 1.e-9, size_t it_max = 1000) { + size_t it = 0; + auto x = x_min; + auto fx = f(x); + + for (auto dx = x_eps; f_eps < dx && it < it_max; ++it) { + auto fx_new = f(x + dx); + if (!std::isfinite(fx_new) || fx_new < fx) { + dx /= 2.; + } + else { + x += dx; + fx = fx_new; + dx *= 2.; + } + } + + ASSERT(0. < fx && fx < 90.); + return fx; + }; + + auto eps_xy = 1e-6 * h; + auto eps_ll = 1e-6; + + auto max_lon = geometric_maximum(0., eps_xy, [&](double x) { return projectionGreenwich_.lonlat({x, 0}).lon(); }); + auto w = Lop_ - max_lon - eps_ll; + auto e = Lop_ + max_lon + eps_ll; + + auto max_lat = geometric_maximum(0., eps_xy, [&](double y) { return projectionGreenwich_.lonlat({0, y}).lat(); }); + auto n = max_lat + eps_ll; + auto s = -n; +#endif + + bbox_ = {n, w, s, e}; +} + + +const std::vector& SpaceViewInternal::lonlat() const { + if (lonlat_.empty()) { + trace::Timer timer("SpaceView: pre-calculate (lon, lat) coordinates"); + + ASSERT(projectionGreenwich_); // Greenwich-centred (avoids PROJ normalisation) + lonlat_.resize(Nx_ * Ny_); + + size_t index = 0; + for (const auto& _y : y()) { + for (const auto& _x : x()) { + auto& ll = lonlat_[index++]; + ll = projectionGreenwich_.lonlat({_x, _y}); + if (std::isfinite(ll.lon()) && std::isfinite(ll.lat())) { + ASSERT(-90. < ll.lon() && ll.lon() < 90.); + ASSERT(-90. < ll.lat() && ll.lat() < 90.); + + ll.lon() += Lop_; + } + else { + ll = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + } + } + } + } + + ASSERT(!lonlat_.empty()); + return lonlat_; +} + + +} // namespace detail + + +SpaceView::SpaceView(const Configuration& param) : + detail::SpaceViewInternal(param), + RegularGrid(SpaceViewInternal::projection_, SpaceViewInternal::bbox_, SpaceViewInternal::x(), + SpaceViewInternal::y(), {param}) {} + + +Iterator* SpaceView::iterator() const { + class SpaceViewIterator : public Iterator { + const std::vector& lonlat_; + size_t count_; + + void print(std::ostream& out) const override { + out << "SpaceViewIterator["; + Iterator::print(out); + out << ",count=" << count_ << "]"; + } + + bool next(double& _lat, double& _lon) override { + while (count_ < lonlat_.size()) { + // only one of (lon, lat) needs to be checked + const auto& ll = lonlat_[count_++]; + if (std::isfinite(ll.lon())) { + _lat = lat(ll.lat()); + _lon = lon(ll.lon()); + return true; + } + } + + return false; + } + + size_t index() const override { return count_; } + + public: + SpaceViewIterator(const std::vector& lonlat) : + lonlat_(lonlat), count_(0) {} + ~SpaceViewIterator() override = default; + + SpaceViewIterator(const SpaceViewIterator&) = delete; + SpaceViewIterator(SpaceViewIterator&&) = delete; + SpaceViewIterator& operator=(const SpaceViewIterator&) = delete; + SpaceViewIterator& operator=(SpaceViewIterator&&) = delete; + }; + + return new SpaceViewIterator(lonlat()); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/SpaceView.h b/src/eckit/geo/grid/SpaceView.h new file mode 100644 index 000000000..145caa50c --- /dev/null +++ b/src/eckit/geo/grid/SpaceView.h @@ -0,0 +1,112 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/RegularGrid.h" + + +namespace eckit::geo::grid { +namespace detail { + + +/* + * References: + * - [1] LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) + * - [2] MSG Ground Segment LRIT/HRIT Mission Specific Implementation, EUMETSAT Document, (EUM/MSG/SPE/057, Issue 6, 21. + * June 2006) + * - [3] MSG Ground Segment LRIT/HRIT Mission Specific Implementation, EUMETSAT Document, (EUM/MSG/SPE/057 v7 e-signed. + * 30 November 2015) + */ +struct SpaceViewInternal { + SpaceViewInternal(const Configuration&); + Projection projection_; + Projection projectionGreenwich_; + BoundingBox bbox_; + + RegularGrid::LinearSpacing x() const { return {xa_, xb_, Nx_, true}; } + RegularGrid::LinearSpacing y() const { return {ya_, yb_, Ny_, true}; } + + const std::vector& lonlat() const; + + long Nx_; + long Ny_; + double xa_; + double xb_; + double ya_; + double yb_; + double LongestElementDiagonal_; + double Lop_; + +private: + mutable std::vector lonlat_; +}; + + +} // namespace detail + + +class SpaceView final : public detail::SpaceViewInternal, public RegularGrid { +public: + // -- Exceptions + // None + + // -- Constructors + + SpaceView(const Configuration&); + SpaceView(const SpaceView&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + SpaceView& operator=(const SpaceView&) = delete; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + Iterator* iterator() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedGG.cc b/src/eckit/geo/grid/StretchedGG.cc new file mode 100644 index 000000000..26ec938a2 --- /dev/null +++ b/src/eckit/geo/grid/StretchedGG.cc @@ -0,0 +1,33 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/StretchedGG.h" + +#include + + +namespace eckit::geo::grid { + + +StretchedGG::StretchedGG(const Configuration& /*config*/) {} + + +void StretchedGG::print(std::ostream& out) const { + out << "StretchedGG[" + << "]"; +} + + +static const GridBuilder __repres("stretched_gg"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedGG.h b/src/eckit/geo/grid/StretchedGG.h new file mode 100644 index 000000000..7be463b6c --- /dev/null +++ b/src/eckit/geo/grid/StretchedGG.h @@ -0,0 +1,91 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class StretchedGG : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + StretchedGG(const Configuration&); + StretchedGG(const StretchedGG&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + StretchedGG& operator=(const StretchedGG&) = delete; + + // -- Methods + // // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedLL.cc b/src/eckit/geo/grid/StretchedLL.cc new file mode 100644 index 000000000..2186f507b --- /dev/null +++ b/src/eckit/geo/grid/StretchedLL.cc @@ -0,0 +1,33 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/StretchedLL.h" + +#include + + +namespace eckit::geo::grid { + + +StretchedLL::StretchedLL(const Configuration& /*config*/) {} + + +void StretchedLL::print(std::ostream& out) const { + out << "StretchedLL[" + << "]"; +} + + +static const GridBuilder __repres("stretched_ll"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedLL.h b/src/eckit/geo/grid/StretchedLL.h new file mode 100644 index 000000000..76409446d --- /dev/null +++ b/src/eckit/geo/grid/StretchedLL.h @@ -0,0 +1,91 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class StretchedLL : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + StretchedLL(const Configuration&); + StretchedLL(const StretchedLL&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + StretchedLL& operator=(const StretchedLL&) = delete; + + // -- Methods + // // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedRotatedGG.cc b/src/eckit/geo/grid/StretchedRotatedGG.cc new file mode 100644 index 000000000..fe78be8bb --- /dev/null +++ b/src/eckit/geo/grid/StretchedRotatedGG.cc @@ -0,0 +1,33 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/StretchedRotatedGG.h" + +#include + + +namespace eckit::geo::grid { + + +StretchedRotatedGG::StretchedRotatedGG(const Configuration& /*config*/) {} + + +void StretchedRotatedGG::print(std::ostream& out) const { + out << "StretchedRotatedGG[" + << "]"; +} + + +static const GridBuilder __repres("stretched_rotated_gg"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedRotatedGG.h b/src/eckit/geo/grid/StretchedRotatedGG.h new file mode 100644 index 000000000..4663edc6a --- /dev/null +++ b/src/eckit/geo/grid/StretchedRotatedGG.h @@ -0,0 +1,91 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class StretchedRotatedGG : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + StretchedRotatedGG(const Configuration&); + StretchedRotatedGG(const StretchedRotatedGG&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + StretchedRotatedGG& operator=(const StretchedRotatedGG&) = delete; + + // -- Methods + // // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedRotatedLL.cc b/src/eckit/geo/grid/StretchedRotatedLL.cc new file mode 100644 index 000000000..8fbca1727 --- /dev/null +++ b/src/eckit/geo/grid/StretchedRotatedLL.cc @@ -0,0 +1,33 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/StretchedRotatedLL.h" + +#include + + +namespace eckit::geo::grid { + + +StretchedRotatedLL::StretchedRotatedLL(const Configuration& /*config*/) {} + + +void StretchedRotatedLL::print(std::ostream& out) const { + out << "StretchedRotatedLL[" + << "]"; +} + + +static const GridBuilder __repres("stretched_rotated_ll"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedRotatedLL.h b/src/eckit/geo/grid/StretchedRotatedLL.h new file mode 100644 index 000000000..b7009c64d --- /dev/null +++ b/src/eckit/geo/grid/StretchedRotatedLL.h @@ -0,0 +1,91 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class StretchedRotatedLL : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + StretchedRotatedLL(const Configuration&); + StretchedRotatedLL(const StretchedRotatedLL&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + StretchedRotatedLL& operator=(const StretchedRotatedLL&) = delete; + + // -- Methods + // // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/TransverseMercator.cc b/src/eckit/geo/grid/TransverseMercator.cc new file mode 100644 index 000000000..4dfc8889b --- /dev/null +++ b/src/eckit/geo/grid/TransverseMercator.cc @@ -0,0 +1,33 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/TransverseMercator.h" + +#include + + +namespace eckit::geo::grid { + + +TransverseMercator::TransverseMercator(const Configuration& /*config*/) {} + + +void TransverseMercator::print(std::ostream& out) const { + out << "TransverseMercator[" + << "]"; +} + + +static const GridBuilder __repres("transverse_mercator"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/TransverseMercator.h b/src/eckit/geo/grid/TransverseMercator.h new file mode 100644 index 000000000..32819cbac --- /dev/null +++ b/src/eckit/geo/grid/TransverseMercator.h @@ -0,0 +1,91 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::grid { + + +class TransverseMercator : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + TransverseMercator(const Configuration&); + TransverseMercator(const TransverseMercator&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + TransverseMercator& operator=(const TransverseMercator&) = delete; + + // -- Methods + // // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/UnstructuredGrid.cc b/src/eckit/geo/grid/UnstructuredGrid.cc new file mode 100644 index 000000000..99a001a3d --- /dev/null +++ b/src/eckit/geo/grid/UnstructuredGrid.cc @@ -0,0 +1,215 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/UnstructuredGrid.h" + +#include +#include +#include +#include +#include +#include + +#include "eckit/config/Resource.h" +#include "eckit/filesystem/PathName.h" +#include "eckit/geo/Iterator.h" +#include "eckit/geo/grid/ORCA.h" +#include "eckit/serialisation/FileStream.h" +#include "eckit/serialisation/IfstreamStream.h" + + +namespace eckit::geo::grid { + + +UnstructuredGrid::UnstructuredGrid(const Configuration& config) { + config.get("latitudes", latitudes_); + config.get("longitudes", longitudes_); + + if (latitudes_.empty() || longitudes_.empty()) { + throw UserError("UnstructuredGrid: requires 'latitudes' and 'longitudes'"); + } + ASSERT(latitudes_.size() == longitudes_.size()); + + check_duplicate_points("UnstructuredGrid from Configuration", latitudes_, longitudes_, config); +} + + +UnstructuredGrid::UnstructuredGrid(const PathName& path) { + std::ifstream in(path.asString().c_str()); + if (!in) { + throw CantOpenFile(path); + } + + if (::isprint(in.peek()) == 0) { + + Log::info() << "UnstructuredGrid::load " << path << std::endl; + + IfstreamStream s(in); + size_t version; + s >> version; + ASSERT(version == 1); + + size_t count; + s >> count; + + latitudes_.resize(count); + longitudes_.resize(count); + + for (size_t i = 0; i < count; ++i) { + s >> latitudes_[i]; + s >> longitudes_[i]; + // Log::info() << latitudes_[i] << " " << longitudes_[i] << std::endl; + } + } + else { + double lat; + double lon; + while (in >> lat >> lon) { + latitudes_.push_back(lat); + longitudes_.push_back(lon); + } + } + + check_duplicate_points("UnstructuredGrid from " + path.asString(), latitudes_, longitudes_); +} + + +void UnstructuredGrid::save(const PathName& path, const std::vector& latitudes, + const std::vector& longitudes, bool binary) { + Log::info() << "UnstructuredGrid::save " << path << std::endl; + + check_duplicate_points("UnstructuredGrid::save to " + path.asString(), latitudes, longitudes); + + ASSERT(latitudes.size() == longitudes.size()); + if (binary) { + FileStream s(path, "w"); + size_t version = 1; + size_t count = latitudes.size(); + s << version; + s << count; + for (size_t i = 0; i < count; ++i) { + s << latitudes[i]; + s << longitudes[i]; + + Log::info() << latitudes[i] << " " << longitudes[i] << std::endl; + } + s.close(); + } + else { + NOTIMP; + } +} + + +UnstructuredGrid::UnstructuredGrid(const std::vector& latitudes, const std::vector& longitudes, + const BoundingBox& bbox) : + Grid(bbox), latitudes_(latitudes), longitudes_(longitudes) { + ASSERT(latitudes_.size() == longitudes_.size()); + check_duplicate_points("UnstructuredGrid from arguments", latitudes_, longitudes_); +} + + +UnstructuredGrid::~UnstructuredGrid() = default; + + +void UnstructuredGrid::print(std::ostream& out) const { + out << "UnstructuredGrid[points=" << numberOfPoints() << "]"; +} + + +bool UnstructuredGrid::sameAs(const Grid& other) const { + const auto* o = dynamic_cast(&other); + return (o != nullptr) && (latitudes_ == o->latitudes_) && (longitudes_ == o->longitudes_); +} + + +Domain UnstructuredGrid::domain() const { + // FIXME Should be global? + return {bbox().north(), bbox().west(), bbox().south(), bbox().east()}; +} + + +size_t UnstructuredGrid::numberOfPoints() const { + ASSERT(latitudes_.size() == longitudes_.size()); + return latitudes_.size(); +} + + +const Grid* UnstructuredGrid::croppedGrid(const BoundingBox& bbox) const { + std::vector lat; + std::vector lon; + + size_t i = 0; + size_t j = 0; + + for (const std::unique_ptr iter(iterator()); iter->next(); ++i) { + if (bbox.contains(iter->pointUnrotated())) { + auto ip = iter->index(); + lat.emplace_back(latitudes_.at(ip)); + lon.emplace_back(longitudes_.at(ip)); + ++j; + } + } + + if (j < i) { + Log::debug() << "UnstructuredGrid::croppedGrid: cropped " << Log::Pretty(i) << " to " + << Log::Pretty(j, {"point"}) << std::endl; + ASSERT(j); + return new UnstructuredGrid(lat, lon, bbox); + } + + Log::debug() << "UnstructuredGrid::croppedGrid: no cropping" << std::endl; + return this; +} + + +Iterator* UnstructuredGrid::iterator() const { + return new iterator::UnstructuredIterator(latitudes_, longitudes_); +} + + +bool UnstructuredGrid::isPeriodicWestEast() const { + return bbox().east() - bbox().west() == GLOBE; +} + + +bool UnstructuredGrid::includesNorthPole() const { + return bbox().north() == NORTH_POLE; +} + + +bool UnstructuredGrid::includesSouthPole() const { + return bbox().south() == SOUTH_POLE; +} + + +static const GridBuilder triangular_grid("triangular_grid"); +static const GridBuilder unstructured_grid("unstructured_grid"); + + +template <> +Grid* GridBuilder::make(const Configuration& param) { +#if mir_HAVE_ATLAS + // specially-named unstructured grids + std::string grid; + if (param.get("grid", grid)) { + if (!key::grid::ORCAPattern::match(grid, param).empty()) { + return new other::ORCA(param); + } + } +#endif + + return new other::UnstructuredGrid(param); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/UnstructuredGrid.h b/src/eckit/geo/grid/UnstructuredGrid.h new file mode 100644 index 000000000..739504c2f --- /dev/null +++ b/src/eckit/geo/grid/UnstructuredGrid.h @@ -0,0 +1,121 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "eckit/geo/Grid.h" + + +namespace eckit { +class PathName; +} + + +namespace eckit::geo::grid { + + +class UnstructuredGrid : public Grid { +public: + // -- Exceptions + // None + + // -- Constructors + + explicit UnstructuredGrid(const PathName&); + explicit UnstructuredGrid(const Configuration&); + UnstructuredGrid(const std::vector& latitudes, const std::vector& longitudes, + const BoundingBox& = BoundingBox()); + + UnstructuredGrid(const UnstructuredGrid&) = delete; + UnstructuredGrid(UnstructuredGrid&&) = delete; + + // -- Destructor + + ~UnstructuredGrid() override; + + // -- Convertors + // None + + // -- Operators + + void operator=(const UnstructuredGrid&) = delete; + void operator=(const UnstructuredGrid&&) = delete; + + // -- Methods + + static void save(const PathName&, const std::vector& latitudes, + const std::vector& longitudes, bool binary); + + // -- Overridden methods + + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + + // From Grid + void print(std::ostream&) const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + std::vector latitudes_; + std::vector longitudes_; + + // -- Methods + // None + + // -- Overridden methods + + Domain domain() const override; + Iterator* iterator() const override; + bool sameAs(const Grid&) const override; + + // Domain operations + bool isPeriodicWestEast() const override; + bool includesNorthPole() const override; + bool includesSouthPole() const override; + + size_t numberOfPoints() const override; + const Grid* croppedGrid(const BoundingBox&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid From 7f95e86e56c0c19572ae7f4d1159aba5781c68b1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 7 Jun 2023 16:48:25 +0100 Subject: [PATCH 240/737] eckit::geo::grid --- src/eckit/geo/BoundingBox.cc | 7 +- src/eckit/geo/BoundingBox.h | 8 +- src/eckit/geo/CMakeLists.txt | 23 +- src/eckit/geo/Domain.cc | 7 +- .../geo/{grid/StretchedLL.cc => Earth.h} | 26 +- src/eckit/geo/Grid.cc | 74 +---- src/eckit/geo/Grid.h | 5 +- .../{grid/StretchedGG.cc => Increments.cc} | 18 +- src/eckit/geo/Increments.h | 54 ++++ src/eckit/geo/Point.h | 4 + src/eckit/geo/grid/Albers.h | 4 +- src/eckit/geo/grid/AzimuthRange.h | 4 +- src/eckit/geo/grid/Classic.cc | 6 - src/eckit/geo/grid/Classic.h | 20 +- .../geo/grid/EquatorialAzimuthalEquidistant.h | 4 +- src/eckit/geo/grid/FromPL.cc | 6 - src/eckit/geo/grid/FromPL.h | 20 +- src/eckit/geo/grid/Gaussian.cc | 6 - src/eckit/geo/grid/Gaussian.h | 1 - src/eckit/geo/grid/GaussianIterator.h | 1 + src/eckit/geo/grid/IrregularLatlon.cc | 24 -- src/eckit/geo/grid/IrregularLatlon.h | 7 +- src/eckit/geo/grid/Lambert.cc | 45 ++- src/eckit/geo/grid/Lambert.h | 2 +- .../geo/grid/LambertAzimuthalEqualArea.cc | 26 -- .../geo/grid/LambertAzimuthalEqualArea.h | 3 +- src/eckit/geo/grid/LatLon.cc | 211 ------------- src/eckit/geo/grid/LatLon.h | 138 --------- src/eckit/geo/grid/None.h | 1 - src/eckit/geo/grid/ORCA.cc | 33 +- src/eckit/geo/grid/ORCA.h | 3 - src/eckit/geo/grid/Octahedral.cc | 6 - src/eckit/geo/grid/Octahedral.h | 17 -- src/eckit/geo/grid/Reduced.cc | 6 - src/eckit/geo/grid/Reduced.h | 3 - src/eckit/geo/grid/ReducedClassic.cc | 11 - src/eckit/geo/grid/ReducedClassic.h | 2 - src/eckit/geo/grid/ReducedFromPL.cc | 11 - src/eckit/geo/grid/ReducedFromPL.h | 2 - src/eckit/geo/grid/ReducedLL.cc | 12 - src/eckit/geo/grid/ReducedLL.h | 5 +- src/eckit/geo/grid/ReducedOctahedral.cc | 11 - src/eckit/geo/grid/ReducedOctahedral.h | 2 - src/eckit/geo/grid/Regular.cc | 61 ++-- src/eckit/geo/grid/Regular.h | 3 - src/eckit/geo/grid/RegularGG.cc | 16 - src/eckit/geo/grid/RegularGG.h | 21 +- src/eckit/geo/grid/RegularGrid.cc | 12 - src/eckit/geo/grid/RegularGrid.h | 3 - src/eckit/geo/grid/RegularLL.cc | 288 ++++++++++++++++-- src/eckit/geo/grid/RegularLL.h | 34 ++- src/eckit/geo/grid/RotatedClassic.cc | 48 --- src/eckit/geo/grid/RotatedClassic.h | 94 ------ src/eckit/geo/grid/RotatedFromPL.cc | 56 ---- src/eckit/geo/grid/RotatedFromPL.h | 95 ------ src/eckit/geo/grid/RotatedGG.cc | 59 ---- src/eckit/geo/grid/RotatedGG.h | 95 ------ src/eckit/geo/grid/RotatedLL.cc | 78 ----- src/eckit/geo/grid/RotatedLL.h | 83 ----- src/eckit/geo/grid/RotatedOctahedral.cc | 48 --- src/eckit/geo/grid/RotatedOctahedral.h | 94 ------ src/eckit/geo/grid/SpaceView.cc | 25 +- src/eckit/geo/grid/SpaceView.h | 14 +- src/eckit/geo/grid/StretchedGG.h | 91 ------ src/eckit/geo/grid/StretchedLL.h | 91 ------ src/eckit/geo/grid/StretchedRotatedGG.cc | 33 -- src/eckit/geo/grid/StretchedRotatedGG.h | 91 ------ src/eckit/geo/grid/StretchedRotatedLL.cc | 33 -- src/eckit/geo/grid/StretchedRotatedLL.h | 91 ------ src/eckit/geo/grid/TransverseMercator.cc | 2 +- src/eckit/geo/grid/TransverseMercator.h | 4 +- src/eckit/geo/grid/UnstructuredGrid.cc | 179 +++++------ src/eckit/geo/grid/UnstructuredGrid.h | 10 +- src/eckit/geo/projection/Rotation.cc | 42 +-- src/eckit/geo/projection/Rotation.h | 2 +- src/eckit/geo/util.h | 4 + tests/geo/test_projection_rotation.cc | 40 +-- 77 files changed, 628 insertions(+), 2191 deletions(-) rename src/eckit/geo/{grid/StretchedLL.cc => Earth.h} (50%) rename src/eckit/geo/{grid/StretchedGG.cc => Increments.cc} (54%) create mode 100644 src/eckit/geo/Increments.h delete mode 100644 src/eckit/geo/grid/LatLon.cc delete mode 100644 src/eckit/geo/grid/LatLon.h delete mode 100644 src/eckit/geo/grid/RotatedClassic.cc delete mode 100644 src/eckit/geo/grid/RotatedClassic.h delete mode 100644 src/eckit/geo/grid/RotatedFromPL.cc delete mode 100644 src/eckit/geo/grid/RotatedFromPL.h delete mode 100644 src/eckit/geo/grid/RotatedGG.cc delete mode 100644 src/eckit/geo/grid/RotatedGG.h delete mode 100644 src/eckit/geo/grid/RotatedLL.cc delete mode 100644 src/eckit/geo/grid/RotatedLL.h delete mode 100644 src/eckit/geo/grid/RotatedOctahedral.cc delete mode 100644 src/eckit/geo/grid/RotatedOctahedral.h delete mode 100644 src/eckit/geo/grid/StretchedGG.h delete mode 100644 src/eckit/geo/grid/StretchedLL.h delete mode 100644 src/eckit/geo/grid/StretchedRotatedGG.cc delete mode 100644 src/eckit/geo/grid/StretchedRotatedGG.h delete mode 100644 src/eckit/geo/grid/StretchedRotatedLL.cc delete mode 100644 src/eckit/geo/grid/StretchedRotatedLL.h diff --git a/src/eckit/geo/BoundingBox.cc b/src/eckit/geo/BoundingBox.cc index e6cab9064..385a808de 100644 --- a/src/eckit/geo/BoundingBox.cc +++ b/src/eckit/geo/BoundingBox.cc @@ -18,6 +18,7 @@ #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/Point.h" +#include "eckit/geo/util.h" #include "eckit/geometry/Sphere.h" #include "eckit/types/FloatCompare.h" @@ -135,10 +136,8 @@ double BoundingBox::area(double radius) const { double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); ASSERT(0. <= lonf && lonf <= 1.); - constexpr auto degrees_to_radians = M_PI / 180.; - - const auto sn = std::sin(north_ * degrees_to_radians); - const auto ss = std::sin(south_ * degrees_to_radians); + const auto sn = std::sin(north_ * util::degree_to_radian); + const auto ss = std::sin(south_ * util::degree_to_radian); double latf = 0.5 * (sn - ss); ASSERT(0. <= latf && latf <= 1.); diff --git a/src/eckit/geo/BoundingBox.h b/src/eckit/geo/BoundingBox.h index e435cef93..e1cd72f5a 100644 --- a/src/eckit/geo/BoundingBox.h +++ b/src/eckit/geo/BoundingBox.h @@ -12,6 +12,8 @@ #pragma once +#include + namespace eckit { class Configuration; @@ -56,6 +58,7 @@ class BoundingBox { double west() const { return west_; } double south() const { return south_; } double east() const { return east_; } + bool isPeriodicWestEast() const; bool contains(double lat, double lon) const; bool contains(const BoundingBox&) const; @@ -112,7 +115,10 @@ class BoundingBox { // None // -- Friends - // None + + friend std::ostream& operator<<(std::ostream& out, const BoundingBox& p) { + return out << '{' << p.north_<< ", " << p.west_<< ", " << p.south_<< ", " << p.east_<< '}'; + } }; diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 22da23e00..b35b645f1 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -3,6 +3,7 @@ list(APPEND eckit_geo_srcs BoundingBox.h Domain.cc Domain.h + Earth.h Grid.cc Grid.h Iterator.cc @@ -14,6 +15,8 @@ list(APPEND eckit_geo_srcs Range.cc Range.h Renumber.h + Increments.cc + Increments.h Scanner.cc Scanner.h Search.h @@ -37,8 +40,6 @@ list(APPEND eckit_geo_srcs grid/Lambert.h grid/LambertAzimuthalEqualArea.cc grid/LambertAzimuthalEqualArea.h - grid/LatLon.cc - grid/LatLon.h grid/Mercator.cc grid/Mercator.h grid/None.cc @@ -67,26 +68,8 @@ list(APPEND eckit_geo_srcs grid/RegularGrid.h grid/RegularLL.cc grid/RegularLL.h - grid/RotatedClassic.cc - grid/RotatedClassic.h - grid/RotatedFromPL.cc - grid/RotatedFromPL.h - grid/RotatedGG.cc - grid/RotatedGG.h - grid/RotatedLL.cc - grid/RotatedLL.h - grid/RotatedOctahedral.cc - grid/RotatedOctahedral.h grid/SpaceView.cc grid/SpaceView.h - grid/StretchedGG.cc - grid/StretchedGG.h - grid/StretchedLL.cc - grid/StretchedLL.h - grid/StretchedRotatedGG.cc - grid/StretchedRotatedGG.h - grid/StretchedRotatedLL.cc - grid/StretchedRotatedLL.h grid/TransverseMercator.cc grid/TransverseMercator.h grid/UnstructuredGrid.cc diff --git a/src/eckit/geo/Domain.cc b/src/eckit/geo/Domain.cc index 2567a8c9f..b60a65a83 100644 --- a/src/eckit/geo/Domain.cc +++ b/src/eckit/geo/Domain.cc @@ -17,6 +17,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Point.h" +#include "eckit/geo/util.h" #include "eckit/geometry/Sphere.h" #include "eckit/types/FloatCompare.h" @@ -141,10 +142,8 @@ double Domain::area(double radius) const { double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); ASSERT(0. <= lonf && lonf <= 1.); - constexpr auto degrees_to_radians = M_PI / 180.; - - const auto sn = std::sin(north_ * degrees_to_radians); - const auto ss = std::sin(south_ * degrees_to_radians); + const auto sn = std::sin(north_ * util::degree_to_radian); + const auto ss = std::sin(south_ * util::degree_to_radian); double latf = 0.5 * (sn - ss); ASSERT(0. <= latf && latf <= 1.); diff --git a/src/eckit/geo/grid/StretchedLL.cc b/src/eckit/geo/Earth.h similarity index 50% rename from src/eckit/geo/grid/StretchedLL.cc rename to src/eckit/geo/Earth.h index 2186f507b..1999eea6c 100644 --- a/src/eckit/geo/grid/StretchedLL.cc +++ b/src/eckit/geo/Earth.h @@ -10,24 +10,30 @@ */ -#include "eckit/geo/grid/StretchedLL.h" +#pragma once -#include +#include "eckit/geometry/SphereT.h" -namespace eckit::geo::grid { +namespace eckit::geo { -StretchedLL::StretchedLL(const Configuration& /*config*/) {} +struct DatumIFS { + static constexpr double radius() { return 6371229.; } +}; -void StretchedLL::print(std::ostream& out) const { - out << "StretchedLL[" - << "]"; -} +struct DatumGRIB1 { + static constexpr double radius() { return 6367470.; } +}; -static const GridBuilder __repres("stretched_ll"); +struct DatumWGS84SemiMajorAxis { + static constexpr double radius() { return 6378137.; } +}; -} // namespace eckit::geo::grid +using Earth = eckit::geometry::SphereT; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 243364b9a..3c310ccbe 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -20,6 +20,7 @@ #include "eckit/geo/Domain.h" #include "eckit/geo/Iterator.h" #include "eckit/geo/grid/UnstructuredGrid.h" +#include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -40,74 +41,11 @@ bool Grid::isGlobal() const { } -bool Grid::isPeriodicWestEast() const { - std::ostringstream os; - os << "Grid::isPeriodicWestEast() not implemented for " << *this; - throw SeriousBug(os.str()); -} - - -bool Grid::includesNorthPole() const { - std::ostringstream os; - os << "Grid::includesNorthPole() not implemented for " << *this; - throw SeriousBug(os.str()); -} - - -bool Grid::includesSouthPole() const { - std::ostringstream os; - os << "Grid::includesSouthPole() not implemented for " << *this; - throw SeriousBug(os.str()); -} - - -const Grid* Grid::croppedGrid(const BoundingBox& /*unused*/) const { - std::ostringstream os; - os << "Grid::croppedGrid() not implemented for " << *this; - throw SeriousBug(os.str()); -} - - -bool Grid::sameAs(const Grid& /*unused*/) const { - std::ostringstream os; - os << "Grid::sameAs() not implemented for " << *this; - throw SeriousBug(os.str()); -} - - -bool Grid::crop(BoundingBox& /*unused*/, Renumber& /*unused*/) const { - std::ostringstream os; - os << "Grid::crop() not implemented for " << *this; - throw SeriousBug(os.str()); -} - - -size_t Grid::numberOfPoints() const { - std::ostringstream os; - os << "Grid::numberOfPoints() not implemented for " << *this; - throw SeriousBug(os.str()); -} - - -void Grid::reorder(long /*unused*/, MIRValuesVector& /*unused*/) const { - std::ostringstream os; - os << "Grid::reorder() not implemented for " << *this; - throw SeriousBug(os.str()); -} - - -Iterator* Grid::iterator() const { - std::ostringstream os; - os << "Grid::iterator() not implemented for " << *this; - throw SeriousBug(os.str()); -} - - Domain Grid::domain() const { - double n = includesNorthPole() ? NORTH_POLE : bbox_.north(); - double s = includesSouthPole() ? SOUTH_POLE : bbox_.south(); - double w = bbox_.west(); - double e = isPeriodicWestEast() ? bbox_.west() + GLOBE : bbox_.east(); + auto n = includesNorthPole() ? NORTH_POLE : bbox_.north(); + auto s = includesSouthPole() ? SOUTH_POLE : bbox_.south(); + auto w = bbox_.west(); + auto e = isPeriodicWestEast() ? bbox_.west() + GLOBE : bbox_.east(); return {n, w, s, e}; } @@ -157,8 +95,6 @@ const Grid* GridFactory::build(const Configuration& params) { throw SeriousBug("GridFactory: cannot get 'gridType'"); } - Log::debug() << "GridFactory: looking for '" << name << "'" << std::endl; - auto j = m->find(name); if (j == m->end()) { list(Log::error() << "GridFactory: unknown '" << name << "', choices are: "); diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 861ed502a..993849639 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -60,13 +60,11 @@ class Grid { virtual bool includesSouthPole() const; virtual bool isGlobal() const; virtual bool isPeriodicWestEast() const; - virtual bool sameAs(const Grid&) const; virtual const BoundingBox& boundingBox() const; - virtual const Grid* croppedGrid(const BoundingBox&) const; virtual size_t numberOfPoints() const; - virtual Domain domain() const; virtual void print(std::ostream&) const; virtual void reorder(long scanningMode) const; + virtual Domain domain() const; // -- Overridden methods // None @@ -99,7 +97,6 @@ class Grid { // -- Members BoundingBox bbox_; - mutable std::string uniqueName_; // -- Methods // None diff --git a/src/eckit/geo/grid/StretchedGG.cc b/src/eckit/geo/Increments.cc similarity index 54% rename from src/eckit/geo/grid/StretchedGG.cc rename to src/eckit/geo/Increments.cc index 26ec938a2..a4c63df2e 100644 --- a/src/eckit/geo/grid/StretchedGG.cc +++ b/src/eckit/geo/Increments.cc @@ -10,24 +10,18 @@ */ -#include "eckit/geo/grid/StretchedGG.h" +#include "eckit/geo/Increments.h" -#include +#include "eckit/config/Configuration.h" -namespace eckit::geo::grid { +namespace eckit::geo { -StretchedGG::StretchedGG(const Configuration& /*config*/) {} - - -void StretchedGG::print(std::ostream& out) const { - out << "StretchedGG[" - << "]"; +Increments::Increments(const Configuration& config) : + Increments(config.getDouble("west_east_increment"), config.getDouble("south_north_increment")) { } -static const GridBuilder __repres("stretched_gg"); - -} // namespace eckit::geo::grid +} // namespace eckit::geo diff --git a/src/eckit/geo/Increments.h b/src/eckit/geo/Increments.h new file mode 100644 index 000000000..2b1d9836b --- /dev/null +++ b/src/eckit/geo/Increments.h @@ -0,0 +1,54 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + + +namespace eckit { +class Configuration; +} + + +namespace eckit::geo { + + +class Increments : protected std::array { +private: + // -- Types + + using P = std::array; + +public: + // -- Constructors + + Increments(double west_east, double south_north) : + P{west_east, south_north} {}; + + Increments(const Configuration&); + + // -- Members + + double& west_east = P::operator[](0); + double& south_north = P::operator[](1); + + // -- Friends + + friend std::ostream& operator<<(std::ostream&out, const Increments&p) { + return out << '{' << p.west_east << ", " << p.south_north << '}'; + } +}; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Point.h b/src/eckit/geo/Point.h index 1bcba88ff..3390c15dc 100644 --- a/src/eckit/geo/Point.h +++ b/src/eckit/geo/Point.h @@ -39,6 +39,10 @@ constexpr double NORTH_POLE = 90.; constexpr double SOUTH_POLE = -90.; +using Longitude = double; +using Latitude = double; + + } // namespace eckit::geo diff --git a/src/eckit/geo/grid/Albers.h b/src/eckit/geo/grid/Albers.h index 5f5585e86..fcbdc73d3 100644 --- a/src/eckit/geo/grid/Albers.h +++ b/src/eckit/geo/grid/Albers.h @@ -12,13 +12,13 @@ #pragma once -#include "eckit/geo/Grid.h" +#include "eckit/geo/grid/RegularGrid.h" namespace eckit::geo::grid { -class Albers : public Grid { +class Albers : public RegularGrid { public: // -- Exceptions // None diff --git a/src/eckit/geo/grid/AzimuthRange.h b/src/eckit/geo/grid/AzimuthRange.h index 980940872..ddce73d16 100644 --- a/src/eckit/geo/grid/AzimuthRange.h +++ b/src/eckit/geo/grid/AzimuthRange.h @@ -12,13 +12,13 @@ #pragma once -#include "eckit/geo/Grid.h" +#include "eckit/geo/grid/RegularGrid.h" namespace eckit::geo::grid { -class AzimuthRange : public Grid { +class AzimuthRange : public RegularGridGrid { public: // -- Exceptions // None diff --git a/src/eckit/geo/grid/Classic.cc b/src/eckit/geo/grid/Classic.cc index e4cb5ec15..565264c28 100644 --- a/src/eckit/geo/grid/Classic.cc +++ b/src/eckit/geo/grid/Classic.cc @@ -34,10 +34,4 @@ Classic::Classic(size_t N, const BoundingBox& box, double angularPrecision) : } -bool Classic::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && Reduced::sameAs(other); -} - - } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Classic.h b/src/eckit/geo/grid/Classic.h index 7e30d1751..166779787 100644 --- a/src/eckit/geo/grid/Classic.h +++ b/src/eckit/geo/grid/Classic.h @@ -28,8 +28,7 @@ class Classic : public Reduced { Classic(size_t, const BoundingBox& = BoundingBox(), double angularPrecision = 0); // -- Destructor - - virtual ~Classic() override = default; + // None // -- Convertors // None @@ -49,23 +48,6 @@ class Classic : public Reduced { // -- Class methods // None -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - bool sameAs(const Grid&) const override; - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members // None diff --git a/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.h b/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.h index eb20674bc..4d3b8f750 100644 --- a/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.h +++ b/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.h @@ -12,13 +12,13 @@ #pragma once -#include "eckit/geo/Grid.h" +#include "eckit/geo/grid/RegularGrid.h" namespace eckit::geo::grid { -class EquatorialAzimuthalEquidistant : public Grid { +class EquatorialAzimuthalEquidistant : public RegularGrid { public: // -- Exceptions // None diff --git a/src/eckit/geo/grid/FromPL.cc b/src/eckit/geo/grid/FromPL.cc index b4c445664..0802cde1d 100644 --- a/src/eckit/geo/grid/FromPL.cc +++ b/src/eckit/geo/grid/FromPL.cc @@ -24,10 +24,4 @@ FromPL::FromPL(size_t N, const std::vector& pl, const BoundingBox& bbox, d Reduced(N, pl, bbox, angularPrecision) {} -bool FromPL::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && (pls() == o->pls()) && Reduced::sameAs(other); -} - - } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/FromPL.h b/src/eckit/geo/grid/FromPL.h index ffd781b2e..eac70faba 100644 --- a/src/eckit/geo/grid/FromPL.h +++ b/src/eckit/geo/grid/FromPL.h @@ -30,8 +30,7 @@ class FromPL : public Reduced { double angularPrecision = 0); // -- Destructor - - virtual ~FromPL() override = default; + // None // -- Convertors // None @@ -51,23 +50,6 @@ class FromPL : public Reduced { // -- Class methods // None -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - bool sameAs(const Grid&) const override; - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members // None diff --git a/src/eckit/geo/grid/Gaussian.cc b/src/eckit/geo/grid/Gaussian.cc index a81e8cccf..76a6bc43c 100644 --- a/src/eckit/geo/grid/Gaussian.cc +++ b/src/eckit/geo/grid/Gaussian.cc @@ -43,12 +43,6 @@ Gaussian::Gaussian(const Configuration& config) : Gaussian::~Gaussian() = default; -bool Gaussian::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && (N_ == o->N_) && (domain() == o->domain()); -} - - bool Gaussian::includesNorthPole() const { return bbox().north() >= latitudes().front(); } diff --git a/src/eckit/geo/grid/Gaussian.h b/src/eckit/geo/grid/Gaussian.h index 44cc7d5c0..4ccee2bec 100644 --- a/src/eckit/geo/grid/Gaussian.h +++ b/src/eckit/geo/grid/Gaussian.h @@ -66,7 +66,6 @@ class Gaussian : public Grid { // -- Overridden methods - bool sameAs(const Grid&) const override; bool includesNorthPole() const override; bool includesSouthPole() const override; diff --git a/src/eckit/geo/grid/GaussianIterator.h b/src/eckit/geo/grid/GaussianIterator.h index b47c922ba..cdd53685e 100644 --- a/src/eckit/geo/grid/GaussianIterator.h +++ b/src/eckit/geo/grid/GaussianIterator.h @@ -16,6 +16,7 @@ #include "eckit/types/Fraction.h" +#include "eckit/geo/BoundingBox.h" #include "eckit/geo/Iterator.h" diff --git a/src/eckit/geo/grid/IrregularLatlon.cc b/src/eckit/geo/grid/IrregularLatlon.cc index 2833becad..8dbca433d 100644 --- a/src/eckit/geo/grid/IrregularLatlon.cc +++ b/src/eckit/geo/grid/IrregularLatlon.cc @@ -24,7 +24,6 @@ namespace eckit::geo::grid { static void range(const std::vector& v, double& mn, double& mx, double& dmax) { - ASSERT(v.size() >= 2); dmax = 0; @@ -41,7 +40,6 @@ static void range(const std::vector& v, double& mn, double& mx, double& IrregularLatlon::IrregularLatlon(const Configuration& config) { - ASSERT(config.get("latitudes", latitudes_)); range(latitudes_, south_, north_, south_north_); @@ -50,12 +48,6 @@ IrregularLatlon::IrregularLatlon(const Configuration& config) { } -IrregularLatlon::IrregularLatlon() = default; - - -IrregularLatlon::~IrregularLatlon() = default; - - size_t IrregularLatlon::numberOfPoints() const { return latitudes_.size() * longitudes_.size(); } @@ -66,22 +58,6 @@ void IrregularLatlon::print(std::ostream& out) const { } -bool IrregularLatlon::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && (latitudes_ == o->latitudes_) && (longitudes_ == o->longitudes_); -} - - -Domain IrregularLatlon::domain() const { - const auto n = includesNorthPole() ? NORTH_POLE : north_; - const auto s = includesSouthPole() ? SOUTH_POLE : south_; - const auto w = west_; - const auto e = isPeriodicWestEast() ? west_ + GLOBE : east_; - - return {n, w, s, e}; -} - - class IrregularLatlonIterator : public Iterator { size_t i_; size_t ni_; diff --git a/src/eckit/geo/grid/IrregularLatlon.h b/src/eckit/geo/grid/IrregularLatlon.h index 53c7b9132..b59b6ada0 100644 --- a/src/eckit/geo/grid/IrregularLatlon.h +++ b/src/eckit/geo/grid/IrregularLatlon.h @@ -28,8 +28,7 @@ class IrregularLatlon : public Grid { IrregularLatlon(const Configuration&); // -- Destructor - - ~IrregularLatlon() override; + // None // -- Convertors // None @@ -66,8 +65,6 @@ class IrregularLatlon : public Grid { // None private: - IrregularLatlon(); - // -- Members double south_; @@ -87,8 +84,6 @@ class IrregularLatlon : public Grid { // -- Overridden methods size_t numberOfPoints() const override; - bool sameAs(const Grid&) const override; - Domain domain() const override; Iterator* iterator() const override; bool isPeriodicWestEast() const override; bool includesNorthPole() const override; diff --git a/src/eckit/geo/grid/Lambert.cc b/src/eckit/geo/grid/Lambert.cc index dad114788..681b76eef 100644 --- a/src/eckit/geo/grid/Lambert.cc +++ b/src/eckit/geo/grid/Lambert.cc @@ -12,6 +12,8 @@ #include "eckit/geo/grid/Lambert.h" +#include "eckit/config/MappedConfiguration.h" + namespace eckit::geo::grid { @@ -19,41 +21,38 @@ namespace eckit::geo::grid { static const GridBuilder __builder("lambert"); -Lambert::Lambert(const Configuration& param) : - RegularGrid(param, make_projection(param)) { - long edition = 0; - param.get("edition", edition); +Lambert::Lambert(const Configuration& config) : + RegularGrid(config, make_projection(config)) { + auto edition = config.getLong("edition", 0); // GRIB1 cannot write LaD writeLaDInDegrees_ = edition == 2; - param.get("writeLaDInDegrees", writeLaDInDegrees_); + config.get("writeLaDInDegrees", writeLaDInDegrees_); // GRIB2 cannot write negative longitude values writeLonPositive_ = edition == 2; - param.get("writeLonPositive", writeLonPositive_); + config.get("writeLonPositive", writeLonPositive_); } -Projection Lambert::make_projection(const Configuration& param) { - auto spec = make_proj_spec(param); +Projection* Lambert::make_projection(const Configuration& config) { +#if 0 + auto spec = make_proj_spec(config); if (!spec.empty()) { return spec; } - - double LaDInDegrees; - double LoVInDegrees; - double Latin1InDegrees; - double Latin2InDegrees; - ASSERT(param.get("LaDInDegrees", LaDInDegrees)); - ASSERT(param.get("LoVInDegrees", LoVInDegrees)); - param.get("Latin1InDegrees", Latin1InDegrees = LaDInDegrees); - param.get("Latin2InDegrees", Latin2InDegrees = LaDInDegrees); - - return Configuration("type", "lambert_conformal_conic") - .set("latitude1", Latin1InDegrees) - .set("latitude2", Latin2InDegrees) - .set("latitude0", LaDInDegrees) - .set("longitude0", LoVInDegrees); +#endif + + auto LaDInDegrees = config.getDouble("LaDInDegrees"); + auto LoVInDegrees = config.getDouble("LoVInDegrees"); + auto Latin1InDegrees = config.getDouble("Latin1InDegrees", LaDInDegrees); + auto Latin2InDegrees = config.getDouble("Latin2InDegrees", LaDInDegrees); + + return ProjectionFactory::build("lambert_conformal_conic", + MappedConfiguration({{"latitude1", Latin1InDegrees}, + {"latitude2", Latin2InDegrees}, + {"latitude0", LaDInDegrees}, + {"longitude0", LoVInDegrees}})); } diff --git a/src/eckit/geo/grid/Lambert.h b/src/eckit/geo/grid/Lambert.h index f6ad62b3b..0552731b2 100644 --- a/src/eckit/geo/grid/Lambert.h +++ b/src/eckit/geo/grid/Lambert.h @@ -58,7 +58,7 @@ class Lambert : public RegularGrid { // -- Methods - static Projection make_projection(const Configuration&); + static Projection* make_projection(const Configuration&); // -- Overridden methods // None diff --git a/src/eckit/geo/grid/LambertAzimuthalEqualArea.cc b/src/eckit/geo/grid/LambertAzimuthalEqualArea.cc index 493c0ad25..677ed6d28 100644 --- a/src/eckit/geo/grid/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/grid/LambertAzimuthalEqualArea.cc @@ -53,30 +53,4 @@ Projection LambertAzimuthalEqualArea::make_projection(const Configuration& param } -const Grid* LambertAzimuthalEqualArea::croppedGrid(const BoundingBox& bbox) const { - auto mm = minmax_ij(bbox); - auto Ni = x_.size(); - - auto projection = grid_.projection(); - ASSERT(projection); - - auto first = [this, projection, Ni](size_t firsti, size_t firstj) -> Point2 { - for (std::unique_ptr it(iterator()); it->next();) { - auto i = it->index() % Ni; - auto j = it->index() / Ni; - if (i == firsti && j == firstj) { - const auto& latlon = *(*it); - return projection.xy(PointLonLat{latlon[1], latlon[0]}); - } - } - throw UserError("LambertAzimuthalEqualArea::croppedGrid: cannot find first point"); - }(mm.first.i, mm.first.j); - - auto x = linspace(first.x(), std::abs(x_.step()), long(mm.second.i - mm.first.i + 1), xPlus_); - auto y = linspace(first.y(), std::abs(y_.step()), long(mm.second.j - mm.first.j + 1), yPlus_); - - return new LambertAzimuthalEqualArea(projection, bbox, x, y, shape_); -} - - } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/LambertAzimuthalEqualArea.h b/src/eckit/geo/grid/LambertAzimuthalEqualArea.h index e55a7b8f4..803d12ddc 100644 --- a/src/eckit/geo/grid/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/grid/LambertAzimuthalEqualArea.h @@ -61,8 +61,7 @@ class LambertAzimuthalEqualArea : public RegularGrid { static Projection make_projection(const Configuration&); // -- Overridden methods - - const Grid* croppedGrid(const BoundingBox&) const override; + // None // -- Class members // None diff --git a/src/eckit/geo/grid/LatLon.cc b/src/eckit/geo/grid/LatLon.cc deleted file mode 100644 index 3c6708ded..000000000 --- a/src/eckit/geo/grid/LatLon.cc +++ /dev/null @@ -1,211 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/LatLon.h" - -#include -#include -#include - -#include "eckit/types/FloatCompare.h" -#include "eckit/types/Fraction.h" - - -namespace eckit::geo::grid { - - -LatLon::LatLon(const Configuration& config) : - Grid(config), increments_(parametrisation), reference_(bbox_.south(), bbox_.west()), ni_(0), nj_(0) { - correctBoundingBox(bbox_, ni_, nj_, increments_, reference_); - ASSERT(ni_ != 0); - ASSERT(nj_ != 0); - - // confirm Ni/Nj from config (input) - size_t ni = 0; - size_t nj = 0; - ASSERT(config.get("Ni", ni)); - ASSERT(config.get("Nj", nj)); - - Log::debug() << "LatLon:" - "\n\t" - "(Ni, Nj) = (" - << ni_ << ", " << nj_ - << ") calculated" - "\n\t" - "(Ni, Nj) = (" - << ni << ", " << nj << ") from config" << std::endl; - - ASSERT(ni == ni_); - ASSERT(nj == nj_); -} - - -LatLon::LatLon(const Increments& increments, const BoundingBox& bbox, const PointLonLat& reference) : - Grid(bbox), increments_(increments), reference_(reference), ni_(0), nj_(0) { - correctBoundingBox(bbox_, ni_, nj_, increments_, reference_); - ASSERT(ni_ != 0); - ASSERT(nj_ != 0); -} - - -LatLon::~LatLon() = default; - - -void LatLon::reorder(long scanningMode) const { - grib_reorder(values, scanningMode, ni_, nj_); -} - - -void LatLon::print(std::ostream& out) const { - out << "LatLon[" - << "bbox=" << bbox_ << ",increments=" << increments_ << ",ni=" << ni_ << ",nj=" << nj_ << "]"; -} - - -bool LatLon::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && (bbox_ == o->bbox_) && (increments_ == o->increments_); -} - - -bool LatLon::isPeriodicWestEast() const { - - // if range West-East is within one increment (or greater than) 360 degree - double inc = increments_.west_east().longitude(); - return bbox_.east() - bbox_.west() + inc >= GLOBE; -} - - -bool LatLon::includesNorthPole() const { - - // if North latitude is within one increment from North Pole - double inc = increments_.south_north().latitude(); - return bbox_.north() + inc > NORTH_POLE; -} - - -bool LatLon::includesSouthPole() const { - - // if South latitude is within one increment from South Pole - double inc = increments_.south_north().latitude(); - return bbox_.south() - inc < SOUTH_POLE; -} - - -size_t LatLon::numberOfPoints() const { - ASSERT(ni_); - ASSERT(nj_); - return ni_ * nj_; -} - - -const LatLon* LatLon::croppedGrid(const BoundingBox& /*unused*/) const { - std::ostringstream os; - os << "LatLon::croppedGrid() not implemented for " << *this; - throw SeriousBug(os.str()); -} - - -LatLon::LatLonIterator::LatLonIterator(size_t ni, size_t nj, Latitude north, Longitude west, - const Increments& increments) : - ni_(ni), - nj_(nj), - north_(north.fraction()), - west_(west.fraction()), - we_(increments.west_east().longitude().fraction()), - ns_(increments.south_north().latitude().fraction()), - i_(0), - j_(0), - count_(0), - first_(true) { - lat_ = north_; - lon_ = west_; - latValue_ = lat_; - lonValue_ = lon_; -} - - -LatLon::LatLonIterator::~LatLonIterator() { - auto count = count_ + (i_ > 0 || j_ > 0 ? 1 : 0); - ASSERT(count == ni_ * nj_); -} - - -void LatLon::LatLonIterator::print(std::ostream& out) const { - out << "LatLonIterator[" - << "ni=" << ni_ << ",nj=" << nj_ << ",north=" << north_ << ",west=" << west_ << ",we=" << we_ << ",ns=" << ns_ - << ",i=" << i_ << ",j=" << j_ << ",count=" << count_ << "]"; -} - - -bool LatLon::LatLonIterator::next(double& lat, double& lon) { - if (j_ < nj_) { - if (i_ < ni_) { - lat = latValue_; - lon = lonValue_; - - lon_ += we_; - - if (first_) { - first_ = false; - } - else { - count_++; - } - - if (++i_ == ni_) { - j_++; - i_ = 0; - lat_ -= ns_; - lon_ = west_; - latValue_ = lat_; - } - - lonValue_ = lon_; - - return true; - } - } - return false; -} - - -void LatLon::correctBoundingBox(BoundingBox& bbox, size_t& ni, size_t& nj, const Increments& inc, - const PointLonLat& reference) { - using iterator::detail::RegularIterator; - - // Latitude/longitude ranges - RegularIterator lat{bbox.south().fraction(), bbox.north().fraction(), inc.south_north().latitude().fraction(), - reference.lat().fraction()}; - auto n = lat.b(); - auto s = lat.a(); - - nj = lat.n(); - ASSERT(nj > 0); - - RegularIterator lon{bbox.west().fraction(), bbox.east().fraction(), inc.west_east().longitude().fraction(), - reference.lon().fraction(), GLOBE.fraction()}; - auto w = lon.a(); - auto e = lon.b(); - - ni = lon.n(); - ASSERT(ni > 0); - - // checks - ASSERT(w + (ni - 1) * lon.inc() == e || ni * lon.inc() == GLOBE.fraction()); - ASSERT(s + (nj - 1) * lat.inc() == n); - - bbox = {n, w, s, e}; -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/LatLon.h b/src/eckit/geo/grid/LatLon.h deleted file mode 100644 index 3add6549c..000000000 --- a/src/eckit/geo/grid/LatLon.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Grid.h" -#include "eckit/types/Fraction.h" - - -namespace eckit::geo::grid { - - -class LatLon : public Grid { -public: - // -- Exceptions - // None - - // -- Constructors - - LatLon(const Configuration&); - LatLon(const Increments&, const BoundingBox& = {}, const PointLonLat& reference = {0, 0}); - - // -- Destructor - - ~LatLon() override; - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - size_t Ni() const { return ni_; } - - size_t Nj() const { return nj_; } - - static void correctBoundingBox(BoundingBox&, size_t& ni, size_t& nj, const Increments&, - const PointLonLat& reference = {0, 0}); - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - - const Increments increments_; - const PointLonLat reference_; - size_t ni_; - size_t nj_; - - // -- Methods - // None - - // -- Overridden methods - - void print(std::ostream&) const override; - - bool sameAs(const Grid&) const override; - - bool isPeriodicWestEast() const override; - bool includesNorthPole() const override; - bool includesSouthPole() const override; - - size_t numberOfPoints() const override; - - // -- Class members - - class LatLonIterator { - size_t ni_; - size_t nj_; - Fraction north_; - Fraction west_; - Fraction we_; - Fraction ns_; - size_t i_; - size_t j_; - Latitude latValue_; - Longitude lonValue_; - Fraction lat_; - Fraction lon_; - - protected: - size_t count_; - bool first_; - - ~LatLonIterator(); - void print(std::ostream&) const; - bool next(double&, double&); - - public: - LatLonIterator(size_t ni, size_t nj, Latitude north, Longitude west, const Increments& increments); - }; - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - void reorder(long scanningMode) const override; - - const LatLon* croppedGrid(const BoundingBox&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/None.h b/src/eckit/geo/grid/None.h index 91e46d1d4..21852e240 100644 --- a/src/eckit/geo/grid/None.h +++ b/src/eckit/geo/grid/None.h @@ -61,7 +61,6 @@ class None : public Grid { // -- Overridden methods - // from Grid void print(std::ostream&) const override; // -- Class members diff --git a/src/eckit/geo/grid/ORCA.cc b/src/eckit/geo/grid/ORCA.cc index e19d7efad..80dcbd341 100644 --- a/src/eckit/geo/grid/ORCA.cc +++ b/src/eckit/geo/grid/ORCA.cc @@ -22,7 +22,7 @@ namespace eckit::geo::grid { -// order is important for makeName() +// order is important static const std::vector> grib_keys{ {"orca_name", "unstructuredGridType"}, {"orca_arrangement", "unstructuredGridSubtype"}, {"uid", "uuidOfHGrid"}}; @@ -42,26 +42,11 @@ ORCA::ORCA(const Configuration& param) : ORCA::~ORCA() = default; -bool ORCA::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && spec_.getString("uid") == o->spec_.getString("uid"); -} - - size_t ORCA::numberOfPoints() const { return static_cast(atlasGridRef().size()); } -// void ORCA::makeName(std::ostream& out) const { -// const auto* sep = ""; -// for (const auto& key : grib_keys) { -// out << sep << spec_.getString(key.first); -// sep = "_"; -// } -// } - - void ORCA::print(std::ostream& out) const { out << "ORCA[spec=" << spec_ << "]"; } @@ -133,4 +118,20 @@ const atlas::Grid& ORCA::atlasGridRef() const { } +#if 0 +Grid* GridBuilder::make(const Configuration& config) { + + // specially-named unstructured grids + std::string grid; + if (config.get("grid", grid)) { + if (!key::grid::ORCAPattern::match(grid, config).empty()) { + return new other::ORCA(config); + } + } + + return new UnstructuredGrid(config); +} +#endif + + } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ORCA.h b/src/eckit/geo/grid/ORCA.h index b029c9ee8..6e572d8ee 100644 --- a/src/eckit/geo/grid/ORCA.h +++ b/src/eckit/geo/grid/ORCA.h @@ -63,7 +63,6 @@ class ORCA : public Grid { // -- Overridden methods - // from Grid void print(std::ostream&) const override; // -- Class members @@ -81,8 +80,6 @@ class ORCA : public Grid { // -- Overridden methods - // from Grid - bool sameAs(const Grid&) const override; size_t numberOfPoints() const override; bool includesNorthPole() const override { return true; } diff --git a/src/eckit/geo/grid/Octahedral.cc b/src/eckit/geo/grid/Octahedral.cc index ebce13dda..a9956178e 100644 --- a/src/eckit/geo/grid/Octahedral.cc +++ b/src/eckit/geo/grid/Octahedral.cc @@ -34,10 +34,4 @@ Octahedral::Octahedral(size_t N, const BoundingBox& box, double angularPrecision } -bool Octahedral::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && Reduced::sameAs(other); -} - - } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Octahedral.h b/src/eckit/geo/grid/Octahedral.h index 7bb187a9e..23f70f748 100644 --- a/src/eckit/geo/grid/Octahedral.h +++ b/src/eckit/geo/grid/Octahedral.h @@ -49,23 +49,6 @@ class Octahedral : public Reduced { // -- Class methods // None -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - bool sameAs(const Grid&) const override; - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members // None diff --git a/src/eckit/geo/grid/Reduced.cc b/src/eckit/geo/grid/Reduced.cc index a39ad59b1..9244a44f2 100644 --- a/src/eckit/geo/grid/Reduced.cc +++ b/src/eckit/geo/grid/Reduced.cc @@ -166,12 +166,6 @@ void Reduced::correctWestEast(double& w, double& e) const { } -bool Reduced::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && Gaussian::sameAs(other); -} - - Iterator* Reduced::unrotatedIterator() const { auto pl = pls(); return new GaussianIterator(latitudes(), std::move(pl), bbox(), N_, Nj_, k_); diff --git a/src/eckit/geo/grid/Reduced.h b/src/eckit/geo/grid/Reduced.h index 0fd70e106..ead9d0733 100644 --- a/src/eckit/geo/grid/Reduced.h +++ b/src/eckit/geo/grid/Reduced.h @@ -71,9 +71,6 @@ class Reduced : public Gaussian { // -- Overridden methods - bool sameAs(const Grid&) const override; - - // from Grid bool isPeriodicWestEast() const override; // -- Class members diff --git a/src/eckit/geo/grid/ReducedClassic.cc b/src/eckit/geo/grid/ReducedClassic.cc index 43a206bc4..7dfc8e095 100644 --- a/src/eckit/geo/grid/ReducedClassic.cc +++ b/src/eckit/geo/grid/ReducedClassic.cc @@ -32,15 +32,4 @@ Iterator* ReducedClassic::iterator() const { } -const Grid* ReducedClassic::croppedGrid(const BoundingBox& bbox) const { - return new ReducedClassic(N_, bbox, angularPrecision_); -} - - -bool ReducedClassic::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && Classic::sameAs(other); -} - - } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedClassic.h b/src/eckit/geo/grid/ReducedClassic.h index 7e6c3bc55..7f8557a53 100644 --- a/src/eckit/geo/grid/ReducedClassic.h +++ b/src/eckit/geo/grid/ReducedClassic.h @@ -75,8 +75,6 @@ class ReducedClassic : public Classic { // -- Overridden methods Iterator* iterator() const override; - const Grid* croppedGrid(const BoundingBox&) const override; - bool sameAs(const Grid&) const override; // -- Class members // None diff --git a/src/eckit/geo/grid/ReducedFromPL.cc b/src/eckit/geo/grid/ReducedFromPL.cc index d6f0f1e9d..d7197e0c6 100644 --- a/src/eckit/geo/grid/ReducedFromPL.cc +++ b/src/eckit/geo/grid/ReducedFromPL.cc @@ -37,17 +37,6 @@ Iterator* ReducedFromPL::iterator() const { } -const Grid* ReducedFromPL::croppedGrid(const BoundingBox& bbox) const { - return new ReducedFromPL(N_, pls(), bbox, angularPrecision_); -} - - -bool ReducedFromPL::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && FromPL::sameAs(other); -} - - static const GridBuilder reducedFromPL("reduced_gg"); diff --git a/src/eckit/geo/grid/ReducedFromPL.h b/src/eckit/geo/grid/ReducedFromPL.h index ac0c52564..260ee374c 100644 --- a/src/eckit/geo/grid/ReducedFromPL.h +++ b/src/eckit/geo/grid/ReducedFromPL.h @@ -77,8 +77,6 @@ class ReducedFromPL : public FromPL { // -- Overridden methods Iterator* iterator() const override; - const Grid* croppedGrid(const BoundingBox&) const override; - bool sameAs(const Grid&) const override; // -- Class members // None diff --git a/src/eckit/geo/grid/ReducedLL.cc b/src/eckit/geo/grid/ReducedLL.cc index 5cc323fe2..5fd525c0e 100644 --- a/src/eckit/geo/grid/ReducedLL.cc +++ b/src/eckit/geo/grid/ReducedLL.cc @@ -53,11 +53,6 @@ size_t ReducedLL::numberOfPoints() const { return total; } -bool ReducedLL::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && (bbox() == o->bbox()) && (pl_ == o->pl_); -} - bool ReducedLL::isPeriodicWestEast() const { ASSERT(!pl_.empty()); @@ -173,13 +168,6 @@ Iterator* ReducedLL::iterator() const { } -const Grid* mir::repres::latlon::ReducedLL::croppedGrid(const BoundingBox&) const { - std::ostringstream os; - os << "ReducedLL::croppedGrid() not supported for " << *this; - throw FunctionalityNotSupported(os.str()); -} - - static const GridBuilder reducedLL("reduced_ll"); diff --git a/src/eckit/geo/grid/ReducedLL.h b/src/eckit/geo/grid/ReducedLL.h index 3607477bf..743a08786 100644 --- a/src/eckit/geo/grid/ReducedLL.h +++ b/src/eckit/geo/grid/ReducedLL.h @@ -81,11 +81,8 @@ class ReducedLL : public Grid { // -- Overridden methods Iterator* iterator() const override; - bool sameAs(const Grid&) const override; - size_t numberOfPoints() const override; - // From Grid - const Grid* croppedGrid(const BoundingBox&) const override; + size_t numberOfPoints() const override; // -- Class members // None diff --git a/src/eckit/geo/grid/ReducedOctahedral.cc b/src/eckit/geo/grid/ReducedOctahedral.cc index f691e7129..97a130333 100644 --- a/src/eckit/geo/grid/ReducedOctahedral.cc +++ b/src/eckit/geo/grid/ReducedOctahedral.cc @@ -32,15 +32,4 @@ Iterator* ReducedOctahedral::iterator() const { } -const Grid* ReducedOctahedral::croppedGrid(const BoundingBox& bbox) const { - return new ReducedOctahedral(N_, bbox, angularPrecision_); -} - - -bool ReducedOctahedral::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && Octahedral::sameAs(other); -} - - } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedOctahedral.h b/src/eckit/geo/grid/ReducedOctahedral.h index 3b50473e4..63614e244 100644 --- a/src/eckit/geo/grid/ReducedOctahedral.h +++ b/src/eckit/geo/grid/ReducedOctahedral.h @@ -75,8 +75,6 @@ class ReducedOctahedral : public Octahedral { // -- Overridden methods Iterator* iterator() const override; - const Grid* croppedGrid(const BoundingBox&) const override; - bool sameAs(const Grid&) const override; // -- Class members // None diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index f15d4974d..e78e9eeea 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -18,6 +18,7 @@ namespace eckit::geo::grid { + Regular::Regular(const Configuration& config) : Gaussian(config), k_(0), Ni_(0), Nj_(0) { // adjust latitudes, longitudes and re-set bounding box @@ -34,6 +35,7 @@ Regular::Regular(const Configuration& config) : setNiNj(); } + Regular::Regular(size_t N, const BoundingBox& box, double angularPrecision) : Gaussian(N, box, angularPrecision), k_(0), Ni_(0), Nj_(0) { @@ -51,6 +53,7 @@ Regular::Regular(size_t N, const BoundingBox& box, double angularPrecision) : setNiNj(); } + void Regular::correctWestEast(double& w, double& e) const { ASSERT(w <= e); @@ -58,74 +61,69 @@ void Regular::correctWestEast(double& w, double& e) const { ASSERT(inc > 0); if (angleApproximatelyEqual(GREENWICH, w) && (angleApproximatelyEqual(GLOBE - inc, e - w) || GLOBE - inc < e - w || (e != w && e.normalise(w) == w))) { - w = GREENWICH; e = GLOBE - inc; + return; } - else { - const Fraction west = w; - const Fraction east = e; + const Fraction west = w; + const Fraction east = e; - Fraction::value_type Nw = (west / inc).integralPart(); - if (Nw * inc < west) { - Nw += 1; - } - - Fraction::value_type Ne = (east / inc).integralPart(); - if (Ne * inc > east) { - Ne -= 1; - } + Fraction::value_type Nw = (west / inc).integralPart(); + if (Nw * inc < west) { + Nw += 1; + } - ASSERT(Nw <= Ne); - w = Nw * inc; - e = Ne * inc; + Fraction::value_type Ne = (east / inc).integralPart(); + if (Ne * inc > east) { + Ne -= 1; } -} -bool Regular::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && (N_ == o->N_) && (bbox() == o->bbox()); + ASSERT(Nw <= Ne); + w = Nw * inc; + e = Ne * inc; } + eckit::Fraction Regular::getSmallestIncrement() const { ASSERT(N_); return {90, Fraction::value_type(N_)}; } + size_t Regular::numberOfPoints() const { ASSERT(Ni_); ASSERT(Nj_); return Ni_ * Nj_; } + bool Regular::isPeriodicWestEast() const { auto inc = getSmallestIncrement(); return bbox().east() - bbox().west() + inc >= GLOBE; } + void Regular::setNiNj() { ASSERT(N_); const auto inc = getSmallestIncrement(); const auto& lats = latitudes(); - double west = bbox().west(); - double east = bbox().east(); - double south = bbox().south(); - double north = bbox().north(); + Fraction w(bbox().west()); + Fraction e(bbox().east()); + Fraction s(bbox().south()); + Fraction n(bbox().north()); Ni_ = N_ * 4; - if (east - west + inc < GLOBE) { + if (e - w + inc < GLOBE) { - auto w = west.fraction(); auto Nw = (w / inc).integralPart(); if (Nw * inc < w) { Nw += 1; } - auto e = east.fraction(); auto Ne = (e / inc).integralPart(); if (Ne * inc > e) { Ne -= 1; @@ -140,13 +138,13 @@ void Regular::setNiNj() { k_ = 0; Nj_ = N_ * 2; - if (north < lats.front() || south > lats.back()) { + if (n < lats.front() || s > lats.back()) { Nj_ = 0; for (auto lat : lats) { - if (north < lat && !angleApproximatelyEqual(north, lat)) { + if (n < lat && !angleApproximatelyEqual(n, lat)) { ++k_; } - else if (south <= lat || angleApproximatelyEqual(south, lat)) { + else if (s <= lat || angleApproximatelyEqual(s, lat)) { ++Nj_; } else { @@ -155,8 +153,7 @@ void Regular::setNiNj() { } ASSERT(Nj_ > 0); } - - Log::debug() << "Regular::setNiNj: Ni*Nj = " << Ni_ << " * " << Nj_ << " = " << (Ni_ * Nj_) << std::endl; } + } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index 165485570..c040ae665 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -67,9 +67,6 @@ class Regular : public Gaussian { // -- Overridden methods - bool sameAs(const Grid&) const override; - - // from Grid bool isPeriodicWestEast() const override; // -- Class members diff --git a/src/eckit/geo/grid/RegularGG.cc b/src/eckit/geo/grid/RegularGG.cc index 89873e771..f35489f1d 100644 --- a/src/eckit/geo/grid/RegularGG.cc +++ b/src/eckit/geo/grid/RegularGG.cc @@ -37,28 +37,12 @@ void RegularGG::print(std::ostream& out) const { } -bool RegularGG::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && Regular::sameAs(other); -} - - Iterator* RegularGG::iterator() const { std::vector pl(N_ * 2, long(4 * N_)); return new GaussianIterator(latitudes(), std::move(pl), bbox(), N_, Nj_, k_); } -const Grid* RegularGG::croppedGrid(const BoundingBox& bbox) const { - return new RegularGG(N_, bbox, angularPrecision_); -} - - -std::string RegularGG::factory() const { - return "regular_gg"; -} - - static const GridBuilder reducedGG("regular_gg"); diff --git a/src/eckit/geo/grid/RegularGG.h b/src/eckit/geo/grid/RegularGG.h index d27f5e80d..55ad2dd82 100644 --- a/src/eckit/geo/grid/RegularGG.h +++ b/src/eckit/geo/grid/RegularGG.h @@ -48,23 +48,6 @@ class RegularGG : public Regular { // -- Class methods // None -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members // None @@ -74,10 +57,8 @@ class RegularGG : public Regular { // -- Overridden methods - const Grid* croppedGrid(const BoundingBox&) const override; - bool sameAs(const Grid&) const override; + void print(std::ostream&) const override; Iterator* iterator() const override; - std::string factory() const override; // -- Class members // None diff --git a/src/eckit/geo/grid/RegularGrid.cc b/src/eckit/geo/grid/RegularGrid.cc index e080c38e7..e13661560 100644 --- a/src/eckit/geo/grid/RegularGrid.cc +++ b/src/eckit/geo/grid/RegularGrid.cc @@ -230,16 +230,4 @@ Iterator* RegularGrid::iterator() const { } -bool RegularGrid::sameAs(const Grid& other) const { - auto name = [](const RegularGrid& repres) { - std::ostringstream str; - // repres.makeName(str); - return str.str(); - }; - - const auto* o = dynamic_cast(&other); - return (o != nullptr) && name(*this) == name(*o); -} - - } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularGrid.h b/src/eckit/geo/grid/RegularGrid.h index 09412ab9c..76336f6ed 100644 --- a/src/eckit/geo/grid/RegularGrid.h +++ b/src/eckit/geo/grid/RegularGrid.h @@ -81,9 +81,6 @@ class RegularGrid : public Grid { // -- Overridden methods - // from Grid - bool sameAs(const Grid&) const override; - bool includesNorthPole() const override; bool includesSouthPole() const override; bool isPeriodicWestEast() const override; diff --git a/src/eckit/geo/grid/RegularLL.cc b/src/eckit/geo/grid/RegularLL.cc index a343b8052..63ba4c65b 100644 --- a/src/eckit/geo/grid/RegularLL.cc +++ b/src/eckit/geo/grid/RegularLL.cc @@ -12,60 +12,288 @@ #include "eckit/geo/grid/RegularLL.h" +#include #include +#include +#include "eckit/exception/Exceptions.h" #include "eckit/geo/Iterator.h" +#include "eckit/geo/Point.h" +#include "eckit/geo/grid/RegularLL.h" +#include "eckit/types/FloatCompare.h" +#include "eckit/types/Fraction.h" namespace eckit::geo::grid { -RegularLL::RegularLL(const Configuration& config) : - LatLon(config) {} -RegularLL::RegularLL(const Increments& increments, const BoundingBox& bbox, const PointLonLat& reference) : - LatLon(increments, bbox, reference) {} +namespace detail { -RegularLL::~RegularLL() = default; -Iterator* RegularLL::iterator() const { - class RegularLLIterator : protected LatLonIterator, public Iterator { - void print(std::ostream& out) const override { - out << "RegularLLIterator["; - Iterator::print(out); - out << ","; - LatLonIterator::print(out); - out << "]"; + +class RegularIterator { +public: + RegularIterator(const Fraction& a, const Fraction& b, const Fraction& inc, const Fraction& ref); + RegularIterator(const Fraction& a, const Fraction& b, const Fraction& inc, const Fraction& ref, const Fraction& period); + + static Fraction adjust(const Fraction& target, const Fraction& inc, bool up) { + ASSERT(inc > 0); + + auto r = target / inc; + auto n = r.integralPart(); + + if (!r.integer() && (r > 0) == up) { + n += (up ? 1 : -1); } - bool next(double& lat, double& lon) override { return LatLonIterator::next(lat, lon); } - size_t index() const override { return count_; } + return (n * inc); + } + + const Fraction& a() const { return a_; } + const Fraction& b() const { return b_; } + const Fraction& inc() const { return inc_; } + size_t n() const { return n_; } + +private: + Fraction a_; + Fraction b_; + Fraction inc_; + size_t n_; +}; + + +RegularIterator::RegularIterator(const Fraction& a, const Fraction& b, const Fraction& inc, + const Fraction& ref) : + inc_(inc) { + ASSERT(a <= b); + ASSERT(inc >= 0); + + if (inc_ == 0) { + + b_ = a_ = a; + n_ = 1; + } + else { + + auto shift = (ref / inc_).decimalPart() * inc; + a_ = shift + adjust(a - shift, inc_, true); + + if (b == a) { + b_ = a_; + } + else { + + auto c = shift + adjust(b - shift, inc_, false); + c = a_ + ((c - a_) / inc_).integralPart() * inc_; + b_ = c < a_ ? a_ : c; + } + + n_ = size_t(((b_ - a_) / inc_).integralPart() + 1); + } + ASSERT(a_ <= b_); + ASSERT(n_ >= 1); +} + + +RegularIterator::RegularIterator(const Fraction& a, const Fraction& b, const Fraction& inc, + const Fraction& ref, const Fraction& period) : + RegularIterator(a, b, inc, ref) { + ASSERT(period > 0); + + if ((n_ - 1) * inc_ >= period) { + n_ -= 1; + ASSERT(n_ * inc_ == period || (n_ - 1) * inc_ < period); + + b_ = a_ + (n_ - 1) * inc_; + } +} + + +} // namespace detail + + +RegularLL::RegularLL(const Configuration& config) : + Grid(config), increments_(config), reference_(bbox().south(), bbox().west()), ni_(0), nj_(0) { + bbox(correctBoundingBox(bbox(), ni_, nj_, increments_, reference_)); + ASSERT(ni_ != 0); + ASSERT(nj_ != 0); + + // confirm Ni/Nj from config (input) + size_t ni = 0; + size_t nj = 0; + ASSERT(config.get("Ni", ni)); + ASSERT(config.get("Nj", nj)); + + ASSERT(ni == ni_); + ASSERT(nj == nj_); +} + + +RegularLL::RegularLL(const Increments& increments, const BoundingBox& bb, const PointLonLat& reference) : + Grid(bb), increments_(increments), reference_(reference), ni_(0), nj_(0) { + bbox(correctBoundingBox(bbox(), ni_, nj_, increments_, reference_)); + ASSERT(ni_ != 0); + ASSERT(nj_ != 0); +} + + +RegularLL::~RegularLL() = default; - public: - RegularLLIterator(size_t ni, size_t nj, Latitude north, Longitude west, const Increments& increments) : - LatLonIterator(ni, nj, north, west, increments) {} - }; - return new RegularLLIterator(ni_, nj_, bbox_.north(), bbox_.west(), increments_); +void RegularLL::reorder(long scanningMode) const { + grib_reorder(values, scanningMode, ni_, nj_); } + void RegularLL::print(std::ostream& out) const { - out << "RegularLL["; - LatLon::print(out); - out << "]"; + out << "RegularLL[" + << "bbox=" << bbox() << ",increments=" << increments_ << ",ni=" << ni_ << ",nj=" << nj_ << "]"; +} + + +bool RegularLL::isPeriodicWestEast() const { + + // if range West-East is within one increment (or greater than) 360 degree + double inc = increments_.west_east().longitude(); + return bbox().east() - bbox().west() + inc >= GLOBE; +} + + +bool RegularLL::includesNorthPole() const { + + // if North latitude is within one increment from North Pole + double inc = increments_.south_north().latitude(); + return bbox().north() + inc > NORTH_POLE; } -bool RegularLL::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && LatLon::sameAs(other); + +bool RegularLL::includesSouthPole() const { + + // if South latitude is within one increment from South Pole + auto inc = increments_.south_north; + return bbox().south() - inc < SOUTH_POLE; } -const RegularLL* RegularLL::croppedGrid(const BoundingBox& bbox) const { - return new RegularLL(increments_, bbox, reference_); + +size_t RegularLL::numberOfPoints() const { + ASSERT(ni_); + ASSERT(nj_); + return ni_ * nj_; } -std::string RegularLL::factory() const { - return "regular_ll"; + +BoundingBox RegularLL::correctBoundingBox(const BoundingBox& bbox, size_t& ni, size_t& nj, const Increments& inc, + const PointLonLat& reference) { + // Latitude/longitude ranges + detail::RegularIterator lat{bbox.south(), bbox.north(), inc.south_north(), + reference.lat}; + auto n = lat.b(); + auto s = lat.a(); + + nj = lat.n(); + ASSERT(nj > 0); + + detail::RegularIterator lon{bbox.west(), bbox.east(), inc.west_east().longitude(), + reference.lon, GLOBE}; + auto w = lon.a(); + auto e = lon.b(); + + ni = lon.n(); + ASSERT(ni > 0); + + // checks + ASSERT(w + (ni - 1) * lon.inc() == e || ni * lon.inc() == GLOBE); + ASSERT(s + (nj - 1) * lat.inc() == n); + + return {n, w, s, e}; +} + + +Iterator* RegularLL::iterator() const { + + class RegularLLIterator : public Iterator { + public: + size_t ni_; + size_t nj_; + Fraction north_; + Fraction west_; + Fraction we_; + Fraction ns_; + size_t i_; + size_t j_; + Latitude latValue_; + Longitude lonValue_; + Fraction lat_; + Fraction lon_; + + size_t count_; + bool first_; + + ~RegularLLIterator() { + auto count = count_ + (i_ > 0 || j_ > 0 ? 1 : 0); + ASSERT(count == ni_ * nj_); + } + + void print(std::ostream& out) const override { + out << "RegularLLIterator[" + << "ni=" << ni_ << ",nj=" << nj_ << ",north=" << north_ << ",west=" << west_ << ",we=" << we_ << ",ns=" << ns_ + << ",i=" << i_ << ",j=" << j_ << ",count=" << count_ << "]"; + } + + bool next(double& lat, double& lon) { + if (j_ < nj_) { + if (i_ < ni_) { + lat = latValue_; + lon = lonValue_; + + lon_ += we_; + + if (first_) { + first_ = false; + } + else { + count_++; + } + + if (++i_ == ni_) { + j_++; + i_ = 0; + lat_ -= ns_; + lon_ = west_; + latValue_ = lat_; + } + + lonValue_ = lon_; + + return true; + } + } + return false; + } + + size_t index() const override { return count_; } + + public: + RegularLLIterator(size_t ni, size_t nj, Latitude north, Longitude west, const Increments& increments) : + ni_(ni), + nj_(nj), + north_(north), + west_(west), + we_(increments.west_east), + ns_(increments.south_north), + i_(0), + j_(0), + count_(0), + first_(true) { + lat_ = north_; + lon_ = west_; + latValue_ = lat_; + lonValue_ = lon_; + } + }; + + return new RegularLLIterator(ni_, nj_, bbox().north(), bbox().west(), increments_); } diff --git a/src/eckit/geo/grid/RegularLL.h b/src/eckit/geo/grid/RegularLL.h index 03107d479..75dc64027 100644 --- a/src/eckit/geo/grid/RegularLL.h +++ b/src/eckit/geo/grid/RegularLL.h @@ -12,13 +12,15 @@ #pragma once -#include "eckit/geo/grid/LatLon.h" +#include "eckit/geo/Grid.h" +#include "eckit/geo/Increments.h" +#include "eckit/types/Fraction.h" namespace eckit::geo::grid { -class RegularLL : public LatLon { +class RegularLL : public Grid { public: // -- Exceptions // None @@ -39,7 +41,13 @@ class RegularLL : public LatLon { // None // -- Methods - // None + + size_t Ni() const { return ni_; } + + size_t Nj() const { return nj_; } + + static BoundingBox correctBoundingBox(const BoundingBox&, size_t& ni, size_t& nj, const Increments&, + const PointLonLat& reference = {0, 0}); // -- Overridden methods // None @@ -52,22 +60,24 @@ class RegularLL : public LatLon { private: // -- Members - // None + + const Increments increments_; + const PointLonLat reference_; + size_t ni_; + size_t nj_; // -- Methods // None // -- Overridden methods - Iterator* iterator() const override; void print(std::ostream&) const override; - - bool sameAs(const Grid&) const override; - - // From Grid - const RegularLL* croppedGrid(const BoundingBox&) const override; - - std::string factory() const override; + bool isPeriodicWestEast() const override; + bool includesNorthPole() const override; + bool includesSouthPole() const override; + size_t numberOfPoints() const override; + void reorder(long scanningMode) const override; + Iterator* iterator() const override; // -- Class members // None diff --git a/src/eckit/geo/grid/RotatedClassic.cc b/src/eckit/geo/grid/RotatedClassic.cc deleted file mode 100644 index c3620e1df..000000000 --- a/src/eckit/geo/grid/RotatedClassic.cc +++ /dev/null @@ -1,48 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/RotatedClassic.h" - -#include - - -namespace eckit::geo::grid { - - -RotatedClassic::RotatedClassic(size_t N, const Rotation& rotation, const BoundingBox& bbox, - double angularPrecision) : - Classic(N, bbox, angularPrecision), rotation_(rotation) {} - - -void RotatedClassic::print(std::ostream& out) const { - out << "RotatedClassic[" - "N=" - << N_ << ",bbox=" << bbox() << ",rotation=" << rotation_ << "]"; -} - - -bool RotatedClassic::sameAs(const Grid& /*unused*/) const { - NOTIMP; -} - - -Iterator* RotatedClassic::iterator() const { - return rotatedIterator(rotation_); -} - - -const Grid* RotatedClassic::croppedGrid(const BoundingBox& bbox) const { - return new RotatedClassic(N_, rotation_, bbox, angularPrecision_); -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedClassic.h b/src/eckit/geo/grid/RotatedClassic.h deleted file mode 100644 index 93547796c..000000000 --- a/src/eckit/geo/grid/RotatedClassic.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/Classic.h" - - -namespace eckit::geo::grid { - - -class RotatedClassic : public Classic { -public: - // -- Exceptions - // None - - // -- Constructors - - RotatedClassic(size_t, const Rotation&, const BoundingBox& = BoundingBox(), - double angularPrecision = 0); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - - Rotation rotation_; - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - Iterator* iterator() const override; - const Grid* croppedGrid(const BoundingBox&) const override; - bool sameAs(const Grid&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedFromPL.cc b/src/eckit/geo/grid/RotatedFromPL.cc deleted file mode 100644 index 521576612..000000000 --- a/src/eckit/geo/grid/RotatedFromPL.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/RotatedFromPL.h" - -#include - - -namespace eckit::geo::grid { - - -RotatedFromPL::RotatedFromPL(const Configuration& config) : - FromPL(config), rotation_(parametrisation) {} - - -RotatedFromPL::RotatedFromPL(size_t N, const std::vector& pl, const Rotation& rotation, - const BoundingBox& bbox, double angularPrecision) : - FromPL(N, pl, bbox, angularPrecision), rotation_(rotation) {} - - -void RotatedFromPL::print(std::ostream& out) const { - out << "RotatedFromPL[" - "N=" - << N_ << ",bbox=" << bbox() << ",rotation=" << rotation_ << "]"; -} - - -bool RotatedFromPL::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && (rotation_ == o->rotation_) && FromPL::sameAs(other); -} - - -Iterator* RotatedFromPL::iterator() const { - return rotatedIterator(rotation_); -} - - -const Grid* RotatedFromPL::croppedGrid(const BoundingBox& bbox) const { - return new RotatedFromPL(N_, pls(), rotation_, bbox, angularPrecision_); -} - - -static const GridBuilder rotatedFromPL("reduced_rotated_gg"); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedFromPL.h b/src/eckit/geo/grid/RotatedFromPL.h deleted file mode 100644 index ca8a0a14e..000000000 --- a/src/eckit/geo/grid/RotatedFromPL.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/FromPL.h" - - -namespace eckit::geo::grid { - - -class RotatedFromPL : public FromPL { -public: - // -- Exceptions - // None - - // -- Constructors - - RotatedFromPL(const Configuration&); - RotatedFromPL(size_t, const std::vector&, const Rotation&, - const BoundingBox& = BoundingBox(), double angularPrecision = 0); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - - Rotation rotation_; - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - Iterator* iterator() const override; - const Grid* croppedGrid(const BoundingBox&) const override; - bool sameAs(const Grid&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedGG.cc b/src/eckit/geo/grid/RotatedGG.cc deleted file mode 100644 index 18212b316..000000000 --- a/src/eckit/geo/grid/RotatedGG.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/RotatedGG.h" - -#include -#include - -#include "eckit/geo/grid/GaussianIterator.h" - - -namespace eckit::geo::grid { - - -RotatedGG::RotatedGG(const Configuration& config) : - Regular(config), rotation_(parametrisation) {} - - -RotatedGG::RotatedGG(size_t N, const Rotation& rotation, const BoundingBox& bbox, double angularPrecision) : - Regular(N, bbox, angularPrecision), rotation_(rotation) {} - - -void RotatedGG::print(std::ostream& out) const { - out << "RotatedGG[" - "N=" - << N_ << ",Ni=" << Ni_ << ",Nj=" << Nj_ << ",bbox=" << bbox() << ",rotation=" << rotation_ << "]"; -} - - -bool RotatedGG::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && (rotation_ == o->rotation_) && Regular::sameAs(other); -} - - -Iterator* RotatedGG::iterator() const { - std::vector pl(N_ * 2, long(4 * N_)); - return new GaussianIterator(latitudes(), std::move(pl), bbox(), N_, Nj_, k_, rotation_); -} - - -const Grid* RotatedGG::croppedGrid(const BoundingBox& bbox) const { - return new RotatedGG(N_, rotation_, bbox, angularPrecision_); -} - - -static const GridBuilder rotatedGG("rotated_gg"); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedGG.h b/src/eckit/geo/grid/RotatedGG.h deleted file mode 100644 index a0057a122..000000000 --- a/src/eckit/geo/grid/RotatedGG.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/Regular.h" - - -namespace eckit::geo::grid { - - -class RotatedGG : public Regular { -public: - // -- Exceptions - // None - - // -- Constructors - - RotatedGG(const Configuration&); - RotatedGG(size_t N, const Rotation&, const BoundingBox& = BoundingBox(), - double angularPrecision = 0); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - - Rotation rotation_; - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - Iterator* iterator() const override; - - const Grid* croppedGrid(const BoundingBox&) const override; - bool sameAs(const Grid&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedLL.cc b/src/eckit/geo/grid/RotatedLL.cc deleted file mode 100644 index 9c58d702e..000000000 --- a/src/eckit/geo/grid/RotatedLL.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/RotatedLL.h" - -#include - -#include "eckit/geo/Iterator.h" - - -namespace eckit::geo::grid { - -RotatedLL::RotatedLL(const Configuration& config) : - LatLon(config), rotation_(parametrisation) {} - -RotatedLL::RotatedLL(const Increments& increments, const Rotation& rotation, const BoundingBox& bbox, - const PointLonLat& reference) : - LatLon(increments, bbox, reference), rotation_(rotation) {} - -RotatedLL::~RotatedLL() = default; - -Iterator* RotatedLL::iterator() const { - - class RotatedLLIterator : protected LatLonIterator, public Iterator { - void print(std::ostream& out) const override { - out << "RotatedLLIterator["; - Iterator::print(out); - out << ","; - LatLonIterator::print(out); - out << "]"; - } - bool next(double& lat, double& lon) override { return LatLonIterator::next(lat, lon); } - - size_t index() const override { return count_; } - - public: - RotatedLLIterator(size_t ni, size_t nj, Latitude north, Longitude west, const Increments& increments, - const Rotation& rotation) : - LatLonIterator(ni, nj, north, west, increments), Iterator(rotation) {} - }; - - return new RotatedLLIterator(ni_, nj_, bbox_.north(), bbox_.west(), increments_, rotation_); -} - -void RotatedLL::print(std::ostream& out) const { - out << "RotatedLL["; - LatLon::print(out); - out << ",rotation=" << rotation_ << "]"; -} - -bool RotatedLL::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && (rotation_ == o->rotation_) && LatLon::sameAs(other); -} - -const RotatedLL* RotatedLL::croppedGrid(const BoundingBox& bbox) const { - return new RotatedLL(increments_, rotation_, bbox, reference_); -} - - -std::string RotatedLL::factory() const { - return "rotated_ll"; -} - - -static const GridBuilder rotatedLL("rotated_ll"); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedLL.h b/src/eckit/geo/grid/RotatedLL.h deleted file mode 100644 index 0ec2d198e..000000000 --- a/src/eckit/geo/grid/RotatedLL.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/LatLon.h" - - -namespace eckit::geo::grid { - - -class RotatedLL : public LatLon { -public: - // -- Exceptions - // None - - // -- Constructors - - RotatedLL(const Configuration&); - RotatedLL(const Increments&, const Rotation&, const BoundingBox& = {}, - const PointLonLat& reference = {0, 0}); - - // -- Destructor - - ~RotatedLL() override; - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - Rotation rotation_; - - // -- Methods - // None - - // -- Overridden methods - Iterator* iterator() const override; - void print(std::ostream&) const override; - - bool sameAs(const Grid&) const override; - - // From Grid - const RotatedLL* croppedGrid(const BoundingBox&) const override; - std::string factory() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedOctahedral.cc b/src/eckit/geo/grid/RotatedOctahedral.cc deleted file mode 100644 index 47fe0aaeb..000000000 --- a/src/eckit/geo/grid/RotatedOctahedral.cc +++ /dev/null @@ -1,48 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/RotatedOctahedral.h" - -#include - - -namespace eckit::geo::grid { - - -RotatedOctahedral::RotatedOctahedral(size_t N, const Rotation& rotation, const BoundingBox& bbox, - double angularPrecision) : - Octahedral(N, bbox, angularPrecision), rotation_(rotation) {} - - -void RotatedOctahedral::print(std::ostream& out) const { - out << "RotatedOctahedral[" - "N=" - << N_ << ",bbox=" << bbox() << ",rotation=" << rotation_ << "]"; -} - - -bool RotatedOctahedral::sameAs(const Grid& /*unused*/) const { - NOTIMP; -} - - -Iterator* RotatedOctahedral::iterator() const { - return rotatedIterator(rotation_); -} - - -const Grid* RotatedOctahedral::croppedGrid(const BoundingBox& bbox) const { - return new RotatedOctahedral(N_, rotation_, bbox, angularPrecision_); -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RotatedOctahedral.h b/src/eckit/geo/grid/RotatedOctahedral.h deleted file mode 100644 index 32b93337d..000000000 --- a/src/eckit/geo/grid/RotatedOctahedral.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/Octahedral.h" - - -namespace eckit::geo::grid { - - -class RotatedOctahedral : public Octahedral { -public: - // -- Exceptions - // None - - // -- Constructors - - RotatedOctahedral(size_t, const Rotation&, const BoundingBox& = BoundingBox(), - double angularPrecision = 0); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - - Rotation rotation_; - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - Iterator* iterator() const override; - const Grid* croppedGrid(const BoundingBox&) const override; - bool sameAs(const Grid&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/SpaceView.cc b/src/eckit/geo/grid/SpaceView.cc index 2e6aa522a..30ed35058 100644 --- a/src/eckit/geo/grid/SpaceView.cc +++ b/src/eckit/geo/grid/SpaceView.cc @@ -20,7 +20,9 @@ #include #include +#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/Iterator.h" +#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -67,8 +69,9 @@ SpaceViewInternal::SpaceViewInternal(const Configuration& param) { return "+proj=geos +type=crs +sweep=y" + _h + _l + _e; }; - projection_ = RegularGrid::Configuration("type", "proj").set("proj", proj(h, a, b, Lop_)); - projectionGreenwich_ = RegularGrid::Configuration("type", "proj").set("proj", proj(h, a, b, 0)); + projection_.reset(ProjectionFactory::build("proj", MappedConfiguration({{"proj", proj(h, a, b, Lop_)}}))); + + projectionGreenwich_.reset(ProjectionFactory::build("proj", MappedConfiguration({{"proj", proj(h, a, b, 0)}}))); // (x, y) space Nx_ = get(param, "Nx"); @@ -99,7 +102,7 @@ SpaceViewInternal::SpaceViewInternal(const Configuration& param) { // longest element diagonal, a multiple of a reference central element diagonal (avoiding distortion) - LongestElementDiagonal_ = 20. * Earth::distance(projection_.lonlat({-rx / 2, ry / 2}), projection_.lonlat({rx / 2, -ry / 2})); + LongestElementDiagonal_ = 20. * Earth::distance(projection_->inv(geometry::Point2{-rx / 2, ry / 2}), projection_->inv(geometry::Point2{rx / 2, -ry / 2})); ASSERT(0. < LongestElementDiagonal_); @@ -108,10 +111,10 @@ SpaceViewInternal::SpaceViewInternal(const Configuration& param) { // [1] page 25, solution of s_d^2=0, restrained at x=0 (lon) and y=0 (lat). Note: uses a, b, height defined there auto eps_ll = 1e-6; - auto n = 90. - radian_to_degree(0.151347) + eps_ll; + auto n = 90. - util::radian_to_degree * 0.151347 + eps_ll; auto s = -n; - auto e = 90. - radian_to_degree(0.151853) + eps_ll + Lop_; + auto e = 90. - util::radian_to_degree * 0.151853 + eps_ll + Lop_; auto w = 2. * Lop_ - e; #else auto geometric_maximum = [](double x_min, double x_eps, const std::function& f, @@ -152,10 +155,8 @@ SpaceViewInternal::SpaceViewInternal(const Configuration& param) { } -const std::vector& SpaceViewInternal::lonlat() const { +const std::vector& SpaceViewInternal::lonlat() const { if (lonlat_.empty()) { - trace::Timer timer("SpaceView: pre-calculate (lon, lat) coordinates"); - ASSERT(projectionGreenwich_); // Greenwich-centred (avoids PROJ normalisation) lonlat_.resize(Nx_ * Ny_); @@ -164,11 +165,11 @@ const std::vector& SpaceViewInternal::lonlat() const { for (const auto& _x : x()) { auto& ll = lonlat_[index++]; ll = projectionGreenwich_.lonlat({_x, _y}); - if (std::isfinite(ll.lon()) && std::isfinite(ll.lat())) { - ASSERT(-90. < ll.lon() && ll.lon() < 90.); - ASSERT(-90. < ll.lat() && ll.lat() < 90.); + if (std::isfinite(ll.lon) && std::isfinite(ll.lat)) { + ASSERT(-90. < ll.lon && ll.lon < 90.); + ASSERT(-90. < ll.lat && ll.lat < 90.); - ll.lon() += Lop_; + ll.lon += Lop_; } else { ll = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; diff --git a/src/eckit/geo/grid/SpaceView.h b/src/eckit/geo/grid/SpaceView.h index 145caa50c..daaf0f141 100644 --- a/src/eckit/geo/grid/SpaceView.h +++ b/src/eckit/geo/grid/SpaceView.h @@ -12,6 +12,8 @@ #pragma once +#include + #include "eckit/geo/grid/RegularGrid.h" @@ -29,14 +31,14 @@ namespace detail { */ struct SpaceViewInternal { SpaceViewInternal(const Configuration&); - Projection projection_; - Projection projectionGreenwich_; + std::unique_ptr projection_; + std::unique_ptr projectionGreenwich_; BoundingBox bbox_; - RegularGrid::LinearSpacing x() const { return {xa_, xb_, Nx_, true}; } - RegularGrid::LinearSpacing y() const { return {ya_, yb_, Ny_, true}; } + LinearSpacing x() const { return {xa_, xb_, Nx_, true}; } + LinearSpacing y() const { return {ya_, yb_, Ny_, true}; } - const std::vector& lonlat() const; + const std::vector& lonlat() const; long Nx_; long Ny_; @@ -48,7 +50,7 @@ struct SpaceViewInternal { double Lop_; private: - mutable std::vector lonlat_; + mutable std::vector lonlat_; }; diff --git a/src/eckit/geo/grid/StretchedGG.h b/src/eckit/geo/grid/StretchedGG.h deleted file mode 100644 index 7be463b6c..000000000 --- a/src/eckit/geo/grid/StretchedGG.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Grid.h" - - -namespace eckit::geo::grid { - - -class StretchedGG : public Grid { -public: - // -- Exceptions - // None - - // -- Constructors - - StretchedGG(const Configuration&); - StretchedGG(const StretchedGG&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - StretchedGG& operator=(const StretchedGG&) = delete; - - // -- Methods - // // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedLL.h b/src/eckit/geo/grid/StretchedLL.h deleted file mode 100644 index 76409446d..000000000 --- a/src/eckit/geo/grid/StretchedLL.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Grid.h" - - -namespace eckit::geo::grid { - - -class StretchedLL : public Grid { -public: - // -- Exceptions - // None - - // -- Constructors - - StretchedLL(const Configuration&); - StretchedLL(const StretchedLL&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - StretchedLL& operator=(const StretchedLL&) = delete; - - // -- Methods - // // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedRotatedGG.cc b/src/eckit/geo/grid/StretchedRotatedGG.cc deleted file mode 100644 index fe78be8bb..000000000 --- a/src/eckit/geo/grid/StretchedRotatedGG.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/StretchedRotatedGG.h" - -#include - - -namespace eckit::geo::grid { - - -StretchedRotatedGG::StretchedRotatedGG(const Configuration& /*config*/) {} - - -void StretchedRotatedGG::print(std::ostream& out) const { - out << "StretchedRotatedGG[" - << "]"; -} - - -static const GridBuilder __repres("stretched_rotated_gg"); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedRotatedGG.h b/src/eckit/geo/grid/StretchedRotatedGG.h deleted file mode 100644 index 4663edc6a..000000000 --- a/src/eckit/geo/grid/StretchedRotatedGG.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Grid.h" - - -namespace eckit::geo::grid { - - -class StretchedRotatedGG : public Grid { -public: - // -- Exceptions - // None - - // -- Constructors - - StretchedRotatedGG(const Configuration&); - StretchedRotatedGG(const StretchedRotatedGG&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - StretchedRotatedGG& operator=(const StretchedRotatedGG&) = delete; - - // -- Methods - // // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedRotatedLL.cc b/src/eckit/geo/grid/StretchedRotatedLL.cc deleted file mode 100644 index 8fbca1727..000000000 --- a/src/eckit/geo/grid/StretchedRotatedLL.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/StretchedRotatedLL.h" - -#include - - -namespace eckit::geo::grid { - - -StretchedRotatedLL::StretchedRotatedLL(const Configuration& /*config*/) {} - - -void StretchedRotatedLL::print(std::ostream& out) const { - out << "StretchedRotatedLL[" - << "]"; -} - - -static const GridBuilder __repres("stretched_rotated_ll"); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/StretchedRotatedLL.h b/src/eckit/geo/grid/StretchedRotatedLL.h deleted file mode 100644 index b7009c64d..000000000 --- a/src/eckit/geo/grid/StretchedRotatedLL.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Grid.h" - - -namespace eckit::geo::grid { - - -class StretchedRotatedLL : public Grid { -public: - // -- Exceptions - // None - - // -- Constructors - - StretchedRotatedLL(const Configuration&); - StretchedRotatedLL(const StretchedRotatedLL&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - StretchedRotatedLL& operator=(const StretchedRotatedLL&) = delete; - - // -- Methods - // // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/TransverseMercator.cc b/src/eckit/geo/grid/TransverseMercator.cc index 4dfc8889b..5a7205640 100644 --- a/src/eckit/geo/grid/TransverseMercator.cc +++ b/src/eckit/geo/grid/TransverseMercator.cc @@ -18,7 +18,7 @@ namespace eckit::geo::grid { -TransverseMercator::TransverseMercator(const Configuration& /*config*/) {} +TransverseMercator::TransverseMercator(const Configuration& config) : RegularGrid(config){} void TransverseMercator::print(std::ostream& out) const { diff --git a/src/eckit/geo/grid/TransverseMercator.h b/src/eckit/geo/grid/TransverseMercator.h index 32819cbac..65e0fa10d 100644 --- a/src/eckit/geo/grid/TransverseMercator.h +++ b/src/eckit/geo/grid/TransverseMercator.h @@ -12,13 +12,13 @@ #pragma once -#include "eckit/geo/Grid.h" +#include "eckit/geo/grid/RegularGrid.h" namespace eckit::geo::grid { -class TransverseMercator : public Grid { +class TransverseMercator : public RegularGrid { public: // -- Exceptions // None diff --git a/src/eckit/geo/grid/UnstructuredGrid.cc b/src/eckit/geo/grid/UnstructuredGrid.cc index 99a001a3d..56647432c 100644 --- a/src/eckit/geo/grid/UnstructuredGrid.cc +++ b/src/eckit/geo/grid/UnstructuredGrid.cc @@ -20,9 +20,10 @@ #include #include "eckit/config/Resource.h" +#include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" +#include "eckit/geo/Domain.h" #include "eckit/geo/Iterator.h" -#include "eckit/geo/grid/ORCA.h" #include "eckit/serialisation/FileStream.h" #include "eckit/serialisation/IfstreamStream.h" @@ -30,7 +31,95 @@ namespace eckit::geo::grid { -UnstructuredGrid::UnstructuredGrid(const Configuration& config) { +namespace detail { + + +class UnstructuredIterator : public Iterator { +public: + // -- Exceptions + // None + + // -- Constructors + UnstructuredIterator(const std::vector& latitudes, const std::vector& longitudes) : + count_(0), size_(latitudes.size()), latitudes_(latitudes), longitudes_(longitudes), first_(true) { + ASSERT(latitudes_.size() == longitudes_.size()); + } + + UnstructuredIterator(const UnstructuredIterator&) = delete; + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + + UnstructuredIterator& operator=(const UnstructuredIterator&) = delete; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + size_t count_; + const size_t size_; + const std::vector& latitudes_; + const std::vector& longitudes_; + bool first_; + + // -- Methods + // None + + // -- Overridden methods + + // From Iterator + + void print(std::ostream& out) const override { + out << "UnstructuredGridIterator["; + Iterator::print(out); + out << "]"; + } + + bool next(Latitude& lat, Longitude& lon) override { + if ((first_ ? count_ : ++count_) < size_) { + first_ = false; + lat = latitudes_[count_]; + lon = longitudes_[count_]; + + return true; + } + return false; + } + + size_t index() const override { return count_; } + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace detail + + +UnstructuredGrid::UnstructuredGrid(const Configuration& config) : + Grid(config) { config.get("latitudes", latitudes_); config.get("longitudes", longitudes_); @@ -38,8 +127,6 @@ UnstructuredGrid::UnstructuredGrid(const Configuration& config) { throw UserError("UnstructuredGrid: requires 'latitudes' and 'longitudes'"); } ASSERT(latitudes_.size() == longitudes_.size()); - - check_duplicate_points("UnstructuredGrid from Configuration", latitudes_, longitudes_, config); } @@ -50,9 +137,6 @@ UnstructuredGrid::UnstructuredGrid(const PathName& path) { } if (::isprint(in.peek()) == 0) { - - Log::info() << "UnstructuredGrid::load " << path << std::endl; - IfstreamStream s(in); size_t version; s >> version; @@ -67,7 +151,6 @@ UnstructuredGrid::UnstructuredGrid(const PathName& path) { for (size_t i = 0; i < count; ++i) { s >> latitudes_[i]; s >> longitudes_[i]; - // Log::info() << latitudes_[i] << " " << longitudes_[i] << std::endl; } } else { @@ -78,35 +161,6 @@ UnstructuredGrid::UnstructuredGrid(const PathName& path) { longitudes_.push_back(lon); } } - - check_duplicate_points("UnstructuredGrid from " + path.asString(), latitudes_, longitudes_); -} - - -void UnstructuredGrid::save(const PathName& path, const std::vector& latitudes, - const std::vector& longitudes, bool binary) { - Log::info() << "UnstructuredGrid::save " << path << std::endl; - - check_duplicate_points("UnstructuredGrid::save to " + path.asString(), latitudes, longitudes); - - ASSERT(latitudes.size() == longitudes.size()); - if (binary) { - FileStream s(path, "w"); - size_t version = 1; - size_t count = latitudes.size(); - s << version; - s << count; - for (size_t i = 0; i < count; ++i) { - s << latitudes[i]; - s << longitudes[i]; - - Log::info() << latitudes[i] << " " << longitudes[i] << std::endl; - } - s.close(); - } - else { - NOTIMP; - } } @@ -114,7 +168,6 @@ UnstructuredGrid::UnstructuredGrid(const std::vector& latitudes, const s const BoundingBox& bbox) : Grid(bbox), latitudes_(latitudes), longitudes_(longitudes) { ASSERT(latitudes_.size() == longitudes_.size()); - check_duplicate_points("UnstructuredGrid from arguments", latitudes_, longitudes_); } @@ -126,12 +179,6 @@ void UnstructuredGrid::print(std::ostream& out) const { } -bool UnstructuredGrid::sameAs(const Grid& other) const { - const auto* o = dynamic_cast(&other); - return (o != nullptr) && (latitudes_ == o->latitudes_) && (longitudes_ == o->longitudes_); -} - - Domain UnstructuredGrid::domain() const { // FIXME Should be global? return {bbox().north(), bbox().west(), bbox().south(), bbox().east()}; @@ -144,34 +191,6 @@ size_t UnstructuredGrid::numberOfPoints() const { } -const Grid* UnstructuredGrid::croppedGrid(const BoundingBox& bbox) const { - std::vector lat; - std::vector lon; - - size_t i = 0; - size_t j = 0; - - for (const std::unique_ptr iter(iterator()); iter->next(); ++i) { - if (bbox.contains(iter->pointUnrotated())) { - auto ip = iter->index(); - lat.emplace_back(latitudes_.at(ip)); - lon.emplace_back(longitudes_.at(ip)); - ++j; - } - } - - if (j < i) { - Log::debug() << "UnstructuredGrid::croppedGrid: cropped " << Log::Pretty(i) << " to " - << Log::Pretty(j, {"point"}) << std::endl; - ASSERT(j); - return new UnstructuredGrid(lat, lon, bbox); - } - - Log::debug() << "UnstructuredGrid::croppedGrid: no cropping" << std::endl; - return this; -} - - Iterator* UnstructuredGrid::iterator() const { return new iterator::UnstructuredIterator(latitudes_, longitudes_); } @@ -196,20 +215,4 @@ static const GridBuilder triangular_grid("triangular_grid"); static const GridBuilder unstructured_grid("unstructured_grid"); -template <> -Grid* GridBuilder::make(const Configuration& param) { -#if mir_HAVE_ATLAS - // specially-named unstructured grids - std::string grid; - if (param.get("grid", grid)) { - if (!key::grid::ORCAPattern::match(grid, param).empty()) { - return new other::ORCA(param); - } - } -#endif - - return new other::UnstructuredGrid(param); -} - - } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/UnstructuredGrid.h b/src/eckit/geo/grid/UnstructuredGrid.h index 739504c2f..e1e47c13e 100644 --- a/src/eckit/geo/grid/UnstructuredGrid.h +++ b/src/eckit/geo/grid/UnstructuredGrid.h @@ -53,12 +53,10 @@ class UnstructuredGrid : public Grid { void operator=(const UnstructuredGrid&&) = delete; // -- Methods - - static void save(const PathName&, const std::vector& latitudes, - const std::vector& longitudes, bool binary); + // None // -- Overridden methods - + // None // -- Class members // None @@ -72,7 +70,6 @@ class UnstructuredGrid : public Grid { // -- Methods - // From Grid void print(std::ostream&) const override; // -- Overridden methods @@ -97,7 +94,7 @@ class UnstructuredGrid : public Grid { Domain domain() const override; Iterator* iterator() const override; - bool sameAs(const Grid&) const override; + // Domain operations bool isPeriodicWestEast() const override; @@ -105,7 +102,6 @@ class UnstructuredGrid : public Grid { bool includesSouthPole() const override; size_t numberOfPoints() const override; - const Grid* croppedGrid(const BoundingBox&) const override; // -- Class members // None diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 88cb25c56..3557562bc 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -16,6 +16,7 @@ #include #include "eckit/config/Configuration.h" +#include "eckit/geo/util.h" #include "eckit/geometry/UnitSphere.h" #include "eckit/maths/Matrix3.h" #include "eckit/types/FloatCompare.h" @@ -27,23 +28,23 @@ namespace eckit::geo::projection { static ProjectionBuilder __projection("rotation"); -Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : +Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : rotated_(true) { using M = maths::Matrix3; - struct No final : Rotate { + struct NonRotated final : Rotate { PointLonLat operator()(const PointLonLat& p) const override { return p; } }; - struct Angle final : Rotate { - explicit Angle(double angle) : + struct RotationAngle final : Rotate { + explicit RotationAngle(double angle) : angle_(angle) {} - PointLonLat operator()(const PointLonLat& p) const override { return {p.lat, p.lon + angle_}; } + PointLonLat operator()(const PointLonLat& p) const override { return {p.lon + angle_, p.lat}; } const double angle_; }; - struct Matrix final : Rotate { - explicit Matrix(M&& R) : + struct RotationMatrix final : Rotate { + explicit RotationMatrix(M&& R) : R_(R) {} PointLonLat operator()(const PointLonLat& p) const override { return geometry::UnitSphere::convertCartesianToSpherical( @@ -52,12 +53,11 @@ Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : const M R_; }; - constexpr auto eps = 1e-12; - constexpr auto degrees_to_radians = M_PI / 180.; + constexpr auto eps = 1e-12; - const auto alpha = angle * degrees_to_radians; - const auto theta = -(south_pole_lat + 90.) * degrees_to_radians; - const auto phi = -south_pole_lon * degrees_to_radians; + const auto alpha = util::degree_to_radian * angle; + const auto theta = util::degree_to_radian * -(south_pole_lat + 90.); + const auto phi = util::degree_to_radian * -south_pole_lon; const auto ca = std::cos(alpha); const auto ct = std::cos(theta); @@ -67,8 +67,8 @@ Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : angle = PointLonLat::normalise_angle_to_minimum(angle - south_pole_lon, -180.); rotated_ = !types::is_approximately_equal(angle, 0., eps); - fwd_.reset(rotated_ ? static_cast(new Angle(-angle)) : new No); - inv_.reset(rotated_ ? static_cast(new Angle(angle)) : new No); + fwd_.reset(rotated_ ? static_cast(new RotationAngle(-angle)) : new NonRotated); + inv_.reset(rotated_ ? static_cast(new RotationAngle(angle)) : new NonRotated); return; } @@ -83,22 +83,22 @@ Rotation::Rotation(double south_pole_lat, double south_pole_lon, double angle) : // q = Rz Ry Ra p = [ cosφ sinφ ] [ cosϑ sinϑ ] [ cosα sinα ] p // [ -sinφ cosφ ] [ 1 ] [ -sinα cosα ] // [ 1 ] [ -sinϑ cosϑ ] [ 1 ] - fwd_ = std::make_unique(M{ca * cp * ct - sa * sp, sa * cp * ct + ca * sp, cp * st, // - -sa * cp - ca * ct * sp, ca * cp - sa * ct * sp, -sp * st, // - -ca * st, -sa * st, ct}); + fwd_ = std::make_unique(M{ca * cp * ct - sa * sp, sa * cp * ct + ca * sp, cp * st, // + -sa * cp - ca * ct * sp, ca * cp - sa * ct * sp, -sp * st, // + -ca * st, -sa * st, ct}); // Un-rotate (rotate by -φ, -ϑ, -α): // p = Ra Ry Rz q = [ cosα -sinα ] [ cosϑ -sinϑ ] [ cosφ -sinφ ] q // [ sinα cosα ] [ 1 ] [ sinφ cosφ ] // [ 1 ] [ sinϑ cosϑ ] [ 1 ] - inv_ = std::make_unique(M{ca * cp * ct - sa * sp, -sa * cp - ca * ct * sp, -ca * st, // - sa * cp * ct + ca * sp, ca * cp - sa * ct * sp, -sa * st, // - cp * st, -sp * st, ct}); + inv_ = std::make_unique(M{ca * cp * ct - sa * sp, -sa * cp - ca * ct * sp, -ca * st, // + sa * cp * ct + ca * sp, ca * cp - sa * ct * sp, -sa * st, // + cp * st, -sp * st, ct}); } Rotation::Rotation(const Configuration& param) : - Rotation(param.getDouble("south_pole_lat"), param.getDouble("south_pole_lon"), + Rotation(param.getDouble("south_pole_lon"), param.getDouble("south_pole_lat"), param.getDouble("angle", 0)) {} diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index a9ccd9229..1e016448c 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -28,7 +28,7 @@ class Rotation final : public Projection { // -- Constructors - Rotation(double south_pole_lat, double south_pole_lon, double angle); + Rotation(double south_pole_lon, double south_pole_lat, double angle); explicit Rotation(const Configuration&); // -- Destructor diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index a39c35065..7c6157b8a 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -22,6 +22,10 @@ namespace eckit::geo::util { +constexpr double degree_to_radian = M_PI / 180.; +constexpr double radian_to_degree = M_1_PI * 180.; + + using pl_type = std::vector; diff --git a/tests/geo/test_projection_rotation.cc b/tests/geo/test_projection_rotation.cc index 7bef6ba7e..532fa76d3 100644 --- a/tests/geo/test_projection_rotation.cc +++ b/tests/geo/test_projection_rotation.cc @@ -29,7 +29,7 @@ int main(int argc, char* argv[]) { for (auto a : delta) { for (auto b : delta) { for (auto c : delta) { - Rotation rot(-90. + static_cast(a), 0. + static_cast(b), static_cast(c)); + Rotation rot(0. + static_cast(b), -90. + static_cast(a), static_cast(c)); EXPECT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); EXPECT(points_equal(p, rot.inv(rot.fwd(p)))); @@ -43,7 +43,7 @@ int main(int argc, char* argv[]) { const int Ni = 12; const int Nj = 3; - Rotation rot(-46.7, 182., 0.); + Rotation rot(182., -46.7, 0.); const PointLonLat ref[]{ {-178., -46.7}, {-178., -16.7}, @@ -143,13 +143,13 @@ int main(int argc, char* argv[]) { } { - const Rotation unrotated(-90., 0., 0.); - const Rotation angle_only(-90., 0., -180.); - const Rotation rotation(-40., 4., 180.); + const Rotation non_rotated(0., -90., 0.); + const Rotation rotation_angle(0., -90., -180.); + const Rotation rotation_matrix(4., -40., 180.); - EXPECT(not unrotated.rotated()); - EXPECT(angle_only.rotated()); - EXPECT(rotation.rotated()); + EXPECT(not non_rotated.rotated()); + EXPECT(rotation_angle.rotated()); + EXPECT(rotation_matrix.rotated()); const PointLonLat p[] = {{0., 90.}, {0., 0.}, {270., 25.}, {-180., 45.}}; @@ -158,18 +158,18 @@ int main(int argc, char* argv[]) { const PointLonLat a; const PointLonLat b; } tests[] = { - {unrotated, p[0], p[0]}, - {unrotated, p[1], p[1]}, - {unrotated, p[2], p[2]}, - {unrotated, p[3], p[3]}, - {angle_only, p[0], {p[0].lon - 180., p[0].lat}}, - {angle_only, p[1], {p[1].lon - 180., p[1].lat}}, - {angle_only, p[2], {p[2].lon - 180., p[2].lat}}, - {angle_only, p[3], {p[3].lon - 180., p[3].lat}}, - {rotation, p[0], {-176., 40.}}, - {rotation, p[1], {-176., -50.}}, - {rotation, p[2], {113.657357, 15.762700}}, - {rotation, p[3], {-176., 85.}}, + {non_rotated, p[0], p[0]}, + {non_rotated, p[1], p[1]}, + {non_rotated, p[2], p[2]}, + {non_rotated, p[3], p[3]}, + {rotation_angle, p[0], {p[0].lon - 180., p[0].lat}}, + {rotation_angle, p[1], {p[1].lon - 180., p[1].lat}}, + {rotation_angle, p[2], {p[2].lon - 180., p[2].lat}}, + {rotation_angle, p[3], {p[3].lon - 180., p[3].lat}}, + {rotation_matrix, p[0], {-176., 40.}}, + {rotation_matrix, p[1], {-176., -50.}}, + {rotation_matrix, p[2], {113.657357, 15.762700}}, + {rotation_matrix, p[3], {-176., 85.}}, }; for (const auto& test : tests) { From 92722f2d8602512d8b04f8da3e8367e827f07202 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 8 Jun 2023 09:27:45 +0100 Subject: [PATCH 241/737] eckit::geo::grid --- src/eckit/geo/BoundingBox.h | 9 +- src/eckit/geo/CMakeLists.txt | 39 +---- src/eckit/geo/Domain.cc | 53 ------ src/eckit/geo/Domain.h | 9 +- src/eckit/geo/Grid.cc | 7 +- src/eckit/geo/Grid.h | 9 +- src/eckit/geo/Increments.cc | 1 - src/eckit/geo/Increments.h | 2 +- src/eckit/geo/Iterator.h | 8 +- src/eckit/geo/grid/Albers.cc | 33 ---- src/eckit/geo/grid/Albers.h | 91 ---------- src/eckit/geo/grid/AzimuthRange.cc | 33 ---- src/eckit/geo/grid/AzimuthRange.h | 91 ---------- src/eckit/geo/grid/Classic.cc | 37 ---- src/eckit/geo/grid/Classic.h | 72 -------- .../grid/EquatorialAzimuthalEquidistant.cc | 33 ---- .../geo/grid/EquatorialAzimuthalEquidistant.h | 91 ---------- src/eckit/geo/grid/FromPL.cc | 27 --- src/eckit/geo/grid/FromPL.h | 74 -------- src/eckit/geo/grid/GaussianIterator.cc | 17 +- src/eckit/geo/grid/GaussianIterator.h | 6 +- src/eckit/geo/grid/IrregularLatlon.cc | 12 +- src/eckit/geo/grid/Lambert.cc | 59 ------- src/eckit/geo/grid/Lambert.h | 77 --------- .../geo/grid/LambertAzimuthalEqualArea.cc | 56 ------ .../geo/grid/LambertAzimuthalEqualArea.h | 77 --------- src/eckit/geo/grid/Mercator.cc | 26 --- src/eckit/geo/grid/Mercator.h | 74 -------- src/eckit/geo/grid/None.cc | 38 ----- src/eckit/geo/grid/None.h | 93 ---------- src/eckit/geo/grid/ORCA.cc | 9 +- src/eckit/geo/grid/Octahedral.cc | 37 ---- src/eckit/geo/grid/Octahedral.h | 73 -------- src/eckit/geo/grid/PolarStereographic.cc | 26 --- src/eckit/geo/grid/PolarStereographic.h | 74 -------- src/eckit/geo/grid/ReducedClassic.cc | 35 ---- src/eckit/geo/grid/ReducedClassic.h | 90 ---------- src/eckit/geo/grid/ReducedFromPL.cc | 43 ----- src/eckit/geo/grid/ReducedFromPL.h | 92 ---------- .../geo/grid/{Reduced.cc => ReducedGG.cc} | 136 ++++++++------- src/eckit/geo/grid/{Reduced.h => ReducedGG.h} | 28 +-- src/eckit/geo/grid/ReducedLL.cc | 20 ++- src/eckit/geo/grid/ReducedOctahedral.cc | 35 ---- src/eckit/geo/grid/ReducedOctahedral.h | 90 ---------- src/eckit/geo/grid/Regular.cc | 159 ------------------ src/eckit/geo/grid/Regular.h | 102 ----------- src/eckit/geo/grid/RegularGG.cc | 150 ++++++++++++++++- src/eckit/geo/grid/RegularGG.h | 29 +++- src/eckit/geo/grid/RegularGrid.cc | 149 +++++++++++----- src/eckit/geo/grid/RegularGrid.h | 16 +- src/eckit/geo/grid/RegularLL.cc | 49 +++--- src/eckit/geo/grid/RegularLL.h | 13 +- src/eckit/geo/grid/SpaceView.cc | 60 ++++--- src/eckit/geo/grid/TransverseMercator.cc | 33 ---- src/eckit/geo/grid/TransverseMercator.h | 91 ---------- src/eckit/geo/grid/UnstructuredGrid.cc | 9 +- src/eckit/geo/iterator/IteratorAggregator.h | 94 ----------- src/eckit/geo/iterator/IteratorComposer.cc | 43 ----- src/eckit/geo/iterator/IteratorComposer.h | 85 ---------- src/eckit/geo/projection/LonLatToXYZ.cc | 6 +- src/eckit/geo/projection/PROJ.cc | 8 +- src/eckit/geo/projection/Rotation.cc | 6 +- src/eckit/geo/scanner/Reduced.cc | 2 +- src/eckit/geo/scanner/Reduced.h | 4 - src/eckit/geo/util.h | 16 +- tests/geo/test_iterator.cc | 16 +- tests/types/test_floatcompare.cc | 31 +++- 67 files changed, 566 insertions(+), 2647 deletions(-) delete mode 100644 src/eckit/geo/grid/Albers.cc delete mode 100644 src/eckit/geo/grid/Albers.h delete mode 100644 src/eckit/geo/grid/AzimuthRange.cc delete mode 100644 src/eckit/geo/grid/AzimuthRange.h delete mode 100644 src/eckit/geo/grid/Classic.cc delete mode 100644 src/eckit/geo/grid/Classic.h delete mode 100644 src/eckit/geo/grid/EquatorialAzimuthalEquidistant.cc delete mode 100644 src/eckit/geo/grid/EquatorialAzimuthalEquidistant.h delete mode 100644 src/eckit/geo/grid/FromPL.cc delete mode 100644 src/eckit/geo/grid/FromPL.h delete mode 100644 src/eckit/geo/grid/Lambert.cc delete mode 100644 src/eckit/geo/grid/Lambert.h delete mode 100644 src/eckit/geo/grid/LambertAzimuthalEqualArea.cc delete mode 100644 src/eckit/geo/grid/LambertAzimuthalEqualArea.h delete mode 100644 src/eckit/geo/grid/Mercator.cc delete mode 100644 src/eckit/geo/grid/Mercator.h delete mode 100644 src/eckit/geo/grid/None.cc delete mode 100644 src/eckit/geo/grid/None.h delete mode 100644 src/eckit/geo/grid/Octahedral.cc delete mode 100644 src/eckit/geo/grid/Octahedral.h delete mode 100644 src/eckit/geo/grid/PolarStereographic.cc delete mode 100644 src/eckit/geo/grid/PolarStereographic.h delete mode 100644 src/eckit/geo/grid/ReducedClassic.cc delete mode 100644 src/eckit/geo/grid/ReducedClassic.h delete mode 100644 src/eckit/geo/grid/ReducedFromPL.cc delete mode 100644 src/eckit/geo/grid/ReducedFromPL.h rename src/eckit/geo/grid/{Reduced.cc => ReducedGG.cc} (67%) rename src/eckit/geo/grid/{Reduced.h => ReducedGG.h} (66%) delete mode 100644 src/eckit/geo/grid/ReducedOctahedral.cc delete mode 100644 src/eckit/geo/grid/ReducedOctahedral.h delete mode 100644 src/eckit/geo/grid/Regular.cc delete mode 100644 src/eckit/geo/grid/Regular.h delete mode 100644 src/eckit/geo/grid/TransverseMercator.cc delete mode 100644 src/eckit/geo/grid/TransverseMercator.h delete mode 100644 src/eckit/geo/iterator/IteratorAggregator.h delete mode 100644 src/eckit/geo/iterator/IteratorComposer.cc delete mode 100644 src/eckit/geo/iterator/IteratorComposer.h diff --git a/src/eckit/geo/BoundingBox.h b/src/eckit/geo/BoundingBox.h index e1cd72f5a..cbea24d74 100644 --- a/src/eckit/geo/BoundingBox.h +++ b/src/eckit/geo/BoundingBox.h @@ -13,6 +13,7 @@ #pragma once #include +#include namespace eckit { @@ -54,15 +55,19 @@ class BoundingBox { // -- Methods + std::tuple deconstruct() const { return {north_, west_, south_, east_}; } + double north() const { return north_; } double west() const { return west_; } double south() const { return south_; } double east() const { return east_; } bool isPeriodicWestEast() const; + + bool intersects(BoundingBox&) const; + bool contains(double lat, double lon) const; bool contains(const BoundingBox&) const; - bool intersects(BoundingBox&) const; bool empty() const; double area(double radius) const; @@ -117,7 +122,7 @@ class BoundingBox { // -- Friends friend std::ostream& operator<<(std::ostream& out, const BoundingBox& p) { - return out << '{' << p.north_<< ", " << p.west_<< ", " << p.south_<< ", " << p.east_<< '}'; + return out << '{' << p.north_ << ", " << p.west_ << ", " << p.south_ << ", " << p.east_ << '}'; } }; diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index b35b645f1..004425c74 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -20,48 +20,18 @@ list(APPEND eckit_geo_srcs Scanner.cc Scanner.h Search.h - grid/Albers.cc - grid/Albers.h - grid/AzimuthRange.cc - grid/AzimuthRange.h - grid/Classic.cc - grid/Classic.h - grid/EquatorialAzimuthalEquidistant.cc - grid/EquatorialAzimuthalEquidistant.h - grid/FromPL.cc - grid/FromPL.h grid/Gaussian.cc grid/Gaussian.h grid/GaussianIterator.cc grid/GaussianIterator.h grid/IrregularLatlon.cc grid/IrregularLatlon.h - grid/Lambert.cc - grid/Lambert.h - grid/LambertAzimuthalEqualArea.cc - grid/LambertAzimuthalEqualArea.h - grid/Mercator.cc - grid/Mercator.h - grid/None.cc - grid/None.h grid/ORCA.cc grid/ORCA.h - grid/Octahedral.cc - grid/Octahedral.h - grid/PolarStereographic.cc - grid/PolarStereographic.h - grid/Reduced.cc - grid/Reduced.h - grid/ReducedClassic.cc - grid/ReducedClassic.h - grid/ReducedFromPL.cc - grid/ReducedFromPL.h + grid/ReducedGG.cc + grid/ReducedGG.h grid/ReducedLL.cc grid/ReducedLL.h - grid/ReducedOctahedral.cc - grid/ReducedOctahedral.h - grid/Regular.cc - grid/Regular.h grid/RegularGG.cc grid/RegularGG.h grid/RegularGrid.cc @@ -70,13 +40,8 @@ list(APPEND eckit_geo_srcs grid/RegularLL.h grid/SpaceView.cc grid/SpaceView.h - grid/TransverseMercator.cc - grid/TransverseMercator.h grid/UnstructuredGrid.cc grid/UnstructuredGrid.h - iterator/IteratorAggregator.h - iterator/IteratorComposer.cc - iterator/IteratorComposer.h projection/LonLatToXYZ.cc projection/LonLatToXYZ.h projection/None.cc diff --git a/src/eckit/geo/Domain.cc b/src/eckit/geo/Domain.cc index b60a65a83..814283ec0 100644 --- a/src/eckit/geo/Domain.cc +++ b/src/eckit/geo/Domain.cc @@ -46,11 +46,6 @@ bool Domain::operator==(const Domain& other) const { } -bool Domain::isGlobal() const { - return includesNorthPole() && includesSouthPole() && isPeriodicWestEast(); -} - - bool Domain::includesNorthPole() const { return north_ == NORTH_POLE; } @@ -85,54 +80,6 @@ bool Domain::contains(const Domain& other) const { } -bool Domain::intersects(Domain& other) const { - auto n = std::min(north_, other.north_); - auto s = std::max(south_, other.south_); - - bool intersectsSN = s <= n; - if (!intersectsSN) { - n = s; - } - - if (isPeriodicWestEast() && other.isPeriodicWestEast()) { - other = {n, other.west_, s, other.east_}; - return intersectsSN; - } - - auto w = std::min(west_, other.west_); - auto e = w; - - auto intersect = [](const Domain& a, const Domain& b, double& w, double& e) { - bool p = a.isPeriodicWestEast(); - if (p || b.isPeriodicWestEast()) { - w = (p ? b : a).west_; - e = (p ? b : a).east_; - return true; - } - - auto ref = PointLonLat::normalise_angle_to_minimum(b.west_, a.west_); - auto w_ = std::max(a.west_, ref); - auto e_ = std::min(a.east_, PointLonLat::normalise_angle_to_minimum(b.east_, ref)); - - if (w_ <= e_) { - w = w_; - e = e_; - return true; - } - - return false; - }; - - bool intersectsWE = west_ <= other.west_ ? intersect(*this, other, w, e) || intersect(other, *this, w, e) - : intersect(other, *this, w, e) || intersect(*this, other, w, e); - - ASSERT_MSG(w <= e, "Domain::intersects: longitude range"); - other = {n, w, s, e}; - - return intersectsSN && intersectsWE; -} - - bool Domain::empty() const { return types::is_approximately_equal(north_, south_) || types::is_approximately_equal(west_, east_); } diff --git a/src/eckit/geo/Domain.h b/src/eckit/geo/Domain.h index 002096d65..fd91cc6f0 100644 --- a/src/eckit/geo/Domain.h +++ b/src/eckit/geo/Domain.h @@ -12,6 +12,8 @@ #pragma once +#include + namespace eckit::geo { @@ -49,14 +51,12 @@ class Domain { double south() const { return south_; } double east() const { return east_; } - bool isGlobal() const; bool includesNorthPole() const; bool includesSouthPole() const; bool isPeriodicWestEast() const; bool contains(double lat, double lon) const; bool contains(const Domain&) const; - bool intersects(Domain&) const; bool empty() const; double area(double radius) const; @@ -109,7 +109,10 @@ class Domain { // None // -- Friends - // None + + friend std::ostream& operator<<(std::ostream& out, const Domain& p) { + return out << '{' << p.north_ << ", " << p.west_ << ", " << p.south_ << ", " << p.east_ << '}'; + } }; diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 3c310ccbe..e6ffb53db 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -74,7 +74,6 @@ GridFactory::GridFactory(const std::string& name) : throw SeriousBug("GridFactory: duplicate '" + name + "'"); } - ASSERT(m->find(name) == m->end()); (*m)[name] = this; } @@ -86,12 +85,12 @@ GridFactory::~GridFactory() { } -const Grid* GridFactory::build(const Configuration& params) { +const Grid* GridFactory::build(const Configuration& config) { pthread_once(&__once, __init); AutoLock lock(*__mutex); std::string name; - if (!params.get("gridType", name)) { + if (!config.get("gridType", name)) { throw SeriousBug("GridFactory: cannot get 'gridType'"); } @@ -101,7 +100,7 @@ const Grid* GridFactory::build(const Configuration& params) { throw SeriousBug("GridFactory: unknown '" + name + "'"); } - return j->second->make(params); + return j->second->make(config); } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 993849639..faa1d1b34 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -20,10 +20,10 @@ #include "eckit/config/Configuration.h" #include "eckit/geo/BoundingBox.h" #include "eckit/geo/Point.h" +#include "eckit/geo/Renumber.h" namespace eckit::geo { -class Renumber; class Domain; class Iterator; } // namespace eckit::geo @@ -55,7 +55,6 @@ class Grid { // -- Methods virtual Iterator* iterator() const; - virtual Renumber crop(BoundingBox&) const; virtual bool includesNorthPole() const; virtual bool includesSouthPole() const; virtual bool isGlobal() const; @@ -63,9 +62,11 @@ class Grid { virtual const BoundingBox& boundingBox() const; virtual size_t numberOfPoints() const; virtual void print(std::ostream&) const; - virtual void reorder(long scanningMode) const; virtual Domain domain() const; + virtual Renumber crop(BoundingBox&) const = 0; + virtual Renumber reorder(long scanningMode) const = 0; + // -- Overridden methods // None @@ -139,7 +140,7 @@ class GridFactory { template class GridBuilder : public GridFactory { - Grid* make(const Configuration& param) override { return new T(param); } + Grid* make(const Configuration& config) override { return new T(config); } public: GridBuilder(const std::string& name) : diff --git a/src/eckit/geo/Increments.cc b/src/eckit/geo/Increments.cc index a4c63df2e..8730f9bd7 100644 --- a/src/eckit/geo/Increments.cc +++ b/src/eckit/geo/Increments.cc @@ -23,5 +23,4 @@ Increments::Increments(const Configuration& config) : } - } // namespace eckit::geo diff --git a/src/eckit/geo/Increments.h b/src/eckit/geo/Increments.h index 2b1d9836b..7bae5b12c 100644 --- a/src/eckit/geo/Increments.h +++ b/src/eckit/geo/Increments.h @@ -45,7 +45,7 @@ class Increments : protected std::array { // -- Friends - friend std::ostream& operator<<(std::ostream&out, const Increments&p) { + friend std::ostream& operator<<(std::ostream& out, const Increments& p) { return out << '{' << p.west_east << ", " << p.south_north << '}'; } }; diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index 5411d1e4a..4ad8e7091 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -56,10 +56,6 @@ class Iterator { const typename X::value_type& operator*() const { return cnt.at(pos); } }; - // -- Constructors - - Iterator() = default; - public: // -- Types @@ -93,7 +89,8 @@ class Iterator { // -- Methods - virtual size_t size() const = 0; + virtual size_t size() const = 0; + virtual size_t index() const = 0; iterator begin() { return {*this, 0}; } iterator end() { return {*this, this->size()}; } @@ -123,7 +120,6 @@ class Iterator { // -- Methods virtual void print(std::ostream&) const = 0; - virtual size_t index() const = 0; // -- Overridden methods // None diff --git a/src/eckit/geo/grid/Albers.cc b/src/eckit/geo/grid/Albers.cc deleted file mode 100644 index 7fdfadbba..000000000 --- a/src/eckit/geo/grid/Albers.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/Albers.h" - -#include - - -namespace eckit::geo::grid { - - -Albers::Albers(const Configuration& /*config*/) {} - - -void Albers::print(std::ostream& out) const { - out << "Albers[" - << "]"; -} - - -static const GridBuilder __repres("albers"); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Albers.h b/src/eckit/geo/grid/Albers.h deleted file mode 100644 index fcbdc73d3..000000000 --- a/src/eckit/geo/grid/Albers.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/RegularGrid.h" - - -namespace eckit::geo::grid { - - -class Albers : public RegularGrid { -public: - // -- Exceptions - // None - - // -- Constructors - - Albers(const Configuration&); - Albers(const Albers&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - Albers& operator=(const Albers&) = delete; - - // -- Methods - // // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/AzimuthRange.cc b/src/eckit/geo/grid/AzimuthRange.cc deleted file mode 100644 index 4ce1fad4b..000000000 --- a/src/eckit/geo/grid/AzimuthRange.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/AzimuthRange.h" - -#include - - -namespace eckit::geo::grid { - - -AzimuthRange::AzimuthRange(const Configuration& /*config*/) {} - - -void AzimuthRange::print(std::ostream& out) const { - out << "AzimuthRange[" - << "]"; -} - - -static const GridBuilder __repres("azimuth_range"); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/AzimuthRange.h b/src/eckit/geo/grid/AzimuthRange.h deleted file mode 100644 index ddce73d16..000000000 --- a/src/eckit/geo/grid/AzimuthRange.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/RegularGrid.h" - - -namespace eckit::geo::grid { - - -class AzimuthRange : public RegularGridGrid { -public: - // -- Exceptions - // None - - // -- Constructors - - AzimuthRange(const Configuration&); - AzimuthRange(const AzimuthRange&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - AzimuthRange& operator=(const AzimuthRange&) = delete; - - // -- Methods - // // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Classic.cc b/src/eckit/geo/grid/Classic.cc deleted file mode 100644 index 565264c28..000000000 --- a/src/eckit/geo/grid/Classic.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/Classic.h" - - -namespace eckit::geo::grid { - - -Classic::Classic(size_t N, const BoundingBox& box, double angularPrecision) : - Reduced(N, box, angularPrecision) { - - // adjust latitudes, longitudes and re-set bounding box - auto n = box.north(); - auto s = box.south(); - correctSouthNorth(s, n); - - setNj(pls("N" + std::to_string(N_)), s, n); - - auto w = box.west(); - auto e = box.east(); - correctWestEast(w, e); - - bbox({n, w, s, e}); -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Classic.h b/src/eckit/geo/grid/Classic.h deleted file mode 100644 index 166779787..000000000 --- a/src/eckit/geo/grid/Classic.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/Reduced.h" - - -namespace eckit::geo::grid { - - -class Classic : public Reduced { -public: - // -- Exceptions - // None - - // -- Constructors - - Classic(size_t, const BoundingBox& = BoundingBox(), double angularPrecision = 0); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.cc b/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.cc deleted file mode 100644 index dd38b1384..000000000 --- a/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/EquatorialAzimuthalEquidistant.h" - -#include - - -namespace eckit::geo::grid { - - -EquatorialAzimuthalEquidistant::EquatorialAzimuthalEquidistant(const Configuration& /*config*/) {} - - -void EquatorialAzimuthalEquidistant::print(std::ostream& out) const { - out << "EquatorialAzimuthalEquidistant[" - << "]"; -} - - -static const GridBuilder __repres("equatorial_azimuthal_equidistant"); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.h b/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.h deleted file mode 100644 index 4d3b8f750..000000000 --- a/src/eckit/geo/grid/EquatorialAzimuthalEquidistant.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/RegularGrid.h" - - -namespace eckit::geo::grid { - - -class EquatorialAzimuthalEquidistant : public RegularGrid { -public: - // -- Exceptions - // None - - // -- Constructors - - EquatorialAzimuthalEquidistant(const Configuration&); - EquatorialAzimuthalEquidistant(const EquatorialAzimuthalEquidistant&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - EquatorialAzimuthalEquidistant& operator=(const EquatorialAzimuthalEquidistant&) = delete; - - // -- Methods - // // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/FromPL.cc b/src/eckit/geo/grid/FromPL.cc deleted file mode 100644 index 0802cde1d..000000000 --- a/src/eckit/geo/grid/FromPL.cc +++ /dev/null @@ -1,27 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/FromPL.h" - - -namespace eckit::geo::grid { - - -FromPL::FromPL(const Configuration& config) : - Reduced(config) {} - - -FromPL::FromPL(size_t N, const std::vector& pl, const BoundingBox& bbox, double angularPrecision) : - Reduced(N, pl, bbox, angularPrecision) {} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/FromPL.h b/src/eckit/geo/grid/FromPL.h deleted file mode 100644 index eac70faba..000000000 --- a/src/eckit/geo/grid/FromPL.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/Reduced.h" - - -namespace eckit::geo::grid { - - -class FromPL : public Reduced { -public: - // -- Exceptions - // None - - // -- Constructors - - FromPL(const Configuration&); - FromPL(size_t, const std::vector&, const BoundingBox& = BoundingBox(), - double angularPrecision = 0); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/GaussianIterator.cc b/src/eckit/geo/grid/GaussianIterator.cc index 499d3be1a..dceae15bb 100644 --- a/src/eckit/geo/grid/GaussianIterator.cc +++ b/src/eckit/geo/grid/GaussianIterator.cc @@ -14,14 +14,14 @@ #include +#include "eckit/exception/Exceptions.h" + namespace eckit::geo::grid { GaussianIterator::GaussianIterator(const std::vector& latitudes, std::vector&& pl, - const BoundingBox& bbox, size_t N, size_t Nj, size_t k, - const Rotation& rotation) : - Iterator(rotation), + const BoundingBox& bbox, size_t N, size_t Nj, size_t k) : latitudes_(latitudes), pl_(pl), bbox_(bbox), @@ -51,15 +51,15 @@ size_t GaussianIterator::resetToRow(size_t j) { auto Ni_globe = pl_[j]; ASSERT(Ni_globe > 1); - inc_ = GLOBE.fraction() / Ni_globe; + inc_ = Fraction(GLOBE) / Ni_globe; - const auto w = bbox_.west().fraction(); + const auto w = Fraction(bbox_.west()); auto Nw = (w / inc_).integralPart(); if (Nw * inc_ < w) { Nw += 1; } - const auto e = bbox_.east().fraction(); + const auto e = Fraction(bbox_.east()); auto Ne = (e / inc_).integralPart(); if (Ne * inc_ > e) { Ne -= 1; @@ -110,4 +110,9 @@ size_t GaussianIterator::index() const { } +size_t GaussianIterator::size() const { + NOTIMP; +} + + } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/GaussianIterator.h b/src/eckit/geo/grid/GaussianIterator.h index cdd53685e..11286a0d3 100644 --- a/src/eckit/geo/grid/GaussianIterator.h +++ b/src/eckit/geo/grid/GaussianIterator.h @@ -18,6 +18,7 @@ #include "eckit/geo/BoundingBox.h" #include "eckit/geo/Iterator.h" +#include "eckit/geo/Projection.h" namespace eckit::geo::grid { @@ -26,7 +27,7 @@ namespace eckit::geo::grid { class GaussianIterator : public Iterator { public: GaussianIterator(const std::vector& latitudes, std::vector&& pl, const BoundingBox&, size_t N, - size_t Nj, size_t k, const Rotation& = Rotation()); + size_t Nj, size_t k); ~GaussianIterator() override; private: @@ -45,10 +46,11 @@ class GaussianIterator : public Iterator { size_t count_; bool first_; -protected: void print(std::ostream&) const override; bool operator++() override; size_t index() const override; + size_t size() const override; + size_t resetToRow(size_t j); }; diff --git a/src/eckit/geo/grid/IrregularLatlon.cc b/src/eckit/geo/grid/IrregularLatlon.cc index 8dbca433d..985fcfdfc 100644 --- a/src/eckit/geo/grid/IrregularLatlon.cc +++ b/src/eckit/geo/grid/IrregularLatlon.cc @@ -18,6 +18,7 @@ #include "eckit/utils/MD5.h" #include "eckit/geo/Iterator.h" +#include "eckit/geo/Projection.h" namespace eckit::geo::grid { @@ -39,7 +40,8 @@ static void range(const std::vector& v, double& mn, double& mx, double& } -IrregularLatlon::IrregularLatlon(const Configuration& config) { +IrregularLatlon::IrregularLatlon(const Configuration& config) : + Grid(config) { ASSERT(config.get("latitudes", latitudes_)); range(latitudes_, south_, north_, south_north_); @@ -101,6 +103,8 @@ class IrregularLatlonIterator : public Iterator { size_t index() const override { return count_; } + size_t size() const override { NOTIMP; } + public: // TODO: Consider keeping a reference on the latitudes and bbox, to avoid copying @@ -132,17 +136,17 @@ Iterator* IrregularLatlon::iterator() const { bool IrregularLatlon::isPeriodicWestEast() const { - return (east_ - west_) + west_east_ >= GLOBE.value(); + return (east_ - west_) + west_east_ >= GLOBE; } bool IrregularLatlon::includesNorthPole() const { - return north_ + south_north_ >= NORTH_POLE.value(); + return north_ + south_north_ >= NORTH_POLE; } bool IrregularLatlon::includesSouthPole() const { - return south_ - south_north_ <= SOUTH_POLE.value(); + return south_ - south_north_ <= SOUTH_POLE; } diff --git a/src/eckit/geo/grid/Lambert.cc b/src/eckit/geo/grid/Lambert.cc deleted file mode 100644 index 681b76eef..000000000 --- a/src/eckit/geo/grid/Lambert.cc +++ /dev/null @@ -1,59 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/Lambert.h" - -#include "eckit/config/MappedConfiguration.h" - - -namespace eckit::geo::grid { - - -static const GridBuilder __builder("lambert"); - - -Lambert::Lambert(const Configuration& config) : - RegularGrid(config, make_projection(config)) { - auto edition = config.getLong("edition", 0); - - // GRIB1 cannot write LaD - writeLaDInDegrees_ = edition == 2; - config.get("writeLaDInDegrees", writeLaDInDegrees_); - - // GRIB2 cannot write negative longitude values - writeLonPositive_ = edition == 2; - config.get("writeLonPositive", writeLonPositive_); -} - - -Projection* Lambert::make_projection(const Configuration& config) { -#if 0 - auto spec = make_proj_spec(config); - if (!spec.empty()) { - return spec; - } -#endif - - auto LaDInDegrees = config.getDouble("LaDInDegrees"); - auto LoVInDegrees = config.getDouble("LoVInDegrees"); - auto Latin1InDegrees = config.getDouble("Latin1InDegrees", LaDInDegrees); - auto Latin2InDegrees = config.getDouble("Latin2InDegrees", LaDInDegrees); - - return ProjectionFactory::build("lambert_conformal_conic", - MappedConfiguration({{"latitude1", Latin1InDegrees}, - {"latitude2", Latin2InDegrees}, - {"latitude0", LaDInDegrees}, - {"longitude0", LoVInDegrees}})); -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Lambert.h b/src/eckit/geo/grid/Lambert.h deleted file mode 100644 index 0552731b2..000000000 --- a/src/eckit/geo/grid/Lambert.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/RegularGrid.h" - - -namespace eckit::geo::grid { - - -class Lambert : public RegularGrid { -public: - // -- Exceptions - // None - - // -- Constructors - - Lambert(const Configuration&); - Lambert(const Lambert&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - Lambert& operator=(const Lambert&) = delete; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - bool writeLaDInDegrees_; - bool writeLonPositive_; - - // -- Methods - - static Projection* make_projection(const Configuration&); - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/LambertAzimuthalEqualArea.cc b/src/eckit/geo/grid/LambertAzimuthalEqualArea.cc deleted file mode 100644 index 677ed6d28..000000000 --- a/src/eckit/geo/grid/LambertAzimuthalEqualArea.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/LambertAzimuthalEqualArea.h" - -#include - -#include "eckit/geo/Iterator.h" - - -namespace eckit::geo::grid { - - -static const GridBuilder __builder("lambert_azimuthal_equal_area"); - - -LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Configuration& param) : - RegularGrid(param, make_projection(param)) {} - - -LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Projection& projection, const BoundingBox& bbox, - const LinearSpacing& x, const LinearSpacing& y, - const Shape& shape) : - RegularGrid(projection, bbox, x, y, shape) {} - - -Projection LambertAzimuthalEqualArea::make_projection(const Configuration& param) { - auto spec = make_proj_spec(param); - if (!spec.empty()) { - return spec; - } - - double standardParallel = 0.; - double centralLongitude = 0.; - double radius = 0.; - ASSERT(param.get("standardParallelInDegrees", standardParallel)); - ASSERT(param.get("centralLongitudeInDegrees", centralLongitude)); - param.get("radius", radius = Earth::radius()); - - return Configuration("type", "lambert_azimuthal_equal_area") - .set("standard_parallel", standardParallel) - .set("central_longitude", centralLongitude) - .set("radius", radius); -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/LambertAzimuthalEqualArea.h b/src/eckit/geo/grid/LambertAzimuthalEqualArea.h deleted file mode 100644 index 803d12ddc..000000000 --- a/src/eckit/geo/grid/LambertAzimuthalEqualArea.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/RegularGrid.h" - - -namespace eckit::geo::grid { - - -class LambertAzimuthalEqualArea : public RegularGrid { -public: - // -- Exceptions - // None - - // -- Constructors - - LambertAzimuthalEqualArea(const Configuration&); - LambertAzimuthalEqualArea(const Projection&, const BoundingBox&, const LinearSpacing& x, - const LinearSpacing& y, const Shape&); - LambertAzimuthalEqualArea(const LambertAzimuthalEqualArea&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - LambertAzimuthalEqualArea& operator=(const LambertAzimuthalEqualArea&) = delete; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - - static Projection make_projection(const Configuration&); - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Mercator.cc b/src/eckit/geo/grid/Mercator.cc deleted file mode 100644 index 10512257b..000000000 --- a/src/eckit/geo/grid/Mercator.cc +++ /dev/null @@ -1,26 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/Mercator.h" - - -namespace eckit::geo::grid { - - -static const GridBuilder __builder("mercator"); - - -Mercator::Mercator(const Configuration& param) : - RegularGrid(param, make_proj_spec(param)) {} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Mercator.h b/src/eckit/geo/grid/Mercator.h deleted file mode 100644 index f16febd81..000000000 --- a/src/eckit/geo/grid/Mercator.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/RegularGrid.h" - - -namespace eckit::geo::grid { - - -class Mercator : public RegularGrid { -public: - // -- Exceptions - // None - - // -- Constructors - - Mercator(const Configuration&); - Mercator(const Mercator&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - Mercator& operator=(const Mercator&) = delete; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/None.cc b/src/eckit/geo/grid/None.cc deleted file mode 100644 index 58204f7b5..000000000 --- a/src/eckit/geo/grid/None.cc +++ /dev/null @@ -1,38 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/None.h" - -#include - - -namespace eckit::geo::grid { - - -None::None() = default; - - -None::None(const Configuration& /*unused*/) {} - - -None::~None() = default; - - -void None::print(std::ostream& out) const { - out << "None[]"; -} - - -static const GridBuilder builder("none"); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/None.h b/src/eckit/geo/grid/None.h deleted file mode 100644 index 21852e240..000000000 --- a/src/eckit/geo/grid/None.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Grid.h" - - -namespace eckit::geo::grid { - - -class None : public Grid { -public: - // -- Exceptions - // None - - // -- Constructors - - None(); - None(const Configuration&); - None(const None&) = delete; - - // -- Destructor - - ~None() override; - - // -- Convertors - // None - - // -- Operators - - None& operator=(const None&) = delete; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - void print(std::ostream&) const override; - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ORCA.cc b/src/eckit/geo/grid/ORCA.cc index 80dcbd341..5e9711636 100644 --- a/src/eckit/geo/grid/ORCA.cc +++ b/src/eckit/geo/grid/ORCA.cc @@ -17,6 +17,7 @@ #include #include "eckit/geo/Iterator.h" +#include "eckit/geo/Projection.h" namespace eckit::geo::grid { @@ -31,10 +32,10 @@ ORCA::ORCA(const std::string& uid) : Grid(BoundingBox() /*assumed global*/), spec_(atlas::grid::SpecRegistry::get(uid)) {} -ORCA::ORCA(const Configuration& param) : - ORCA([¶m]() { +ORCA::ORCA(const Configuration& config) : + ORCA([&config]() { std::string uid; - ASSERT(param.get("uid", uid)); + ASSERT(config.get("uid", uid)); return uid; }()) {} @@ -93,6 +94,8 @@ Iterator* ORCA::iterator() const { size_t index() const override { return count_; } + size_t size() const override { NOTIMP; } + public: ORCAIterator(::atlas::Grid grid) : grid_(grid), diff --git a/src/eckit/geo/grid/Octahedral.cc b/src/eckit/geo/grid/Octahedral.cc deleted file mode 100644 index a9956178e..000000000 --- a/src/eckit/geo/grid/Octahedral.cc +++ /dev/null @@ -1,37 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/Octahedral.h" - - -namespace eckit::geo::grid { - - -Octahedral::Octahedral(size_t N, const BoundingBox& box, double angularPrecision) : - Reduced(N, box, angularPrecision) { - - // adjust latitudes, longitudes and re-set bounding box - auto n = bbox().north(); - auto s = bbox().south(); - correctSouthNorth(s, n); - - setNj(pls("O" + std::to_string(N_)), s, n); - - auto w = bbox().west(); - auto e = bbox().east(); - correctWestEast(w, e); - - bbox({n, w, s, e}); -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Octahedral.h b/src/eckit/geo/grid/Octahedral.h deleted file mode 100644 index 23f70f748..000000000 --- a/src/eckit/geo/grid/Octahedral.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/Reduced.h" - - -namespace eckit::geo::grid { - - -class Octahedral : public Reduced { -public: - // -- Exceptions - // None - - // -- Constructors - - Octahedral(size_t, const BoundingBox& = BoundingBox(), double angularPrecision = 0); - - // -- Destructor - - virtual ~Octahedral() override = default; - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/PolarStereographic.cc b/src/eckit/geo/grid/PolarStereographic.cc deleted file mode 100644 index c86946536..000000000 --- a/src/eckit/geo/grid/PolarStereographic.cc +++ /dev/null @@ -1,26 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/PolarStereographic.h" - - -namespace eckit::geo::grid { - - -static const GridBuilder __builder("polar_stereographic"); - - -PolarStereographic::PolarStereographic(const Configuration& param) : - RegularGrid(param, make_proj_spec(param)) {} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/PolarStereographic.h b/src/eckit/geo/grid/PolarStereographic.h deleted file mode 100644 index 4383a658c..000000000 --- a/src/eckit/geo/grid/PolarStereographic.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/RegularGrid.h" - - -namespace eckit::geo::grid { - - -class PolarStereographic : public RegularGrid { -public: - // -- Exceptions - // None - - // -- Constructors - - PolarStereographic(const Configuration&); - PolarStereographic(const PolarStereographic&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - PolarStereographic& operator=(const PolarStereographic&) = delete; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedClassic.cc b/src/eckit/geo/grid/ReducedClassic.cc deleted file mode 100644 index 7dfc8e095..000000000 --- a/src/eckit/geo/grid/ReducedClassic.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/ReducedClassic.h" - -#include - - -namespace eckit::geo::grid { - - -ReducedClassic::ReducedClassic(size_t N, const BoundingBox& bbox, double angularPrecision) : - Classic(N, bbox, angularPrecision) {} - - -void ReducedClassic::print(std::ostream& out) const { - out << "ReducedClassic[N=" << N_ << ",bbox=" << bbox() << "]"; -} - - -Iterator* ReducedClassic::iterator() const { - return unrotatedIterator(); -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedClassic.h b/src/eckit/geo/grid/ReducedClassic.h deleted file mode 100644 index 7f8557a53..000000000 --- a/src/eckit/geo/grid/ReducedClassic.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/Classic.h" - - -namespace eckit::geo::grid { - - -class ReducedClassic : public Classic { -public: - // -- Exceptions - // None - - // -- Constructors - - ReducedClassic(size_t, const BoundingBox& = BoundingBox(), double angularPrecision = 0); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - Iterator* iterator() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedFromPL.cc b/src/eckit/geo/grid/ReducedFromPL.cc deleted file mode 100644 index d7197e0c6..000000000 --- a/src/eckit/geo/grid/ReducedFromPL.cc +++ /dev/null @@ -1,43 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/ReducedFromPL.h" - -#include - - -namespace eckit::geo::grid { - - -ReducedFromPL::ReducedFromPL(const Configuration& config) : - FromPL(config) {} - - -ReducedFromPL::ReducedFromPL(size_t N, const std::vector& pl, const BoundingBox& bbox, - double angularPrecision) : - FromPL(N, pl, bbox, angularPrecision) {} - - -void ReducedFromPL::print(std::ostream& out) const { - out << "ReducedFromPL[N=" << N_ << ",bbox=" << bbox() << "]"; -} - - -Iterator* ReducedFromPL::iterator() const { - return unrotatedIterator(); -} - - -static const GridBuilder reducedFromPL("reduced_gg"); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedFromPL.h b/src/eckit/geo/grid/ReducedFromPL.h deleted file mode 100644 index 260ee374c..000000000 --- a/src/eckit/geo/grid/ReducedFromPL.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/FromPL.h" - - -namespace eckit::geo::grid { - - -class ReducedFromPL : public FromPL { -public: - // -- Exceptions - // None - - // -- Constructors - - ReducedFromPL(const Configuration&); - ReducedFromPL(size_t, const std::vector&, const BoundingBox& = BoundingBox(), - double angularPrecision = 0); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - Iterator* iterator() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Reduced.cc b/src/eckit/geo/grid/ReducedGG.cc similarity index 67% rename from src/eckit/geo/grid/Reduced.cc rename to src/eckit/geo/grid/ReducedGG.cc index 9244a44f2..4672e0193 100644 --- a/src/eckit/geo/grid/Reduced.cc +++ b/src/eckit/geo/grid/ReducedGG.cc @@ -10,40 +10,26 @@ */ -#include "eckit/geo/grid/Reduced.h" +#include "eckit/geo/grid/ReducedGG.h" #include #include #include #include #include +#include #include #include -#include "eckit/geo/grid/GaussianIterator.h" +#include "eckit/geo/Iterator.h" +#include "eckit/geo/Projection.h" #include "eckit/types/Fraction.h" namespace eckit::geo::grid { -template -std::vector pl_convert(const T& nx) { - ASSERT(!nx.empty()); - std::vector pl(nx.size()); - std::transform(nx.begin(), nx.end(), pl.begin(), [](typename T::value_type p) { return long(p); }); - return pl; -} - - -template <> -std::vector pl_convert(const std::vector& nx) { - ASSERT(!nx.empty()); - return nx; -} - - -Reduced::Reduced(const Configuration& config) : +ReducedGG::ReducedGG(const Configuration& config) : Gaussian(config), k_(0), Nj_(N_ * 2) { // adjust latitudes, longitudes and re-set bounding box @@ -51,7 +37,7 @@ Reduced::Reduced(const Configuration& config) : auto s = bbox().south(); correctSouthNorth(s, n); - std::vector pl; + pl_type pl; ASSERT(config.get("pl", pl)); // if pl isn't global (from file!) insert leading/trailing 0's @@ -90,33 +76,21 @@ Reduced::Reduced(const Configuration& config) : } -Reduced::Reduced(size_t N, const std::vector& pl, const BoundingBox& bbox, double angularPrecision) : - Gaussian(N, bbox, angularPrecision), k_(0), Nj_(N_ * 2) { - setNj(pl, bbox.south(), bbox.north()); -} - - -Reduced::Reduced(size_t N, const BoundingBox& bbox, double angularPrecision) : - Gaussian(N, bbox, angularPrecision), k_(0), Nj_(N * 2) { - // derived classes must set k_, Nj_ using this constructor -} - - -void Reduced::correctWestEast(double& w, double& e) const { +void ReducedGG::correctWestEast(double& w, double& e) const { ASSERT(w <= e); const Fraction smallestIncrement = getSmallestIncrement(); ASSERT(smallestIncrement > 0); - if (angleApproximatelyEqual(GREENWICH, w) && (angleApproximatelyEqual(GLOBE - smallestIncrement, e - w) || GLOBE - smallestIncrement < e - w || (e != w && e.normalise(w) == w))) { + if (angleApproximatelyEqual(GREENWICH, w) && (angleApproximatelyEqual(GLOBE - smallestIncrement, e - w) || GLOBE - smallestIncrement < e - w || (e != w && PointLonLat::normalise_angle_to_minimum(e, w) == w))) { w = GREENWICH; e = GLOBE - smallestIncrement; } else { - const Fraction west = w.fraction(); - const Fraction east = e.fraction(); + const Fraction west{w}; + const Fraction east{e}; Fraction W = west; Fraction E = east; @@ -131,7 +105,7 @@ void Reduced::correctWestEast(double& w, double& e) const { ASSERT(Ni >= 2); if (NiTried.insert(Ni).second) { - Fraction inc = GLOBE.fraction() / Ni; + Fraction inc = Fraction{GLOBE} / Ni; Fraction::value_type Nw = (west / inc).integralPart(); if (Nw * inc < west) { @@ -166,19 +140,7 @@ void Reduced::correctWestEast(double& w, double& e) const { } -Iterator* Reduced::unrotatedIterator() const { - auto pl = pls(); - return new GaussianIterator(latitudes(), std::move(pl), bbox(), N_, Nj_, k_); -} - - -Iterator* Reduced::rotatedIterator(const Rotation& rotation) const { - auto pl = pls(); - return new GaussianIterator(latitudes(), std::move(pl), bbox(), N_, Nj_, k_, rotation); -} - - -const std::vector& Reduced::pls() const { +const pl_type& ReducedGG::pls() const { ASSERT(pl_.size() == N_ * 2); ASSERT(pl_.size() >= k_ + Nj_); ASSERT(Nj_ > 0); @@ -187,14 +149,7 @@ const std::vector& Reduced::pls() const { } -std::vector Reduced::pls(const std::string& name) { - atlas::ReducedGaussianGrid grid(name); - ASSERT(grid); - return pl_convert(grid.nx()); -} - - -void Reduced::setNj(std::vector pl, double s, double n) { +void ReducedGG::setNj(pl_type pl, double s, double n) { ASSERT(0 < N_ && N_ * 2 == pl.size()); // position to first latitude and first/last longitude @@ -227,24 +182,81 @@ void Reduced::setNj(std::vector pl, double s, double n) { } -size_t Reduced::numberOfPoints() const { +size_t ReducedGG::numberOfPoints() const { if (isGlobal()) { const auto& pl = pls(); return size_t(std::accumulate(pl.begin(), pl.end(), 0L)); } size_t total = 0; - for (const std::unique_ptr it(iterator()); it->next();) { + for (const std::unique_ptr it(iterator()); ++(*it);) { total++; } return total; } -bool Reduced::isPeriodicWestEast() const { +bool ReducedGG::isPeriodicWestEast() const { auto inc = getSmallestIncrement(); - return bbox_.east() - bbox_.west() + inc >= GLOBE; + return bbox().east() - bbox().west() + inc >= GLOBE; +} + + +void ReducedGG::print(std::ostream& out) const { + out << "ReducedClassic[N=" << N_ << ",bbox=" << bbox() << "]"; } +struct ReducedGGClassic : ReducedGG { + ReducedGGClassic(size_t N, const BoundingBox& box= BoundingBox()) : + ReducedGG(N, box) { + + // adjust latitudes, longitudes and re-set bounding box + auto n = box.north(); + auto s = box.south(); + correctSouthNorth(s, n); + + setNj(pls("N" + std::to_string(N_)), s, n); + + auto w = box.west(); + auto e = box.east(); + correctWestEast(w, e); + + bbox({n, w, s, e}); + } +}; + + + + + +struct ReducedGGFromPL : ReducedGG { + ReducedGGFromPL(const Configuration& config) : + ReducedGG(config) {} + ReducedGGFromPL(size_t N, const pl_type& pl, const BoundingBox& box = BoundingBox()) : + ReducedGG(N, pl, box) {} +}; + + +struct ReducedGGOctahedral : ReducedGG { + ReducedGGOctahedral(size_t N, const BoundingBox& box = BoundingBox()) : + ReducedGG(N, box) { + + // adjust latitudes, longitudes and re-set bounding box + auto [n, w, s, e] = bbox().deconstruct(); + + correctSouthNorth(s, n); + + setNj(pls("O" + std::to_string(N_)), s, n); + + correctWestEast(w, e); + + bbox({n, w, s, e}); + } +}; + + +static const GridBuilder reducedFromPL("reduced_gg"); + + } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Reduced.h b/src/eckit/geo/grid/ReducedGG.h similarity index 66% rename from src/eckit/geo/grid/Reduced.h rename to src/eckit/geo/grid/ReducedGG.h index ead9d0733..a9ad52752 100644 --- a/src/eckit/geo/grid/Reduced.h +++ b/src/eckit/geo/grid/ReducedGG.h @@ -13,25 +13,29 @@ #pragma once #include "eckit/geo/grid/Gaussian.h" +#include "eckit/geo/util.h" namespace eckit::geo::grid { -class Reduced : public Gaussian { +class ReducedGG : public Gaussian { public: // -- Exceptions // None // -- Constructors - Reduced(const Configuration&); - Reduced(size_t N, const std::vector& pl, const BoundingBox& = BoundingBox(), - double angularPrecision = 0); + ReducedGG(const Configuration&); + + ReducedGG(size_t N, const pl_type& pl, const BoundingBox& box = BoundingBox()) : + Gaussian(N, box), k_(0), Nj_(N_ * 2) { + setNj(pl, box.south(), box.north()); + } // -- Destructor - ~Reduced() override = default; + ~ReducedGG() override = default; // -- Convertors // None @@ -41,7 +45,7 @@ class Reduced : public Gaussian { // -- Methods - static std::vector pls(const std::string&); + static pl_type pls(const std::string&); // -- Overridden methods // None @@ -55,7 +59,10 @@ class Reduced : public Gaussian { protected: // -- Constructors - Reduced(size_t N, const BoundingBox& = BoundingBox(), double angularPrecision = 0); + ReducedGG(size_t N, const BoundingBox& box = BoundingBox()) : + Gaussian(N, box), k_(0), Nj_(N * 2) { + // derived classes must set k_, Nj_ using this constructor + } // -- Members @@ -64,14 +71,15 @@ class Reduced : public Gaussian { // -- Methods - const std::vector& pls() const; + const pl_type& pls() const; - void setNj(std::vector, double s, double n); + void setNj(pl_type, double s, double n); void correctWestEast(double& w, double& e) const; // -- Overridden methods bool isPeriodicWestEast() const override; + void print(std::ostream& out) const override; // -- Class members @@ -81,7 +89,7 @@ class Reduced : public Gaussian { private: // -- Members - std::vector pl_; + pl_type pl_; // -- Methods // None diff --git a/src/eckit/geo/grid/ReducedLL.cc b/src/eckit/geo/grid/ReducedLL.cc index 5fd525c0e..6f59d8bfb 100644 --- a/src/eckit/geo/grid/ReducedLL.cc +++ b/src/eckit/geo/grid/ReducedLL.cc @@ -17,7 +17,9 @@ #include #include +#include "eckit/geo/Domain.h" #include "eckit/geo/Iterator.h" +#include "eckit/geo/Projection.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" @@ -102,12 +104,12 @@ class ReducedLLIterator : public Iterator { << ",count=" << count_ << "]"; } - bool next(double& lat, double& lon) override { + bool operator++() override { while (j_ < nj_ && i_ < ni_) { - lat = latitude_; - lon = longitude_; + // lat = latitude_; + // lon = longitude_; - bool contains = domain_.contains(lat, lon); + bool contains = domain_.contains(latitude_, longitude_); if (contains && !first_) { count_++; } @@ -138,15 +140,17 @@ class ReducedLLIterator : public Iterator { size_t index() const override { return count_; } + size_t size() const override { NOTIMP; } + public: ReducedLLIterator(const std::vector& pl, const Domain& dom) : pl_(pl), nj_(pl.size()), domain_(dom), - west_(domain_.west().fraction()), - ew_((domain_.east() - domain_.west()).fraction()), - inc_north_south_((domain_.north() - domain_.south()).fraction() / Fraction(nj_ - 1)), - latitude_(domain_.north().fraction()), + west_(domain_.west()), + ew_((domain_.east() - domain_.west())), + inc_north_south_(Fraction(domain_.north() - domain_.south()) / Fraction(nj_ - 1)), + latitude_(domain_.north()), longitude_(west_), i_(0), j_(0), diff --git a/src/eckit/geo/grid/ReducedOctahedral.cc b/src/eckit/geo/grid/ReducedOctahedral.cc deleted file mode 100644 index 97a130333..000000000 --- a/src/eckit/geo/grid/ReducedOctahedral.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/ReducedOctahedral.h" - -#include - - -namespace eckit::geo::grid { - - -ReducedOctahedral::ReducedOctahedral(size_t N, const BoundingBox& bbox, double angularPrecision) : - Octahedral(N, bbox, angularPrecision) {} - - -void ReducedOctahedral::print(std::ostream& out) const { - out << "ReducedOctahedral[N=" << N_ << ",bbox=" << bbox() << "]"; -} - - -Iterator* ReducedOctahedral::iterator() const { - return unrotatedIterator(); -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedOctahedral.h b/src/eckit/geo/grid/ReducedOctahedral.h deleted file mode 100644 index 63614e244..000000000 --- a/src/eckit/geo/grid/ReducedOctahedral.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/Octahedral.h" - - -namespace eckit::geo::grid { - - -class ReducedOctahedral : public Octahedral { -public: - // -- Exceptions - // None - - // -- Constructors - - ReducedOctahedral(size_t, const BoundingBox& = BoundingBox(), double angularPrecision = 0); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - Iterator* iterator() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc deleted file mode 100644 index e78e9eeea..000000000 --- a/src/eckit/geo/grid/Regular.cc +++ /dev/null @@ -1,159 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/Regular.h" - -#include "eckit/types/FloatCompare.h" -#include "eckit/types/Fraction.h" - - -namespace eckit::geo::grid { - - -Regular::Regular(const Configuration& config) : - Gaussian(config), k_(0), Ni_(0), Nj_(0) { - // adjust latitudes, longitudes and re-set bounding box - auto n = bbox().north(); - auto s = bbox().south(); - correctSouthNorth(s, n); - - auto e = bbox().east(); - auto w = bbox().west(); - correctWestEast(w, e); - - bbox({n, w, s, e}); - - setNiNj(); -} - - -Regular::Regular(size_t N, const BoundingBox& box, double angularPrecision) : - Gaussian(N, box, angularPrecision), k_(0), Ni_(0), Nj_(0) { - - // adjust latitudes, longitudes and re-set bounding box - auto n = box.north(); - auto s = box.south(); - correctSouthNorth(s, n); - - auto w = box.west(); - auto e = box.east(); - correctWestEast(w, e); - - bbox({n, w, s, e}); - - setNiNj(); -} - - -void Regular::correctWestEast(double& w, double& e) const { - ASSERT(w <= e); - - auto inc = getSmallestIncrement(); - ASSERT(inc > 0); - - if (angleApproximatelyEqual(GREENWICH, w) && (angleApproximatelyEqual(GLOBE - inc, e - w) || GLOBE - inc < e - w || (e != w && e.normalise(w) == w))) { - w = GREENWICH; - e = GLOBE - inc; - return; - } - - const Fraction west = w; - const Fraction east = e; - - Fraction::value_type Nw = (west / inc).integralPart(); - if (Nw * inc < west) { - Nw += 1; - } - - Fraction::value_type Ne = (east / inc).integralPart(); - if (Ne * inc > east) { - Ne -= 1; - } - - ASSERT(Nw <= Ne); - w = Nw * inc; - e = Ne * inc; -} - - -eckit::Fraction Regular::getSmallestIncrement() const { - ASSERT(N_); - return {90, Fraction::value_type(N_)}; -} - - -size_t Regular::numberOfPoints() const { - ASSERT(Ni_); - ASSERT(Nj_); - return Ni_ * Nj_; -} - - -bool Regular::isPeriodicWestEast() const { - auto inc = getSmallestIncrement(); - return bbox().east() - bbox().west() + inc >= GLOBE; -} - - -void Regular::setNiNj() { - ASSERT(N_); - - const auto inc = getSmallestIncrement(); - const auto& lats = latitudes(); - - Fraction w(bbox().west()); - Fraction e(bbox().east()); - Fraction s(bbox().south()); - Fraction n(bbox().north()); - - Ni_ = N_ * 4; - - if (e - w + inc < GLOBE) { - - auto Nw = (w / inc).integralPart(); - if (Nw * inc < w) { - Nw += 1; - } - - auto Ne = (e / inc).integralPart(); - if (Ne * inc > e) { - Ne -= 1; - } - - ASSERT(Ne - Nw + 1 > 0); - Ni_ = size_t(Ne - Nw + 1); - - ASSERT(2 <= Ni_ && Ni_ <= N_ * 4); - } - - k_ = 0; - Nj_ = N_ * 2; - - if (n < lats.front() || s > lats.back()) { - Nj_ = 0; - for (auto lat : lats) { - if (n < lat && !angleApproximatelyEqual(n, lat)) { - ++k_; - } - else if (s <= lat || angleApproximatelyEqual(s, lat)) { - ++Nj_; - } - else { - break; - } - } - ASSERT(Nj_ > 0); - } -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h deleted file mode 100644 index c040ae665..000000000 --- a/src/eckit/geo/grid/Regular.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/Gaussian.h" - - -namespace eckit::geo::grid { - - -class Regular : public Gaussian { -public: - // -- Exceptions - // None - - // -- Constructors - - Regular(const Configuration&); - Regular(size_t N, const BoundingBox& = BoundingBox(), double angularPrecision = 0); - - // -- Destructor - - virtual ~Regular() override = default; - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Constructors - // None - - // -- Members - - size_t k_; - size_t Ni_; - size_t Nj_; - - // -- Methods - - void correctWestEast(double& w, double& e) const; - void setNiNj(); - - // -- Overridden methods - - bool isPeriodicWestEast() const override; - - // -- Class members - // None - - // -- Class methods - // None - -private: - Regular(); - - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - size_t numberOfPoints() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularGG.cc b/src/eckit/geo/grid/RegularGG.cc index f35489f1d..f15de390b 100644 --- a/src/eckit/geo/grid/RegularGG.cc +++ b/src/eckit/geo/grid/RegularGG.cc @@ -17,17 +17,149 @@ #include #include "eckit/geo/grid/GaussianIterator.h" +#include "eckit/geo/grid/RegularGG.h" +#include "eckit/types/FloatCompare.h" +#include "eckit/types/Fraction.h" namespace eckit::geo::grid { RegularGG::RegularGG(const Configuration& config) : - Regular(config) {} + Gaussian(config), k_(0), Ni_(0), Nj_(0) { + // adjust latitudes, longitudes and re-set bounding box + auto n = bbox().north(); + auto s = bbox().south(); + correctSouthNorth(s, n); + + auto e = bbox().east(); + auto w = bbox().west(); + correctWestEast(w, e); + + bbox({n, w, s, e}); + + setNiNj(); +} + + +RegularGG::RegularGG(size_t N, const BoundingBox& box) : + Gaussian(N, box), k_(0), Ni_(0), Nj_(0) { + + // adjust latitudes, longitudes and re-set bounding box + auto n = box.north(); + auto s = box.south(); + correctSouthNorth(s, n); + + auto w = box.west(); + auto e = box.east(); + correctWestEast(w, e); + + bbox({n, w, s, e}); + + setNiNj(); +} + +void RegularGG::correctWestEast(double& w, double& e) const { + ASSERT(w <= e); -RegularGG::RegularGG(size_t N, const BoundingBox& bbox, double angularPrecision) : - Regular(N, bbox, angularPrecision) {} + auto inc = getSmallestIncrement(); + ASSERT(inc > 0); + + if (angleApproximatelyEqual(GREENWICH, w) && (angleApproximatelyEqual(GLOBE - inc, e - w) || GLOBE - inc < e - w || (e != w && PointLonLat::normalise_angle_to_minimum(e, w) == w))) { + w = GREENWICH; + e = GLOBE - inc; + return; + } + + const Fraction west{w}; + const Fraction east{e}; + + Fraction::value_type Nw = (west / inc).integralPart(); + if (Nw * inc < west) { + Nw += 1; + } + + Fraction::value_type Ne = (east / inc).integralPart(); + if (Ne * inc > east) { + Ne -= 1; + } + + ASSERT(Nw <= Ne); + w = Nw * inc; + e = Ne * inc; +} + + +Fraction RegularGG::getSmallestIncrement() const { + ASSERT(N_); + return {90, Fraction::value_type(N_)}; +} + + +size_t RegularGG::numberOfPoints() const { + ASSERT(Ni_); + ASSERT(Nj_); + return Ni_ * Nj_; +} + + +bool RegularGG::isPeriodicWestEast() const { + auto inc = getSmallestIncrement(); + return bbox().east() - bbox().west() + inc >= GLOBE; +} + + +void RegularGG::setNiNj() { + ASSERT(N_); + + const auto inc = getSmallestIncrement(); + const auto& lats = latitudes(); + + Fraction w(bbox().west()); + Fraction e(bbox().east()); + Fraction s(bbox().south()); + Fraction n(bbox().north()); + + Ni_ = N_ * 4; + + if (e - w + inc < GLOBE) { + + auto Nw = (w / inc).integralPart(); + if (Nw * inc < w) { + Nw += 1; + } + + auto Ne = (e / inc).integralPart(); + if (Ne * inc > e) { + Ne -= 1; + } + + ASSERT(Ne - Nw + 1 > 0); + Ni_ = size_t(Ne - Nw + 1); + + ASSERT(2 <= Ni_ && Ni_ <= N_ * 4); + } + + k_ = 0; + Nj_ = N_ * 2; + + if (n < lats.front() || s > lats.back()) { + Nj_ = 0; + for (auto lat : lats) { + if (n < lat && !angleApproximatelyEqual(n, lat)) { + ++k_; + } + else if (s <= lat || angleApproximatelyEqual(s, lat)) { + ++Nj_; + } + else { + break; + } + } + ASSERT(Nj_ > 0); + } +} void RegularGG::print(std::ostream& out) const { @@ -43,6 +175,18 @@ Iterator* RegularGG::iterator() const { } +Renumber RegularGG::crop(BoundingBox&) const { + NOTIMP; +} + + +Renumber RegularGG::reorder(long /*scanningMode*/) const { + NOTIMP; +} + + + + static const GridBuilder reducedGG("regular_gg"); diff --git a/src/eckit/geo/grid/RegularGG.h b/src/eckit/geo/grid/RegularGG.h index 55ad2dd82..bfab2f5d8 100644 --- a/src/eckit/geo/grid/RegularGG.h +++ b/src/eckit/geo/grid/RegularGG.h @@ -12,13 +12,18 @@ #pragma once -#include "eckit/geo/grid/Regular.h" +#include "eckit/geo/grid/Gaussian.h" + + +namespace eckit { +class Fraction; +} namespace eckit::geo::grid { -class RegularGG : public Regular { +class RegularGG final : public Gaussian { public: // -- Exceptions // None @@ -26,10 +31,10 @@ class RegularGG : public Regular { // -- Constructors RegularGG(const Configuration&); - RegularGG(size_t N, const BoundingBox& = BoundingBox(), double angularPrecision = 0); + RegularGG(size_t N, const BoundingBox& = BoundingBox()); // -- Destructor - // None +//None // -- Convertors // None @@ -38,6 +43,7 @@ class RegularGG : public Regular { // None // -- Methods + // None // -- Overridden methods // None @@ -50,15 +56,26 @@ class RegularGG : public Regular { private: // -- Members - // None + + size_t k_; + size_t Ni_; + size_t Nj_; // -- Methods - // None + + Fraction getSmallestIncrement() const; + void correctWestEast(double& w, double& e) const; + void setNiNj(); // -- Overridden methods + size_t numberOfPoints() const override; void print(std::ostream&) const override; Iterator* iterator() const override; + bool isPeriodicWestEast() const override; + + Renumber crop(BoundingBox&) const override; + Renumber reorder(long scanningMode) const override; // -- Class members // None diff --git a/src/eckit/geo/grid/RegularGrid.cc b/src/eckit/geo/grid/RegularGrid.cc index e13661560..60a1a1c3f 100644 --- a/src/eckit/geo/grid/RegularGrid.cc +++ b/src/eckit/geo/grid/RegularGrid.cc @@ -18,6 +18,7 @@ #include #include +#include "eckit/config/MappedConfiguration.h" #include "eckit/config/Resource.h" #include "eckit/geo/Iterator.h" #include "eckit/utils/StringTools.h" @@ -26,48 +27,53 @@ namespace eckit::geo::grid { -RegularGrid::RegularGrid(const Configuration& param, const Projection& projection) : - shape_(param), xPlus_(true), yPlus_(false), firstPointBottomLeft_(false) { - ASSERT(projection); +RegularGrid::RegularGrid(const Configuration& config, Projection* projection) :Grid(config), + projection_(projection), + shape_(config), xPlus_(true), yPlus_(false), firstPointBottomLeft_(false) { + ASSERT(projection_); - auto get_long_first_key = [](const Configuration& param, const std::vector& keys) -> long { + auto get_long_first_key = [](const Configuration& config, const std::vector& keys) -> long { long value = 0; for (const auto& key : keys) { - if (param.get(key, value)) { + if (config.get(key, value)) { return value; } } throw SeriousBug("RegularGrid: couldn't find any key: " + StringTools::join(", ", keys)); }; - long nx = get_long_first_key(param, {"numberOfPointsAlongXAxis", "Ni"}); - long ny = get_long_first_key(param, {"numberOfPointsAlongYAxis", "Nj"}); + long nx = get_long_first_key(config, {"numberOfPointsAlongXAxis", "Ni"}); + long ny = get_long_first_key(config, {"numberOfPointsAlongYAxis", "Nj"}); ASSERT(nx > 0); ASSERT(ny > 0); std::vector grid; - ASSERT(param.get("grid", grid)); - ASSERT_KEYWORD_GRID_SIZE(grid.size()); + ASSERT(config.get("grid", grid)); + ASSERT(grid.size() == 2); Point2 firstLL; - ASSERT(param.get("latitudeOfFirstGridPointInDegrees", firstLL[LLCOORDS::LAT])); - ASSERT(param.get("longitudeOfFirstGridPointInDegrees", firstLL[LLCOORDS::LON])); + ASSERT(config.get("latitudeOfFirstGridPointInDegrees", firstLL[LLCOORDS::LAT])); + ASSERT(config.get("longitudeOfFirstGridPointInDegrees", firstLL[LLCOORDS::LON])); auto first = projection.xy(firstLL); - param.get("iScansPositively", xPlus_); // iScansPositively != 0 - param.get("jScansPositively", yPlus_); // jScansPositively == 0 - param.get("first_point_bottom_left", firstPointBottomLeft_); + config.get("iScansPositively", xPlus_); // iScansPositively != 0 + config.get("jScansPositively", yPlus_); // jScansPositively == 0 + config.get("first_point_bottom_left", firstPointBottomLeft_); x_ = linspace(first.x(), grid[0], nx, firstPointBottomLeft_ || xPlus_); y_ = linspace(first.y(), grid[1], ny, firstPointBottomLeft_ || yPlus_); grid_ = {x_, y_, projection}; +#if 0 atlas::RectangularDomain range({x_.min(), x_.max()}, {y_.min(), y_.max()}, "meters"); auto box = projection.lonlatBoundingBox(range); ASSERT(box); bbox({box.north(), box.west(), box.south(), box.east()}); +#else + bbox({y_.max(), x_.min(), y_.min(), x_.max()}); +#endif } @@ -91,9 +97,9 @@ RegularGrid::RegularGrid(const Projection& projection, const BoundingBox& bbox, RegularGrid::~RegularGrid() = default; -RegularGrid::Configuration RegularGrid::make_proj_spec(const Configuration& param) { +RegularGrid::Configuration RegularGrid::make_projection_from_proj(const Configuration& config) { std::string proj; - param.get("proj", proj); + config.get("proj", proj); if (proj.empty() || !::atlas::projection::ProjectionFactory::has("proj")) { return {}; @@ -103,12 +109,12 @@ RegularGrid::Configuration RegularGrid::make_proj_spec(const Configuration& para spec.set("proj", proj); std::string projSource; - if (param.get("projSource", projSource) && !projSource.empty()) { + if (config.get("projSource", projSource) && !projSource.empty()) { spec.set("proj_source", projSource); } std::string projGeocentric; - if (param.get("projGeocentric", projGeocentric) && !projGeocentric.empty()) { + if (config.get("projGeocentric", projGeocentric) && !projGeocentric.empty()) { spec.set("proj_geocentric", projGeocentric); } @@ -128,26 +134,6 @@ void RegularGrid::print(std::ostream& out) const { } -bool RegularGrid::crop(BoundingBox& bbox, Renumber& mapping) const { - auto mm = minmax_ij(bbox); - auto Ni = x_.size(); - auto N = (mm.second.i - mm.first.i + 1) * (mm.second.j - mm.first.j + 1); - mapping.clear(); - mapping.reserve(N); - - for (std::unique_ptr it(iterator()); it->next();) { - auto i = it->index() % Ni; - auto j = it->index() / Ni; - if (mm.first.i <= i && i <= mm.second.i && mm.first.j <= j && j <= mm.second.j) { - mapping.push_back(it->index()); - } - } - ASSERT(mapping.size() == N); - - return true; -} - - size_t RegularGrid::numberOfPoints() const { return x_.size() * y_.size(); } @@ -159,24 +145,28 @@ bool RegularGrid::isPeriodicWestEast() const { bool RegularGrid::includesNorthPole() const { - return bbox_.north() == NORTH_POLE; + return bbox().north() == NORTH_POLE; } bool RegularGrid::includesSouthPole() const { - return bbox_.south() == SOUTH_POLE; + return bbox().south() == SOUTH_POLE; } -void RegularGrid::reorder(long /*scanningMode*/) const { - // do not reorder, iterator is doing the right thing - // FIXME this function should not be overriding to do nothing +Renumber RegularGrid::crop(BoundingBox& bbox) const { + NOTIMP; +} + + +Renumber RegularGrid::reorder(long /*scanningMode*/) const { + NOTIMP; } Iterator* RegularGrid::iterator() const { class RegularGridIterator : public Iterator { - Projection projection_; + Projection* projection_; const LinearSpacing& x_; const LinearSpacing& y_; PointLonLat pLonLat_; @@ -215,6 +205,8 @@ Iterator* RegularGrid::iterator() const { size_t index() const override { return count_; } + size_t size() const override { NOTIMP; } + public: RegularGridIterator(Projection projection, const LinearSpacing& x, const LinearSpacing& y) : projection_(std::move(projection)), x_(x), y_(y), ni_(x.size()), nj_(y.size()), i_(0), j_(0), count_(0) {} @@ -230,4 +222,73 @@ Iterator* RegularGrid::iterator() const { } +struct Lambert : RegularGrid { + Lambert(const Configuration& config) : + RegularGrid(config, make_projection(config)) { + } + + static Projection* make_projection(const Configuration& config) { + if (auto spec = RegularGrid::make_projection_from_proj(config); spec != nullptr) { + return spec; + } + + auto LaDInDegrees = config.getDouble("LaDInDegrees"); + auto LoVInDegrees = config.getDouble("LoVInDegrees"); + auto Latin1InDegrees = config.getDouble("Latin1InDegrees", LaDInDegrees); + auto Latin2InDegrees = config.getDouble("Latin2InDegrees", LaDInDegrees); + + return ProjectionFactory::build("lambert_conformal_conic", + MappedConfiguration({{"latitude1", Latin1InDegrees}, + {"latitude2", Latin2InDegrees}, + {"latitude0", LaDInDegrees}, + {"longitude0", LoVInDegrees}})); + } +}; + + +struct LambertAzimuthalEqualArea : RegularGrid { + + LambertAzimuthalEqualArea(const Configuration& config) : + RegularGrid(config, make_projection(config)) {} + + LambertAzimuthalEqualArea(const Projection& projection, const BoundingBox& bbox, const LinearSpacing& x, const LinearSpacing& y, const Shape& shape) : + RegularGrid(projection, bbox, x, y, shape) {} + + static Projection* make_projection(const Configuration& config) { + if (auto spec = RegularGrid::make_projection_from_proj(config); spec != nullptr) { + return spec; + } + + double standardParallel = 0.; + double centralLongitude = 0.; + double radius = 0.; + ASSERT(config.get("standardParallelInDegrees", standardParallel)); + ASSERT(config.get("centralLongitudeInDegrees", centralLongitude)); + config.get("radius", radius = Earth::radius()); + + return ProjectionFactory::build("lambert_azimuthal_equal_area", MappedConfiguration({{"standard_parallel", standardParallel}, + {"central_longitude", centralLongitude}, + {"radius", radius}})); + } +}; + + +struct Mercator : RegularGrid { + Mercator(const Configuration&) : + RegularGrid(config, RegularGrid::make_projection_from_proj(config)) {} +}; + + +struct PolarStereographic : RegularGrid { + PolarStereographic(const Configuration& config) : + RegularGrid(config, RegularGrid::make_projection_from_proj(config)) {} +}; + + +static const GridBuilder __builder("lambert"); +static const GridBuilder __builder("lambert_azimuthal_equal_area"); +static const GridBuilder __builder("mercator"); +static const GridBuilder __builder("polar_stereographic"); + + } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularGrid.h b/src/eckit/geo/grid/RegularGrid.h index 76336f6ed..f7733f46c 100644 --- a/src/eckit/geo/grid/RegularGrid.h +++ b/src/eckit/geo/grid/RegularGrid.h @@ -12,12 +12,14 @@ #pragma once +#include +#include + #include "eckit/geo/Grid.h" #include "eckit/geo/Projection.h" namespace eckit::geo { -class LinearSpacing {}; class Shape {}; } // namespace eckit::geo @@ -28,14 +30,15 @@ namespace eckit::geo::grid { class RegularGrid : public Grid { public: // -- Types - // None + + using LinearSpacing = std::vector; // -- Exceptions // None // -- Constructors - RegularGrid(const Configuration&, const Projection&); + RegularGrid(const Configuration&, Projection*); RegularGrid(const Projection&, const BoundingBox&, const LinearSpacing& x, const LinearSpacing& y, const Shape&); RegularGrid(const RegularGrid&) = delete; @@ -67,6 +70,7 @@ class RegularGrid : public Grid { protected: // -- Members + std::unique_ptr projection_; LinearSpacing x_; LinearSpacing y_; Shape shape_; @@ -85,12 +89,12 @@ class RegularGrid : public Grid { bool includesSouthPole() const override; bool isPeriodicWestEast() const override; - void reorder(long scanningMode) const override; void print(std::ostream&) const override; - - bool crop(BoundingBox&, Renumber&) const override; size_t numberOfPoints() const override; + Renumber crop(BoundingBox&) const override; + Renumber reorder(long scanningMode) const override; + // -- Class members // None diff --git a/src/eckit/geo/grid/RegularLL.cc b/src/eckit/geo/grid/RegularLL.cc index 63ba4c65b..a21a35a92 100644 --- a/src/eckit/geo/grid/RegularLL.cc +++ b/src/eckit/geo/grid/RegularLL.cc @@ -18,6 +18,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Iterator.h" +#include "eckit/geo/Projection.h" #include "eckit/geo/Point.h" #include "eckit/geo/grid/RegularLL.h" #include "eckit/types/FloatCompare.h" @@ -30,8 +31,6 @@ namespace eckit::geo::grid { namespace detail { - - class RegularIterator { public: RegularIterator(const Fraction& a, const Fraction& b, const Fraction& inc, const Fraction& ref); @@ -138,11 +137,14 @@ RegularLL::RegularLL(const Increments& increments, const BoundingBox& bb, const } -RegularLL::~RegularLL() = default; +Renumber RegularLL::crop(BoundingBox&) const { + NOTIMP; +} -void RegularLL::reorder(long scanningMode) const { - grib_reorder(values, scanningMode, ni_, nj_); +Renumber RegularLL::reorder(long scanningMode) const { + NOTIMP; + // grib_reorder(values, scanningMode, ni_, nj_); } @@ -153,26 +155,20 @@ void RegularLL::print(std::ostream& out) const { bool RegularLL::isPeriodicWestEast() const { - // if range West-East is within one increment (or greater than) 360 degree - double inc = increments_.west_east().longitude(); - return bbox().east() - bbox().west() + inc >= GLOBE; + return bbox().east() - bbox().west() + increments_.west_east >= GLOBE; } bool RegularLL::includesNorthPole() const { - // if North latitude is within one increment from North Pole - double inc = increments_.south_north().latitude(); - return bbox().north() + inc > NORTH_POLE; + return bbox().north() + increments_.south_north > NORTH_POLE; } bool RegularLL::includesSouthPole() const { - // if South latitude is within one increment from South Pole - auto inc = increments_.south_north; - return bbox().south() - inc < SOUTH_POLE; + return bbox().south() - increments_.south_north < SOUTH_POLE; } @@ -183,19 +179,24 @@ size_t RegularLL::numberOfPoints() const { } -BoundingBox RegularLL::correctBoundingBox(const BoundingBox& bbox, size_t& ni, size_t& nj, const Increments& inc, - const PointLonLat& reference) { +BoundingBox RegularLL::correctBoundingBox(const BoundingBox& box, size_t& ni, size_t& nj, const Increments& inc, + const PointLonLat& reference) { // Latitude/longitude ranges - detail::RegularIterator lat{bbox.south(), bbox.north(), inc.south_north(), - reference.lat}; + detail::RegularIterator lat{Fraction{box.south()}, + Fraction{box.north()}, + Fraction{inc.south_north}, + Fraction{reference.lat}}; auto n = lat.b(); auto s = lat.a(); nj = lat.n(); ASSERT(nj > 0); - detail::RegularIterator lon{bbox.west(), bbox.east(), inc.west_east().longitude(), - reference.lon, GLOBE}; + detail::RegularIterator lon{Fraction{box.west()}, + Fraction{box.east()}, + Fraction{inc.west_east}, + Fraction{reference.lon}, + Fraction{GLOBE}}; auto w = lon.a(); auto e = lon.b(); @@ -241,11 +242,11 @@ Iterator* RegularLL::iterator() const { << ",i=" << i_ << ",j=" << j_ << ",count=" << count_ << "]"; } - bool next(double& lat, double& lon) { + bool operator++() override { if (j_ < nj_) { if (i_ < ni_) { - lat = latValue_; - lon = lonValue_; + // lat = latValue_; + // lon = lonValue_; lon_ += we_; @@ -274,6 +275,8 @@ Iterator* RegularLL::iterator() const { size_t index() const override { return count_; } + size_t size() const override { NOTIMP; } + public: RegularLLIterator(size_t ni, size_t nj, Latitude north, Longitude west, const Increments& increments) : ni_(ni), diff --git a/src/eckit/geo/grid/RegularLL.h b/src/eckit/geo/grid/RegularLL.h index 75dc64027..8dbf5fa2d 100644 --- a/src/eckit/geo/grid/RegularLL.h +++ b/src/eckit/geo/grid/RegularLL.h @@ -31,8 +31,7 @@ class RegularLL : public Grid { RegularLL(const Increments&, const BoundingBox& = {}, const PointLonLat& reference = {0, 0}); // -- Destructor - - ~RegularLL() override; + // None // -- Convertors // None @@ -42,12 +41,8 @@ class RegularLL : public Grid { // -- Methods - size_t Ni() const { return ni_; } - - size_t Nj() const { return nj_; } - static BoundingBox correctBoundingBox(const BoundingBox&, size_t& ni, size_t& nj, const Increments&, - const PointLonLat& reference = {0, 0}); + const PointLonLat& reference = {0, 0}); // -- Overridden methods // None @@ -76,9 +71,11 @@ class RegularLL : public Grid { bool includesNorthPole() const override; bool includesSouthPole() const override; size_t numberOfPoints() const override; - void reorder(long scanningMode) const override; Iterator* iterator() const override; + Renumber crop(BoundingBox&) const override; + Renumber reorder(long scanningMode) const override; + // -- Class members // None diff --git a/src/eckit/geo/grid/SpaceView.cc b/src/eckit/geo/grid/SpaceView.cc index 30ed35058..1309c0151 100644 --- a/src/eckit/geo/grid/SpaceView.cc +++ b/src/eckit/geo/grid/SpaceView.cc @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -36,28 +35,28 @@ namespace detail { template -EXTERNAL_T get(const Configuration& param, const std::string& key) { +EXTERNAL_T get(const Configuration& config, const std::string& key) { INTERNAL_T value; - ASSERT(param.get(key, value)); + ASSERT(config.get(key, value)); return static_cast(value); } -SpaceViewInternal::SpaceViewInternal(const Configuration& param) { - auto earthIsOblate = get(param, "earthIsOblate"); - auto a = get(param, earthIsOblate ? "earthMajorAxis" : "radius"); - auto b = earthIsOblate ? get(param, "earthMinorAxis") : a; +SpaceViewInternal::SpaceViewInternal(const Configuration& config) { + auto earthIsOblate = get(config, "earthIsOblate"); + auto a = get(config, earthIsOblate ? "earthMajorAxis" : "radius"); + auto b = earthIsOblate ? get(config, "earthMinorAxis") : a; - auto Nr = get(param, "NrInRadiusOfEarthScaled"); + auto Nr = get(config, "NrInRadiusOfEarthScaled"); ASSERT(Nr > 1.); auto h = (Nr - 1.) * a; - Lop_ = get(param, "longitudeOfSubSatellitePointInDegrees"); - auto Lap = get(param, "latitudeOfSubSatellitePointInDegrees"); + Lop_ = get(config, "longitudeOfSubSatellitePointInDegrees"); + auto Lap = get(config, "latitudeOfSubSatellitePointInDegrees"); ASSERT(types::is_approximately_equal(Lap, 0.)); - // ASSERT(get(param, "orientationOfTheGridInDegrees") == 180); + // ASSERT(get(config, "orientationOfTheGridInDegrees") == 180); // projection @@ -74,12 +73,12 @@ SpaceViewInternal::SpaceViewInternal(const Configuration& param) { projectionGreenwich_.reset(ProjectionFactory::build("proj", MappedConfiguration({{"proj", proj(h, a, b, 0)}}))); // (x, y) space - Nx_ = get(param, "Nx"); + Nx_ = get(config, "Nx"); ASSERT(1 < Nx_); - auto ip = get(param, "iScansPositively"); - auto xp = get(param, "XpInGridLengths"); - auto dx = get(param, "dx"); + auto ip = get(config, "iScansPositively"); + auto xp = get(config, "XpInGridLengths"); + auto dx = get(config, "dx"); ASSERT(dx > 0); auto rx = 2. * std::asin(1. / Nr) / dx * h; // (height factor is PROJ-specific) @@ -87,12 +86,12 @@ SpaceViewInternal::SpaceViewInternal(const Configuration& param) { (ip ? xa_ : xb_) = rx * (-xp); (ip ? xb_ : xa_) = rx * (-xp + double(Nx_ - 1)); - Ny_ = get(param, "Ny"); + Ny_ = get(config, "Ny"); ASSERT(1 < Ny_); - auto jp = get(param, "jScansPositively"); - auto yp = get(param, "YpInGridLengths"); - auto dy = get(param, "dy"); + auto jp = get(config, "jScansPositively"); + auto yp = get(config, "YpInGridLengths"); + auto dy = get(config, "dy"); ASSERT(dy > 0); auto ry = 2. * std::asin(1. / Nr) / dy * h; // (height factor is PROJ-specific) @@ -142,11 +141,11 @@ SpaceViewInternal::SpaceViewInternal(const Configuration& param) { auto eps_xy = 1e-6 * h; auto eps_ll = 1e-6; - auto max_lon = geometric_maximum(0., eps_xy, [&](double x) { return projectionGreenwich_.lonlat({x, 0}).lon(); }); + auto max_lon = geometric_maximum(0., eps_xy, [&](double x) { return projectionGreenwich_->inv({x, 0}).lon(); }); auto w = Lop_ - max_lon - eps_ll; auto e = Lop_ + max_lon + eps_ll; - auto max_lat = geometric_maximum(0., eps_xy, [&](double y) { return projectionGreenwich_.lonlat({0, y}).lat(); }); + auto max_lat = geometric_maximum(0., eps_xy, [&](double y) { return projectionGreenwich_->inv({0, y}).lat(); }); auto n = max_lat + eps_ll; auto s = -n; #endif @@ -158,21 +157,18 @@ SpaceViewInternal::SpaceViewInternal(const Configuration& param) { const std::vector& SpaceViewInternal::lonlat() const { if (lonlat_.empty()) { ASSERT(projectionGreenwich_); // Greenwich-centred (avoids PROJ normalisation) - lonlat_.resize(Nx_ * Ny_); + lonlat_.reserve(Nx_ * Ny_); size_t index = 0; for (const auto& _y : y()) { for (const auto& _x : x()) { - auto& ll = lonlat_[index++]; - ll = projectionGreenwich_.lonlat({_x, _y}); + // auto& ll = lonlat_[index++]; + PointLonLat ll = projectionGreenwich_->inv({_x, _y}); if (std::isfinite(ll.lon) && std::isfinite(ll.lat)) { ASSERT(-90. < ll.lon && ll.lon < 90.); - ASSERT(-90. < ll.lat && ll.lat < 90.); ll.lon += Lop_; - } - else { - ll = {std::numeric_limits::quiet_NaN(), std::numeric_limits::quiet_NaN()}; + lonlat_.push_back(ll); } } } @@ -186,10 +182,10 @@ const std::vector& SpaceViewInternal::lonlat() const { } // namespace detail -SpaceView::SpaceView(const Configuration& param) : - detail::SpaceViewInternal(param), +SpaceView::SpaceView(const Configuration& config) : + detail::SpaceViewInternal(config), RegularGrid(SpaceViewInternal::projection_, SpaceViewInternal::bbox_, SpaceViewInternal::x(), - SpaceViewInternal::y(), {param}) {} + SpaceViewInternal::y(), {config}) {} Iterator* SpaceView::iterator() const { @@ -219,6 +215,8 @@ Iterator* SpaceView::iterator() const { size_t index() const override { return count_; } + size_t size() const override { NOTIMP; } + public: SpaceViewIterator(const std::vector& lonlat) : lonlat_(lonlat), count_(0) {} diff --git a/src/eckit/geo/grid/TransverseMercator.cc b/src/eckit/geo/grid/TransverseMercator.cc deleted file mode 100644 index 5a7205640..000000000 --- a/src/eckit/geo/grid/TransverseMercator.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/TransverseMercator.h" - -#include - - -namespace eckit::geo::grid { - - -TransverseMercator::TransverseMercator(const Configuration& config) : RegularGrid(config){} - - -void TransverseMercator::print(std::ostream& out) const { - out << "TransverseMercator[" - << "]"; -} - - -static const GridBuilder __repres("transverse_mercator"); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/TransverseMercator.h b/src/eckit/geo/grid/TransverseMercator.h deleted file mode 100644 index 65e0fa10d..000000000 --- a/src/eckit/geo/grid/TransverseMercator.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/RegularGrid.h" - - -namespace eckit::geo::grid { - - -class TransverseMercator : public RegularGrid { -public: - // -- Exceptions - // None - - // -- Constructors - - TransverseMercator(const Configuration&); - TransverseMercator(const TransverseMercator&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - TransverseMercator& operator=(const TransverseMercator&) = delete; - - // -- Methods - // // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/UnstructuredGrid.cc b/src/eckit/geo/grid/UnstructuredGrid.cc index 56647432c..02fea391b 100644 --- a/src/eckit/geo/grid/UnstructuredGrid.cc +++ b/src/eckit/geo/grid/UnstructuredGrid.cc @@ -24,6 +24,7 @@ #include "eckit/filesystem/PathName.h" #include "eckit/geo/Domain.h" #include "eckit/geo/Iterator.h" +#include "eckit/geo/Projection.h" #include "eckit/serialisation/FileStream.h" #include "eckit/serialisation/IfstreamStream.h" @@ -91,11 +92,11 @@ class UnstructuredIterator : public Iterator { out << "]"; } - bool next(Latitude& lat, Longitude& lon) override { + bool operator++() override { if ((first_ ? count_ : ++count_) < size_) { first_ = false; - lat = latitudes_[count_]; - lon = longitudes_[count_]; + // lat = latitudes_[count_]; + // lon = longitudes_[count_]; return true; } @@ -104,6 +105,8 @@ class UnstructuredIterator : public Iterator { size_t index() const override { return count_; } + size_t size() const override { NOTIMP; } + // -- Class members // None diff --git a/src/eckit/geo/iterator/IteratorAggregator.h b/src/eckit/geo/iterator/IteratorAggregator.h deleted file mode 100644 index bbeddb56c..000000000 --- a/src/eckit/geo/iterator/IteratorAggregator.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Iterator.h" - - -namespace eckit::geo::iterator { - - -template -class IteratorAggregator final : public Iterator, protected Scanner { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - IteratorAggregator() = default; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - bool operator++() override { return Scanner::operator++(); } - size_t size() const override { return Scanner::size(); } - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::iterator diff --git a/src/eckit/geo/iterator/IteratorComposer.cc b/src/eckit/geo/iterator/IteratorComposer.cc deleted file mode 100644 index cf4cce71c..000000000 --- a/src/eckit/geo/iterator/IteratorComposer.cc +++ /dev/null @@ -1,43 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/iterator/IteratorComposer.h" - -#include "eckit/exception/Exceptions.h" - - -namespace eckit::geo::iterator { - - -IteratorComposer::IteratorComposer(Scanner* scanner, const std::vector& projections) : - scanner_(scanner) { - ASSERT(scanner_); - - projections_.reserve(projections.size()); - for (auto* p : projections) { - ASSERT(p != nullptr); - projections_.emplace_back(p); - } -} - - -bool IteratorComposer::operator++() { - return scanner_->operator++(); -} - - -size_t IteratorComposer::size() const { - return scanner_->size(); -} - - -} // namespace eckit::geo::iterator diff --git a/src/eckit/geo/iterator/IteratorComposer.h b/src/eckit/geo/iterator/IteratorComposer.h deleted file mode 100644 index 929fce29d..000000000 --- a/src/eckit/geo/iterator/IteratorComposer.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include - -#include "eckit/geo/Iterator.h" -#include "eckit/geo/Projection.h" -#include "eckit/geo/Scanner.h" - - -namespace eckit::geo::iterator { - - -class IteratorComposer final : public Iterator { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit IteratorComposer(Scanner*, const std::vector& = {}); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - bool operator++() override; - - // -- Methods - - size_t size() const override; - const std::vector> projections() const; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - std::unique_ptr scanner_; - std::vector> projections_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::iterator diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc index 649ff0056..eb109ff8a 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -64,9 +64,9 @@ LonLatToXYZ::LonLatToXYZ(double R) : LonLatToXYZ(R, R) {} -LonLatToXYZ::LonLatToXYZ(const Configuration& param) : - LonLatToXYZ(param.getDouble("a", param.getDouble("R", 1.)), - param.getDouble("b", param.getDouble("R", 1.))) {} +LonLatToXYZ::LonLatToXYZ(const Configuration& config) : + LonLatToXYZ(config.getDouble("a", config.getDouble("R", 1.)), + config.getDouble("b", config.getDouble("R", 1.))) {} } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 870e9c751..f84130307 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -90,10 +90,10 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini } -PROJ::PROJ(const Configuration& param) : - PROJ(param.getString("source", "EPSG:4326"), // default to WGS 84 - param.getString("target", "EPSG:4326"), // ... - param.getDouble("lon_minimum", 0)) {} +PROJ::PROJ(const Configuration& config) : + PROJ(config.getString("source", "EPSG:4326"), // default to WGS 84 + config.getString("target", "EPSG:4326"), // ... + config.getDouble("lon_minimum", 0)) {} std::string PROJ::ellipsoid(const std::string& string) { diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 3557562bc..dcad90c4c 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -97,9 +97,9 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : } -Rotation::Rotation(const Configuration& param) : - Rotation(param.getDouble("south_pole_lon"), param.getDouble("south_pole_lat"), - param.getDouble("angle", 0)) {} +Rotation::Rotation(const Configuration& config) : + Rotation(config.getDouble("south_pole_lon"), config.getDouble("south_pole_lat"), + config.getDouble("angle", 0)) {} } // namespace eckit::geo::projection diff --git a/src/eckit/geo/scanner/Reduced.cc b/src/eckit/geo/scanner/Reduced.cc index 6e333c9a8..9c35f55a3 100644 --- a/src/eckit/geo/scanner/Reduced.cc +++ b/src/eckit/geo/scanner/Reduced.cc @@ -21,7 +21,7 @@ namespace eckit::geo::scanner { Reduced::Reduced(const std::vector& latitudes, - Reduced::pl_type&& pl, + pl_type&& pl, const BoundingBox& bbox, size_t N, size_t Nj, diff --git a/src/eckit/geo/scanner/Reduced.h b/src/eckit/geo/scanner/Reduced.h index e1e6c804b..3299b9167 100644 --- a/src/eckit/geo/scanner/Reduced.h +++ b/src/eckit/geo/scanner/Reduced.h @@ -24,10 +24,6 @@ namespace eckit::geo::scanner { class Reduced final : public Scanner { public: - // -- Types - - using pl_type = util::pl_type; - // -- Exceptions // None diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index 7c6157b8a..efa1b7dc8 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -19,14 +19,17 @@ #include -namespace eckit::geo::util { +namespace eckit::geo { -constexpr double degree_to_radian = M_PI / 180.; -constexpr double radian_to_degree = M_1_PI * 180.; +using pl_type = std::vector; -using pl_type = std::vector; +namespace util { + + +constexpr double degree_to_radian = M_PI / 180.; +constexpr double radian_to_degree = M_1_PI * 180.; template @@ -66,4 +69,7 @@ const pl_type& reduced_octahedral_pl(size_t N); pl_type::value_type regular_pl(size_t N); -} // namespace eckit::geo::util +} // namespace util + + +} // namespace eckit::geo diff --git a/tests/geo/test_iterator.cc b/tests/geo/test_iterator.cc index aafe6f715..05c32425d 100644 --- a/tests/geo/test_iterator.cc +++ b/tests/geo/test_iterator.cc @@ -14,19 +14,19 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Scanner.h" -#include "eckit/geo/iterator/IteratorAggregator.h" -#include "eckit/geo/iterator/IteratorComposer.h" +// #include "eckit/geo/iterator/IteratorAggregator.h" +// #include "eckit/geo/iterator/IteratorComposer.h" int main(int argc, const char* argv[]) { - eckit::geo::iterator::IteratorComposer i(nullptr); + // eckit::geo::iterator::IteratorComposer i(nullptr); - struct ScannerTest : public eckit::geo::Scanner { - bool operator++() override { NOTIMP; } - size_t size() const override { NOTIMP; } - }; + // struct ScannerTest : public eckit::geo::Scanner { + // bool operator++() override { NOTIMP; } + // size_t size() const override { NOTIMP; } + // }; - eckit::geo::iterator::IteratorAggregator j; + // eckit::geo::iterator::IteratorAggregator j; return 0; } diff --git a/tests/types/test_floatcompare.cc b/tests/types/test_floatcompare.cc index be63c9716..60dab9bde 100644 --- a/tests/types/test_floatcompare.cc +++ b/tests/types/test_floatcompare.cc @@ -26,14 +26,10 @@ bool is_equal(float a, float b, float epsilon, int maxUlps) { return eckit::types::is_approximately_equal(a, b, epsilon, maxUlps); } -bool is_equal(float a, float b, float epsilon) { +bool is_equal(float a, float b, float epsilon = 0.00001F) { return eckit::types::is_approximately_equal(a, b, epsilon); } -bool is_equal(float a, float b) { - return eckit::types::is_approximately_equal(a, b, 0.00001f); -} - const float dEps = std::numeric_limits::epsilon(); const float dInf = std::numeric_limits::infinity(); const float sMin = std::numeric_limits::denorm_min(); @@ -46,6 +42,30 @@ const float sNaN = std::numeric_limits::signaling_NaN(); //---------------------------------------------------------------------------------------------------------------------- +CASE("test_epsilon_zero") { + Log::info() << "test_tolerance_limit" << std::endl; + + { + constexpr auto eps = std::numeric_limits::epsilon(); + EXPECT_EQUAL(1., 1.); // sanity check + EXPECT(types::is_approximately_equal(1., 1., 0.)); + EXPECT_NOT(types::is_approximately_equal(1., 1. + eps, 0.)); + EXPECT_NOT(types::is_approximately_equal(1., 1.1 + eps, 0.1)); + EXPECT(types::is_approximately_equal(1., 1.1, 0.1 + eps)); + } + + { + // constexpr auto eps = std::numeric_limits::epsilon(); + // EXPECT_EQUAL(1.F, 1.F); // sanity check + // EXPECT(types::is_approximately_equal(1.F, 1.F, 0.F)); + // EXPECT(types::is_approximately_equal(1.F, 1.1F, 0.1F)); + // EXPECT_NOT(types::is_approximately_equal(1.F, 1.F + eps, 0.F)); + } +} + +//---------------------------------------------------------------------------------------------------------------------- + +#if 0 CASE("test_large_numbers") { Log::info() << "test_large_numbers" << std::endl; @@ -317,6 +337,7 @@ CASE("test_comparisons_ulps") { EXPECT(!is_equal(-dMin, 0, 0, 0)); EXPECT(!is_equal(0, -dMin, 0, 0)); } +#endif //---------------------------------------------------------------------------------------------------------------------- From bfd7859ad3c78ab6a08d2191081f577c14833602 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 9 Jun 2023 20:41:31 +0100 Subject: [PATCH 242/737] eckit::geo::grid --- src/eckit/geo/Grid.cc | 5 ---- src/eckit/geo/Grid.h | 1 - src/eckit/geo/grid/IrregularLatlon.cc | 10 ++++++++ src/eckit/geo/grid/IrregularLatlon.h | 23 ++++------------- src/eckit/geo/grid/ReducedGG.cc | 21 ++++------------ src/eckit/geo/grid/ReducedLL.cc | 10 ++++++++ src/eckit/geo/grid/ReducedLL.h | 30 +++++++---------------- src/eckit/geo/grid/RegularGG.cc | 4 +-- src/eckit/geo/grid/RegularGG.h | 4 +-- src/eckit/geo/grid/RegularGrid.cc | 34 ++++++++++++++------------ src/eckit/geo/grid/RegularGrid.h | 2 +- src/eckit/geo/grid/RegularLL.cc | 2 +- src/eckit/geo/grid/UnstructuredGrid.cc | 14 ++++++++++- src/eckit/geo/grid/UnstructuredGrid.h | 3 +++ 14 files changed, 78 insertions(+), 85 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index e6ffb53db..1113dc77d 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -36,11 +36,6 @@ Grid::Grid(const BoundingBox& bbox) : bbox_(bbox) {} -bool Grid::isGlobal() const { - return domain().isGlobal(); -} - - Domain Grid::domain() const { auto n = includesNorthPole() ? NORTH_POLE : bbox_.north(); auto s = includesSouthPole() ? SOUTH_POLE : bbox_.south(); diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index faa1d1b34..0dd42fbd0 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -57,7 +57,6 @@ class Grid { virtual Iterator* iterator() const; virtual bool includesNorthPole() const; virtual bool includesSouthPole() const; - virtual bool isGlobal() const; virtual bool isPeriodicWestEast() const; virtual const BoundingBox& boundingBox() const; virtual size_t numberOfPoints() const; diff --git a/src/eckit/geo/grid/IrregularLatlon.cc b/src/eckit/geo/grid/IrregularLatlon.cc index 985fcfdfc..14786472f 100644 --- a/src/eckit/geo/grid/IrregularLatlon.cc +++ b/src/eckit/geo/grid/IrregularLatlon.cc @@ -150,6 +150,16 @@ bool IrregularLatlon::includesSouthPole() const { } +Renumber IrregularLatlon::crop(BoundingBox&) const { + NOTIMP; +} + + +Renumber IrregularLatlon::reorder(long scanningMode) const { + NOTIMP; +} + + static const GridBuilder irregularLatlon("irregular_latlon"); diff --git a/src/eckit/geo/grid/IrregularLatlon.h b/src/eckit/geo/grid/IrregularLatlon.h index b59b6ada0..36b47c7fa 100644 --- a/src/eckit/geo/grid/IrregularLatlon.h +++ b/src/eckit/geo/grid/IrregularLatlon.h @@ -18,7 +18,7 @@ namespace eckit::geo::grid { -class IrregularLatlon : public Grid { +class IrregularLatlon final : public Grid { public: // -- Exceptions // None @@ -47,23 +47,6 @@ class IrregularLatlon : public Grid { // -- Class methods // None -protected: - // -- Members - // None - - // -- Methods - - void print(std::ostream&) const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members @@ -88,6 +71,10 @@ class IrregularLatlon : public Grid { bool isPeriodicWestEast() const override; bool includesNorthPole() const override; bool includesSouthPole() const override; + void print(std::ostream&) const override; + + Renumber crop(BoundingBox&) const override; + Renumber reorder(long scanningMode) const override; // -- Class members // None diff --git a/src/eckit/geo/grid/ReducedGG.cc b/src/eckit/geo/grid/ReducedGG.cc index 4672e0193..365af4da0 100644 --- a/src/eckit/geo/grid/ReducedGG.cc +++ b/src/eckit/geo/grid/ReducedGG.cc @@ -91,8 +91,8 @@ void ReducedGG::correctWestEast(double& w, double& e) const { const Fraction west{w}; const Fraction east{e}; - Fraction W = west; - Fraction E = east; + Fraction W = west; + Fraction E = east; bool first = true; std::set NiTried; @@ -183,16 +183,8 @@ void ReducedGG::setNj(pl_type pl, double s, double n) { size_t ReducedGG::numberOfPoints() const { - if (isGlobal()) { - const auto& pl = pls(); - return size_t(std::accumulate(pl.begin(), pl.end(), 0L)); - } - - size_t total = 0; - for (const std::unique_ptr it(iterator()); ++(*it);) { - total++; - } - return total; + const auto& pl = pls(); + return size_t(std::accumulate(pl.begin(), pl.end(), pl_type::value_type{0})); } @@ -208,7 +200,7 @@ void ReducedGG::print(std::ostream& out) const { struct ReducedGGClassic : ReducedGG { - ReducedGGClassic(size_t N, const BoundingBox& box= BoundingBox()) : + ReducedGGClassic(size_t N, const BoundingBox& box = BoundingBox()) : ReducedGG(N, box) { // adjust latitudes, longitudes and re-set bounding box @@ -227,9 +219,6 @@ struct ReducedGGClassic : ReducedGG { }; - - - struct ReducedGGFromPL : ReducedGG { ReducedGGFromPL(const Configuration& config) : ReducedGG(config) {} diff --git a/src/eckit/geo/grid/ReducedLL.cc b/src/eckit/geo/grid/ReducedLL.cc index 6f59d8bfb..1de4e078d 100644 --- a/src/eckit/geo/grid/ReducedLL.cc +++ b/src/eckit/geo/grid/ReducedLL.cc @@ -172,6 +172,16 @@ Iterator* ReducedLL::iterator() const { } +Renumber ReducedLL::crop(BoundingBox&) const { + NOTIMP; +} + + +Renumber ReducedLL::reorder(long scanningMode) const { + NOTIMP; +} + + static const GridBuilder reducedLL("reduced_ll"); diff --git a/src/eckit/geo/grid/ReducedLL.h b/src/eckit/geo/grid/ReducedLL.h index 743a08786..bd10724ed 100644 --- a/src/eckit/geo/grid/ReducedLL.h +++ b/src/eckit/geo/grid/ReducedLL.h @@ -49,27 +49,6 @@ class ReducedLL : public Grid { // -- Class methods // None -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - bool isPeriodicWestEast() const override; - bool includesNorthPole() const override; - bool includesSouthPole() const override; - - void print(std::ostream&) const override; - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members @@ -84,6 +63,15 @@ class ReducedLL : public Grid { size_t numberOfPoints() const override; + bool isPeriodicWestEast() const override; + bool includesNorthPole() const override; + bool includesSouthPole() const override; + + void print(std::ostream&) const override; + + Renumber crop(BoundingBox&) const override; + Renumber reorder(long scanningMode) const override; + // -- Class members // None diff --git a/src/eckit/geo/grid/RegularGG.cc b/src/eckit/geo/grid/RegularGG.cc index f15de390b..c427c113c 100644 --- a/src/eckit/geo/grid/RegularGG.cc +++ b/src/eckit/geo/grid/RegularGG.cc @@ -175,7 +175,7 @@ Iterator* RegularGG::iterator() const { } -Renumber RegularGG::crop(BoundingBox&) const { +Renumber RegularGG::crop(BoundingBox&) const { NOTIMP; } @@ -185,8 +185,6 @@ Renumber RegularGG::reorder(long /*scanningMode*/) const { } - - static const GridBuilder reducedGG("regular_gg"); diff --git a/src/eckit/geo/grid/RegularGG.h b/src/eckit/geo/grid/RegularGG.h index bfab2f5d8..7662ced16 100644 --- a/src/eckit/geo/grid/RegularGG.h +++ b/src/eckit/geo/grid/RegularGG.h @@ -34,7 +34,7 @@ class RegularGG final : public Gaussian { RegularGG(size_t N, const BoundingBox& = BoundingBox()); // -- Destructor -//None + // None // -- Convertors // None @@ -74,7 +74,7 @@ class RegularGG final : public Gaussian { Iterator* iterator() const override; bool isPeriodicWestEast() const override; - Renumber crop(BoundingBox&) const override; + Renumber crop(BoundingBox&) const override; Renumber reorder(long scanningMode) const override; // -- Class members diff --git a/src/eckit/geo/grid/RegularGrid.cc b/src/eckit/geo/grid/RegularGrid.cc index 60a1a1c3f..9c498fc00 100644 --- a/src/eckit/geo/grid/RegularGrid.cc +++ b/src/eckit/geo/grid/RegularGrid.cc @@ -27,9 +27,13 @@ namespace eckit::geo::grid { -RegularGrid::RegularGrid(const Configuration& config, Projection* projection) :Grid(config), +RegularGrid::RegularGrid(const Configuration& config, Projection* projection) : + Grid(config), projection_(projection), - shape_(config), xPlus_(true), yPlus_(false), firstPointBottomLeft_(false) { + shape_(config), + xPlus_(true), + yPlus_(false), + firstPointBottomLeft_(false) { ASSERT(projection_); auto get_long_first_key = [](const Configuration& config, const std::vector& keys) -> long { @@ -64,16 +68,14 @@ RegularGrid::RegularGrid(const Configuration& config, Projection* projection) :G y_ = linspace(first.y(), grid[1], ny, firstPointBottomLeft_ || yPlus_); grid_ = {x_, y_, projection}; -#if 0 - atlas::RectangularDomain range({x_.min(), x_.max()}, {y_.min(), y_.max()}, "meters"); - - auto box = projection.lonlatBoundingBox(range); - ASSERT(box); + ASSERT(!x_.empty()); + ASSERT(!y_.empty()); + auto n = y_.front() > y_.back() ? y_.front() : y_.back(); + auto s = y_.front() > y_.back() ? y_.back() : y_.front(); + auto w = x_.front() > x_.back() ? x_.back() : x_.front(); + auto e = x_.front() > x_.back() ? x_.front() : x_.back(); - bbox({box.north(), box.west(), box.south(), box.east()}); -#else - bbox({y_.max(), x_.min(), y_.min(), x_.max()}); -#endif + bbox(projection.lonlatBoundingBox({n, w, s, e})); } @@ -222,7 +224,7 @@ Iterator* RegularGrid::iterator() const { } -struct Lambert : RegularGrid { +struct Lambert : RegularGrid { Lambert(const Configuration& config) : RegularGrid(config, make_projection(config)) { } @@ -246,7 +248,7 @@ struct Lambert : RegularGrid { }; -struct LambertAzimuthalEqualArea : RegularGrid { +struct LambertAzimuthalEqualArea : RegularGrid { LambertAzimuthalEqualArea(const Configuration& config) : RegularGrid(config, make_projection(config)) {} @@ -273,13 +275,13 @@ struct LambertAzimuthalEqualArea : RegularGrid { }; -struct Mercator : RegularGrid { - Mercator(const Configuration&) : +struct Mercator : RegularGrid { + Mercator(const Configuration&) : RegularGrid(config, RegularGrid::make_projection_from_proj(config)) {} }; -struct PolarStereographic : RegularGrid { +struct PolarStereographic : RegularGrid { PolarStereographic(const Configuration& config) : RegularGrid(config, RegularGrid::make_projection_from_proj(config)) {} }; diff --git a/src/eckit/geo/grid/RegularGrid.h b/src/eckit/geo/grid/RegularGrid.h index f7733f46c..7cd352d59 100644 --- a/src/eckit/geo/grid/RegularGrid.h +++ b/src/eckit/geo/grid/RegularGrid.h @@ -92,7 +92,7 @@ class RegularGrid : public Grid { void print(std::ostream&) const override; size_t numberOfPoints() const override; - Renumber crop(BoundingBox&) const override; + Renumber crop(BoundingBox&) const override; Renumber reorder(long scanningMode) const override; // -- Class members diff --git a/src/eckit/geo/grid/RegularLL.cc b/src/eckit/geo/grid/RegularLL.cc index a21a35a92..a67471fb6 100644 --- a/src/eckit/geo/grid/RegularLL.cc +++ b/src/eckit/geo/grid/RegularLL.cc @@ -18,8 +18,8 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Iterator.h" -#include "eckit/geo/Projection.h" #include "eckit/geo/Point.h" +#include "eckit/geo/Projection.h" #include "eckit/geo/grid/RegularLL.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" diff --git a/src/eckit/geo/grid/UnstructuredGrid.cc b/src/eckit/geo/grid/UnstructuredGrid.cc index 02fea391b..832292c72 100644 --- a/src/eckit/geo/grid/UnstructuredGrid.cc +++ b/src/eckit/geo/grid/UnstructuredGrid.cc @@ -133,6 +133,7 @@ UnstructuredGrid::UnstructuredGrid(const Configuration& config) : } +#if 0 UnstructuredGrid::UnstructuredGrid(const PathName& path) { std::ifstream in(path.asString().c_str()); if (!in) { @@ -165,6 +166,7 @@ UnstructuredGrid::UnstructuredGrid(const PathName& path) { } } } +#endif UnstructuredGrid::UnstructuredGrid(const std::vector& latitudes, const std::vector& longitudes, @@ -194,8 +196,18 @@ size_t UnstructuredGrid::numberOfPoints() const { } +Renumber UnstructuredGrid::crop(BoundingBox&) const { + NOTIMP; +} + + +Renumber UnstructuredGrid::reorder(long scanningMode) const { + NOTIMP; +} + + Iterator* UnstructuredGrid::iterator() const { - return new iterator::UnstructuredIterator(latitudes_, longitudes_); + return new detail::UnstructuredIterator(latitudes_, longitudes_); } diff --git a/src/eckit/geo/grid/UnstructuredGrid.h b/src/eckit/geo/grid/UnstructuredGrid.h index e1e47c13e..fc5463199 100644 --- a/src/eckit/geo/grid/UnstructuredGrid.h +++ b/src/eckit/geo/grid/UnstructuredGrid.h @@ -103,6 +103,9 @@ class UnstructuredGrid : public Grid { size_t numberOfPoints() const override; + Renumber crop(BoundingBox&) const override; + Renumber reorder(long scanningMode) const override; + // -- Class members // None From 01e90eab2fcb54668c2a8ae360d3005d2d6f6d25 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 9 Jun 2023 23:21:46 +0100 Subject: [PATCH 243/737] eckit::geo::grid --- src/eckit/geo/grid/Gaussian.cc | 6 +----- src/eckit/geo/grid/ReducedGG.cc | 24 +++++++++++++++++++++++- src/eckit/geo/grid/ReducedGG.h | 8 ++++++++ src/eckit/geo/grid/RegularGrid.cc | 24 ++++++++++-------------- src/eckit/geo/grid/RegularGrid.h | 1 - 5 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/eckit/geo/grid/Gaussian.cc b/src/eckit/geo/grid/Gaussian.cc index 76a6bc43c..e85d8be0a 100644 --- a/src/eckit/geo/grid/Gaussian.cc +++ b/src/eckit/geo/grid/Gaussian.cc @@ -30,12 +30,8 @@ Gaussian::Gaussian(size_t N, const BoundingBox& bbox) : Gaussian::Gaussian(const Configuration& config) : - Grid(config), N_(0), angularPrecision_(0) { - - ASSERT(config.get("N", N_)); + Grid(config), N_(config.getUnsigned("N")), angularPrecision_(config.getDouble("angular_precision", 0)) { ASSERT(N_ > 0); - - config.get("angular_precision", angularPrecision_); ASSERT(angularPrecision_ >= 0); } diff --git a/src/eckit/geo/grid/ReducedGG.cc b/src/eckit/geo/grid/ReducedGG.cc index 365af4da0..9bd9e1616 100644 --- a/src/eckit/geo/grid/ReducedGG.cc +++ b/src/eckit/geo/grid/ReducedGG.cc @@ -188,6 +188,18 @@ size_t ReducedGG::numberOfPoints() const { } +Fraction ReducedGG::getSmallestIncrement() const { + using distance_t = std::make_signed::type; + + const auto& pl = pls(); + auto maxpl = *std::max_element(pl.begin() + distance_t(k_), pl.begin() + distance_t(k_ + Nj_)); + ASSERT(maxpl >= 2); + + const Fraction globe_f(GLOBE); + return globe_f / maxpl; +} + + bool ReducedGG::isPeriodicWestEast() const { auto inc = getSmallestIncrement(); return bbox().east() - bbox().west() + inc >= GLOBE; @@ -195,7 +207,17 @@ bool ReducedGG::isPeriodicWestEast() const { void ReducedGG::print(std::ostream& out) const { - out << "ReducedClassic[N=" << N_ << ",bbox=" << bbox() << "]"; + out << "ReducedGG[N=" << N_ << ",bbox=" << bbox() << "]"; +} + + +Renumber ReducedGG::crop(BoundingBox&) const { + NOTIMP; +} + + +Renumber ReducedGG::reorder(long scanningMode) const { + NOTIMP; } diff --git a/src/eckit/geo/grid/ReducedGG.h b/src/eckit/geo/grid/ReducedGG.h index a9ad52752..67265b01a 100644 --- a/src/eckit/geo/grid/ReducedGG.h +++ b/src/eckit/geo/grid/ReducedGG.h @@ -16,6 +16,11 @@ #include "eckit/geo/util.h" +namespace eckit { +class Fraction; +} + + namespace eckit::geo::grid { @@ -97,6 +102,9 @@ class ReducedGG : public Gaussian { // -- Overridden methods size_t numberOfPoints() const override; + Fraction getSmallestIncrement() const; + Renumber crop(BoundingBox&) const override; + Renumber reorder(long scanningMode) const override; // -- Class members // None diff --git a/src/eckit/geo/grid/RegularGrid.cc b/src/eckit/geo/grid/RegularGrid.cc index 9c498fc00..725f69601 100644 --- a/src/eckit/geo/grid/RegularGrid.cc +++ b/src/eckit/geo/grid/RegularGrid.cc @@ -32,8 +32,7 @@ RegularGrid::RegularGrid(const Configuration& config, Projection* projection) : projection_(projection), shape_(config), xPlus_(true), - yPlus_(false), - firstPointBottomLeft_(false) { + yPlus_(false) { ASSERT(projection_); auto get_long_first_key = [](const Configuration& config, const std::vector& keys) -> long { @@ -51,21 +50,19 @@ RegularGrid::RegularGrid(const Configuration& config, Projection* projection) : ASSERT(nx > 0); ASSERT(ny > 0); - std::vector grid; - ASSERT(config.get("grid", grid)); + auto grid = config.getDoubleVector("grid"); ASSERT(grid.size() == 2); - Point2 firstLL; - ASSERT(config.get("latitudeOfFirstGridPointInDegrees", firstLL[LLCOORDS::LAT])); - ASSERT(config.get("longitudeOfFirstGridPointInDegrees", firstLL[LLCOORDS::LON])); - auto first = projection.xy(firstLL); + auto first = projection->fwd(PointLonLat{config.getDouble("longitudeOfFirstGridPointInDegrees"), config.getDouble("latitudeOfFirstGridPointInDegrees")}); + auto first_xy = std::get(first); config.get("iScansPositively", xPlus_); // iScansPositively != 0 config.get("jScansPositively", yPlus_); // jScansPositively == 0 - config.get("first_point_bottom_left", firstPointBottomLeft_); - x_ = linspace(first.x(), grid[0], nx, firstPointBottomLeft_ || xPlus_); - y_ = linspace(first.y(), grid[1], ny, firstPointBottomLeft_ || yPlus_); + auto firstPointBottomLeft_ = config.getBool("first_point_bottom_left", false); + + x_ = linspace(first_xy.X, grid[0], nx, firstPointBottomLeft_ || xPlus_); + y_ = linspace(first_xy.Y, grid[1], ny, firstPointBottomLeft_ || yPlus_); grid_ = {x_, y_, projection}; ASSERT(!x_.empty()); @@ -86,8 +83,7 @@ RegularGrid::RegularGrid(const Projection& projection, const BoundingBox& bbox, y_(y), shape_(shape), xPlus_(x.front() <= x.back()), - yPlus_(y.front() < y.back()), - firstPointBottomLeft_(false) { + yPlus_(y.front() < y.back()) { grid_ = {x_, y_, projection}; if (!shape_.provided) { @@ -132,7 +128,7 @@ RegularGrid::LinearSpacing RegularGrid::linspace(double start, double step, long void RegularGrid::print(std::ostream& out) const { out << "RegularGrid[x=" << x_.spec() << ",y=" << y_.spec() << ",projection=" << grid_.projection().spec() - << ",firstPointBottomLeft=" << firstPointBottomLeft_ << ",bbox=" << bbox_ << "]"; + << ",bbox=" << bbox_ << "]"; } diff --git a/src/eckit/geo/grid/RegularGrid.h b/src/eckit/geo/grid/RegularGrid.h index 7cd352d59..c34050c31 100644 --- a/src/eckit/geo/grid/RegularGrid.h +++ b/src/eckit/geo/grid/RegularGrid.h @@ -76,7 +76,6 @@ class RegularGrid : public Grid { Shape shape_; bool xPlus_; bool yPlus_; - bool firstPointBottomLeft_; // -- Methods From 8fd9b0d7abd465f3355f793a41de1b8dd0a8bd71 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 11 Jun 2023 21:23:31 +0100 Subject: [PATCH 244/737] eckit::geo --- src/eckit/geo/BoundingBox.cc | 5 ++ src/eckit/geo/BoundingBox.h | 5 ++ src/eckit/geo/CMakeLists.txt | 6 +- src/eckit/geo/Figure.cc | 27 ++++++++ src/eckit/geo/Figure.h | 97 ++++++++++++++++++++++++++ src/eckit/geo/grid/RegularGrid.cc | 109 ++++++++++++------------------ src/eckit/geo/grid/RegularGrid.h | 22 +++--- 7 files changed, 193 insertions(+), 78 deletions(-) create mode 100644 src/eckit/geo/Figure.cc create mode 100644 src/eckit/geo/Figure.h diff --git a/src/eckit/geo/BoundingBox.cc b/src/eckit/geo/BoundingBox.cc index 385a808de..187c47a23 100644 --- a/src/eckit/geo/BoundingBox.cc +++ b/src/eckit/geo/BoundingBox.cc @@ -146,4 +146,9 @@ double BoundingBox::area(double radius) const { } +BoundingBox BoundingBox::make(const BoundingBox&, const Projection&) { + NOTIMP; +} + + } // namespace eckit::geo diff --git a/src/eckit/geo/BoundingBox.h b/src/eckit/geo/BoundingBox.h index cbea24d74..9596b0208 100644 --- a/src/eckit/geo/BoundingBox.h +++ b/src/eckit/geo/BoundingBox.h @@ -18,7 +18,10 @@ namespace eckit { class Configuration; +namespace geo { +class Projection; } +} // namespace eckit namespace eckit::geo { @@ -71,6 +74,8 @@ class BoundingBox { bool empty() const; double area(double radius) const; + static BoundingBox make(const BoundingBox&, const Projection&); + // -- Overridden methods // None diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 004425c74..73ec4faa6 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -4,8 +4,12 @@ list(APPEND eckit_geo_srcs Domain.cc Domain.h Earth.h + Figure.cc + Figure.h Grid.cc Grid.h + Increments.cc + Increments.h Iterator.cc Iterator.h Point.cc @@ -15,8 +19,6 @@ list(APPEND eckit_geo_srcs Range.cc Range.h Renumber.h - Increments.cc - Increments.h Scanner.cc Scanner.h Search.h diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc new file mode 100644 index 000000000..67b3685a9 --- /dev/null +++ b/src/eckit/geo/Figure.cc @@ -0,0 +1,27 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Figure.h" + +#include "eckit/config/Configuration.h" + + +namespace eckit::geo { + + +Figure::Figure(const Configuration& config) /*: + Figure(config.getDouble("a"), config.getDouble("b"))*/ +{ +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h new file mode 100644 index 000000000..bafe5ac26 --- /dev/null +++ b/src/eckit/geo/Figure.h @@ -0,0 +1,97 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + + +namespace eckit { +class Configuration; +} + + +namespace eckit::geo { + + +class Figure { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + Figure(const Configuration&); + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None + + friend std::ostream& operator<<(std::ostream& out, const Figure& p) { + return out << '{' << '}'; + } +}; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/grid/RegularGrid.cc b/src/eckit/geo/grid/RegularGrid.cc index 725f69601..c1678e0a2 100644 --- a/src/eckit/geo/grid/RegularGrid.cc +++ b/src/eckit/geo/grid/RegularGrid.cc @@ -20,6 +20,7 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/config/Resource.h" +#include "eckit/geo/Earth.h" #include "eckit/geo/Iterator.h" #include "eckit/utils/StringTools.h" @@ -27,10 +28,10 @@ namespace eckit::geo::grid { -RegularGrid::RegularGrid(const Configuration& config, Projection* projection) : +RegularGrid::RegularGrid(Projection* projection, const Configuration& config) : Grid(config), projection_(projection), - shape_(config), + figure_(config), xPlus_(true), yPlus_(false) { ASSERT(projection_); @@ -61,9 +62,14 @@ RegularGrid::RegularGrid(const Configuration& config, Projection* projection) : auto firstPointBottomLeft_ = config.getBool("first_point_bottom_left", false); - x_ = linspace(first_xy.X, grid[0], nx, firstPointBottomLeft_ || xPlus_); - y_ = linspace(first_xy.Y, grid[1], ny, firstPointBottomLeft_ || yPlus_); - grid_ = {x_, y_, projection}; + auto linspace = [](double start, double step, long num, bool plus) -> LinearSpacing { + ASSERT(step >= 0.); + // return {start, start + step * double(plus ? num - 1 : 1 - num), num}; + NOTIMP; + }; + + x_ = linspace(first_xy.X, grid[0], nx, firstPointBottomLeft_ || xPlus_); + y_ = linspace(first_xy.Y, grid[1], ny, firstPointBottomLeft_ || yPlus_); ASSERT(!x_.empty()); ASSERT(!y_.empty()); @@ -72,63 +78,36 @@ RegularGrid::RegularGrid(const Configuration& config, Projection* projection) : auto w = x_.front() > x_.back() ? x_.back() : x_.front(); auto e = x_.front() > x_.back() ? x_.front() : x_.back(); - bbox(projection.lonlatBoundingBox({n, w, s, e})); + bbox(BoundingBox::make({n, w, s, e}, *projection_)); } -RegularGrid::RegularGrid(const Projection& projection, const BoundingBox& bbox, const LinearSpacing& x, - const LinearSpacing& y, const Shape& shape) : +RegularGrid::RegularGrid(Projection* projection, const BoundingBox& bbox, const LinearSpacing& x, + const LinearSpacing& y, const Figure& figure) : Grid(bbox), x_(x), y_(y), - shape_(shape), + figure_(figure), xPlus_(x.front() <= x.back()), yPlus_(y.front() < y.back()) { - grid_ = {x_, y_, projection}; - - if (!shape_.provided) { - shape_ = {grid_.projection().spec()}; - } } RegularGrid::~RegularGrid() = default; -RegularGrid::Configuration RegularGrid::make_projection_from_proj(const Configuration& config) { - std::string proj; - config.get("proj", proj); - - if (proj.empty() || !::atlas::projection::ProjectionFactory::has("proj")) { - return {}; - } - - Configuration spec("type", "proj"); - spec.set("proj", proj); - - std::string projSource; - if (config.get("projSource", projSource) && !projSource.empty()) { - spec.set("proj_source", projSource); - } - - std::string projGeocentric; - if (config.get("projGeocentric", projGeocentric) && !projGeocentric.empty()) { - spec.set("proj_geocentric", projGeocentric); +Projection* RegularGrid::make_projection_from_proj(const Configuration& config) { + if (std::string proj; + config.get("proj", proj)) { + return ProjectionFactory::build("proj", config); } - return spec; -} - - -RegularGrid::LinearSpacing RegularGrid::linspace(double start, double step, long num, bool plus) { - ASSERT(step >= 0.); - return {start, start + step * double(plus ? num - 1 : 1 - num), num}; + return nullptr; } void RegularGrid::print(std::ostream& out) const { - out << "RegularGrid[x=" << x_.spec() << ",y=" << y_.spec() << ",projection=" << grid_.projection().spec() - << ",bbox=" << bbox_ << "]"; + NOTIMP; } @@ -164,10 +143,9 @@ Renumber RegularGrid::reorder(long /*scanningMode*/) const { Iterator* RegularGrid::iterator() const { class RegularGridIterator : public Iterator { - Projection* projection_; + const Projection& projection_; const LinearSpacing& x_; const LinearSpacing& y_; - PointLonLat pLonLat_; size_t ni_; size_t nj_; @@ -181,11 +159,12 @@ Iterator* RegularGrid::iterator() const { out << ",i=" << i_ << ",j=" << j_ << ",count=" << count_ << "]"; } - bool next(double& _lat, double& _lon) override { + bool operator++() override { if (j_ < nj_ && i_ < ni_) { - pLonLat_ = projection_.lonlat({x_[i_], y_[j_]}); - _lat = lat(pLonLat_.lat()); - _lon = lon(pLonLat_.lon()); + const auto p = projection_.inv(Point2{x_[i_], y_[j_]}); + const auto ll = std::get(p); + // _lat = ll.lat; + // _lon = ll.lon; if (i_ > 0 || j_ > 0) { count_++; @@ -206,8 +185,8 @@ Iterator* RegularGrid::iterator() const { size_t size() const override { NOTIMP; } public: - RegularGridIterator(Projection projection, const LinearSpacing& x, const LinearSpacing& y) : - projection_(std::move(projection)), x_(x), y_(y), ni_(x.size()), nj_(y.size()), i_(0), j_(0), count_(0) {} + RegularGridIterator(const Projection& projection, const LinearSpacing& x, const LinearSpacing& y) : + projection_(projection), x_(x), y_(y), ni_(x.size()), nj_(y.size()), i_(0), j_(0), count_(0) {} ~RegularGridIterator() override = default; RegularGridIterator(const RegularGridIterator&) = delete; @@ -216,18 +195,18 @@ Iterator* RegularGrid::iterator() const { RegularGridIterator& operator=(RegularGridIterator&&) = delete; }; - return new RegularGridIterator(grid_.projection(), x_, y_); + return new RegularGridIterator(*projection_, x_, y_); } struct Lambert : RegularGrid { Lambert(const Configuration& config) : - RegularGrid(config, make_projection(config)) { + RegularGrid(make_projection(config), config) { } static Projection* make_projection(const Configuration& config) { - if (auto spec = RegularGrid::make_projection_from_proj(config); spec != nullptr) { - return spec; + if (auto p = RegularGrid::make_projection_from_proj(config); p != nullptr) { + return p; } auto LaDInDegrees = config.getDouble("LaDInDegrees"); @@ -247,14 +226,14 @@ struct Lambert : RegularGrid { struct LambertAzimuthalEqualArea : RegularGrid { LambertAzimuthalEqualArea(const Configuration& config) : - RegularGrid(config, make_projection(config)) {} + RegularGrid(make_projection(config), config) {} - LambertAzimuthalEqualArea(const Projection& projection, const BoundingBox& bbox, const LinearSpacing& x, const LinearSpacing& y, const Shape& shape) : + LambertAzimuthalEqualArea(Projection* projection, const BoundingBox& bbox, const LinearSpacing& x, const LinearSpacing& y, const Figure& shape) : RegularGrid(projection, bbox, x, y, shape) {} static Projection* make_projection(const Configuration& config) { - if (auto spec = RegularGrid::make_projection_from_proj(config); spec != nullptr) { - return spec; + if (auto p = RegularGrid::make_projection_from_proj(config); p != nullptr) { + return p; } double standardParallel = 0.; @@ -272,21 +251,21 @@ struct LambertAzimuthalEqualArea : RegularGrid { struct Mercator : RegularGrid { - Mercator(const Configuration&) : - RegularGrid(config, RegularGrid::make_projection_from_proj(config)) {} + Mercator(const Configuration& config) : + RegularGrid(RegularGrid::make_projection_from_proj(config), config) {} }; struct PolarStereographic : RegularGrid { PolarStereographic(const Configuration& config) : - RegularGrid(config, RegularGrid::make_projection_from_proj(config)) {} + RegularGrid(RegularGrid::make_projection_from_proj(config), config) {} }; -static const GridBuilder __builder("lambert"); -static const GridBuilder __builder("lambert_azimuthal_equal_area"); -static const GridBuilder __builder("mercator"); -static const GridBuilder __builder("polar_stereographic"); +static const GridBuilder __builder1("lambert"); +static const GridBuilder __builder2("lambert_azimuthal_equal_area"); +static const GridBuilder __builder3("mercator"); +static const GridBuilder __builder4("polar_stereographic"); } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularGrid.h b/src/eckit/geo/grid/RegularGrid.h index c34050c31..faf0b8973 100644 --- a/src/eckit/geo/grid/RegularGrid.h +++ b/src/eckit/geo/grid/RegularGrid.h @@ -15,15 +15,11 @@ #include #include +#include "eckit/geo/Figure.h" #include "eckit/geo/Grid.h" #include "eckit/geo/Projection.h" -namespace eckit::geo { -class Shape {}; -} // namespace eckit::geo - - namespace eckit::geo::grid { @@ -38,10 +34,8 @@ class RegularGrid : public Grid { // -- Constructors - RegularGrid(const Configuration&, Projection*); - RegularGrid(const Projection&, const BoundingBox&, const LinearSpacing& x, const LinearSpacing& y, - const Shape&); RegularGrid(const RegularGrid&) = delete; + RegularGrid(RegularGrid&&) = delete; // -- Destructor @@ -53,6 +47,7 @@ class RegularGrid : public Grid { // -- Operators RegularGrid& operator=(const RegularGrid&) = delete; + RegularGrid& operator=(RegularGrid&&) = delete; // -- Methods // None @@ -68,19 +63,24 @@ class RegularGrid : public Grid { // None protected: + // -- Constructors + + RegularGrid(Projection*, const Configuration&); + RegularGrid(Projection*, const BoundingBox&, const LinearSpacing& x, const LinearSpacing& y, + const Figure&); + // -- Members std::unique_ptr projection_; LinearSpacing x_; LinearSpacing y_; - Shape shape_; + Figure figure_; bool xPlus_; bool yPlus_; // -- Methods - static Configuration make_proj_spec(const Configuration&); - static LinearSpacing linspace(double start, double step, long num, bool plus); + static Projection* make_projection_from_proj(const Configuration&); // -- Overridden methods From 26f84bbb45d55342b555af1d51a47094395172bf Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 11 Jun 2023 21:49:47 +0100 Subject: [PATCH 245/737] eckit::geo --- src/eckit/geo/CMakeLists.txt | 4 - src/eckit/geo/grid/ORCA.cc | 140 ------------------- src/eckit/geo/grid/ORCA.h | 102 -------------- src/eckit/geo/grid/SpaceView.cc | 235 -------------------------------- src/eckit/geo/grid/SpaceView.h | 114 ---------------- 5 files changed, 595 deletions(-) delete mode 100644 src/eckit/geo/grid/ORCA.cc delete mode 100644 src/eckit/geo/grid/ORCA.h delete mode 100644 src/eckit/geo/grid/SpaceView.cc delete mode 100644 src/eckit/geo/grid/SpaceView.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 73ec4faa6..61c43afc0 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -28,8 +28,6 @@ list(APPEND eckit_geo_srcs grid/GaussianIterator.h grid/IrregularLatlon.cc grid/IrregularLatlon.h - grid/ORCA.cc - grid/ORCA.h grid/ReducedGG.cc grid/ReducedGG.h grid/ReducedLL.cc @@ -40,8 +38,6 @@ list(APPEND eckit_geo_srcs grid/RegularGrid.h grid/RegularLL.cc grid/RegularLL.h - grid/SpaceView.cc - grid/SpaceView.h grid/UnstructuredGrid.cc grid/UnstructuredGrid.h projection/LonLatToXYZ.cc diff --git a/src/eckit/geo/grid/ORCA.cc b/src/eckit/geo/grid/ORCA.cc deleted file mode 100644 index 5e9711636..000000000 --- a/src/eckit/geo/grid/ORCA.cc +++ /dev/null @@ -1,140 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/ORCA.h" - -#include -#include -#include - -#include "eckit/geo/Iterator.h" -#include "eckit/geo/Projection.h" - - -namespace eckit::geo::grid { - - -// order is important -static const std::vector> grib_keys{ - {"orca_name", "unstructuredGridType"}, {"orca_arrangement", "unstructuredGridSubtype"}, {"uid", "uuidOfHGrid"}}; - - -ORCA::ORCA(const std::string& uid) : - Grid(BoundingBox() /*assumed global*/), spec_(atlas::grid::SpecRegistry::get(uid)) {} - - -ORCA::ORCA(const Configuration& config) : - ORCA([&config]() { - std::string uid; - ASSERT(config.get("uid", uid)); - return uid; - }()) {} - - -ORCA::~ORCA() = default; - - -size_t ORCA::numberOfPoints() const { - return static_cast(atlasGridRef().size()); -} - - -void ORCA::print(std::ostream& out) const { - out << "ORCA[spec=" << spec_ << "]"; -} - - -Iterator* ORCA::iterator() const { - class ORCAIterator : public Iterator { - ::atlas::Grid grid_; // Note: needs the object because IterateLonLat uses a Grid reference - ::atlas::Grid::IterateLonLat lonlat_; - - decltype(lonlat_)::iterator it_; - decltype(lonlat_)::iterator::value_type p_; - - const size_t total_; - size_t count_; - bool first_; - - void print(std::ostream& out) const override { - out << "ORCAIterator["; - Iterator::print(out); - out << ",count=" << count_ << ",total=" << total_ << "]"; - } - - bool next(double& _lat, double& _lon) override { - if (it_.next(p_)) { - point_[0] = p_.lat(); - point_[1] = p_.lon(); - _lat = p_.lat(); - _lon = p_.lon(); - - if (first_) { - first_ = false; - } - else { - count_++; - } - - return true; - } - - ASSERT(count_ == total_); - return false; - } - - size_t index() const override { return count_; } - - size_t size() const override { NOTIMP; } - - public: - ORCAIterator(::atlas::Grid grid) : - grid_(grid), - lonlat_(grid.lonlat()), - it_(lonlat_.begin()), - total_(size_t(grid.size())), - count_(0), - first_(true) {} - - ~ORCAIterator() override = default; - - ORCAIterator(const ORCAIterator&) = delete; - ORCAIterator(ORCAIterator&&) = delete; - ORCAIterator& operator=(const ORCAIterator&) = delete; - ORCAIterator& operator=(ORCAIterator&&) = delete; - }; - return new ORCAIterator(atlasGridRef()); -} - - -const atlas::Grid& ORCA::atlasGridRef() const { - return grid_ ? grid_ : (grid_ = atlas::Grid(spec_)); -} - - -#if 0 -Grid* GridBuilder::make(const Configuration& config) { - - // specially-named unstructured grids - std::string grid; - if (config.get("grid", grid)) { - if (!key::grid::ORCAPattern::match(grid, config).empty()) { - return new other::ORCA(config); - } - } - - return new UnstructuredGrid(config); -} -#endif - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ORCA.h b/src/eckit/geo/grid/ORCA.h deleted file mode 100644 index 6e572d8ee..000000000 --- a/src/eckit/geo/grid/ORCA.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include - -#include "eckit/geo/Grid.h" - - -namespace eckit::geo::grid { - - -class ORCA : public Grid { -public: - // -- Exceptions - // None - - // -- Constructors - - ORCA(const std::string& uid); - ORCA(const Configuration&); - ORCA(const ORCA&) = delete; - - // -- Destructor - - ~ORCA() override; - - // -- Convertors - // None - - // -- Operators - - ORCA& operator=(const ORCA&) = delete; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - void print(std::ostream&) const override; - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - size_t numberOfPoints() const override; - - bool includesNorthPole() const override { return true; } - bool includesSouthPole() const override { return true; } - bool isPeriodicWestEast() const override { return true; } - - Iterator* iterator() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/SpaceView.cc b/src/eckit/geo/grid/SpaceView.cc deleted file mode 100644 index 1309c0151..000000000 --- a/src/eckit/geo/grid/SpaceView.cc +++ /dev/null @@ -1,235 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/SpaceView.h" - -#include -#include -#include -#include -#include -#include - -#include "eckit/config/MappedConfiguration.h" -#include "eckit/geo/Iterator.h" -#include "eckit/geo/util.h" -#include "eckit/types/FloatCompare.h" - - -namespace eckit::geo::grid { - - -static const GridBuilder __builder("space_view"); - - -namespace detail { - - -template -EXTERNAL_T get(const Configuration& config, const std::string& key) { - INTERNAL_T value; - ASSERT(config.get(key, value)); - return static_cast(value); -} - - -SpaceViewInternal::SpaceViewInternal(const Configuration& config) { - auto earthIsOblate = get(config, "earthIsOblate"); - auto a = get(config, earthIsOblate ? "earthMajorAxis" : "radius"); - auto b = earthIsOblate ? get(config, "earthMinorAxis") : a; - - auto Nr = get(config, "NrInRadiusOfEarthScaled"); - ASSERT(Nr > 1.); - - auto h = (Nr - 1.) * a; - - Lop_ = get(config, "longitudeOfSubSatellitePointInDegrees"); - auto Lap = get(config, "latitudeOfSubSatellitePointInDegrees"); - ASSERT(types::is_approximately_equal(Lap, 0.)); - - // ASSERT(get(config, "orientationOfTheGridInDegrees") == 180); - - - // projection - auto proj = [](double h, double a, double b, double lon_0) { - auto _h = " +h=" + std::to_string(h); - auto _l = types::is_approximately_equal(lon_0, 0.) ? "" : " +lon_0=" + std::to_string(lon_0); - auto _e = types::is_approximately_equal(a, b) ? " +R=" + std::to_string(a) - : " +a=" + std::to_string(a) + " +b=" + std::to_string(b); - return "+proj=geos +type=crs +sweep=y" + _h + _l + _e; - }; - - projection_.reset(ProjectionFactory::build("proj", MappedConfiguration({{"proj", proj(h, a, b, Lop_)}}))); - - projectionGreenwich_.reset(ProjectionFactory::build("proj", MappedConfiguration({{"proj", proj(h, a, b, 0)}}))); - - // (x, y) space - Nx_ = get(config, "Nx"); - ASSERT(1 < Nx_); - - auto ip = get(config, "iScansPositively"); - auto xp = get(config, "XpInGridLengths"); - auto dx = get(config, "dx"); - ASSERT(dx > 0); - - auto rx = 2. * std::asin(1. / Nr) / dx * h; // (height factor is PROJ-specific) - - (ip ? xa_ : xb_) = rx * (-xp); - (ip ? xb_ : xa_) = rx * (-xp + double(Nx_ - 1)); - - Ny_ = get(config, "Ny"); - ASSERT(1 < Ny_); - - auto jp = get(config, "jScansPositively"); - auto yp = get(config, "YpInGridLengths"); - auto dy = get(config, "dy"); - ASSERT(dy > 0); - - auto ry = 2. * std::asin(1. / Nr) / dy * h; // (height factor is PROJ-specific) - - (jp ? ya_ : yb_) = ry * (-yp); - (jp ? yb_ : ya_) = ry * (-yp + double(Ny_ - 1)); - - - // longest element diagonal, a multiple of a reference central element diagonal (avoiding distortion) - LongestElementDiagonal_ = 20. * Earth::distance(projection_->inv(geometry::Point2{-rx / 2, ry / 2}), projection_->inv(geometry::Point2{rx / 2, -ry / 2})); - ASSERT(0. < LongestElementDiagonal_); - - - // bounding box -#if 1 - // [1] page 25, solution of s_d^2=0, restrained at x=0 (lon) and y=0 (lat). Note: uses a, b, height defined there - auto eps_ll = 1e-6; - - auto n = 90. - util::radian_to_degree * 0.151347 + eps_ll; - auto s = -n; - - auto e = 90. - util::radian_to_degree * 0.151853 + eps_ll + Lop_; - auto w = 2. * Lop_ - e; -#else - auto geometric_maximum = [](double x_min, double x_eps, const std::function& f, - double f_eps = 1.e-9, size_t it_max = 1000) { - size_t it = 0; - auto x = x_min; - auto fx = f(x); - - for (auto dx = x_eps; f_eps < dx && it < it_max; ++it) { - auto fx_new = f(x + dx); - if (!std::isfinite(fx_new) || fx_new < fx) { - dx /= 2.; - } - else { - x += dx; - fx = fx_new; - dx *= 2.; - } - } - - ASSERT(0. < fx && fx < 90.); - return fx; - }; - - auto eps_xy = 1e-6 * h; - auto eps_ll = 1e-6; - - auto max_lon = geometric_maximum(0., eps_xy, [&](double x) { return projectionGreenwich_->inv({x, 0}).lon(); }); - auto w = Lop_ - max_lon - eps_ll; - auto e = Lop_ + max_lon + eps_ll; - - auto max_lat = geometric_maximum(0., eps_xy, [&](double y) { return projectionGreenwich_->inv({0, y}).lat(); }); - auto n = max_lat + eps_ll; - auto s = -n; -#endif - - bbox_ = {n, w, s, e}; -} - - -const std::vector& SpaceViewInternal::lonlat() const { - if (lonlat_.empty()) { - ASSERT(projectionGreenwich_); // Greenwich-centred (avoids PROJ normalisation) - lonlat_.reserve(Nx_ * Ny_); - - size_t index = 0; - for (const auto& _y : y()) { - for (const auto& _x : x()) { - // auto& ll = lonlat_[index++]; - PointLonLat ll = projectionGreenwich_->inv({_x, _y}); - if (std::isfinite(ll.lon) && std::isfinite(ll.lat)) { - ASSERT(-90. < ll.lon && ll.lon < 90.); - - ll.lon += Lop_; - lonlat_.push_back(ll); - } - } - } - } - - ASSERT(!lonlat_.empty()); - return lonlat_; -} - - -} // namespace detail - - -SpaceView::SpaceView(const Configuration& config) : - detail::SpaceViewInternal(config), - RegularGrid(SpaceViewInternal::projection_, SpaceViewInternal::bbox_, SpaceViewInternal::x(), - SpaceViewInternal::y(), {config}) {} - - -Iterator* SpaceView::iterator() const { - class SpaceViewIterator : public Iterator { - const std::vector& lonlat_; - size_t count_; - - void print(std::ostream& out) const override { - out << "SpaceViewIterator["; - Iterator::print(out); - out << ",count=" << count_ << "]"; - } - - bool next(double& _lat, double& _lon) override { - while (count_ < lonlat_.size()) { - // only one of (lon, lat) needs to be checked - const auto& ll = lonlat_[count_++]; - if (std::isfinite(ll.lon())) { - _lat = lat(ll.lat()); - _lon = lon(ll.lon()); - return true; - } - } - - return false; - } - - size_t index() const override { return count_; } - - size_t size() const override { NOTIMP; } - - public: - SpaceViewIterator(const std::vector& lonlat) : - lonlat_(lonlat), count_(0) {} - ~SpaceViewIterator() override = default; - - SpaceViewIterator(const SpaceViewIterator&) = delete; - SpaceViewIterator(SpaceViewIterator&&) = delete; - SpaceViewIterator& operator=(const SpaceViewIterator&) = delete; - SpaceViewIterator& operator=(SpaceViewIterator&&) = delete; - }; - - return new SpaceViewIterator(lonlat()); -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/SpaceView.h b/src/eckit/geo/grid/SpaceView.h deleted file mode 100644 index daaf0f141..000000000 --- a/src/eckit/geo/grid/SpaceView.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include - -#include "eckit/geo/grid/RegularGrid.h" - - -namespace eckit::geo::grid { -namespace detail { - - -/* - * References: - * - [1] LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) - * - [2] MSG Ground Segment LRIT/HRIT Mission Specific Implementation, EUMETSAT Document, (EUM/MSG/SPE/057, Issue 6, 21. - * June 2006) - * - [3] MSG Ground Segment LRIT/HRIT Mission Specific Implementation, EUMETSAT Document, (EUM/MSG/SPE/057 v7 e-signed. - * 30 November 2015) - */ -struct SpaceViewInternal { - SpaceViewInternal(const Configuration&); - std::unique_ptr projection_; - std::unique_ptr projectionGreenwich_; - BoundingBox bbox_; - - LinearSpacing x() const { return {xa_, xb_, Nx_, true}; } - LinearSpacing y() const { return {ya_, yb_, Ny_, true}; } - - const std::vector& lonlat() const; - - long Nx_; - long Ny_; - double xa_; - double xb_; - double ya_; - double yb_; - double LongestElementDiagonal_; - double Lop_; - -private: - mutable std::vector lonlat_; -}; - - -} // namespace detail - - -class SpaceView final : public detail::SpaceViewInternal, public RegularGrid { -public: - // -- Exceptions - // None - - // -- Constructors - - SpaceView(const Configuration&); - SpaceView(const SpaceView&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - SpaceView& operator=(const SpaceView&) = delete; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - Iterator* iterator() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid From 9c0eabd6c17a35113b50c0d05e6d742e0774a907 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 11 Jun 2023 22:44:22 +0100 Subject: [PATCH 246/737] eckit::geo --- src/eckit/geo/Grid.h | 16 +++++++++------- src/eckit/geo/grid/Gaussian.cc | 6 ++++++ src/eckit/geo/grid/Gaussian.h | 1 + src/eckit/geo/grid/ReducedGG.cc | 6 ++++++ src/eckit/geo/grid/ReducedGG.h | 1 + 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 0dd42fbd0..4159c7015 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -54,14 +54,16 @@ class Grid { // -- Methods - virtual Iterator* iterator() const; - virtual bool includesNorthPole() const; - virtual bool includesSouthPole() const; - virtual bool isPeriodicWestEast() const; - virtual const BoundingBox& boundingBox() const; - virtual size_t numberOfPoints() const; - virtual void print(std::ostream&) const; virtual Domain domain() const; + virtual const BoundingBox& boundingBox() const; + + virtual Iterator* iterator() const = 0; + virtual size_t numberOfPoints() const = 0; + virtual void print(std::ostream&) const = 0; + + virtual bool includesNorthPole() const = 0; + virtual bool includesSouthPole() const = 0; + virtual bool isPeriodicWestEast() const = 0; virtual Renumber crop(BoundingBox&) const = 0; virtual Renumber reorder(long scanningMode) const = 0; diff --git a/src/eckit/geo/grid/Gaussian.cc b/src/eckit/geo/grid/Gaussian.cc index e85d8be0a..ca36e6263 100644 --- a/src/eckit/geo/grid/Gaussian.cc +++ b/src/eckit/geo/grid/Gaussian.cc @@ -17,6 +17,7 @@ #include #include "eckit/geo/Domain.h" +#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -36,6 +37,11 @@ Gaussian::Gaussian(const Configuration& config) : } +const std::vector& Gaussian::latitudes() const { + return latitudes_.empty() ? (latitudes_ = util::gaussian_latitudes(N_, false)) : latitudes_; +} + + Gaussian::~Gaussian() = default; diff --git a/src/eckit/geo/grid/Gaussian.h b/src/eckit/geo/grid/Gaussian.h index 4ccee2bec..57f1b39e2 100644 --- a/src/eckit/geo/grid/Gaussian.h +++ b/src/eckit/geo/grid/Gaussian.h @@ -55,6 +55,7 @@ class Gaussian : public Grid { size_t N_; double angularPrecision_; + mutable std::vector latitudes_; // -- Methods diff --git a/src/eckit/geo/grid/ReducedGG.cc b/src/eckit/geo/grid/ReducedGG.cc index 9bd9e1616..206710d3c 100644 --- a/src/eckit/geo/grid/ReducedGG.cc +++ b/src/eckit/geo/grid/ReducedGG.cc @@ -23,6 +23,7 @@ #include "eckit/geo/Iterator.h" #include "eckit/geo/Projection.h" +#include "eckit/geo/grid/GaussianIterator.h" #include "eckit/types/Fraction.h" @@ -140,6 +141,11 @@ void ReducedGG::correctWestEast(double& w, double& e) const { } +Iterator* ReducedGG::iterator() const { + NOTIMP; +} + + const pl_type& ReducedGG::pls() const { ASSERT(pl_.size() == N_ * 2); ASSERT(pl_.size() >= k_ + Nj_); diff --git a/src/eckit/geo/grid/ReducedGG.h b/src/eckit/geo/grid/ReducedGG.h index 67265b01a..6ade62448 100644 --- a/src/eckit/geo/grid/ReducedGG.h +++ b/src/eckit/geo/grid/ReducedGG.h @@ -83,6 +83,7 @@ class ReducedGG : public Gaussian { // -- Overridden methods + Iterator* iterator() const override; bool isPeriodicWestEast() const override; void print(std::ostream& out) const override; From 4065386d9d5f5a6b2b7aabc4527fdbe5cec012f1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 30 Jun 2023 16:12:51 +0100 Subject: [PATCH 247/737] eckit::grid --- src/eckit/CMakeLists.txt | 2 +- src/eckit/{geo => grid}/BoundingBox.cc | 10 +-- src/eckit/{geo => grid}/BoundingBox.h | 6 +- src/eckit/{geo => grid}/CMakeLists.txt | 62 +++++++++--------- src/eckit/{geo => grid}/Domain.cc | 10 +-- src/eckit/{geo => grid}/Domain.h | 4 +- src/eckit/{geo => grid}/Earth.h | 4 +- src/eckit/{geo => grid}/Figure.cc | 6 +- src/eckit/{geo => grid}/Figure.h | 4 +- src/eckit/{geo => grid}/Grid.cc | 12 ++-- src/eckit/{geo => grid}/Grid.h | 14 ++-- src/eckit/{geo => grid}/Increments.cc | 6 +- src/eckit/{geo => grid}/Increments.h | 4 +- src/eckit/{geo => grid}/Iterator.cc | 8 +-- src/eckit/{geo => grid}/Iterator.h | 8 +-- src/eckit/{geo => grid}/Point.cc | 8 +-- src/eckit/{geo => grid}/Point.h | 6 +- src/eckit/{geo => grid}/Projection.cc | 6 +- src/eckit/{geo => grid}/Projection.h | 6 +- src/eckit/{geo => grid}/Range.cc | 8 +-- src/eckit/{geo => grid}/Range.h | 4 +- src/eckit/{geo => grid}/Renumber.h | 4 +- src/eckit/{geo => grid}/Scanner.cc | 6 +- src/eckit/{geo => grid}/Scanner.h | 4 +- src/eckit/{geo => grid}/Search.h | 4 +- .../{geo/grid => grid/detail}/Gaussian.cc | 10 +-- .../{geo/grid => grid/detail}/Gaussian.h | 6 +- .../grid => grid/detail}/GaussianIterator.cc | 6 +- .../grid => grid/detail}/GaussianIterator.h | 10 +-- .../grid => grid/detail}/IrregularLatlon.cc | 10 +-- .../grid => grid/detail}/IrregularLatlon.h | 6 +- .../{geo/grid => grid/detail}/ReducedGG.cc | 12 ++-- .../{geo/grid => grid/detail}/ReducedGG.h | 8 +-- .../{geo/grid => grid/detail}/ReducedLL.cc | 12 ++-- .../{geo/grid => grid/detail}/ReducedLL.h | 6 +- .../{geo/grid => grid/detail}/RegularGG.cc | 10 +-- .../{geo/grid => grid/detail}/RegularGG.h | 6 +- .../{geo/grid => grid/detail}/RegularGrid.cc | 10 +-- .../{geo/grid => grid/detail}/RegularGrid.h | 10 +-- .../{geo/grid => grid/detail}/RegularLL.cc | 14 ++-- .../{geo/grid => grid/detail}/RegularLL.h | 8 +-- .../grid => grid/detail}/UnstructuredGrid.cc | 12 ++-- .../grid => grid/detail}/UnstructuredGrid.h | 6 +- .../{geo => grid}/grib/GribConfiguration.cc | 6 +- .../{geo => grid}/grib/GribConfiguration.h | 4 +- .../{geo => grid}/projection/LonLatToXYZ.cc | 6 +- .../{geo => grid}/projection/LonLatToXYZ.h | 6 +- src/eckit/{geo => grid}/projection/None.cc | 6 +- src/eckit/{geo => grid}/projection/None.h | 6 +- src/eckit/{geo => grid}/projection/PROJ.cc | 6 +- src/eckit/{geo => grid}/projection/PROJ.h | 6 +- .../{geo => grid}/projection/Rotation.cc | 8 +-- src/eckit/{geo => grid}/projection/Rotation.h | 6 +- src/eckit/{geo => grid}/scanner/Reduced.cc | 6 +- src/eckit/{geo => grid}/scanner/Reduced.h | 12 ++-- src/eckit/{geo => grid}/scanner/Regular.cc | 6 +- src/eckit/{geo => grid}/scanner/Regular.h | 8 +-- .../{geo => grid}/scanner/Unstructured.cc | 6 +- .../{geo => grid}/scanner/Unstructured.h | 6 +- src/eckit/{geo => grid}/util.cc | 6 +- src/eckit/{geo => grid}/util.h | 4 +- src/eckit/{geo => grid}/util/arange.cc | 4 +- .../{geo => grid}/util/gaussian_latitudes.cc | 4 +- src/eckit/{geo => grid}/util/linspace.cc | 4 +- .../{geo => grid}/util/monotonic_crop.cc | 4 +- .../util/reduced_classical_pl.cc | 6 +- .../util/reduced_octahedral_pl.cc | 6 +- src/eckit/{geo => grid}/util/regular_pl.cc | 6 +- tests/CMakeLists.txt | 4 +- tests/{geo => grid}/CMakeLists.txt | 8 +-- tests/{geo => grid}/reduced_gg.grib2 | Bin tests/{geo => grid}/reduced_ll.grib1 | Bin tests/{geo => grid}/regular_gg.grib1 | Bin tests/{geo => grid}/regular_ll.grib1 | Bin tests/{geo => grid}/test_grib.cc | 24 +++---- tests/{geo => grid}/test_iterator.cc | 12 ++-- tests/{geo => grid}/test_param.cc | 0 tests/{geo => grid}/test_projection.cc | 14 ++-- .../test_projection_ll_to_xyz.cc | 10 +-- tests/{geo => grid}/test_projection_proj.cc | 24 +++---- .../{geo => grid}/test_projection_rotation.cc | 10 +-- tests/{geo => grid}/test_search.cc | 10 +-- tests/{geo => grid}/test_types.cc | 4 +- tests/{geo => grid}/test_util.cc | 4 +- 84 files changed, 325 insertions(+), 325 deletions(-) rename src/eckit/{geo => grid}/BoundingBox.cc (96%) rename src/eckit/{geo => grid}/BoundingBox.h (97%) rename src/eckit/{geo => grid}/CMakeLists.txt (51%) rename src/eckit/{geo => grid}/Domain.cc (95%) rename src/eckit/{geo => grid}/Domain.h (97%) rename src/eckit/{geo => grid}/Earth.h (93%) rename src/eckit/{geo => grid}/Figure.cc (86%) rename src/eckit/{geo => grid}/Figure.h (96%) rename src/eckit/{geo => grid}/Grid.cc (92%) rename src/eckit/{geo => grid}/Grid.h (93%) rename src/eckit/{geo => grid}/Increments.cc (87%) rename src/eckit/{geo => grid}/Increments.h (95%) rename src/eckit/{geo => grid}/Iterator.cc (95%) rename src/eckit/{geo => grid}/Iterator.h (97%) rename src/eckit/{geo => grid}/Point.cc (82%) rename src/eckit/{geo => grid}/Point.h (89%) rename src/eckit/{geo => grid}/Projection.cc (98%) rename src/eckit/{geo => grid}/Projection.h (96%) rename src/eckit/{geo => grid}/Range.cc (95%) rename src/eckit/{geo => grid}/Range.h (97%) rename src/eckit/{geo => grid}/Renumber.h (90%) rename src/eckit/{geo => grid}/Scanner.cc (95%) rename src/eckit/{geo => grid}/Scanner.h (96%) rename src/eckit/{geo => grid}/Search.h (97%) rename src/eckit/{geo/grid => grid/detail}/Gaussian.cc (94%) rename src/eckit/{geo/grid => grid/detail}/Gaussian.h (94%) rename src/eckit/{geo/grid => grid/detail}/GaussianIterator.cc (95%) rename src/eckit/{geo/grid => grid/detail}/GaussianIterator.h (87%) rename src/eckit/{geo/grid => grid/detail}/IrregularLatlon.cc (95%) rename src/eckit/{geo/grid => grid/detail}/IrregularLatlon.h (94%) rename src/eckit/{geo/grid => grid/detail}/ReducedGG.cc (96%) rename src/eckit/{geo/grid => grid/detail}/ReducedGG.h (94%) rename src/eckit/{geo/grid => grid/detail}/ReducedLL.cc (95%) rename src/eckit/{geo/grid => grid/detail}/ReducedLL.h (93%) rename src/eckit/{geo/grid => grid/detail}/RegularGG.cc (95%) rename src/eckit/{geo/grid => grid/detail}/RegularGG.h (93%) rename src/eckit/{geo/grid => grid/detail}/RegularGrid.cc (98%) rename src/eckit/{geo/grid => grid/detail}/RegularGrid.h (92%) rename src/eckit/{geo/grid => grid/detail}/RegularLL.cc (97%) rename src/eckit/{geo/grid => grid/detail}/RegularLL.h (93%) rename src/eckit/{geo/grid => grid/detail}/UnstructuredGrid.cc (95%) rename src/eckit/{geo/grid => grid/detail}/UnstructuredGrid.h (95%) rename src/eckit/{geo => grid}/grib/GribConfiguration.cc (98%) rename src/eckit/{geo => grid}/grib/GribConfiguration.h (98%) rename src/eckit/{geo => grid}/projection/LonLatToXYZ.cc (94%) rename src/eckit/{geo => grid}/projection/LonLatToXYZ.h (94%) rename src/eckit/{geo => grid}/projection/None.cc (82%) rename src/eckit/{geo => grid}/projection/None.h (91%) rename src/eckit/{geo => grid}/projection/PROJ.cc (97%) rename src/eckit/{geo => grid}/projection/PROJ.h (95%) rename src/eckit/{geo => grid}/projection/Rotation.cc (96%) rename src/eckit/{geo => grid}/projection/Rotation.h (94%) rename src/eckit/{geo => grid}/scanner/Reduced.cc (95%) rename src/eckit/{geo => grid}/scanner/Reduced.h (89%) rename src/eckit/{geo => grid}/scanner/Regular.cc (94%) rename src/eckit/{geo => grid}/scanner/Regular.h (91%) rename src/eckit/{geo => grid}/scanner/Unstructured.cc (83%) rename src/eckit/{geo => grid}/scanner/Unstructured.h (91%) rename src/eckit/{geo => grid}/util.cc (83%) rename src/eckit/{geo => grid}/util.h (96%) rename src/eckit/{geo => grid}/util/arange.cc (93%) rename src/eckit/{geo => grid}/util/gaussian_latitudes.cc (97%) rename src/eckit/{geo => grid}/util/linspace.cc (93%) rename src/eckit/{geo => grid}/util/monotonic_crop.cc (96%) rename src/eckit/{geo => grid}/util/reduced_classical_pl.cc (99%) rename src/eckit/{geo => grid}/util/reduced_octahedral_pl.cc (90%) rename src/eckit/{geo => grid}/util/regular_pl.cc (85%) rename tests/{geo => grid}/CMakeLists.txt (71%) rename tests/{geo => grid}/reduced_gg.grib2 (100%) rename tests/{geo => grid}/reduced_ll.grib1 (100%) rename tests/{geo => grid}/regular_gg.grib1 (100%) rename tests/{geo => grid}/regular_ll.grib1 (100%) rename tests/{geo => grid}/test_grib.cc (88%) rename tests/{geo => grid}/test_iterator.cc (66%) rename tests/{geo => grid}/test_param.cc (100%) rename tests/{geo => grid}/test_projection.cc (88%) rename tests/{geo => grid}/test_projection_ll_to_xyz.cc (84%) rename tests/{geo => grid}/test_projection_proj.cc (59%) rename tests/{geo => grid}/test_projection_rotation.cc (96%) rename tests/{geo => grid}/test_search.cc (85%) rename tests/{geo => grid}/test_types.cc (96%) rename tests/{geo => grid}/test_util.cc (97%) diff --git a/src/eckit/CMakeLists.txt b/src/eckit/CMakeLists.txt index b98df5115..ecf9fae38 100644 --- a/src/eckit/CMakeLists.txt +++ b/src/eckit/CMakeLists.txt @@ -970,8 +970,8 @@ if( HAVE_ECKIT_SQL ) endif() add_subdirectory( distributed ) -add_subdirectory( geo ) add_subdirectory( geometry ) +add_subdirectory( grid ) add_subdirectory( linalg ) add_subdirectory( maths ) add_subdirectory( mpi ) diff --git a/src/eckit/geo/BoundingBox.cc b/src/eckit/grid/BoundingBox.cc similarity index 96% rename from src/eckit/geo/BoundingBox.cc rename to src/eckit/grid/BoundingBox.cc index 187c47a23..868c8946c 100644 --- a/src/eckit/geo/BoundingBox.cc +++ b/src/eckit/grid/BoundingBox.cc @@ -10,20 +10,20 @@ */ -#include "eckit/geo/BoundingBox.h" +#include "eckit/grid/BoundingBox.h" #include #include #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Point.h" -#include "eckit/geo/util.h" #include "eckit/geometry/Sphere.h" +#include "eckit/grid/Point.h" +#include "eckit/grid/util.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geo { +namespace eckit::grid { BoundingBox::BoundingBox(const Configuration& config) : @@ -151,4 +151,4 @@ BoundingBox BoundingBox::make(const BoundingBox&, const Projection&) { } -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/BoundingBox.h b/src/eckit/grid/BoundingBox.h similarity index 97% rename from src/eckit/geo/BoundingBox.h rename to src/eckit/grid/BoundingBox.h index 9596b0208..cc4014f4b 100644 --- a/src/eckit/geo/BoundingBox.h +++ b/src/eckit/grid/BoundingBox.h @@ -18,13 +18,13 @@ namespace eckit { class Configuration; -namespace geo { +namespace grid { class Projection; } } // namespace eckit -namespace eckit::geo { +namespace eckit::grid { class BoundingBox { @@ -132,4 +132,4 @@ class BoundingBox { }; -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/grid/CMakeLists.txt similarity index 51% rename from src/eckit/geo/CMakeLists.txt rename to src/eckit/grid/CMakeLists.txt index 61c43afc0..0fa92d764 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/grid/CMakeLists.txt @@ -1,4 +1,4 @@ -list(APPEND eckit_geo_srcs +list(APPEND eckit_grid_srcs BoundingBox.cc BoundingBox.h Domain.cc @@ -22,24 +22,24 @@ list(APPEND eckit_geo_srcs Scanner.cc Scanner.h Search.h - grid/Gaussian.cc - grid/Gaussian.h - grid/GaussianIterator.cc - grid/GaussianIterator.h - grid/IrregularLatlon.cc - grid/IrregularLatlon.h - grid/ReducedGG.cc - grid/ReducedGG.h - grid/ReducedLL.cc - grid/ReducedLL.h - grid/RegularGG.cc - grid/RegularGG.h - grid/RegularGrid.cc - grid/RegularGrid.h - grid/RegularLL.cc - grid/RegularLL.h - grid/UnstructuredGrid.cc - grid/UnstructuredGrid.h + detail/Gaussian.cc + detail/Gaussian.h + detail/GaussianIterator.cc + detail/GaussianIterator.h + detail/IrregularLatlon.cc + detail/IrregularLatlon.h + detail/ReducedGG.cc + detail/ReducedGG.h + detail/ReducedLL.cc + detail/ReducedLL.h + detail/RegularGG.cc + detail/RegularGG.h + detail/RegularGrid.cc + detail/RegularGrid.h + detail/RegularLL.cc + detail/RegularLL.h + detail/UnstructuredGrid.cc + detail/UnstructuredGrid.h projection/LonLatToXYZ.cc projection/LonLatToXYZ.h projection/None.cc @@ -63,30 +63,30 @@ list(APPEND eckit_geo_srcs util/regular_pl.cc ) -set(eckit_geo_include_dirs ) -set(eckit_geo_libs eckit_geometry eckit_maths) +set(eckit_grid_include_dirs ) +set(eckit_grid_libs eckit_geometry eckit_maths) if(HAVE_PROJ) - list(APPEND eckit_geo_srcs projection/PROJ.cc projection/PROJ.h) - list(APPEND eckit_geo_libs PROJ::proj) - list(APPEND eckit_geo_include_dirs ${PROJ_INCLUDE_DIRS}) + list(APPEND eckit_grid_srcs projection/PROJ.cc projection/PROJ.h) + list(APPEND eckit_grid_libs PROJ::proj) + list(APPEND eckit_grid_include_dirs ${PROJ_INCLUDE_DIRS}) endif() ecbuild_add_library( - TARGET eckit_geo + TARGET eckit_grid TYPE SHARED INSTALL_HEADERS ALL - HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geo - SOURCES ${eckit_geo_srcs} - PUBLIC_LIBS ${eckit_geo_libs} - PUBLIC_INCLUDES ${eckit_geo_include_dirs} + HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/grid + SOURCES ${eckit_grid_srcs} + PUBLIC_LIBS ${eckit_grid_libs} + PUBLIC_INCLUDES ${eckit_grid_include_dirs} ) ecbuild_add_library( - TARGET eckit_geo_grib + TARGET eckit_grid_grib TYPE SHARED CONDITION HAVE_ECCODES SOURCES grib/GribConfiguration.cc grib/GribConfiguration.h - PUBLIC_LIBS eckit_geo eccodes + PUBLIC_LIBS eckit_grid eccodes ) diff --git a/src/eckit/geo/Domain.cc b/src/eckit/grid/Domain.cc similarity index 95% rename from src/eckit/geo/Domain.cc rename to src/eckit/grid/Domain.cc index 814283ec0..dc950fe6f 100644 --- a/src/eckit/geo/Domain.cc +++ b/src/eckit/grid/Domain.cc @@ -10,19 +10,19 @@ */ -#include "eckit/geo/Domain.h" +#include "eckit/grid/Domain.h" #include #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Point.h" -#include "eckit/geo/util.h" #include "eckit/geometry/Sphere.h" +#include "eckit/grid/Point.h" +#include "eckit/grid/util.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geo { +namespace eckit::grid { Domain::Domain(double north, double west, double south, double east) : @@ -99,4 +99,4 @@ double Domain::area(double radius) const { } -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Domain.h b/src/eckit/grid/Domain.h similarity index 97% rename from src/eckit/geo/Domain.h rename to src/eckit/grid/Domain.h index fd91cc6f0..ee5c82187 100644 --- a/src/eckit/geo/Domain.h +++ b/src/eckit/grid/Domain.h @@ -15,7 +15,7 @@ #include -namespace eckit::geo { +namespace eckit::grid { class Domain { @@ -116,4 +116,4 @@ class Domain { }; -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Earth.h b/src/eckit/grid/Earth.h similarity index 93% rename from src/eckit/geo/Earth.h rename to src/eckit/grid/Earth.h index 1999eea6c..bb51f21b2 100644 --- a/src/eckit/geo/Earth.h +++ b/src/eckit/grid/Earth.h @@ -15,7 +15,7 @@ #include "eckit/geometry/SphereT.h" -namespace eckit::geo { +namespace eckit::grid { struct DatumIFS { @@ -36,4 +36,4 @@ struct DatumWGS84SemiMajorAxis { using Earth = eckit::geometry::SphereT; -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Figure.cc b/src/eckit/grid/Figure.cc similarity index 86% rename from src/eckit/geo/Figure.cc rename to src/eckit/grid/Figure.cc index 67b3685a9..6eafe5abb 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/grid/Figure.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geo/Figure.h" +#include "eckit/grid/Figure.h" #include "eckit/config/Configuration.h" -namespace eckit::geo { +namespace eckit::grid { Figure::Figure(const Configuration& config) /*: @@ -24,4 +24,4 @@ Figure::Figure(const Configuration& config) /*: } -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Figure.h b/src/eckit/grid/Figure.h similarity index 96% rename from src/eckit/geo/Figure.h rename to src/eckit/grid/Figure.h index bafe5ac26..f733f26cf 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/grid/Figure.h @@ -20,7 +20,7 @@ class Configuration; } -namespace eckit::geo { +namespace eckit::grid { class Figure { @@ -94,4 +94,4 @@ class Figure { }; -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Grid.cc b/src/eckit/grid/Grid.cc similarity index 92% rename from src/eckit/geo/Grid.cc rename to src/eckit/grid/Grid.cc index 1113dc77d..252702fda 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/grid/Grid.cc @@ -10,22 +10,22 @@ */ -#include "eckit/geo/Grid.h" +#include "eckit/grid/Grid.h" #include #include #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Domain.h" -#include "eckit/geo/Iterator.h" -#include "eckit/geo/grid/UnstructuredGrid.h" +#include "eckit/grid/Domain.h" +#include "eckit/grid/Iterator.h" +#include "eckit/grid/detail/UnstructuredGrid.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" -namespace eckit::geo { +namespace eckit::grid { Grid::Grid(const Configuration& config) : @@ -111,4 +111,4 @@ void GridFactory::list(std::ostream& out) { } -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Grid.h b/src/eckit/grid/Grid.h similarity index 93% rename from src/eckit/geo/Grid.h rename to src/eckit/grid/Grid.h index 4159c7015..0cd7b83be 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/grid/Grid.h @@ -18,18 +18,18 @@ #include #include "eckit/config/Configuration.h" -#include "eckit/geo/BoundingBox.h" -#include "eckit/geo/Point.h" -#include "eckit/geo/Renumber.h" +#include "eckit/grid/BoundingBox.h" +#include "eckit/grid/Point.h" +#include "eckit/grid/Renumber.h" -namespace eckit::geo { +namespace eckit::grid { class Domain; class Iterator; -} // namespace eckit::geo +} // namespace eckit::grid -namespace eckit::geo { +namespace eckit::grid { class Grid { @@ -149,4 +149,4 @@ class GridBuilder : public GridFactory { }; -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Increments.cc b/src/eckit/grid/Increments.cc similarity index 87% rename from src/eckit/geo/Increments.cc rename to src/eckit/grid/Increments.cc index 8730f9bd7..fe7b66d89 100644 --- a/src/eckit/geo/Increments.cc +++ b/src/eckit/grid/Increments.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geo/Increments.h" +#include "eckit/grid/Increments.h" #include "eckit/config/Configuration.h" -namespace eckit::geo { +namespace eckit::grid { Increments::Increments(const Configuration& config) : @@ -23,4 +23,4 @@ Increments::Increments(const Configuration& config) : } -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Increments.h b/src/eckit/grid/Increments.h similarity index 95% rename from src/eckit/geo/Increments.h rename to src/eckit/grid/Increments.h index 7bae5b12c..7cd0cc293 100644 --- a/src/eckit/geo/Increments.h +++ b/src/eckit/grid/Increments.h @@ -21,7 +21,7 @@ class Configuration; } -namespace eckit::geo { +namespace eckit::grid { class Increments : protected std::array { @@ -51,4 +51,4 @@ class Increments : protected std::array { }; -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Iterator.cc b/src/eckit/grid/Iterator.cc similarity index 95% rename from src/eckit/geo/Iterator.cc rename to src/eckit/grid/Iterator.cc index c94c3ac72..2f5458618 100644 --- a/src/eckit/geo/Iterator.cc +++ b/src/eckit/grid/Iterator.cc @@ -10,19 +10,19 @@ */ -#include "eckit/geo/Iterator.h" +#include "eckit/grid/Iterator.h" #include #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Projection.h" +#include "eckit/grid/Projection.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" -namespace eckit::geo { +namespace eckit::grid { static pthread_once_t __once = PTHREAD_ONCE_INIT; @@ -96,4 +96,4 @@ IteratorFactory::~IteratorFactory() { } -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Iterator.h b/src/eckit/grid/Iterator.h similarity index 97% rename from src/eckit/geo/Iterator.h rename to src/eckit/grid/Iterator.h index 4ad8e7091..738ca6073 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/grid/Iterator.h @@ -16,18 +16,18 @@ #include #include -#include "eckit/geo/Point.h" +#include "eckit/grid/Point.h" namespace eckit { class Configuration; -namespace geo { +namespace grid { class Projection; } } // namespace eckit -namespace eckit::geo { +namespace eckit::grid { class Iterator { @@ -187,4 +187,4 @@ class IteratorBuilder final : public IteratorFactory { }; -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Point.cc b/src/eckit/grid/Point.cc similarity index 82% rename from src/eckit/geo/Point.cc rename to src/eckit/grid/Point.cc index 0f8ddd107..19e033001 100644 --- a/src/eckit/geo/Point.cc +++ b/src/eckit/grid/Point.cc @@ -10,14 +10,14 @@ */ -#include "eckit/geo/Point.h" +#include "eckit/grid/Point.h" #include #include "eckit/exception/Exceptions.h" -namespace eckit::geo { +namespace eckit::grid { bool points_equal(const Point& p, const Point& q) { @@ -26,10 +26,10 @@ bool points_equal(const Point& p, const Point& q) { } -} // namespace eckit::geo +} // namespace eckit::grid -std::ostream& operator<<(std::ostream& out, const eckit::geo::Point& p) { +std::ostream& operator<<(std::ostream& out, const eckit::grid::Point& p) { std::visit([&](const auto& p) { out << p; }, p); return out; } diff --git a/src/eckit/geo/Point.h b/src/eckit/grid/Point.h similarity index 89% rename from src/eckit/geo/Point.h rename to src/eckit/grid/Point.h index 3390c15dc..64b85f1ec 100644 --- a/src/eckit/geo/Point.h +++ b/src/eckit/grid/Point.h @@ -20,7 +20,7 @@ #include "eckit/geometry/PointLonLat.h" -namespace eckit::geo { +namespace eckit::grid { using geometry::Point2; @@ -43,7 +43,7 @@ using Longitude = double; using Latitude = double; -} // namespace eckit::geo +} // namespace eckit::grid -std::ostream& operator<<(std::ostream&, const eckit::geo::Point&); +std::ostream& operator<<(std::ostream&, const eckit::grid::Point&); diff --git a/src/eckit/geo/Projection.cc b/src/eckit/grid/Projection.cc similarity index 98% rename from src/eckit/geo/Projection.cc rename to src/eckit/grid/Projection.cc index 366e96376..0d70db3f3 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/grid/Projection.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/Projection.h" +#include "eckit/grid/Projection.h" #include #include @@ -21,7 +21,7 @@ #include "eckit/thread/Mutex.h" -namespace eckit::geo { +namespace eckit::grid { #if 0 @@ -280,4 +280,4 @@ ProjectionFactory::~ProjectionFactory() { } -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Projection.h b/src/eckit/grid/Projection.h similarity index 96% rename from src/eckit/geo/Projection.h rename to src/eckit/grid/Projection.h index e73dbb5f2..b4b97e217 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/grid/Projection.h @@ -15,7 +15,7 @@ #include #include -#include "eckit/geo/Point.h" +#include "eckit/grid/Point.h" namespace eckit { @@ -23,7 +23,7 @@ class Configuration; } -namespace eckit::geo { +namespace eckit::grid { class Projection { @@ -136,4 +136,4 @@ class ProjectionBuilder final : public ProjectionFactory { }; -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Range.cc b/src/eckit/grid/Range.cc similarity index 95% rename from src/eckit/geo/Range.cc rename to src/eckit/grid/Range.cc index f8b60c8b4..1897e3944 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/grid/Range.cc @@ -10,18 +10,18 @@ */ -#include "eckit/geo/Range.h" +#include "eckit/grid/Range.h" #include "eckit/exception/Exceptions.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geo::util { +namespace eckit::grid::util { std::vector arange(double start, double stop, double step); } -namespace eckit::geo { +namespace eckit::grid { static Fraction adjust(const Fraction& target, const Fraction& inc, bool up) { @@ -104,4 +104,4 @@ std::vector Range::to_vector() const { } -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Range.h b/src/eckit/grid/Range.h similarity index 97% rename from src/eckit/geo/Range.h rename to src/eckit/grid/Range.h index ffcc953d1..5be793add 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/grid/Range.h @@ -17,7 +17,7 @@ #include "eckit/types/Fraction.h" -namespace eckit::geo { +namespace eckit::grid { class Range { @@ -106,4 +106,4 @@ class Range { }; -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Renumber.h b/src/eckit/grid/Renumber.h similarity index 90% rename from src/eckit/geo/Renumber.h rename to src/eckit/grid/Renumber.h index e0c7c92c0..cd60ec7c7 100644 --- a/src/eckit/geo/Renumber.h +++ b/src/eckit/grid/Renumber.h @@ -15,10 +15,10 @@ #include -namespace eckit::geo { +namespace eckit::grid { using Renumber = std::vector; -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Scanner.cc b/src/eckit/grid/Scanner.cc similarity index 95% rename from src/eckit/geo/Scanner.cc rename to src/eckit/grid/Scanner.cc index 4a676c5b9..066248009 100644 --- a/src/eckit/geo/Scanner.cc +++ b/src/eckit/grid/Scanner.cc @@ -10,10 +10,10 @@ */ -#include "eckit/geo/Scanner.h" +#include "eckit/grid/Scanner.h" -namespace eckit::geo { +namespace eckit::grid { #if 0 @@ -51,4 +51,4 @@ Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) #endif -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Scanner.h b/src/eckit/grid/Scanner.h similarity index 96% rename from src/eckit/geo/Scanner.h rename to src/eckit/grid/Scanner.h index 5bda3cfd5..60dd483a8 100644 --- a/src/eckit/geo/Scanner.h +++ b/src/eckit/grid/Scanner.h @@ -15,7 +15,7 @@ #include -namespace eckit::geo { +namespace eckit::grid { class Scanner { @@ -99,4 +99,4 @@ class Scanner { }; -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/Search.h b/src/eckit/grid/Search.h similarity index 97% rename from src/eckit/geo/Search.h rename to src/eckit/grid/Search.h index 5a0701b21..7bf8f1cab 100644 --- a/src/eckit/geo/Search.h +++ b/src/eckit/grid/Search.h @@ -20,7 +20,7 @@ #include "eckit/geometry/UnitSphere.h" -namespace eckit::geo { +namespace eckit::grid { namespace search { @@ -77,4 +77,4 @@ struct SearchLonLat : Search3 { }; -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/grid/Gaussian.cc b/src/eckit/grid/detail/Gaussian.cc similarity index 94% rename from src/eckit/geo/grid/Gaussian.cc rename to src/eckit/grid/detail/Gaussian.cc index ca36e6263..24c74df22 100644 --- a/src/eckit/geo/grid/Gaussian.cc +++ b/src/eckit/grid/detail/Gaussian.cc @@ -10,18 +10,18 @@ */ -#include "eckit/geo/grid/Gaussian.h" +#include "eckit/grid/detail/Gaussian.h" #include #include #include -#include "eckit/geo/Domain.h" -#include "eckit/geo/util.h" +#include "eckit/grid/Domain.h" +#include "eckit/grid/util.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { Gaussian::Gaussian(size_t N, const BoundingBox& bbox) : @@ -117,4 +117,4 @@ void Gaussian::correctSouthNorth(double& s, double& n, bool in) const { } -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/Gaussian.h b/src/eckit/grid/detail/Gaussian.h similarity index 94% rename from src/eckit/geo/grid/Gaussian.h rename to src/eckit/grid/detail/Gaussian.h index 57f1b39e2..bb27add5d 100644 --- a/src/eckit/geo/grid/Gaussian.h +++ b/src/eckit/grid/detail/Gaussian.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geo/Grid.h" +#include "eckit/grid/Grid.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { class Gaussian : public Grid { @@ -98,4 +98,4 @@ class Gaussian : public Grid { }; -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/GaussianIterator.cc b/src/eckit/grid/detail/GaussianIterator.cc similarity index 95% rename from src/eckit/geo/grid/GaussianIterator.cc rename to src/eckit/grid/detail/GaussianIterator.cc index dceae15bb..59a34915b 100644 --- a/src/eckit/geo/grid/GaussianIterator.cc +++ b/src/eckit/grid/detail/GaussianIterator.cc @@ -10,14 +10,14 @@ */ -#include "eckit/geo/grid/GaussianIterator.h" +#include "eckit/grid/detail/GaussianIterator.h" #include #include "eckit/exception/Exceptions.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { GaussianIterator::GaussianIterator(const std::vector& latitudes, std::vector&& pl, @@ -115,4 +115,4 @@ size_t GaussianIterator::size() const { } -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/GaussianIterator.h b/src/eckit/grid/detail/GaussianIterator.h similarity index 87% rename from src/eckit/geo/grid/GaussianIterator.h rename to src/eckit/grid/detail/GaussianIterator.h index 11286a0d3..dc05d0a12 100644 --- a/src/eckit/geo/grid/GaussianIterator.h +++ b/src/eckit/grid/detail/GaussianIterator.h @@ -16,12 +16,12 @@ #include "eckit/types/Fraction.h" -#include "eckit/geo/BoundingBox.h" -#include "eckit/geo/Iterator.h" -#include "eckit/geo/Projection.h" +#include "eckit/grid/BoundingBox.h" +#include "eckit/grid/Iterator.h" +#include "eckit/grid/Projection.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { class GaussianIterator : public Iterator { @@ -55,4 +55,4 @@ class GaussianIterator : public Iterator { }; -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/IrregularLatlon.cc b/src/eckit/grid/detail/IrregularLatlon.cc similarity index 95% rename from src/eckit/geo/grid/IrregularLatlon.cc rename to src/eckit/grid/detail/IrregularLatlon.cc index 14786472f..9ac450d58 100644 --- a/src/eckit/geo/grid/IrregularLatlon.cc +++ b/src/eckit/grid/detail/IrregularLatlon.cc @@ -10,18 +10,18 @@ */ -#include "eckit/geo/grid/IrregularLatlon.h" +#include "eckit/grid/detail/IrregularLatlon.h" #include #include #include "eckit/utils/MD5.h" -#include "eckit/geo/Iterator.h" -#include "eckit/geo/Projection.h" +#include "eckit/grid/Iterator.h" +#include "eckit/grid/Projection.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { static void range(const std::vector& v, double& mn, double& mx, double& dmax) { @@ -163,4 +163,4 @@ Renumber IrregularLatlon::reorder(long scanningMode) const { static const GridBuilder irregularLatlon("irregular_latlon"); -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/IrregularLatlon.h b/src/eckit/grid/detail/IrregularLatlon.h similarity index 94% rename from src/eckit/geo/grid/IrregularLatlon.h rename to src/eckit/grid/detail/IrregularLatlon.h index 36b47c7fa..980845a81 100644 --- a/src/eckit/geo/grid/IrregularLatlon.h +++ b/src/eckit/grid/detail/IrregularLatlon.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geo/Grid.h" +#include "eckit/grid/Grid.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { class IrregularLatlon final : public Grid { @@ -87,4 +87,4 @@ class IrregularLatlon final : public Grid { }; -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/ReducedGG.cc b/src/eckit/grid/detail/ReducedGG.cc similarity index 96% rename from src/eckit/geo/grid/ReducedGG.cc rename to src/eckit/grid/detail/ReducedGG.cc index 206710d3c..8d248f4f3 100644 --- a/src/eckit/geo/grid/ReducedGG.cc +++ b/src/eckit/grid/detail/ReducedGG.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/ReducedGG.h" +#include "eckit/grid/detail/ReducedGG.h" #include #include @@ -21,13 +21,13 @@ #include #include -#include "eckit/geo/Iterator.h" -#include "eckit/geo/Projection.h" -#include "eckit/geo/grid/GaussianIterator.h" +#include "eckit/grid/Iterator.h" +#include "eckit/grid/Projection.h" +#include "eckit/grid/detail/GaussianIterator.h" #include "eckit/types/Fraction.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { ReducedGG::ReducedGG(const Configuration& config) : @@ -276,4 +276,4 @@ struct ReducedGGOctahedral : ReducedGG { static const GridBuilder reducedFromPL("reduced_gg"); -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/ReducedGG.h b/src/eckit/grid/detail/ReducedGG.h similarity index 94% rename from src/eckit/geo/grid/ReducedGG.h rename to src/eckit/grid/detail/ReducedGG.h index 6ade62448..b5e25dc6c 100644 --- a/src/eckit/geo/grid/ReducedGG.h +++ b/src/eckit/grid/detail/ReducedGG.h @@ -12,8 +12,8 @@ #pragma once -#include "eckit/geo/grid/Gaussian.h" -#include "eckit/geo/util.h" +#include "eckit/grid/detail/Gaussian.h" +#include "eckit/grid/util.h" namespace eckit { @@ -21,7 +21,7 @@ class Fraction; } -namespace eckit::geo::grid { +namespace eckit::grid::grid { class ReducedGG : public Gaussian { @@ -118,4 +118,4 @@ class ReducedGG : public Gaussian { }; -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/ReducedLL.cc b/src/eckit/grid/detail/ReducedLL.cc similarity index 95% rename from src/eckit/geo/grid/ReducedLL.cc rename to src/eckit/grid/detail/ReducedLL.cc index 1de4e078d..314004649 100644 --- a/src/eckit/geo/grid/ReducedLL.cc +++ b/src/eckit/grid/detail/ReducedLL.cc @@ -10,21 +10,21 @@ */ -#include "eckit/geo/grid/ReducedLL.h" +#include "eckit/grid/detail/ReducedLL.h" #include #include #include #include -#include "eckit/geo/Domain.h" -#include "eckit/geo/Iterator.h" -#include "eckit/geo/Projection.h" +#include "eckit/grid/Domain.h" +#include "eckit/grid/Iterator.h" +#include "eckit/grid/Projection.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { static bool checkPl(const std::vector& pl) { ASSERT(!pl.empty()); @@ -185,4 +185,4 @@ Renumber ReducedLL::reorder(long scanningMode) const { static const GridBuilder reducedLL("reduced_ll"); -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/ReducedLL.h b/src/eckit/grid/detail/ReducedLL.h similarity index 93% rename from src/eckit/geo/grid/ReducedLL.h rename to src/eckit/grid/detail/ReducedLL.h index bd10724ed..fe16a13f0 100644 --- a/src/eckit/geo/grid/ReducedLL.h +++ b/src/eckit/grid/detail/ReducedLL.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geo/Grid.h" +#include "eckit/grid/Grid.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { class ReducedLL : public Grid { @@ -83,4 +83,4 @@ class ReducedLL : public Grid { }; -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/RegularGG.cc b/src/eckit/grid/detail/RegularGG.cc similarity index 95% rename from src/eckit/geo/grid/RegularGG.cc rename to src/eckit/grid/detail/RegularGG.cc index c427c113c..5b72b61cb 100644 --- a/src/eckit/geo/grid/RegularGG.cc +++ b/src/eckit/grid/detail/RegularGG.cc @@ -10,19 +10,19 @@ */ -#include "eckit/geo/grid/RegularGG.h" +#include "eckit/grid/detail/RegularGG.h" #include #include #include -#include "eckit/geo/grid/GaussianIterator.h" -#include "eckit/geo/grid/RegularGG.h" +#include "eckit/grid/detail/GaussianIterator.h" +#include "eckit/grid/detail/RegularGG.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { RegularGG::RegularGG(const Configuration& config) : @@ -188,4 +188,4 @@ Renumber RegularGG::reorder(long /*scanningMode*/) const { static const GridBuilder reducedGG("regular_gg"); -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/RegularGG.h b/src/eckit/grid/detail/RegularGG.h similarity index 93% rename from src/eckit/geo/grid/RegularGG.h rename to src/eckit/grid/detail/RegularGG.h index 7662ced16..e78a1cd89 100644 --- a/src/eckit/geo/grid/RegularGG.h +++ b/src/eckit/grid/detail/RegularGG.h @@ -12,7 +12,7 @@ #pragma once -#include "eckit/geo/grid/Gaussian.h" +#include "eckit/grid/detail/Gaussian.h" namespace eckit { @@ -20,7 +20,7 @@ class Fraction; } -namespace eckit::geo::grid { +namespace eckit::grid::grid { class RegularGG final : public Gaussian { @@ -88,4 +88,4 @@ class RegularGG final : public Gaussian { }; -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/RegularGrid.cc b/src/eckit/grid/detail/RegularGrid.cc similarity index 98% rename from src/eckit/geo/grid/RegularGrid.cc rename to src/eckit/grid/detail/RegularGrid.cc index c1678e0a2..c8322d83f 100644 --- a/src/eckit/geo/grid/RegularGrid.cc +++ b/src/eckit/grid/detail/RegularGrid.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/RegularGrid.h" +#include "eckit/grid/detail/RegularGrid.h" #include #include @@ -20,12 +20,12 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/config/Resource.h" -#include "eckit/geo/Earth.h" -#include "eckit/geo/Iterator.h" +#include "eckit/grid/Earth.h" +#include "eckit/grid/Iterator.h" #include "eckit/utils/StringTools.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { RegularGrid::RegularGrid(Projection* projection, const Configuration& config) : @@ -268,4 +268,4 @@ static const GridBuilder __builder3("mercator"); static const GridBuilder __builder4("polar_stereographic"); -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/RegularGrid.h b/src/eckit/grid/detail/RegularGrid.h similarity index 92% rename from src/eckit/geo/grid/RegularGrid.h rename to src/eckit/grid/detail/RegularGrid.h index faf0b8973..51725e5d8 100644 --- a/src/eckit/geo/grid/RegularGrid.h +++ b/src/eckit/grid/detail/RegularGrid.h @@ -15,12 +15,12 @@ #include #include -#include "eckit/geo/Figure.h" -#include "eckit/geo/Grid.h" -#include "eckit/geo/Projection.h" +#include "eckit/grid/Figure.h" +#include "eckit/grid/Grid.h" +#include "eckit/grid/Projection.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { class RegularGrid : public Grid { @@ -105,4 +105,4 @@ class RegularGrid : public Grid { }; -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/RegularLL.cc b/src/eckit/grid/detail/RegularLL.cc similarity index 97% rename from src/eckit/geo/grid/RegularLL.cc rename to src/eckit/grid/detail/RegularLL.cc index a67471fb6..64f804990 100644 --- a/src/eckit/geo/grid/RegularLL.cc +++ b/src/eckit/grid/detail/RegularLL.cc @@ -10,22 +10,22 @@ */ -#include "eckit/geo/grid/RegularLL.h" +#include "eckit/grid/detail/RegularLL.h" #include #include #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Iterator.h" -#include "eckit/geo/Point.h" -#include "eckit/geo/Projection.h" -#include "eckit/geo/grid/RegularLL.h" +#include "eckit/grid/Iterator.h" +#include "eckit/grid/Point.h" +#include "eckit/grid/Projection.h" +#include "eckit/grid/detail/RegularLL.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { namespace detail { @@ -303,4 +303,4 @@ Iterator* RegularLL::iterator() const { static const GridBuilder regularLL("regular_ll"); -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/RegularLL.h b/src/eckit/grid/detail/RegularLL.h similarity index 93% rename from src/eckit/geo/grid/RegularLL.h rename to src/eckit/grid/detail/RegularLL.h index 8dbf5fa2d..99c7088df 100644 --- a/src/eckit/geo/grid/RegularLL.h +++ b/src/eckit/grid/detail/RegularLL.h @@ -12,12 +12,12 @@ #pragma once -#include "eckit/geo/Grid.h" -#include "eckit/geo/Increments.h" +#include "eckit/grid/Grid.h" +#include "eckit/grid/Increments.h" #include "eckit/types/Fraction.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { class RegularLL : public Grid { @@ -87,4 +87,4 @@ class RegularLL : public Grid { }; -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/UnstructuredGrid.cc b/src/eckit/grid/detail/UnstructuredGrid.cc similarity index 95% rename from src/eckit/geo/grid/UnstructuredGrid.cc rename to src/eckit/grid/detail/UnstructuredGrid.cc index 832292c72..572f14b59 100644 --- a/src/eckit/geo/grid/UnstructuredGrid.cc +++ b/src/eckit/grid/detail/UnstructuredGrid.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/UnstructuredGrid.h" +#include "eckit/grid/detail/UnstructuredGrid.h" #include #include @@ -22,14 +22,14 @@ #include "eckit/config/Resource.h" #include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" -#include "eckit/geo/Domain.h" -#include "eckit/geo/Iterator.h" -#include "eckit/geo/Projection.h" +#include "eckit/grid/Domain.h" +#include "eckit/grid/Iterator.h" +#include "eckit/grid/Projection.h" #include "eckit/serialisation/FileStream.h" #include "eckit/serialisation/IfstreamStream.h" -namespace eckit::geo::grid { +namespace eckit::grid::grid { namespace detail { @@ -230,4 +230,4 @@ static const GridBuilder triangular_grid("triangular_grid"); static const GridBuilder unstructured_grid("unstructured_grid"); -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grid/UnstructuredGrid.h b/src/eckit/grid/detail/UnstructuredGrid.h similarity index 95% rename from src/eckit/geo/grid/UnstructuredGrid.h rename to src/eckit/grid/detail/UnstructuredGrid.h index fc5463199..f8124ce81 100644 --- a/src/eckit/geo/grid/UnstructuredGrid.h +++ b/src/eckit/grid/detail/UnstructuredGrid.h @@ -14,7 +14,7 @@ #include -#include "eckit/geo/Grid.h" +#include "eckit/grid/Grid.h" namespace eckit { @@ -22,7 +22,7 @@ class PathName; } -namespace eckit::geo::grid { +namespace eckit::grid::grid { class UnstructuredGrid : public Grid { @@ -117,4 +117,4 @@ class UnstructuredGrid : public Grid { }; -} // namespace eckit::geo::grid +} // namespace eckit::grid::grid diff --git a/src/eckit/geo/grib/GribConfiguration.cc b/src/eckit/grid/grib/GribConfiguration.cc similarity index 98% rename from src/eckit/geo/grib/GribConfiguration.cc rename to src/eckit/grid/grib/GribConfiguration.cc index 5c89f951b..7b0645b89 100644 --- a/src/eckit/geo/grib/GribConfiguration.cc +++ b/src/eckit/grid/grib/GribConfiguration.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geo/grib/GribConfiguration.h" +#include "eckit/grid/grib/GribConfiguration.h" #include "eckit/value/Value.h" -namespace eckit::geo::grib { +namespace eckit::grid::grib { static Value __root_dummy; @@ -221,4 +221,4 @@ void GribConfiguration::print(std::ostream&) const { } -} // namespace eckit::geo::grib +} // namespace eckit::grid::grib diff --git a/src/eckit/geo/grib/GribConfiguration.h b/src/eckit/grid/grib/GribConfiguration.h similarity index 98% rename from src/eckit/geo/grib/GribConfiguration.h rename to src/eckit/grid/grib/GribConfiguration.h index 78575f5ce..7c538aa05 100644 --- a/src/eckit/geo/grib/GribConfiguration.h +++ b/src/eckit/grid/grib/GribConfiguration.h @@ -21,7 +21,7 @@ #include "eckit/exception/Exceptions.h" -namespace eckit::geo::grib { +namespace eckit::grid::grib { class GribConfiguration final : Configuration { @@ -140,4 +140,4 @@ class GribConfiguration final : Configuration { // None }; -} // namespace eckit::geo::grib +} // namespace eckit::grid::grib diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/grid/projection/LonLatToXYZ.cc similarity index 94% rename from src/eckit/geo/projection/LonLatToXYZ.cc rename to src/eckit/grid/projection/LonLatToXYZ.cc index eb109ff8a..24ca04747 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/grid/projection/LonLatToXYZ.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/projection/LonLatToXYZ.h" +#include "eckit/grid/projection/LonLatToXYZ.h" #include "eckit/config/Configuration.h" #include "eckit/geometry/EllipsoidOfRevolution.h" @@ -18,7 +18,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geo::projection { +namespace eckit::grid::projection { static ProjectionBuilder __projection("ll_to_xyz"); @@ -69,4 +69,4 @@ LonLatToXYZ::LonLatToXYZ(const Configuration& config) : config.getDouble("b", config.getDouble("R", 1.))) {} -} // namespace eckit::geo::projection +} // namespace eckit::grid::projection diff --git a/src/eckit/geo/projection/LonLatToXYZ.h b/src/eckit/grid/projection/LonLatToXYZ.h similarity index 94% rename from src/eckit/geo/projection/LonLatToXYZ.h rename to src/eckit/grid/projection/LonLatToXYZ.h index c47061fd0..fbe7c11d0 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.h +++ b/src/eckit/grid/projection/LonLatToXYZ.h @@ -14,10 +14,10 @@ #include -#include "eckit/geo/Projection.h" +#include "eckit/grid/Projection.h" -namespace eckit::geo::projection { +namespace eckit::grid::projection { /// Calculate coordinates of a point on a sphere or spheroid, in [x, y, z] @@ -94,4 +94,4 @@ class LonLatToXYZ final : public Projection { }; -} // namespace eckit::geo::projection +} // namespace eckit::grid::projection diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/grid/projection/None.cc similarity index 82% rename from src/eckit/geo/projection/None.cc rename to src/eckit/grid/projection/None.cc index e7847db5f..b907d5542 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/grid/projection/None.cc @@ -10,10 +10,10 @@ */ -#include "eckit/geo/projection/None.h" +#include "eckit/grid/projection/None.h" -namespace eckit::geo::projection { +namespace eckit::grid::projection { static ProjectionBuilder __projection1(""); @@ -23,4 +23,4 @@ static ProjectionBuilder __projection2("none"); None::None(const Configuration&) {} -} // namespace eckit::geo::projection +} // namespace eckit::grid::projection diff --git a/src/eckit/geo/projection/None.h b/src/eckit/grid/projection/None.h similarity index 91% rename from src/eckit/geo/projection/None.h rename to src/eckit/grid/projection/None.h index 1a9fc3ff5..1b1433e3a 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/grid/projection/None.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geo/Projection.h" +#include "eckit/grid/Projection.h" -namespace eckit::geo::projection { +namespace eckit::grid::projection { class None final : public Projection { @@ -75,4 +75,4 @@ class None final : public Projection { }; -} // namespace eckit::geo::projection +} // namespace eckit::grid::projection diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/grid/projection/PROJ.cc similarity index 97% rename from src/eckit/geo/projection/PROJ.cc rename to src/eckit/grid/projection/PROJ.cc index f84130307..6e95ed434 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/grid/projection/PROJ.cc @@ -10,13 +10,13 @@ */ -#include "eckit/geo/projection/PROJ.h" +#include "eckit/grid/projection/PROJ.h" #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" -namespace eckit::geo::projection { +namespace eckit::grid::projection { static ProjectionBuilder __projection("proj"); @@ -123,4 +123,4 @@ Point PROJ::inv(const Point& q) const { } -} // namespace eckit::geo::projection +} // namespace eckit::grid::projection diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/grid/projection/PROJ.h similarity index 95% rename from src/eckit/geo/projection/PROJ.h rename to src/eckit/grid/projection/PROJ.h index fe87a74c2..399f6b0a6 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/grid/projection/PROJ.h @@ -16,10 +16,10 @@ #include -#include "eckit/geo/Projection.h" +#include "eckit/grid/Projection.h" -namespace eckit::geo::projection { +namespace eckit::grid::projection { /// Calculate coordinates using PROJ @@ -118,4 +118,4 @@ class PROJ final : public Projection { }; -} // namespace eckit::geo::projection +} // namespace eckit::grid::projection diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/grid/projection/Rotation.cc similarity index 96% rename from src/eckit/geo/projection/Rotation.cc rename to src/eckit/grid/projection/Rotation.cc index dcad90c4c..c5f572df0 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/grid/projection/Rotation.cc @@ -10,19 +10,19 @@ */ -#include "eckit/geo/projection/Rotation.h" +#include "eckit/grid/projection/Rotation.h" #include #include #include "eckit/config/Configuration.h" -#include "eckit/geo/util.h" #include "eckit/geometry/UnitSphere.h" +#include "eckit/grid/util.h" #include "eckit/maths/Matrix3.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geo::projection { +namespace eckit::grid::projection { static ProjectionBuilder __projection("rotation"); @@ -102,4 +102,4 @@ Rotation::Rotation(const Configuration& config) : config.getDouble("angle", 0)) {} -} // namespace eckit::geo::projection +} // namespace eckit::grid::projection diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/grid/projection/Rotation.h similarity index 94% rename from src/eckit/geo/projection/Rotation.h rename to src/eckit/grid/projection/Rotation.h index 1e016448c..56e2c62c4 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/grid/projection/Rotation.h @@ -14,10 +14,10 @@ #include -#include "eckit/geo/Projection.h" +#include "eckit/grid/Projection.h" -namespace eckit::geo::projection { +namespace eckit::grid::projection { /// Calculate coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle @@ -95,4 +95,4 @@ class Rotation final : public Projection { }; -} // namespace eckit::geo::projection +} // namespace eckit::grid::projection diff --git a/src/eckit/geo/scanner/Reduced.cc b/src/eckit/grid/scanner/Reduced.cc similarity index 95% rename from src/eckit/geo/scanner/Reduced.cc rename to src/eckit/grid/scanner/Reduced.cc index 9c35f55a3..a39e0ab42 100644 --- a/src/eckit/geo/scanner/Reduced.cc +++ b/src/eckit/grid/scanner/Reduced.cc @@ -10,14 +10,14 @@ */ -#include "eckit/geo/scanner/Reduced.h" +#include "eckit/grid/scanner/Reduced.h" #include #include "eckit/exception/Exceptions.h" -namespace eckit::geo::scanner { +namespace eckit::grid::scanner { Reduced::Reduced(const std::vector& latitudes, @@ -104,4 +104,4 @@ size_t Reduced::size() const { } -} // namespace eckit::geo::scanner +} // namespace eckit::grid::scanner diff --git a/src/eckit/geo/scanner/Reduced.h b/src/eckit/grid/scanner/Reduced.h similarity index 89% rename from src/eckit/geo/scanner/Reduced.h rename to src/eckit/grid/scanner/Reduced.h index 3299b9167..14dfb939e 100644 --- a/src/eckit/geo/scanner/Reduced.h +++ b/src/eckit/grid/scanner/Reduced.h @@ -12,14 +12,14 @@ #pragma once -#include "eckit/geo/BoundingBox.h" -#include "eckit/geo/Point.h" -#include "eckit/geo/Scanner.h" -#include "eckit/geo/util.h" +#include "eckit/grid/BoundingBox.h" +#include "eckit/grid/Point.h" +#include "eckit/grid/Scanner.h" +#include "eckit/grid/util.h" #include "eckit/types/Fraction.h" -namespace eckit::geo::scanner { +namespace eckit::grid::scanner { class Reduced final : public Scanner { @@ -99,4 +99,4 @@ class Reduced final : public Scanner { }; -} // namespace eckit::geo::scanner +} // namespace eckit::grid::scanner diff --git a/src/eckit/geo/scanner/Regular.cc b/src/eckit/grid/scanner/Regular.cc similarity index 94% rename from src/eckit/geo/scanner/Regular.cc rename to src/eckit/grid/scanner/Regular.cc index 3fa2328db..610cb943d 100644 --- a/src/eckit/geo/scanner/Regular.cc +++ b/src/eckit/grid/scanner/Regular.cc @@ -10,14 +10,14 @@ */ -#include "eckit/geo/scanner/Regular.h" +#include "eckit/grid/scanner/Regular.h" #include #include "eckit/exception/Exceptions.h" -namespace eckit::geo::scanner { +namespace eckit::grid::scanner { Regular::Regular(size_t ni, size_t nj, double north, double west, double we, double ns) : @@ -76,4 +76,4 @@ size_t Regular::size() const { } -} // namespace eckit::geo::scanner +} // namespace eckit::grid::scanner diff --git a/src/eckit/geo/scanner/Regular.h b/src/eckit/grid/scanner/Regular.h similarity index 91% rename from src/eckit/geo/scanner/Regular.h rename to src/eckit/grid/scanner/Regular.h index f8685963d..62feeea6c 100644 --- a/src/eckit/geo/scanner/Regular.h +++ b/src/eckit/grid/scanner/Regular.h @@ -12,12 +12,12 @@ #pragma once -#include "eckit/geo/Point.h" -#include "eckit/geo/Scanner.h" +#include "eckit/grid/Point.h" +#include "eckit/grid/Scanner.h" #include "eckit/types/Fraction.h" -namespace eckit::geo::scanner { +namespace eckit::grid::scanner { class Regular final : public Scanner { @@ -94,4 +94,4 @@ class Regular final : public Scanner { }; -} // namespace eckit::geo::scanner +} // namespace eckit::grid::scanner diff --git a/src/eckit/geo/scanner/Unstructured.cc b/src/eckit/grid/scanner/Unstructured.cc similarity index 83% rename from src/eckit/geo/scanner/Unstructured.cc rename to src/eckit/grid/scanner/Unstructured.cc index 873ff1ec6..8d1df6c01 100644 --- a/src/eckit/geo/scanner/Unstructured.cc +++ b/src/eckit/grid/scanner/Unstructured.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geo/scanner/Unstructured.h" +#include "eckit/grid/scanner/Unstructured.h" // #include <> -namespace eckit::geo::scanner { +namespace eckit::grid::scanner { Unstructured::Unstructured() = default; @@ -31,4 +31,4 @@ size_t Unstructured::size() const { } -} // namespace eckit::geo::scanner +} // namespace eckit::grid::scanner diff --git a/src/eckit/geo/scanner/Unstructured.h b/src/eckit/grid/scanner/Unstructured.h similarity index 91% rename from src/eckit/geo/scanner/Unstructured.h rename to src/eckit/grid/scanner/Unstructured.h index 68bf30a96..7c441c246 100644 --- a/src/eckit/geo/scanner/Unstructured.h +++ b/src/eckit/grid/scanner/Unstructured.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geo/Scanner.h" +#include "eckit/grid/Scanner.h" -namespace eckit::geo::scanner { +namespace eckit::grid::scanner { class Unstructured final : public Scanner { @@ -74,4 +74,4 @@ class Unstructured final : public Scanner { }; -} // namespace eckit::geo::scanner +} // namespace eckit::grid::scanner diff --git a/src/eckit/geo/util.cc b/src/eckit/grid/util.cc similarity index 83% rename from src/eckit/geo/util.cc rename to src/eckit/grid/util.cc index 5937054c6..5e2847c47 100644 --- a/src/eckit/geo/util.cc +++ b/src/eckit/grid/util.cc @@ -10,10 +10,10 @@ */ -#include "eckit/geo/util.h" +#include "eckit/grid/util.h" -namespace eckit::geo::util { +namespace eckit::grid::util { template <> @@ -22,4 +22,4 @@ pl_type pl_convert(const pl_type& pl) { } -} // namespace eckit::geo::util +} // namespace eckit::grid::util diff --git a/src/eckit/geo/util.h b/src/eckit/grid/util.h similarity index 96% rename from src/eckit/geo/util.h rename to src/eckit/grid/util.h index efa1b7dc8..6f0bb0885 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/grid/util.h @@ -19,7 +19,7 @@ #include -namespace eckit::geo { +namespace eckit::grid { using pl_type = std::vector; @@ -72,4 +72,4 @@ pl_type::value_type regular_pl(size_t N); } // namespace util -} // namespace eckit::geo +} // namespace eckit::grid diff --git a/src/eckit/geo/util/arange.cc b/src/eckit/grid/util/arange.cc similarity index 93% rename from src/eckit/geo/util/arange.cc rename to src/eckit/grid/util/arange.cc index 095eb8fcd..5ae30e32f 100644 --- a/src/eckit/geo/util/arange.cc +++ b/src/eckit/grid/util/arange.cc @@ -15,7 +15,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geo::util { +namespace eckit::grid::util { std::vector arange(double start, double stop, double step) { @@ -33,4 +33,4 @@ std::vector arange(double start, double stop, double step) { } -} // namespace eckit::geo::util +} // namespace eckit::grid::util diff --git a/src/eckit/geo/util/gaussian_latitudes.cc b/src/eckit/grid/util/gaussian_latitudes.cc similarity index 97% rename from src/eckit/geo/util/gaussian_latitudes.cc rename to src/eckit/grid/util/gaussian_latitudes.cc index 4fd5a8ba6..436abca78 100644 --- a/src/eckit/geo/util/gaussian_latitudes.cc +++ b/src/eckit/grid/util/gaussian_latitudes.cc @@ -18,7 +18,7 @@ #include "eckit/exception/Exceptions.h" -namespace eckit::geo::util { +namespace eckit::grid::util { std::vector gaussian_latitudes(size_t N, bool increasing) { @@ -95,4 +95,4 @@ std::vector gaussian_latitudes(size_t N, bool increasing) { } -} // namespace eckit::geo::util +} // namespace eckit::grid::util diff --git a/src/eckit/geo/util/linspace.cc b/src/eckit/grid/util/linspace.cc similarity index 93% rename from src/eckit/geo/util/linspace.cc rename to src/eckit/grid/util/linspace.cc index 5f8948a67..f1da13149 100644 --- a/src/eckit/geo/util/linspace.cc +++ b/src/eckit/grid/util/linspace.cc @@ -14,7 +14,7 @@ #include -namespace eckit::geo::util { +namespace eckit::grid::util { std::vector linspace(double start, double stop, size_t num, bool endpoint) { @@ -32,4 +32,4 @@ std::vector linspace(double start, double stop, size_t num, bool endpoin } -} // namespace eckit::geo::util +} // namespace eckit::grid::util diff --git a/src/eckit/geo/util/monotonic_crop.cc b/src/eckit/grid/util/monotonic_crop.cc similarity index 96% rename from src/eckit/geo/util/monotonic_crop.cc rename to src/eckit/grid/util/monotonic_crop.cc index d636a5d14..88fbbce21 100644 --- a/src/eckit/geo/util/monotonic_crop.cc +++ b/src/eckit/grid/util/monotonic_crop.cc @@ -18,7 +18,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geo::util { +namespace eckit::grid::util { std::pair::const_iterator, std::vector::const_iterator> monotonic_crop( @@ -48,4 +48,4 @@ std::pair::const_iterator, std::vector::const_iterat } -} // namespace eckit::geo::util +} // namespace eckit::grid::util diff --git a/src/eckit/geo/util/reduced_classical_pl.cc b/src/eckit/grid/util/reduced_classical_pl.cc similarity index 99% rename from src/eckit/geo/util/reduced_classical_pl.cc rename to src/eckit/grid/util/reduced_classical_pl.cc index 46441eb54..23c1b050e 100644 --- a/src/eckit/geo/util/reduced_classical_pl.cc +++ b/src/eckit/grid/util/reduced_classical_pl.cc @@ -14,10 +14,10 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/util.h" +#include "eckit/grid/util.h" -namespace eckit::geo::util { +namespace eckit::grid::util { static const std::map __classical_pls{ @@ -1341,4 +1341,4 @@ const pl_type& reduced_classical_pl(size_t N) { } -} // namespace eckit::geo::util +} // namespace eckit::grid::util diff --git a/src/eckit/geo/util/reduced_octahedral_pl.cc b/src/eckit/grid/util/reduced_octahedral_pl.cc similarity index 90% rename from src/eckit/geo/util/reduced_octahedral_pl.cc rename to src/eckit/grid/util/reduced_octahedral_pl.cc index a6223dd22..268fc18ed 100644 --- a/src/eckit/geo/util/reduced_octahedral_pl.cc +++ b/src/eckit/grid/util/reduced_octahedral_pl.cc @@ -13,10 +13,10 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/util.h" +#include "eckit/grid/util.h" -namespace eckit::geo::util { +namespace eckit::grid::util { const pl_type& reduced_octahedral_pl(size_t N) { @@ -40,4 +40,4 @@ const pl_type& reduced_octahedral_pl(size_t N) { } -} // namespace eckit::geo::util +} // namespace eckit::grid::util diff --git a/src/eckit/geo/util/regular_pl.cc b/src/eckit/grid/util/regular_pl.cc similarity index 85% rename from src/eckit/geo/util/regular_pl.cc rename to src/eckit/grid/util/regular_pl.cc index f6c639c84..326501b6f 100644 --- a/src/eckit/geo/util/regular_pl.cc +++ b/src/eckit/grid/util/regular_pl.cc @@ -11,10 +11,10 @@ #include "eckit/exception/Exceptions.h" -#include "eckit/geo/util.h" +#include "eckit/grid/util.h" -namespace eckit::geo::util { +namespace eckit::grid::util { pl_type::value_type regular_pl(size_t N) { @@ -24,4 +24,4 @@ pl_type::value_type regular_pl(size_t N) { } -} // namespace eckit::geo::util +} // namespace eckit::grid::util diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e959e5e87..9b7ba999f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,9 +1,9 @@ -add_subdirectory( config ) +add_subdirectory( config ) add_subdirectory( container ) add_subdirectory( exception ) add_subdirectory( filesystem ) -add_subdirectory( geo ) add_subdirectory( geometry ) +add_subdirectory( grid ) add_subdirectory( io ) add_subdirectory( large_file ) add_subdirectory( linalg ) diff --git a/tests/geo/CMakeLists.txt b/tests/grid/CMakeLists.txt similarity index 71% rename from tests/geo/CMakeLists.txt rename to tests/grid/CMakeLists.txt index b4f22d007..683fc8169 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/grid/CMakeLists.txt @@ -10,15 +10,15 @@ foreach( _test util ) ecbuild_add_test( - TARGET eckit_test_geo_${_test} + TARGET eckit_test_grid_${_test} SOURCES test_${_test}.cc - LIBS eckit_geo ) + LIBS eckit_grid ) endforeach() if(HAVE_ECCODES) ecbuild_add_test( - TARGET eckit_test_geo_grib + TARGET eckit_test_grid_grib SOURCES test_grib.cc - LIBS eckit_geo_grib) + LIBS eckit_grid_grib) endif() diff --git a/tests/geo/reduced_gg.grib2 b/tests/grid/reduced_gg.grib2 similarity index 100% rename from tests/geo/reduced_gg.grib2 rename to tests/grid/reduced_gg.grib2 diff --git a/tests/geo/reduced_ll.grib1 b/tests/grid/reduced_ll.grib1 similarity index 100% rename from tests/geo/reduced_ll.grib1 rename to tests/grid/reduced_ll.grib1 diff --git a/tests/geo/regular_gg.grib1 b/tests/grid/regular_gg.grib1 similarity index 100% rename from tests/geo/regular_gg.grib1 rename to tests/grid/regular_gg.grib1 diff --git a/tests/geo/regular_ll.grib1 b/tests/grid/regular_ll.grib1 similarity index 100% rename from tests/geo/regular_ll.grib1 rename to tests/grid/regular_ll.grib1 diff --git a/tests/geo/test_grib.cc b/tests/grid/test_grib.cc similarity index 88% rename from tests/geo/test_grib.cc rename to tests/grid/test_grib.cc index 5e0ae25fa..4434321ab 100644 --- a/tests/geo/test_grib.cc +++ b/tests/grid/test_grib.cc @@ -21,7 +21,7 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/grib/GribConfiguration.h" +#include "eckit/grid/grib/GribConfiguration.h" #if 0 @@ -41,39 +41,39 @@ #if 0 -eckit::geo::Figure* make_figure(long code) { +eckit::grid::Figure* make_figure(long code) { // Code table 3.2 – Shape of the reference system switch (code) { case 0: - return new eckit::geo::figure::Sphere(6367470.); + return new eckit::grid::figure::Sphere(6367470.); case 1: // Earth assumed spherical with radius specified (in m) by data producer NOTIMP; case 2: - return new eckit::geo::figure::Spheroid(6378160., 6356775.); + return new eckit::grid::figure::Spheroid(6378160., 6356775.); case 3: // Earth assumed oblate spheroid with major and minor axes specified (in km) by data producer NOTIMP; case 4: - return new eckit::geo::figure::Spheroid(6378137., 6356752.314); + return new eckit::grid::figure::Spheroid(6378137., 6356752.314); case 5: - return new eckit::geo::figure::Spheroid(6378137., 6356752.314140347); + return new eckit::grid::figure::Spheroid(6378137., 6356752.314140347); case 6: - return new eckit::geo::figure::Sphere(6371229.); + return new eckit::grid::figure::Sphere(6371229.); case 7: // Earth assumed oblate spheroid with major or minor axes specified (in m) by data producer NOTIMP; case 8: - return new eckit::geo::figure::Sphere(6371200.); + return new eckit::grid::figure::Sphere(6371200.); case 9: - return new eckit::geo::figure::Spheroid(6377563.396, 6356256.909); + return new eckit::grid::figure::Spheroid(6377563.396, 6356256.909); case 10: // Earth model assumed WGS84 with corrected geomagnetic coordinates (latitude and longitude) defined by // Gustafsson et al., 1992 NOTIMP; case 11: - return new eckit::geo::figure::Sphere(695990000.); + return new eckit::grid::figure::Sphere(695990000.); default: NOTIMP; } @@ -138,7 +138,7 @@ int main(int argc, const char* argv[]) { int err = 0; for (codes_handle* h = nullptr; nullptr != (h = codes_handle_new_from_file(nullptr, in, PRODUCT_GRIB, &err));) { - eckit::geo::grib::GribConfiguration grib(h); + eckit::grid::grib::GribConfiguration grib(h); #if 0 int n = 0; @@ -153,7 +153,7 @@ int main(int argc, const char* argv[]) { std::cout << "type: '" << type << "'" << std::endl; if (grib.has("pl")) { - // std::cout << "pl: '" << grib.get("pl") << "'" << std::endl; + // std::cout << "pl: '" << grib.get("pl") << "'" << std::endl; } if (type == "regular_ll") { diff --git a/tests/geo/test_iterator.cc b/tests/grid/test_iterator.cc similarity index 66% rename from tests/geo/test_iterator.cc rename to tests/grid/test_iterator.cc index 05c32425d..9936e70b4 100644 --- a/tests/geo/test_iterator.cc +++ b/tests/grid/test_iterator.cc @@ -13,20 +13,20 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Scanner.h" -// #include "eckit/geo/iterator/IteratorAggregator.h" -// #include "eckit/geo/iterator/IteratorComposer.h" +#include "eckit/grid/Scanner.h" +// #include "eckit/grid/iterator/IteratorAggregator.h" +// #include "eckit/grid/iterator/IteratorComposer.h" int main(int argc, const char* argv[]) { - // eckit::geo::iterator::IteratorComposer i(nullptr); + // eckit::grid::iterator::IteratorComposer i(nullptr); - // struct ScannerTest : public eckit::geo::Scanner { + // struct ScannerTest : public eckit::grid::Scanner { // bool operator++() override { NOTIMP; } // size_t size() const override { NOTIMP; } // }; - // eckit::geo::iterator::IteratorAggregator j; + // eckit::grid::iterator::IteratorAggregator j; return 0; } diff --git a/tests/geo/test_param.cc b/tests/grid/test_param.cc similarity index 100% rename from tests/geo/test_param.cc rename to tests/grid/test_param.cc diff --git a/tests/geo/test_projection.cc b/tests/grid/test_projection.cc similarity index 88% rename from tests/geo/test_projection.cc rename to tests/grid/test_projection.cc index 1511faea7..11c09aa32 100644 --- a/tests/geo/test_projection.cc +++ b/tests/grid/test_projection.cc @@ -14,20 +14,20 @@ #include #include "eckit/config/MappedConfiguration.h" -#include "eckit/geo/Projection.h" +#include "eckit/grid/Projection.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { using eckit::MappedConfiguration; - using eckit::geo::Point; - using eckit::geo::Point3; - using eckit::geo::PointLonLat; - using eckit::geo::points_equal; + using eckit::grid::Point; + using eckit::grid::Point3; + using eckit::grid::PointLonLat; + using eckit::grid::points_equal; - using Projection = std::unique_ptr; - using ProjectionFactory = eckit::geo::ProjectionFactory; + using Projection = std::unique_ptr; + using ProjectionFactory = eckit::grid::ProjectionFactory; Point p = PointLonLat{1, 1}; diff --git a/tests/geo/test_projection_ll_to_xyz.cc b/tests/grid/test_projection_ll_to_xyz.cc similarity index 84% rename from tests/geo/test_projection_ll_to_xyz.cc rename to tests/grid/test_projection_ll_to_xyz.cc index 687bdad84..38122064f 100644 --- a/tests/geo/test_projection_ll_to_xyz.cc +++ b/tests/grid/test_projection_ll_to_xyz.cc @@ -12,14 +12,14 @@ #include -#include "eckit/geo/projection/LonLatToXYZ.h" +#include "eckit/grid/projection/LonLatToXYZ.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using eckit::geo::Point; - using eckit::geo::PointLonLat; - using eckit::geo::projection::LonLatToXYZ; + using eckit::grid::Point; + using eckit::grid::PointLonLat; + using eckit::grid::projection::LonLatToXYZ; const PointLonLat p(1., 723.); @@ -30,7 +30,7 @@ int main(int argc, char* argv[]) { auto r = to_xyz.inv(q); std::cout << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; - EXPECT(eckit::geo::points_equal(p, r)); + EXPECT(eckit::grid::points_equal(p, r)); } diff --git a/tests/geo/test_projection_proj.cc b/tests/grid/test_projection_proj.cc similarity index 59% rename from tests/geo/test_projection_proj.cc rename to tests/grid/test_projection_proj.cc index d9380f325..bf4f9a431 100644 --- a/tests/geo/test_projection_proj.cc +++ b/tests/grid/test_projection_proj.cc @@ -13,37 +13,37 @@ #include #include "eckit/config/MappedConfiguration.h" -#include "eckit/geo/projection/PROJ.h" +#include "eckit/grid/projection/PROJ.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using eckit::geo::points_equal; + using eckit::grid::points_equal; std::cout.precision(14); - eckit::geo::PointLonLat a{12., 55.}; + eckit::grid::PointLonLat a{12., 55.}; struct { - const eckit::geo::Point b; + const eckit::grid::Point b; const std::string target; } tests[] = { - {eckit::geo::Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, - {eckit::geo::Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, + {eckit::grid::Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, + {eckit::grid::Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, {a, "EPSG:4326"}, {a, "EPSG:4979"}, - {eckit::geo::Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, - {eckit::geo::Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, + {eckit::grid::Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, + {eckit::grid::Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, "+proj=cart +R=6371229."}, - {eckit::geo::Point3{3574399.5431832, 759762.07693392, 5218815.216709}, + {eckit::grid::Point3{3574399.5431832, 759762.07693392, 5218815.216709}, "+proj=cart +ellps=sphere"}, {a, "+proj=latlon +ellps=sphere"}, }; for (const auto& test : tests) { - eckit::geo::projection::PROJ projection(eckit::MappedConfiguration({{"source", "EPSG:4326"}, {"target", test.target}})); + eckit::grid::projection::PROJ projection(eckit::MappedConfiguration({{"source", "EPSG:4326"}, {"target", test.target}})); - std::cout << "ellipsoid: '" << eckit::geo::projection::PROJ::ellipsoid(projection.target()) + std::cout << "ellipsoid: '" << eckit::grid::projection::PROJ::ellipsoid(projection.target()) << std::endl; auto b = projection.fwd(a); @@ -54,7 +54,7 @@ int main(int argc, char* argv[]) { EXPECT(points_equal(b, test.b)); EXPECT(points_equal(c, a)); - eckit::geo::projection::PROJ reverse(eckit::MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}})); + eckit::grid::projection::PROJ reverse(eckit::MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}})); auto d = reverse.fwd(test.b); auto e = reverse.inv(d); diff --git a/tests/geo/test_projection_rotation.cc b/tests/grid/test_projection_rotation.cc similarity index 96% rename from tests/geo/test_projection_rotation.cc rename to tests/grid/test_projection_rotation.cc index 532fa76d3..4a8deb6fa 100644 --- a/tests/geo/test_projection_rotation.cc +++ b/tests/grid/test_projection_rotation.cc @@ -12,15 +12,15 @@ #include -#include "eckit/geo/projection/Rotation.h" +#include "eckit/grid/projection/Rotation.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using eckit::geo::Point; - using eckit::geo::PointLonLat; - using eckit::geo::points_equal; - using eckit::geo::projection::Rotation; + using eckit::grid::Point; + using eckit::grid::PointLonLat; + using eckit::grid::points_equal; + using eckit::grid::projection::Rotation; { const PointLonLat p(1, 1); diff --git a/tests/geo/test_search.cc b/tests/grid/test_search.cc similarity index 85% rename from tests/geo/test_search.cc rename to tests/grid/test_search.cc index d0672b506..dbf161c2a 100644 --- a/tests/geo/test_search.cc +++ b/tests/grid/test_search.cc @@ -13,16 +13,16 @@ #include #include -#include "eckit/geo/Search.h" +#include "eckit/grid/Search.h" int main(int argc, const char* argv[]) { { - std::vector points{ + std::vector points{ {{0, 0, 0}, 0}, }; - eckit::geo::Search3 search; + eckit::grid::Search3 search; search.build(points); std::cout << search.nearestNeighbour({0.1, 0, 0}) << std::endl; @@ -36,11 +36,11 @@ int main(int argc, const char* argv[]) { { - std::vector points{ + std::vector points{ {{0, 0}, 0}, }; - eckit::geo::Search2 search; + eckit::grid::Search2 search; search.build(points); std::cout << search.nearestNeighbour({0.1, 0}) << std::endl; diff --git a/tests/geo/test_types.cc b/tests/grid/test_types.cc similarity index 96% rename from tests/geo/test_types.cc rename to tests/grid/test_types.cc index f0d88a86d..d03479788 100644 --- a/tests/geo/test_types.cc +++ b/tests/grid/test_types.cc @@ -12,13 +12,13 @@ #include -#include "eckit/geo/Point.h" +#include "eckit/grid/Point.h" #include "eckit/maths/Matrix3.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using namespace eckit::geo; + using namespace eckit::grid; PointLonLat p(1, 90.); diff --git a/tests/geo/test_util.cc b/tests/grid/test_util.cc similarity index 97% rename from tests/geo/test_util.cc rename to tests/grid/test_util.cc index 383df4315..7991595c1 100644 --- a/tests/geo/test_util.cc +++ b/tests/grid/test_util.cc @@ -13,7 +13,7 @@ #include #include -#include "eckit/geo/util.h" +#include "eckit/grid/util.h" template @@ -68,7 +68,7 @@ class iterable_t : public std::vector { int main(int argc, char* argv[]) { - using namespace eckit::geo::util; + using namespace eckit::grid::util; #if 0 std::cout << linspace(1, 2, 2, true) << std::endl; From 17b52bc2985ac4acc243ba5094e516636a471d35 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 4 Jul 2023 11:51:50 +0100 Subject: [PATCH 248/737] eckit::geometry --- src/eckit/CMakeLists.txt | 1 - src/eckit/{grid => geometry}/BoundingBox.cc | 10 +- src/eckit/{grid => geometry}/BoundingBox.h | 6 +- src/eckit/geometry/CMakeLists.txt | 133 ++++++++--- src/eckit/{grid => geometry}/Domain.cc | 10 +- src/eckit/{grid => geometry}/Domain.h | 4 +- src/eckit/{grid => geometry}/Earth.h | 4 +- src/eckit/{grid => geometry}/Figure.cc | 6 +- src/eckit/{grid => geometry}/Figure.h | 4 +- src/eckit/{grid => geometry}/Grid.cc | 12 +- src/eckit/{grid => geometry}/Grid.h | 14 +- src/eckit/{grid => geometry}/Increments.cc | 6 +- src/eckit/{grid => geometry}/Increments.h | 4 +- src/eckit/{grid => geometry}/Iterator.cc | 8 +- src/eckit/{grid => geometry}/Iterator.h | 8 +- src/eckit/{grid => geometry}/Point.cc | 8 +- src/eckit/{grid => geometry}/Point.h | 6 +- src/eckit/{grid => geometry}/Projection.cc | 6 +- src/eckit/{grid => geometry}/Projection.h | 6 +- src/eckit/{grid => geometry}/Range.cc | 8 +- src/eckit/{grid => geometry}/Range.h | 4 +- src/eckit/{grid => geometry}/Renumber.h | 4 +- src/eckit/{grid => geometry}/Scanner.cc | 6 +- src/eckit/{grid => geometry}/Scanner.h | 4 +- src/eckit/{grid => geometry}/Search.h | 4 +- .../{grid => geometry}/detail/Gaussian.cc | 10 +- .../{grid => geometry}/detail/Gaussian.h | 6 +- .../detail/GaussianIterator.cc | 6 +- .../detail/GaussianIterator.h | 10 +- .../detail/IrregularLatlon.cc | 10 +- .../detail/IrregularLatlon.h | 6 +- .../{grid => geometry}/detail/ReducedGG.cc | 12 +- .../{grid => geometry}/detail/ReducedGG.h | 8 +- .../{grid => geometry}/detail/ReducedLL.cc | 12 +- .../{grid => geometry}/detail/ReducedLL.h | 6 +- .../{grid => geometry}/detail/RegularGG.cc | 10 +- .../{grid => geometry}/detail/RegularGG.h | 6 +- .../{grid => geometry}/detail/RegularGrid.cc | 10 +- .../{grid => geometry}/detail/RegularGrid.h | 10 +- .../{grid => geometry}/detail/RegularLL.cc | 14 +- .../{grid => geometry}/detail/RegularLL.h | 8 +- .../detail/UnstructuredGrid.cc | 12 +- .../detail/UnstructuredGrid.h | 6 +- .../projection/LonLatToXYZ.cc | 6 +- .../projection/LonLatToXYZ.h | 6 +- .../{grid => geometry}/projection/None.cc | 6 +- .../{grid => geometry}/projection/None.h | 6 +- .../{grid => geometry}/projection/PROJ.cc | 6 +- .../{grid => geometry}/projection/PROJ.h | 6 +- .../{grid => geometry}/projection/Rotation.cc | 8 +- .../{grid => geometry}/projection/Rotation.h | 6 +- .../{grid => geometry}/scanner/Reduced.cc | 6 +- .../{grid => geometry}/scanner/Reduced.h | 12 +- .../{grid => geometry}/scanner/Regular.cc | 6 +- .../{grid => geometry}/scanner/Regular.h | 8 +- .../scanner/Unstructured.cc | 6 +- .../{grid => geometry}/scanner/Unstructured.h | 6 +- src/eckit/{grid => geometry}/util.cc | 6 +- src/eckit/{grid => geometry}/util.h | 4 +- src/eckit/{grid => geometry}/util/arange.cc | 4 +- .../util/gaussian_latitudes.cc | 4 +- src/eckit/{grid => geometry}/util/linspace.cc | 4 +- .../{grid => geometry}/util/monotonic_crop.cc | 4 +- .../util/reduced_classical_pl.cc | 6 +- .../util/reduced_octahedral_pl.cc | 6 +- .../{grid => geometry}/util/regular_pl.cc | 6 +- src/eckit/grid/CMakeLists.txt | 92 ------- src/eckit/grid/grib/GribConfiguration.cc | 224 ------------------ src/eckit/grid/grib/GribConfiguration.h | 143 ----------- tests/CMakeLists.txt | 1 - tests/geometry/CMakeLists.txt | 32 ++- tests/{grid => geometry}/test_iterator.cc | 8 +- tests/{grid => geometry}/test_param.cc | 0 tests/{grid => geometry}/test_projection.cc | 14 +- .../test_projection_ll_to_xyz.cc | 9 +- .../test_projection_proj.cc | 29 ++- .../test_projection_rotation.cc | 10 +- tests/{grid => geometry}/test_search.cc | 13 +- tests/{grid => geometry}/test_types.cc | 4 +- tests/{grid => geometry}/test_util.cc | 4 +- tests/grid/CMakeLists.txt | 24 -- tests/grid/reduced_gg.grib2 | Bin 6420 -> 0 bytes tests/grid/reduced_ll.grib1 | Bin 3470 -> 0 bytes tests/grid/regular_gg.grib1 | Bin 108 -> 0 bytes tests/grid/regular_ll.grib1 | Bin 108 -> 0 bytes tests/grid/test_grib.cc | 206 ---------------- 86 files changed, 405 insertions(+), 994 deletions(-) rename src/eckit/{grid => geometry}/BoundingBox.cc (96%) rename src/eckit/{grid => geometry}/BoundingBox.h (96%) rename src/eckit/{grid => geometry}/Domain.cc (94%) rename src/eckit/{grid => geometry}/Domain.h (97%) rename src/eckit/{grid => geometry}/Earth.h (92%) rename src/eckit/{grid => geometry}/Figure.cc (85%) rename src/eckit/{grid => geometry}/Figure.h (95%) rename src/eckit/{grid => geometry}/Grid.cc (91%) rename src/eckit/{grid => geometry}/Grid.h (92%) rename src/eckit/{grid => geometry}/Increments.cc (85%) rename src/eckit/{grid => geometry}/Increments.h (94%) rename src/eckit/{grid => geometry}/Iterator.cc (94%) rename src/eckit/{grid => geometry}/Iterator.h (97%) rename src/eckit/{grid => geometry}/Point.cc (80%) rename src/eckit/{grid => geometry}/Point.h (88%) rename src/eckit/{grid => geometry}/Projection.cc (98%) rename src/eckit/{grid => geometry}/Projection.h (96%) rename src/eckit/{grid => geometry}/Range.cc (95%) rename src/eckit/{grid => geometry}/Range.h (96%) rename src/eckit/{grid => geometry}/Renumber.h (88%) rename src/eckit/{grid => geometry}/Scanner.cc (94%) rename src/eckit/{grid => geometry}/Scanner.h (96%) rename src/eckit/{grid => geometry}/Search.h (97%) rename src/eckit/{grid => geometry}/detail/Gaussian.cc (94%) rename src/eckit/{grid => geometry}/detail/Gaussian.h (93%) rename src/eckit/{grid => geometry}/detail/GaussianIterator.cc (95%) rename src/eckit/{grid => geometry}/detail/GaussianIterator.h (86%) rename src/eckit/{grid => geometry}/detail/IrregularLatlon.cc (95%) rename src/eckit/{grid => geometry}/detail/IrregularLatlon.h (93%) rename src/eckit/{grid => geometry}/detail/ReducedGG.cc (96%) rename src/eckit/{grid => geometry}/detail/ReducedGG.h (93%) rename src/eckit/{grid => geometry}/detail/ReducedLL.cc (94%) rename src/eckit/{grid => geometry}/detail/ReducedLL.h (92%) rename src/eckit/{grid => geometry}/detail/RegularGG.cc (94%) rename src/eckit/{grid => geometry}/detail/RegularGG.h (92%) rename src/eckit/{grid => geometry}/detail/RegularGrid.cc (97%) rename src/eckit/{grid => geometry}/detail/RegularGrid.h (91%) rename src/eckit/{grid => geometry}/detail/RegularLL.cc (96%) rename src/eckit/{grid => geometry}/detail/RegularLL.h (92%) rename src/eckit/{grid => geometry}/detail/UnstructuredGrid.cc (95%) rename src/eckit/{grid => geometry}/detail/UnstructuredGrid.h (95%) rename src/eckit/{grid => geometry}/projection/LonLatToXYZ.cc (93%) rename src/eckit/{grid => geometry}/projection/LonLatToXYZ.h (94%) rename src/eckit/{grid => geometry}/projection/None.cc (80%) rename src/eckit/{grid => geometry}/projection/None.h (90%) rename src/eckit/{grid => geometry}/projection/PROJ.cc (96%) rename src/eckit/{grid => geometry}/projection/PROJ.h (95%) rename src/eckit/{grid => geometry}/projection/Rotation.cc (96%) rename src/eckit/{grid => geometry}/projection/Rotation.h (94%) rename src/eckit/{grid => geometry}/scanner/Reduced.cc (95%) rename src/eckit/{grid => geometry}/scanner/Reduced.h (88%) rename src/eckit/{grid => geometry}/scanner/Regular.cc (93%) rename src/eckit/{grid => geometry}/scanner/Regular.h (90%) rename src/eckit/{grid => geometry}/scanner/Unstructured.cc (81%) rename src/eckit/{grid => geometry}/scanner/Unstructured.h (90%) rename src/eckit/{grid => geometry}/util.cc (81%) rename src/eckit/{grid => geometry}/util.h (96%) rename src/eckit/{grid => geometry}/util/arange.cc (93%) rename src/eckit/{grid => geometry}/util/gaussian_latitudes.cc (97%) rename src/eckit/{grid => geometry}/util/linspace.cc (92%) rename src/eckit/{grid => geometry}/util/monotonic_crop.cc (95%) rename src/eckit/{grid => geometry}/util/reduced_classical_pl.cc (99%) rename src/eckit/{grid => geometry}/util/reduced_octahedral_pl.cc (89%) rename src/eckit/{grid => geometry}/util/regular_pl.cc (84%) delete mode 100644 src/eckit/grid/CMakeLists.txt delete mode 100644 src/eckit/grid/grib/GribConfiguration.cc delete mode 100644 src/eckit/grid/grib/GribConfiguration.h rename tests/{grid => geometry}/test_iterator.cc (77%) rename tests/{grid => geometry}/test_param.cc (100%) rename tests/{grid => geometry}/test_projection.cc (88%) rename tests/{grid => geometry}/test_projection_ll_to_xyz.cc (84%) rename tests/{grid => geometry}/test_projection_proj.cc (58%) rename tests/{grid => geometry}/test_projection_rotation.cc (96%) rename tests/{grid => geometry}/test_search.cc (85%) rename tests/{grid => geometry}/test_types.cc (96%) rename tests/{grid => geometry}/test_util.cc (97%) delete mode 100644 tests/grid/CMakeLists.txt delete mode 100644 tests/grid/reduced_gg.grib2 delete mode 100644 tests/grid/reduced_ll.grib1 delete mode 100644 tests/grid/regular_gg.grib1 delete mode 100644 tests/grid/regular_ll.grib1 delete mode 100644 tests/grid/test_grib.cc diff --git a/src/eckit/CMakeLists.txt b/src/eckit/CMakeLists.txt index ecf9fae38..a328e32ee 100644 --- a/src/eckit/CMakeLists.txt +++ b/src/eckit/CMakeLists.txt @@ -971,7 +971,6 @@ endif() add_subdirectory( distributed ) add_subdirectory( geometry ) -add_subdirectory( grid ) add_subdirectory( linalg ) add_subdirectory( maths ) add_subdirectory( mpi ) diff --git a/src/eckit/grid/BoundingBox.cc b/src/eckit/geometry/BoundingBox.cc similarity index 96% rename from src/eckit/grid/BoundingBox.cc rename to src/eckit/geometry/BoundingBox.cc index 868c8946c..6e84a14f2 100644 --- a/src/eckit/grid/BoundingBox.cc +++ b/src/eckit/geometry/BoundingBox.cc @@ -10,20 +10,20 @@ */ -#include "eckit/grid/BoundingBox.h" +#include "eckit/geometry/BoundingBox.h" #include #include #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geometry/Point.h" #include "eckit/geometry/Sphere.h" -#include "eckit/grid/Point.h" -#include "eckit/grid/util.h" +#include "eckit/geometry/util.h" #include "eckit/types/FloatCompare.h" -namespace eckit::grid { +namespace eckit::geometry { BoundingBox::BoundingBox(const Configuration& config) : @@ -151,4 +151,4 @@ BoundingBox BoundingBox::make(const BoundingBox&, const Projection&) { } -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/BoundingBox.h b/src/eckit/geometry/BoundingBox.h similarity index 96% rename from src/eckit/grid/BoundingBox.h rename to src/eckit/geometry/BoundingBox.h index cc4014f4b..57cf4bfef 100644 --- a/src/eckit/grid/BoundingBox.h +++ b/src/eckit/geometry/BoundingBox.h @@ -18,13 +18,13 @@ namespace eckit { class Configuration; -namespace grid { +namespace geometry { class Projection; } } // namespace eckit -namespace eckit::grid { +namespace eckit::geometry { class BoundingBox { @@ -132,4 +132,4 @@ class BoundingBox { }; -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index d35836935..ce485c0a0 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -1,35 +1,106 @@ list( APPEND eckit_geometry_srcs -CoordinateHelpers.cc -CoordinateHelpers.h -EllipsoidOfRevolution.cc -EllipsoidOfRevolution.h -GreatCircle.cc -GreatCircle.h -KPoint.cc -KPoint.h -Point2.cc -Point2.h -Point3.cc -Point3.h -PointLonLat.cc -PointLonLat.h -Sphere.cc -Sphere.h -SphereT.h -UnitSphere.h -polygon/LonLatPolygon.cc -polygon/LonLatPolygon.h -polygon/Polygon.cc -polygon/Polygon.h + BoundingBox.cc + BoundingBox.h + CoordinateHelpers.cc + CoordinateHelpers.h + Domain.cc + Domain.h + Earth.h + EllipsoidOfRevolution.cc + EllipsoidOfRevolution.h + Figure.cc + Figure.h + GreatCircle.cc + GreatCircle.h + Grid.cc + Grid.h + Increments.cc + Increments.h + Iterator.cc + Iterator.h + KPoint.cc + KPoint.h + Point.cc + Point.h + Point2.cc + Point2.h + Point3.cc + Point3.h + PointLonLat.cc + PointLonLat.h + Projection.cc + Projection.h + Range.cc + Range.h + Renumber.h + Scanner.cc + Scanner.h + Search.h + Sphere.cc + Sphere.h + SphereT.h + UnitSphere.h + detail/Gaussian.cc + detail/Gaussian.h + detail/GaussianIterator.cc + detail/GaussianIterator.h + detail/IrregularLatlon.cc + detail/IrregularLatlon.h + detail/ReducedGG.cc + detail/ReducedGG.h + detail/ReducedLL.cc + detail/ReducedLL.h + detail/RegularGG.cc + detail/RegularGG.h + detail/RegularGrid.cc + detail/RegularGrid.h + detail/RegularLL.cc + detail/RegularLL.h + detail/UnstructuredGrid.cc + detail/UnstructuredGrid.h + polygon/LonLatPolygon.cc + polygon/LonLatPolygon.h + polygon/Polygon.cc + polygon/Polygon.h + projection/LonLatToXYZ.cc + projection/LonLatToXYZ.h + projection/None.cc + projection/None.h + projection/Rotation.cc + projection/Rotation.h + scanner/Reduced.cc + scanner/Reduced.h + scanner/Regular.cc + scanner/Regular.h + scanner/Unstructured.cc + scanner/Unstructured.h + util.cc + util.h + util/arange.cc + util/gaussian_latitudes.cc + util/linspace.cc + util/monotonic_crop.cc + util/reduced_classical_pl.cc + util/reduced_octahedral_pl.cc + util/regular_pl.cc ) +set(eckit_geometry_include_dirs ) +set(eckit_geometry_libs eckit_maths) + +if(HAVE_PROJ) + list(APPEND eckit_geometry_srcs projection/PROJ.cc projection/PROJ.h) + list(APPEND eckit_geometry_libs PROJ::proj) + list(APPEND eckit_geometry_include_dirs ${PROJ_INCLUDE_DIRS}) +endif() + ecbuild_add_library( - TARGET eckit_geometry - TYPE SHARED - INSTALL_HEADERS ALL - HEADER_DESTINATION - ${INSTALL_INCLUDE_DIR}/eckit/geometry - SOURCES - ${eckit_geometry_srcs} - PUBLIC_LIBS - eckit ) + TARGET eckit_geometry + TYPE SHARED + INSTALL_HEADERS ALL + HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geometry + SOURCES ${eckit_geometry_srcs} + PUBLIC_LIBS ${eckit_geometry_libs} + PUBLIC_INCLUDES ${eckit_geometry_include_dirs} +) + diff --git a/src/eckit/grid/Domain.cc b/src/eckit/geometry/Domain.cc similarity index 94% rename from src/eckit/grid/Domain.cc rename to src/eckit/geometry/Domain.cc index dc950fe6f..1f92c3ce6 100644 --- a/src/eckit/grid/Domain.cc +++ b/src/eckit/geometry/Domain.cc @@ -10,19 +10,19 @@ */ -#include "eckit/grid/Domain.h" +#include "eckit/geometry/Domain.h" #include #include #include "eckit/exception/Exceptions.h" +#include "eckit/geometry/Point.h" #include "eckit/geometry/Sphere.h" -#include "eckit/grid/Point.h" -#include "eckit/grid/util.h" +#include "eckit/geometry/util.h" #include "eckit/types/FloatCompare.h" -namespace eckit::grid { +namespace eckit::geometry { Domain::Domain(double north, double west, double south, double east) : @@ -99,4 +99,4 @@ double Domain::area(double radius) const { } -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Domain.h b/src/eckit/geometry/Domain.h similarity index 97% rename from src/eckit/grid/Domain.h rename to src/eckit/geometry/Domain.h index ee5c82187..38e0e4222 100644 --- a/src/eckit/grid/Domain.h +++ b/src/eckit/geometry/Domain.h @@ -15,7 +15,7 @@ #include -namespace eckit::grid { +namespace eckit::geometry { class Domain { @@ -116,4 +116,4 @@ class Domain { }; -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Earth.h b/src/eckit/geometry/Earth.h similarity index 92% rename from src/eckit/grid/Earth.h rename to src/eckit/geometry/Earth.h index bb51f21b2..e83d70188 100644 --- a/src/eckit/grid/Earth.h +++ b/src/eckit/geometry/Earth.h @@ -15,7 +15,7 @@ #include "eckit/geometry/SphereT.h" -namespace eckit::grid { +namespace eckit::geometry { struct DatumIFS { @@ -36,4 +36,4 @@ struct DatumWGS84SemiMajorAxis { using Earth = eckit::geometry::SphereT; -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Figure.cc b/src/eckit/geometry/Figure.cc similarity index 85% rename from src/eckit/grid/Figure.cc rename to src/eckit/geometry/Figure.cc index 6eafe5abb..2ac866af3 100644 --- a/src/eckit/grid/Figure.cc +++ b/src/eckit/geometry/Figure.cc @@ -10,12 +10,12 @@ */ -#include "eckit/grid/Figure.h" +#include "eckit/geometry/Figure.h" #include "eckit/config/Configuration.h" -namespace eckit::grid { +namespace eckit::geometry { Figure::Figure(const Configuration& config) /*: @@ -24,4 +24,4 @@ Figure::Figure(const Configuration& config) /*: } -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Figure.h b/src/eckit/geometry/Figure.h similarity index 95% rename from src/eckit/grid/Figure.h rename to src/eckit/geometry/Figure.h index f733f26cf..d3facb07c 100644 --- a/src/eckit/grid/Figure.h +++ b/src/eckit/geometry/Figure.h @@ -20,7 +20,7 @@ class Configuration; } -namespace eckit::grid { +namespace eckit::geometry { class Figure { @@ -94,4 +94,4 @@ class Figure { }; -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Grid.cc b/src/eckit/geometry/Grid.cc similarity index 91% rename from src/eckit/grid/Grid.cc rename to src/eckit/geometry/Grid.cc index 252702fda..8ccda8cca 100644 --- a/src/eckit/grid/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -10,22 +10,22 @@ */ -#include "eckit/grid/Grid.h" +#include "eckit/geometry/Grid.h" #include #include #include #include "eckit/exception/Exceptions.h" -#include "eckit/grid/Domain.h" -#include "eckit/grid/Iterator.h" -#include "eckit/grid/detail/UnstructuredGrid.h" +#include "eckit/geometry/Domain.h" +#include "eckit/geometry/Iterator.h" +#include "eckit/geometry/detail/UnstructuredGrid.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" -namespace eckit::grid { +namespace eckit::geometry { Grid::Grid(const Configuration& config) : @@ -111,4 +111,4 @@ void GridFactory::list(std::ostream& out) { } -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Grid.h b/src/eckit/geometry/Grid.h similarity index 92% rename from src/eckit/grid/Grid.h rename to src/eckit/geometry/Grid.h index 0cd7b83be..6dcb56661 100644 --- a/src/eckit/grid/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -18,18 +18,18 @@ #include #include "eckit/config/Configuration.h" -#include "eckit/grid/BoundingBox.h" -#include "eckit/grid/Point.h" -#include "eckit/grid/Renumber.h" +#include "eckit/geometry/BoundingBox.h" +#include "eckit/geometry/Point.h" +#include "eckit/geometry/Renumber.h" -namespace eckit::grid { +namespace eckit::geometry { class Domain; class Iterator; -} // namespace eckit::grid +} // namespace eckit::geometry -namespace eckit::grid { +namespace eckit::geometry { class Grid { @@ -149,4 +149,4 @@ class GridBuilder : public GridFactory { }; -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Increments.cc b/src/eckit/geometry/Increments.cc similarity index 85% rename from src/eckit/grid/Increments.cc rename to src/eckit/geometry/Increments.cc index fe7b66d89..ab95f6edc 100644 --- a/src/eckit/grid/Increments.cc +++ b/src/eckit/geometry/Increments.cc @@ -10,12 +10,12 @@ */ -#include "eckit/grid/Increments.h" +#include "eckit/geometry/Increments.h" #include "eckit/config/Configuration.h" -namespace eckit::grid { +namespace eckit::geometry { Increments::Increments(const Configuration& config) : @@ -23,4 +23,4 @@ Increments::Increments(const Configuration& config) : } -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Increments.h b/src/eckit/geometry/Increments.h similarity index 94% rename from src/eckit/grid/Increments.h rename to src/eckit/geometry/Increments.h index 7cd0cc293..55dda166c 100644 --- a/src/eckit/grid/Increments.h +++ b/src/eckit/geometry/Increments.h @@ -21,7 +21,7 @@ class Configuration; } -namespace eckit::grid { +namespace eckit::geometry { class Increments : protected std::array { @@ -51,4 +51,4 @@ class Increments : protected std::array { }; -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Iterator.cc b/src/eckit/geometry/Iterator.cc similarity index 94% rename from src/eckit/grid/Iterator.cc rename to src/eckit/geometry/Iterator.cc index 2f5458618..fc79cd52f 100644 --- a/src/eckit/grid/Iterator.cc +++ b/src/eckit/geometry/Iterator.cc @@ -10,19 +10,19 @@ */ -#include "eckit/grid/Iterator.h" +#include "eckit/geometry/Iterator.h" #include #include #include "eckit/exception/Exceptions.h" -#include "eckit/grid/Projection.h" +#include "eckit/geometry/Projection.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" -namespace eckit::grid { +namespace eckit::geometry { static pthread_once_t __once = PTHREAD_ONCE_INIT; @@ -96,4 +96,4 @@ IteratorFactory::~IteratorFactory() { } -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Iterator.h b/src/eckit/geometry/Iterator.h similarity index 97% rename from src/eckit/grid/Iterator.h rename to src/eckit/geometry/Iterator.h index 738ca6073..d83c7e2b0 100644 --- a/src/eckit/grid/Iterator.h +++ b/src/eckit/geometry/Iterator.h @@ -16,18 +16,18 @@ #include #include -#include "eckit/grid/Point.h" +#include "eckit/geometry/Point.h" namespace eckit { class Configuration; -namespace grid { +namespace geometry { class Projection; } } // namespace eckit -namespace eckit::grid { +namespace eckit::geometry { class Iterator { @@ -187,4 +187,4 @@ class IteratorBuilder final : public IteratorFactory { }; -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Point.cc b/src/eckit/geometry/Point.cc similarity index 80% rename from src/eckit/grid/Point.cc rename to src/eckit/geometry/Point.cc index 19e033001..5acde5a34 100644 --- a/src/eckit/grid/Point.cc +++ b/src/eckit/geometry/Point.cc @@ -10,14 +10,14 @@ */ -#include "eckit/grid/Point.h" +#include "eckit/geometry/Point.h" #include #include "eckit/exception/Exceptions.h" -namespace eckit::grid { +namespace eckit::geometry { bool points_equal(const Point& p, const Point& q) { @@ -26,10 +26,10 @@ bool points_equal(const Point& p, const Point& q) { } -} // namespace eckit::grid +} // namespace eckit::geometry -std::ostream& operator<<(std::ostream& out, const eckit::grid::Point& p) { +std::ostream& operator<<(std::ostream& out, const eckit::geometry::Point& p) { std::visit([&](const auto& p) { out << p; }, p); return out; } diff --git a/src/eckit/grid/Point.h b/src/eckit/geometry/Point.h similarity index 88% rename from src/eckit/grid/Point.h rename to src/eckit/geometry/Point.h index 64b85f1ec..b79ba971e 100644 --- a/src/eckit/grid/Point.h +++ b/src/eckit/geometry/Point.h @@ -20,7 +20,7 @@ #include "eckit/geometry/PointLonLat.h" -namespace eckit::grid { +namespace eckit::geometry { using geometry::Point2; @@ -43,7 +43,7 @@ using Longitude = double; using Latitude = double; -} // namespace eckit::grid +} // namespace eckit::geometry -std::ostream& operator<<(std::ostream&, const eckit::grid::Point&); +std::ostream& operator<<(std::ostream&, const eckit::geometry::Point&); diff --git a/src/eckit/grid/Projection.cc b/src/eckit/geometry/Projection.cc similarity index 98% rename from src/eckit/grid/Projection.cc rename to src/eckit/geometry/Projection.cc index 0d70db3f3..62b776d5e 100644 --- a/src/eckit/grid/Projection.cc +++ b/src/eckit/geometry/Projection.cc @@ -10,7 +10,7 @@ */ -#include "eckit/grid/Projection.h" +#include "eckit/geometry/Projection.h" #include #include @@ -21,7 +21,7 @@ #include "eckit/thread/Mutex.h" -namespace eckit::grid { +namespace eckit::geometry { #if 0 @@ -280,4 +280,4 @@ ProjectionFactory::~ProjectionFactory() { } -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Projection.h b/src/eckit/geometry/Projection.h similarity index 96% rename from src/eckit/grid/Projection.h rename to src/eckit/geometry/Projection.h index b4b97e217..4609717d5 100644 --- a/src/eckit/grid/Projection.h +++ b/src/eckit/geometry/Projection.h @@ -15,7 +15,7 @@ #include #include -#include "eckit/grid/Point.h" +#include "eckit/geometry/Point.h" namespace eckit { @@ -23,7 +23,7 @@ class Configuration; } -namespace eckit::grid { +namespace eckit::geometry { class Projection { @@ -136,4 +136,4 @@ class ProjectionBuilder final : public ProjectionFactory { }; -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Range.cc b/src/eckit/geometry/Range.cc similarity index 95% rename from src/eckit/grid/Range.cc rename to src/eckit/geometry/Range.cc index 1897e3944..54e1479e9 100644 --- a/src/eckit/grid/Range.cc +++ b/src/eckit/geometry/Range.cc @@ -10,18 +10,18 @@ */ -#include "eckit/grid/Range.h" +#include "eckit/geometry/Range.h" #include "eckit/exception/Exceptions.h" #include "eckit/types/FloatCompare.h" -namespace eckit::grid::util { +namespace eckit::geometry::util { std::vector arange(double start, double stop, double step); } -namespace eckit::grid { +namespace eckit::geometry { static Fraction adjust(const Fraction& target, const Fraction& inc, bool up) { @@ -104,4 +104,4 @@ std::vector Range::to_vector() const { } -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Range.h b/src/eckit/geometry/Range.h similarity index 96% rename from src/eckit/grid/Range.h rename to src/eckit/geometry/Range.h index 5be793add..ee4e3cf22 100644 --- a/src/eckit/grid/Range.h +++ b/src/eckit/geometry/Range.h @@ -17,7 +17,7 @@ #include "eckit/types/Fraction.h" -namespace eckit::grid { +namespace eckit::geometry { class Range { @@ -106,4 +106,4 @@ class Range { }; -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Renumber.h b/src/eckit/geometry/Renumber.h similarity index 88% rename from src/eckit/grid/Renumber.h rename to src/eckit/geometry/Renumber.h index cd60ec7c7..7ffec908f 100644 --- a/src/eckit/grid/Renumber.h +++ b/src/eckit/geometry/Renumber.h @@ -15,10 +15,10 @@ #include -namespace eckit::grid { +namespace eckit::geometry { using Renumber = std::vector; -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Scanner.cc b/src/eckit/geometry/Scanner.cc similarity index 94% rename from src/eckit/grid/Scanner.cc rename to src/eckit/geometry/Scanner.cc index 066248009..5607d73eb 100644 --- a/src/eckit/grid/Scanner.cc +++ b/src/eckit/geometry/Scanner.cc @@ -10,10 +10,10 @@ */ -#include "eckit/grid/Scanner.h" +#include "eckit/geometry/Scanner.h" -namespace eckit::grid { +namespace eckit::geometry { #if 0 @@ -51,4 +51,4 @@ Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) #endif -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Scanner.h b/src/eckit/geometry/Scanner.h similarity index 96% rename from src/eckit/grid/Scanner.h rename to src/eckit/geometry/Scanner.h index 60dd483a8..a5dd08b75 100644 --- a/src/eckit/grid/Scanner.h +++ b/src/eckit/geometry/Scanner.h @@ -15,7 +15,7 @@ #include -namespace eckit::grid { +namespace eckit::geometry { class Scanner { @@ -99,4 +99,4 @@ class Scanner { }; -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/Search.h b/src/eckit/geometry/Search.h similarity index 97% rename from src/eckit/grid/Search.h rename to src/eckit/geometry/Search.h index 7bf8f1cab..e31a8d27e 100644 --- a/src/eckit/grid/Search.h +++ b/src/eckit/geometry/Search.h @@ -20,7 +20,7 @@ #include "eckit/geometry/UnitSphere.h" -namespace eckit::grid { +namespace eckit::geometry { namespace search { @@ -77,4 +77,4 @@ struct SearchLonLat : Search3 { }; -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/detail/Gaussian.cc b/src/eckit/geometry/detail/Gaussian.cc similarity index 94% rename from src/eckit/grid/detail/Gaussian.cc rename to src/eckit/geometry/detail/Gaussian.cc index 24c74df22..2e5cd5970 100644 --- a/src/eckit/grid/detail/Gaussian.cc +++ b/src/eckit/geometry/detail/Gaussian.cc @@ -10,18 +10,18 @@ */ -#include "eckit/grid/detail/Gaussian.h" +#include "eckit/geometry/detail/Gaussian.h" #include #include #include -#include "eckit/grid/Domain.h" -#include "eckit/grid/util.h" +#include "eckit/geometry/Domain.h" +#include "eckit/geometry/util.h" #include "eckit/types/FloatCompare.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { Gaussian::Gaussian(size_t N, const BoundingBox& bbox) : @@ -117,4 +117,4 @@ void Gaussian::correctSouthNorth(double& s, double& n, bool in) const { } -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/Gaussian.h b/src/eckit/geometry/detail/Gaussian.h similarity index 93% rename from src/eckit/grid/detail/Gaussian.h rename to src/eckit/geometry/detail/Gaussian.h index bb27add5d..c5a6f4757 100644 --- a/src/eckit/grid/detail/Gaussian.h +++ b/src/eckit/geometry/detail/Gaussian.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/grid/Grid.h" +#include "eckit/geometry/Grid.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { class Gaussian : public Grid { @@ -98,4 +98,4 @@ class Gaussian : public Grid { }; -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/GaussianIterator.cc b/src/eckit/geometry/detail/GaussianIterator.cc similarity index 95% rename from src/eckit/grid/detail/GaussianIterator.cc rename to src/eckit/geometry/detail/GaussianIterator.cc index 59a34915b..9f05dbb17 100644 --- a/src/eckit/grid/detail/GaussianIterator.cc +++ b/src/eckit/geometry/detail/GaussianIterator.cc @@ -10,14 +10,14 @@ */ -#include "eckit/grid/detail/GaussianIterator.h" +#include "eckit/geometry/detail/GaussianIterator.h" #include #include "eckit/exception/Exceptions.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { GaussianIterator::GaussianIterator(const std::vector& latitudes, std::vector&& pl, @@ -115,4 +115,4 @@ size_t GaussianIterator::size() const { } -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/GaussianIterator.h b/src/eckit/geometry/detail/GaussianIterator.h similarity index 86% rename from src/eckit/grid/detail/GaussianIterator.h rename to src/eckit/geometry/detail/GaussianIterator.h index dc05d0a12..23c393568 100644 --- a/src/eckit/grid/detail/GaussianIterator.h +++ b/src/eckit/geometry/detail/GaussianIterator.h @@ -16,12 +16,12 @@ #include "eckit/types/Fraction.h" -#include "eckit/grid/BoundingBox.h" -#include "eckit/grid/Iterator.h" -#include "eckit/grid/Projection.h" +#include "eckit/geometry/BoundingBox.h" +#include "eckit/geometry/Iterator.h" +#include "eckit/geometry/Projection.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { class GaussianIterator : public Iterator { @@ -55,4 +55,4 @@ class GaussianIterator : public Iterator { }; -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/IrregularLatlon.cc b/src/eckit/geometry/detail/IrregularLatlon.cc similarity index 95% rename from src/eckit/grid/detail/IrregularLatlon.cc rename to src/eckit/geometry/detail/IrregularLatlon.cc index 9ac450d58..2572490a6 100644 --- a/src/eckit/grid/detail/IrregularLatlon.cc +++ b/src/eckit/geometry/detail/IrregularLatlon.cc @@ -10,18 +10,18 @@ */ -#include "eckit/grid/detail/IrregularLatlon.h" +#include "eckit/geometry/detail/IrregularLatlon.h" #include #include #include "eckit/utils/MD5.h" -#include "eckit/grid/Iterator.h" -#include "eckit/grid/Projection.h" +#include "eckit/geometry/Iterator.h" +#include "eckit/geometry/Projection.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { static void range(const std::vector& v, double& mn, double& mx, double& dmax) { @@ -163,4 +163,4 @@ Renumber IrregularLatlon::reorder(long scanningMode) const { static const GridBuilder irregularLatlon("irregular_latlon"); -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/IrregularLatlon.h b/src/eckit/geometry/detail/IrregularLatlon.h similarity index 93% rename from src/eckit/grid/detail/IrregularLatlon.h rename to src/eckit/geometry/detail/IrregularLatlon.h index 980845a81..36e7d036e 100644 --- a/src/eckit/grid/detail/IrregularLatlon.h +++ b/src/eckit/geometry/detail/IrregularLatlon.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/grid/Grid.h" +#include "eckit/geometry/Grid.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { class IrregularLatlon final : public Grid { @@ -87,4 +87,4 @@ class IrregularLatlon final : public Grid { }; -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/ReducedGG.cc b/src/eckit/geometry/detail/ReducedGG.cc similarity index 96% rename from src/eckit/grid/detail/ReducedGG.cc rename to src/eckit/geometry/detail/ReducedGG.cc index 8d248f4f3..c1bca5bec 100644 --- a/src/eckit/grid/detail/ReducedGG.cc +++ b/src/eckit/geometry/detail/ReducedGG.cc @@ -10,7 +10,7 @@ */ -#include "eckit/grid/detail/ReducedGG.h" +#include "eckit/geometry/detail/ReducedGG.h" #include #include @@ -21,13 +21,13 @@ #include #include -#include "eckit/grid/Iterator.h" -#include "eckit/grid/Projection.h" -#include "eckit/grid/detail/GaussianIterator.h" +#include "eckit/geometry/Iterator.h" +#include "eckit/geometry/Projection.h" +#include "eckit/geometry/detail/GaussianIterator.h" #include "eckit/types/Fraction.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { ReducedGG::ReducedGG(const Configuration& config) : @@ -276,4 +276,4 @@ struct ReducedGGOctahedral : ReducedGG { static const GridBuilder reducedFromPL("reduced_gg"); -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/ReducedGG.h b/src/eckit/geometry/detail/ReducedGG.h similarity index 93% rename from src/eckit/grid/detail/ReducedGG.h rename to src/eckit/geometry/detail/ReducedGG.h index b5e25dc6c..1fcc2916f 100644 --- a/src/eckit/grid/detail/ReducedGG.h +++ b/src/eckit/geometry/detail/ReducedGG.h @@ -12,8 +12,8 @@ #pragma once -#include "eckit/grid/detail/Gaussian.h" -#include "eckit/grid/util.h" +#include "eckit/geometry/detail/Gaussian.h" +#include "eckit/geometry/util.h" namespace eckit { @@ -21,7 +21,7 @@ class Fraction; } -namespace eckit::grid::grid { +namespace eckit::geometry::detail { class ReducedGG : public Gaussian { @@ -118,4 +118,4 @@ class ReducedGG : public Gaussian { }; -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/ReducedLL.cc b/src/eckit/geometry/detail/ReducedLL.cc similarity index 94% rename from src/eckit/grid/detail/ReducedLL.cc rename to src/eckit/geometry/detail/ReducedLL.cc index 314004649..0daea87ec 100644 --- a/src/eckit/grid/detail/ReducedLL.cc +++ b/src/eckit/geometry/detail/ReducedLL.cc @@ -10,21 +10,21 @@ */ -#include "eckit/grid/detail/ReducedLL.h" +#include "eckit/geometry/detail/ReducedLL.h" #include #include #include #include -#include "eckit/grid/Domain.h" -#include "eckit/grid/Iterator.h" -#include "eckit/grid/Projection.h" +#include "eckit/geometry/Domain.h" +#include "eckit/geometry/Iterator.h" +#include "eckit/geometry/Projection.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { static bool checkPl(const std::vector& pl) { ASSERT(!pl.empty()); @@ -185,4 +185,4 @@ Renumber ReducedLL::reorder(long scanningMode) const { static const GridBuilder reducedLL("reduced_ll"); -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/ReducedLL.h b/src/eckit/geometry/detail/ReducedLL.h similarity index 92% rename from src/eckit/grid/detail/ReducedLL.h rename to src/eckit/geometry/detail/ReducedLL.h index fe16a13f0..fefe76ba3 100644 --- a/src/eckit/grid/detail/ReducedLL.h +++ b/src/eckit/geometry/detail/ReducedLL.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/grid/Grid.h" +#include "eckit/geometry/Grid.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { class ReducedLL : public Grid { @@ -83,4 +83,4 @@ class ReducedLL : public Grid { }; -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/RegularGG.cc b/src/eckit/geometry/detail/RegularGG.cc similarity index 94% rename from src/eckit/grid/detail/RegularGG.cc rename to src/eckit/geometry/detail/RegularGG.cc index 5b72b61cb..40e8e1f00 100644 --- a/src/eckit/grid/detail/RegularGG.cc +++ b/src/eckit/geometry/detail/RegularGG.cc @@ -10,19 +10,19 @@ */ -#include "eckit/grid/detail/RegularGG.h" +#include "eckit/geometry/detail/RegularGG.h" #include #include #include -#include "eckit/grid/detail/GaussianIterator.h" -#include "eckit/grid/detail/RegularGG.h" +#include "eckit/geometry/detail/GaussianIterator.h" +#include "eckit/geometry/detail/RegularGG.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { RegularGG::RegularGG(const Configuration& config) : @@ -188,4 +188,4 @@ Renumber RegularGG::reorder(long /*scanningMode*/) const { static const GridBuilder reducedGG("regular_gg"); -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/RegularGG.h b/src/eckit/geometry/detail/RegularGG.h similarity index 92% rename from src/eckit/grid/detail/RegularGG.h rename to src/eckit/geometry/detail/RegularGG.h index e78a1cd89..80946c3c7 100644 --- a/src/eckit/grid/detail/RegularGG.h +++ b/src/eckit/geometry/detail/RegularGG.h @@ -12,7 +12,7 @@ #pragma once -#include "eckit/grid/detail/Gaussian.h" +#include "eckit/geometry/detail/Gaussian.h" namespace eckit { @@ -20,7 +20,7 @@ class Fraction; } -namespace eckit::grid::grid { +namespace eckit::geometry::detail { class RegularGG final : public Gaussian { @@ -88,4 +88,4 @@ class RegularGG final : public Gaussian { }; -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/RegularGrid.cc b/src/eckit/geometry/detail/RegularGrid.cc similarity index 97% rename from src/eckit/grid/detail/RegularGrid.cc rename to src/eckit/geometry/detail/RegularGrid.cc index c8322d83f..5ccd07deb 100644 --- a/src/eckit/grid/detail/RegularGrid.cc +++ b/src/eckit/geometry/detail/RegularGrid.cc @@ -10,7 +10,7 @@ */ -#include "eckit/grid/detail/RegularGrid.h" +#include "eckit/geometry/detail/RegularGrid.h" #include #include @@ -20,12 +20,12 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/config/Resource.h" -#include "eckit/grid/Earth.h" -#include "eckit/grid/Iterator.h" +#include "eckit/geometry/Earth.h" +#include "eckit/geometry/Iterator.h" #include "eckit/utils/StringTools.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { RegularGrid::RegularGrid(Projection* projection, const Configuration& config) : @@ -268,4 +268,4 @@ static const GridBuilder __builder3("mercator"); static const GridBuilder __builder4("polar_stereographic"); -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/RegularGrid.h b/src/eckit/geometry/detail/RegularGrid.h similarity index 91% rename from src/eckit/grid/detail/RegularGrid.h rename to src/eckit/geometry/detail/RegularGrid.h index 51725e5d8..df8f5a434 100644 --- a/src/eckit/grid/detail/RegularGrid.h +++ b/src/eckit/geometry/detail/RegularGrid.h @@ -15,12 +15,12 @@ #include #include -#include "eckit/grid/Figure.h" -#include "eckit/grid/Grid.h" -#include "eckit/grid/Projection.h" +#include "eckit/geometry/Figure.h" +#include "eckit/geometry/Grid.h" +#include "eckit/geometry/Projection.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { class RegularGrid : public Grid { @@ -105,4 +105,4 @@ class RegularGrid : public Grid { }; -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/RegularLL.cc b/src/eckit/geometry/detail/RegularLL.cc similarity index 96% rename from src/eckit/grid/detail/RegularLL.cc rename to src/eckit/geometry/detail/RegularLL.cc index 64f804990..dd3a5953a 100644 --- a/src/eckit/grid/detail/RegularLL.cc +++ b/src/eckit/geometry/detail/RegularLL.cc @@ -10,22 +10,22 @@ */ -#include "eckit/grid/detail/RegularLL.h" +#include "eckit/geometry/detail/RegularLL.h" #include #include #include #include "eckit/exception/Exceptions.h" -#include "eckit/grid/Iterator.h" -#include "eckit/grid/Point.h" -#include "eckit/grid/Projection.h" -#include "eckit/grid/detail/RegularLL.h" +#include "eckit/geometry/Iterator.h" +#include "eckit/geometry/Point.h" +#include "eckit/geometry/Projection.h" +#include "eckit/geometry/detail/RegularLL.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { namespace detail { @@ -303,4 +303,4 @@ Iterator* RegularLL::iterator() const { static const GridBuilder regularLL("regular_ll"); -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/RegularLL.h b/src/eckit/geometry/detail/RegularLL.h similarity index 92% rename from src/eckit/grid/detail/RegularLL.h rename to src/eckit/geometry/detail/RegularLL.h index 99c7088df..eb1e4dfe1 100644 --- a/src/eckit/grid/detail/RegularLL.h +++ b/src/eckit/geometry/detail/RegularLL.h @@ -12,12 +12,12 @@ #pragma once -#include "eckit/grid/Grid.h" -#include "eckit/grid/Increments.h" +#include "eckit/geometry/Grid.h" +#include "eckit/geometry/Increments.h" #include "eckit/types/Fraction.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { class RegularLL : public Grid { @@ -87,4 +87,4 @@ class RegularLL : public Grid { }; -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/UnstructuredGrid.cc b/src/eckit/geometry/detail/UnstructuredGrid.cc similarity index 95% rename from src/eckit/grid/detail/UnstructuredGrid.cc rename to src/eckit/geometry/detail/UnstructuredGrid.cc index 572f14b59..62903bc60 100644 --- a/src/eckit/grid/detail/UnstructuredGrid.cc +++ b/src/eckit/geometry/detail/UnstructuredGrid.cc @@ -10,7 +10,7 @@ */ -#include "eckit/grid/detail/UnstructuredGrid.h" +#include "eckit/geometry/detail/UnstructuredGrid.h" #include #include @@ -22,14 +22,14 @@ #include "eckit/config/Resource.h" #include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" -#include "eckit/grid/Domain.h" -#include "eckit/grid/Iterator.h" -#include "eckit/grid/Projection.h" +#include "eckit/geometry/Domain.h" +#include "eckit/geometry/Iterator.h" +#include "eckit/geometry/Projection.h" #include "eckit/serialisation/FileStream.h" #include "eckit/serialisation/IfstreamStream.h" -namespace eckit::grid::grid { +namespace eckit::geometry::detail { namespace detail { @@ -230,4 +230,4 @@ static const GridBuilder triangular_grid("triangular_grid"); static const GridBuilder unstructured_grid("unstructured_grid"); -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/detail/UnstructuredGrid.h b/src/eckit/geometry/detail/UnstructuredGrid.h similarity index 95% rename from src/eckit/grid/detail/UnstructuredGrid.h rename to src/eckit/geometry/detail/UnstructuredGrid.h index f8124ce81..5dea08809 100644 --- a/src/eckit/grid/detail/UnstructuredGrid.h +++ b/src/eckit/geometry/detail/UnstructuredGrid.h @@ -14,7 +14,7 @@ #include -#include "eckit/grid/Grid.h" +#include "eckit/geometry/Grid.h" namespace eckit { @@ -22,7 +22,7 @@ class PathName; } -namespace eckit::grid::grid { +namespace eckit::geometry::detail { class UnstructuredGrid : public Grid { @@ -117,4 +117,4 @@ class UnstructuredGrid : public Grid { }; -} // namespace eckit::grid::grid +} // namespace eckit::geometry::detail diff --git a/src/eckit/grid/projection/LonLatToXYZ.cc b/src/eckit/geometry/projection/LonLatToXYZ.cc similarity index 93% rename from src/eckit/grid/projection/LonLatToXYZ.cc rename to src/eckit/geometry/projection/LonLatToXYZ.cc index 24ca04747..cfa89adce 100644 --- a/src/eckit/grid/projection/LonLatToXYZ.cc +++ b/src/eckit/geometry/projection/LonLatToXYZ.cc @@ -10,7 +10,7 @@ */ -#include "eckit/grid/projection/LonLatToXYZ.h" +#include "eckit/geometry/projection/LonLatToXYZ.h" #include "eckit/config/Configuration.h" #include "eckit/geometry/EllipsoidOfRevolution.h" @@ -18,7 +18,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::grid::projection { +namespace eckit::geometry::projection { static ProjectionBuilder __projection("ll_to_xyz"); @@ -69,4 +69,4 @@ LonLatToXYZ::LonLatToXYZ(const Configuration& config) : config.getDouble("b", config.getDouble("R", 1.))) {} -} // namespace eckit::grid::projection +} // namespace eckit::geometry::projection diff --git a/src/eckit/grid/projection/LonLatToXYZ.h b/src/eckit/geometry/projection/LonLatToXYZ.h similarity index 94% rename from src/eckit/grid/projection/LonLatToXYZ.h rename to src/eckit/geometry/projection/LonLatToXYZ.h index fbe7c11d0..4c8c49cf8 100644 --- a/src/eckit/grid/projection/LonLatToXYZ.h +++ b/src/eckit/geometry/projection/LonLatToXYZ.h @@ -14,10 +14,10 @@ #include -#include "eckit/grid/Projection.h" +#include "eckit/geometry/Projection.h" -namespace eckit::grid::projection { +namespace eckit::geometry::projection { /// Calculate coordinates of a point on a sphere or spheroid, in [x, y, z] @@ -94,4 +94,4 @@ class LonLatToXYZ final : public Projection { }; -} // namespace eckit::grid::projection +} // namespace eckit::geometry::projection diff --git a/src/eckit/grid/projection/None.cc b/src/eckit/geometry/projection/None.cc similarity index 80% rename from src/eckit/grid/projection/None.cc rename to src/eckit/geometry/projection/None.cc index b907d5542..a2fa61874 100644 --- a/src/eckit/grid/projection/None.cc +++ b/src/eckit/geometry/projection/None.cc @@ -10,10 +10,10 @@ */ -#include "eckit/grid/projection/None.h" +#include "eckit/geometry/projection/None.h" -namespace eckit::grid::projection { +namespace eckit::geometry::projection { static ProjectionBuilder __projection1(""); @@ -23,4 +23,4 @@ static ProjectionBuilder __projection2("none"); None::None(const Configuration&) {} -} // namespace eckit::grid::projection +} // namespace eckit::geometry::projection diff --git a/src/eckit/grid/projection/None.h b/src/eckit/geometry/projection/None.h similarity index 90% rename from src/eckit/grid/projection/None.h rename to src/eckit/geometry/projection/None.h index 1b1433e3a..f6c332e09 100644 --- a/src/eckit/grid/projection/None.h +++ b/src/eckit/geometry/projection/None.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/grid/Projection.h" +#include "eckit/geometry/Projection.h" -namespace eckit::grid::projection { +namespace eckit::geometry::projection { class None final : public Projection { @@ -75,4 +75,4 @@ class None final : public Projection { }; -} // namespace eckit::grid::projection +} // namespace eckit::geometry::projection diff --git a/src/eckit/grid/projection/PROJ.cc b/src/eckit/geometry/projection/PROJ.cc similarity index 96% rename from src/eckit/grid/projection/PROJ.cc rename to src/eckit/geometry/projection/PROJ.cc index 6e95ed434..880472d6f 100644 --- a/src/eckit/grid/projection/PROJ.cc +++ b/src/eckit/geometry/projection/PROJ.cc @@ -10,13 +10,13 @@ */ -#include "eckit/grid/projection/PROJ.h" +#include "eckit/geometry/projection/PROJ.h" #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" -namespace eckit::grid::projection { +namespace eckit::geometry::projection { static ProjectionBuilder __projection("proj"); @@ -123,4 +123,4 @@ Point PROJ::inv(const Point& q) const { } -} // namespace eckit::grid::projection +} // namespace eckit::geometry::projection diff --git a/src/eckit/grid/projection/PROJ.h b/src/eckit/geometry/projection/PROJ.h similarity index 95% rename from src/eckit/grid/projection/PROJ.h rename to src/eckit/geometry/projection/PROJ.h index 399f6b0a6..5b5f0ae7b 100644 --- a/src/eckit/grid/projection/PROJ.h +++ b/src/eckit/geometry/projection/PROJ.h @@ -16,10 +16,10 @@ #include -#include "eckit/grid/Projection.h" +#include "eckit/geometry/Projection.h" -namespace eckit::grid::projection { +namespace eckit::geometry::projection { /// Calculate coordinates using PROJ @@ -118,4 +118,4 @@ class PROJ final : public Projection { }; -} // namespace eckit::grid::projection +} // namespace eckit::geometry::projection diff --git a/src/eckit/grid/projection/Rotation.cc b/src/eckit/geometry/projection/Rotation.cc similarity index 96% rename from src/eckit/grid/projection/Rotation.cc rename to src/eckit/geometry/projection/Rotation.cc index c5f572df0..0d34df9b2 100644 --- a/src/eckit/grid/projection/Rotation.cc +++ b/src/eckit/geometry/projection/Rotation.cc @@ -10,19 +10,19 @@ */ -#include "eckit/grid/projection/Rotation.h" +#include "eckit/geometry/projection/Rotation.h" #include #include #include "eckit/config/Configuration.h" #include "eckit/geometry/UnitSphere.h" -#include "eckit/grid/util.h" +#include "eckit/geometry/util.h" #include "eckit/maths/Matrix3.h" #include "eckit/types/FloatCompare.h" -namespace eckit::grid::projection { +namespace eckit::geometry::projection { static ProjectionBuilder __projection("rotation"); @@ -102,4 +102,4 @@ Rotation::Rotation(const Configuration& config) : config.getDouble("angle", 0)) {} -} // namespace eckit::grid::projection +} // namespace eckit::geometry::projection diff --git a/src/eckit/grid/projection/Rotation.h b/src/eckit/geometry/projection/Rotation.h similarity index 94% rename from src/eckit/grid/projection/Rotation.h rename to src/eckit/geometry/projection/Rotation.h index 56e2c62c4..c61c5bda2 100644 --- a/src/eckit/grid/projection/Rotation.h +++ b/src/eckit/geometry/projection/Rotation.h @@ -14,10 +14,10 @@ #include -#include "eckit/grid/Projection.h" +#include "eckit/geometry/Projection.h" -namespace eckit::grid::projection { +namespace eckit::geometry::projection { /// Calculate coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle @@ -95,4 +95,4 @@ class Rotation final : public Projection { }; -} // namespace eckit::grid::projection +} // namespace eckit::geometry::projection diff --git a/src/eckit/grid/scanner/Reduced.cc b/src/eckit/geometry/scanner/Reduced.cc similarity index 95% rename from src/eckit/grid/scanner/Reduced.cc rename to src/eckit/geometry/scanner/Reduced.cc index a39e0ab42..8df15bf13 100644 --- a/src/eckit/grid/scanner/Reduced.cc +++ b/src/eckit/geometry/scanner/Reduced.cc @@ -10,14 +10,14 @@ */ -#include "eckit/grid/scanner/Reduced.h" +#include "eckit/geometry/scanner/Reduced.h" #include #include "eckit/exception/Exceptions.h" -namespace eckit::grid::scanner { +namespace eckit::geometry::scanner { Reduced::Reduced(const std::vector& latitudes, @@ -104,4 +104,4 @@ size_t Reduced::size() const { } -} // namespace eckit::grid::scanner +} // namespace eckit::geometry::scanner diff --git a/src/eckit/grid/scanner/Reduced.h b/src/eckit/geometry/scanner/Reduced.h similarity index 88% rename from src/eckit/grid/scanner/Reduced.h rename to src/eckit/geometry/scanner/Reduced.h index 14dfb939e..84923d3da 100644 --- a/src/eckit/grid/scanner/Reduced.h +++ b/src/eckit/geometry/scanner/Reduced.h @@ -12,14 +12,14 @@ #pragma once -#include "eckit/grid/BoundingBox.h" -#include "eckit/grid/Point.h" -#include "eckit/grid/Scanner.h" -#include "eckit/grid/util.h" +#include "eckit/geometry/BoundingBox.h" +#include "eckit/geometry/Point.h" +#include "eckit/geometry/Scanner.h" +#include "eckit/geometry/util.h" #include "eckit/types/Fraction.h" -namespace eckit::grid::scanner { +namespace eckit::geometry::scanner { class Reduced final : public Scanner { @@ -99,4 +99,4 @@ class Reduced final : public Scanner { }; -} // namespace eckit::grid::scanner +} // namespace eckit::geometry::scanner diff --git a/src/eckit/grid/scanner/Regular.cc b/src/eckit/geometry/scanner/Regular.cc similarity index 93% rename from src/eckit/grid/scanner/Regular.cc rename to src/eckit/geometry/scanner/Regular.cc index 610cb943d..061210ecd 100644 --- a/src/eckit/grid/scanner/Regular.cc +++ b/src/eckit/geometry/scanner/Regular.cc @@ -10,14 +10,14 @@ */ -#include "eckit/grid/scanner/Regular.h" +#include "eckit/geometry/scanner/Regular.h" #include #include "eckit/exception/Exceptions.h" -namespace eckit::grid::scanner { +namespace eckit::geometry::scanner { Regular::Regular(size_t ni, size_t nj, double north, double west, double we, double ns) : @@ -76,4 +76,4 @@ size_t Regular::size() const { } -} // namespace eckit::grid::scanner +} // namespace eckit::geometry::scanner diff --git a/src/eckit/grid/scanner/Regular.h b/src/eckit/geometry/scanner/Regular.h similarity index 90% rename from src/eckit/grid/scanner/Regular.h rename to src/eckit/geometry/scanner/Regular.h index 62feeea6c..f13273aa5 100644 --- a/src/eckit/grid/scanner/Regular.h +++ b/src/eckit/geometry/scanner/Regular.h @@ -12,12 +12,12 @@ #pragma once -#include "eckit/grid/Point.h" -#include "eckit/grid/Scanner.h" +#include "eckit/geometry/Point.h" +#include "eckit/geometry/Scanner.h" #include "eckit/types/Fraction.h" -namespace eckit::grid::scanner { +namespace eckit::geometry::scanner { class Regular final : public Scanner { @@ -94,4 +94,4 @@ class Regular final : public Scanner { }; -} // namespace eckit::grid::scanner +} // namespace eckit::geometry::scanner diff --git a/src/eckit/grid/scanner/Unstructured.cc b/src/eckit/geometry/scanner/Unstructured.cc similarity index 81% rename from src/eckit/grid/scanner/Unstructured.cc rename to src/eckit/geometry/scanner/Unstructured.cc index 8d1df6c01..5e7d261ae 100644 --- a/src/eckit/grid/scanner/Unstructured.cc +++ b/src/eckit/geometry/scanner/Unstructured.cc @@ -10,12 +10,12 @@ */ -#include "eckit/grid/scanner/Unstructured.h" +#include "eckit/geometry/scanner/Unstructured.h" // #include <> -namespace eckit::grid::scanner { +namespace eckit::geometry::scanner { Unstructured::Unstructured() = default; @@ -31,4 +31,4 @@ size_t Unstructured::size() const { } -} // namespace eckit::grid::scanner +} // namespace eckit::geometry::scanner diff --git a/src/eckit/grid/scanner/Unstructured.h b/src/eckit/geometry/scanner/Unstructured.h similarity index 90% rename from src/eckit/grid/scanner/Unstructured.h rename to src/eckit/geometry/scanner/Unstructured.h index 7c441c246..09d85a26a 100644 --- a/src/eckit/grid/scanner/Unstructured.h +++ b/src/eckit/geometry/scanner/Unstructured.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/grid/Scanner.h" +#include "eckit/geometry/Scanner.h" -namespace eckit::grid::scanner { +namespace eckit::geometry::scanner { class Unstructured final : public Scanner { @@ -74,4 +74,4 @@ class Unstructured final : public Scanner { }; -} // namespace eckit::grid::scanner +} // namespace eckit::geometry::scanner diff --git a/src/eckit/grid/util.cc b/src/eckit/geometry/util.cc similarity index 81% rename from src/eckit/grid/util.cc rename to src/eckit/geometry/util.cc index 5e2847c47..a34f97f52 100644 --- a/src/eckit/grid/util.cc +++ b/src/eckit/geometry/util.cc @@ -10,10 +10,10 @@ */ -#include "eckit/grid/util.h" +#include "eckit/geometry/util.h" -namespace eckit::grid::util { +namespace eckit::geometry::util { template <> @@ -22,4 +22,4 @@ pl_type pl_convert(const pl_type& pl) { } -} // namespace eckit::grid::util +} // namespace eckit::geometry::util diff --git a/src/eckit/grid/util.h b/src/eckit/geometry/util.h similarity index 96% rename from src/eckit/grid/util.h rename to src/eckit/geometry/util.h index 6f0bb0885..d8fffe2ae 100644 --- a/src/eckit/grid/util.h +++ b/src/eckit/geometry/util.h @@ -19,7 +19,7 @@ #include -namespace eckit::grid { +namespace eckit::geometry { using pl_type = std::vector; @@ -72,4 +72,4 @@ pl_type::value_type regular_pl(size_t N); } // namespace util -} // namespace eckit::grid +} // namespace eckit::geometry diff --git a/src/eckit/grid/util/arange.cc b/src/eckit/geometry/util/arange.cc similarity index 93% rename from src/eckit/grid/util/arange.cc rename to src/eckit/geometry/util/arange.cc index 5ae30e32f..820124ff5 100644 --- a/src/eckit/grid/util/arange.cc +++ b/src/eckit/geometry/util/arange.cc @@ -15,7 +15,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::grid::util { +namespace eckit::geometry::util { std::vector arange(double start, double stop, double step) { @@ -33,4 +33,4 @@ std::vector arange(double start, double stop, double step) { } -} // namespace eckit::grid::util +} // namespace eckit::geometry::util diff --git a/src/eckit/grid/util/gaussian_latitudes.cc b/src/eckit/geometry/util/gaussian_latitudes.cc similarity index 97% rename from src/eckit/grid/util/gaussian_latitudes.cc rename to src/eckit/geometry/util/gaussian_latitudes.cc index 436abca78..692238508 100644 --- a/src/eckit/grid/util/gaussian_latitudes.cc +++ b/src/eckit/geometry/util/gaussian_latitudes.cc @@ -18,7 +18,7 @@ #include "eckit/exception/Exceptions.h" -namespace eckit::grid::util { +namespace eckit::geometry::util { std::vector gaussian_latitudes(size_t N, bool increasing) { @@ -95,4 +95,4 @@ std::vector gaussian_latitudes(size_t N, bool increasing) { } -} // namespace eckit::grid::util +} // namespace eckit::geometry::util diff --git a/src/eckit/grid/util/linspace.cc b/src/eckit/geometry/util/linspace.cc similarity index 92% rename from src/eckit/grid/util/linspace.cc rename to src/eckit/geometry/util/linspace.cc index f1da13149..b4eb9c691 100644 --- a/src/eckit/grid/util/linspace.cc +++ b/src/eckit/geometry/util/linspace.cc @@ -14,7 +14,7 @@ #include -namespace eckit::grid::util { +namespace eckit::geometry::util { std::vector linspace(double start, double stop, size_t num, bool endpoint) { @@ -32,4 +32,4 @@ std::vector linspace(double start, double stop, size_t num, bool endpoin } -} // namespace eckit::grid::util +} // namespace eckit::geometry::util diff --git a/src/eckit/grid/util/monotonic_crop.cc b/src/eckit/geometry/util/monotonic_crop.cc similarity index 95% rename from src/eckit/grid/util/monotonic_crop.cc rename to src/eckit/geometry/util/monotonic_crop.cc index 88fbbce21..e5cfb4679 100644 --- a/src/eckit/grid/util/monotonic_crop.cc +++ b/src/eckit/geometry/util/monotonic_crop.cc @@ -18,7 +18,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::grid::util { +namespace eckit::geometry::util { std::pair::const_iterator, std::vector::const_iterator> monotonic_crop( @@ -48,4 +48,4 @@ std::pair::const_iterator, std::vector::const_iterat } -} // namespace eckit::grid::util +} // namespace eckit::geometry::util diff --git a/src/eckit/grid/util/reduced_classical_pl.cc b/src/eckit/geometry/util/reduced_classical_pl.cc similarity index 99% rename from src/eckit/grid/util/reduced_classical_pl.cc rename to src/eckit/geometry/util/reduced_classical_pl.cc index 23c1b050e..fe8df7c98 100644 --- a/src/eckit/grid/util/reduced_classical_pl.cc +++ b/src/eckit/geometry/util/reduced_classical_pl.cc @@ -14,10 +14,10 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/grid/util.h" +#include "eckit/geometry/util.h" -namespace eckit::grid::util { +namespace eckit::geometry::util { static const std::map __classical_pls{ @@ -1341,4 +1341,4 @@ const pl_type& reduced_classical_pl(size_t N) { } -} // namespace eckit::grid::util +} // namespace eckit::geometry::util diff --git a/src/eckit/grid/util/reduced_octahedral_pl.cc b/src/eckit/geometry/util/reduced_octahedral_pl.cc similarity index 89% rename from src/eckit/grid/util/reduced_octahedral_pl.cc rename to src/eckit/geometry/util/reduced_octahedral_pl.cc index 268fc18ed..0e6a3460d 100644 --- a/src/eckit/grid/util/reduced_octahedral_pl.cc +++ b/src/eckit/geometry/util/reduced_octahedral_pl.cc @@ -13,10 +13,10 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/grid/util.h" +#include "eckit/geometry/util.h" -namespace eckit::grid::util { +namespace eckit::geometry::util { const pl_type& reduced_octahedral_pl(size_t N) { @@ -40,4 +40,4 @@ const pl_type& reduced_octahedral_pl(size_t N) { } -} // namespace eckit::grid::util +} // namespace eckit::geometry::util diff --git a/src/eckit/grid/util/regular_pl.cc b/src/eckit/geometry/util/regular_pl.cc similarity index 84% rename from src/eckit/grid/util/regular_pl.cc rename to src/eckit/geometry/util/regular_pl.cc index 326501b6f..9e4254c08 100644 --- a/src/eckit/grid/util/regular_pl.cc +++ b/src/eckit/geometry/util/regular_pl.cc @@ -11,10 +11,10 @@ #include "eckit/exception/Exceptions.h" -#include "eckit/grid/util.h" +#include "eckit/geometry/util.h" -namespace eckit::grid::util { +namespace eckit::geometry::util { pl_type::value_type regular_pl(size_t N) { @@ -24,4 +24,4 @@ pl_type::value_type regular_pl(size_t N) { } -} // namespace eckit::grid::util +} // namespace eckit::geometry::util diff --git a/src/eckit/grid/CMakeLists.txt b/src/eckit/grid/CMakeLists.txt deleted file mode 100644 index 0fa92d764..000000000 --- a/src/eckit/grid/CMakeLists.txt +++ /dev/null @@ -1,92 +0,0 @@ -list(APPEND eckit_grid_srcs - BoundingBox.cc - BoundingBox.h - Domain.cc - Domain.h - Earth.h - Figure.cc - Figure.h - Grid.cc - Grid.h - Increments.cc - Increments.h - Iterator.cc - Iterator.h - Point.cc - Point.h - Projection.cc - Projection.h - Range.cc - Range.h - Renumber.h - Scanner.cc - Scanner.h - Search.h - detail/Gaussian.cc - detail/Gaussian.h - detail/GaussianIterator.cc - detail/GaussianIterator.h - detail/IrregularLatlon.cc - detail/IrregularLatlon.h - detail/ReducedGG.cc - detail/ReducedGG.h - detail/ReducedLL.cc - detail/ReducedLL.h - detail/RegularGG.cc - detail/RegularGG.h - detail/RegularGrid.cc - detail/RegularGrid.h - detail/RegularLL.cc - detail/RegularLL.h - detail/UnstructuredGrid.cc - detail/UnstructuredGrid.h - projection/LonLatToXYZ.cc - projection/LonLatToXYZ.h - projection/None.cc - projection/None.h - projection/Rotation.cc - projection/Rotation.h - scanner/Reduced.cc - scanner/Reduced.h - scanner/Regular.cc - scanner/Regular.h - scanner/Unstructured.cc - scanner/Unstructured.h - util.cc - util.h - util/arange.cc - util/gaussian_latitudes.cc - util/linspace.cc - util/monotonic_crop.cc - util/reduced_classical_pl.cc - util/reduced_octahedral_pl.cc - util/regular_pl.cc -) - -set(eckit_grid_include_dirs ) -set(eckit_grid_libs eckit_geometry eckit_maths) - -if(HAVE_PROJ) - list(APPEND eckit_grid_srcs projection/PROJ.cc projection/PROJ.h) - list(APPEND eckit_grid_libs PROJ::proj) - list(APPEND eckit_grid_include_dirs ${PROJ_INCLUDE_DIRS}) -endif() - -ecbuild_add_library( - TARGET eckit_grid - TYPE SHARED - INSTALL_HEADERS ALL - HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/grid - SOURCES ${eckit_grid_srcs} - PUBLIC_LIBS ${eckit_grid_libs} - PUBLIC_INCLUDES ${eckit_grid_include_dirs} -) - -ecbuild_add_library( - TARGET eckit_grid_grib - TYPE SHARED - CONDITION HAVE_ECCODES - SOURCES grib/GribConfiguration.cc grib/GribConfiguration.h - PUBLIC_LIBS eckit_grid eccodes -) - diff --git a/src/eckit/grid/grib/GribConfiguration.cc b/src/eckit/grid/grib/GribConfiguration.cc deleted file mode 100644 index 7b0645b89..000000000 --- a/src/eckit/grid/grib/GribConfiguration.cc +++ /dev/null @@ -1,224 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/grid/grib/GribConfiguration.h" - -#include "eckit/value/Value.h" - - -namespace eckit::grid::grib { - - -static Value __root_dummy; - - -GribConfiguration::GribConfiguration(codes_handle* h) : - Configuration(__root_dummy), codes_handle_(h, &codes_handle_delete) { - ASSERT(codes_handle_); -} - - -bool GribConfiguration::has(const std::string& name) const { - return 0 != codes_is_defined(codes_handle_.get(), name.c_str()); -} - - -bool GribConfiguration::get(const std::string& name, std::string& value) const { - if (cache_.get(name, value)) { - return true; - } - - char mesg[1024]; - if (auto length = sizeof(mesg); - CODES_SUCCESS == codes_get_string(codes_handle_.get(), name.c_str(), mesg, &length)) { - value = mesg; - cache_.set(name, value); - return true; - } - - return false; -} - - -bool GribConfiguration::get(const std::string& name, bool& value) const { - if (long another = 0; get(name, another)) { - value = another != 0; - return true; - } - - return false; -} - - -bool GribConfiguration::get(const std::string& name, int& value) const { - if (long another = 0; get(name, another)) { - value = static_cast(another); - return true; - } - - return false; -} - - -bool GribConfiguration::get(const std::string& name, long& value) const { - if (cache_.get(name, value)) { - return true; - } - - if (CODES_SUCCESS == codes_get_long(codes_handle_.get(), name.c_str(), &value)) { - cache_.set(name, value); - return true; - } - - return false; -} - - -bool GribConfiguration::get(const std::string& name, long long& value) const { - NOTIMP; -} - - -bool GribConfiguration::get(const std::string& name, std::size_t& value) const { - if (long another = 0; get(name, another) && 0 <= another) { - value = static_cast(another); - return true; - } - - return false; -} - - -bool GribConfiguration::get(const std::string& name, float& value) const { - if (double another = 0; get(name, another)) { - value = static_cast(another); - return true; - } - - return false; -} - - -bool GribConfiguration::get(const std::string& name, double& value) const { - if (cache_.get(name, value)) { - return true; - } - - if (CODES_SUCCESS == codes_get_double(codes_handle_.get(), name.c_str(), &value)) { - cache_.set(name, value); - return true; - } - - return false; -} - - -bool GribConfiguration::get(const std::string& name, std::vector& value) const { - if (std::vector another; get(name, another)) { - value.resize(another.size()); - std::transform(another.begin(), another.end(), value.begin(), [](long v) { - return static_cast(v); - }); - return true; - } - - return false; -} - - -bool GribConfiguration::get(const std::string& name, std::vector& value) const { - if (cache_.get(name, value)) { - return true; - } - - if (size_t size = 0; CODES_SUCCESS == codes_get_size(codes_handle_.get(), name.c_str(), &size)) { - std::vector another(size); - if (CODES_SUCCESS - == codes_get_long_array(codes_handle_.get(), name.c_str(), another.data(), &size)) { - value.swap(another); - cache_.set(name, value); - return true; - } - } - - return false; -} - - -bool GribConfiguration::get(const std::string& name, std::vector& value) const { - NOTIMP; -} - - -bool GribConfiguration::get(const std::string& name, std::vector& value) const { - if (std::vector another; get(name, another)) { - value.resize(another.size()); - std::transform(another.begin(), another.end(), value.begin(), [](long v) { - ASSERT(0 <= v); - return static_cast(v); - }); - return true; - } - - return false; -} - - -bool GribConfiguration::get(const std::string& name, std::vector& value) const { - if (cache_.get(name, value)) { - return true; - } - - if (size_t size = 0; CODES_SUCCESS == codes_get_size(codes_handle_.get(), name.c_str(), &size)) { - std::vector another(size); - if (CODES_SUCCESS - == codes_get_float_array(codes_handle_.get(), name.c_str(), another.data(), &size)) { - value.swap(another); - cache_.set(name, value); - return true; - } - } - - return false; -} - - -bool GribConfiguration::get(const std::string& name, std::vector& value) const { - if (cache_.get(name, value)) { - return true; - } - - if (size_t size = 0; CODES_SUCCESS == codes_get_size(codes_handle_.get(), name.c_str(), &size)) { - std::vector another(size); - if (CODES_SUCCESS - == codes_get_double_array(codes_handle_.get(), name.c_str(), another.data(), &size)) { - value.swap(another); - cache_.set(name, value); - return true; - } - } - - return false; -} - - -bool GribConfiguration::get(const std::string& name, std::vector& value) const { - NOTIMP; -} - - -void GribConfiguration::print(std::ostream&) const { - NOTIMP; -} - - -} // namespace eckit::grid::grib diff --git a/src/eckit/grid/grib/GribConfiguration.h b/src/eckit/grid/grib/GribConfiguration.h deleted file mode 100644 index 7c538aa05..000000000 --- a/src/eckit/grid/grib/GribConfiguration.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include - -#include "eccodes.h" - -#include "eckit/config/Configuration.h" -#include "eckit/exception/Exceptions.h" - - -namespace eckit::grid::grib { - - -class GribConfiguration final : Configuration { -private: - // -- Types - - using codes_handle_type = std::unique_ptr; - - using cache_value_type = std::variant, - std::vector, - std::vector, - std::vector, - std::vector, - std::vector, - std::vector, - std::vector>; - - struct cache_type : protected std::map { - template - bool get(const key_type& name, T& value) const { - if (auto it = find(name); it != end()) { - value = std::get(it->second); - return true; - } - - return false; - } - - template - void set(const key_type& name, T& value) { - operator[](name) = value; - } - }; - -public: - // -- Exceptions - // None - - // -- Constructors - - explicit GribConfiguration(codes_handle* h); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - template - T get(const std::string& name) const { - auto value = T(); - ASSERT(get(name, value)); - return value; - } - - // -- Overridden methods - - bool has(const std::string& name) const override; - - bool get(const std::string& name, std::string& value) const override; - bool get(const std::string& name, bool& value) const override; - bool get(const std::string& name, int& value) const override; - bool get(const std::string& name, long& value) const override; - bool get(const std::string& name, long long& value) const override; - bool get(const std::string& name, std::size_t& value) const override; - bool get(const std::string& name, float& value) const override; - bool get(const std::string& name, double& value) const override; - - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - codes_handle_type codes_handle_; - mutable cache_type cache_; - - // -- Methods - // None - - // -- Overridden methods - - void print(std::ostream&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - -} // namespace eckit::grid::grib diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9b7ba999f..f540219bb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,7 +3,6 @@ add_subdirectory( container ) add_subdirectory( exception ) add_subdirectory( filesystem ) add_subdirectory( geometry ) -add_subdirectory( grid ) add_subdirectory( io ) add_subdirectory( large_file ) add_subdirectory( linalg ) diff --git a/tests/geometry/CMakeLists.txt b/tests/geometry/CMakeLists.txt index 45673e9f9..2f76c49a1 100644 --- a/tests/geometry/CMakeLists.txt +++ b/tests/geometry/CMakeLists.txt @@ -1,5 +1,29 @@ -foreach( _test coordinate_helpers great_circle kdtree sphere kpoint points polygon ) - ecbuild_add_test( TARGET eckit_test_geometry_${_test} - SOURCES test_${_test}.cc - LIBS eckit_geometry ) +foreach( _test + coordinate_helpers + great_circle + iterator + kdtree + kpoint + param + points + polygon + projection + projection_ll_to_xyz + projection_rotation + search + sphere + types + util ) + ecbuild_add_test( + TARGET eckit_test_geometry_${_test} + SOURCES test_${_test}.cc + LIBS eckit_geometry ) endforeach() + +if(HAVE_PROJ) + ecbuild_add_test( + TARGET eckit_test_geometry_projection_proj + SOURCES test_projection_proj.cc + LIBS eckit_geometry ) +endif() + diff --git a/tests/grid/test_iterator.cc b/tests/geometry/test_iterator.cc similarity index 77% rename from tests/grid/test_iterator.cc rename to tests/geometry/test_iterator.cc index 9936e70b4..3bbc35ff4 100644 --- a/tests/grid/test_iterator.cc +++ b/tests/geometry/test_iterator.cc @@ -13,13 +13,13 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/grid/Scanner.h" -// #include "eckit/grid/iterator/IteratorAggregator.h" -// #include "eckit/grid/iterator/IteratorComposer.h" +#include "eckit/geometry/Scanner.h" +// #include "eckit/geometry/iterator/IteratorAggregator.h" +// #include "eckit/geometry/iterator/IteratorComposer.h" int main(int argc, const char* argv[]) { - // eckit::grid::iterator::IteratorComposer i(nullptr); + // eckit::geometry::iterator::IteratorComposer i(nullptr); // struct ScannerTest : public eckit::grid::Scanner { // bool operator++() override { NOTIMP; } diff --git a/tests/grid/test_param.cc b/tests/geometry/test_param.cc similarity index 100% rename from tests/grid/test_param.cc rename to tests/geometry/test_param.cc diff --git a/tests/grid/test_projection.cc b/tests/geometry/test_projection.cc similarity index 88% rename from tests/grid/test_projection.cc rename to tests/geometry/test_projection.cc index 11c09aa32..671fb8f69 100644 --- a/tests/grid/test_projection.cc +++ b/tests/geometry/test_projection.cc @@ -14,20 +14,20 @@ #include #include "eckit/config/MappedConfiguration.h" -#include "eckit/grid/Projection.h" +#include "eckit/geometry/Projection.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { using eckit::MappedConfiguration; - using eckit::grid::Point; - using eckit::grid::Point3; - using eckit::grid::PointLonLat; - using eckit::grid::points_equal; + using eckit::geometry::Point; + using eckit::geometry::Point3; + using eckit::geometry::PointLonLat; + using eckit::geometry::points_equal; - using Projection = std::unique_ptr; - using ProjectionFactory = eckit::grid::ProjectionFactory; + using Projection = std::unique_ptr; + using eckit::geometry::ProjectionFactory; Point p = PointLonLat{1, 1}; diff --git a/tests/grid/test_projection_ll_to_xyz.cc b/tests/geometry/test_projection_ll_to_xyz.cc similarity index 84% rename from tests/grid/test_projection_ll_to_xyz.cc rename to tests/geometry/test_projection_ll_to_xyz.cc index 38122064f..b16ade496 100644 --- a/tests/grid/test_projection_ll_to_xyz.cc +++ b/tests/geometry/test_projection_ll_to_xyz.cc @@ -12,14 +12,13 @@ #include -#include "eckit/grid/projection/LonLatToXYZ.h" +#include "eckit/geometry/projection/LonLatToXYZ.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using eckit::grid::Point; - using eckit::grid::PointLonLat; - using eckit::grid::projection::LonLatToXYZ; + using eckit::geometry::PointLonLat; + using eckit::geometry::projection::LonLatToXYZ; const PointLonLat p(1., 723.); @@ -30,7 +29,7 @@ int main(int argc, char* argv[]) { auto r = to_xyz.inv(q); std::cout << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; - EXPECT(eckit::grid::points_equal(p, r)); + EXPECT(points_equal(p, r)); } diff --git a/tests/grid/test_projection_proj.cc b/tests/geometry/test_projection_proj.cc similarity index 58% rename from tests/grid/test_projection_proj.cc rename to tests/geometry/test_projection_proj.cc index bf4f9a431..e0ec41703 100644 --- a/tests/grid/test_projection_proj.cc +++ b/tests/geometry/test_projection_proj.cc @@ -13,37 +13,42 @@ #include #include "eckit/config/MappedConfiguration.h" -#include "eckit/grid/projection/PROJ.h" +#include "eckit/geometry/projection/PROJ.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using eckit::grid::points_equal; + using eckit::geometry::Point; + using eckit::geometry::Point2; + using eckit::geometry::Point3; + using eckit::geometry::PointLonLat; + using eckit::geometry::points_equal; + using eckit::geometry::projection::PROJ; std::cout.precision(14); - eckit::grid::PointLonLat a{12., 55.}; + PointLonLat a{12., 55.}; struct { - const eckit::grid::Point b; + const Point b; const std::string target; } tests[] = { - {eckit::grid::Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, - {eckit::grid::Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, + {Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, + {Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, {a, "EPSG:4326"}, {a, "EPSG:4979"}, - {eckit::grid::Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, - {eckit::grid::Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, + {Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, + {Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, "+proj=cart +R=6371229."}, - {eckit::grid::Point3{3574399.5431832, 759762.07693392, 5218815.216709}, + {Point3{3574399.5431832, 759762.07693392, 5218815.216709}, "+proj=cart +ellps=sphere"}, {a, "+proj=latlon +ellps=sphere"}, }; for (const auto& test : tests) { - eckit::grid::projection::PROJ projection(eckit::MappedConfiguration({{"source", "EPSG:4326"}, {"target", test.target}})); + PROJ projection(eckit::MappedConfiguration({{"source", "EPSG:4326"}, {"target", test.target}})); - std::cout << "ellipsoid: '" << eckit::grid::projection::PROJ::ellipsoid(projection.target()) + std::cout << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) << std::endl; auto b = projection.fwd(a); @@ -54,7 +59,7 @@ int main(int argc, char* argv[]) { EXPECT(points_equal(b, test.b)); EXPECT(points_equal(c, a)); - eckit::grid::projection::PROJ reverse(eckit::MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}})); + PROJ reverse(eckit::MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}})); auto d = reverse.fwd(test.b); auto e = reverse.inv(d); diff --git a/tests/grid/test_projection_rotation.cc b/tests/geometry/test_projection_rotation.cc similarity index 96% rename from tests/grid/test_projection_rotation.cc rename to tests/geometry/test_projection_rotation.cc index 4a8deb6fa..68b848cc8 100644 --- a/tests/grid/test_projection_rotation.cc +++ b/tests/geometry/test_projection_rotation.cc @@ -12,15 +12,15 @@ #include -#include "eckit/grid/projection/Rotation.h" +#include "eckit/geometry/projection/Rotation.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using eckit::grid::Point; - using eckit::grid::PointLonLat; - using eckit::grid::points_equal; - using eckit::grid::projection::Rotation; + using eckit::geometry::Point; + using eckit::geometry::PointLonLat; + using eckit::geometry::points_equal; + using eckit::geometry::projection::Rotation; { const PointLonLat p(1, 1); diff --git a/tests/grid/test_search.cc b/tests/geometry/test_search.cc similarity index 85% rename from tests/grid/test_search.cc rename to tests/geometry/test_search.cc index dbf161c2a..1f9d2b0f6 100644 --- a/tests/grid/test_search.cc +++ b/tests/geometry/test_search.cc @@ -13,16 +13,19 @@ #include #include -#include "eckit/grid/Search.h" +#include "eckit/geometry/Search.h" int main(int argc, const char* argv[]) { + using namespace eckit::geometry; + + { - std::vector points{ + std::vector points{ {{0, 0, 0}, 0}, }; - eckit::grid::Search3 search; + Search3 search; search.build(points); std::cout << search.nearestNeighbour({0.1, 0, 0}) << std::endl; @@ -36,11 +39,11 @@ int main(int argc, const char* argv[]) { { - std::vector points{ + std::vector points{ {{0, 0}, 0}, }; - eckit::grid::Search2 search; + Search2 search; search.build(points); std::cout << search.nearestNeighbour({0.1, 0}) << std::endl; diff --git a/tests/grid/test_types.cc b/tests/geometry/test_types.cc similarity index 96% rename from tests/grid/test_types.cc rename to tests/geometry/test_types.cc index d03479788..64494e236 100644 --- a/tests/grid/test_types.cc +++ b/tests/geometry/test_types.cc @@ -12,13 +12,13 @@ #include -#include "eckit/grid/Point.h" +#include "eckit/geometry/Point.h" #include "eckit/maths/Matrix3.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using namespace eckit::grid; + using namespace eckit::geometry; PointLonLat p(1, 90.); diff --git a/tests/grid/test_util.cc b/tests/geometry/test_util.cc similarity index 97% rename from tests/grid/test_util.cc rename to tests/geometry/test_util.cc index 7991595c1..7be4704b2 100644 --- a/tests/grid/test_util.cc +++ b/tests/geometry/test_util.cc @@ -13,7 +13,7 @@ #include #include -#include "eckit/grid/util.h" +#include "eckit/geometry/util.h" template @@ -68,7 +68,7 @@ class iterable_t : public std::vector { int main(int argc, char* argv[]) { - using namespace eckit::grid::util; + using namespace eckit::geometry::util; #if 0 std::cout << linspace(1, 2, 2, true) << std::endl; diff --git a/tests/grid/CMakeLists.txt b/tests/grid/CMakeLists.txt deleted file mode 100644 index 683fc8169..000000000 --- a/tests/grid/CMakeLists.txt +++ /dev/null @@ -1,24 +0,0 @@ -foreach( _test - iterator - param - projection - projection_ll_to_xyz - projection_proj - projection_rotation - search - types - util - ) - ecbuild_add_test( - TARGET eckit_test_grid_${_test} - SOURCES test_${_test}.cc - LIBS eckit_grid ) -endforeach() - -if(HAVE_ECCODES) - ecbuild_add_test( - TARGET eckit_test_grid_grib - SOURCES test_grib.cc - LIBS eckit_grid_grib) -endif() - diff --git a/tests/grid/reduced_gg.grib2 b/tests/grid/reduced_gg.grib2 deleted file mode 100644 index 74275e4fbc65f71ac771d1e7d06ef2e7e74a547f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6420 zcmds+|CeKDUB{n$?{mL@zc(#Ii7-fj@fbLvq;1+}C+Y6Z?T7&bM2r$4&>&Mzgjix5 zAuItR1RL#0Lp!B$cf`OMA;qCY88nrtC(1~3?0^A=5^;c_11G>NrZ7loeQ)tM{{yq< z%=aYsKF{ZQe|hcAulSX-Pd-Ul^3>z$0erfGA+IMSNEq=yxhu7w|AN>oVepToOe7L{ z5g~y!j*w!Xunbudp8UTLLX@YTdHFYdzM6jOn?J-CS5%f>eEElj@c3DPEa9D&NrTiIF%-5|6BrG|7-G$&oxMkRn+pB~m68QYAG~Ck@ghEwVw{WRrBr7U`00(jz;h zPj<xlzc+47;W-?5c$uW7Rz!aHvro@z)3R7ijOr2>kO{T?cFl}a&=`dSNm)T}|%ns9M zc9{XQ#|)W$X2cvYW9E>VFh|UkIc8?e2{UI-nFWhwWF=N(EjGX|u|am34Y4b1n2oSe zHpa%;B>fL0_t_D9z>e8NcETR9Q}&phu_x@DJ!Kah;V36@8fS3ATn=G-Z_poCH?QH@$OK$mEcF4GWQpAHTA)R`PD`{*E3`^$v`!neNn3P-w&^DA&@I}f+q6e_XrJ!V z0o|iRx=%;+fR5=QozNpXrN?wePw1SU(gja=%1gY)TYP|D;)DD$AL3W|FdyNge2kCt zN#5hv_%xs4vwV)v^98=huk$6o%vbm-U*qe1gKzRJeuHoGn|z1g;=BAd-{W`qKEKNk z_&t8e@AD)6fFJXR{DeQ^r~ENL<4^cGf66ZeB2YmRG{F)A!jcdamW7b8B7}vA5EWuV zTu2I@uqLF1jF1&_LS85cMPXei31y)oRE3&Q7aBrSXbBraTi6sj!j{k#wuPRsBlLw` zVIb@YLt$SS2?xShI20zrkuVjGg_&?7%!N~7Arg^_lBkK67!a4lptvlC#1%0tM#QKX z6XRl1^u#qWEoQ{5m=p72K`e^vVo5BE6|pMT#JboJn_^4c5ZmIW*b%qHuDC7s#2v9O z?ur9(PaKN-;z&FY$Ks(l5s$>Fcr4Du6LBt{iVKNIRFWi3vZR2tBn72qDI~2(VJRX- zrI-|#l9DH_Nogq~Wu=^ymkLr*T9-;vS*l1?sV3E>hSZc=(uUNQHl>cVC3U53sVD77 zeQ8%3NPE&y+LuPsfi#v5rHOPTO{HULCY?xg=~PMuF5sJE;r<++>$rsw!A5K)RL1kG9DJx1? zi6~Jero@$`;wfuNTFEF`C8y+-f>Ko0m6B3cDoRzUDRrfxG?kXJp|q7vrK4;qU1eM8 zDLYDE*;NM0o-$PSm639wjFm%Wq8uqxZ!WWh(C_ ziWb%)T2zZ^aV@EN+M1TuGFn#4X?d-n6}5G(q?NUbR@G`+U2AAft)*>fZEaKQXj@uW z+tzy8j@H+9wSl&$4Yhr3q#bBu?NFO&N7__7)@Is?HrGzIg-&#;OS-08dO%;&gZi=_ z(pU7b9?_$EOpohH-P70fw4TwkdQQ*l1-+=R>m|LcSM;i0)9ZReZ|W_5LvQPwdPm>V zyZW}?(|7c~zN-)PJ$m&U@AM1zuL_gA}`msLKPxQHdsxJ&;P(v~_!!iQKk`XkP zjgYZogpG(1HDX5GNE)88W~7abku`Eg-Y6JFW8EkjWuszLjhaz68b;G-85>61*fcuE zmeDn~jh?Y%^o?C(VC)$~W8WAV2gcYqG$zK8F*S~jnQ>ywjZoXW0okD^A#nI8i6&#GRz$IcrYZ$v9aj=j5G&Q*_pyl2djnPSvS7b*JGpotCrV zw4F_-<7_!yXWQvHJ5Jx(bq3C!Gj#Tyk#pdTokM5h963|x*qJ#e&fGb57A|qAE4i9$ zxdC^{4Z6#2$X#*6Zp4kcF*oieUC&)}({9Gix;Z!R7Tlt{?v~uLTXCyy&8@o)x9PUr z4Y%!Xx*d1R?Yi4;&)sqR?yfs<_uQeo?~dF9ckCXz6ZgoSy2tL!J#pvmsk;b}01Ze1 zEr9LEM+x5%cY)u`@fS1v0 z)o^7MTww`UTErFSaphUuK^k}B;f~_CvncK`j5`hCj)S=K09HW5N>GD>TDO zO|fDVtlStYIKoN}v7!U4Y#%G!!%BCt;vKAf8#~a#PBgG1HSA0UJ5<6>6|rM^>|7Q* zn8r?e*wHw4Hi{h%W2Zyd@gR0SfC0+TVvgv>B0Q%uYRlQYHyjW9_=Ow<6A z)yIVOFlk*(TnCfa#ss!7i49C-4U<{HgqAR=MNDiSlbgi^r!mPMCOVGEj$*>YnDh`P zK8VQ=-~?zm3DhRm0w-gR6Eed|nc~DuaB{{tK_i@`Ax_i)C##PW*278b;>2}u^4d6o zEu6##PGk)yvw{;^!bvUS#O85wvpB(NoMaCtI*yYa#R(7Nq=#_ggE;vCD1ZhfpcXL~ zP=+}aVg{v{LNO*#jxiKu1SJ_lQ3gO@<>8Ru}w8Juzo$DF`9$8gXQoOB3B9l%-paM&K4whPDYz#nRFF_gNGe4nmOPS676~Se zB;z5`#F1>GNH}36oe&aF5XmQi1f(GeQI#kQB%?VJ(hNyyio`TQavCE+jgX{NbNbK_Y6|}8q$0csXm5uA3@4rLE2wN>R&?ox6lG4v;iV6&quEB$aKmW2AvE3~nr{FN zSVI%0JfRCT<2f4g3{828#ymlD9-~2z(4>cG)B`l@J{oopO}mT6-9hti(+%39O|`XDSlkd`ipO9$ko4Fb~wiD`hy)Ieq`AT%YAnj(lz9^@tqf|CZx@j!Iq zAUjbIo-jyH2*f7{@)H07(m;YJ;MxLYXbwU&11Xw<7)?Nq#vn)|kfb4q(g0+s55m*~ zY3hPFbwHllAW$uks0N5s4P>eULRA8(DuP($L9VhOSZR4J3>*ge*YD<{)GnwJFCi-GP%K>1cc`<6ldmO%dqy^S*XgbR4` zK2Sk?Cgj%3ADGLK@G>SOcryRfq<`l#lON37m3-{{=Wlw(f8Bl4Z~oO6ZfgJg({B3Q zH}}qRmtJ%Bmm9gWum0j2&fclK|Lg;w|K!;(k0*n{JOT4Og?v_*i+K3euR?ti(r z^{J-!$={rjJ{?{_}^Z~mYCIO|{d*5CRUs~7x>{T2V>-DUrx`(gjWiv_>) z{jh((r~CK4=(+wq{fdA0=V$)LTi@ij9(c@ezVj3QdoC6H^Ggx`tq<<|>;HV<|Mu^v z{g*!)@Kcv0|N6)C{tF(D`M)Uj{VRRTR~|k{J^2ih`p#{8sqtSFQhUQ>>Va=rsg6-d z-TA8|bw{F*`Ym@al?WtL&$~LAGH*HZ9*+?3(YGYM2Y#>a{mC)$-ndowuKR4=GblMX zzJ{E;_Y67rk{UTXkCL-*UnV#G%??SH>+I$E`2YNPamdbH`^~TZW>#w{1!OG8WaIg7|8*aVf!VRCyT)dHe|2uEIarNFC-~G&gx^XA=x*Naq*{kAD zd+2rXo8GL&Z+j>izsG9FKmF`?$0y(X&>8NLE6zOQ;SZd-_Kw+^ta<57VN+2)!^vS)$orVTU~u_VKq}AtG9gohSjQZ zu=?K5byq*|^x5hKa$)sjw?DD^>EB&i9X^s;{o?r_t{znmR=4~eFpGZ9WC1T?FU(Y07xOy=WeM2O1!%MGBB!2kuMCuhkOT47?ro^wEc{uUP z&l!oFw3*0rpGmy-GvmZ9F9;=m=e6HR+?xG(qGa5jc=KHkCCZa<;*1#_~FMA=XYy~cNTXN^`|D~3jXqcT>Sh|f6o7Y OAqbbHh8M5H<9`6U`uP_C diff --git a/tests/grid/reduced_ll.grib1 b/tests/grid/reduced_ll.grib1 deleted file mode 100644 index 60cfabd08b36e16a3280969f2a93ad4c6bdae596..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3470 zcmbuCe?+BU9>>pfp7WgN{LF0nCK+jyktBD&(k2;K(zY2%k|b@Ck&z_VNZPa`8CTMd zBpKI8GLmE@8OcbJBuTE3E6Hqy^?p5nYxsL5 zvEvRQC1V{&KZgJFl8`_7!VvsK5kh{!pa1a2J-K3B7lOZxf!eoL> zlL(n33uKwBl6A60cF6&Wk{CH77v!4Uk_U%6!bx*7oNOo0DR7FN5~th=I@L~{)9AD~ z?aoW5+v#)qondFx8FSt_(@w;ha~7OsXU*Agwwzt(z==9B=ghfuuAN)wfl?}H8qJ{D zG>;b0Vp>AWX^>Xa7qo#k({}ojcGEuEPlxCT4buraMc>moxCT<#h--OX}y+U2cyXatGXDchnto-?`In z#GP{&++}ywU3WL#9e3Y7a*y3p_uT#N#@#zN!5C94on^5cmd^@VfR(ZeR>^8u9cy6C ztc`WDSFD%4W`pbvd&|bzB%5I$*gRWgpV%7PU|VdL9k3{iu`_nTuGkH`X9X zmbdF2cu_CroqFfqcQ5YUc?nLr;AuRAXY*X1&kK2gm+}f;$*cJb-oTrA8}Hy-l#df5YGM zcl>?-$p7k}_-Fowf91#hJO4pYA%qd>B2zpSx#F295&=;v%0*CAiCR%78bz~c6CI*U zbc;UGF9yXMF)GHygqRXDA|mF*N3kS6i8ZkU=iCN9L4h>JV%Ac^Es z$tN;HX2~3xCktee49HShE`zd4*2p^9Ae&^XY?qz#mF$syvR@9$VL2+pa$HWzY587$ zkn?guF3A4}5il|vNuNKsj`lMFX zXSJa=)wbGI`|40d)v-EJXX;#Csw)*&x9VOcG}T-you<=urq0$mI#=iG0$rp7x2BStL;AHI&_nu-9@SwzrYH2Ip4KxuqG$EIUeJqr zS+D3d{aJ75O}(Xe^qxM@hdQc{bxfb?Z~9zc>MMP%Z}gqM*9k)nGr|~?X3|ZD$udt( zj>$9mroa@LV)LshF=eLQJU2m8Wok^VsWbJa(KMMB(`wpHhk0qbOt>iE9`R{w3W8XR@)j|YhTzpTW=d|qiwRyw#ByEHrsAHY^Qx` zyX-65ZF_95?Xw~K8tJzKcF+#lVf)68*iq!I4cjq0ZYPj;cG6DSX*+|ww-NgRnYD9v z-hMK~9k~ zYoFYR~a3b{@tZsYbQm0Npj?^3z9$vmWzut*w82?6#~VQG&6uu>6ezelD0 z9*oP+r2XOZB<=srAO6dqzb*NDfBzQh=Qk6-eOLb5cV|DJCiQH|r$io~`SJN5&mws$ zkLQy-smC)*o?h}4lc)K3uE`Tlo^<+)3SN z@@6+vx4ea-b}1sC3f4^!a81b7h! zH%7saVQ^#sJPCm-J>W|hIMV^%w1PWL;7>g`R0|$eflJT9r!sKrSMaI`+{y>Pa=@`H z@GKqUV!$_Ms7`=)ci`SN_;(2oegh9<;9?YfJOC$mz{^c=^E3Fl0*)?%r}N-y1bm$a zXD7hhFu3~${2c&?L*Q{YxZDXow}I15;B_6iT@8K*!SOQiJOHj2fbY5Bd^UKW4(==P zpQ;49;1->5g>E=UN1UK5qUel$bjLP2WCLBYicVQVx6GqsBIueabj}#MX9OKIh%O4D zle*DO9q6bQbX5a7s}|iAM2D53%L3@MXXv&ZbX+F7&Y<&{BJv&`7)KXgq7zTijbG7` z`{>GTbmls`a|Io`fG+)jPMt=#j-z8o(Y1r<+&*;gD|B!>y0{6QT!(J1LPwXQs{`ol z0(5r{Iy?hiuF&a3JfPp>==lru{Rw(MivHh&2W-Lz*5Cz8@Pj#c!VG+20^TqRe;9;E z^uZ^(;1zA~i$-`xEqo&g?{sUYk4rjT5yPUvbj^HvoaGDLc z%?cc60j?8)^Gw2h!f>D=xKIdA^a^g&21jayE7ii8p2M9=;82BdsT?>}2HZ;cj3?k) zaX8ln+$#nLJA{jE!^zg+X3KE2dAQmPoNWT`HUftmfXns3={n$c&2YRIaJ@=6Un$(L z5Du6N7t8=)1*cvDju?k4p2HbqaK{5U9F<4{+j1xba&! z@*rHf7tY)XcW#D5*TJPL;nbyY>q0no4qQ7O&duBe{5uX0KZlPW!^`*K=bP~KRrvY> zygdSce+Q2rh0hPb>wDn$9q{}n_Soi~#@u diff --git a/tests/grid/regular_gg.grib1 b/tests/grid/regular_gg.grib1 deleted file mode 100644 index 3bca954e594550c452f25f4f726d89d1535f59c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108 zcmZ<{@^oTg$YEq)Flk7d{=Z>5kR{3}#lrxkK|mBj!AV9&CKg5m0|P^_hyufZ7KR1} f2gYy7G`~=pj2<8{;7oh5SI2t%1OmiRr081wiSpWb4 diff --git a/tests/grid/test_grib.cc b/tests/grid/test_grib.cc deleted file mode 100644 index 4434321ab..000000000 --- a/tests/grid/test_grib.cc +++ /dev/null @@ -1,206 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eccodes.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/grid/grib/GribConfiguration.h" - - -#if 0 -(grib2/template.3.(gaussian|grid|latlon).def) - double latitudeOfFirstPointInDegrees - double latitudeOfLastPointInDegrees - double longitudeOfFirstPointInDegrees - double longitudeOfLastPointInDegrees - double DiInDegrees - double DjInDegrees - size_t n_i - size_t n_j - size_t numberOfParallelsBetweenAPoleAndTheEquator - size_t basicAngleOfTheInitialProductionDomain - size_t subdivisionsOfBasicAngle -#endif - - -#if 0 -eckit::grid::Figure* make_figure(long code) { - // Code table 3.2 – Shape of the reference system - - switch (code) { - case 0: - return new eckit::grid::figure::Sphere(6367470.); - case 1: - // Earth assumed spherical with radius specified (in m) by data producer - NOTIMP; - case 2: - return new eckit::grid::figure::Spheroid(6378160., 6356775.); - case 3: - // Earth assumed oblate spheroid with major and minor axes specified (in km) by data producer - NOTIMP; - case 4: - return new eckit::grid::figure::Spheroid(6378137., 6356752.314); - case 5: - return new eckit::grid::figure::Spheroid(6378137., 6356752.314140347); - case 6: - return new eckit::grid::figure::Sphere(6371229.); - case 7: - // Earth assumed oblate spheroid with major or minor axes specified (in m) by data producer - NOTIMP; - case 8: - return new eckit::grid::figure::Sphere(6371200.); - case 9: - return new eckit::grid::figure::Spheroid(6377563.396, 6356256.909); - case 10: - // Earth model assumed WGS84 with corrected geomagnetic coordinates (latitude and longitude) defined by - // Gustafsson et al., 1992 - NOTIMP; - case 11: - return new eckit::grid::figure::Sphere(695990000.); - default: - NOTIMP; - } -} -#endif - - -#if 0 - std::string type() const { return get_string("gridType"); } - - size_t Ni() const { return get_size_t("Ni"); } - size_t Nj() const { return get_size_t("Nj"); } - - double i_start() const { return get_double("longitudeOfFirstGridPointInDegrees"); } - double i_step() const { return get_double("iDirectionIncrementInDegrees"); } - double i_stop() const { return get_double("longitudeOfLastGridPointInDegrees"); } - - double j_start() const { return get_double("latitudeOfFirstGridPointInDegrees"); } - double j_step() const { return get_double("jDirectionIncrementInDegrees"); } - double j_stop() const { return get_double("latitudeOfLastGridPointInDegrees"); } - - struct iterator : std::unique_ptr { - using t = std::unique_ptr; - - explicit iterator(codes_handle* h) : t(codes_grib_iterator_new(h, 0, &err), &codes_grib_iterator_delete) { - ASSERT(CODES_SUCCESS == err); - ASSERT(*this); - } - - bool next() { return codes_grib_iterator_next(get(), &lat, &lon, &value) > 0; } - - friend std::ostream& operator<<(std::ostream& out, const iterator& it) { - return (out << "- lat=" << it.lat << " lon=" << it.lon << " value=" << it.value); - } - - int err = 0; - double lat = 0; - double lon = 0; - double value = 0; - }; -#endif - - -template -std::ostream& operator<<(std::ostream& out, const std::vector& vec) { - const auto* s = ""; - - out << '{'; - for (const auto& v : vec) { - out << s << v; - s = ", "; - } - - return out << '}'; -} - - -int main(int argc, const char* argv[]) { - for (int i = 1; i < argc; ++i) { - auto* in = std::fopen(argv[i], "rb"); - ASSERT(in != nullptr && "unable to open file"); - - int err = 0; - for (codes_handle* h = nullptr; nullptr != (h = codes_handle_new_from_file(nullptr, in, PRODUCT_GRIB, &err));) { - eckit::grid::grib::GribConfiguration grib(h); - -#if 0 - int n = 0; - for (grib::iterator it(h); it.next(); ++n) { - std::cout << "- " << n << " " << it << "\n"; - } - std::cout.flush(); -#endif - - std::string type; - ASSERT(grib.get("gridType", type)); - std::cout << "type: '" << type << "'" << std::endl; - - if (grib.has("pl")) { - // std::cout << "pl: '" << grib.get("pl") << "'" << std::endl; - } - - if (type == "regular_ll") { - // struct regular_ll_args { // also, rotated_ll - // size_t n_i; - // double i_start; - // double i_stop; - // double i_step; - // size_t n_j; - // double j_start; - // double j_stop; - // double j_step; - // };`` - // - // struct regular_gg_args { // also, rotated_gg - // size_t n; - // size_t n_i; - // double i_start; - // double i_stop; - // double j_start; - // double j_stop; - // }; - // - // struct reduced_gg_args { // also, reduced_rotated_gg - // size_t n; - // std::vector n_i; - // double i_start; - // double i_stop; - // double i_step; - // double j_start; - // double j_stop; - // double j_step; - // }; - // - // struct reduced_ll_args { - // std::vector n_i; - // double i_start; - // double i_stop; - // double i_step; - // double j_start; - // double j_stop; - // double j_step; - }; - } - - std::fclose(in); - } - - return 0; -} From 8abe617ecf84689a2e77e08a9a6865ee45e7c95d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 4 Jul 2023 13:58:58 +0100 Subject: [PATCH 249/737] eckit::geometry --- tests/geometry/test_grid.cc | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tests/geometry/test_grid.cc diff --git a/tests/geometry/test_grid.cc b/tests/geometry/test_grid.cc new file mode 100644 index 000000000..3bbc35ff4 --- /dev/null +++ b/tests/geometry/test_grid.cc @@ -0,0 +1,32 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/exception/Exceptions.h" +#include "eckit/geometry/Scanner.h" +// #include "eckit/geometry/iterator/IteratorAggregator.h" +// #include "eckit/geometry/iterator/IteratorComposer.h" + + +int main(int argc, const char* argv[]) { + // eckit::geometry::iterator::IteratorComposer i(nullptr); + + // struct ScannerTest : public eckit::grid::Scanner { + // bool operator++() override { NOTIMP; } + // size_t size() const override { NOTIMP; } + // }; + + // eckit::grid::iterator::IteratorAggregator j; + + return 0; +} From 15d90b8a23d88cdb2f71580a7060ff7337a27bec Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 4 Jul 2023 14:36:38 +0100 Subject: [PATCH 250/737] eckit::geometry --- src/eckit/geometry/BoundingBox.h | 2 +- src/eckit/geometry/Grid.cc | 44 +++++++++----- src/eckit/geometry/Grid.h | 59 +++++++++++++------ src/eckit/geometry/detail/Gaussian.cc | 1 + src/eckit/geometry/detail/IrregularLatlon.cc | 18 ++---- src/eckit/geometry/detail/IrregularLatlon.h | 6 +- src/eckit/geometry/detail/ReducedGG.cc | 17 +----- src/eckit/geometry/detail/ReducedGG.h | 5 +- src/eckit/geometry/detail/ReducedLL.cc | 16 +---- src/eckit/geometry/detail/ReducedLL.h | 7 +-- src/eckit/geometry/detail/RegularGG.cc | 14 +---- src/eckit/geometry/detail/RegularGG.h | 7 +-- src/eckit/geometry/detail/RegularGrid.cc | 14 +---- src/eckit/geometry/detail/RegularGrid.h | 8 +-- src/eckit/geometry/detail/RegularLL.cc | 15 +---- src/eckit/geometry/detail/RegularLL.h | 6 +- src/eckit/geometry/detail/UnstructuredGrid.cc | 25 +------- src/eckit/geometry/detail/UnstructuredGrid.h | 10 +--- src/eckit/geometry/projection/Rotation.cc | 4 ++ src/eckit/geometry/projection/Rotation.h | 1 + tests/geometry/CMakeLists.txt | 1 + tests/geometry/test_grid.cc | 52 ++++++++++++---- 22 files changed, 143 insertions(+), 189 deletions(-) diff --git a/src/eckit/geometry/BoundingBox.h b/src/eckit/geometry/BoundingBox.h index 57cf4bfef..858c19b5a 100644 --- a/src/eckit/geometry/BoundingBox.h +++ b/src/eckit/geometry/BoundingBox.h @@ -34,7 +34,7 @@ class BoundingBox { // -- Constructors - BoundingBox(const Configuration&); + explicit BoundingBox(const Configuration&); BoundingBox(double north, double west, double south, double east); BoundingBox(); diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 8ccda8cca..31b6b3674 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -36,16 +36,6 @@ Grid::Grid(const BoundingBox& bbox) : bbox_(bbox) {} -Domain Grid::domain() const { - auto n = includesNorthPole() ? NORTH_POLE : bbox_.north(); - auto s = includesSouthPole() ? SOUTH_POLE : bbox_.south(); - auto w = bbox_.west(); - auto e = isPeriodicWestEast() ? bbox_.west() + GLOBE : bbox_.east(); - - return {n, w, s, e}; -} - - const BoundingBox& Grid::boundingBox() const { return bbox_; } @@ -89,13 +79,37 @@ const Grid* GridFactory::build(const Configuration& config) { throw SeriousBug("GridFactory: cannot get 'gridType'"); } - auto j = m->find(name); - if (j == m->end()) { - list(Log::error() << "GridFactory: unknown '" << name << "', choices are: "); - throw SeriousBug("GridFactory: unknown '" + name + "'"); + if (auto j = m->find(name); j != m->end()) { + return j->second->make(config); } - return j->second->make(config); + list(Log::error() << "GridFactory: unknown '" << name << "', choices are: "); + throw SeriousBug("GridFactory: unknown '" + name + "'"); +} + + +const Grid* GridFactory::build_from_uid(const Grid::UID& uid) { + NOTIMP; +} + + +const Grid* GridFactory::build_from_name(const Grid::Name&, const Grid::Area& area, const Grid::Rotation& rotation) { + NOTIMP; +} + + +const Grid* GridFactory::build_from_name(const Grid::Name&, const Grid::Rotation& rotation) { + NOTIMP; +} + + +const Grid* GridFactory::build_from_increments(const Increments&, const Grid::Area& area, const Grid::Rotation& rotation) { + NOTIMP; +} + + +const Grid* GridFactory::build_from_increments(const Increments&, const Grid::Rotation& rotation) { + NOTIMP; } diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 6dcb56661..554ae49a7 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -19,14 +19,10 @@ #include "eckit/config/Configuration.h" #include "eckit/geometry/BoundingBox.h" +#include "eckit/geometry/Increments.h" #include "eckit/geometry/Point.h" #include "eckit/geometry/Renumber.h" - - -namespace eckit::geometry { -class Domain; -class Iterator; -} // namespace eckit::geometry +#include "eckit/geometry/projection/Rotation.h" namespace eckit::geometry { @@ -34,13 +30,22 @@ namespace eckit::geometry { class Grid { public: + // -- Types + + using UID = std::string; + using Name = std::string; + using Rotation = projection::Rotation; + using Area = BoundingBox; + // -- Exceptions // None // -- Constructors - Grid(const Configuration&); - Grid(const BoundingBox&); + explicit Grid(const Configuration&); + + Grid(const Grid&) = default; + Grid(Grid&&) = default; // -- Destructor @@ -52,22 +57,21 @@ class Grid { // -- Operators // None + Grid& operator=(const Grid&) = default; + Grid& operator=(Grid&&) = default; + // -- Methods - virtual Domain domain() const; virtual const BoundingBox& boundingBox() const; - virtual Iterator* iterator() const = 0; - virtual size_t numberOfPoints() const = 0; + virtual size_t size() const = 0; + virtual void print(std::ostream&) const = 0; virtual bool includesNorthPole() const = 0; virtual bool includesSouthPole() const = 0; virtual bool isPeriodicWestEast() const = 0; - virtual Renumber crop(BoundingBox&) const = 0; - virtual Renumber reorder(long scanningMode) const = 0; - // -- Overridden methods // None @@ -78,7 +82,10 @@ class Grid { // None protected: - // -- Members + // -- Constructors + + Grid(const BoundingBox&); + // None // -- Methods @@ -125,17 +132,31 @@ class GridFactory { std::string name_; virtual Grid* make(const Configuration&) = 0; - GridFactory(const GridFactory&) = delete; - GridFactory& operator=(const GridFactory&) = delete; - protected: - GridFactory(const std::string&); + explicit GridFactory(const std::string&); virtual ~GridFactory(); public: // This is 'const' as Grid should always be immutable static const Grid* build(const Configuration&); + + // This is 'const' as Grid should always be immutable + static const Grid* build_from_uid(const Grid::UID&); + + // This is 'const' as Grid should always be immutable + static const Grid* build_from_name(const Grid::Name&, const Grid::Area& = {}, const Grid::Rotation& = {}); + static const Grid* build_from_name(const Grid::Name&, const Grid::Rotation&); + + // This is 'const' as Grid should always be immutable + static const Grid* build_from_increments(const Increments&, const Grid::Area& = {}, const Grid::Rotation& = {}); + static const Grid* build_from_increments(const Increments&, const Grid::Rotation&); + static void list(std::ostream&); + + GridFactory(const GridFactory&) = delete; + GridFactory(GridFactory&&) = delete; + GridFactory& operator=(const GridFactory&) = delete; + GridFactory& operator=(GridFactory&&) = delete; }; diff --git a/src/eckit/geometry/detail/Gaussian.cc b/src/eckit/geometry/detail/Gaussian.cc index 2e5cd5970..14e0c4ba5 100644 --- a/src/eckit/geometry/detail/Gaussian.cc +++ b/src/eckit/geometry/detail/Gaussian.cc @@ -16,6 +16,7 @@ #include #include +#include "eckit/exception/Exceptions.h" #include "eckit/geometry/Domain.h" #include "eckit/geometry/util.h" #include "eckit/types/FloatCompare.h" diff --git a/src/eckit/geometry/detail/IrregularLatlon.cc b/src/eckit/geometry/detail/IrregularLatlon.cc index 2572490a6..a88ae5135 100644 --- a/src/eckit/geometry/detail/IrregularLatlon.cc +++ b/src/eckit/geometry/detail/IrregularLatlon.cc @@ -50,7 +50,7 @@ IrregularLatlon::IrregularLatlon(const Configuration& config) : } -size_t IrregularLatlon::numberOfPoints() const { +size_t IrregularLatlon::size() const { return latitudes_.size() * longitudes_.size(); } @@ -130,9 +130,9 @@ class IrregularLatlonIterator : public Iterator { }; -Iterator* IrregularLatlon::iterator() const { - return new IrregularLatlonIterator(latitudes_, longitudes_); -} +// Iterator* IrregularLatlon::iterator() const { +// return new IrregularLatlonIterator(latitudes_, longitudes_); +// } bool IrregularLatlon::isPeriodicWestEast() const { @@ -150,16 +150,6 @@ bool IrregularLatlon::includesSouthPole() const { } -Renumber IrregularLatlon::crop(BoundingBox&) const { - NOTIMP; -} - - -Renumber IrregularLatlon::reorder(long scanningMode) const { - NOTIMP; -} - - static const GridBuilder irregularLatlon("irregular_latlon"); diff --git a/src/eckit/geometry/detail/IrregularLatlon.h b/src/eckit/geometry/detail/IrregularLatlon.h index 36e7d036e..6a0c8acdd 100644 --- a/src/eckit/geometry/detail/IrregularLatlon.h +++ b/src/eckit/geometry/detail/IrregularLatlon.h @@ -66,16 +66,12 @@ class IrregularLatlon final : public Grid { // -- Overridden methods - size_t numberOfPoints() const override; - Iterator* iterator() const override; + size_t size() const override; bool isPeriodicWestEast() const override; bool includesNorthPole() const override; bool includesSouthPole() const override; void print(std::ostream&) const override; - Renumber crop(BoundingBox&) const override; - Renumber reorder(long scanningMode) const override; - // -- Class members // None diff --git a/src/eckit/geometry/detail/ReducedGG.cc b/src/eckit/geometry/detail/ReducedGG.cc index c1bca5bec..5b5f90f49 100644 --- a/src/eckit/geometry/detail/ReducedGG.cc +++ b/src/eckit/geometry/detail/ReducedGG.cc @@ -141,11 +141,6 @@ void ReducedGG::correctWestEast(double& w, double& e) const { } -Iterator* ReducedGG::iterator() const { - NOTIMP; -} - - const pl_type& ReducedGG::pls() const { ASSERT(pl_.size() == N_ * 2); ASSERT(pl_.size() >= k_ + Nj_); @@ -188,7 +183,7 @@ void ReducedGG::setNj(pl_type pl, double s, double n) { } -size_t ReducedGG::numberOfPoints() const { +size_t ReducedGG::size() const { const auto& pl = pls(); return size_t(std::accumulate(pl.begin(), pl.end(), pl_type::value_type{0})); } @@ -217,16 +212,6 @@ void ReducedGG::print(std::ostream& out) const { } -Renumber ReducedGG::crop(BoundingBox&) const { - NOTIMP; -} - - -Renumber ReducedGG::reorder(long scanningMode) const { - NOTIMP; -} - - struct ReducedGGClassic : ReducedGG { ReducedGGClassic(size_t N, const BoundingBox& box = BoundingBox()) : ReducedGG(N, box) { diff --git a/src/eckit/geometry/detail/ReducedGG.h b/src/eckit/geometry/detail/ReducedGG.h index 1fcc2916f..e8f3c0065 100644 --- a/src/eckit/geometry/detail/ReducedGG.h +++ b/src/eckit/geometry/detail/ReducedGG.h @@ -83,7 +83,6 @@ class ReducedGG : public Gaussian { // -- Overridden methods - Iterator* iterator() const override; bool isPeriodicWestEast() const override; void print(std::ostream& out) const override; @@ -102,10 +101,8 @@ class ReducedGG : public Gaussian { // -- Overridden methods - size_t numberOfPoints() const override; + size_t size() const override; Fraction getSmallestIncrement() const; - Renumber crop(BoundingBox&) const override; - Renumber reorder(long scanningMode) const override; // -- Class members // None diff --git a/src/eckit/geometry/detail/ReducedLL.cc b/src/eckit/geometry/detail/ReducedLL.cc index 0daea87ec..2f9de6b63 100644 --- a/src/eckit/geometry/detail/ReducedLL.cc +++ b/src/eckit/geometry/detail/ReducedLL.cc @@ -47,7 +47,7 @@ void ReducedLL::print(std::ostream& out) const { out << "ReducedLL[bbox=" << bbox() << "]"; } -size_t ReducedLL::numberOfPoints() const { +size_t ReducedLL::size() const { size_t total = 0; for (const auto& j : pl_) { total += size_t(j); @@ -167,20 +167,6 @@ class ReducedLLIterator : public Iterator { } }; -Iterator* ReducedLL::iterator() const { - return new ReducedLLIterator(pl_, domain()); -} - - -Renumber ReducedLL::crop(BoundingBox&) const { - NOTIMP; -} - - -Renumber ReducedLL::reorder(long scanningMode) const { - NOTIMP; -} - static const GridBuilder reducedLL("reduced_ll"); diff --git a/src/eckit/geometry/detail/ReducedLL.h b/src/eckit/geometry/detail/ReducedLL.h index fefe76ba3..74cface5d 100644 --- a/src/eckit/geometry/detail/ReducedLL.h +++ b/src/eckit/geometry/detail/ReducedLL.h @@ -59,9 +59,7 @@ class ReducedLL : public Grid { // -- Overridden methods - Iterator* iterator() const override; - - size_t numberOfPoints() const override; + size_t size() const override; bool isPeriodicWestEast() const override; bool includesNorthPole() const override; @@ -69,9 +67,6 @@ class ReducedLL : public Grid { void print(std::ostream&) const override; - Renumber crop(BoundingBox&) const override; - Renumber reorder(long scanningMode) const override; - // -- Class members // None diff --git a/src/eckit/geometry/detail/RegularGG.cc b/src/eckit/geometry/detail/RegularGG.cc index 40e8e1f00..0edc9c942 100644 --- a/src/eckit/geometry/detail/RegularGG.cc +++ b/src/eckit/geometry/detail/RegularGG.cc @@ -97,7 +97,7 @@ Fraction RegularGG::getSmallestIncrement() const { } -size_t RegularGG::numberOfPoints() const { +size_t RegularGG::size() const { ASSERT(Ni_); ASSERT(Nj_); return Ni_ * Nj_; @@ -169,20 +169,12 @@ void RegularGG::print(std::ostream& out) const { } +#if 0 Iterator* RegularGG::iterator() const { std::vector pl(N_ * 2, long(4 * N_)); return new GaussianIterator(latitudes(), std::move(pl), bbox(), N_, Nj_, k_); } - - -Renumber RegularGG::crop(BoundingBox&) const { - NOTIMP; -} - - -Renumber RegularGG::reorder(long /*scanningMode*/) const { - NOTIMP; -} +#endif static const GridBuilder reducedGG("regular_gg"); diff --git a/src/eckit/geometry/detail/RegularGG.h b/src/eckit/geometry/detail/RegularGG.h index 80946c3c7..4c5761399 100644 --- a/src/eckit/geometry/detail/RegularGG.h +++ b/src/eckit/geometry/detail/RegularGG.h @@ -69,14 +69,11 @@ class RegularGG final : public Gaussian { // -- Overridden methods - size_t numberOfPoints() const override; + size_t size() const override; + void print(std::ostream&) const override; - Iterator* iterator() const override; bool isPeriodicWestEast() const override; - Renumber crop(BoundingBox&) const override; - Renumber reorder(long scanningMode) const override; - // -- Class members // None diff --git a/src/eckit/geometry/detail/RegularGrid.cc b/src/eckit/geometry/detail/RegularGrid.cc index 5ccd07deb..3617b282e 100644 --- a/src/eckit/geometry/detail/RegularGrid.cc +++ b/src/eckit/geometry/detail/RegularGrid.cc @@ -111,7 +111,7 @@ void RegularGrid::print(std::ostream& out) const { } -size_t RegularGrid::numberOfPoints() const { +size_t RegularGrid::size() const { return x_.size() * y_.size(); } @@ -131,16 +131,7 @@ bool RegularGrid::includesSouthPole() const { } -Renumber RegularGrid::crop(BoundingBox& bbox) const { - NOTIMP; -} - - -Renumber RegularGrid::reorder(long /*scanningMode*/) const { - NOTIMP; -} - - +#if 0 Iterator* RegularGrid::iterator() const { class RegularGridIterator : public Iterator { const Projection& projection_; @@ -197,6 +188,7 @@ Iterator* RegularGrid::iterator() const { return new RegularGridIterator(*projection_, x_, y_); } +#endif struct Lambert : RegularGrid { diff --git a/src/eckit/geometry/detail/RegularGrid.h b/src/eckit/geometry/detail/RegularGrid.h index df8f5a434..531b8e0e6 100644 --- a/src/eckit/geometry/detail/RegularGrid.h +++ b/src/eckit/geometry/detail/RegularGrid.h @@ -53,8 +53,7 @@ class RegularGrid : public Grid { // None // -- Overridden methods - - Iterator* iterator() const override; + // None // -- Class members // None @@ -89,10 +88,7 @@ class RegularGrid : public Grid { bool isPeriodicWestEast() const override; void print(std::ostream&) const override; - size_t numberOfPoints() const override; - - Renumber crop(BoundingBox&) const override; - Renumber reorder(long scanningMode) const override; + size_t size() const override; // -- Class members // None diff --git a/src/eckit/geometry/detail/RegularLL.cc b/src/eckit/geometry/detail/RegularLL.cc index dd3a5953a..808c12866 100644 --- a/src/eckit/geometry/detail/RegularLL.cc +++ b/src/eckit/geometry/detail/RegularLL.cc @@ -137,17 +137,6 @@ RegularLL::RegularLL(const Increments& increments, const BoundingBox& bb, const } -Renumber RegularLL::crop(BoundingBox&) const { - NOTIMP; -} - - -Renumber RegularLL::reorder(long scanningMode) const { - NOTIMP; - // grib_reorder(values, scanningMode, ni_, nj_); -} - - void RegularLL::print(std::ostream& out) const { out << "RegularLL[" << "bbox=" << bbox() << ",increments=" << increments_ << ",ni=" << ni_ << ",nj=" << nj_ << "]"; @@ -172,7 +161,7 @@ bool RegularLL::includesSouthPole() const { } -size_t RegularLL::numberOfPoints() const { +size_t RegularLL::size() const { ASSERT(ni_); ASSERT(nj_); return ni_ * nj_; @@ -211,6 +200,7 @@ BoundingBox RegularLL::correctBoundingBox(const BoundingBox& box, size_t& ni, si } +#if 0 Iterator* RegularLL::iterator() const { class RegularLLIterator : public Iterator { @@ -298,6 +288,7 @@ Iterator* RegularLL::iterator() const { return new RegularLLIterator(ni_, nj_, bbox().north(), bbox().west(), increments_); } +#endif static const GridBuilder regularLL("regular_ll"); diff --git a/src/eckit/geometry/detail/RegularLL.h b/src/eckit/geometry/detail/RegularLL.h index eb1e4dfe1..dd96e1437 100644 --- a/src/eckit/geometry/detail/RegularLL.h +++ b/src/eckit/geometry/detail/RegularLL.h @@ -70,11 +70,7 @@ class RegularLL : public Grid { bool isPeriodicWestEast() const override; bool includesNorthPole() const override; bool includesSouthPole() const override; - size_t numberOfPoints() const override; - Iterator* iterator() const override; - - Renumber crop(BoundingBox&) const override; - Renumber reorder(long scanningMode) const override; + size_t size() const override; // -- Class members // None diff --git a/src/eckit/geometry/detail/UnstructuredGrid.cc b/src/eckit/geometry/detail/UnstructuredGrid.cc index 62903bc60..a2eb1d29b 100644 --- a/src/eckit/geometry/detail/UnstructuredGrid.cc +++ b/src/eckit/geometry/detail/UnstructuredGrid.cc @@ -180,37 +180,16 @@ UnstructuredGrid::~UnstructuredGrid() = default; void UnstructuredGrid::print(std::ostream& out) const { - out << "UnstructuredGrid[points=" << numberOfPoints() << "]"; + out << "UnstructuredGrid[points=" << size() << "]"; } -Domain UnstructuredGrid::domain() const { - // FIXME Should be global? - return {bbox().north(), bbox().west(), bbox().south(), bbox().east()}; -} - - -size_t UnstructuredGrid::numberOfPoints() const { +size_t UnstructuredGrid::size() const { ASSERT(latitudes_.size() == longitudes_.size()); return latitudes_.size(); } -Renumber UnstructuredGrid::crop(BoundingBox&) const { - NOTIMP; -} - - -Renumber UnstructuredGrid::reorder(long scanningMode) const { - NOTIMP; -} - - -Iterator* UnstructuredGrid::iterator() const { - return new detail::UnstructuredIterator(latitudes_, longitudes_); -} - - bool UnstructuredGrid::isPeriodicWestEast() const { return bbox().east() - bbox().west() == GLOBE; } diff --git a/src/eckit/geometry/detail/UnstructuredGrid.h b/src/eckit/geometry/detail/UnstructuredGrid.h index 5dea08809..4a8e234cd 100644 --- a/src/eckit/geometry/detail/UnstructuredGrid.h +++ b/src/eckit/geometry/detail/UnstructuredGrid.h @@ -91,20 +91,14 @@ class UnstructuredGrid : public Grid { // None // -- Overridden methods - - Domain domain() const override; - Iterator* iterator() const override; - + // None // Domain operations bool isPeriodicWestEast() const override; bool includesNorthPole() const override; bool includesSouthPole() const override; - size_t numberOfPoints() const override; - - Renumber crop(BoundingBox&) const override; - Renumber reorder(long scanningMode) const override; + size_t size() const override; // -- Class members // None diff --git a/src/eckit/geometry/projection/Rotation.cc b/src/eckit/geometry/projection/Rotation.cc index 0d34df9b2..4ad48079a 100644 --- a/src/eckit/geometry/projection/Rotation.cc +++ b/src/eckit/geometry/projection/Rotation.cc @@ -28,6 +28,10 @@ namespace eckit::geometry::projection { static ProjectionBuilder __projection("rotation"); +Rotation::Rotation() : + Rotation(-90., 0., 0.) {} + + Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : rotated_(true) { using M = maths::Matrix3; diff --git a/src/eckit/geometry/projection/Rotation.h b/src/eckit/geometry/projection/Rotation.h index c61c5bda2..4a69450dd 100644 --- a/src/eckit/geometry/projection/Rotation.h +++ b/src/eckit/geometry/projection/Rotation.h @@ -28,6 +28,7 @@ class Rotation final : public Projection { // -- Constructors + Rotation(); Rotation(double south_pole_lon, double south_pole_lat, double angle); explicit Rotation(const Configuration&); diff --git a/tests/geometry/CMakeLists.txt b/tests/geometry/CMakeLists.txt index 2f76c49a1..2ce209265 100644 --- a/tests/geometry/CMakeLists.txt +++ b/tests/geometry/CMakeLists.txt @@ -1,6 +1,7 @@ foreach( _test coordinate_helpers great_circle + grid iterator kdtree kpoint diff --git a/tests/geometry/test_grid.cc b/tests/geometry/test_grid.cc index 3bbc35ff4..2147eabca 100644 --- a/tests/geometry/test_grid.cc +++ b/tests/geometry/test_grid.cc @@ -10,23 +10,49 @@ */ -#include +#include -#include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Scanner.h" -// #include "eckit/geometry/iterator/IteratorAggregator.h" -// #include "eckit/geometry/iterator/IteratorComposer.h" +#include "eckit/config/MappedConfiguration.h" +#include "eckit/geometry/Grid.h" +#include "eckit/testing/Test.h" -int main(int argc, const char* argv[]) { - // eckit::geometry::iterator::IteratorComposer i(nullptr); +namespace eckit::test { - // struct ScannerTest : public eckit::grid::Scanner { - // bool operator++() override { NOTIMP; } - // size_t size() const override { NOTIMP; } - // }; - // eckit::grid::iterator::IteratorAggregator j; +using namespace geometry; - return 0; + +CASE("GridFactory::build") { + SECTION("GridFactory::build_from_name") { + std::unique_ptr grid(GridFactory::build_from_name("O2")); + + auto size = grid->size(); + EXPECT_EQUAL(size, 88); + } + + + SECTION("GridFactory::build_from_uid") { + } + + + SECTION("GridFactory::build_from_increments") { + } + + + SECTION("GridFactory::build") { + std::unique_ptr grid(GridFactory::build(MappedConfiguration{ + {{"grid", "O2"}}})); + + auto size = grid->size(); + EXPECT_EQUAL(size, 88); + } +} + + +} // namespace eckit::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); } From 0f0bac5dd7f04aad6c261e84e3f4f45e787e5753 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 6 Jul 2023 10:03:06 +0100 Subject: [PATCH 251/737] eckit::geometry --- src/eckit/geometry/BoundingBox.cc | 2 +- src/eckit/geometry/Domain.cc | 2 +- src/eckit/geometry/Earth.h | 2 +- src/eckit/geometry/Point.h | 6 ------ src/eckit/geometry/Point2.h | 4 ++-- src/eckit/geometry/Point3.h | 2 +- src/eckit/geometry/Search.h | 8 ++++---- src/eckit/geometry/projection/LonLatToXYZ.cc | 4 ++-- src/eckit/geometry/projection/Rotation.cc | 3 +-- 9 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/eckit/geometry/BoundingBox.cc b/src/eckit/geometry/BoundingBox.cc index 6e84a14f2..1edbb06f9 100644 --- a/src/eckit/geometry/BoundingBox.cc +++ b/src/eckit/geometry/BoundingBox.cc @@ -142,7 +142,7 @@ double BoundingBox::area(double radius) const { double latf = 0.5 * (sn - ss); ASSERT(0. <= latf && latf <= 1.); - return geometry::Sphere::area(radius) * latf * lonf; + return Sphere::area(radius) * latf * lonf; } diff --git a/src/eckit/geometry/Domain.cc b/src/eckit/geometry/Domain.cc index 1f92c3ce6..a93336b91 100644 --- a/src/eckit/geometry/Domain.cc +++ b/src/eckit/geometry/Domain.cc @@ -95,7 +95,7 @@ double Domain::area(double radius) const { double latf = 0.5 * (sn - ss); ASSERT(0. <= latf && latf <= 1.); - return geometry::Sphere::area(radius) * latf * lonf; + return Sphere::area(radius) * latf * lonf; } diff --git a/src/eckit/geometry/Earth.h b/src/eckit/geometry/Earth.h index e83d70188..d892e22e2 100644 --- a/src/eckit/geometry/Earth.h +++ b/src/eckit/geometry/Earth.h @@ -33,7 +33,7 @@ struct DatumWGS84SemiMajorAxis { }; -using Earth = eckit::geometry::SphereT; +using Earth = SphereT; } // namespace eckit::geometry diff --git a/src/eckit/geometry/Point.h b/src/eckit/geometry/Point.h index b79ba971e..6fb3330b0 100644 --- a/src/eckit/geometry/Point.h +++ b/src/eckit/geometry/Point.h @@ -23,12 +23,6 @@ namespace eckit::geometry { -using geometry::Point2; -using geometry::Point3; -using geometry::PointLonLat; -using geometry::points_equal; - - using Point = std::variant; bool points_equal(const Point&, const Point&); diff --git a/src/eckit/geometry/Point2.h b/src/eckit/geometry/Point2.h index 0c9952542..054731c91 100644 --- a/src/eckit/geometry/Point2.h +++ b/src/eckit/geometry/Point2.h @@ -26,7 +26,7 @@ namespace eckit::geometry { //------------------------------------------------------------------------------------------------------ -class Point2 : public eckit::geometry::KPoint<2> { +class Point2 : public KPoint<2> { using BasePoint = KPoint<2>; public: @@ -57,7 +57,7 @@ class Point2 : public eckit::geometry::KPoint<2> { double& Y = x_[YY]; - double x(size_t axis) const { return eckit::geometry::KPoint<2>::x(axis); } + double x(size_t axis) const { return KPoint<2>::x(axis); } Point2& operator=(const Point2& other) { x_[0] = other[0]; diff --git a/src/eckit/geometry/Point3.h b/src/eckit/geometry/Point3.h index aefbe9c9d..20ba41648 100644 --- a/src/eckit/geometry/Point3.h +++ b/src/eckit/geometry/Point3.h @@ -18,7 +18,7 @@ namespace eckit::geometry { //------------------------------------------------------------------------------------------------------ -class Point3 : public eckit::geometry::KPoint<3> { +class Point3 : public KPoint<3> { using BasePoint = KPoint<3>; public: diff --git a/src/eckit/geometry/Search.h b/src/eckit/geometry/Search.h index e31a8d27e..31f7cc9af 100644 --- a/src/eckit/geometry/Search.h +++ b/src/eckit/geometry/Search.h @@ -32,14 +32,14 @@ struct Traits { } // namespace search -using Search3 = KDTreeMemory>; +using Search3 = KDTreeMemory>; -using Search2 = KDTreeMemory>; +using Search2 = KDTreeMemory>; struct SearchLonLat : Search3 { - using Point = geometry::PointLonLat; + using Point = PointLonLat; using Value = SPValue, KDMemory>>; using Search3::Search3; @@ -72,7 +72,7 @@ struct SearchLonLat : Search3 { private: static Search3::Point convert(const Point& p) { - return geometry::UnitSphere::convertSphericalToCartesian(p); + return UnitSphere::convertSphericalToCartesian(p); } }; diff --git a/src/eckit/geometry/projection/LonLatToXYZ.cc b/src/eckit/geometry/projection/LonLatToXYZ.cc index cfa89adce..c3d76abff 100644 --- a/src/eckit/geometry/projection/LonLatToXYZ.cc +++ b/src/eckit/geometry/projection/LonLatToXYZ.cc @@ -29,7 +29,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { ASSERT(0. < b); struct LonLatToSphereXYZ final : Implementation { - using S = geometry::Sphere; + using S = Sphere; const double R_; explicit LonLatToSphereXYZ(double R) : @@ -43,7 +43,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { }; struct LonLatToSpheroidXYZ final : Implementation { - using S = geometry::EllipsoidOfRevolution; + using S = EllipsoidOfRevolution; const double a_; const double b_; diff --git a/src/eckit/geometry/projection/Rotation.cc b/src/eckit/geometry/projection/Rotation.cc index 4ad48079a..7871a4fdd 100644 --- a/src/eckit/geometry/projection/Rotation.cc +++ b/src/eckit/geometry/projection/Rotation.cc @@ -51,8 +51,7 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : explicit RotationMatrix(M&& R) : R_(R) {} PointLonLat operator()(const PointLonLat& p) const override { - return geometry::UnitSphere::convertCartesianToSpherical( - R_ * geometry::UnitSphere::convertSphericalToCartesian(p)); + return UnitSphere::convertCartesianToSpherical(R_ * UnitSphere::convertSphericalToCartesian(p)); } const M R_; }; From 0807def2c950a5688c1573ebe6f648eb4ffb5f13 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 12 Jul 2023 12:24:44 +0100 Subject: [PATCH 252/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 35 ++++++++++++++++++++++++++++------- src/eckit/geometry/Grid.h | 18 ++++++++---------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 31b6b3674..09af2ffa3 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -74,17 +74,28 @@ const Grid* GridFactory::build(const Configuration& config) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - std::string name; - if (!config.get("gridType", name)) { - throw SeriousBug("GridFactory: cannot get 'gridType'"); + if (Grid::UID uid; config.get("uid", uid)) { + return build_from_uid(uid); } - if (auto j = m->find(name); j != m->end()) { - return j->second->make(config); + if (Grid::Name name; config.get("name", name)) { + return config.has("area") ? config.has("rotation") ? build_from_name(name, Grid::Area(config), Grid::Rotation(config)) : build_from_name(name, Grid::Area(config)) : config.has("rotation") ? build_from_name(name, Grid::Rotation(config)) + : build_from_name(name); } - list(Log::error() << "GridFactory: unknown '" << name << "', choices are: "); - throw SeriousBug("GridFactory: unknown '" + name + "'"); + if (Grid::Type type; config.get("type", type)) { + return config.has("area") ? config.has("rotation") ? build_from_type(type, Grid::Area(config), Grid::Rotation(config)) : build_from_type(type, Grid::Area(config)) : config.has("rotation") ? build_from_type(type, Grid::Rotation(config)) + : build_from_type(type); + } + + if (config.has("increments")) { + Grid::Increments increments(config); + return config.has("area") ? config.has("rotation") ? build_from_increments(increments, Grid::Area(config), Grid::Rotation(config)) : build_from_increments(increments, Grid::Area(config)) : config.has("rotation") ? build_from_increments(increments, Grid::Rotation(config)) + : build_from_increments(increments); + } + + list(Log::error() << "GridFactory: cannot build grid, choices are: "); + throw SeriousBug("GridFactory: cannot build grid"); } @@ -103,6 +114,16 @@ const Grid* GridFactory::build_from_name(const Grid::Name&, const Grid::Rotation } +const Grid* GridFactory::build_from_type(const Grid::Type&, const Grid::Area& area, const Grid::Rotation& rotation) { + NOTIMP; +} + + +const Grid* GridFactory::build_from_type(const Grid::Type&, const Grid::Rotation& rotation) { + NOTIMP; +} + + const Grid* GridFactory::build_from_increments(const Increments&, const Grid::Area& area, const Grid::Rotation& rotation) { NOTIMP; } diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 554ae49a7..7e9b051d6 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -32,10 +32,12 @@ class Grid { public: // -- Types - using UID = std::string; - using Name = std::string; - using Rotation = projection::Rotation; - using Area = BoundingBox; + using UID = std::string; + using Name = std::string; + using Type = std::string; + using Increments = geometry::Increments; + using Rotation = projection::Rotation; + using Area = BoundingBox; // -- Exceptions // None @@ -139,15 +141,11 @@ class GridFactory { public: // This is 'const' as Grid should always be immutable static const Grid* build(const Configuration&); - - // This is 'const' as Grid should always be immutable static const Grid* build_from_uid(const Grid::UID&); - - // This is 'const' as Grid should always be immutable static const Grid* build_from_name(const Grid::Name&, const Grid::Area& = {}, const Grid::Rotation& = {}); static const Grid* build_from_name(const Grid::Name&, const Grid::Rotation&); - - // This is 'const' as Grid should always be immutable + static const Grid* build_from_type(const Grid::Type&, const Grid::Area& = {}, const Grid::Rotation& = {}); + static const Grid* build_from_type(const Grid::Type&, const Grid::Rotation&); static const Grid* build_from_increments(const Increments&, const Grid::Area& = {}, const Grid::Rotation& = {}); static const Grid* build_from_increments(const Increments&, const Grid::Rotation&); From acc682dcdd7950d1d20557b14bd243e4eed9aa14 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 12 Jul 2023 12:39:23 +0100 Subject: [PATCH 253/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 24 ++++++++++++------------ src/eckit/geometry/Grid.h | 18 +++++++++--------- src/eckit/geometry/Projection.cc | 30 +++++++++++++++++++++--------- src/eckit/geometry/Projection.h | 14 +++++++------- 4 files changed, 49 insertions(+), 37 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 09af2ffa3..1d800c2bf 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -79,19 +79,19 @@ const Grid* GridFactory::build(const Configuration& config) { } if (Grid::Name name; config.get("name", name)) { - return config.has("area") ? config.has("rotation") ? build_from_name(name, Grid::Area(config), Grid::Rotation(config)) : build_from_name(name, Grid::Area(config)) : config.has("rotation") ? build_from_name(name, Grid::Rotation(config)) - : build_from_name(name); + return config.has("area") ? config.has("rotation") ? build_from_name(name, new Grid::Area(config), ProjectionFactory::build(config)) : build_from_name(name, new Grid::Area(config)) : config.has("rotation") ? build_from_name(name, ProjectionFactory::build(config)) + : build_from_name(name); } if (Grid::Type type; config.get("type", type)) { - return config.has("area") ? config.has("rotation") ? build_from_type(type, Grid::Area(config), Grid::Rotation(config)) : build_from_type(type, Grid::Area(config)) : config.has("rotation") ? build_from_type(type, Grid::Rotation(config)) - : build_from_type(type); + return config.has("area") ? config.has("rotation") ? build_from_type(type, new Grid::Area(config), ProjectionFactory::build(config)) : build_from_type(type, new Grid::Area(config)) : config.has("rotation") ? build_from_type(type, ProjectionFactory::build(config)) + : build_from_type(type); } if (config.has("increments")) { Grid::Increments increments(config); - return config.has("area") ? config.has("rotation") ? build_from_increments(increments, Grid::Area(config), Grid::Rotation(config)) : build_from_increments(increments, Grid::Area(config)) : config.has("rotation") ? build_from_increments(increments, Grid::Rotation(config)) - : build_from_increments(increments); + return config.has("area") ? config.has("rotation") ? build_from_increments(increments, new Grid::Area(config), ProjectionFactory::build(config)) : build_from_increments(increments, new Grid::Area(config)) : config.has("rotation") ? build_from_increments(increments, ProjectionFactory::build(config)) + : build_from_increments(increments); } list(Log::error() << "GridFactory: cannot build grid, choices are: "); @@ -104,32 +104,32 @@ const Grid* GridFactory::build_from_uid(const Grid::UID& uid) { } -const Grid* GridFactory::build_from_name(const Grid::Name&, const Grid::Area& area, const Grid::Rotation& rotation) { +const Grid* GridFactory::build_from_name(const Grid::Name&, Grid::Area*, Grid::Projection*) { NOTIMP; } -const Grid* GridFactory::build_from_name(const Grid::Name&, const Grid::Rotation& rotation) { +const Grid* GridFactory::build_from_name(const Grid::Name&, Grid::Projection*) { NOTIMP; } -const Grid* GridFactory::build_from_type(const Grid::Type&, const Grid::Area& area, const Grid::Rotation& rotation) { +const Grid* GridFactory::build_from_type(const Grid::Type&, Grid::Area*, Grid::Projection*) { NOTIMP; } -const Grid* GridFactory::build_from_type(const Grid::Type&, const Grid::Rotation& rotation) { +const Grid* GridFactory::build_from_type(const Grid::Type&, Grid::Projection*) { NOTIMP; } -const Grid* GridFactory::build_from_increments(const Increments&, const Grid::Area& area, const Grid::Rotation& rotation) { +const Grid* GridFactory::build_from_increments(const Increments&, Grid::Area*, Grid::Projection*) { NOTIMP; } -const Grid* GridFactory::build_from_increments(const Increments&, const Grid::Rotation& rotation) { +const Grid* GridFactory::build_from_increments(const Increments&, Grid::Projection*) { NOTIMP; } diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 7e9b051d6..690400780 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -21,8 +21,8 @@ #include "eckit/geometry/BoundingBox.h" #include "eckit/geometry/Increments.h" #include "eckit/geometry/Point.h" +#include "eckit/geometry/Projection.h" #include "eckit/geometry/Renumber.h" -#include "eckit/geometry/projection/Rotation.h" namespace eckit::geometry { @@ -35,8 +35,8 @@ class Grid { using UID = std::string; using Name = std::string; using Type = std::string; - using Increments = geometry::Increments; - using Rotation = projection::Rotation; + using Increments = Increments; + using Projection = Projection; using Area = BoundingBox; // -- Exceptions @@ -142,12 +142,12 @@ class GridFactory { // This is 'const' as Grid should always be immutable static const Grid* build(const Configuration&); static const Grid* build_from_uid(const Grid::UID&); - static const Grid* build_from_name(const Grid::Name&, const Grid::Area& = {}, const Grid::Rotation& = {}); - static const Grid* build_from_name(const Grid::Name&, const Grid::Rotation&); - static const Grid* build_from_type(const Grid::Type&, const Grid::Area& = {}, const Grid::Rotation& = {}); - static const Grid* build_from_type(const Grid::Type&, const Grid::Rotation&); - static const Grid* build_from_increments(const Increments&, const Grid::Area& = {}, const Grid::Rotation& = {}); - static const Grid* build_from_increments(const Increments&, const Grid::Rotation&); + static const Grid* build_from_name(const Grid::Name&, Grid::Area* = nullptr, Grid::Projection* = nullptr); + static const Grid* build_from_name(const Grid::Name&, Grid::Projection*); + static const Grid* build_from_type(const Grid::Type&, Grid::Area* = nullptr, Grid::Projection* = nullptr); + static const Grid* build_from_type(const Grid::Type&, Grid::Projection*); + static const Grid* build_from_increments(const Increments&, Grid::Area* = nullptr, Grid::Projection* = nullptr); + static const Grid* build_from_increments(const Increments&, Grid::Projection*); static void list(std::ostream&); diff --git a/src/eckit/geometry/Projection.cc b/src/eckit/geometry/Projection.cc index 62b776d5e..9cc707417 100644 --- a/src/eckit/geometry/Projection.cc +++ b/src/eckit/geometry/Projection.cc @@ -15,6 +15,7 @@ #include #include +#include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" @@ -219,28 +220,39 @@ Projection centre (grib2/tables/30/3.5.table) #endif -static pthread_once_t __once = PTHREAD_ONCE_INIT; -static Mutex* __mutex = nullptr; -static std::map* __factories = nullptr; +static pthread_once_t __once = PTHREAD_ONCE_INIT; +static Mutex* __mutex = nullptr; +static std::map* __factories = nullptr; static void __init() { __mutex = new Mutex; - __factories = new std::map(); + __factories = new std::map(); } -Projection* ProjectionFactory::build(const ProjectionFactory::key_type& key, +Projection* ProjectionFactory::build(const Configuration& config) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + Projection::Type type; + ASSERT(config.get("type", type)); + + return build(type, config); +} + + +Projection* ProjectionFactory::build(const Projection::Type& type, const Configuration& config) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - if (auto f = __factories->find(key); f != __factories->end()) { + if (auto f = __factories->find(type); f != __factories->end()) { return f->second->make(config); } - list(Log::error() << "ProjectionFactory: unknown '" << key << "', choices are: "); - throw BadValue("ProjectionFactory: unknown '" + key + "'"); + list(Log::error() << "ProjectionFactory: unknown '" << type << "', choices are: "); + throw BadValue("ProjectionFactory: unknown '" + type + "'"); } @@ -258,7 +270,7 @@ std::ostream& ProjectionFactory::list(std::ostream& out) { } -ProjectionFactory::ProjectionFactory(const ProjectionFactory::key_type& key) : +ProjectionFactory::ProjectionFactory(const Projection::Type& key) : key_(key) { pthread_once(&__once, __init); AutoLock lock(*__mutex); diff --git a/src/eckit/geometry/Projection.h b/src/eckit/geometry/Projection.h index 4609717d5..1964aeaba 100644 --- a/src/eckit/geometry/Projection.h +++ b/src/eckit/geometry/Projection.h @@ -29,7 +29,8 @@ namespace eckit::geometry { class Projection { public: // -- Types - // None + + using Type = std::string; // -- Exceptions // None @@ -105,9 +106,8 @@ class Projection { struct ProjectionFactory { - using key_type = std::string; - - static Projection* build(const key_type&, const Configuration&); + static Projection* build(const Configuration&); + static Projection* build(const Projection::Type&, const Configuration&); static std::ostream& list(std::ostream&); ProjectionFactory(const ProjectionFactory&) = delete; @@ -118,11 +118,11 @@ struct ProjectionFactory { virtual Projection* make(const Configuration&) = 0; protected: - explicit ProjectionFactory(const key_type&); + explicit ProjectionFactory(const Projection::Type&); virtual ~ProjectionFactory(); private: - const key_type key_; + const Projection::Type key_; }; @@ -131,7 +131,7 @@ class ProjectionBuilder final : public ProjectionFactory { Projection* make(const Configuration& config) override { return new T(config); } public: - explicit ProjectionBuilder(const ProjectionFactory::key_type& key) : + explicit ProjectionBuilder(const Projection::Type& key) : ProjectionFactory(key) {} }; From 0cc1fa0d73cb5f5c96199733decdd46383e95710 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 12 Jul 2023 13:14:33 +0100 Subject: [PATCH 254/737] eckit::geometry --- src/eckit/geometry/Area.cc | 100 +++++++++++++ src/eckit/geometry/Area.h | 139 ++++++++++++++++++ src/eckit/geometry/CMakeLists.txt | 6 +- src/eckit/geometry/Grid.cc | 19 +-- src/eckit/geometry/Grid.h | 15 +- src/eckit/geometry/{ => area}/BoundingBox.cc | 6 +- src/eckit/geometry/{ => area}/BoundingBox.h | 4 +- src/eckit/geometry/detail/Gaussian.cc | 2 +- src/eckit/geometry/detail/Gaussian.h | 2 +- src/eckit/geometry/detail/GaussianIterator.cc | 2 +- src/eckit/geometry/detail/GaussianIterator.h | 6 +- src/eckit/geometry/detail/ReducedGG.cc | 6 +- src/eckit/geometry/detail/ReducedGG.h | 4 +- src/eckit/geometry/detail/RegularGG.cc | 2 +- src/eckit/geometry/detail/RegularGG.h | 2 +- src/eckit/geometry/detail/RegularGrid.cc | 6 +- src/eckit/geometry/detail/RegularGrid.h | 2 +- src/eckit/geometry/detail/RegularLL.cc | 6 +- src/eckit/geometry/detail/RegularLL.h | 6 +- src/eckit/geometry/detail/UnstructuredGrid.cc | 2 +- src/eckit/geometry/detail/UnstructuredGrid.h | 2 +- src/eckit/geometry/scanner/Reduced.cc | 2 +- src/eckit/geometry/scanner/Reduced.h | 6 +- 23 files changed, 293 insertions(+), 54 deletions(-) create mode 100644 src/eckit/geometry/Area.cc create mode 100644 src/eckit/geometry/Area.h rename src/eckit/geometry/{ => area}/BoundingBox.cc (97%) rename src/eckit/geometry/{ => area}/BoundingBox.h (97%) diff --git a/src/eckit/geometry/Area.cc b/src/eckit/geometry/Area.cc new file mode 100644 index 000000000..6106463db --- /dev/null +++ b/src/eckit/geometry/Area.cc @@ -0,0 +1,100 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/Area.h" + +#include +#include + +#include "eckit/config/Configuration.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/log/Log.h" +#include "eckit/thread/AutoLock.h" +#include "eckit/thread/Mutex.h" + + +namespace eckit::geometry { + + +static pthread_once_t __once = PTHREAD_ONCE_INIT; +static Mutex* __mutex = nullptr; +static std::map* __factories = nullptr; + + +static void __init() { + __mutex = new Mutex; + __factories = new std::map(); +} + + +Area* AreaFactory::build(const Configuration& config) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + Area::Type type; + ASSERT(config.get("type", type)); + + return build(type, config); +} + + +Area* AreaFactory::build(const Area::Type& type, + const Configuration& config) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + if (auto f = __factories->find(type); f != __factories->end()) { + return f->second->make(config); + } + + list(Log::error() << "AreaFactory: unknown '" << type << "', choices are: "); + throw BadValue("AreaFactory: unknown '" + type + "'"); +} + + +std::ostream& AreaFactory::list(std::ostream& out) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + const char* sep = "'"; + for (const auto& j : *__factories) { + out << sep << j.first << '\''; + sep = ", '"; + } + + return out; +} + + +AreaFactory::AreaFactory(const Area::Type& key) : + key_(key) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + if (auto f = __factories->find(key); f != __factories->end()) { + throw BadValue("AreaFactory: duplicate '" + key + "'"); + } + + (*__factories)[key] = this; +} + + +AreaFactory::~AreaFactory() { + AutoLock lock(*__mutex); + + if (__factories != nullptr) { + __factories->erase(key_); + } +} + + +} // namespace eckit::geometry diff --git a/src/eckit/geometry/Area.h b/src/eckit/geometry/Area.h new file mode 100644 index 000000000..359b3e9b4 --- /dev/null +++ b/src/eckit/geometry/Area.h @@ -0,0 +1,139 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + + +namespace eckit { +class Configuration; +namespace geometry::area { +class BoundingBox; +} +} // namespace eckit + + +namespace eckit::geometry { + + +class Area { +public: + // -- Types + + using Type = std::string; + + // -- Exceptions + // None + + // -- Constructors + + Area() noexcept = default; + + Area(const Area&) = default; + Area(Area&&) = default; + + // -- Destructor + + virtual ~Area() = default; + + // -- Convertors + // None + + // -- Operators + + Area& operator=(const Area&) = default; + Area& operator=(Area&&) = default; + + // -- Methods + + virtual area::BoundingBox bbox() const = 0; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +struct AreaFactory { + static Area* build(const Configuration&); + static Area* build(const Area::Type&, const Configuration&); + static std::ostream& list(std::ostream&); + + AreaFactory(const AreaFactory&) = delete; + AreaFactory(AreaFactory&&) = delete; + AreaFactory& operator=(const AreaFactory&) = delete; + AreaFactory& operator=(AreaFactory&&) = delete; + + virtual Area* make(const Configuration&) = 0; + +protected: + explicit AreaFactory(const Area::Type&); + virtual ~AreaFactory(); + +private: + const Area::Type key_; +}; + + +template +class AreaBuilder final : public AreaFactory { + Area* make(const Configuration& config) override { return new T(config); } + +public: + explicit AreaBuilder(const Area::Type& key) : + AreaFactory(key) {} +}; + + +} // namespace eckit::geometry diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index ce485c0a0..c77584bc4 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -1,6 +1,6 @@ list( APPEND eckit_geometry_srcs - BoundingBox.cc - BoundingBox.h + Area.cc + Area.h CoordinateHelpers.cc CoordinateHelpers.h Domain.cc @@ -40,6 +40,8 @@ list( APPEND eckit_geometry_srcs Sphere.h SphereT.h UnitSphere.h + area/BoundingBox.cc + area/BoundingBox.h detail/Gaussian.cc detail/Gaussian.h detail/GaussianIterator.cc diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 1d800c2bf..cf1d6adaa 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -17,9 +17,6 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Domain.h" -#include "eckit/geometry/Iterator.h" -#include "eckit/geometry/detail/UnstructuredGrid.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -32,11 +29,11 @@ Grid::Grid(const Configuration& config) : bbox_(config) {} -Grid::Grid(const BoundingBox& bbox) : +Grid::Grid(const area::BoundingBox& bbox) : bbox_(bbox) {} -const BoundingBox& Grid::boundingBox() const { +const area::BoundingBox& Grid::boundingBox() const { return bbox_; } @@ -79,19 +76,19 @@ const Grid* GridFactory::build(const Configuration& config) { } if (Grid::Name name; config.get("name", name)) { - return config.has("area") ? config.has("rotation") ? build_from_name(name, new Grid::Area(config), ProjectionFactory::build(config)) : build_from_name(name, new Grid::Area(config)) : config.has("rotation") ? build_from_name(name, ProjectionFactory::build(config)) - : build_from_name(name); + return config.has("area") ? config.has("rotation") ? build_from_name(name, AreaFactory::build(config), ProjectionFactory::build(config)) : build_from_name(name, AreaFactory::build(config)) : config.has("rotation") ? build_from_name(name, ProjectionFactory::build(config)) + : build_from_name(name); } if (Grid::Type type; config.get("type", type)) { - return config.has("area") ? config.has("rotation") ? build_from_type(type, new Grid::Area(config), ProjectionFactory::build(config)) : build_from_type(type, new Grid::Area(config)) : config.has("rotation") ? build_from_type(type, ProjectionFactory::build(config)) - : build_from_type(type); + return config.has("area") ? config.has("rotation") ? build_from_type(type, AreaFactory::build(config), ProjectionFactory::build(config)) : build_from_type(type, AreaFactory::build(config)) : config.has("rotation") ? build_from_type(type, ProjectionFactory::build(config)) + : build_from_type(type); } if (config.has("increments")) { Grid::Increments increments(config); - return config.has("area") ? config.has("rotation") ? build_from_increments(increments, new Grid::Area(config), ProjectionFactory::build(config)) : build_from_increments(increments, new Grid::Area(config)) : config.has("rotation") ? build_from_increments(increments, ProjectionFactory::build(config)) - : build_from_increments(increments); + return config.has("area") ? config.has("rotation") ? build_from_increments(increments, AreaFactory::build(config), ProjectionFactory::build(config)) : build_from_increments(increments, AreaFactory::build(config)) : config.has("rotation") ? build_from_increments(increments, ProjectionFactory::build(config)) + : build_from_increments(increments); } list(Log::error() << "GridFactory: cannot build grid, choices are: "); diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 690400780..b8843fd5f 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -18,11 +18,12 @@ #include #include "eckit/config/Configuration.h" -#include "eckit/geometry/BoundingBox.h" +#include "eckit/geometry/Area.h" #include "eckit/geometry/Increments.h" #include "eckit/geometry/Point.h" #include "eckit/geometry/Projection.h" #include "eckit/geometry/Renumber.h" +#include "eckit/geometry/area/BoundingBox.h" namespace eckit::geometry { @@ -37,7 +38,7 @@ class Grid { using Type = std::string; using Increments = Increments; using Projection = Projection; - using Area = BoundingBox; + using Area = Area; // -- Exceptions // None @@ -64,7 +65,7 @@ class Grid { // -- Methods - virtual const BoundingBox& boundingBox() const; + virtual const area::BoundingBox& boundingBox() const; virtual size_t size() const = 0; @@ -86,14 +87,14 @@ class Grid { protected: // -- Constructors - Grid(const BoundingBox&); + Grid(const area::BoundingBox&); // None // -- Methods - const BoundingBox& bbox() const { return bbox_; } - void bbox(const BoundingBox& bbox) { bbox_ = bbox; } + area::BoundingBox bbox() const { return bbox_; } + void bbox(const area::BoundingBox& bbox) { bbox_ = bbox; } // -- Overridden methods // None @@ -107,7 +108,7 @@ class Grid { private: // -- Members - BoundingBox bbox_; + area::BoundingBox bbox_; // -- Methods // None diff --git a/src/eckit/geometry/BoundingBox.cc b/src/eckit/geometry/area/BoundingBox.cc similarity index 97% rename from src/eckit/geometry/BoundingBox.cc rename to src/eckit/geometry/area/BoundingBox.cc index 1edbb06f9..fc4052eb6 100644 --- a/src/eckit/geometry/BoundingBox.cc +++ b/src/eckit/geometry/area/BoundingBox.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/BoundingBox.h" +#include "eckit/geometry/area/BoundingBox.h" #include #include @@ -23,7 +23,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geometry { +namespace eckit::geometry::area { BoundingBox::BoundingBox(const Configuration& config) : @@ -151,4 +151,4 @@ BoundingBox BoundingBox::make(const BoundingBox&, const Projection&) { } -} // namespace eckit::geometry +} // namespace eckit::geometry::area diff --git a/src/eckit/geometry/BoundingBox.h b/src/eckit/geometry/area/BoundingBox.h similarity index 97% rename from src/eckit/geometry/BoundingBox.h rename to src/eckit/geometry/area/BoundingBox.h index 858c19b5a..56d309ca1 100644 --- a/src/eckit/geometry/BoundingBox.h +++ b/src/eckit/geometry/area/BoundingBox.h @@ -24,7 +24,7 @@ class Projection; } // namespace eckit -namespace eckit::geometry { +namespace eckit::geometry::area { class BoundingBox { @@ -132,4 +132,4 @@ class BoundingBox { }; -} // namespace eckit::geometry +} // namespace eckit::geometry::area diff --git a/src/eckit/geometry/detail/Gaussian.cc b/src/eckit/geometry/detail/Gaussian.cc index 14e0c4ba5..5ba2a9a8f 100644 --- a/src/eckit/geometry/detail/Gaussian.cc +++ b/src/eckit/geometry/detail/Gaussian.cc @@ -25,7 +25,7 @@ namespace eckit::geometry::detail { -Gaussian::Gaussian(size_t N, const BoundingBox& bbox) : +Gaussian::Gaussian(size_t N, const area::BoundingBox& bbox) : Grid(bbox), N_(N), angularPrecision_(0) { ASSERT(N_ > 0); } diff --git a/src/eckit/geometry/detail/Gaussian.h b/src/eckit/geometry/detail/Gaussian.h index c5a6f4757..dd4fe1cde 100644 --- a/src/eckit/geometry/detail/Gaussian.h +++ b/src/eckit/geometry/detail/Gaussian.h @@ -25,7 +25,7 @@ class Gaussian : public Grid { // -- Constructors - Gaussian(size_t N, const BoundingBox& = {}); + Gaussian(size_t N, const area::BoundingBox& = {}); Gaussian(const Configuration&); // -- Destructor diff --git a/src/eckit/geometry/detail/GaussianIterator.cc b/src/eckit/geometry/detail/GaussianIterator.cc index 9f05dbb17..67a1d5434 100644 --- a/src/eckit/geometry/detail/GaussianIterator.cc +++ b/src/eckit/geometry/detail/GaussianIterator.cc @@ -21,7 +21,7 @@ namespace eckit::geometry::detail { GaussianIterator::GaussianIterator(const std::vector& latitudes, std::vector&& pl, - const BoundingBox& bbox, size_t N, size_t Nj, size_t k) : + const area::BoundingBox& bbox, size_t N, size_t Nj, size_t k) : latitudes_(latitudes), pl_(pl), bbox_(bbox), diff --git a/src/eckit/geometry/detail/GaussianIterator.h b/src/eckit/geometry/detail/GaussianIterator.h index 23c393568..168161824 100644 --- a/src/eckit/geometry/detail/GaussianIterator.h +++ b/src/eckit/geometry/detail/GaussianIterator.h @@ -16,9 +16,9 @@ #include "eckit/types/Fraction.h" -#include "eckit/geometry/BoundingBox.h" #include "eckit/geometry/Iterator.h" #include "eckit/geometry/Projection.h" +#include "eckit/geometry/area/BoundingBox.h" namespace eckit::geometry::detail { @@ -26,14 +26,14 @@ namespace eckit::geometry::detail { class GaussianIterator : public Iterator { public: - GaussianIterator(const std::vector& latitudes, std::vector&& pl, const BoundingBox&, size_t N, + GaussianIterator(const std::vector& latitudes, std::vector&& pl, const area::BoundingBox&, size_t N, size_t Nj, size_t k); ~GaussianIterator() override; private: const std::vector& latitudes_; const std::vector pl_; - const BoundingBox& bbox_; + const area::BoundingBox& bbox_; const size_t N_; size_t Ni_; size_t Nj_; diff --git a/src/eckit/geometry/detail/ReducedGG.cc b/src/eckit/geometry/detail/ReducedGG.cc index 5b5f90f49..b69d7f478 100644 --- a/src/eckit/geometry/detail/ReducedGG.cc +++ b/src/eckit/geometry/detail/ReducedGG.cc @@ -213,7 +213,7 @@ void ReducedGG::print(std::ostream& out) const { struct ReducedGGClassic : ReducedGG { - ReducedGGClassic(size_t N, const BoundingBox& box = BoundingBox()) : + ReducedGGClassic(size_t N, const area::BoundingBox& box = {}) : ReducedGG(N, box) { // adjust latitudes, longitudes and re-set bounding box @@ -235,13 +235,13 @@ struct ReducedGGClassic : ReducedGG { struct ReducedGGFromPL : ReducedGG { ReducedGGFromPL(const Configuration& config) : ReducedGG(config) {} - ReducedGGFromPL(size_t N, const pl_type& pl, const BoundingBox& box = BoundingBox()) : + ReducedGGFromPL(size_t N, const pl_type& pl, const area::BoundingBox& box = {}) : ReducedGG(N, pl, box) {} }; struct ReducedGGOctahedral : ReducedGG { - ReducedGGOctahedral(size_t N, const BoundingBox& box = BoundingBox()) : + ReducedGGOctahedral(size_t N, const area::BoundingBox& box = {}) : ReducedGG(N, box) { // adjust latitudes, longitudes and re-set bounding box diff --git a/src/eckit/geometry/detail/ReducedGG.h b/src/eckit/geometry/detail/ReducedGG.h index e8f3c0065..4154d67de 100644 --- a/src/eckit/geometry/detail/ReducedGG.h +++ b/src/eckit/geometry/detail/ReducedGG.h @@ -33,7 +33,7 @@ class ReducedGG : public Gaussian { ReducedGG(const Configuration&); - ReducedGG(size_t N, const pl_type& pl, const BoundingBox& box = BoundingBox()) : + ReducedGG(size_t N, const pl_type& pl, const area::BoundingBox& box = {}) : Gaussian(N, box), k_(0), Nj_(N_ * 2) { setNj(pl, box.south(), box.north()); } @@ -64,7 +64,7 @@ class ReducedGG : public Gaussian { protected: // -- Constructors - ReducedGG(size_t N, const BoundingBox& box = BoundingBox()) : + ReducedGG(size_t N, const area::BoundingBox& box = {}) : Gaussian(N, box), k_(0), Nj_(N * 2) { // derived classes must set k_, Nj_ using this constructor } diff --git a/src/eckit/geometry/detail/RegularGG.cc b/src/eckit/geometry/detail/RegularGG.cc index 0edc9c942..e4a315816 100644 --- a/src/eckit/geometry/detail/RegularGG.cc +++ b/src/eckit/geometry/detail/RegularGG.cc @@ -42,7 +42,7 @@ RegularGG::RegularGG(const Configuration& config) : } -RegularGG::RegularGG(size_t N, const BoundingBox& box) : +RegularGG::RegularGG(size_t N, const area::BoundingBox& box) : Gaussian(N, box), k_(0), Ni_(0), Nj_(0) { // adjust latitudes, longitudes and re-set bounding box diff --git a/src/eckit/geometry/detail/RegularGG.h b/src/eckit/geometry/detail/RegularGG.h index 4c5761399..2d76c841f 100644 --- a/src/eckit/geometry/detail/RegularGG.h +++ b/src/eckit/geometry/detail/RegularGG.h @@ -31,7 +31,7 @@ class RegularGG final : public Gaussian { // -- Constructors RegularGG(const Configuration&); - RegularGG(size_t N, const BoundingBox& = BoundingBox()); + RegularGG(size_t N, const area::BoundingBox& = {}); // -- Destructor // None diff --git a/src/eckit/geometry/detail/RegularGrid.cc b/src/eckit/geometry/detail/RegularGrid.cc index 3617b282e..3bac9359b 100644 --- a/src/eckit/geometry/detail/RegularGrid.cc +++ b/src/eckit/geometry/detail/RegularGrid.cc @@ -78,11 +78,11 @@ RegularGrid::RegularGrid(Projection* projection, const Configuration& config) : auto w = x_.front() > x_.back() ? x_.back() : x_.front(); auto e = x_.front() > x_.back() ? x_.front() : x_.back(); - bbox(BoundingBox::make({n, w, s, e}, *projection_)); + bbox(area::BoundingBox::make({n, w, s, e}, *projection_)); } -RegularGrid::RegularGrid(Projection* projection, const BoundingBox& bbox, const LinearSpacing& x, +RegularGrid::RegularGrid(Projection* projection, const area::BoundingBox& bbox, const LinearSpacing& x, const LinearSpacing& y, const Figure& figure) : Grid(bbox), x_(x), @@ -220,7 +220,7 @@ struct LambertAzimuthalEqualArea : RegularGrid { LambertAzimuthalEqualArea(const Configuration& config) : RegularGrid(make_projection(config), config) {} - LambertAzimuthalEqualArea(Projection* projection, const BoundingBox& bbox, const LinearSpacing& x, const LinearSpacing& y, const Figure& shape) : + LambertAzimuthalEqualArea(Projection* projection, const area::BoundingBox& bbox, const LinearSpacing& x, const LinearSpacing& y, const Figure& shape) : RegularGrid(projection, bbox, x, y, shape) {} static Projection* make_projection(const Configuration& config) { diff --git a/src/eckit/geometry/detail/RegularGrid.h b/src/eckit/geometry/detail/RegularGrid.h index 531b8e0e6..6cbbaf5ef 100644 --- a/src/eckit/geometry/detail/RegularGrid.h +++ b/src/eckit/geometry/detail/RegularGrid.h @@ -65,7 +65,7 @@ class RegularGrid : public Grid { // -- Constructors RegularGrid(Projection*, const Configuration&); - RegularGrid(Projection*, const BoundingBox&, const LinearSpacing& x, const LinearSpacing& y, + RegularGrid(Projection*, const area::BoundingBox&, const LinearSpacing& x, const LinearSpacing& y, const Figure&); // -- Members diff --git a/src/eckit/geometry/detail/RegularLL.cc b/src/eckit/geometry/detail/RegularLL.cc index 808c12866..5aa747a99 100644 --- a/src/eckit/geometry/detail/RegularLL.cc +++ b/src/eckit/geometry/detail/RegularLL.cc @@ -129,7 +129,7 @@ RegularLL::RegularLL(const Configuration& config) : } -RegularLL::RegularLL(const Increments& increments, const BoundingBox& bb, const PointLonLat& reference) : +RegularLL::RegularLL(const Increments& increments, const area::BoundingBox& bb, const PointLonLat& reference) : Grid(bb), increments_(increments), reference_(reference), ni_(0), nj_(0) { bbox(correctBoundingBox(bbox(), ni_, nj_, increments_, reference_)); ASSERT(ni_ != 0); @@ -168,8 +168,8 @@ size_t RegularLL::size() const { } -BoundingBox RegularLL::correctBoundingBox(const BoundingBox& box, size_t& ni, size_t& nj, const Increments& inc, - const PointLonLat& reference) { +area::BoundingBox RegularLL::correctBoundingBox(const area::BoundingBox& box, size_t& ni, size_t& nj, const Increments& inc, + const PointLonLat& reference) { // Latitude/longitude ranges detail::RegularIterator lat{Fraction{box.south()}, Fraction{box.north()}, diff --git a/src/eckit/geometry/detail/RegularLL.h b/src/eckit/geometry/detail/RegularLL.h index dd96e1437..a377dcd63 100644 --- a/src/eckit/geometry/detail/RegularLL.h +++ b/src/eckit/geometry/detail/RegularLL.h @@ -28,7 +28,7 @@ class RegularLL : public Grid { // -- Constructors RegularLL(const Configuration&); - RegularLL(const Increments&, const BoundingBox& = {}, const PointLonLat& reference = {0, 0}); + RegularLL(const Increments&, const area::BoundingBox& = {}, const PointLonLat& reference = {0, 0}); // -- Destructor // None @@ -41,8 +41,8 @@ class RegularLL : public Grid { // -- Methods - static BoundingBox correctBoundingBox(const BoundingBox&, size_t& ni, size_t& nj, const Increments&, - const PointLonLat& reference = {0, 0}); + static area::BoundingBox correctBoundingBox(const area::BoundingBox&, size_t& ni, size_t& nj, const Increments&, + const PointLonLat& reference = {0, 0}); // -- Overridden methods // None diff --git a/src/eckit/geometry/detail/UnstructuredGrid.cc b/src/eckit/geometry/detail/UnstructuredGrid.cc index a2eb1d29b..49ddf3cf4 100644 --- a/src/eckit/geometry/detail/UnstructuredGrid.cc +++ b/src/eckit/geometry/detail/UnstructuredGrid.cc @@ -170,7 +170,7 @@ UnstructuredGrid::UnstructuredGrid(const PathName& path) { UnstructuredGrid::UnstructuredGrid(const std::vector& latitudes, const std::vector& longitudes, - const BoundingBox& bbox) : + const area::BoundingBox& bbox) : Grid(bbox), latitudes_(latitudes), longitudes_(longitudes) { ASSERT(latitudes_.size() == longitudes_.size()); } diff --git a/src/eckit/geometry/detail/UnstructuredGrid.h b/src/eckit/geometry/detail/UnstructuredGrid.h index 4a8e234cd..6533f7caf 100644 --- a/src/eckit/geometry/detail/UnstructuredGrid.h +++ b/src/eckit/geometry/detail/UnstructuredGrid.h @@ -35,7 +35,7 @@ class UnstructuredGrid : public Grid { explicit UnstructuredGrid(const PathName&); explicit UnstructuredGrid(const Configuration&); UnstructuredGrid(const std::vector& latitudes, const std::vector& longitudes, - const BoundingBox& = BoundingBox()); + const area::BoundingBox& = {}); UnstructuredGrid(const UnstructuredGrid&) = delete; UnstructuredGrid(UnstructuredGrid&&) = delete; diff --git a/src/eckit/geometry/scanner/Reduced.cc b/src/eckit/geometry/scanner/Reduced.cc index 8df15bf13..711271238 100644 --- a/src/eckit/geometry/scanner/Reduced.cc +++ b/src/eckit/geometry/scanner/Reduced.cc @@ -22,7 +22,7 @@ namespace eckit::geometry::scanner { Reduced::Reduced(const std::vector& latitudes, pl_type&& pl, - const BoundingBox& bbox, + const area::BoundingBox& bbox, size_t N, size_t Nj, size_t k) : diff --git a/src/eckit/geometry/scanner/Reduced.h b/src/eckit/geometry/scanner/Reduced.h index 84923d3da..3e30a1f41 100644 --- a/src/eckit/geometry/scanner/Reduced.h +++ b/src/eckit/geometry/scanner/Reduced.h @@ -12,9 +12,9 @@ #pragma once -#include "eckit/geometry/BoundingBox.h" #include "eckit/geometry/Point.h" #include "eckit/geometry/Scanner.h" +#include "eckit/geometry/area/BoundingBox.h" #include "eckit/geometry/util.h" #include "eckit/types/Fraction.h" @@ -31,7 +31,7 @@ class Reduced final : public Scanner { Reduced(const std::vector& latitudes, pl_type&& pl, - const BoundingBox&, + const area::BoundingBox&, size_t N, size_t Nj, size_t k); @@ -62,7 +62,7 @@ class Reduced final : public Scanner { const std::vector& latitudes_; const pl_type pl_; - const BoundingBox& bbox_; + const area::BoundingBox& bbox_; const size_t N_; size_t Ni_; size_t Nj_; From 8a6df403e71d2ea04bf2c72689ed6568f355cf04 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 12 Jul 2023 14:52:02 +0100 Subject: [PATCH 255/737] eckit::geometry --- src/eckit/geometry/projection/None.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/eckit/geometry/projection/None.cc b/src/eckit/geometry/projection/None.cc index a2fa61874..387f41d4e 100644 --- a/src/eckit/geometry/projection/None.cc +++ b/src/eckit/geometry/projection/None.cc @@ -18,6 +18,8 @@ namespace eckit::geometry::projection { static ProjectionBuilder __projection1(""); static ProjectionBuilder __projection2("none"); +static ProjectionBuilder __projection3("equirectangular"); +static ProjectionBuilder __projection4("plate-carree"); None::None(const Configuration&) {} From f2a08bd633660be7cb73f8bc3c62f17d6d4ecc2d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 24 Jul 2023 14:46:48 +0100 Subject: [PATCH 256/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 16 ++++++++-------- src/eckit/geometry/Grid.h | 13 +++++-------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index cf1d6adaa..5ee7ab5ab 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -71,16 +71,16 @@ const Grid* GridFactory::build(const Configuration& config) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - if (Grid::UID uid; config.get("uid", uid)) { + if (std::string uid; config.get("uid", uid)) { return build_from_uid(uid); } - if (Grid::Name name; config.get("name", name)) { + if (std::string name; config.get("name", name)) { return config.has("area") ? config.has("rotation") ? build_from_name(name, AreaFactory::build(config), ProjectionFactory::build(config)) : build_from_name(name, AreaFactory::build(config)) : config.has("rotation") ? build_from_name(name, ProjectionFactory::build(config)) : build_from_name(name); } - if (Grid::Type type; config.get("type", type)) { + if (std::string type; config.get("type", type)) { return config.has("area") ? config.has("rotation") ? build_from_type(type, AreaFactory::build(config), ProjectionFactory::build(config)) : build_from_type(type, AreaFactory::build(config)) : config.has("rotation") ? build_from_type(type, ProjectionFactory::build(config)) : build_from_type(type); } @@ -96,27 +96,27 @@ const Grid* GridFactory::build(const Configuration& config) { } -const Grid* GridFactory::build_from_uid(const Grid::UID& uid) { +const Grid* GridFactory::build_from_uid(const std::string& uid) { NOTIMP; } -const Grid* GridFactory::build_from_name(const Grid::Name&, Grid::Area*, Grid::Projection*) { +const Grid* GridFactory::build_from_name(const std::string&, Grid::Area*, Grid::Projection*) { NOTIMP; } -const Grid* GridFactory::build_from_name(const Grid::Name&, Grid::Projection*) { +const Grid* GridFactory::build_from_name(const std::string&, Grid::Projection*) { NOTIMP; } -const Grid* GridFactory::build_from_type(const Grid::Type&, Grid::Area*, Grid::Projection*) { +const Grid* GridFactory::build_from_type(const std::string&, Grid::Area*, Grid::Projection*) { NOTIMP; } -const Grid* GridFactory::build_from_type(const Grid::Type&, Grid::Projection*) { +const Grid* GridFactory::build_from_type(const std::string&, Grid::Projection*) { NOTIMP; } diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index b8843fd5f..bdbe82642 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -33,9 +33,6 @@ class Grid { public: // -- Types - using UID = std::string; - using Name = std::string; - using Type = std::string; using Increments = Increments; using Projection = Projection; using Area = Area; @@ -142,11 +139,11 @@ class GridFactory { public: // This is 'const' as Grid should always be immutable static const Grid* build(const Configuration&); - static const Grid* build_from_uid(const Grid::UID&); - static const Grid* build_from_name(const Grid::Name&, Grid::Area* = nullptr, Grid::Projection* = nullptr); - static const Grid* build_from_name(const Grid::Name&, Grid::Projection*); - static const Grid* build_from_type(const Grid::Type&, Grid::Area* = nullptr, Grid::Projection* = nullptr); - static const Grid* build_from_type(const Grid::Type&, Grid::Projection*); + static const Grid* build_from_uid(const std::string&); + static const Grid* build_from_name(const std::string&, Grid::Area* = nullptr, Grid::Projection* = nullptr); + static const Grid* build_from_name(const std::string&, Grid::Projection*); + static const Grid* build_from_type(const std::string&, Grid::Area* = nullptr, Grid::Projection* = nullptr); + static const Grid* build_from_type(const std::string&, Grid::Projection*); static const Grid* build_from_increments(const Increments&, Grid::Area* = nullptr, Grid::Projection* = nullptr); static const Grid* build_from_increments(const Increments&, Grid::Projection*); From 03b20236ecdc38f22d30b3f637bf2efd1e49f31c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 25 Jul 2023 00:13:02 +0100 Subject: [PATCH 257/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 175 +++++++++++++----- src/eckit/geometry/Grid.h | 111 ++++++++--- src/eckit/geometry/detail/IrregularLatlon.cc | 2 +- src/eckit/geometry/detail/ReducedGG.cc | 2 +- src/eckit/geometry/detail/ReducedLL.cc | 2 +- src/eckit/geometry/detail/RegularGG.cc | 2 +- src/eckit/geometry/detail/RegularGrid.cc | 8 +- src/eckit/geometry/detail/RegularLL.cc | 2 +- src/eckit/geometry/detail/UnstructuredGrid.cc | 4 +- tests/geometry/test_grid.cc | 8 +- 10 files changed, 231 insertions(+), 85 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 5ee7ab5ab..cd70b38cd 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include "eckit/exception/Exceptions.h" #include "eckit/log/Log.h" @@ -39,104 +40,194 @@ const area::BoundingBox& Grid::boundingBox() const { static pthread_once_t __once; -static Mutex* __mutex = nullptr; -static std::map* m = nullptr; + +static Mutex* __mutex = nullptr; +static std::map* __grid_uids = nullptr; +static std::map* __grid_names = nullptr; +static std::map* __grid_types = nullptr; + static void __init() { - __mutex = new Mutex; - m = new std::map(); + __mutex = new Mutex; + __grid_uids = new std::remove_reference::type; + __grid_names = new std::remove_reference::type; + __grid_types = new std::remove_reference::type; } -GridFactory::GridFactory(const std::string& name) : - name_(name) { +const Grid* GridFactory::build(const Configuration& config) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - if (m->find(name) != m->end()) { - throw SeriousBug("GridFactory: duplicate '" + name + "'"); + if (std::string uid; config.get("uid", uid)) { + return GridFactoryUID::build(uid); + } + + if (std::string name; config.get("name", name)) { + return config.has("area") ? config.has("rotation") ? GridFactoryName::build(name, AreaFactory::build(config), ProjectionFactory::build(config)) : GridFactoryName::build(name, AreaFactory::build(config)) : config.has("rotation") ? GridFactoryName::build(name, ProjectionFactory::build(config)) + : GridFactoryName::build(name); + } + + if (std::string type; config.get("type", type)) { + return config.has("area") ? config.has("rotation") ? GridFactoryType::build(type, AreaFactory::build(config), ProjectionFactory::build(config)) : GridFactoryType::build(type, AreaFactory::build(config)) : config.has("rotation") ? GridFactoryType::build(type, ProjectionFactory::build(config)) + : GridFactoryType::build(type); } - (*m)[name] = this; + list(Log::error() << "Grid: cannot build grid, choices are: "); + throw SeriousBug("Grid: cannot build grid"); } -GridFactory::~GridFactory() { +void GridFactory::list(std::ostream& out) { + pthread_once(&__once, __init); AutoLock lock(*__mutex); - m->erase(name_); + GridFactoryUID::list(out); + GridFactoryName::list(out); + GridFactoryType::list(out); } -const Grid* GridFactory::build(const Configuration& config) { +GridFactoryUID::GridFactoryUID(const std::string& uid) : + uid_(uid) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - if (std::string uid; config.get("uid", uid)) { - return build_from_uid(uid); + if (__grid_uids->find(uid) == __grid_uids->end()) { + (*__grid_uids)[uid] = this; + return; } - if (std::string name; config.get("name", name)) { - return config.has("area") ? config.has("rotation") ? build_from_name(name, AreaFactory::build(config), ProjectionFactory::build(config)) : build_from_name(name, AreaFactory::build(config)) : config.has("rotation") ? build_from_name(name, ProjectionFactory::build(config)) - : build_from_name(name); + throw SeriousBug("Grid: duplicate identifier '" + uid + "'"); +} + + +GridFactoryUID::~GridFactoryUID() { + AutoLock lock(*__mutex); + __grid_uids->erase(uid_); +} + + +const Grid* GridFactoryUID::build(const std::string& uid) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + if (auto j = __grid_uids->find(uid); j != __grid_uids->end()) { + return j->second->make(); } - if (std::string type; config.get("type", type)) { - return config.has("area") ? config.has("rotation") ? build_from_type(type, AreaFactory::build(config), ProjectionFactory::build(config)) : build_from_type(type, AreaFactory::build(config)) : config.has("rotation") ? build_from_type(type, ProjectionFactory::build(config)) - : build_from_type(type); + list(Log::error() << "Grid: unknown identifier '" << uid << "', choices are: "); + throw SeriousBug("Grid: unknown identifier '" + uid + "'"); +} + + +void GridFactoryUID::list(std::ostream& out) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + const char* sep = ""; + for (const auto& j : *__grid_uids) { + out << sep << j.first; + sep = ", "; } +} + - if (config.has("increments")) { - Grid::Increments increments(config); - return config.has("area") ? config.has("rotation") ? build_from_increments(increments, AreaFactory::build(config), ProjectionFactory::build(config)) : build_from_increments(increments, AreaFactory::build(config)) : config.has("rotation") ? build_from_increments(increments, ProjectionFactory::build(config)) - : build_from_increments(increments); +GridFactoryName::GridFactoryName(const std::string& name) : + name_(name) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + if (__grid_names->find(name) == __grid_names->end()) { + (*__grid_names)[name] = this; + return; } - list(Log::error() << "GridFactory: cannot build grid, choices are: "); - throw SeriousBug("GridFactory: cannot build grid"); + throw SeriousBug("Grid: duplicate name '" + name + "'"); } -const Grid* GridFactory::build_from_uid(const std::string& uid) { - NOTIMP; +const Grid* GridFactoryName::build(const std::string& name, Area* area, Projection* projection) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + if (auto j = __grid_names->find(name); j != __grid_names->end()) { + NOTIMP; + // return j->second->make(name, area, projection); + } + + list(Log::error() << "Grid: unknown name '" << name << "', choices are: "); + throw SeriousBug("Grid: unknown name '" + name + "'"); } -const Grid* GridFactory::build_from_name(const std::string&, Grid::Area*, Grid::Projection*) { - NOTIMP; +const Grid* GridFactoryName::build(const std::string& name, Projection* projection) { + return build(name, nullptr, projection); } -const Grid* GridFactory::build_from_name(const std::string&, Grid::Projection*) { - NOTIMP; +void GridFactoryName::list(std::ostream& out) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + const char* sep = ""; + for (const auto& j : *__grid_names) { + out << sep << j.first; + sep = ", "; + } } -const Grid* GridFactory::build_from_type(const std::string&, Grid::Area*, Grid::Projection*) { - NOTIMP; +GridFactoryName::~GridFactoryName() { + AutoLock lock(*__mutex); + __grid_names->erase(name_); } -const Grid* GridFactory::build_from_type(const std::string&, Grid::Projection*) { - NOTIMP; +GridFactoryType::GridFactoryType(const std::string& type) : + type_(type) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + if (__grid_types->find(type) == __grid_types->end()) { + (*__grid_types)[type] = this; + return; + } + + throw SeriousBug("Grid: duplicate type '" + type + "'"); } -const Grid* GridFactory::build_from_increments(const Increments&, Grid::Area*, Grid::Projection*) { - NOTIMP; +GridFactoryType::~GridFactoryType() { + AutoLock lock(*__mutex); + __grid_types->erase(type_); } -const Grid* GridFactory::build_from_increments(const Increments&, Grid::Projection*) { - NOTIMP; +const Grid* GridFactoryType::build(const std::string& type, Area* area, Projection* projection) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + if (auto j = __grid_types->find(type); j != __grid_types->end()) { + NOTIMP; + // return j->second->make(type, area, projection); + } + + list(Log::error() << "Grid: unknown type '" << type << "', choices are: "); + throw SeriousBug("Grid: unknown type '" + type + "'"); } -void GridFactory::list(std::ostream& out) { +const Grid* GridFactoryType::build(const std::string& type, Projection* projection) { + return build(type, nullptr, projection); +} + + +void GridFactoryType::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); const char* sep = ""; - for (const auto& j : *m) { + for (const auto& j : *__grid_types) { out << sep << j.first; sep = ", "; } diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index bdbe82642..95a306ff4 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -32,10 +32,7 @@ namespace eckit::geometry { class Grid { public: // -- Types - - using Increments = Increments; - using Projection = Projection; - using Area = Area; + // None // -- Exceptions // None @@ -128,41 +125,99 @@ class Grid { }; -class GridFactory { - std::string name_; - virtual Grid* make(const Configuration&) = 0; +static struct GridFactory { + // This is 'const' as Grid should always be immutable + static const Grid* build(const Configuration&); + static void list(std::ostream&); +}; -protected: - explicit GridFactory(const std::string&); - virtual ~GridFactory(); -public: +struct GridFactoryUID { + explicit GridFactoryUID(const std::string& uid); + virtual ~GridFactoryUID(); + + virtual const Grid* make() = 0; + + GridFactoryUID(const GridFactoryUID&) = delete; + GridFactoryUID(GridFactoryUID&&) = delete; + GridFactoryUID& operator=(const GridFactoryUID&) = delete; + GridFactoryUID& operator=(GridFactoryUID&&) = delete; + // This is 'const' as Grid should always be immutable - static const Grid* build(const Configuration&); - static const Grid* build_from_uid(const std::string&); - static const Grid* build_from_name(const std::string&, Grid::Area* = nullptr, Grid::Projection* = nullptr); - static const Grid* build_from_name(const std::string&, Grid::Projection*); - static const Grid* build_from_type(const std::string&, Grid::Area* = nullptr, Grid::Projection* = nullptr); - static const Grid* build_from_type(const std::string&, Grid::Projection*); - static const Grid* build_from_increments(const Increments&, Grid::Area* = nullptr, Grid::Projection* = nullptr); - static const Grid* build_from_increments(const Increments&, Grid::Projection*); + static const Grid* build(const std::string&); static void list(std::ostream&); - GridFactory(const GridFactory&) = delete; - GridFactory(GridFactory&&) = delete; - GridFactory& operator=(const GridFactory&) = delete; - GridFactory& operator=(GridFactory&&) = delete; +private: + const std::string uid_; +}; + + +struct GridFactoryName { + explicit GridFactoryName(const std::string& name); + virtual ~GridFactoryName(); + + virtual const Grid* make(const Configuration&) = 0; + + GridFactoryName(const GridFactoryName&) = delete; + GridFactoryName(GridFactoryName&&) = delete; + GridFactoryName& operator=(const GridFactoryName&) = delete; + GridFactoryName& operator=(GridFactoryName&&) = delete; + + // This is 'const' as Grid should always be immutable + static const Grid* build(const std::string&, Area* = nullptr, Projection* = nullptr); + static const Grid* build(const std::string&, Projection*); + + static void list(std::ostream&); + +private: + const std::string name_; +}; + + +struct GridFactoryType { + explicit GridFactoryType(const std::string& type); + virtual ~GridFactoryType(); + + virtual const Grid* make(const Configuration&) = 0; + + GridFactoryType(const GridFactoryType&) = delete; + GridFactoryType(GridFactoryType&&) = delete; + GridFactoryType& operator=(const GridFactoryType&) = delete; + GridFactoryType& operator=(GridFactoryType&&) = delete; + + // This is 'const' as Grid should always be immutable + static const Grid* build(const std::string&, Area* = nullptr, Projection* = nullptr); + static const Grid* build(const std::string&, Projection*); + + static void list(std::ostream&); + +private: + const std::string type_; }; template -class GridBuilder : public GridFactory { - Grid* make(const Configuration& config) override { return new T(config); } +struct GridRegisterUID final : GridFactoryUID { + explicit GridRegisterUID(const std::string& uid) : + GridFactoryUID(uid) {} + const Grid* make() override { return new T(); } +}; -public: - GridBuilder(const std::string& name) : - GridFactory(name) {} + +template +struct GridRegisterName final : GridFactoryName { + explicit GridRegisterName(const std::string& name) : + GridFactoryName(name) {} + const Grid* make(const Configuration& config) override { return new T(config); } +}; + + +template +struct GridRegisterType final : GridFactoryType { + explicit GridRegisterType(const std::string& type) : + GridFactoryType(type) {} + const Grid* make(const Configuration& config) override { return new T(config); } }; diff --git a/src/eckit/geometry/detail/IrregularLatlon.cc b/src/eckit/geometry/detail/IrregularLatlon.cc index a88ae5135..f6e26da3a 100644 --- a/src/eckit/geometry/detail/IrregularLatlon.cc +++ b/src/eckit/geometry/detail/IrregularLatlon.cc @@ -150,7 +150,7 @@ bool IrregularLatlon::includesSouthPole() const { } -static const GridBuilder irregularLatlon("irregular_latlon"); +static const GridRegisterType irregularLatlon("irregular_latlon"); } // namespace eckit::geometry::detail diff --git a/src/eckit/geometry/detail/ReducedGG.cc b/src/eckit/geometry/detail/ReducedGG.cc index b69d7f478..4923ea557 100644 --- a/src/eckit/geometry/detail/ReducedGG.cc +++ b/src/eckit/geometry/detail/ReducedGG.cc @@ -258,7 +258,7 @@ struct ReducedGGOctahedral : ReducedGG { }; -static const GridBuilder reducedFromPL("reduced_gg"); +static const GridRegisterType reducedFromPL("reduced_gg"); } // namespace eckit::geometry::detail diff --git a/src/eckit/geometry/detail/ReducedLL.cc b/src/eckit/geometry/detail/ReducedLL.cc index 2f9de6b63..3ad349b8d 100644 --- a/src/eckit/geometry/detail/ReducedLL.cc +++ b/src/eckit/geometry/detail/ReducedLL.cc @@ -168,7 +168,7 @@ class ReducedLLIterator : public Iterator { }; -static const GridBuilder reducedLL("reduced_ll"); +static const GridRegisterType reducedLL("reduced_ll"); } // namespace eckit::geometry::detail diff --git a/src/eckit/geometry/detail/RegularGG.cc b/src/eckit/geometry/detail/RegularGG.cc index e4a315816..92a41989f 100644 --- a/src/eckit/geometry/detail/RegularGG.cc +++ b/src/eckit/geometry/detail/RegularGG.cc @@ -177,7 +177,7 @@ Iterator* RegularGG::iterator() const { #endif -static const GridBuilder reducedGG("regular_gg"); +static const GridRegisterType reducedGG("regular_gg"); } // namespace eckit::geometry::detail diff --git a/src/eckit/geometry/detail/RegularGrid.cc b/src/eckit/geometry/detail/RegularGrid.cc index 3bac9359b..62aaca1be 100644 --- a/src/eckit/geometry/detail/RegularGrid.cc +++ b/src/eckit/geometry/detail/RegularGrid.cc @@ -254,10 +254,10 @@ struct PolarStereographic : RegularGrid { }; -static const GridBuilder __builder1("lambert"); -static const GridBuilder __builder2("lambert_azimuthal_equal_area"); -static const GridBuilder __builder3("mercator"); -static const GridBuilder __builder4("polar_stereographic"); +static const GridRegisterType __builder1("lambert"); +static const GridRegisterType __builder2("lambert_azimuthal_equal_area"); +static const GridRegisterType __builder3("mercator"); +static const GridRegisterType __builder4("polar_stereographic"); } // namespace eckit::geometry::detail diff --git a/src/eckit/geometry/detail/RegularLL.cc b/src/eckit/geometry/detail/RegularLL.cc index 5aa747a99..8520c389d 100644 --- a/src/eckit/geometry/detail/RegularLL.cc +++ b/src/eckit/geometry/detail/RegularLL.cc @@ -291,7 +291,7 @@ Iterator* RegularLL::iterator() const { #endif -static const GridBuilder regularLL("regular_ll"); +static const GridRegisterType regularLL("regular_ll"); } // namespace eckit::geometry::detail diff --git a/src/eckit/geometry/detail/UnstructuredGrid.cc b/src/eckit/geometry/detail/UnstructuredGrid.cc index 49ddf3cf4..950b335dc 100644 --- a/src/eckit/geometry/detail/UnstructuredGrid.cc +++ b/src/eckit/geometry/detail/UnstructuredGrid.cc @@ -205,8 +205,8 @@ bool UnstructuredGrid::includesSouthPole() const { } -static const GridBuilder triangular_grid("triangular_grid"); -static const GridBuilder unstructured_grid("unstructured_grid"); +static const GridRegisterType triangular_grid("triangular_grid"); +static const GridRegisterType unstructured_grid("unstructured_grid"); } // namespace eckit::geometry::detail diff --git a/tests/geometry/test_grid.cc b/tests/geometry/test_grid.cc index 2147eabca..837342d59 100644 --- a/tests/geometry/test_grid.cc +++ b/tests/geometry/test_grid.cc @@ -25,22 +25,22 @@ using namespace geometry; CASE("GridFactory::build") { SECTION("GridFactory::build_from_name") { - std::unique_ptr grid(GridFactory::build_from_name("O2")); + std::unique_ptr grid(GridFactoryName::build("O2")); auto size = grid->size(); EXPECT_EQUAL(size, 88); } - SECTION("GridFactory::build_from_uid") { + SECTION("Grid::build_from_uid") { } - SECTION("GridFactory::build_from_increments") { + SECTION("Grid::build_from_increments") { } - SECTION("GridFactory::build") { + SECTION("Grid::build") { std::unique_ptr grid(GridFactory::build(MappedConfiguration{ {{"grid", "O2"}}})); From da368b3b4e03ceb42e395a229ccf78e064c5bf56 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 25 Jul 2023 00:57:31 +0100 Subject: [PATCH 258/737] eckit::config --- src/eckit/CMakeLists.txt | 2 + src/eckit/config/DynamicConfiguration.cc | 201 +++++++++++++++++++++++ src/eckit/config/DynamicConfiguration.h | 116 +++++++++++++ src/eckit/config/MappedConfiguration.cc | 2 +- tests/config/test_configuration.cc | 32 +++- 5 files changed, 351 insertions(+), 2 deletions(-) create mode 100644 src/eckit/config/DynamicConfiguration.cc create mode 100644 src/eckit/config/DynamicConfiguration.h diff --git a/src/eckit/CMakeLists.txt b/src/eckit/CMakeLists.txt index a328e32ee..ab7d88ddc 100644 --- a/src/eckit/CMakeLists.txt +++ b/src/eckit/CMakeLists.txt @@ -347,6 +347,8 @@ config/Configuration.cc config/Configuration.h config/Configured.cc config/Configured.h +config/DynamicConfiguration.cc +config/DynamicConfiguration.h config/EtcTable.cc config/EtcTable.h config/JSONConfiguration.h diff --git a/src/eckit/config/DynamicConfiguration.cc b/src/eckit/config/DynamicConfiguration.cc new file mode 100644 index 000000000..7614ac322 --- /dev/null +++ b/src/eckit/config/DynamicConfiguration.cc @@ -0,0 +1,201 @@ +/* + * (C) Copyright 1996- 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 "eckit/config/DynamicConfiguration.h" + +#include "eckit/config/LocalConfiguration.h" +#include "eckit/value/Value.h" + +namespace eckit { + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace { + + +static const LocalConfiguration __empty_configuration; +static const eckit::Value __empty_root; + + +} // namespace + + +DynamicConfiguration::DynamicConfiguration() : + DynamicConfiguration(__empty_configuration) {} + + +DynamicConfiguration::DynamicConfiguration(const Configuration& passive) : + Configuration(__empty_root), passive_(passive) {} + + +void DynamicConfiguration::set(const std::string& name, std::string& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, bool& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, int& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, long& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, long long& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, std::size_t& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, float& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, double& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, std::vector& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, std::vector& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, std::vector& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, std::vector& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, std::vector& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, std::vector& value) { + active_.set(name, value); +} + + +void DynamicConfiguration::set(const std::string& name, std::vector& value) { + active_.set(name, value); +} + + +bool DynamicConfiguration::has(const std::string& name) const { + return active_.has(name) || passive_.has(name); +} + + +bool DynamicConfiguration::get(const std::string& name, std::string& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, bool& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, int& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, long& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, long long& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, std::size_t& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, float& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, double& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { + return active_.get(name, value) || passive_.get(name, value); +} + + +void DynamicConfiguration::print(std::ostream& out) const { + out << "DynamicConfiguration[active=" << active_ << ",passive=" << passive_ << "]"; +} + + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit diff --git a/src/eckit/config/DynamicConfiguration.h b/src/eckit/config/DynamicConfiguration.h new file mode 100644 index 000000000..40d695b42 --- /dev/null +++ b/src/eckit/config/DynamicConfiguration.h @@ -0,0 +1,116 @@ +/* + * (C) Copyright 1996- 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. + */ + +#ifndef eckit_DynamicConfiguration_H +#define eckit_DynamicConfiguration_H + +#include "eckit/config/Configuration.h" +#include "eckit/config/MappedConfiguration.h" + +namespace eckit { + +//---------------------------------------------------------------------------------------------------------------------- + +class DynamicConfiguration : public Configuration { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + DynamicConfiguration(); + explicit DynamicConfiguration(const Configuration&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + void set(const std::string&, std::string&); + void set(const std::string&, bool&); + void set(const std::string&, int&); + void set(const std::string&, long&); + void set(const std::string&, long long&); + void set(const std::string&, std::size_t&); + void set(const std::string&, float&); + void set(const std::string&, double&); + + void set(const std::string&, std::vector&); + void set(const std::string&, std::vector&); + void set(const std::string&, std::vector&); + void set(const std::string&, std::vector&); + void set(const std::string&, std::vector&); + void set(const std::string&, std::vector&); + void set(const std::string&, std::vector&); + + // -- Overridden methods + + bool has(const std::string&) const override; + + bool get(const std::string&, std::string&) const override; + bool get(const std::string&, bool&) const override; + bool get(const std::string&, int&) const override; + bool get(const std::string&, long&) const override; + bool get(const std::string&, long long&) const override; + bool get(const std::string&, std::size_t&) const override; + bool get(const std::string&, float&) const override; + bool get(const std::string&, double&) const override; + + bool get(const std::string&, std::vector&) const override; + bool get(const std::string&, std::vector&) const override; + bool get(const std::string&, std::vector&) const override; + bool get(const std::string&, std::vector&) const override; + bool get(const std::string&, std::vector&) const override; + bool get(const std::string&, std::vector&) const override; + bool get(const std::string&, std::vector&) const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + const Configuration& passive_; + MappedConfiguration active_; + + // -- Methods + // None + + // -- Overridden methods + + void print(std::ostream&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit + +#endif diff --git a/src/eckit/config/MappedConfiguration.cc b/src/eckit/config/MappedConfiguration.cc index fe2d8f3fd..f03510f98 100644 --- a/src/eckit/config/MappedConfiguration.cc +++ b/src/eckit/config/MappedConfiguration.cc @@ -22,7 +22,7 @@ namespace eckit { namespace { -const eckit::Value __empty_root{}; +const eckit::Value __empty_root; template diff --git a/tests/config/test_configuration.cc b/tests/config/test_configuration.cc index 623ed2646..36beb7580 100644 --- a/tests/config/test_configuration.cc +++ b/tests/config/test_configuration.cc @@ -10,7 +10,9 @@ #include +#include "eckit/config/DynamicConfiguration.h" #include "eckit/config/LocalConfiguration.h" +#include "eckit/config/MappedConfiguration.h" #include "eckit/config/YAMLConfiguration.h" #include "eckit/filesystem/PathName.h" #include "eckit/log/Log.h" @@ -18,7 +20,6 @@ #include "eckit/types/Types.h" #include "eckit/utils/Hash.h" -using namespace std; using namespace eckit; using namespace eckit::testing; @@ -406,6 +407,35 @@ CASE("Hash a configuration") { //---------------------------------------------------------------------------------------------------------------------- +CASE("test_dynamic_configuration") { + double one = 1.; + int two = 2; + std::string three = "3"; + + DynamicConfiguration a; + EXPECT_NOT(a.has("a")); + + a.set("a", one); + EXPECT(a.has("a")); + + a.set("b", two); + EXPECT_EQUAL(a.getInt("b"), two); + EXPECT_THROWS_AS(a.getString("b"), std::bad_variant_access); + + a.set("a", three); + EXPECT_EQUAL(a.getString("a"), three); + + DynamicConfiguration b(a); + + EXPECT(b.has("a")); + EXPECT_EQUAL(b.getString("a"), three); + + b.set("a", two); + EXPECT_EQUAL(b.getInt("a"), two); +} + +//---------------------------------------------------------------------------------------------------------------------- + } // namespace eckit::test int main(int argc, char** argv) { From 5521d6d71a80bdab4afaad2e188bf49424fe914a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 27 Jul 2023 01:43:04 +0100 Subject: [PATCH 259/737] eckit::config --- src/eckit/config/DynamicConfiguration.cc | 76 ++++++++++++++---------- src/eckit/config/DynamicConfiguration.h | 21 ++++++- tests/config/test_configuration.cc | 35 +++++++---- 3 files changed, 86 insertions(+), 46 deletions(-) diff --git a/src/eckit/config/DynamicConfiguration.cc b/src/eckit/config/DynamicConfiguration.cc index 7614ac322..a82dbe7a3 100644 --- a/src/eckit/config/DynamicConfiguration.cc +++ b/src/eckit/config/DynamicConfiguration.cc @@ -21,8 +21,8 @@ namespace eckit { namespace { -static const LocalConfiguration __empty_configuration; -static const eckit::Value __empty_root; +const LocalConfiguration __empty_configuration; +const eckit::Value __empty_root; } // namespace @@ -37,157 +37,167 @@ DynamicConfiguration::DynamicConfiguration(const Configuration& passive) : void DynamicConfiguration::set(const std::string& name, std::string& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, bool& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, int& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, long& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, long long& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, std::size_t& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, float& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, double& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, std::vector& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, std::vector& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, std::vector& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, std::vector& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, std::vector& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, std::vector& value) { - active_.set(name, value); + __set(*this, name, value); } void DynamicConfiguration::set(const std::string& name, std::vector& value) { - active_.set(name, value); + __set(*this, name, value); +} + + +void DynamicConfiguration::hide(const std::string& name) { + hide_.insert(name); +} + + +void DynamicConfiguration::unhide(const std::string& name) { + hide_.erase(name); } bool DynamicConfiguration::has(const std::string& name) const { - return active_.has(name) || passive_.has(name); + return !hide_.contains(name) && (active_.has(name) || passive_.has(name)); } bool DynamicConfiguration::get(const std::string& name, std::string& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, bool& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, int& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, long& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, long long& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, std::size_t& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, float& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, double& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return active_.get(name, value) || passive_.get(name, value); + return __get(*this, name, value); } diff --git a/src/eckit/config/DynamicConfiguration.h b/src/eckit/config/DynamicConfiguration.h index 40d695b42..ff5d5bcfa 100644 --- a/src/eckit/config/DynamicConfiguration.h +++ b/src/eckit/config/DynamicConfiguration.h @@ -11,6 +11,8 @@ #ifndef eckit_DynamicConfiguration_H #define eckit_DynamicConfiguration_H +#include + #include "eckit/config/Configuration.h" #include "eckit/config/MappedConfiguration.h" @@ -59,6 +61,9 @@ class DynamicConfiguration : public Configuration { void set(const std::string&, std::vector&); void set(const std::string&, std::vector&); + void hide(const std::string&); + void unhide(const std::string&); + // -- Overridden methods bool has(const std::string&) const override; @@ -92,6 +97,10 @@ class DynamicConfiguration : public Configuration { const Configuration& passive_; MappedConfiguration active_; + struct : std::unordered_set { + bool contains(const value_type& key) const { return find(key) != end(); } + } hide_; + // -- Methods // None @@ -106,7 +115,17 @@ class DynamicConfiguration : public Configuration { // None // -- Friends - // None + + template + friend void __set(DynamicConfiguration& config, const std::string& name, T& value) { + config.active_.set(name, value); + config.hide_.erase(name); + } + + template + friend bool __get(const DynamicConfiguration& config, const std::string& name, T& value) { + return !config.hide_.contains(name) && (config.active_.get(name, value) || config.passive_.get(name, value)); + } }; //---------------------------------------------------------------------------------------------------------------------- diff --git a/tests/config/test_configuration.cc b/tests/config/test_configuration.cc index 36beb7580..d2ff38726 100644 --- a/tests/config/test_configuration.cc +++ b/tests/config/test_configuration.cc @@ -413,25 +413,36 @@ CASE("test_dynamic_configuration") { std::string three = "3"; DynamicConfiguration a; - EXPECT_NOT(a.has("a")); + EXPECT_NOT(a.has("foo")); - a.set("a", one); - EXPECT(a.has("a")); + a.set("foo", one); + EXPECT(a.has("foo")); - a.set("b", two); - EXPECT_EQUAL(a.getInt("b"), two); - EXPECT_THROWS_AS(a.getString("b"), std::bad_variant_access); + a.set("bar", two); + EXPECT_EQUAL(a.getInt("bar"), two); + EXPECT_THROWS_AS(a.getString("bar"), std::bad_variant_access); - a.set("a", three); - EXPECT_EQUAL(a.getString("a"), three); + a.set("foo", three); + EXPECT_EQUAL(a.getString("foo"), three); DynamicConfiguration b(a); - EXPECT(b.has("a")); - EXPECT_EQUAL(b.getString("a"), three); + EXPECT(b.has("foo")); + EXPECT_EQUAL(b.getString("foo"), three); - b.set("a", two); - EXPECT_EQUAL(b.getInt("a"), two); + b.set("foo", two); + EXPECT_EQUAL(b.getInt("foo"), two); + + DynamicConfiguration c(a); + + ASSERT(c.has("foo")); + ASSERT(c.has("bar")); + + c.hide("bar"); + EXPECT_NOT(c.has("bar")); + + c.unhide("bar"); + EXPECT_EQUAL(a.getInt("bar"), two); } //---------------------------------------------------------------------------------------------------------------------- From 914f36284cc17e7b27fbebb095045db04ae57bea Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 27 Jul 2023 00:49:46 +0100 Subject: [PATCH 260/737] eckit::geometry --- src/eckit/geometry/CMakeLists.txt | 36 +++++++++---------- .../geometry/{detail => grid}/Gaussian.cc | 6 ++-- .../geometry/{detail => grid}/Gaussian.h | 4 +-- .../{detail => grid}/GaussianIterator.cc | 6 ++-- .../{detail => grid}/GaussianIterator.h | 4 +-- .../{detail => grid}/IrregularLatlon.cc | 6 ++-- .../{detail => grid}/IrregularLatlon.h | 4 +-- .../geometry/{detail => grid}/ReducedGG.cc | 8 ++--- .../geometry/{detail => grid}/ReducedGG.h | 6 ++-- .../geometry/{detail => grid}/ReducedLL.cc | 6 ++-- .../geometry/{detail => grid}/ReducedLL.h | 4 +-- .../geometry/{detail => grid}/RegularGG.cc | 10 +++--- .../geometry/{detail => grid}/RegularGG.h | 6 ++-- .../geometry/{detail => grid}/RegularGrid.cc | 6 ++-- .../geometry/{detail => grid}/RegularGrid.h | 4 +-- .../geometry/{detail => grid}/RegularLL.cc | 8 ++--- .../geometry/{detail => grid}/RegularLL.h | 4 +-- .../{detail => grid}/UnstructuredGrid.cc | 6 ++-- .../{detail => grid}/UnstructuredGrid.h | 4 +-- 19 files changed, 69 insertions(+), 69 deletions(-) rename src/eckit/geometry/{detail => grid}/Gaussian.cc (96%) rename src/eckit/geometry/{detail => grid}/Gaussian.h (95%) rename src/eckit/geometry/{detail => grid}/GaussianIterator.cc (95%) rename src/eckit/geometry/{detail => grid}/GaussianIterator.h (94%) rename src/eckit/geometry/{detail => grid}/IrregularLatlon.cc (96%) rename src/eckit/geometry/{detail => grid}/IrregularLatlon.h (95%) rename src/eckit/geometry/{detail => grid}/ReducedGG.cc (97%) rename src/eckit/geometry/{detail => grid}/ReducedGG.h (94%) rename src/eckit/geometry/{detail => grid}/ReducedLL.cc (97%) rename src/eckit/geometry/{detail => grid}/ReducedLL.h (94%) rename src/eckit/geometry/{detail => grid}/RegularGG.cc (94%) rename src/eckit/geometry/{detail => grid}/RegularGG.h (92%) rename src/eckit/geometry/{detail => grid}/RegularGrid.cc (98%) rename src/eckit/geometry/{detail => grid}/RegularGrid.h (96%) rename src/eckit/geometry/{detail => grid}/RegularLL.cc (97%) rename src/eckit/geometry/{detail => grid}/RegularLL.h (95%) rename src/eckit/geometry/{detail => grid}/UnstructuredGrid.cc (97%) rename src/eckit/geometry/{detail => grid}/UnstructuredGrid.h (96%) diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index c77584bc4..c27afa46a 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -42,24 +42,24 @@ list( APPEND eckit_geometry_srcs UnitSphere.h area/BoundingBox.cc area/BoundingBox.h - detail/Gaussian.cc - detail/Gaussian.h - detail/GaussianIterator.cc - detail/GaussianIterator.h - detail/IrregularLatlon.cc - detail/IrregularLatlon.h - detail/ReducedGG.cc - detail/ReducedGG.h - detail/ReducedLL.cc - detail/ReducedLL.h - detail/RegularGG.cc - detail/RegularGG.h - detail/RegularGrid.cc - detail/RegularGrid.h - detail/RegularLL.cc - detail/RegularLL.h - detail/UnstructuredGrid.cc - detail/UnstructuredGrid.h + grid/Gaussian.cc + grid/Gaussian.h + grid/GaussianIterator.cc + grid/GaussianIterator.h + grid/IrregularLatlon.cc + grid/IrregularLatlon.h + grid/ReducedGG.cc + grid/ReducedGG.h + grid/ReducedLL.cc + grid/ReducedLL.h + grid/RegularGG.cc + grid/RegularGG.h + grid/RegularGrid.cc + grid/RegularGrid.h + grid/RegularLL.cc + grid/RegularLL.h + grid/UnstructuredGrid.cc + grid/UnstructuredGrid.h polygon/LonLatPolygon.cc polygon/LonLatPolygon.h polygon/Polygon.cc diff --git a/src/eckit/geometry/detail/Gaussian.cc b/src/eckit/geometry/grid/Gaussian.cc similarity index 96% rename from src/eckit/geometry/detail/Gaussian.cc rename to src/eckit/geometry/grid/Gaussian.cc index 5ba2a9a8f..11a720df2 100644 --- a/src/eckit/geometry/detail/Gaussian.cc +++ b/src/eckit/geometry/grid/Gaussian.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/detail/Gaussian.h" +#include "eckit/geometry/grid/Gaussian.h" #include #include @@ -22,7 +22,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { Gaussian::Gaussian(size_t N, const area::BoundingBox& bbox) : @@ -118,4 +118,4 @@ void Gaussian::correctSouthNorth(double& s, double& n, bool in) const { } -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/Gaussian.h b/src/eckit/geometry/grid/Gaussian.h similarity index 95% rename from src/eckit/geometry/detail/Gaussian.h rename to src/eckit/geometry/grid/Gaussian.h index dd4fe1cde..5b0f4fec2 100644 --- a/src/eckit/geometry/detail/Gaussian.h +++ b/src/eckit/geometry/grid/Gaussian.h @@ -15,7 +15,7 @@ #include "eckit/geometry/Grid.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { class Gaussian : public Grid { @@ -98,4 +98,4 @@ class Gaussian : public Grid { }; -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/GaussianIterator.cc b/src/eckit/geometry/grid/GaussianIterator.cc similarity index 95% rename from src/eckit/geometry/detail/GaussianIterator.cc rename to src/eckit/geometry/grid/GaussianIterator.cc index 67a1d5434..2f3abd1b6 100644 --- a/src/eckit/geometry/detail/GaussianIterator.cc +++ b/src/eckit/geometry/grid/GaussianIterator.cc @@ -10,14 +10,14 @@ */ -#include "eckit/geometry/detail/GaussianIterator.h" +#include "eckit/geometry/grid/GaussianIterator.h" #include #include "eckit/exception/Exceptions.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { GaussianIterator::GaussianIterator(const std::vector& latitudes, std::vector&& pl, @@ -115,4 +115,4 @@ size_t GaussianIterator::size() const { } -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/GaussianIterator.h b/src/eckit/geometry/grid/GaussianIterator.h similarity index 94% rename from src/eckit/geometry/detail/GaussianIterator.h rename to src/eckit/geometry/grid/GaussianIterator.h index 168161824..d4c03f777 100644 --- a/src/eckit/geometry/detail/GaussianIterator.h +++ b/src/eckit/geometry/grid/GaussianIterator.h @@ -21,7 +21,7 @@ #include "eckit/geometry/area/BoundingBox.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { class GaussianIterator : public Iterator { @@ -55,4 +55,4 @@ class GaussianIterator : public Iterator { }; -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/IrregularLatlon.cc b/src/eckit/geometry/grid/IrregularLatlon.cc similarity index 96% rename from src/eckit/geometry/detail/IrregularLatlon.cc rename to src/eckit/geometry/grid/IrregularLatlon.cc index f6e26da3a..7440c31cf 100644 --- a/src/eckit/geometry/detail/IrregularLatlon.cc +++ b/src/eckit/geometry/grid/IrregularLatlon.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/detail/IrregularLatlon.h" +#include "eckit/geometry/grid/IrregularLatlon.h" #include #include @@ -21,7 +21,7 @@ #include "eckit/geometry/Projection.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { static void range(const std::vector& v, double& mn, double& mx, double& dmax) { @@ -153,4 +153,4 @@ bool IrregularLatlon::includesSouthPole() const { static const GridRegisterType irregularLatlon("irregular_latlon"); -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/IrregularLatlon.h b/src/eckit/geometry/grid/IrregularLatlon.h similarity index 95% rename from src/eckit/geometry/detail/IrregularLatlon.h rename to src/eckit/geometry/grid/IrregularLatlon.h index 6a0c8acdd..34ec9f894 100644 --- a/src/eckit/geometry/detail/IrregularLatlon.h +++ b/src/eckit/geometry/grid/IrregularLatlon.h @@ -15,7 +15,7 @@ #include "eckit/geometry/Grid.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { class IrregularLatlon final : public Grid { @@ -83,4 +83,4 @@ class IrregularLatlon final : public Grid { }; -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/ReducedGG.cc b/src/eckit/geometry/grid/ReducedGG.cc similarity index 97% rename from src/eckit/geometry/detail/ReducedGG.cc rename to src/eckit/geometry/grid/ReducedGG.cc index 4923ea557..6b6d4a592 100644 --- a/src/eckit/geometry/detail/ReducedGG.cc +++ b/src/eckit/geometry/grid/ReducedGG.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/detail/ReducedGG.h" +#include "eckit/geometry/grid/ReducedGG.h" #include #include @@ -23,11 +23,11 @@ #include "eckit/geometry/Iterator.h" #include "eckit/geometry/Projection.h" -#include "eckit/geometry/detail/GaussianIterator.h" +#include "eckit/geometry/grid/GaussianIterator.h" #include "eckit/types/Fraction.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { ReducedGG::ReducedGG(const Configuration& config) : @@ -261,4 +261,4 @@ struct ReducedGGOctahedral : ReducedGG { static const GridRegisterType reducedFromPL("reduced_gg"); -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/ReducedGG.h b/src/eckit/geometry/grid/ReducedGG.h similarity index 94% rename from src/eckit/geometry/detail/ReducedGG.h rename to src/eckit/geometry/grid/ReducedGG.h index 4154d67de..c11ff2e64 100644 --- a/src/eckit/geometry/detail/ReducedGG.h +++ b/src/eckit/geometry/grid/ReducedGG.h @@ -12,7 +12,7 @@ #pragma once -#include "eckit/geometry/detail/Gaussian.h" +#include "eckit/geometry/grid/Gaussian.h" #include "eckit/geometry/util.h" @@ -21,7 +21,7 @@ class Fraction; } -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { class ReducedGG : public Gaussian { @@ -115,4 +115,4 @@ class ReducedGG : public Gaussian { }; -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/ReducedLL.cc b/src/eckit/geometry/grid/ReducedLL.cc similarity index 97% rename from src/eckit/geometry/detail/ReducedLL.cc rename to src/eckit/geometry/grid/ReducedLL.cc index 3ad349b8d..879c5ddea 100644 --- a/src/eckit/geometry/detail/ReducedLL.cc +++ b/src/eckit/geometry/grid/ReducedLL.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/detail/ReducedLL.h" +#include "eckit/geometry/grid/ReducedLL.h" #include #include @@ -24,7 +24,7 @@ #include "eckit/types/Fraction.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { static bool checkPl(const std::vector& pl) { ASSERT(!pl.empty()); @@ -171,4 +171,4 @@ class ReducedLLIterator : public Iterator { static const GridRegisterType reducedLL("reduced_ll"); -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/ReducedLL.h b/src/eckit/geometry/grid/ReducedLL.h similarity index 94% rename from src/eckit/geometry/detail/ReducedLL.h rename to src/eckit/geometry/grid/ReducedLL.h index 74cface5d..aea11fa0a 100644 --- a/src/eckit/geometry/detail/ReducedLL.h +++ b/src/eckit/geometry/grid/ReducedLL.h @@ -15,7 +15,7 @@ #include "eckit/geometry/Grid.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { class ReducedLL : public Grid { @@ -78,4 +78,4 @@ class ReducedLL : public Grid { }; -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/RegularGG.cc b/src/eckit/geometry/grid/RegularGG.cc similarity index 94% rename from src/eckit/geometry/detail/RegularGG.cc rename to src/eckit/geometry/grid/RegularGG.cc index 92a41989f..f6c9bcc02 100644 --- a/src/eckit/geometry/detail/RegularGG.cc +++ b/src/eckit/geometry/grid/RegularGG.cc @@ -10,19 +10,19 @@ */ -#include "eckit/geometry/detail/RegularGG.h" +#include "eckit/geometry/grid/RegularGG.h" #include #include #include -#include "eckit/geometry/detail/GaussianIterator.h" -#include "eckit/geometry/detail/RegularGG.h" +#include "eckit/geometry/grid/GaussianIterator.h" +#include "eckit/geometry/grid/RegularGG.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { RegularGG::RegularGG(const Configuration& config) : @@ -180,4 +180,4 @@ Iterator* RegularGG::iterator() const { static const GridRegisterType reducedGG("regular_gg"); -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/RegularGG.h b/src/eckit/geometry/grid/RegularGG.h similarity index 92% rename from src/eckit/geometry/detail/RegularGG.h rename to src/eckit/geometry/grid/RegularGG.h index 2d76c841f..a6395f60c 100644 --- a/src/eckit/geometry/detail/RegularGG.h +++ b/src/eckit/geometry/grid/RegularGG.h @@ -12,7 +12,7 @@ #pragma once -#include "eckit/geometry/detail/Gaussian.h" +#include "eckit/geometry/grid/Gaussian.h" namespace eckit { @@ -20,7 +20,7 @@ class Fraction; } -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { class RegularGG final : public Gaussian { @@ -85,4 +85,4 @@ class RegularGG final : public Gaussian { }; -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/RegularGrid.cc b/src/eckit/geometry/grid/RegularGrid.cc similarity index 98% rename from src/eckit/geometry/detail/RegularGrid.cc rename to src/eckit/geometry/grid/RegularGrid.cc index 62aaca1be..3927b6cc8 100644 --- a/src/eckit/geometry/detail/RegularGrid.cc +++ b/src/eckit/geometry/grid/RegularGrid.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/detail/RegularGrid.h" +#include "eckit/geometry/grid/RegularGrid.h" #include #include @@ -25,7 +25,7 @@ #include "eckit/utils/StringTools.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { RegularGrid::RegularGrid(Projection* projection, const Configuration& config) : @@ -260,4 +260,4 @@ static const GridRegisterType __builder3("mercator"); static const GridRegisterType __builder4("polar_stereographic"); -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/RegularGrid.h b/src/eckit/geometry/grid/RegularGrid.h similarity index 96% rename from src/eckit/geometry/detail/RegularGrid.h rename to src/eckit/geometry/grid/RegularGrid.h index 6cbbaf5ef..d4cbf7b9b 100644 --- a/src/eckit/geometry/detail/RegularGrid.h +++ b/src/eckit/geometry/grid/RegularGrid.h @@ -20,7 +20,7 @@ #include "eckit/geometry/Projection.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { class RegularGrid : public Grid { @@ -101,4 +101,4 @@ class RegularGrid : public Grid { }; -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/RegularLL.cc b/src/eckit/geometry/grid/RegularLL.cc similarity index 97% rename from src/eckit/geometry/detail/RegularLL.cc rename to src/eckit/geometry/grid/RegularLL.cc index 8520c389d..61c1c4695 100644 --- a/src/eckit/geometry/detail/RegularLL.cc +++ b/src/eckit/geometry/grid/RegularLL.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/detail/RegularLL.h" +#include "eckit/geometry/grid/RegularLL.h" #include #include @@ -20,12 +20,12 @@ #include "eckit/geometry/Iterator.h" #include "eckit/geometry/Point.h" #include "eckit/geometry/Projection.h" -#include "eckit/geometry/detail/RegularLL.h" +#include "eckit/geometry/grid/RegularLL.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { namespace detail { @@ -294,4 +294,4 @@ Iterator* RegularLL::iterator() const { static const GridRegisterType regularLL("regular_ll"); -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/RegularLL.h b/src/eckit/geometry/grid/RegularLL.h similarity index 95% rename from src/eckit/geometry/detail/RegularLL.h rename to src/eckit/geometry/grid/RegularLL.h index a377dcd63..888c03fcc 100644 --- a/src/eckit/geometry/detail/RegularLL.h +++ b/src/eckit/geometry/grid/RegularLL.h @@ -17,7 +17,7 @@ #include "eckit/types/Fraction.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { class RegularLL : public Grid { @@ -83,4 +83,4 @@ class RegularLL : public Grid { }; -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/UnstructuredGrid.cc b/src/eckit/geometry/grid/UnstructuredGrid.cc similarity index 97% rename from src/eckit/geometry/detail/UnstructuredGrid.cc rename to src/eckit/geometry/grid/UnstructuredGrid.cc index 950b335dc..16d22bd4d 100644 --- a/src/eckit/geometry/detail/UnstructuredGrid.cc +++ b/src/eckit/geometry/grid/UnstructuredGrid.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/detail/UnstructuredGrid.h" +#include "eckit/geometry/grid/UnstructuredGrid.h" #include #include @@ -29,7 +29,7 @@ #include "eckit/serialisation/IfstreamStream.h" -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { namespace detail { @@ -209,4 +209,4 @@ static const GridRegisterType triangular_grid("triangular_grid static const GridRegisterType unstructured_grid("unstructured_grid"); -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/detail/UnstructuredGrid.h b/src/eckit/geometry/grid/UnstructuredGrid.h similarity index 96% rename from src/eckit/geometry/detail/UnstructuredGrid.h rename to src/eckit/geometry/grid/UnstructuredGrid.h index 6533f7caf..7327f21d2 100644 --- a/src/eckit/geometry/detail/UnstructuredGrid.h +++ b/src/eckit/geometry/grid/UnstructuredGrid.h @@ -22,7 +22,7 @@ class PathName; } -namespace eckit::geometry::detail { +namespace eckit::geometry::grid { class UnstructuredGrid : public Grid { @@ -111,4 +111,4 @@ class UnstructuredGrid : public Grid { }; -} // namespace eckit::geometry::detail +} // namespace eckit::geometry::grid From 199a1d4c74a20d784c934653df42cda8a5aa97ae Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 27 Jul 2023 03:08:02 +0100 Subject: [PATCH 261/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 88 +++++++++++++++++----------- src/eckit/geometry/Grid.h | 53 ++++++++--------- src/eckit/geometry/grid/ReducedGG.cc | 12 +++- tests/geometry/test_grid.cc | 2 +- 4 files changed, 92 insertions(+), 63 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index cd70b38cd..eee4b9d06 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -14,7 +14,8 @@ #include #include -#include +#include +#include #include #include "eckit/exception/Exceptions.h" @@ -63,13 +64,11 @@ const Grid* GridFactory::build(const Configuration& config) { } if (std::string name; config.get("name", name)) { - return config.has("area") ? config.has("rotation") ? GridFactoryName::build(name, AreaFactory::build(config), ProjectionFactory::build(config)) : GridFactoryName::build(name, AreaFactory::build(config)) : config.has("rotation") ? GridFactoryName::build(name, ProjectionFactory::build(config)) - : GridFactoryName::build(name); + return GridFactoryName::build(name); } - if (std::string type; config.get("type", type)) { - return config.has("area") ? config.has("rotation") ? GridFactoryType::build(type, AreaFactory::build(config), ProjectionFactory::build(config)) : GridFactoryType::build(type, AreaFactory::build(config)) : config.has("rotation") ? GridFactoryType::build(type, ProjectionFactory::build(config)) - : GridFactoryType::build(type); + if (config.has("type")) { + return GridFactoryType::build(config); } list(Log::error() << "Grid: cannot build grid, choices are: "); @@ -81,9 +80,21 @@ void GridFactory::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - GridFactoryUID::list(out); - GridFactoryName::list(out); - GridFactoryType::list(out); + const char* sep = ""; + for (const auto& j : *__grid_uids) { + out << sep << j.first; + sep = ", "; + } + + for (const auto& j : *__grid_names) { + out << sep << j.first; + sep = ", "; + } + + for (const auto& j : *__grid_types) { + out << sep << j.first; + sep = ", "; + } } @@ -132,27 +143,46 @@ void GridFactoryUID::list(std::ostream& out) { } -GridFactoryName::GridFactoryName(const std::string& name) : - name_(name) { +GridFactoryName::GridFactoryName(const std::string& pattern) : + pattern_(pattern) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - if (__grid_names->find(name) == __grid_names->end()) { - (*__grid_names)[name] = this; + if (__grid_names->find(pattern) == __grid_names->end()) { + (*__grid_names)[pattern] = this; return; } - throw SeriousBug("Grid: duplicate name '" + name + "'"); + throw SeriousBug("Grid: duplicate name '" + pattern + "'"); } -const Grid* GridFactoryName::build(const std::string& name, Area* area, Projection* projection) { +const Grid* GridFactoryName::build(const std::string& name) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - if (auto j = __grid_names->find(name); j != __grid_names->end()) { - NOTIMP; - // return j->second->make(name, area, projection); + auto matches = [](const std::string& s, const std::string& pattern) -> bool { + const std::regex e(pattern, std::regex_constants::extended); + std::smatch match; + std::regex_match(s, match, e); + return !match.empty(); + }; + + const auto end = __grid_names->cend(); + + auto i = end; + for (auto j = __grid_names->cbegin(); j != end; ++j) { + if (matches(name, j->second->pattern_)) { + if (i != end) { + throw SeriousBug("Grid: name '" + name + "' matches '" + i->second->pattern_ + "' and '" + j->second->pattern_ + "'"); + } + i = j; + } + } + + if (i != end) { + std::unique_ptr config(i->second->config(name)); + return GridFactory::build(*config); } list(Log::error() << "Grid: unknown name '" << name << "', choices are: "); @@ -160,11 +190,6 @@ const Grid* GridFactoryName::build(const std::string& name, Area* area, Projecti } -const Grid* GridFactoryName::build(const std::string& name, Projection* projection) { - return build(name, nullptr, projection); -} - - void GridFactoryName::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); @@ -179,7 +204,7 @@ void GridFactoryName::list(std::ostream& out) { GridFactoryName::~GridFactoryName() { AutoLock lock(*__mutex); - __grid_names->erase(name_); + __grid_names->erase(pattern_); } @@ -203,13 +228,15 @@ GridFactoryType::~GridFactoryType() { } -const Grid* GridFactoryType::build(const std::string& type, Area* area, Projection* projection) { +const Grid* GridFactoryType::build(const Configuration& config) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - if (auto j = __grid_types->find(type); j != __grid_types->end()) { - NOTIMP; - // return j->second->make(type, area, projection); + std::string type; + if (config.get("type", type)) { + if (auto j = __grid_types->find(type); j != __grid_types->end()) { + return j->second->make(config); + } } list(Log::error() << "Grid: unknown type '" << type << "', choices are: "); @@ -217,11 +244,6 @@ const Grid* GridFactoryType::build(const std::string& type, Area* area, Projecti } -const Grid* GridFactoryType::build(const std::string& type, Projection* projection) { - return build(type, nullptr, projection); -} - - void GridFactoryType::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 95a306ff4..4861e90d1 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -14,7 +14,6 @@ #include #include - #include #include "eckit/config/Configuration.h" @@ -125,7 +124,7 @@ class Grid { }; -static struct GridFactory { +struct GridFactory { // This is 'const' as Grid should always be immutable static const Grid* build(const Configuration&); static void list(std::ostream&); @@ -133,11 +132,6 @@ static struct GridFactory { struct GridFactoryUID { - explicit GridFactoryUID(const std::string& uid); - virtual ~GridFactoryUID(); - - virtual const Grid* make() = 0; - GridFactoryUID(const GridFactoryUID&) = delete; GridFactoryUID(GridFactoryUID&&) = delete; GridFactoryUID& operator=(const GridFactoryUID&) = delete; @@ -145,54 +139,57 @@ struct GridFactoryUID { // This is 'const' as Grid should always be immutable static const Grid* build(const std::string&); - static void list(std::ostream&); +protected: + explicit GridFactoryUID(const std::string& uid); + virtual ~GridFactoryUID(); + private: + virtual const Grid* make() = 0; + const std::string uid_; }; struct GridFactoryName { - explicit GridFactoryName(const std::string& name); - virtual ~GridFactoryName(); - - virtual const Grid* make(const Configuration&) = 0; - GridFactoryName(const GridFactoryName&) = delete; GridFactoryName(GridFactoryName&&) = delete; GridFactoryName& operator=(const GridFactoryName&) = delete; GridFactoryName& operator=(GridFactoryName&&) = delete; // This is 'const' as Grid should always be immutable - static const Grid* build(const std::string&, Area* = nullptr, Projection* = nullptr); - static const Grid* build(const std::string&, Projection*); - + static const Grid* build(const std::string& name); static void list(std::ostream&); +protected: + explicit GridFactoryName(const std::string& pattern); + virtual ~GridFactoryName(); + private: - const std::string name_; + virtual Configuration* config(const std::string& name) = 0; + + const std::string pattern_; }; struct GridFactoryType { - explicit GridFactoryType(const std::string& type); - virtual ~GridFactoryType(); - - virtual const Grid* make(const Configuration&) = 0; - GridFactoryType(const GridFactoryType&) = delete; GridFactoryType(GridFactoryType&&) = delete; GridFactoryType& operator=(const GridFactoryType&) = delete; GridFactoryType& operator=(GridFactoryType&&) = delete; // This is 'const' as Grid should always be immutable - static const Grid* build(const std::string&, Area* = nullptr, Projection* = nullptr); - static const Grid* build(const std::string&, Projection*); - + static const Grid* build(const Configuration&); static void list(std::ostream&); +protected: + explicit GridFactoryType(const std::string& type); + virtual ~GridFactoryType(); + private: + virtual const Grid* make(const Configuration&) = 0; + const std::string type_; }; @@ -207,9 +204,9 @@ struct GridRegisterUID final : GridFactoryUID { template struct GridRegisterName final : GridFactoryName { - explicit GridRegisterName(const std::string& name) : - GridFactoryName(name) {} - const Grid* make(const Configuration& config) override { return new T(config); } + explicit GridRegisterName(const std::string& pattern) : + GridFactoryName(pattern) {} + Configuration* config(const std::string& name) override { return T::config(name); } }; diff --git a/src/eckit/geometry/grid/ReducedGG.cc b/src/eckit/geometry/grid/ReducedGG.cc index 6b6d4a592..a818eed7e 100644 --- a/src/eckit/geometry/grid/ReducedGG.cc +++ b/src/eckit/geometry/grid/ReducedGG.cc @@ -21,10 +21,12 @@ #include #include +#include "eckit/config/MappedConfiguration.h" #include "eckit/geometry/Iterator.h" #include "eckit/geometry/Projection.h" #include "eckit/geometry/grid/GaussianIterator.h" #include "eckit/types/Fraction.h" +#include "eckit/utils/Translator.h" namespace eckit::geometry::grid { @@ -255,10 +257,18 @@ struct ReducedGGOctahedral : ReducedGG { bbox({n, w, s, e}); } + + static Configuration* config(const std::string& name) { + Translator trans; + + return new MappedConfiguration({{"type", "reduced_gg"}, + {"N", trans(name.substr(1))}}); + } }; -static const GridRegisterType reducedFromPL("reduced_gg"); +static const GridRegisterType __grid_type("reduced_gg"); +static const GridRegisterName __grid_pattern("[oO][1-9][0-9]*"); } // namespace eckit::geometry::grid diff --git a/tests/geometry/test_grid.cc b/tests/geometry/test_grid.cc index 837342d59..72c6dffce 100644 --- a/tests/geometry/test_grid.cc +++ b/tests/geometry/test_grid.cc @@ -42,7 +42,7 @@ CASE("GridFactory::build") { SECTION("Grid::build") { std::unique_ptr grid(GridFactory::build(MappedConfiguration{ - {{"grid", "O2"}}})); + {{"name", "O2"}}})); auto size = grid->size(); EXPECT_EQUAL(size, 88); From e5afc2f7da84b4e9a3dde8c117f3dd90fe7845b2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 28 Jul 2023 12:42:12 +0100 Subject: [PATCH 262/737] eckit::geometry --- src/eckit/geometry/area/BoundingBox.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/eckit/geometry/area/BoundingBox.h b/src/eckit/geometry/area/BoundingBox.h index 56d309ca1..b931cde1d 100644 --- a/src/eckit/geometry/area/BoundingBox.h +++ b/src/eckit/geometry/area/BoundingBox.h @@ -15,9 +15,10 @@ #include #include +#include "eckit/geometry/Area.h" + namespace eckit { -class Configuration; namespace geometry { class Projection; } @@ -27,7 +28,7 @@ class Projection; namespace eckit::geometry::area { -class BoundingBox { +class BoundingBox : public Area { public: // -- Exceptions // None @@ -77,7 +78,8 @@ class BoundingBox { static BoundingBox make(const BoundingBox&, const Projection&); // -- Overridden methods - // None + + area::BoundingBox bbox() const override { return *this; } // -- Class members // None From 6771d3b42f54186cb96567a5046a6bf37ee01656 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 30 Jul 2023 01:54:55 +0100 Subject: [PATCH 263/737] eckit::geometry --- src/eckit/geometry/util/regular_pl.cc | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 src/eckit/geometry/util/regular_pl.cc diff --git a/src/eckit/geometry/util/regular_pl.cc b/src/eckit/geometry/util/regular_pl.cc deleted file mode 100644 index 9e4254c08..000000000 --- a/src/eckit/geometry/util/regular_pl.cc +++ /dev/null @@ -1,27 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/exception/Exceptions.h" -#include "eckit/geometry/util.h" - - -namespace eckit::geometry::util { - - -pl_type::value_type regular_pl(size_t N) { - ASSERT(N > 0); - - return static_cast(4 * N); -} - - -} // namespace eckit::geometry::util From bc370d2957b1d7ce2713f7b36fb91e3f136e54cd Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 30 Jul 2023 02:20:28 +0100 Subject: [PATCH 264/737] eckit::geometry --- src/eckit/geometry/CMakeLists.txt | 1 - src/eckit/geometry/grid/ReducedGG.cc | 215 ++++++++++----------------- src/eckit/geometry/grid/ReducedGG.h | 38 ++--- src/eckit/geometry/grid/RegularGG.cc | 16 +- src/eckit/geometry/grid/RegularGG.h | 3 +- src/eckit/geometry/util.h | 3 - tests/geometry/test_grid.cc | 14 +- 7 files changed, 114 insertions(+), 176 deletions(-) diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index c27afa46a..edda805f8 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -84,7 +84,6 @@ list( APPEND eckit_geometry_srcs util/monotonic_crop.cc util/reduced_classical_pl.cc util/reduced_octahedral_pl.cc - util/regular_pl.cc ) set(eckit_geometry_include_dirs ) diff --git a/src/eckit/geometry/grid/ReducedGG.cc b/src/eckit/geometry/grid/ReducedGG.cc index a818eed7e..e11bd4a57 100644 --- a/src/eckit/geometry/grid/ReducedGG.cc +++ b/src/eckit/geometry/grid/ReducedGG.cc @@ -13,13 +13,10 @@ #include "eckit/geometry/grid/ReducedGG.h" #include -#include -#include -#include #include #include #include -#include +#include #include "eckit/config/MappedConfiguration.h" #include "eckit/geometry/Iterator.h" @@ -32,66 +29,97 @@ namespace eckit::geometry::grid { +static Fraction smallest_increment(const pl_type& pl) { + auto maxpl = *std::max_element(pl.begin(), pl.end()); + ASSERT(maxpl >= 2); + return Fraction(GLOBE) / maxpl; +} + + ReducedGG::ReducedGG(const Configuration& config) : - Gaussian(config), k_(0), Nj_(N_ * 2) { + ReducedGG(config.getUnsigned("N"), config.getLongVector("pl")) {} + +ReducedGG::ReducedGG(size_t N, const pl_type& pl) : + Gaussian(N), pl_(pl), k_(0), Nj_(N_ * 2) { // adjust latitudes, longitudes and re-set bounding box auto n = bbox().north(); auto s = bbox().south(); correctSouthNorth(s, n); - pl_type pl; - ASSERT(config.get("pl", pl)); + const auto& lats = latitudes(); + + // check internal assumptions + ASSERT(pl_.size() == N_ * 2); + ASSERT(pl_.size() >= k_ + Nj_); + ASSERT(Nj_ > 0); // if pl isn't global (from file!) insert leading/trailing 0's - const auto& lats = latitudes(); if (n < lats.front() || s > lats.back()) { size_t k = 0; - size_t nj = 0; - for (auto lat : lats) { + size_t Nj = 0; + for (const auto& lat : lats) { if (n < lat) { ++k; } else if (s <= lat) { - ASSERT(pl[nj] >= 2); - ++nj; + ASSERT(pl_[Nj] >= 2); + ++Nj; } else { break; } } - ASSERT(k + nj <= N_ * 2); + ASSERT(k + Nj <= N_ * 2); if (k > 0) { - pl.reserve(N_ * 2); - pl.insert(pl.begin(), k, 0); + pl_.reserve(N_ * 2); + pl_.insert(pl_.begin(), k, 0); } - pl.resize(N_ * 2, 0); + pl_.resize(N_ * 2, 0); } - setNj(pl, s, n); - auto w = bbox().west(); - auto e = bbox().east(); - correctWestEast(w, e); + // set-up North/South + ASSERT(0 < N_ && N_ * 2 == pl_.size()); - bbox({n, w, s, e}); -} + // position to first latitude and first/last longitude + // NOTE: latitudes() spans the globe, sorted from North-to-South, k_ positions the North + // NOTE: pl spans the globe + k_ = 0; + Nj_ = N_ * 2; + + if (n < lats.front() || s > lats.back()) { + Nj_ = 0; + for (const auto& lat : lats) { + Latitude ll(lat); + if (n < ll && !angleApproximatelyEqual(n, ll)) { + ++k_; + } + else if (s < ll || angleApproximatelyEqual(s, ll)) { + ASSERT(pl_[k_ + Nj_] >= 2); + ++Nj_; + } + else { + break; + } + } + } -void ReducedGG::correctWestEast(double& w, double& e) const { + // correct West/East + auto w = bbox().west(); + auto e = bbox().east(); ASSERT(w <= e); - const Fraction smallestIncrement = getSmallestIncrement(); - ASSERT(smallestIncrement > 0); - - if (angleApproximatelyEqual(GREENWICH, w) && (angleApproximatelyEqual(GLOBE - smallestIncrement, e - w) || GLOBE - smallestIncrement < e - w || (e != w && PointLonLat::normalise_angle_to_minimum(e, w) == w))) { + const Fraction inc = smallest_increment(pl_); + ASSERT(inc > 0); + if (angleApproximatelyEqual(GREENWICH, w) && (angleApproximatelyEqual(GLOBE - inc, e - w) || GLOBE - inc < e - w || (e != w && PointLonLat::normalise_angle_to_minimum(e, w) == w))) { w = GREENWICH; - e = GLOBE - smallestIncrement; + e = GLOBE - inc; } else { - const Fraction west{w}; const Fraction east{e}; Fraction W = west; @@ -100,22 +128,20 @@ void ReducedGG::correctWestEast(double& w, double& e) const { bool first = true; std::set NiTried; - const auto& pl = pls(); for (size_t j = k_; j < k_ + Nj_; ++j) { // crop longitude-wise, track distinct attempts - const long Ni(pl[j]); + const long Ni(pl_[j]); ASSERT(Ni >= 2); if (NiTried.insert(Ni).second) { - Fraction inc = Fraction{GLOBE} / Ni; - Fraction::value_type Nw = (west / inc).integralPart(); + auto Nw = (west / inc).integralPart(); if (Nw * inc < west) { Nw += 1; } - Fraction::value_type Ne = (east / inc).integralPart(); + auto Ne = (east / inc).integralPart(); if (Ne * inc > east || Nw + Ne == Ni) { Ne -= 1; } @@ -124,10 +150,10 @@ void ReducedGG::correctWestEast(double& w, double& e) const { ASSERT(w <= Longitude(Nw * inc)); ASSERT(Longitude(Ne * inc) <= e); - if (W > double(Nw * inc) || first) { + if (W > static_cast(Nw * inc) || first) { W = Nw * inc; } - if (E < double(Ne * inc) || first) { + if (E < static_cast(Ne * inc) || first) { E = Ne * inc; } first = false; @@ -140,71 +166,20 @@ void ReducedGG::correctWestEast(double& w, double& e) const { w = W; e = E; } -} - - -const pl_type& ReducedGG::pls() const { - ASSERT(pl_.size() == N_ * 2); - ASSERT(pl_.size() >= k_ + Nj_); - ASSERT(Nj_ > 0); - - return pl_; -} - -void ReducedGG::setNj(pl_type pl, double s, double n) { - ASSERT(0 < N_ && N_ * 2 == pl.size()); - - // position to first latitude and first/last longitude - // NOTE: latitudes() spans the globe, sorted from North-to-South, k_ positions the North - // NOTE: pl spans the globe - pl_ = pl; - k_ = 0; - Nj_ = N_ * 2; - - const auto& lats = latitudes(); - if (n < lats.front() || s > lats.back()) { - Nj_ = 0; - for (const auto& lat : lats) { - Latitude ll(lat); - if (n < ll && !angleApproximatelyEqual(n, ll)) { - ++k_; - } - else if (s < ll || angleApproximatelyEqual(s, ll)) { - ASSERT(pl[k_ + Nj_] >= 2); - ++Nj_; - } - else { - break; - } - } - } - // check internal assumptions - pls(); + // bounding box + bbox({n, w, s, e}); } size_t ReducedGG::size() const { - const auto& pl = pls(); - return size_t(std::accumulate(pl.begin(), pl.end(), pl_type::value_type{0})); -} - - -Fraction ReducedGG::getSmallestIncrement() const { - using distance_t = std::make_signed::type; - - const auto& pl = pls(); - auto maxpl = *std::max_element(pl.begin() + distance_t(k_), pl.begin() + distance_t(k_ + Nj_)); - ASSERT(maxpl >= 2); - - const Fraction globe_f(GLOBE); - return globe_f / maxpl; + return size_t(std::accumulate(pl_.begin(), pl_.end(), pl_type::value_type{0})); } bool ReducedGG::isPeriodicWestEast() const { - auto inc = getSmallestIncrement(); + auto inc = smallest_increment(pl_); return bbox().east() - bbox().west() + inc >= GLOBE; } @@ -214,61 +189,29 @@ void ReducedGG::print(std::ostream& out) const { } -struct ReducedGGClassic : ReducedGG { - ReducedGGClassic(size_t N, const area::BoundingBox& box = {}) : - ReducedGG(N, box) { - - // adjust latitudes, longitudes and re-set bounding box - auto n = box.north(); - auto s = box.south(); - correctSouthNorth(s, n); - - setNj(pls("N" + std::to_string(N_)), s, n); - - auto w = box.west(); - auto e = box.east(); - correctWestEast(w, e); - - bbox({n, w, s, e}); +struct ReducedGGClassical { + static Configuration* config(const std::string& name) { + auto N = Translator{}(name.substr(1)); + return new MappedConfiguration({{"type", "reduced_gg"}, + {"N", N}, + {"pl", util::reduced_classical_pl(N)}}); } }; -struct ReducedGGFromPL : ReducedGG { - ReducedGGFromPL(const Configuration& config) : - ReducedGG(config) {} - ReducedGGFromPL(size_t N, const pl_type& pl, const area::BoundingBox& box = {}) : - ReducedGG(N, pl, box) {} -}; - - -struct ReducedGGOctahedral : ReducedGG { - ReducedGGOctahedral(size_t N, const area::BoundingBox& box = {}) : - ReducedGG(N, box) { - - // adjust latitudes, longitudes and re-set bounding box - auto [n, w, s, e] = bbox().deconstruct(); - - correctSouthNorth(s, n); - - setNj(pls("O" + std::to_string(N_)), s, n); - - correctWestEast(w, e); - - bbox({n, w, s, e}); - } - +struct ReducedGGOctahedral { static Configuration* config(const std::string& name) { - Translator trans; - + auto N = Translator{}(name.substr(1)); return new MappedConfiguration({{"type", "reduced_gg"}, - {"N", trans(name.substr(1))}}); + {"N", N}, + {"pl", util::reduced_octahedral_pl(N)}}); } }; -static const GridRegisterType __grid_type("reduced_gg"); -static const GridRegisterName __grid_pattern("[oO][1-9][0-9]*"); +static const GridRegisterType __grid_type("reduced_gg"); +static const GridRegisterName __grid_pattern_1("[nN][1-9][0-9]*"); +static const GridRegisterName __grid_pattern_2("[oO][1-9][0-9]*"); } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/ReducedGG.h b/src/eckit/geometry/grid/ReducedGG.h index c11ff2e64..6197eb7ff 100644 --- a/src/eckit/geometry/grid/ReducedGG.h +++ b/src/eckit/geometry/grid/ReducedGG.h @@ -16,11 +16,6 @@ #include "eckit/geometry/util.h" -namespace eckit { -class Fraction; -} - - namespace eckit::geometry::grid { @@ -31,16 +26,11 @@ class ReducedGG : public Gaussian { // -- Constructors - ReducedGG(const Configuration&); - - ReducedGG(size_t N, const pl_type& pl, const area::BoundingBox& box = {}) : - Gaussian(N, box), k_(0), Nj_(N_ * 2) { - setNj(pl, box.south(), box.north()); - } + explicit ReducedGG(const Configuration&); + ReducedGG(size_t N, const pl_type& pl); // -- Destructor - - ~ReducedGG() override = default; + // None // -- Convertors // None @@ -49,8 +39,7 @@ class ReducedGG : public Gaussian { // None // -- Methods - - static pl_type pls(const std::string&); + // None // -- Overridden methods // None @@ -63,23 +52,13 @@ class ReducedGG : public Gaussian { protected: // -- Constructors - - ReducedGG(size_t N, const area::BoundingBox& box = {}) : - Gaussian(N, box), k_(0), Nj_(N * 2) { - // derived classes must set k_, Nj_ using this constructor - } + // None // -- Members - - size_t k_; - size_t Nj_; + // None // -- Methods - - const pl_type& pls() const; - - void setNj(pl_type, double s, double n); - void correctWestEast(double& w, double& e) const; + // None // -- Overridden methods @@ -95,6 +74,8 @@ class ReducedGG : public Gaussian { // -- Members pl_type pl_; + size_t k_; + size_t Nj_; // -- Methods // None @@ -102,7 +83,6 @@ class ReducedGG : public Gaussian { // -- Overridden methods size_t size() const override; - Fraction getSmallestIncrement() const; // -- Class members // None diff --git a/src/eckit/geometry/grid/RegularGG.cc b/src/eckit/geometry/grid/RegularGG.cc index f6c9bcc02..816af8533 100644 --- a/src/eckit/geometry/grid/RegularGG.cc +++ b/src/eckit/geometry/grid/RegularGG.cc @@ -16,10 +16,13 @@ #include #include +#include "eckit/config/MappedConfiguration.h" #include "eckit/geometry/grid/GaussianIterator.h" #include "eckit/geometry/grid/RegularGG.h" +#include "eckit/geometry/util.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" +#include "eckit/utils/Translator.h" namespace eckit::geometry::grid { @@ -60,6 +63,16 @@ RegularGG::RegularGG(size_t N, const area::BoundingBox& box) : } +Configuration* RegularGG::config(const std::string& name) { + auto N = Translator{}(name.substr(1)); + + return new MappedConfiguration({{"type", "regular_gg"}, + {"N", N}, + {"Ni", 2 * N}, + {"Nj", 4 * N}}); +} + + void RegularGG::correctWestEast(double& w, double& e) const { ASSERT(w <= e); @@ -177,7 +190,8 @@ Iterator* RegularGG::iterator() const { #endif -static const GridRegisterType reducedGG("regular_gg"); +static const GridRegisterType __grid_type("regular_gg"); +static const GridRegisterName __grid_pattern("[fF][1-9][0-9]*"); } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/RegularGG.h b/src/eckit/geometry/grid/RegularGG.h index a6395f60c..2136765f6 100644 --- a/src/eckit/geometry/grid/RegularGG.h +++ b/src/eckit/geometry/grid/RegularGG.h @@ -46,7 +46,8 @@ class RegularGG final : public Gaussian { // None // -- Overridden methods - // None + + static Configuration* config(const std::string& name); // -- Class members // None diff --git a/src/eckit/geometry/util.h b/src/eckit/geometry/util.h index d8fffe2ae..0c315cb54 100644 --- a/src/eckit/geometry/util.h +++ b/src/eckit/geometry/util.h @@ -66,9 +66,6 @@ const pl_type& reduced_classical_pl(size_t N); const pl_type& reduced_octahedral_pl(size_t N); -pl_type::value_type regular_pl(size_t N); - - } // namespace util diff --git a/tests/geometry/test_grid.cc b/tests/geometry/test_grid.cc index 72c6dffce..abf1cbc8d 100644 --- a/tests/geometry/test_grid.cc +++ b/tests/geometry/test_grid.cc @@ -25,10 +25,14 @@ using namespace geometry; CASE("GridFactory::build") { SECTION("GridFactory::build_from_name") { - std::unique_ptr grid(GridFactoryName::build("O2")); + std::unique_ptr o(GridFactoryName::build("O2")); - auto size = grid->size(); - EXPECT_EQUAL(size, 88); + // auto size = o->size(); + // EXPECT_EQUAL(size, 88); + + std::unique_ptr f(GridFactoryName::build("f2")); + // auto size = o->size(); + // EXPECT_EQUAL(size, 88); } @@ -44,8 +48,8 @@ CASE("GridFactory::build") { std::unique_ptr grid(GridFactory::build(MappedConfiguration{ {{"name", "O2"}}})); - auto size = grid->size(); - EXPECT_EQUAL(size, 88); + // auto size = grid->size(); + // EXPECT_EQUAL(size, 88); } } From 7b30ef965d34c73c9bb8b90bd9cf81607b3d6b4b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 1 Aug 2023 18:22:19 +0100 Subject: [PATCH 265/737] eckit::geometry --- src/eckit/geometry/area/BoundingBox.cc | 5 +---- src/eckit/geometry/grid/RegularGG.cc | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/eckit/geometry/area/BoundingBox.cc b/src/eckit/geometry/area/BoundingBox.cc index fc4052eb6..2eaef3f5a 100644 --- a/src/eckit/geometry/area/BoundingBox.cc +++ b/src/eckit/geometry/area/BoundingBox.cc @@ -27,10 +27,7 @@ namespace eckit::geometry::area { BoundingBox::BoundingBox(const Configuration& config) : - north_(config.getDouble("north")), - west_(config.getDouble("west")), - south_(config.getDouble("south")), - east_(config.getDouble("east")) { + BoundingBox(config.getDouble("north", 90.), config.getDouble("west", 0.), config.getDouble("south", -90.), config.getDouble("east", 360.)) { } diff --git a/src/eckit/geometry/grid/RegularGG.cc b/src/eckit/geometry/grid/RegularGG.cc index 816af8533..18be391a6 100644 --- a/src/eckit/geometry/grid/RegularGG.cc +++ b/src/eckit/geometry/grid/RegularGG.cc @@ -64,8 +64,7 @@ RegularGG::RegularGG(size_t N, const area::BoundingBox& box) : Configuration* RegularGG::config(const std::string& name) { - auto N = Translator{}(name.substr(1)); - + auto N = Translator{}(name.substr(1)); return new MappedConfiguration({{"type", "regular_gg"}, {"N", N}, {"Ni", 2 * N}, From 041754ce1d8fab48dc223e683059edc76df689a4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 2 Aug 2023 00:34:55 +0100 Subject: [PATCH 266/737] eckit::geometry --- src/eckit/geometry/Grid.h | 8 +--- src/eckit/geometry/grid/GaussianIterator.cc | 10 ----- src/eckit/geometry/grid/GaussianIterator.h | 1 - src/eckit/geometry/grid/IrregularLatlon.cc | 12 ------ src/eckit/geometry/grid/IrregularLatlon.h | 1 - src/eckit/geometry/grid/ReducedGG.cc | 44 ++++++--------------- src/eckit/geometry/grid/ReducedGG.h | 5 ++- src/eckit/geometry/grid/ReducedLL.cc | 12 ------ src/eckit/geometry/grid/ReducedLL.h | 2 - src/eckit/geometry/grid/RegularGG.cc | 8 ---- src/eckit/geometry/grid/RegularGG.h | 1 - src/eckit/geometry/grid/RegularGrid.cc | 12 ------ src/eckit/geometry/grid/RegularGrid.h | 1 - src/eckit/geometry/grid/RegularLL.cc | 13 ------ src/eckit/geometry/grid/RegularLL.h | 1 - src/eckit/geometry/grid/UnstructuredGrid.cc | 12 ------ src/eckit/geometry/grid/UnstructuredGrid.h | 3 +- 17 files changed, 16 insertions(+), 130 deletions(-) diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 4861e90d1..a5f0dfc55 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -62,8 +62,6 @@ class Grid { virtual size_t size() const = 0; - virtual void print(std::ostream&) const = 0; - virtual bool includesNorthPole() const = 0; virtual bool includesSouthPole() const = 0; virtual bool isPeriodicWestEast() const = 0; @@ -116,11 +114,7 @@ class Grid { // None // -- Friends - - friend std::ostream& operator<<(std::ostream& s, const Grid& p) { - p.print(s); - return s; - } + // None }; diff --git a/src/eckit/geometry/grid/GaussianIterator.cc b/src/eckit/geometry/grid/GaussianIterator.cc index 2f3abd1b6..ee2c6d567 100644 --- a/src/eckit/geometry/grid/GaussianIterator.cc +++ b/src/eckit/geometry/grid/GaussianIterator.cc @@ -12,8 +12,6 @@ #include "eckit/geometry/grid/GaussianIterator.h" -#include - #include "eckit/exception/Exceptions.h" @@ -70,14 +68,6 @@ size_t GaussianIterator::resetToRow(size_t j) { } -void GaussianIterator::print(std::ostream& out) const { - out << "GaussianIterator["; - Iterator::print(out); - out << ",N=" << N_ << ",bbox=" << bbox_ << ",Ni=" << Ni_ << ",Nj=" << Nj_ << ",i=" << i_ << ",j=" << j_ - << ",k=" << k_ << ",count=" << count_ << "]"; -} - - bool GaussianIterator::operator++() { while (Ni_ == 0 && j_ < Nj_) { Ni_ = resetToRow(k_ + j_++); diff --git a/src/eckit/geometry/grid/GaussianIterator.h b/src/eckit/geometry/grid/GaussianIterator.h index d4c03f777..4769ed26e 100644 --- a/src/eckit/geometry/grid/GaussianIterator.h +++ b/src/eckit/geometry/grid/GaussianIterator.h @@ -46,7 +46,6 @@ class GaussianIterator : public Iterator { size_t count_; bool first_; - void print(std::ostream&) const override; bool operator++() override; size_t index() const override; size_t size() const override; diff --git a/src/eckit/geometry/grid/IrregularLatlon.cc b/src/eckit/geometry/grid/IrregularLatlon.cc index 7440c31cf..2457a9fd0 100644 --- a/src/eckit/geometry/grid/IrregularLatlon.cc +++ b/src/eckit/geometry/grid/IrregularLatlon.cc @@ -13,7 +13,6 @@ #include "eckit/geometry/grid/IrregularLatlon.h" #include -#include #include "eckit/utils/MD5.h" @@ -55,11 +54,6 @@ size_t IrregularLatlon::size() const { } -void IrregularLatlon::print(std::ostream& out) const { - out << "IrregularLatlon[latitudes=" << latitudes_.size() << ",longitudes=" << longitudes_.size() << "]"; -} - - class IrregularLatlonIterator : public Iterator { size_t i_; size_t ni_; @@ -71,12 +65,6 @@ class IrregularLatlonIterator : public Iterator { const std::vector& latitudes_; const std::vector& longitudes_; - void print(std::ostream& out) const override { - out << "IrregularLatlonIterator["; - Iterator::print(out); - out << "]"; - } - bool operator++() override { if (j_ < nj_) { if (i_ < ni_) { diff --git a/src/eckit/geometry/grid/IrregularLatlon.h b/src/eckit/geometry/grid/IrregularLatlon.h index 34ec9f894..f02497e9e 100644 --- a/src/eckit/geometry/grid/IrregularLatlon.h +++ b/src/eckit/geometry/grid/IrregularLatlon.h @@ -70,7 +70,6 @@ class IrregularLatlon final : public Grid { bool isPeriodicWestEast() const override; bool includesNorthPole() const override; bool includesSouthPole() const override; - void print(std::ostream&) const override; // -- Class members // None diff --git a/src/eckit/geometry/grid/ReducedGG.cc b/src/eckit/geometry/grid/ReducedGG.cc index e11bd4a57..f02ddbe18 100644 --- a/src/eckit/geometry/grid/ReducedGG.cc +++ b/src/eckit/geometry/grid/ReducedGG.cc @@ -14,7 +14,6 @@ #include #include -#include #include #include @@ -54,32 +53,6 @@ ReducedGG::ReducedGG(size_t N, const pl_type& pl) : ASSERT(pl_.size() >= k_ + Nj_); ASSERT(Nj_ > 0); - // if pl isn't global (from file!) insert leading/trailing 0's - if (n < lats.front() || s > lats.back()) { - size_t k = 0; - size_t Nj = 0; - for (const auto& lat : lats) { - if (n < lat) { - ++k; - } - else if (s <= lat) { - ASSERT(pl_[Nj] >= 2); - ++Nj; - } - else { - break; - } - } - ASSERT(k + Nj <= N_ * 2); - - if (k > 0) { - pl_.reserve(N_ * 2); - pl_.insert(pl_.begin(), k, 0); - } - pl_.resize(N_ * 2, 0); - } - - // set-up North/South ASSERT(0 < N_ && N_ * 2 == pl_.size()); @@ -170,11 +143,21 @@ ReducedGG::ReducedGG(size_t N, const pl_type& pl) : // bounding box bbox({n, w, s, e}); + + + // accumulated pl + placc_.resize(1 + pl_.size()); + placc_.front() = 0; + + auto i = pl_.begin(); + for (auto j = placc_.begin(), k = j + 1; k != placc_.end(); ++i, ++j, ++k) { + *k = *i + *j; + } } size_t ReducedGG::size() const { - return size_t(std::accumulate(pl_.begin(), pl_.end(), pl_type::value_type{0})); + return static_cast(placc_.back()); } @@ -184,11 +167,6 @@ bool ReducedGG::isPeriodicWestEast() const { } -void ReducedGG::print(std::ostream& out) const { - out << "ReducedGG[N=" << N_ << ",bbox=" << bbox() << "]"; -} - - struct ReducedGGClassical { static Configuration* config(const std::string& name) { auto N = Translator{}(name.substr(1)); diff --git a/src/eckit/geometry/grid/ReducedGG.h b/src/eckit/geometry/grid/ReducedGG.h index 6197eb7ff..ab9f1a7c7 100644 --- a/src/eckit/geometry/grid/ReducedGG.h +++ b/src/eckit/geometry/grid/ReducedGG.h @@ -63,7 +63,6 @@ class ReducedGG : public Gaussian { // -- Overridden methods bool isPeriodicWestEast() const override; - void print(std::ostream& out) const override; // -- Class members @@ -73,7 +72,9 @@ class ReducedGG : public Gaussian { private: // -- Members - pl_type pl_; + const pl_type& pl_; + pl_type placc_; + size_t k_; size_t Nj_; diff --git a/src/eckit/geometry/grid/ReducedLL.cc b/src/eckit/geometry/grid/ReducedLL.cc index 879c5ddea..0ea350059 100644 --- a/src/eckit/geometry/grid/ReducedLL.cc +++ b/src/eckit/geometry/grid/ReducedLL.cc @@ -14,7 +14,6 @@ #include #include -#include #include #include "eckit/geometry/Domain.h" @@ -43,10 +42,6 @@ ReducedLL::ReducedLL(const Configuration& config) : ReducedLL::~ReducedLL() = default; -void ReducedLL::print(std::ostream& out) const { - out << "ReducedLL[bbox=" << bbox() << "]"; -} - size_t ReducedLL::size() const { size_t total = 0; for (const auto& j : pl_) { @@ -97,13 +92,6 @@ class ReducedLLIterator : public Iterator { bool first_; bool periodic_; - void print(std::ostream& out) const override { - out << "ReducedLLIterator["; - Iterator::print(out); - out << ",domain=" << domain_ << ",ni=" << ni_ << ",nj=" << nj_ << ",i=" << i_ << ",j=" << j_ << ",p=" << p_ - << ",count=" << count_ << "]"; - } - bool operator++() override { while (j_ < nj_ && i_ < ni_) { // lat = latitude_; diff --git a/src/eckit/geometry/grid/ReducedLL.h b/src/eckit/geometry/grid/ReducedLL.h index aea11fa0a..9ddf9c94a 100644 --- a/src/eckit/geometry/grid/ReducedLL.h +++ b/src/eckit/geometry/grid/ReducedLL.h @@ -65,8 +65,6 @@ class ReducedLL : public Grid { bool includesNorthPole() const override; bool includesSouthPole() const override; - void print(std::ostream&) const override; - // -- Class members // None diff --git a/src/eckit/geometry/grid/RegularGG.cc b/src/eckit/geometry/grid/RegularGG.cc index 18be391a6..d456e145d 100644 --- a/src/eckit/geometry/grid/RegularGG.cc +++ b/src/eckit/geometry/grid/RegularGG.cc @@ -13,7 +13,6 @@ #include "eckit/geometry/grid/RegularGG.h" #include -#include #include #include "eckit/config/MappedConfiguration.h" @@ -174,13 +173,6 @@ void RegularGG::setNiNj() { } -void RegularGG::print(std::ostream& out) const { - out << "RegularGG[" - "N=" - << N_ << ",Ni=" << Ni_ << ",Nj=" << Nj_ << ",bbox=" << bbox() << "]"; -} - - #if 0 Iterator* RegularGG::iterator() const { std::vector pl(N_ * 2, long(4 * N_)); diff --git a/src/eckit/geometry/grid/RegularGG.h b/src/eckit/geometry/grid/RegularGG.h index 2136765f6..6c8f64d96 100644 --- a/src/eckit/geometry/grid/RegularGG.h +++ b/src/eckit/geometry/grid/RegularGG.h @@ -72,7 +72,6 @@ class RegularGG final : public Gaussian { size_t size() const override; - void print(std::ostream&) const override; bool isPeriodicWestEast() const override; // -- Class members diff --git a/src/eckit/geometry/grid/RegularGrid.cc b/src/eckit/geometry/grid/RegularGrid.cc index 3927b6cc8..2d2d952ed 100644 --- a/src/eckit/geometry/grid/RegularGrid.cc +++ b/src/eckit/geometry/grid/RegularGrid.cc @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "eckit/config/MappedConfiguration.h" @@ -106,11 +105,6 @@ Projection* RegularGrid::make_projection_from_proj(const Configuration& config) } -void RegularGrid::print(std::ostream& out) const { - NOTIMP; -} - - size_t RegularGrid::size() const { return x_.size() * y_.size(); } @@ -144,12 +138,6 @@ Iterator* RegularGrid::iterator() const { size_t j_; size_t count_; - void print(std::ostream& out) const override { - out << "RegularGridIterator["; - Iterator::print(out); - out << ",i=" << i_ << ",j=" << j_ << ",count=" << count_ << "]"; - } - bool operator++() override { if (j_ < nj_ && i_ < ni_) { const auto p = projection_.inv(Point2{x_[i_], y_[j_]}); diff --git a/src/eckit/geometry/grid/RegularGrid.h b/src/eckit/geometry/grid/RegularGrid.h index d4cbf7b9b..55d235a0d 100644 --- a/src/eckit/geometry/grid/RegularGrid.h +++ b/src/eckit/geometry/grid/RegularGrid.h @@ -87,7 +87,6 @@ class RegularGrid : public Grid { bool includesSouthPole() const override; bool isPeriodicWestEast() const override; - void print(std::ostream&) const override; size_t size() const override; // -- Class members diff --git a/src/eckit/geometry/grid/RegularLL.cc b/src/eckit/geometry/grid/RegularLL.cc index 61c1c4695..367e82ca4 100644 --- a/src/eckit/geometry/grid/RegularLL.cc +++ b/src/eckit/geometry/grid/RegularLL.cc @@ -13,7 +13,6 @@ #include "eckit/geometry/grid/RegularLL.h" #include -#include #include #include "eckit/exception/Exceptions.h" @@ -137,12 +136,6 @@ RegularLL::RegularLL(const Increments& increments, const area::BoundingBox& bb, } -void RegularLL::print(std::ostream& out) const { - out << "RegularLL[" - << "bbox=" << bbox() << ",increments=" << increments_ << ",ni=" << ni_ << ",nj=" << nj_ << "]"; -} - - bool RegularLL::isPeriodicWestEast() const { // if range West-East is within one increment (or greater than) 360 degree return bbox().east() - bbox().west() + increments_.west_east >= GLOBE; @@ -226,12 +219,6 @@ Iterator* RegularLL::iterator() const { ASSERT(count == ni_ * nj_); } - void print(std::ostream& out) const override { - out << "RegularLLIterator[" - << "ni=" << ni_ << ",nj=" << nj_ << ",north=" << north_ << ",west=" << west_ << ",we=" << we_ << ",ns=" << ns_ - << ",i=" << i_ << ",j=" << j_ << ",count=" << count_ << "]"; - } - bool operator++() override { if (j_ < nj_) { if (i_ < ni_) { diff --git a/src/eckit/geometry/grid/RegularLL.h b/src/eckit/geometry/grid/RegularLL.h index 888c03fcc..c959fb7d6 100644 --- a/src/eckit/geometry/grid/RegularLL.h +++ b/src/eckit/geometry/grid/RegularLL.h @@ -66,7 +66,6 @@ class RegularLL : public Grid { // -- Overridden methods - void print(std::ostream&) const override; bool isPeriodicWestEast() const override; bool includesNorthPole() const override; bool includesSouthPole() const override; diff --git a/src/eckit/geometry/grid/UnstructuredGrid.cc b/src/eckit/geometry/grid/UnstructuredGrid.cc index 16d22bd4d..6072ba39d 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.cc +++ b/src/eckit/geometry/grid/UnstructuredGrid.cc @@ -14,7 +14,6 @@ #include #include -#include #include #include #include @@ -86,12 +85,6 @@ class UnstructuredIterator : public Iterator { // From Iterator - void print(std::ostream& out) const override { - out << "UnstructuredGridIterator["; - Iterator::print(out); - out << "]"; - } - bool operator++() override { if ((first_ ? count_ : ++count_) < size_) { first_ = false; @@ -179,11 +172,6 @@ UnstructuredGrid::UnstructuredGrid(const std::vector& latitudes, const s UnstructuredGrid::~UnstructuredGrid() = default; -void UnstructuredGrid::print(std::ostream& out) const { - out << "UnstructuredGrid[points=" << size() << "]"; -} - - size_t UnstructuredGrid::size() const { ASSERT(latitudes_.size() == longitudes_.size()); return latitudes_.size(); diff --git a/src/eckit/geometry/grid/UnstructuredGrid.h b/src/eckit/geometry/grid/UnstructuredGrid.h index 7327f21d2..8742e51ac 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.h +++ b/src/eckit/geometry/grid/UnstructuredGrid.h @@ -69,8 +69,7 @@ class UnstructuredGrid : public Grid { // None // -- Methods - - void print(std::ostream&) const override; + // None // -- Overridden methods // None From 208c33cf20a2f1609a029734337da566f688b970 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 2 Aug 2023 00:35:08 +0100 Subject: [PATCH 267/737] eckit::geometry --- src/eckit/geometry/CMakeLists.txt | 2 + src/eckit/geometry/grid/HEALPix.cc | 58 ++++++++++++++++++++ src/eckit/geometry/grid/HEALPix.h | 85 ++++++++++++++++++++++++++++++ tests/geometry/test_grid.cc | 23 ++++---- 4 files changed, 158 insertions(+), 10 deletions(-) create mode 100644 src/eckit/geometry/grid/HEALPix.cc create mode 100644 src/eckit/geometry/grid/HEALPix.h diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index edda805f8..2971e20ec 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -46,6 +46,8 @@ list( APPEND eckit_geometry_srcs grid/Gaussian.h grid/GaussianIterator.cc grid/GaussianIterator.h + grid/HEALPix.cc + grid/HEALPix.h grid/IrregularLatlon.cc grid/IrregularLatlon.h grid/ReducedGG.cc diff --git a/src/eckit/geometry/grid/HEALPix.cc b/src/eckit/geometry/grid/HEALPix.cc new file mode 100644 index 000000000..2037af5f4 --- /dev/null +++ b/src/eckit/geometry/grid/HEALPix.cc @@ -0,0 +1,58 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/grid/HEALPix.h" + +#include "eckit/config/MappedConfiguration.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geometry/area/BoundingBox.h" +#include "eckit/utils/Translator.h" + + +namespace eckit::geometry::grid { + + +static const area::BoundingBox __global; + + +HEALPix::HEALPix(const Configuration& config) : + HEALPix(config.getUnsigned("Nside")) { +} + + +HEALPix::HEALPix(size_t Nside) : + Grid(__global), N_(Nside) { + ASSERT(N_ > 0); +} + + +Configuration* HEALPix::config(const std::string& name) { + auto Nside = Translator{}(name.substr(1)); + return new MappedConfiguration({{"type", "healpix"}, {"Nside", Nside}}); +} + + +const area::BoundingBox& HEALPix::boundingBox() const { + return __global; +} + + +size_t HEALPix::size() const { + return 12 * N_ * N_; +} + + +static const GridRegisterType __grid_type("healpix"); +static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); + + +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/HEALPix.h b/src/eckit/geometry/grid/HEALPix.h new file mode 100644 index 000000000..e56431eef --- /dev/null +++ b/src/eckit/geometry/grid/HEALPix.h @@ -0,0 +1,85 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geometry/Grid.h" + + +namespace eckit::geometry::grid { + + +class HEALPix final : public Grid { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit HEALPix(const Configuration&); + explicit HEALPix(size_t Nside); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + + static Configuration* config(const std::string& name); + + // -- Class methods + // None + +private: + // -- Members + + const size_t N_; + + // -- Methods + // None + + // -- Overridden methods + + const area::BoundingBox& boundingBox() const override; + + size_t size() const override; + + bool includesNorthPole() const override { return true; } + bool includesSouthPole() const override { return true; } + bool isPeriodicWestEast() const override { return true; } + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geometry::grid diff --git a/tests/geometry/test_grid.cc b/tests/geometry/test_grid.cc index abf1cbc8d..e18dcafb9 100644 --- a/tests/geometry/test_grid.cc +++ b/tests/geometry/test_grid.cc @@ -20,19 +20,22 @@ namespace eckit::test { -using namespace geometry; +CASE("GridFactory::build") { + using geometry::Grid; -CASE("GridFactory::build") { - SECTION("GridFactory::build_from_name") { - std::unique_ptr o(GridFactoryName::build("O2")); + struct test_t { + std::string name; + size_t size; + }; - // auto size = o->size(); - // EXPECT_EQUAL(size, 88); - std::unique_ptr f(GridFactoryName::build("f2")); - // auto size = o->size(); - // EXPECT_EQUAL(size, 88); + SECTION("GridFactory::build_from_name") { + for (const auto& test : {test_t{"O2", 88}, {"f2", 32}, {"h2", 48}}) { + std::unique_ptr grid(geometry::GridFactoryName::build(test.name)); + auto size = grid->size(); + EXPECT_EQUAL(size, test.size); + } } @@ -45,7 +48,7 @@ CASE("GridFactory::build") { SECTION("Grid::build") { - std::unique_ptr grid(GridFactory::build(MappedConfiguration{ + std::unique_ptr grid(geometry::GridFactory::build(MappedConfiguration{ {{"name", "O2"}}})); // auto size = grid->size(); From f6d280f5396deeeb01461c7946d066c3ad142277 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 2 Aug 2023 01:49:53 +0100 Subject: [PATCH 268/737] eckit::geometry --- src/eckit/geometry/grid/HEALPix.cc | 54 +++++++++++++++++++++++++++--- src/eckit/geometry/grid/HEALPix.h | 19 +++++++++-- 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/eckit/geometry/grid/HEALPix.cc b/src/eckit/geometry/grid/HEALPix.cc index 2037af5f4..ec8f7f5de 100644 --- a/src/eckit/geometry/grid/HEALPix.cc +++ b/src/eckit/geometry/grid/HEALPix.cc @@ -15,6 +15,7 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geometry/area/BoundingBox.h" +#include "eckit/geometry/util.h" #include "eckit/utils/Translator.h" @@ -24,20 +25,65 @@ namespace eckit::geometry::grid { static const area::BoundingBox __global; +static HEALPix::ordering_type ordering_type_from_string(const std::string& str) { + return str == "ring" ? HEALPix::ordering_type::ring : str == "nested" ? HEALPix::ordering_type::nested + : throw AssertionFailed("HEALPix::ordering_type", Here()); +} + + HEALPix::HEALPix(const Configuration& config) : - HEALPix(config.getUnsigned("Nside")) { + HEALPix(config.getUnsigned("Nside"), ordering_type_from_string(config.getString("orderingConvention", "ring"))) { } -HEALPix::HEALPix(size_t Nside) : - Grid(__global), N_(Nside) { +HEALPix::HEALPix(size_t Nside, ordering_type ordering) : + Grid(__global), N_(Nside), ordering_(ordering), latitude_(ni()) { ASSERT(N_ > 0); + ASSERT(ordering_ == ordering_type::ring); + + + // accumulated nj + njacc_.resize(1 + ni()); + njacc_.front() = 0; + + size_t i = 0; + for (auto j = njacc_.begin(), k = j + 1; k != njacc_.end(); ++i, ++j, ++k) { + *k = *j + nj(i); + } + + ASSERT(njacc_.back() == size()); + + + // latitude + auto j = latitude_.begin(); + auto k = latitude_.rbegin(); + for (size_t i = 1; i < 2 * N_; ++i, ++j, ++k) { + auto c = i < N_ ? 1. - static_cast(i * i) / static_cast(3 * N_ * N_) + : static_cast(4 * N_ - 2 * i) / static_cast(3 * N_); + + *j = 90. - util::radian_to_degree * std::acos(c); + *k = -*j; + } + + latitude_[2 * N_ - 1] = 0.; } Configuration* HEALPix::config(const std::string& name) { auto Nside = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "healpix"}, {"Nside", Nside}}); + return new MappedConfiguration({{"type", "healpix"}, {"Nside", Nside}, {"orderingConvention", "ring"}}); +} + + +size_t HEALPix::ni() const { + return 4 * N_ - 1; +} + + +size_t HEALPix::nj(size_t i) const { + ASSERT(0 <= i && i < ni()); + return i < N_ ? 4 * (i + 1) : i < 3 * N_ ? 4 * N_ + : nj(ni() - 1 - i); } diff --git a/src/eckit/geometry/grid/HEALPix.h b/src/eckit/geometry/grid/HEALPix.h index e56431eef..2ee3298ef 100644 --- a/src/eckit/geometry/grid/HEALPix.h +++ b/src/eckit/geometry/grid/HEALPix.h @@ -12,6 +12,8 @@ #pragma once +#include + #include "eckit/geometry/Grid.h" @@ -21,7 +23,12 @@ namespace eckit::geometry::grid { class HEALPix final : public Grid { public: // -- Types - // None + + enum ordering_type + { + ring, + nested + }; // -- Exceptions // None @@ -29,7 +36,7 @@ class HEALPix final : public Grid { // -- Constructors explicit HEALPix(const Configuration&); - explicit HEALPix(size_t Nside); + explicit HEALPix(size_t Nside, ordering_type); // -- Destructor // None @@ -57,9 +64,15 @@ class HEALPix final : public Grid { // -- Members const size_t N_; + const ordering_type ordering_; + + std::vector njacc_; + std::vector latitude_; // -- Methods - // None + + size_t ni() const; + size_t nj(size_t i) const; // -- Overridden methods From c205ee7c0bc9ea55330697553dd825aaea13ef8d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 5 Aug 2023 00:51:17 +0100 Subject: [PATCH 269/737] eckit::geometry --- src/eckit/geometry/grid/HEALPix.cc | 66 ++++++++++++++++++++++-------- src/eckit/geometry/grid/HEALPix.h | 7 +++- 2 files changed, 56 insertions(+), 17 deletions(-) diff --git a/src/eckit/geometry/grid/HEALPix.cc b/src/eckit/geometry/grid/HEALPix.cc index ec8f7f5de..ed7381445 100644 --- a/src/eckit/geometry/grid/HEALPix.cc +++ b/src/eckit/geometry/grid/HEALPix.cc @@ -12,6 +12,9 @@ #include "eckit/geometry/grid/HEALPix.h" +#include +#include + #include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geometry/area/BoundingBox.h" @@ -37,7 +40,7 @@ HEALPix::HEALPix(const Configuration& config) : HEALPix::HEALPix(size_t Nside, ordering_type ordering) : - Grid(__global), N_(Nside), ordering_(ordering), latitude_(ni()) { + Grid(__global), N_(Nside), ordering_(ordering) { ASSERT(N_ > 0); ASSERT(ordering_ == ordering_type::ring); @@ -52,20 +55,6 @@ HEALPix::HEALPix(size_t Nside, ordering_type ordering) : } ASSERT(njacc_.back() == size()); - - - // latitude - auto j = latitude_.begin(); - auto k = latitude_.rbegin(); - for (size_t i = 1; i < 2 * N_; ++i, ++j, ++k) { - auto c = i < N_ ? 1. - static_cast(i * i) / static_cast(3 * N_ * N_) - : static_cast(4 * N_ - 2 * i) / static_cast(3 * N_); - - *j = 90. - util::radian_to_degree * std::acos(c); - *k = -*j; - } - - latitude_[2 * N_ - 1] = 0.; } @@ -81,12 +70,57 @@ size_t HEALPix::ni() const { size_t HEALPix::nj(size_t i) const { - ASSERT(0 <= i && i < ni()); + ASSERT(i < ni()); return i < N_ ? 4 * (i + 1) : i < 3 * N_ ? 4 * N_ : nj(ni() - 1 - i); } +const std::vector& HEALPix::latitudes() const { + const auto Ni = ni(); + + if (lats_.empty()) { + lats_.resize(Ni); + + auto i = lats_.begin(); + auto j = lats_.rbegin(); + for (int ring = 1; ring < 2 * N_; ++ring, ++i, ++j) { + const auto f = ring < N_ ? 1. - static_cast(ring * ring) / (3 * static_cast(N_ * N_)) : 4. / 3. - 2 * static_cast(ring) / (3 * static_cast(N_)); + + *i = 90. - util::radian_to_degree * std::acos(f); + *j = -*i; + } + *i = 0.; + + return lats_; + } + + ASSERT(lats_.size() == Ni); + return lats_; +} + + +const std::vector& HEALPix::longitudes(size_t i) const { + const auto Ni = ni(); + ASSERT(i < Ni); + + // ring index: 1-based, symmetric, in range [1, Nside_ + 1] + const auto Nj = nj(i); + const auto ring = i >= N_ * 3 ? Ni - i : i >= N_ ? 1 + N_ - i % 2 + : 1 + i; + + const auto step = 360. / static_cast(Nj); + const auto start = static_cast(i % 2) ? 180. / static_cast(Nj) : ring == 1 ? 45. + : 0.; + + lons_.reserve(N_ * 4); + lons_.resize(Nj); + std::generate_n(lons_.begin(), Nj, [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); + + return lons_; +} + + const area::BoundingBox& HEALPix::boundingBox() const { return __global; } diff --git a/src/eckit/geometry/grid/HEALPix.h b/src/eckit/geometry/grid/HEALPix.h index 2ee3298ef..0a384578c 100644 --- a/src/eckit/geometry/grid/HEALPix.h +++ b/src/eckit/geometry/grid/HEALPix.h @@ -67,13 +67,18 @@ class HEALPix final : public Grid { const ordering_type ordering_; std::vector njacc_; - std::vector latitude_; + + mutable std::vector lats_; + mutable std::vector lons_; // -- Methods size_t ni() const; size_t nj(size_t i) const; + const std::vector& latitudes() const; + const std::vector& longitudes(size_t i) const; + // -- Overridden methods const area::BoundingBox& boundingBox() const override; From aa5acfc3fbac133b065614948b962b1f8e6fbe3f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 7 Aug 2023 21:19:26 +0100 Subject: [PATCH 270/737] eckit::geometry --- src/eckit/geometry/CMakeLists.txt | 2 - src/eckit/geometry/Grid.h | 57 +++++- src/eckit/geometry/Iterator.cc | 99 ---------- src/eckit/geometry/Iterator.h | 190 -------------------- src/eckit/geometry/grid/Gaussian.h | 10 +- src/eckit/geometry/grid/GaussianIterator.cc | 4 + src/eckit/geometry/grid/GaussianIterator.h | 4 + src/eckit/geometry/grid/HEALPix.h | 9 + src/eckit/geometry/grid/IrregularLatlon.cc | 72 +------- src/eckit/geometry/grid/ReducedGG.cc | 1 - src/eckit/geometry/grid/ReducedLL.cc | 88 --------- src/eckit/geometry/grid/ReducedLL.h | 9 + src/eckit/geometry/grid/RegularGrid.cc | 9 +- src/eckit/geometry/grid/RegularLL.cc | 1 - src/eckit/geometry/grid/RegularLL.h | 9 + src/eckit/geometry/grid/UnstructuredGrid.cc | 11 +- 16 files changed, 106 insertions(+), 469 deletions(-) delete mode 100644 src/eckit/geometry/Iterator.cc delete mode 100644 src/eckit/geometry/Iterator.h diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index 2971e20ec..c0c1668b2 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -16,8 +16,6 @@ list( APPEND eckit_geometry_srcs Grid.h Increments.cc Increments.h - Iterator.cc - Iterator.h KPoint.cc KPoint.h Point.cc diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index a5f0dfc55..75f9e65d3 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include #include @@ -31,7 +32,40 @@ namespace eckit::geometry { class Grid { public: // -- Types - // None + + struct Iterator { + explicit Iterator(const Grid& grid) : + grid_(grid) {} + + Iterator(const Iterator&) = delete; + Iterator(Iterator&&) = delete; + + virtual ~Iterator() = default; + + void operator=(const Iterator&) = delete; + void operator=(Iterator&&) = delete; + + bool operator!=(const Iterator& other) const { return &grid_ != &other.grid_ || index_ != other.index_; } + + bool operator++() { + index_++; + return operator bool(); + } + + virtual explicit operator bool() = 0; + virtual const Point& operator*() const = 0; + + size_t size() const { return grid_.size(); } + size_t index() const { return index_; } + + private: + const Grid& grid_; + size_t index_ = 0; + }; + + + using iterator = std::unique_ptr; + using const_iterator = std::unique_ptr; // -- Exceptions // None @@ -40,8 +74,8 @@ class Grid { explicit Grid(const Configuration&); - Grid(const Grid&) = default; - Grid(Grid&&) = default; + Grid(const Grid&) = delete; + Grid(Grid&&) = delete; // -- Destructor @@ -53,11 +87,20 @@ class Grid { // -- Operators // None - Grid& operator=(const Grid&) = default; - Grid& operator=(Grid&&) = default; + Grid& operator=(const Grid&) = delete; + Grid& operator=(Grid&&) = delete; // -- Methods + virtual iterator begin() = 0; + virtual iterator end() = 0; + + virtual const_iterator cbegin() const = 0; + virtual const_iterator cend() const = 0; + + virtual const_iterator begin() const = 0; + virtual const_iterator end() const = 0; + virtual const area::BoundingBox& boundingBox() const; virtual size_t size() const = 0; @@ -78,9 +121,7 @@ class Grid { protected: // -- Constructors - Grid(const area::BoundingBox&); - - // None + explicit Grid(const area::BoundingBox&); // -- Methods diff --git a/src/eckit/geometry/Iterator.cc b/src/eckit/geometry/Iterator.cc deleted file mode 100644 index fc79cd52f..000000000 --- a/src/eckit/geometry/Iterator.cc +++ /dev/null @@ -1,99 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/Iterator.h" - -#include -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Projection.h" -#include "eckit/log/Log.h" -#include "eckit/thread/AutoLock.h" -#include "eckit/thread/Mutex.h" - - -namespace eckit::geometry { - - -static pthread_once_t __once = PTHREAD_ONCE_INIT; -static Mutex* __mutex = nullptr; -static std::map* __factories = nullptr; - - -static void __init() { - __mutex = new Mutex; - __factories = new std::map(); -} - - -Iterator::Iterator(Projection* projection) : - projection_(projection), - valid_(true) {} - - -void Iterator::print(std::ostream& out) const { - out << "Iterator[valid?" - << valid_ << ",point=" << point_ << "]"; -} - - -Iterator* IteratorFactory::build(const IteratorFactory::key_type& key, const Configuration& config) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - if (auto f = __factories->find(key); f != __factories->end()) { - return f->second->make(config); - } - - list(Log::error() << "IteratorFactory: unknown '" << key << "', choices are: "); - throw BadValue("IteratorFactory: unknown '" + key + "'"); -} - - -std::ostream& IteratorFactory::list(std::ostream& out) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - const char* sep = "'"; - for (const auto& j : *__factories) { - out << sep << j.first << '\''; - sep = ", '"; - } - - return out; -} - - -IteratorFactory::IteratorFactory(const key_type& key) : - key_(key) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - if (auto f = __factories->find(key); f != __factories->end()) { - throw BadValue("IteratorFactory: duplicate '" + key + "'"); - } - - (*__factories)[key] = this; -} - - -IteratorFactory::~IteratorFactory() { - AutoLock lock(*__mutex); - - if (__factories != nullptr) { - __factories->erase(key_); - } -} - - -} // namespace eckit::geometry diff --git a/src/eckit/geometry/Iterator.h b/src/eckit/geometry/Iterator.h deleted file mode 100644 index d83c7e2b0..000000000 --- a/src/eckit/geometry/Iterator.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include -#include - -#include "eckit/geometry/Point.h" - - -namespace eckit { -class Configuration; -namespace geometry { -class Projection; -} -} // namespace eckit - - -namespace eckit::geometry { - - -class Iterator { -public: - // -- Types - - using value_type = Point; - -protected: - // -- Types - - template - struct iterator_t { - X& cnt; - size_t pos; - - bool operator!=(const iterator_t& other) const { return &cnt != &other.cnt || pos != other.pos; } - - iterator_t& operator++() { - pos++; - return *this; - } - - typename X::value_type& operator*() { return cnt.at(pos); } - - const typename X::value_type& operator*() const { return cnt.at(pos); } - }; - -public: - // -- Types - - using iterator = iterator_t; - using const_iterator = iterator_t; - - // -- Exceptions - // None - - // -- Constructors - - Iterator(Projection* = nullptr); - - Iterator(const Iterator&) = delete; - Iterator(Iterator&&) = delete; - - // -- Destructor - - virtual ~Iterator() = default; - - // -- Convertors - - operator bool() { return valid_; } - - // -- Operators - - Iterator& operator=(const Iterator&) = delete; - Iterator& operator=(Iterator&&) = delete; - - virtual bool operator++() = 0; - - // -- Methods - - virtual size_t size() const = 0; - virtual size_t index() const = 0; - - iterator begin() { return {*this, 0}; } - iterator end() { return {*this, this->size()}; } - - const_iterator cbegin() const { return {*this, 0}; } - const_iterator cend() const { return {*this, this->size()}; } - - const_iterator begin() const { return cbegin(); } - const_iterator end() const { return cend(); } - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - - Point2 point_; - std::unique_ptr projection_; - bool valid_; - - // -- Methods - - virtual void print(std::ostream&) const = 0; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - - friend std::ostream& operator<<(std::ostream& s, const Iterator& p) { - p.print(s); - return s; - } -}; - - -struct IteratorFactory { - using key_type = std::string; - - static Iterator* build(const key_type&, const Configuration&); - static std::ostream& list(std::ostream&); - - IteratorFactory(const IteratorFactory&) = delete; - IteratorFactory(IteratorFactory&&) = delete; - IteratorFactory& operator=(const IteratorFactory&) = delete; - IteratorFactory& operator=(IteratorFactory&&) = delete; - - virtual Iterator* make(const Configuration&) = 0; - -protected: - explicit IteratorFactory(const key_type&); - virtual ~IteratorFactory(); - -private: - const key_type key_; -}; - - -template -class IteratorBuilder final : public IteratorFactory { - Iterator* make(const Configuration& config) override { return new T(config); } - -public: - explicit IteratorBuilder(const IteratorFactory::key_type& key) : - IteratorFactory(key) {} -}; - - -} // namespace eckit::geometry diff --git a/src/eckit/geometry/grid/Gaussian.h b/src/eckit/geometry/grid/Gaussian.h index 5b0f4fec2..2de28bd30 100644 --- a/src/eckit/geometry/grid/Gaussian.h +++ b/src/eckit/geometry/grid/Gaussian.h @@ -67,10 +67,18 @@ class Gaussian : public Grid { // -- Overridden methods - bool includesNorthPole() const override; bool includesSouthPole() const override; + iterator begin() override { NOTIMP; } + iterator end() override { NOTIMP; } + + const_iterator cbegin() const override { NOTIMP; } + const_iterator cend() const override { NOTIMP; } + + const_iterator begin() const override { NOTIMP; } + const_iterator end() const override { NOTIMP; } + // -- Class members // None diff --git a/src/eckit/geometry/grid/GaussianIterator.cc b/src/eckit/geometry/grid/GaussianIterator.cc index ee2c6d567..27ead3a63 100644 --- a/src/eckit/geometry/grid/GaussianIterator.cc +++ b/src/eckit/geometry/grid/GaussianIterator.cc @@ -12,12 +12,15 @@ #include "eckit/geometry/grid/GaussianIterator.h" +#if 0 #include "eckit/exception/Exceptions.h" +#endif namespace eckit::geometry::grid { +#if 0 GaussianIterator::GaussianIterator(const std::vector& latitudes, std::vector&& pl, const area::BoundingBox& bbox, size_t N, size_t Nj, size_t k) : latitudes_(latitudes), @@ -103,6 +106,7 @@ size_t GaussianIterator::index() const { size_t GaussianIterator::size() const { NOTIMP; } +#endif } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/GaussianIterator.h b/src/eckit/geometry/grid/GaussianIterator.h index 4769ed26e..5b4377641 100644 --- a/src/eckit/geometry/grid/GaussianIterator.h +++ b/src/eckit/geometry/grid/GaussianIterator.h @@ -14,16 +14,19 @@ #include +#if 0 #include "eckit/types/Fraction.h" #include "eckit/geometry/Iterator.h" #include "eckit/geometry/Projection.h" #include "eckit/geometry/area/BoundingBox.h" +#endif namespace eckit::geometry::grid { +#if 0 class GaussianIterator : public Iterator { public: GaussianIterator(const std::vector& latitudes, std::vector&& pl, const area::BoundingBox&, size_t N, @@ -52,6 +55,7 @@ class GaussianIterator : public Iterator { size_t resetToRow(size_t j); }; +#endif } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/HEALPix.h b/src/eckit/geometry/grid/HEALPix.h index 0a384578c..42928fc71 100644 --- a/src/eckit/geometry/grid/HEALPix.h +++ b/src/eckit/geometry/grid/HEALPix.h @@ -89,6 +89,15 @@ class HEALPix final : public Grid { bool includesSouthPole() const override { return true; } bool isPeriodicWestEast() const override { return true; } + iterator begin() override { NOTIMP; } + iterator end() override { NOTIMP; } + + const_iterator cbegin() const override { NOTIMP; } + const_iterator cend() const override { NOTIMP; } + + const_iterator begin() const override { NOTIMP; } + const_iterator end() const override { NOTIMP; } + // -- Class members // None diff --git a/src/eckit/geometry/grid/IrregularLatlon.cc b/src/eckit/geometry/grid/IrregularLatlon.cc index 2457a9fd0..4db1259a0 100644 --- a/src/eckit/geometry/grid/IrregularLatlon.cc +++ b/src/eckit/geometry/grid/IrregularLatlon.cc @@ -16,7 +16,6 @@ #include "eckit/utils/MD5.h" -#include "eckit/geometry/Iterator.h" #include "eckit/geometry/Projection.h" @@ -54,75 +53,6 @@ size_t IrregularLatlon::size() const { } -class IrregularLatlonIterator : public Iterator { - size_t i_; - size_t ni_; - size_t j_; - size_t nj_; - size_t count_; - bool first_; - - const std::vector& latitudes_; - const std::vector& longitudes_; - - bool operator++() override { - if (j_ < nj_) { - if (i_ < ni_) { - // lat = latitudes_[j_]; - // lon = longitudes_[i_]; - - if (first_) { - first_ = false; - } - else { - count_++; - } - - if (++i_ == ni_) { - ++j_; - i_ = 0; - } - - return true; - } - } - return false; - } - - size_t index() const override { return count_; } - - size_t size() const override { NOTIMP; } - -public: - // TODO: Consider keeping a reference on the latitudes and bbox, to avoid copying - - IrregularLatlonIterator(const std::vector& latitudes, const std::vector& longitudes) : - i_(0), - ni_(longitudes.size()), - j_(0), - nj_(latitudes.size()), - count_(0), - first_(true), - latitudes_(latitudes), - longitudes_(longitudes) {} - - ~IrregularLatlonIterator() override { - auto count = count_ + (i_ > 0 || j_ > 0 ? 1 : 0); - ASSERT(count == ni_ * nj_); - } - - IrregularLatlonIterator(const IrregularLatlonIterator&) = delete; - IrregularLatlonIterator(IrregularLatlonIterator&&) = delete; - IrregularLatlonIterator& operator=(const IrregularLatlonIterator&) = delete; - IrregularLatlonIterator& operator=(IrregularLatlonIterator&&) = delete; -}; - - -// Iterator* IrregularLatlon::iterator() const { -// return new IrregularLatlonIterator(latitudes_, longitudes_); -// } - - bool IrregularLatlon::isPeriodicWestEast() const { return (east_ - west_) + west_east_ >= GLOBE; } @@ -138,7 +68,7 @@ bool IrregularLatlon::includesSouthPole() const { } -static const GridRegisterType irregularLatlon("irregular_latlon"); +// static const GridRegisterType irregularLatlon("irregular_latlon"); } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/ReducedGG.cc b/src/eckit/geometry/grid/ReducedGG.cc index f02ddbe18..e49225481 100644 --- a/src/eckit/geometry/grid/ReducedGG.cc +++ b/src/eckit/geometry/grid/ReducedGG.cc @@ -18,7 +18,6 @@ #include #include "eckit/config/MappedConfiguration.h" -#include "eckit/geometry/Iterator.h" #include "eckit/geometry/Projection.h" #include "eckit/geometry/grid/GaussianIterator.h" #include "eckit/types/Fraction.h" diff --git a/src/eckit/geometry/grid/ReducedLL.cc b/src/eckit/geometry/grid/ReducedLL.cc index 0ea350059..13e21b352 100644 --- a/src/eckit/geometry/grid/ReducedLL.cc +++ b/src/eckit/geometry/grid/ReducedLL.cc @@ -17,7 +17,6 @@ #include #include "eckit/geometry/Domain.h" -#include "eckit/geometry/Iterator.h" #include "eckit/geometry/Projection.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" @@ -69,93 +68,6 @@ bool ReducedLL::includesSouthPole() const { return bbox().south() == SOUTH_POLE; } -class ReducedLLIterator : public Iterator { - - const std::vector& pl_; - const size_t nj_; - size_t ni_; - - const Domain domain_; - const Fraction west_; - const Fraction ew_; - Fraction inc_west_east_; - const Fraction inc_north_south_; - - Fraction latitude_; - Fraction longitude_; - - size_t i_; - size_t j_; - size_t p_; - - size_t count_; - bool first_; - bool periodic_; - - bool operator++() override { - while (j_ < nj_ && i_ < ni_) { - // lat = latitude_; - // lon = longitude_; - - bool contains = domain_.contains(latitude_, longitude_); - if (contains && !first_) { - count_++; - } - - longitude_ += inc_west_east_; - - if (++i_ == ni_) { - ++j_; - i_ = 0; - latitude_ -= inc_north_south_; - longitude_ = west_; - - if (j_ < nj_) { - ASSERT(p_ < pl_.size()); - ni_ = size_t(pl_[p_++]); - ASSERT(ni_ > 1); - inc_west_east_ = ew_ / (ni_ - (periodic_ ? 0 : 1)); - } - } - - if (contains) { - first_ = false; - return true; - } - } - return false; - } - - size_t index() const override { return count_; } - - size_t size() const override { NOTIMP; } - -public: - ReducedLLIterator(const std::vector& pl, const Domain& dom) : - pl_(pl), - nj_(pl.size()), - domain_(dom), - west_(domain_.west()), - ew_((domain_.east() - domain_.west())), - inc_north_south_(Fraction(domain_.north() - domain_.south()) / Fraction(nj_ - 1)), - latitude_(domain_.north()), - longitude_(west_), - i_(0), - j_(0), - p_(0), - count_(0), - first_(true), - periodic_(dom.isPeriodicWestEast()) { - - ASSERT(nj_ > 1); - - ni_ = size_t(pl_[p_++]); - ASSERT(ni_ > 1); - inc_west_east_ = ew_ / (ni_ - (periodic_ ? 0 : 1)); - } -}; - - static const GridRegisterType reducedLL("reduced_ll"); diff --git a/src/eckit/geometry/grid/ReducedLL.h b/src/eckit/geometry/grid/ReducedLL.h index 9ddf9c94a..2d23a7673 100644 --- a/src/eckit/geometry/grid/ReducedLL.h +++ b/src/eckit/geometry/grid/ReducedLL.h @@ -65,6 +65,15 @@ class ReducedLL : public Grid { bool includesNorthPole() const override; bool includesSouthPole() const override; + iterator begin() override { NOTIMP; } + iterator end() override { NOTIMP; } + + const_iterator cbegin() const override { NOTIMP; } + const_iterator cend() const override { NOTIMP; } + + const_iterator begin() const override { NOTIMP; } + const_iterator end() const override { NOTIMP; } + // -- Class members // None diff --git a/src/eckit/geometry/grid/RegularGrid.cc b/src/eckit/geometry/grid/RegularGrid.cc index 2d2d952ed..09c905e67 100644 --- a/src/eckit/geometry/grid/RegularGrid.cc +++ b/src/eckit/geometry/grid/RegularGrid.cc @@ -20,7 +20,6 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/config/Resource.h" #include "eckit/geometry/Earth.h" -#include "eckit/geometry/Iterator.h" #include "eckit/utils/StringTools.h" @@ -242,10 +241,10 @@ struct PolarStereographic : RegularGrid { }; -static const GridRegisterType __builder1("lambert"); -static const GridRegisterType __builder2("lambert_azimuthal_equal_area"); -static const GridRegisterType __builder3("mercator"); -static const GridRegisterType __builder4("polar_stereographic"); +// static const GridRegisterType __builder1("lambert"); +// static const GridRegisterType __builder2("lambert_azimuthal_equal_area"); +// static const GridRegisterType __builder3("mercator"); +// static const GridRegisterType __builder4("polar_stereographic"); } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/RegularLL.cc b/src/eckit/geometry/grid/RegularLL.cc index 367e82ca4..06b05bdb9 100644 --- a/src/eckit/geometry/grid/RegularLL.cc +++ b/src/eckit/geometry/grid/RegularLL.cc @@ -16,7 +16,6 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Iterator.h" #include "eckit/geometry/Point.h" #include "eckit/geometry/Projection.h" #include "eckit/geometry/grid/RegularLL.h" diff --git a/src/eckit/geometry/grid/RegularLL.h b/src/eckit/geometry/grid/RegularLL.h index c959fb7d6..a849c06c6 100644 --- a/src/eckit/geometry/grid/RegularLL.h +++ b/src/eckit/geometry/grid/RegularLL.h @@ -66,6 +66,15 @@ class RegularLL : public Grid { // -- Overridden methods + iterator begin() override { NOTIMP; } + iterator end() override { NOTIMP; } + + const_iterator cbegin() const override { NOTIMP; } + const_iterator cend() const override { NOTIMP; } + + const_iterator begin() const override { NOTIMP; } + const_iterator end() const override { NOTIMP; } + bool isPeriodicWestEast() const override; bool includesNorthPole() const override; bool includesSouthPole() const override; diff --git a/src/eckit/geometry/grid/UnstructuredGrid.cc b/src/eckit/geometry/grid/UnstructuredGrid.cc index 6072ba39d..cb28769d9 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.cc +++ b/src/eckit/geometry/grid/UnstructuredGrid.cc @@ -18,14 +18,17 @@ #include #include -#include "eckit/config/Resource.h" #include "eckit/exception/Exceptions.h" + +#if 0 +#include "eckit/config/Resource.h" #include "eckit/filesystem/PathName.h" #include "eckit/geometry/Domain.h" #include "eckit/geometry/Iterator.h" #include "eckit/geometry/Projection.h" #include "eckit/serialisation/FileStream.h" #include "eckit/serialisation/IfstreamStream.h" +#endif namespace eckit::geometry::grid { @@ -34,6 +37,7 @@ namespace eckit::geometry::grid { namespace detail { +#if 0 class UnstructuredIterator : public Iterator { public: // -- Exceptions @@ -109,6 +113,7 @@ class UnstructuredIterator : public Iterator { // -- Friends // None }; +#endif } // namespace detail @@ -193,8 +198,8 @@ bool UnstructuredGrid::includesSouthPole() const { } -static const GridRegisterType triangular_grid("triangular_grid"); -static const GridRegisterType unstructured_grid("unstructured_grid"); +// static const GridRegisterType triangular_grid("triangular_grid"); +// static const GridRegisterType unstructured_grid("unstructured_grid"); } // namespace eckit::geometry::grid From 1650a22bf0b8b832f007c4c1f287421f12b83253 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 7 Aug 2023 23:04:21 +0100 Subject: [PATCH 271/737] eckit::geometry --- src/eckit/geometry/grid/HEALPix.cc | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/eckit/geometry/grid/HEALPix.cc b/src/eckit/geometry/grid/HEALPix.cc index ed7381445..f4266a307 100644 --- a/src/eckit/geometry/grid/HEALPix.cc +++ b/src/eckit/geometry/grid/HEALPix.cc @@ -91,8 +91,6 @@ const std::vector& HEALPix::latitudes() const { *j = -*i; } *i = 0.; - - return lats_; } ASSERT(lats_.size() == Ni); @@ -101,17 +99,9 @@ const std::vector& HEALPix::latitudes() const { const std::vector& HEALPix::longitudes(size_t i) const { - const auto Ni = ni(); - ASSERT(i < Ni); - - // ring index: 1-based, symmetric, in range [1, Nside_ + 1] - const auto Nj = nj(i); - const auto ring = i >= N_ * 3 ? Ni - i : i >= N_ ? 1 + N_ - i % 2 - : 1 + i; - + const auto Nj = nj(i); const auto step = 360. / static_cast(Nj); - const auto start = static_cast(i % 2) ? 180. / static_cast(Nj) : ring == 1 ? 45. - : 0.; + const auto start = i < N_ || 3 * N_ - 1 < i || static_cast((i + N_) % 2) ? step / 2. : 0.; lons_.reserve(N_ * 4); lons_.resize(Nj); From 10c843d1e7df98ec168f076257b8d2a2fcbb9584 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 9 Aug 2023 17:53:26 +0100 Subject: [PATCH 272/737] eckit::geometry eckit-grid --- src/tools/CMakeLists.txt | 6 +++ src/tools/eckit-grid.cc | 93 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 src/tools/eckit-grid.cc diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 6bedcab67..b6bbb081f 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -10,6 +10,12 @@ ecbuild_add_executable( TARGET eckit_info SOURCES eckit-info.cc LIBS eckit_option eckit ) +ecbuild_add_executable( TARGET eckit_grid + OUTPUT_NAME eckit-grid + CONDITION HAVE_BUILD_TOOLS + SOURCES eckit-grid.cc + LIBS eckit_option eckit_geometry ) + ### NOT TO INSTALL ecbuild_add_executable( TARGET dhcopy diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc new file mode 100644 index 000000000..3a4239337 --- /dev/null +++ b/src/tools/eckit-grid.cc @@ -0,0 +1,93 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "eckit/config/Resource.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geometry/Grid.h" +#include "eckit/log/JSON.h" +#include "eckit/log/Log.h" +#include "eckit/option/CmdArgs.h" +#include "eckit/option/EckitTool.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit { + +class EckitGrid final : public EckitTool { +public: + EckitGrid(int argc, char** argv) : + EckitTool(argc, argv) { + options_.push_back(new option::SimpleOption("list", "List possible grids")); + options_.push_back(new option::SimpleOption("uid", "by grid unique identifier, instead of name")); + } + +private: + void execute(const option::CmdArgs& args) override { + bool list = false; + args.get("list", list); + + bool uid = false; + args.get("uid", uid); + + if (list) { + geometry::GridFactory::list(Log::info()); + Log::info() << std::endl; + return; + } + + auto& out = Log::info(); + // JSON out(Log::info()); + // out.precision(args.getInt("precision", 16)); + + for (std::string arg : args) { + std::unique_ptr grid(uid ? geometry::GridFactoryUID::build(arg) : geometry::GridFactoryName::build(arg)); + + // out << "name: " << grid->name() << std::endl; + // out << "uid: " << grid->uid() << std::endl; + out << "size: " << grid->size() << std::endl; + out << "bounding_box: " << grid->boundingBox() << std::endl; + + // auto it = grid->begin(); + // out << "first: " << **it << std::endl; + + // it += grid->size() - 1; + // out << "last: " << **it << std::endl; + // ASSERT(it == grid->rbegin()); + + // out.startList(); + // for (const auto& p : *grid) { + // out << p; + // } + // out.endList(); + } + } + + void usage(const std::string& tool) const override { + Log::info() << "\n" + "Usage: " + << tool << "[options] ..." << std::endl; + } + + int minimumPositionalArguments() const override { + return 0; + } +}; + +} // namespace eckit + +//---------------------------------------------------------------------------------------------------------------------- + +int main(int argc, char** argv) { + eckit::EckitGrid app(argc, argv); + return app.start(); +} From 7df8028bde45fa2d107b76b0b792803959b2f43b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 11 Aug 2023 00:50:21 +0100 Subject: [PATCH 273/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 58 +++++++++++++++++++++++-------------- src/eckit/geometry/Point.cc | 8 ++--- src/eckit/geometry/Point.h | 6 ++-- 3 files changed, 43 insertions(+), 29 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index eee4b9d06..282c34a7b 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -19,6 +19,7 @@ #include #include "eckit/exception/Exceptions.h" +#include "eckit/log/JSON.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -80,21 +81,31 @@ void GridFactory::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - const char* sep = ""; - for (const auto& j : *__grid_uids) { - out << sep << j.first; - sep = ", "; + JSON j(out); + j.startObject(); + + j << "uid"; + j.startList(); + for (const auto& p : *__grid_uids) { + j << p.first; } + j.endList(); - for (const auto& j : *__grid_names) { - out << sep << j.first; - sep = ", "; + j << "name"; + j.startList(); + for (const auto& p : *__grid_names) { + j << p.first; } + j.endList(); - for (const auto& j : *__grid_types) { - out << sep << j.first; - sep = ", "; + j << "type"; + j.startList(); + for (const auto& p : *__grid_types) { + j << p.first; } + j.endList(); + + j.endObject(); } @@ -135,11 +146,12 @@ void GridFactoryUID::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - const char* sep = ""; - for (const auto& j : *__grid_uids) { - out << sep << j.first; - sep = ", "; + JSON j(out); + j.startList(); + for (const auto& p : *__grid_uids) { + out << p.first; } + j.endList(); } @@ -194,11 +206,12 @@ void GridFactoryName::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - const char* sep = ""; - for (const auto& j : *__grid_names) { - out << sep << j.first; - sep = ", "; + JSON j(out); + j.startList(); + for (const auto& p : *__grid_names) { + out << p.first; } + j.endList(); } @@ -248,11 +261,12 @@ void GridFactoryType::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - const char* sep = ""; - for (const auto& j : *__grid_types) { - out << sep << j.first; - sep = ", "; + JSON j(out); + j.startList(); + for (const auto& p : *__grid_types) { + out << p.first; } + j.endList(); } diff --git a/src/eckit/geometry/Point.cc b/src/eckit/geometry/Point.cc index 5acde5a34..34b94967c 100644 --- a/src/eckit/geometry/Point.cc +++ b/src/eckit/geometry/Point.cc @@ -26,10 +26,10 @@ bool points_equal(const Point& p, const Point& q) { } -} // namespace eckit::geometry - - -std::ostream& operator<<(std::ostream& out, const eckit::geometry::Point& p) { +std::ostream& operator<<(std::ostream& out, const Point& p) { std::visit([&](const auto& p) { out << p; }, p); return out; } + + +} // namespace eckit::geometry diff --git a/src/eckit/geometry/Point.h b/src/eckit/geometry/Point.h index 6fb3330b0..e5eb55783 100644 --- a/src/eckit/geometry/Point.h +++ b/src/eckit/geometry/Point.h @@ -27,6 +27,9 @@ using Point = std::variant; bool points_equal(const Point&, const Point&); +std::ostream& operator<<(std::ostream&, const Point&); + + constexpr double GLOBE = 360.; constexpr double GREENWICH = 0.; constexpr double NORTH_POLE = 90.; @@ -38,6 +41,3 @@ using Latitude = double; } // namespace eckit::geometry - - -std::ostream& operator<<(std::ostream&, const eckit::geometry::Point&); From eb3d84f07bdd6aaa435f3833dda7a1bd4c6480ab Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 11 Aug 2023 01:18:55 +0100 Subject: [PATCH 274/737] eckit::geometry --- src/eckit/geometry/CMakeLists.txt | 15 +++--- src/eckit/geometry/Grid.h | 32 +---------- src/eckit/geometry/{Scanner.h => Iterator.h} | 24 +++++---- src/eckit/geometry/Scanner.cc | 54 ------------------- .../geometry/{scanner => iterator}/Reduced.cc | 6 +-- .../geometry/{scanner => iterator}/Reduced.h | 8 +-- .../geometry/{scanner => iterator}/Regular.cc | 41 ++++++++++++-- .../geometry/{scanner => iterator}/Regular.h | 8 +-- .../{scanner => iterator}/Unstructured.cc | 6 +-- .../{scanner => iterator}/Unstructured.h | 8 +-- src/tools/eckit-grid.cc | 12 ++++- tests/geometry/test_iterator.cc | 2 +- 12 files changed, 89 insertions(+), 127 deletions(-) rename src/eckit/geometry/{Scanner.h => Iterator.h} (68%) delete mode 100644 src/eckit/geometry/Scanner.cc rename src/eckit/geometry/{scanner => iterator}/Reduced.cc (95%) rename src/eckit/geometry/{scanner => iterator}/Reduced.h (91%) rename src/eckit/geometry/{scanner => iterator}/Regular.cc (54%) rename src/eckit/geometry/{scanner => iterator}/Regular.h (90%) rename src/eckit/geometry/{scanner => iterator}/Unstructured.cc (81%) rename src/eckit/geometry/{scanner => iterator}/Unstructured.h (86%) diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index c0c1668b2..a4ad494ab 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -16,6 +16,7 @@ list( APPEND eckit_geometry_srcs Grid.h Increments.cc Increments.h + Iterator.h KPoint.cc KPoint.h Point.cc @@ -31,8 +32,6 @@ list( APPEND eckit_geometry_srcs Range.cc Range.h Renumber.h - Scanner.cc - Scanner.h Search.h Sphere.cc Sphere.h @@ -60,6 +59,12 @@ list( APPEND eckit_geometry_srcs grid/RegularLL.h grid/UnstructuredGrid.cc grid/UnstructuredGrid.h + iterator/Reduced.cc + iterator/Reduced.h + iterator/Regular.cc + iterator/Regular.h + iterator/Unstructured.cc + iterator/Unstructured.h polygon/LonLatPolygon.cc polygon/LonLatPolygon.h polygon/Polygon.cc @@ -70,12 +75,6 @@ list( APPEND eckit_geometry_srcs projection/None.h projection/Rotation.cc projection/Rotation.h - scanner/Reduced.cc - scanner/Reduced.h - scanner/Regular.cc - scanner/Regular.h - scanner/Unstructured.cc - scanner/Unstructured.h util.cc util.h util/arange.cc diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 75f9e65d3..8c473d938 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -20,6 +20,7 @@ #include "eckit/config/Configuration.h" #include "eckit/geometry/Area.h" #include "eckit/geometry/Increments.h" +#include "eckit/geometry/Iterator.h" #include "eckit/geometry/Point.h" #include "eckit/geometry/Projection.h" #include "eckit/geometry/Renumber.h" @@ -33,37 +34,6 @@ class Grid { public: // -- Types - struct Iterator { - explicit Iterator(const Grid& grid) : - grid_(grid) {} - - Iterator(const Iterator&) = delete; - Iterator(Iterator&&) = delete; - - virtual ~Iterator() = default; - - void operator=(const Iterator&) = delete; - void operator=(Iterator&&) = delete; - - bool operator!=(const Iterator& other) const { return &grid_ != &other.grid_ || index_ != other.index_; } - - bool operator++() { - index_++; - return operator bool(); - } - - virtual explicit operator bool() = 0; - virtual const Point& operator*() const = 0; - - size_t size() const { return grid_.size(); } - size_t index() const { return index_; } - - private: - const Grid& grid_; - size_t index_ = 0; - }; - - using iterator = std::unique_ptr; using const_iterator = std::unique_ptr; diff --git a/src/eckit/geometry/Scanner.h b/src/eckit/geometry/Iterator.h similarity index 68% rename from src/eckit/geometry/Scanner.h rename to src/eckit/geometry/Iterator.h index a5dd08b75..7fe30970a 100644 --- a/src/eckit/geometry/Scanner.h +++ b/src/eckit/geometry/Iterator.h @@ -12,13 +12,13 @@ #pragma once -#include +#include "eckit/geometry/Point.h" namespace eckit::geometry { -class Scanner { +class Iterator { public: // -- Types // None @@ -28,26 +28,30 @@ class Scanner { // -- Constructors - Scanner(const Scanner&) = delete; - Scanner(Scanner&&) = delete; + Iterator(const Iterator&) = delete; + Iterator(Iterator&&) = delete; // -- Destructor - virtual ~Scanner() = default; + virtual ~Iterator() = default; // -- Convertors // None // -- Operators - Scanner& operator=(const Scanner&) = delete; - Scanner& operator=(Scanner&&) = delete; + void operator=(const Iterator&) = delete; + void operator=(Iterator&&) = delete; - virtual bool operator++() = 0; + virtual bool operator!=(const Iterator&) = 0; + virtual bool operator++() = 0; + virtual explicit operator bool() = 0; + virtual const Point& operator*() const = 0; // -- Methods - virtual size_t size() const = 0; + virtual size_t size() const = 0; + virtual size_t index() const = 0; // -- Overridden methods // None @@ -61,7 +65,7 @@ class Scanner { protected: // -- Constructors - Scanner() = default; + Iterator() = default; // -- Members // None diff --git a/src/eckit/geometry/Scanner.cc b/src/eckit/geometry/Scanner.cc deleted file mode 100644 index 5607d73eb..000000000 --- a/src/eckit/geometry/Scanner.cc +++ /dev/null @@ -1,54 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/Scanner.h" - - -namespace eckit::geometry { - - -#if 0 -Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) - - bool iScansPositively -- 1 0 Points of first row or column scan in the +i (+x) direction -- 1 1 Points of first row or column scan in the -i (-x) direction - - bool jScansPositively -- 2 0 Points of first row or column scan in the -j (-y) direction -- 2 1 Points of first row or column scan in the +j (+y) direction - - bool jPointsAreConsecutive -- 3 0 Adjacent points in i (x) direction are consecutive -- 3 1 Adjacent points in j (y) direction is consecutive - - bool alternativeRowScanning -- 4 0 All rows scan in the same direction -- 4 1 Adjacent rows scan in the opposite direction - -- 5 0 Points within odd rows are not offset in i (x) direction -- 5 1 Points within odd rows are offset by Di/2 in i (x) direction -- 6 0 Points within even rows are not offset in i (x) direction -- 6 1 Points within even rows are offset by Di/2 in i (x) direction -- 7 0 Points are not offset in j (y) direction -- 7 1 Points are offset by Dj/2 in j (y) direction - -- 8 0 n_i columns, n_j rows -- 8 1 Rows have n_i points if points are not offset in i direction - Rows have n_i-1 points if points are offset by Di/2 in i direction - Columns have n_j points if points are not offset in j direction - Columns have n_j-1 points if points are offset by Dj/2 in j direction - -#endif - - -} // namespace eckit::geometry diff --git a/src/eckit/geometry/scanner/Reduced.cc b/src/eckit/geometry/iterator/Reduced.cc similarity index 95% rename from src/eckit/geometry/scanner/Reduced.cc rename to src/eckit/geometry/iterator/Reduced.cc index 711271238..67cd13923 100644 --- a/src/eckit/geometry/scanner/Reduced.cc +++ b/src/eckit/geometry/iterator/Reduced.cc @@ -10,14 +10,14 @@ */ -#include "eckit/geometry/scanner/Reduced.h" +#include "eckit/geometry/iterator/Reduced.h" #include #include "eckit/exception/Exceptions.h" -namespace eckit::geometry::scanner { +namespace eckit::geometry::iterator { Reduced::Reduced(const std::vector& latitudes, @@ -104,4 +104,4 @@ size_t Reduced::size() const { } -} // namespace eckit::geometry::scanner +} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/scanner/Reduced.h b/src/eckit/geometry/iterator/Reduced.h similarity index 91% rename from src/eckit/geometry/scanner/Reduced.h rename to src/eckit/geometry/iterator/Reduced.h index 3e30a1f41..4d9107a96 100644 --- a/src/eckit/geometry/scanner/Reduced.h +++ b/src/eckit/geometry/iterator/Reduced.h @@ -12,17 +12,17 @@ #pragma once +#include "eckit/geometry/Iterator.h" #include "eckit/geometry/Point.h" -#include "eckit/geometry/Scanner.h" #include "eckit/geometry/area/BoundingBox.h" #include "eckit/geometry/util.h" #include "eckit/types/Fraction.h" -namespace eckit::geometry::scanner { +namespace eckit::geometry::iterator { -class Reduced final : public Scanner { +class Reduced final : public Iterator { public: // -- Exceptions // None @@ -99,4 +99,4 @@ class Reduced final : public Scanner { }; -} // namespace eckit::geometry::scanner +} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/scanner/Regular.cc b/src/eckit/geometry/iterator/Regular.cc similarity index 54% rename from src/eckit/geometry/scanner/Regular.cc rename to src/eckit/geometry/iterator/Regular.cc index 061210ecd..7484752d5 100644 --- a/src/eckit/geometry/scanner/Regular.cc +++ b/src/eckit/geometry/iterator/Regular.cc @@ -10,14 +10,49 @@ */ -#include "eckit/geometry/scanner/Regular.h" +#include "eckit/geometry/iterator/Regular.h" #include #include "eckit/exception/Exceptions.h" -namespace eckit::geometry::scanner { +namespace eckit::geometry::iterator { + + +#if 0 +Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) + +bool iScansPositively +- 1 0 Points of first row or column scan in the +i (+x) direction +- 1 1 Points of first row or column scan in the -i (-x) direction + +bool jScansPositively +- 2 0 Points of first row or column scan in the -j (-y) direction +- 2 1 Points of first row or column scan in the +j (+y) direction + +bool jPointsAreConsecutive +- 3 0 Adjacent points in i (x) direction are consecutive +- 3 1 Adjacent points in j (y) direction is consecutive + +bool alternativeRowScanning +- 4 0 All rows scan in the same direction +- 4 1 Adjacent rows scan in the opposite direction + +- 5 0 Points within odd rows are not offset in i (x) direction +- 5 1 Points within odd rows are offset by Di/2 in i (x) direction +- 6 0 Points within even rows are not offset in i (x) direction +- 6 1 Points within even rows are offset by Di/2 in i (x) direction +- 7 0 Points are not offset in j (y) direction +- 7 1 Points are offset by Dj/2 in j (y) direction + +- 8 0 n_i columns, n_j rows +- 8 1 Rows have n_i points if points are not offset in i direction + Rows have n_i-1 points if points are offset by Di/2 in i direction + Columns have n_j points if points are not offset in j direction + Columns have n_j-1 points if points are offset by Dj/2 in j direction + +#endif Regular::Regular(size_t ni, size_t nj, double north, double west, double we, double ns) : @@ -76,4 +111,4 @@ size_t Regular::size() const { } -} // namespace eckit::geometry::scanner +} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/scanner/Regular.h b/src/eckit/geometry/iterator/Regular.h similarity index 90% rename from src/eckit/geometry/scanner/Regular.h rename to src/eckit/geometry/iterator/Regular.h index f13273aa5..495b6c3b8 100644 --- a/src/eckit/geometry/scanner/Regular.h +++ b/src/eckit/geometry/iterator/Regular.h @@ -12,15 +12,15 @@ #pragma once +#include "eckit/geometry/Iterator.h" #include "eckit/geometry/Point.h" -#include "eckit/geometry/Scanner.h" #include "eckit/types/Fraction.h" -namespace eckit::geometry::scanner { +namespace eckit::geometry::iterator { -class Regular final : public Scanner { +class Regular final : public Iterator { public: // -- Types // None @@ -94,4 +94,4 @@ class Regular final : public Scanner { }; -} // namespace eckit::geometry::scanner +} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/scanner/Unstructured.cc b/src/eckit/geometry/iterator/Unstructured.cc similarity index 81% rename from src/eckit/geometry/scanner/Unstructured.cc rename to src/eckit/geometry/iterator/Unstructured.cc index 5e7d261ae..c86d6ea3e 100644 --- a/src/eckit/geometry/scanner/Unstructured.cc +++ b/src/eckit/geometry/iterator/Unstructured.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geometry/scanner/Unstructured.h" +#include "eckit/geometry/iterator/Unstructured.h" // #include <> -namespace eckit::geometry::scanner { +namespace eckit::geometry::iterator { Unstructured::Unstructured() = default; @@ -31,4 +31,4 @@ size_t Unstructured::size() const { } -} // namespace eckit::geometry::scanner +} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/scanner/Unstructured.h b/src/eckit/geometry/iterator/Unstructured.h similarity index 86% rename from src/eckit/geometry/scanner/Unstructured.h rename to src/eckit/geometry/iterator/Unstructured.h index 09d85a26a..12ba6f086 100644 --- a/src/eckit/geometry/scanner/Unstructured.h +++ b/src/eckit/geometry/iterator/Unstructured.h @@ -12,13 +12,13 @@ #pragma once -#include "eckit/geometry/Scanner.h" +#include "eckit/geometry/Iterator.h" -namespace eckit::geometry::scanner { +namespace eckit::geometry::iterator { -class Unstructured final : public Scanner { +class Unstructured final : public Iterator { public: // -- Types // None @@ -74,4 +74,4 @@ class Unstructured final : public Scanner { }; -} // namespace eckit::geometry::scanner +} // namespace eckit::geometry::iterator diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index 3a4239337..98f4ba988 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -14,6 +14,7 @@ #include "eckit/config/Resource.h" #include "eckit/exception/Exceptions.h" #include "eckit/geometry/Grid.h" +#include "eckit/geometry/Point.h" #include "eckit/log/JSON.h" #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" @@ -45,6 +46,9 @@ class EckitGrid final : public EckitTool { return; } + geometry::Point x = geometry::PointLonLat(0., 90.); + std::cout << x << std::endl; + auto& out = Log::info(); // JSON out(Log::info()); // out.precision(args.getInt("precision", 16)); @@ -57,8 +61,12 @@ class EckitGrid final : public EckitTool { out << "size: " << grid->size() << std::endl; out << "bounding_box: " << grid->boundingBox() << std::endl; - // auto it = grid->begin(); - // out << "first: " << **it << std::endl; + auto it = grid->begin(); + + std::cout << **it << std::endl; + + // (*it).print(out) << std::endl; + // static_cast(out) << "first: " << q << std::endl; // it += grid->size() - 1; // out << "last: " << **it << std::endl; diff --git a/tests/geometry/test_iterator.cc b/tests/geometry/test_iterator.cc index 3bbc35ff4..79ea3a516 100644 --- a/tests/geometry/test_iterator.cc +++ b/tests/geometry/test_iterator.cc @@ -13,7 +13,7 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Scanner.h" +// #include "eckit/geometry/Scanner.h" // #include "eckit/geometry/iterator/IteratorAggregator.h" // #include "eckit/geometry/iterator/IteratorComposer.h" From e89f8139e34d63128ee7cc54c364f541d1704775 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 11 Aug 2023 11:18:30 +0100 Subject: [PATCH 275/737] eckit::geometry --- src/eckit/geometry/CMakeLists.txt | 2 - src/eckit/geometry/Grid.h | 27 +++++++- src/eckit/geometry/Iterator.h | 6 +- src/eckit/geometry/iterator/Reduced.cc | 39 +++++++---- src/eckit/geometry/iterator/Reduced.h | 9 ++- src/eckit/geometry/iterator/Regular.cc | 35 ++++++---- src/eckit/geometry/iterator/Regular.h | 13 ++-- src/eckit/geometry/iterator/Unstructured.cc | 34 --------- src/eckit/geometry/iterator/Unstructured.h | 77 --------------------- src/tools/eckit-grid.cc | 2 +- 10 files changed, 93 insertions(+), 151 deletions(-) delete mode 100644 src/eckit/geometry/iterator/Unstructured.cc delete mode 100644 src/eckit/geometry/iterator/Unstructured.h diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index a4ad494ab..88dc23ff5 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -63,8 +63,6 @@ list( APPEND eckit_geometry_srcs iterator/Reduced.h iterator/Regular.cc iterator/Regular.h - iterator/Unstructured.cc - iterator/Unstructured.h polygon/LonLatPolygon.cc polygon/LonLatPolygon.h polygon/Polygon.cc diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 8c473d938..bf7e205a1 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -34,8 +34,31 @@ class Grid { public: // -- Types - using iterator = std::unique_ptr; - using const_iterator = std::unique_ptr; + struct Iterator final : std::unique_ptr { + explicit Iterator(geometry::Iterator* it) : + unique_ptr(it) { ASSERT(operator bool()); } + + Iterator(const Iterator&) = delete; + Iterator(Iterator&&) = delete; + + ~Iterator() = default; + + void operator=(const Iterator&) = delete; + void operator=(Iterator&&) = delete; + + bool operator!=(const Iterator& other) { return get()->operator!=(*(other.get())); } + bool operator++() { return get()->operator++(); } + bool operator--() { return get()->operator--(); } + + explicit operator bool() { return get()->operator bool(); } + Point& operator*() { return get()->operator*(); } + + size_t size() const { return get()->size(); } + size_t index() const { return get()->index(); } + }; + + using iterator = Iterator; + using const_iterator = const Iterator; // -- Exceptions // None diff --git a/src/eckit/geometry/Iterator.h b/src/eckit/geometry/Iterator.h index 7fe30970a..8afd18ec6 100644 --- a/src/eckit/geometry/Iterator.h +++ b/src/eckit/geometry/Iterator.h @@ -45,8 +45,10 @@ class Iterator { virtual bool operator!=(const Iterator&) = 0; virtual bool operator++() = 0; - virtual explicit operator bool() = 0; - virtual const Point& operator*() const = 0; + virtual bool operator--() = 0; + + virtual explicit operator bool() = 0; + virtual Point& operator*() = 0; // -- Methods diff --git a/src/eckit/geometry/iterator/Reduced.cc b/src/eckit/geometry/iterator/Reduced.cc index 67cd13923..fd0b76870 100644 --- a/src/eckit/geometry/iterator/Reduced.cc +++ b/src/eckit/geometry/iterator/Reduced.cc @@ -12,8 +12,6 @@ #include "eckit/geometry/iterator/Reduced.h" -#include - #include "eckit/exception/Exceptions.h" @@ -34,17 +32,6 @@ Reduced::Reduced(const std::vector& latitudes, } -void Reduced::print(std::ostream& out) const { - out << "Reduced[N=" << N_ << /*",bbox=" << bbox_ <<*/ ",Ni=" << Ni_ << ",Nj=" << Nj_ - << ",i=" << i_ << ",j=" << j_ << ",k=" << k_ << ",count=" << count_ << "]"; -} - - -size_t Reduced::index() const { - return count_; -} - - size_t Reduced::resetToRow(size_t j) { ASSERT(j < latitudes_.size()); lat_ = latitudes_[j]; @@ -71,6 +58,11 @@ size_t Reduced::resetToRow(size_t j) { } +bool Reduced::operator!=(const Iterator&) { + NOTIMP; +} + + bool Reduced::operator++() { while (Ni_ == 0 && j_ < Nj_) { Ni_ = resetToRow(k_ + j_++); @@ -99,8 +91,27 @@ bool Reduced::operator++() { } +bool Reduced::operator--() { + NOTIMP; +} + + +Reduced::operator bool() { + NOTIMP; +} + + +Point& Reduced::operator*() { + NOTIMP; +} + + size_t Reduced::size() const { - return 0; + NOTIMP; +} + +size_t Reduced::index() const { + return count_; } diff --git a/src/eckit/geometry/iterator/Reduced.h b/src/eckit/geometry/iterator/Reduced.h index 4d9107a96..412bc6e2e 100644 --- a/src/eckit/geometry/iterator/Reduced.h +++ b/src/eckit/geometry/iterator/Reduced.h @@ -79,14 +79,19 @@ class Reduced final : public Iterator { // -- Methods - void print(std::ostream&) const; - size_t index() const; size_t resetToRow(size_t); // -- Overridden methods + bool operator!=(const Iterator&) override; bool operator++() override; + bool operator--() override; + + explicit operator bool() override; + Point& operator*() override; + size_t size() const override; + size_t index() const override; // -- Class members // None diff --git a/src/eckit/geometry/iterator/Regular.cc b/src/eckit/geometry/iterator/Regular.cc index 7484752d5..f110ec900 100644 --- a/src/eckit/geometry/iterator/Regular.cc +++ b/src/eckit/geometry/iterator/Regular.cc @@ -12,8 +12,6 @@ #include "eckit/geometry/iterator/Regular.h" -#include - #include "eckit/exception/Exceptions.h" @@ -62,16 +60,8 @@ Regular::Regular(size_t ni, size_t nj, double north, double west, double we, dou } -Regular::~Regular() { - auto count = count_ + (i_ > 0 || j_ > 0 ? 1 : 0); - ASSERT(count == ni_ * nj_); -} - - -void Regular::print(std::ostream& out) const { - out << "Regular[ni=" << ni_ << ",nj=" << nj_ << ",north=" << north_ << ",west=" << west_ - << ",we=" << we_ << ",ns=" << ns_ << ",i=" << i_ << ",j=" << j_ << ",count=" << count_ - << "]"; +bool Regular::operator!=(const Iterator&) { + NOTIMP; } @@ -106,8 +96,27 @@ bool Regular::operator++() { } +bool Regular::operator--() { + NOTIMP; +} + + +Regular::operator bool() { + NOTIMP; +} + + +Point& Regular::operator*() { + NOTIMP; +} + + size_t Regular::size() const { - return 0; + NOTIMP; +} + +size_t Regular::index() const { + NOTIMP; } diff --git a/src/eckit/geometry/iterator/Regular.h b/src/eckit/geometry/iterator/Regular.h index 495b6c3b8..36f6276cb 100644 --- a/src/eckit/geometry/iterator/Regular.h +++ b/src/eckit/geometry/iterator/Regular.h @@ -33,8 +33,7 @@ class Regular final : public Iterator { Regular(size_t ni, size_t nj, double north, double west, double we, double ns); // -- Destructor - - ~Regular() override; + // None // -- Convertors // None @@ -75,13 +74,19 @@ class Regular final : public Iterator { Point p_; // -- Methods - - void print(std::ostream&) const; + // None // -- Overridden methods + bool operator!=(const Iterator&) override; bool operator++() override; + bool operator--() override; + + explicit operator bool() override; + Point& operator*() override; + size_t size() const override; + size_t index() const override; // -- Class members // None diff --git a/src/eckit/geometry/iterator/Unstructured.cc b/src/eckit/geometry/iterator/Unstructured.cc deleted file mode 100644 index c86d6ea3e..000000000 --- a/src/eckit/geometry/iterator/Unstructured.cc +++ /dev/null @@ -1,34 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/iterator/Unstructured.h" - -// #include <> - - -namespace eckit::geometry::iterator { - - -Unstructured::Unstructured() = default; - - -bool Unstructured::operator++() { - return false; -} - - -size_t Unstructured::size() const { - return 0; -} - - -} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/iterator/Unstructured.h b/src/eckit/geometry/iterator/Unstructured.h deleted file mode 100644 index 12ba6f086..000000000 --- a/src/eckit/geometry/iterator/Unstructured.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geometry/Iterator.h" - - -namespace eckit::geometry::iterator { - - -class Unstructured final : public Iterator { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - Unstructured(); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - bool operator++() override; - size_t size() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geometry::iterator diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index 98f4ba988..750772a46 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -63,7 +63,7 @@ class EckitGrid final : public EckitTool { auto it = grid->begin(); - std::cout << **it << std::endl; + std::cout << *it << std::endl; // (*it).print(out) << std::endl; // static_cast(out) << "first: " << q << std::endl; From 682a1a12fbb1373efdcd459bb0b034dde821c6f5 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 11 Aug 2023 12:01:43 +0100 Subject: [PATCH 276/737] eckit::geometry --- src/eckit/geometry/CMakeLists.txt | 1 + src/eckit/geometry/Ordering.h | 50 ++++++++++++++++++++++++++ src/eckit/geometry/iterator/Regular.cc | 35 ------------------ 3 files changed, 51 insertions(+), 35 deletions(-) create mode 100644 src/eckit/geometry/Ordering.h diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index 88dc23ff5..8c1db1045 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -19,6 +19,7 @@ list( APPEND eckit_geometry_srcs Iterator.h KPoint.cc KPoint.h + Ordering.h Point.cc Point.h Point2.cc diff --git a/src/eckit/geometry/Ordering.h b/src/eckit/geometry/Ordering.h new file mode 100644 index 000000000..7ee940ae0 --- /dev/null +++ b/src/eckit/geometry/Ordering.h @@ -0,0 +1,50 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + + +namespace eckit::geometry { + + +enum Ordering +{ + scan_full_i_full_j_i_positively_j_negatively_j_consecutive_i_single_direction, + scan_full_i_full_j_i_negatively_j_negatively_j_consecutive_i_single_direction, + scan_full_i_full_j_i_positively_j_positively_j_consecutive_i_single_direction, + scan_full_i_full_j_i_negatively_j_positively_j_consecutive_i_single_direction, + scan_full_i_full_j_i_positively_j_negatively_i_consecutive_i_single_direction, + scan_full_i_full_j_i_negatively_j_negatively_i_consecutive_i_single_direction, + scan_full_i_full_j_i_positively_j_positively_i_consecutive_i_single_direction, + scan_full_i_full_j_i_negatively_j_positively_i_consecutive_i_single_direction, + scan_full_i_full_j_i_positively_j_negatively_j_consecutive_i_alternating_direction, + scan_full_i_full_j_i_negatively_j_negatively_j_consecutive_i_alternating_direction, + scan_full_i_full_j_i_positively_j_positively_j_consecutive_i_alternating_direction, + scan_full_i_full_j_i_negatively_j_positively_j_consecutive_i_alternating_direction, + scan_full_i_full_j_i_positively_j_negatively_i_consecutive_i_alternating_direction, + scan_full_i_full_j_i_negatively_j_negatively_i_consecutive_i_alternating_direction, + scan_full_i_full_j_i_positively_j_positively_i_consecutive_i_alternating_direction, + scan_full_i_full_j_i_negatively_j_positively_i_consecutive_i_alternating_direction, + // TODO scan_ ... shift + + scan_reduced_i_full_j_i_positively_j_negatively, + scan_reduced_i_full_j_i_negatively_j_negatively, + scan_reduced_i_full_j_i_positively_j_positively, + scan_reduced_i_full_j_i_negatively_j_positively, + // TODO scan_ ... shift + + healpix_ring, + healpix_nested, +}; + + +} // namespace eckit::geometry diff --git a/src/eckit/geometry/iterator/Regular.cc b/src/eckit/geometry/iterator/Regular.cc index f110ec900..511f612d6 100644 --- a/src/eckit/geometry/iterator/Regular.cc +++ b/src/eckit/geometry/iterator/Regular.cc @@ -18,41 +18,6 @@ namespace eckit::geometry::iterator { -#if 0 -Scanning mode (grib2/tables/30/3.4.table, grib2/template.3.scanning_mode.def) - -bool iScansPositively -- 1 0 Points of first row or column scan in the +i (+x) direction -- 1 1 Points of first row or column scan in the -i (-x) direction - -bool jScansPositively -- 2 0 Points of first row or column scan in the -j (-y) direction -- 2 1 Points of first row or column scan in the +j (+y) direction - -bool jPointsAreConsecutive -- 3 0 Adjacent points in i (x) direction are consecutive -- 3 1 Adjacent points in j (y) direction is consecutive - -bool alternativeRowScanning -- 4 0 All rows scan in the same direction -- 4 1 Adjacent rows scan in the opposite direction - -- 5 0 Points within odd rows are not offset in i (x) direction -- 5 1 Points within odd rows are offset by Di/2 in i (x) direction -- 6 0 Points within even rows are not offset in i (x) direction -- 6 1 Points within even rows are offset by Di/2 in i (x) direction -- 7 0 Points are not offset in j (y) direction -- 7 1 Points are offset by Dj/2 in j (y) direction - -- 8 0 n_i columns, n_j rows -- 8 1 Rows have n_i points if points are not offset in i direction - Rows have n_i-1 points if points are offset by Di/2 in i direction - Columns have n_j points if points are not offset in j direction - Columns have n_j-1 points if points are offset by Dj/2 in j direction - -#endif - - Regular::Regular(size_t ni, size_t nj, double north, double west, double we, double ns) : ni_(ni), nj_(nj), north_(north), west_(west), we_(we), ns_(ns), i_(0), j_(0), lat_(north_), lon_(west_), count_(0), first_(true), p_(PointLonLat{0, 0}) { latValue_ = lat_; From aa6f0317a733d6edf1629f248b5a91e7e5b30827 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 12 Aug 2023 09:58:01 +0100 Subject: [PATCH 277/737] eckit::geometry --- src/eckit/geometry/Domain.h | 7 +-- src/eckit/geometry/Figure.cc | 85 +++++++++++++++++++++++++++ src/eckit/geometry/Figure.h | 36 ++++++++++-- src/eckit/geometry/Increments.h | 67 +++++++++++++++++++-- src/eckit/geometry/Projection.cc | 15 +++-- src/eckit/geometry/area/BoundingBox.h | 6 +- src/tools/eckit-grid.cc | 1 - 7 files changed, 191 insertions(+), 26 deletions(-) diff --git a/src/eckit/geometry/Domain.h b/src/eckit/geometry/Domain.h index 38e0e4222..e8dfd1253 100644 --- a/src/eckit/geometry/Domain.h +++ b/src/eckit/geometry/Domain.h @@ -12,8 +12,6 @@ #pragma once -#include - namespace eckit::geometry { @@ -109,10 +107,7 @@ class Domain { // None // -- Friends - - friend std::ostream& operator<<(std::ostream& out, const Domain& p) { - return out << '{' << p.north_ << ", " << p.west_ << ", " << p.south_ << ", " << p.east_ << '}'; - } + // None }; diff --git a/src/eckit/geometry/Figure.cc b/src/eckit/geometry/Figure.cc index 2ac866af3..948c8c98f 100644 --- a/src/eckit/geometry/Figure.cc +++ b/src/eckit/geometry/Figure.cc @@ -12,7 +12,15 @@ #include "eckit/geometry/Figure.h" +#include +#include + #include "eckit/config/Configuration.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/log/JSON.h" +#include "eckit/log/Log.h" +#include "eckit/thread/AutoLock.h" +#include "eckit/thread/Mutex.h" namespace eckit::geometry { @@ -24,4 +32,81 @@ Figure::Figure(const Configuration& config) /*: } +static pthread_once_t __once = PTHREAD_ONCE_INIT; +static Mutex* __mutex = nullptr; +static std::map* __factories = nullptr; + + +static void __init() { + __mutex = new Mutex; + __factories = new std::map(); +} + + +Figure* FigureFactory::build(const Configuration& config) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + std::string type; + ASSERT(config.get("type", type)); + + return build(type, config); +} + + +Figure* FigureFactory::build(const std::string& type, const Configuration& config) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + if (auto f = __factories->find(type); f != __factories->end()) { + return f->second->make(config); + } + + list(Log::error() << "FigureFactory: unknown '" << type << "', choices are: "); + throw BadValue("FigureFactory: unknown '" + type + "'"); +} + + +std::ostream& FigureFactory::list(std::ostream& out) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + JSON j(out); + j.startObject(); + + j << "type"; + j.startList(); + for (const auto& p : *__factories) { + j << p.first; + } + j.endList(); + + j.endObject(); + + return out; +} + + +FigureFactory::FigureFactory(const std::string& key) : + key_(key) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + if (auto f = __factories->find(key); f != __factories->end()) { + throw BadValue("FigureFactory: duplicate '" + key + "'"); + } + + (*__factories)[key] = this; +} + + +FigureFactory::~FigureFactory() { + AutoLock lock(*__mutex); + + if (__factories != nullptr) { + __factories->erase(key_); + } +} + + } // namespace eckit::geometry diff --git a/src/eckit/geometry/Figure.h b/src/eckit/geometry/Figure.h index d3facb07c..d5b5aaea3 100644 --- a/src/eckit/geometry/Figure.h +++ b/src/eckit/geometry/Figure.h @@ -12,7 +12,8 @@ #pragma once -#include +#include +#include namespace eckit { @@ -87,10 +88,37 @@ class Figure { // -- Friends // None +}; + + +struct FigureFactory { + static Figure* build(const Configuration&); + static Figure* build(const std::string&, const Configuration&); + static std::ostream& list(std::ostream&); + + FigureFactory(const FigureFactory&) = delete; + FigureFactory(FigureFactory&&) = delete; + FigureFactory& operator=(const FigureFactory&) = delete; + FigureFactory& operator=(FigureFactory&&) = delete; + + virtual Figure* make(const Configuration&) = 0; + +protected: + explicit FigureFactory(const std::string&); + virtual ~FigureFactory(); - friend std::ostream& operator<<(std::ostream& out, const Figure& p) { - return out << '{' << '}'; - } +private: + const std::string key_; +}; + + +template +class FigureBuilder final : public FigureFactory { + Figure* make(const Configuration& config) override { return new T(config); } + +public: + explicit FigureBuilder(const std::string& key) : + FigureFactory(key) {} }; diff --git a/src/eckit/geometry/Increments.h b/src/eckit/geometry/Increments.h index 55dda166c..7df79bbfa 100644 --- a/src/eckit/geometry/Increments.h +++ b/src/eckit/geometry/Increments.h @@ -13,7 +13,6 @@ #pragma once #include -#include namespace eckit { @@ -31,6 +30,12 @@ class Increments : protected std::array { using P = std::array; public: + // -- Types + // None + + // -- Exceptions + // None + // -- Constructors Increments(double west_east, double south_north) : @@ -38,16 +43,66 @@ class Increments : protected std::array { Increments(const Configuration&); - // -- Members + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // Members double& west_east = P::operator[](0); double& south_north = P::operator[](1); - // -- Friends + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Members + // None - friend std::ostream& operator<<(std::ostream& out, const Increments& p) { - return out << '{' << p.west_east << ", " << p.south_north << '}'; - } + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None }; diff --git a/src/eckit/geometry/Projection.cc b/src/eckit/geometry/Projection.cc index 9cc707417..c93178a18 100644 --- a/src/eckit/geometry/Projection.cc +++ b/src/eckit/geometry/Projection.cc @@ -17,6 +17,7 @@ #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" +#include "eckit/log/JSON.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -260,11 +261,17 @@ std::ostream& ProjectionFactory::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - const char* sep = "'"; - for (const auto& j : *__factories) { - out << sep << j.first << '\''; - sep = ", '"; + JSON j(out); + j.startObject(); + + j << "type"; + j.startList(); + for (const auto& p : *__factories) { + j << p.first; } + j.endList(); + + j.endObject(); return out; } diff --git a/src/eckit/geometry/area/BoundingBox.h b/src/eckit/geometry/area/BoundingBox.h index b931cde1d..a0ab33cde 100644 --- a/src/eckit/geometry/area/BoundingBox.h +++ b/src/eckit/geometry/area/BoundingBox.h @@ -12,7 +12,6 @@ #pragma once -#include #include #include "eckit/geometry/Area.h" @@ -127,10 +126,7 @@ class BoundingBox : public Area { // None // -- Friends - - friend std::ostream& operator<<(std::ostream& out, const BoundingBox& p) { - return out << '{' << p.north_ << ", " << p.west_ << ", " << p.south_ << ", " << p.east_ << '}'; - } + // None }; diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index 750772a46..816c2df4b 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -59,7 +59,6 @@ class EckitGrid final : public EckitTool { // out << "name: " << grid->name() << std::endl; // out << "uid: " << grid->uid() << std::endl; out << "size: " << grid->size() << std::endl; - out << "bounding_box: " << grid->boundingBox() << std::endl; auto it = grid->begin(); From 1c3483c1367dc42cd255406dab180604c7cee1a0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 12 Aug 2023 10:00:47 +0100 Subject: [PATCH 278/737] eckit::geometry --- src/eckit/geometry/grid/RegularLL.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/eckit/geometry/grid/RegularLL.cc b/src/eckit/geometry/grid/RegularLL.cc index 06b05bdb9..50aa2eaf9 100644 --- a/src/eckit/geometry/grid/RegularLL.cc +++ b/src/eckit/geometry/grid/RegularLL.cc @@ -277,7 +277,11 @@ Iterator* RegularLL::iterator() const { #endif -static const GridRegisterType regularLL("regular_ll"); +static const GridRegisterType __grid_type("regular_ll"); + +#define fp "[+]?([0-9]*[.])?[0-9]+([eE][-+][0-9]+)?" +static const GridRegisterName __grid_pattern(fp "/" fp); +#undef fp } // namespace eckit::geometry::grid From 157e621095ad2931a1b974d11a0182b25f7e58b0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 12 Aug 2023 13:02:22 +0100 Subject: [PATCH 279/737] eckit::geometry --- src/eckit/geometry/CMakeLists.txt | 2 ++ src/eckit/geometry/util/regex.cc | 55 +++++++++++++++++++++++++++++++ src/eckit/geometry/util/regex.h | 30 +++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 src/eckit/geometry/util/regex.cc create mode 100644 src/eckit/geometry/util/regex.h diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index 8c1db1045..0f933354d 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -82,6 +82,8 @@ list( APPEND eckit_geometry_srcs util/monotonic_crop.cc util/reduced_classical_pl.cc util/reduced_octahedral_pl.cc + util/regex.cc + util/regex.h ) set(eckit_geometry_include_dirs ) diff --git a/src/eckit/geometry/util/regex.cc b/src/eckit/geometry/util/regex.cc new file mode 100644 index 000000000..2d8f2fee3 --- /dev/null +++ b/src/eckit/geometry/util/regex.cc @@ -0,0 +1,55 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/util/regex.h" + +#include + +#include "eckit/log/Log.h" + + +namespace eckit::geometry::util { + + +regex_match_type regex_match(const std::string& pattern, const std::string& s) { + static const std::map __regex_code{ + {std::regex_constants::error_backref, "error_backref"}, + {std::regex_constants::error_badbrace, "error_badbrace"}, + {std::regex_constants::error_badrepeat, "error_badrepeat"}, + {std::regex_constants::error_brace, "error_brace"}, + {std::regex_constants::error_brack, "error_brack"}, + {std::regex_constants::error_collate, "error_collate"}, + {std::regex_constants::error_complexity, "error_complexity"}, + {std::regex_constants::error_ctype, "error_ctype"}, + {std::regex_constants::error_escape, "error_escape"}, + {std::regex_constants::error_paren, "error_paren"}, + {std::regex_constants::error_range, "error_range"}, + {std::regex_constants::error_space, "error_space"}, + {std::regex_constants::error_stack, "error_stack"}, + }; + + std::regex regex; + try { + regex.assign(std::regex(pattern, std::regex_constants::extended)); + } + catch (const std::regex_error& e) { + Log::error() << "regex_error caught: " << e.what() << ", code: " << __regex_code.at(e.code()) << std::endl; + throw; + } + + regex_match_type m; + std::regex_match(s, m, regex); + return m; +} + + +} // namespace eckit::geometry::util diff --git a/src/eckit/geometry/util/regex.h b/src/eckit/geometry/util/regex.h new file mode 100644 index 000000000..6eb211099 --- /dev/null +++ b/src/eckit/geometry/util/regex.h @@ -0,0 +1,30 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + + +namespace eckit::geometry::util { + + +struct regex_match_type : std::smatch { + operator bool() const { return !std::smatch::empty(); } +}; + + +regex_match_type regex_match(const std::string& pattern, const std::string&); + + +} // namespace eckit::geometry::util From 55fca9cce7177b66447f538f2bda9d13a188d2ed Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 12 Aug 2023 13:04:06 +0100 Subject: [PATCH 280/737] eckit::geometry --- src/eckit/geometry/grid/RegularLL.cc | 25 +++++++++++++++++++++++++ src/eckit/geometry/grid/RegularLL.h | 2 ++ 2 files changed, 27 insertions(+) diff --git a/src/eckit/geometry/grid/RegularLL.cc b/src/eckit/geometry/grid/RegularLL.cc index 50aa2eaf9..53e4e623c 100644 --- a/src/eckit/geometry/grid/RegularLL.cc +++ b/src/eckit/geometry/grid/RegularLL.cc @@ -14,13 +14,18 @@ #include #include +#include +#include +#include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geometry/Point.h" #include "eckit/geometry/Projection.h" #include "eckit/geometry/grid/RegularLL.h" +#include "eckit/geometry/util/regex.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" +#include "eckit/utils/Translator.h" namespace eckit::geometry::grid { @@ -279,8 +284,28 @@ Iterator* RegularLL::iterator() const { static const GridRegisterType __grid_type("regular_ll"); + #define fp "[+]?([0-9]*[.])?[0-9]+([eE][-+][0-9]+)?" + + +Configuration* RegularLL::config(const std::string& name) { + static const std::string pattern("(" fp ")/(" fp ")"); + + auto match = util::regex_match(pattern, name); + ASSERT(match); + ASSERT(match.size() == 3); + + auto d = Translator{}; + std::vector increments{d(match[1]), d(match[2])}; + + return new MappedConfiguration({{"type", "regular_ll"}, + {"increments", increments}}); +} + + static const GridRegisterName __grid_pattern(fp "/" fp); + + #undef fp diff --git a/src/eckit/geometry/grid/RegularLL.h b/src/eckit/geometry/grid/RegularLL.h index a849c06c6..8de7aa460 100644 --- a/src/eckit/geometry/grid/RegularLL.h +++ b/src/eckit/geometry/grid/RegularLL.h @@ -44,6 +44,8 @@ class RegularLL : public Grid { static area::BoundingBox correctBoundingBox(const area::BoundingBox&, size_t& ni, size_t& nj, const Increments&, const PointLonLat& reference = {0, 0}); + static Configuration* config(const std::string& name); + // -- Overridden methods // None From 6947eb1568d102884d6aa8c1aaf49cac620bd5a9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 13 Aug 2023 01:34:18 +0100 Subject: [PATCH 281/737] eckit::geometry --- src/eckit/geometry/grid/RegularLL.cc | 110 ++++----------------------- src/eckit/runtime/Tool.cc | 14 +--- 2 files changed, 16 insertions(+), 108 deletions(-) diff --git a/src/eckit/geometry/grid/RegularLL.cc b/src/eckit/geometry/grid/RegularLL.cc index 53e4e623c..e1ab8e2ec 100644 --- a/src/eckit/geometry/grid/RegularLL.cc +++ b/src/eckit/geometry/grid/RegularLL.cc @@ -23,7 +23,6 @@ #include "eckit/geometry/Projection.h" #include "eckit/geometry/grid/RegularLL.h" #include "eckit/geometry/util/regex.h" -#include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" @@ -124,8 +123,8 @@ RegularLL::RegularLL(const Configuration& config) : // confirm Ni/Nj from config (input) size_t ni = 0; size_t nj = 0; - ASSERT(config.get("Ni", ni)); - ASSERT(config.get("Nj", nj)); + ASSERT(config.get("ni", ni)); + ASSERT(config.get("nj", nj)); ASSERT(ni == ni_); ASSERT(nj == nj_); @@ -197,116 +196,37 @@ area::BoundingBox RegularLL::correctBoundingBox(const area::BoundingBox& box, si } -#if 0 -Iterator* RegularLL::iterator() const { - - class RegularLLIterator : public Iterator { - public: - size_t ni_; - size_t nj_; - Fraction north_; - Fraction west_; - Fraction we_; - Fraction ns_; - size_t i_; - size_t j_; - Latitude latValue_; - Longitude lonValue_; - Fraction lat_; - Fraction lon_; - - size_t count_; - bool first_; - - ~RegularLLIterator() { - auto count = count_ + (i_ > 0 || j_ > 0 ? 1 : 0); - ASSERT(count == ni_ * nj_); - } - - bool operator++() override { - if (j_ < nj_) { - if (i_ < ni_) { - // lat = latValue_; - // lon = lonValue_; - - lon_ += we_; - - if (first_) { - first_ = false; - } - else { - count_++; - } - - if (++i_ == ni_) { - j_++; - i_ = 0; - lat_ -= ns_; - lon_ = west_; - latValue_ = lat_; - } - - lonValue_ = lon_; - - return true; - } - } - return false; - } - - size_t index() const override { return count_; } - - size_t size() const override { NOTIMP; } - - public: - RegularLLIterator(size_t ni, size_t nj, Latitude north, Longitude west, const Increments& increments) : - ni_(ni), - nj_(nj), - north_(north), - west_(west), - we_(increments.west_east), - ns_(increments.south_north), - i_(0), - j_(0), - count_(0), - first_(true) { - lat_ = north_; - lon_ = west_; - latValue_ = lat_; - lonValue_ = lon_; - } - }; - - return new RegularLLIterator(ni_, nj_, bbox().north(), bbox().west(), increments_); -} -#endif - - static const GridRegisterType __grid_type("regular_ll"); -#define fp "[+]?([0-9]*[.])?[0-9]+([eE][-+][0-9]+)?" +#define POSITIVE_REAL "[+]?([0-9]*[.])?[0-9]+([eE][-+][0-9]+)?" Configuration* RegularLL::config(const std::string& name) { - static const std::string pattern("(" fp ")/(" fp ")"); + static const std::string pattern("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); auto match = util::regex_match(pattern, name); ASSERT(match); - ASSERT(match.size() == 3); + ASSERT(match.size() == 7); // because of sub-matches auto d = Translator{}; - std::vector increments{d(match[1]), d(match[2])}; + std::vector increments{d(match[1]), d(match[4])}; + + auto ni = detail::RegularIterator(Fraction(0), Fraction(360), Fraction(increments[0]), Fraction(0), Fraction(360)).n(); + auto nj = detail::RegularIterator(Fraction(-90), Fraction(90), Fraction(increments[1]), Fraction(0)).n(); return new MappedConfiguration({{"type", "regular_ll"}, - {"increments", increments}}); + {"west_east_increment", increments[0]}, + {"south_north_increment", increments[1]}, + {"ni", ni}, + {"nj", nj}}); } -static const GridRegisterName __grid_pattern(fp "/" fp); +static const GridRegisterName __grid_pattern(POSITIVE_REAL "/" POSITIVE_REAL); -#undef fp +#undef POSITIVE_REAL } // namespace eckit::geometry::grid diff --git a/src/eckit/runtime/Tool.cc b/src/eckit/runtime/Tool.cc index 2774dc733..0a45742ea 100644 --- a/src/eckit/runtime/Tool.cc +++ b/src/eckit/runtime/Tool.cc @@ -24,19 +24,7 @@ Tool::~Tool() {} int Tool::start() { int status = 0; - try { - run(); - } - catch (Exception& e) { - status = 1; - Log::error() << "** " << e.what() << " Caught in " << Here() << std::endl; - Log::error() << "** Exception terminates " << name() << std::endl; - } - catch (std::exception& e) { - status = 1; - Log::error() << "** " << e.what() << " Caught in " << Here() << std::endl; - Log::error() << "** Exception terminates " << name() << std::endl; - } + run(); return status; } From dfb0415705d078fb379b9d2309e238cbcc208954 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 14 Aug 2023 10:26:34 +0100 Subject: [PATCH 282/737] eckit::geometry --- src/eckit/geometry/CMakeLists.txt | 10 ++- src/eckit/geometry/Grid.cc | 27 +++++- src/eckit/geometry/Grid.h | 13 +-- src/eckit/geometry/Iterator.h | 13 ++- src/eckit/geometry/iterator/ListI.cc | 72 ++++++++++++++++ src/eckit/geometry/iterator/ListI.h | 86 +++++++++++++++++++ .../iterator/{Regular.cc => ListIListJ.cc} | 34 +++++--- .../iterator/{Regular.h => ListIListJ.h} | 10 +-- .../iterator/{Reduced.cc => ReducedIListJ.cc} | 48 +++++++---- .../iterator/{Reduced.h => ReducedIListJ.h} | 18 ++-- 10 files changed, 275 insertions(+), 56 deletions(-) create mode 100644 src/eckit/geometry/iterator/ListI.cc create mode 100644 src/eckit/geometry/iterator/ListI.h rename src/eckit/geometry/iterator/{Regular.cc => ListIListJ.cc} (64%) rename src/eckit/geometry/iterator/{Regular.h => ListIListJ.h} (86%) rename src/eckit/geometry/iterator/{Reduced.cc => ReducedIListJ.cc} (64%) rename src/eckit/geometry/iterator/{Reduced.h => ReducedIListJ.h} (83%) diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index 0f933354d..a0483baf1 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -60,10 +60,12 @@ list( APPEND eckit_geometry_srcs grid/RegularLL.h grid/UnstructuredGrid.cc grid/UnstructuredGrid.h - iterator/Reduced.cc - iterator/Reduced.h - iterator/Regular.cc - iterator/Regular.h + iterator/ListI.cc + iterator/ListI.h + iterator/ListIListJ.cc + iterator/ListIListJ.h + iterator/ReducedIListJ.cc + iterator/ReducedIListJ.h polygon/LonLatPolygon.cc polygon/LonLatPolygon.h polygon/Polygon.cc diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 282c34a7b..b888f810a 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -37,7 +37,32 @@ Grid::Grid(const area::BoundingBox& bbox) : const area::BoundingBox& Grid::boundingBox() const { - return bbox_; + throw NotImplemented("Grid::boundingBox", Here()); +} + + +size_t Grid::size() const { + throw NotImplemented("Grid::size", Here()); +} + + +bool Grid::includesNorthPole() const { + throw NotImplemented("Grid::includesNorthPole", Here()); +} + + +bool Grid::includesSouthPole() const { + throw NotImplemented("Grid::includesSouthPole", Here()); +} + + +bool Grid::isPeriodicWestEast() const { + throw NotImplemented("Grid::isPeriodicWestEast", Here()); +} + + +const std::vector& Grid::to_points() const { + throw NotImplemented("Grid::to_points", Here()); } diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index bf7e205a1..61265c629 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -46,12 +46,13 @@ class Grid { void operator=(const Iterator&) = delete; void operator=(Iterator&&) = delete; + bool operator==(const Iterator& other) { return get()->operator==(*(other.get())); } bool operator!=(const Iterator& other) { return get()->operator!=(*(other.get())); } bool operator++() { return get()->operator++(); } bool operator--() { return get()->operator--(); } explicit operator bool() { return get()->operator bool(); } - Point& operator*() { return get()->operator*(); } + const Point& operator*() { return get()->operator*(); } size_t size() const { return get()->size(); } size_t index() const { return get()->index(); } @@ -96,11 +97,13 @@ class Grid { virtual const area::BoundingBox& boundingBox() const; - virtual size_t size() const = 0; + virtual size_t size() const; - virtual bool includesNorthPole() const = 0; - virtual bool includesSouthPole() const = 0; - virtual bool isPeriodicWestEast() const = 0; + virtual bool includesNorthPole() const; + virtual bool includesSouthPole() const; + virtual bool isPeriodicWestEast() const; + + virtual const std::vector& to_points() const; // -- Overridden methods // None diff --git a/src/eckit/geometry/Iterator.h b/src/eckit/geometry/Iterator.h index 8afd18ec6..d58990070 100644 --- a/src/eckit/geometry/Iterator.h +++ b/src/eckit/geometry/Iterator.h @@ -15,6 +15,11 @@ #include "eckit/geometry/Point.h" +namespace eckit::geometry { +class Grid; +} + + namespace eckit::geometry { @@ -43,12 +48,14 @@ class Iterator { void operator=(const Iterator&) = delete; void operator=(Iterator&&) = delete; - virtual bool operator!=(const Iterator&) = 0; + bool operator!=(const Iterator& other) { return !operator==(other); } + + virtual bool operator==(const Iterator&) = 0; virtual bool operator++() = 0; virtual bool operator--() = 0; virtual explicit operator bool() = 0; - virtual Point& operator*() = 0; + virtual const Point& operator*() = 0; // -- Methods @@ -67,7 +74,7 @@ class Iterator { protected: // -- Constructors - Iterator() = default; + Iterator(const Grid&) {} // -- Members // None diff --git a/src/eckit/geometry/iterator/ListI.cc b/src/eckit/geometry/iterator/ListI.cc new file mode 100644 index 000000000..415e218b6 --- /dev/null +++ b/src/eckit/geometry/iterator/ListI.cc @@ -0,0 +1,72 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/iterator/ListI.h" + +#include + +#include "eckit/geometry/Grid.h" + + +namespace eckit::geometry::iterator { + + +ListI::ListI(const Grid& grid) : + Iterator(grid), + points_(grid.to_points()), + index_(0) { +} + + +bool ListI::operator==(const Iterator& other) { + const auto* another = dynamic_cast(&other); + return another != nullptr && points_.data() == another->points_.data() && index_ == another->index_; +} + + +bool ListI::operator++() { + ++index_; + return operator bool(); +} + + +bool ListI::operator--() { + if (index_ == 0) { + return false; + } + index_--; + return operator bool(); +} + + +ListI::operator bool() { + return index_ < points_.size(); +} + + +const Point& ListI::operator*() { + ASSERT(operator bool()); + return points_[index_]; +} + + +size_t ListI::size() const { + return points_.size(); +} + + +size_t ListI::index() const { + return index_; +} + + +} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/iterator/ListI.h b/src/eckit/geometry/iterator/ListI.h new file mode 100644 index 000000000..80d3bf8d4 --- /dev/null +++ b/src/eckit/geometry/iterator/ListI.h @@ -0,0 +1,86 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geometry/Iterator.h" + + +namespace eckit::geometry::iterator { + + +class ListI final : public Iterator { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit ListI(const Grid&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + const std::vector& points_; + size_t index_; + + // -- Methods + // None + + // -- Overridden methods + + bool operator==(const Iterator&) override; + bool operator++() override; + bool operator--() override; + + explicit operator bool() override; + const Point& operator*() override; + + size_t size() const override; + size_t index() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/iterator/Regular.cc b/src/eckit/geometry/iterator/ListIListJ.cc similarity index 64% rename from src/eckit/geometry/iterator/Regular.cc rename to src/eckit/geometry/iterator/ListIListJ.cc index 511f612d6..722077547 100644 --- a/src/eckit/geometry/iterator/Regular.cc +++ b/src/eckit/geometry/iterator/ListIListJ.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/iterator/Regular.h" +#include "eckit/geometry/iterator/ListIListJ.h" #include "eckit/exception/Exceptions.h" @@ -18,19 +18,32 @@ namespace eckit::geometry::iterator { -Regular::Regular(size_t ni, size_t nj, double north, double west, double we, double ns) : - ni_(ni), nj_(nj), north_(north), west_(west), we_(we), ns_(ns), i_(0), j_(0), lat_(north_), lon_(west_), count_(0), first_(true), p_(PointLonLat{0, 0}) { +ListIListJ::ListIListJ(const Grid& grid) : + Iterator(grid), + ni_(0), // size_t ni + nj_(0), // size_t nj + north_(0), // double north + west_(0), // double west + we_(0), // double we + ns_(0), // double ns + i_(0), + j_(0), + lat_(north_), + lon_(west_), + count_(0), + first_(true), + p_(PointLonLat{0, 0}) { latValue_ = lat_; lonValue_ = lon_; } -bool Regular::operator!=(const Iterator&) { +bool ListIListJ::operator==(const Iterator&) { NOTIMP; } -bool Regular::operator++() { +bool ListIListJ::operator++() { if (j_ < nj_) { if (i_ < ni_) { p_ = PointLonLat{lonValue_, latValue_}; @@ -61,26 +74,27 @@ bool Regular::operator++() { } -bool Regular::operator--() { +bool ListIListJ::operator--() { NOTIMP; } -Regular::operator bool() { +ListIListJ::operator bool() { NOTIMP; } -Point& Regular::operator*() { +const Point& ListIListJ::operator*() { NOTIMP; } -size_t Regular::size() const { +size_t ListIListJ::size() const { NOTIMP; } -size_t Regular::index() const { + +size_t ListIListJ::index() const { NOTIMP; } diff --git a/src/eckit/geometry/iterator/Regular.h b/src/eckit/geometry/iterator/ListIListJ.h similarity index 86% rename from src/eckit/geometry/iterator/Regular.h rename to src/eckit/geometry/iterator/ListIListJ.h index 36f6276cb..74f322afb 100644 --- a/src/eckit/geometry/iterator/Regular.h +++ b/src/eckit/geometry/iterator/ListIListJ.h @@ -13,14 +13,13 @@ #pragma once #include "eckit/geometry/Iterator.h" -#include "eckit/geometry/Point.h" #include "eckit/types/Fraction.h" namespace eckit::geometry::iterator { -class Regular final : public Iterator { +class ListIListJ final : public Iterator { public: // -- Types // None @@ -30,7 +29,7 @@ class Regular final : public Iterator { // -- Constructors - Regular(size_t ni, size_t nj, double north, double west, double we, double ns); + explicit ListIListJ(const Grid&); // -- Destructor // None @@ -70,7 +69,6 @@ class Regular final : public Iterator { Fraction lon_; size_t count_; bool first_; - Point p_; // -- Methods @@ -78,12 +76,12 @@ class Regular final : public Iterator { // -- Overridden methods - bool operator!=(const Iterator&) override; + bool operator==(const Iterator&) override; bool operator++() override; bool operator--() override; explicit operator bool() override; - Point& operator*() override; + const Point& operator*() override; size_t size() const override; size_t index() const override; diff --git a/src/eckit/geometry/iterator/Reduced.cc b/src/eckit/geometry/iterator/ReducedIListJ.cc similarity index 64% rename from src/eckit/geometry/iterator/Reduced.cc rename to src/eckit/geometry/iterator/ReducedIListJ.cc index fd0b76870..3eea54dd1 100644 --- a/src/eckit/geometry/iterator/Reduced.cc +++ b/src/eckit/geometry/iterator/ReducedIListJ.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/iterator/Reduced.h" +#include "eckit/geometry/iterator/ReducedIListJ.h" #include "eckit/exception/Exceptions.h" @@ -18,13 +18,29 @@ namespace eckit::geometry::iterator { -Reduced::Reduced(const std::vector& latitudes, - pl_type&& pl, - const area::BoundingBox& bbox, - size_t N, - size_t Nj, - size_t k) : - latitudes_(latitudes), pl_(pl), bbox_(bbox), N_(N), Ni_(0), Nj_(Nj), lat_(latitudes[k]), i_(0), j_(0), k_(k), count_(0), first_(true), p_(PointLonLat{0, 0}) { +// FIXME +static const std::vector __latitudes; +static const area::BoundingBox __bbox; +static const pl_type __pl; + + +ReducedIListJ::ReducedIListJ( + const Grid& grid) : + Iterator(grid), + latitudes_(__latitudes), // const std::vector& latitudes + pl_(__pl), // pl_type&& pl + bbox_(__bbox), // const area::BoundingBox& bbox + N_(0), // size_t N + Ni_(0), + Nj_(0), // size_t Nj + lon_(0), + lat_(0), // lat_(latitudes[k]) + i_(0), + j_(0), + k_(0), // size_t k + count_(0), + first_(true), + p_(PointLonLat{0, 0}) { // NOTE: latitudes_ span the globe, sorted from North-to-South, k_ positions the North // NOTE: pl is global ASSERT(N_ * 2 == latitudes_.size()); @@ -32,7 +48,7 @@ Reduced::Reduced(const std::vector& latitudes, } -size_t Reduced::resetToRow(size_t j) { +size_t ReducedIListJ::resetToRow(size_t j) { ASSERT(j < latitudes_.size()); lat_ = latitudes_[j]; @@ -58,12 +74,12 @@ size_t Reduced::resetToRow(size_t j) { } -bool Reduced::operator!=(const Iterator&) { +bool ReducedIListJ::operator==(const Iterator&) { NOTIMP; } -bool Reduced::operator++() { +bool ReducedIListJ::operator++() { while (Ni_ == 0 && j_ < Nj_) { Ni_ = resetToRow(k_ + j_++); } @@ -91,26 +107,26 @@ bool Reduced::operator++() { } -bool Reduced::operator--() { +bool ReducedIListJ::operator--() { NOTIMP; } -Reduced::operator bool() { +ReducedIListJ::operator bool() { NOTIMP; } -Point& Reduced::operator*() { +const Point& ReducedIListJ::operator*() { NOTIMP; } -size_t Reduced::size() const { +size_t ReducedIListJ::size() const { NOTIMP; } -size_t Reduced::index() const { +size_t ReducedIListJ::index() const { return count_; } diff --git a/src/eckit/geometry/iterator/Reduced.h b/src/eckit/geometry/iterator/ReducedIListJ.h similarity index 83% rename from src/eckit/geometry/iterator/Reduced.h rename to src/eckit/geometry/iterator/ReducedIListJ.h index 412bc6e2e..4e7eee7f2 100644 --- a/src/eckit/geometry/iterator/Reduced.h +++ b/src/eckit/geometry/iterator/ReducedIListJ.h @@ -13,7 +13,6 @@ #pragma once #include "eckit/geometry/Iterator.h" -#include "eckit/geometry/Point.h" #include "eckit/geometry/area/BoundingBox.h" #include "eckit/geometry/util.h" #include "eckit/types/Fraction.h" @@ -22,19 +21,17 @@ namespace eckit::geometry::iterator { -class Reduced final : public Iterator { +class ReducedIListJ : public Iterator { public: + // -- Types + // None + // -- Exceptions // None // -- Constructors - Reduced(const std::vector& latitudes, - pl_type&& pl, - const area::BoundingBox&, - size_t N, - size_t Nj, - size_t k); + explicit ReducedIListJ(const Grid&); // -- Destructor // None @@ -74,7 +71,6 @@ class Reduced final : public Iterator { size_t k_; size_t count_; bool first_; - Point p_; // -- Methods @@ -83,12 +79,12 @@ class Reduced final : public Iterator { // -- Overridden methods - bool operator!=(const Iterator&) override; + bool operator==(const Iterator&) override; bool operator++() override; bool operator--() override; explicit operator bool() override; - Point& operator*() override; + const Point& operator*() override; size_t size() const override; size_t index() const override; From bfa14a945b48632ed760a187c468916539974c22 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 14 Aug 2023 12:28:10 +0100 Subject: [PATCH 283/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 7 +- src/eckit/geometry/Grid.h | 17 +-- src/eckit/geometry/grid/Gaussian.h | 10 +- src/eckit/geometry/grid/HEALPix.cc | 5 + src/eckit/geometry/grid/HEALPix.h | 10 +- src/eckit/geometry/grid/IrregularLatlon.cc | 50 +++---- src/eckit/geometry/grid/IrregularLatlon.h | 18 +-- src/eckit/geometry/grid/ReducedGG.cc | 5 + src/eckit/geometry/grid/ReducedGG.h | 2 + src/eckit/geometry/grid/ReducedLL.cc | 13 ++ src/eckit/geometry/grid/ReducedLL.h | 10 +- src/eckit/geometry/grid/RegularGG.cc | 5 + src/eckit/geometry/grid/RegularGG.h | 2 + src/eckit/geometry/grid/RegularLL.cc | 5 + src/eckit/geometry/grid/RegularLL.h | 18 +-- src/eckit/geometry/grid/UnstructuredGrid.cc | 155 +------------------- src/eckit/geometry/grid/UnstructuredGrid.h | 45 +----- src/eckit/geometry/iterator/ListI.cc | 12 +- src/eckit/geometry/iterator/ListI.h | 1 + 19 files changed, 121 insertions(+), 269 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index b888f810a..162bcb52d 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -41,6 +41,11 @@ const area::BoundingBox& Grid::boundingBox() const { } +void Grid::boundingBox(const area::BoundingBox& bbox) { + bbox_ = bbox; +} + + size_t Grid::size() const { throw NotImplemented("Grid::size", Here()); } @@ -61,7 +66,7 @@ bool Grid::isPeriodicWestEast() const { } -const std::vector& Grid::to_points() const { +std::vector&& Grid::to_points() const { throw NotImplemented("Grid::to_points", Here()); } diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 61265c629..b8dc90449 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -58,8 +58,7 @@ class Grid { size_t index() const { return get()->index(); } }; - using iterator = Iterator; - using const_iterator = const Iterator; + using iterator = Iterator; // -- Exceptions // None @@ -86,16 +85,14 @@ class Grid { // -- Methods - virtual iterator begin() = 0; - virtual iterator end() = 0; + iterator begin() const { return cbegin(); } + iterator end() const { return cend(); } - virtual const_iterator cbegin() const = 0; - virtual const_iterator cend() const = 0; - - virtual const_iterator begin() const = 0; - virtual const_iterator end() const = 0; + virtual iterator cbegin() const = 0; + virtual iterator cend() const = 0; virtual const area::BoundingBox& boundingBox() const; + void boundingBox(const area::BoundingBox&); virtual size_t size() const; @@ -103,7 +100,7 @@ class Grid { virtual bool includesSouthPole() const; virtual bool isPeriodicWestEast() const; - virtual const std::vector& to_points() const; + virtual std::vector&& to_points() const = 0; // -- Overridden methods // None diff --git a/src/eckit/geometry/grid/Gaussian.h b/src/eckit/geometry/grid/Gaussian.h index 2de28bd30..2ab163bb2 100644 --- a/src/eckit/geometry/grid/Gaussian.h +++ b/src/eckit/geometry/grid/Gaussian.h @@ -70,14 +70,8 @@ class Gaussian : public Grid { bool includesNorthPole() const override; bool includesSouthPole() const override; - iterator begin() override { NOTIMP; } - iterator end() override { NOTIMP; } - - const_iterator cbegin() const override { NOTIMP; } - const_iterator cend() const override { NOTIMP; } - - const_iterator begin() const override { NOTIMP; } - const_iterator end() const override { NOTIMP; } + iterator cbegin() const override { NOTIMP; } + iterator cend() const override { NOTIMP; } // -- Class members // None diff --git a/src/eckit/geometry/grid/HEALPix.cc b/src/eckit/geometry/grid/HEALPix.cc index f4266a307..8cf191b6c 100644 --- a/src/eckit/geometry/grid/HEALPix.cc +++ b/src/eckit/geometry/grid/HEALPix.cc @@ -121,6 +121,11 @@ size_t HEALPix::size() const { } +std::vector&& HEALPix::to_points() const { + NOTIMP; +} + + static const GridRegisterType __grid_type("healpix"); static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); diff --git a/src/eckit/geometry/grid/HEALPix.h b/src/eckit/geometry/grid/HEALPix.h index 42928fc71..60bac4a7b 100644 --- a/src/eckit/geometry/grid/HEALPix.h +++ b/src/eckit/geometry/grid/HEALPix.h @@ -89,14 +89,10 @@ class HEALPix final : public Grid { bool includesSouthPole() const override { return true; } bool isPeriodicWestEast() const override { return true; } - iterator begin() override { NOTIMP; } - iterator end() override { NOTIMP; } + iterator cbegin() const override { NOTIMP; } + iterator cend() const override { NOTIMP; } - const_iterator cbegin() const override { NOTIMP; } - const_iterator cend() const override { NOTIMP; } - - const_iterator begin() const override { NOTIMP; } - const_iterator end() const override { NOTIMP; } + std::vector&& to_points() const override; // -- Class members // None diff --git a/src/eckit/geometry/grid/IrregularLatlon.cc b/src/eckit/geometry/grid/IrregularLatlon.cc index 4db1259a0..02e38df1b 100644 --- a/src/eckit/geometry/grid/IrregularLatlon.cc +++ b/src/eckit/geometry/grid/IrregularLatlon.cc @@ -12,63 +12,63 @@ #include "eckit/geometry/grid/IrregularLatlon.h" -#include +#include -#include "eckit/utils/MD5.h" - -#include "eckit/geometry/Projection.h" +#include "eckit/geometry/area/BoundingBox.h" namespace eckit::geometry::grid { -static void range(const std::vector& v, double& mn, double& mx, double& dmax) { - ASSERT(v.size() >= 2); - - dmax = 0; - mx = v[0]; - mn = v[0]; +static void range(const std::vector& v, double& mn, double& mx) { + ASSERT(!v.empty()); + mx = v[0]; + mn = v[0]; for (size_t i = 1; i < v.size(); ++i) { - double d = std::abs(v[i] - v[i - 1]); - dmax = std::max(d, dmax); - mx = std::max(v[i], mx); - mn = std::min(v[i], mn); + mx = std::max(v[i], mx); + mn = std::min(v[i], mn); } } IrregularLatlon::IrregularLatlon(const Configuration& config) : Grid(config) { + double south = 0; + double north = 0; ASSERT(config.get("latitudes", latitudes_)); - range(latitudes_, south_, north_, south_north_); + range(latitudes_, south, north); + double west = 0; + double east = 0; ASSERT(config.get("longitudes", longitudes_)); - range(longitudes_, west_, east_, west_east_); + range(longitudes_, west, east); + + Grid::boundingBox({north, west, south, east}); } -size_t IrregularLatlon::size() const { - return latitudes_.size() * longitudes_.size(); +Grid::iterator IrregularLatlon::cbegin() const { + NOTIMP; } -bool IrregularLatlon::isPeriodicWestEast() const { - return (east_ - west_) + west_east_ >= GLOBE; +Grid::iterator IrregularLatlon::cend() const { + NOTIMP; } -bool IrregularLatlon::includesNorthPole() const { - return north_ + south_north_ >= NORTH_POLE; +size_t IrregularLatlon::size() const { + return latitudes_.size() * longitudes_.size(); } -bool IrregularLatlon::includesSouthPole() const { - return south_ - south_north_ <= SOUTH_POLE; +std::vector&& IrregularLatlon::to_points() const { + NOTIMP; } -// static const GridRegisterType irregularLatlon("irregular_latlon"); +static const GridRegisterType irregularLatlon("irregular_latlon"); } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/IrregularLatlon.h b/src/eckit/geometry/grid/IrregularLatlon.h index f02497e9e..8d0b3c5d3 100644 --- a/src/eckit/geometry/grid/IrregularLatlon.h +++ b/src/eckit/geometry/grid/IrregularLatlon.h @@ -25,7 +25,7 @@ class IrregularLatlon final : public Grid { // -- Constructors - IrregularLatlon(const Configuration&); + explicit IrregularLatlon(const Configuration&); // -- Destructor // None @@ -50,14 +50,6 @@ class IrregularLatlon final : public Grid { private: // -- Members - double south_; - double north_; - double south_north_; - - double west_; - double east_; - double west_east_; - std::vector latitudes_; std::vector longitudes_; @@ -66,10 +58,12 @@ class IrregularLatlon final : public Grid { // -- Overridden methods + iterator cbegin() const override; + iterator cend() const override; + size_t size() const override; - bool isPeriodicWestEast() const override; - bool includesNorthPole() const override; - bool includesSouthPole() const override; + + std::vector&& to_points() const override; // -- Class members // None diff --git a/src/eckit/geometry/grid/ReducedGG.cc b/src/eckit/geometry/grid/ReducedGG.cc index e49225481..8d1938890 100644 --- a/src/eckit/geometry/grid/ReducedGG.cc +++ b/src/eckit/geometry/grid/ReducedGG.cc @@ -160,6 +160,11 @@ size_t ReducedGG::size() const { } +std::vector&& ReducedGG::to_points() const { + NOTIMP; +} + + bool ReducedGG::isPeriodicWestEast() const { auto inc = smallest_increment(pl_); return bbox().east() - bbox().west() + inc >= GLOBE; diff --git a/src/eckit/geometry/grid/ReducedGG.h b/src/eckit/geometry/grid/ReducedGG.h index ab9f1a7c7..ae69602e8 100644 --- a/src/eckit/geometry/grid/ReducedGG.h +++ b/src/eckit/geometry/grid/ReducedGG.h @@ -85,6 +85,8 @@ class ReducedGG : public Gaussian { size_t size() const override; + std::vector&& to_points() const override; + // -- Class members // None diff --git a/src/eckit/geometry/grid/ReducedLL.cc b/src/eckit/geometry/grid/ReducedLL.cc index 13e21b352..e4c4dd2b5 100644 --- a/src/eckit/geometry/grid/ReducedLL.cc +++ b/src/eckit/geometry/grid/ReducedLL.cc @@ -24,11 +24,13 @@ namespace eckit::geometry::grid { + static bool checkPl(const std::vector& pl) { ASSERT(!pl.empty()); return *std::min_element(pl.begin(), pl.end()) >= 2; } + ReducedLL::ReducedLL(const Configuration& config) : Grid(config) { ASSERT(config.get("pl", pl_)); @@ -39,8 +41,10 @@ ReducedLL::ReducedLL(const Configuration& config) : ASSERT(Nj == pl_.size()); } + ReducedLL::~ReducedLL() = default; + size_t ReducedLL::size() const { size_t total = 0; for (const auto& j : pl_) { @@ -49,6 +53,7 @@ size_t ReducedLL::size() const { return total; } + bool ReducedLL::isPeriodicWestEast() const { ASSERT(!pl_.empty()); @@ -60,14 +65,22 @@ bool ReducedLL::isPeriodicWestEast() const { return bbox().east() - bbox().west() + inc >= GLOBE; } + bool ReducedLL::includesNorthPole() const { return bbox().north() == NORTH_POLE; } + bool ReducedLL::includesSouthPole() const { return bbox().south() == SOUTH_POLE; } + +std::vector&& ReducedLL::to_points() const { + NOTIMP; +} + + static const GridRegisterType reducedLL("reduced_ll"); diff --git a/src/eckit/geometry/grid/ReducedLL.h b/src/eckit/geometry/grid/ReducedLL.h index 2d23a7673..88f2ac357 100644 --- a/src/eckit/geometry/grid/ReducedLL.h +++ b/src/eckit/geometry/grid/ReducedLL.h @@ -65,14 +65,10 @@ class ReducedLL : public Grid { bool includesNorthPole() const override; bool includesSouthPole() const override; - iterator begin() override { NOTIMP; } - iterator end() override { NOTIMP; } + iterator cbegin() const override { NOTIMP; } + iterator cend() const override { NOTIMP; } - const_iterator cbegin() const override { NOTIMP; } - const_iterator cend() const override { NOTIMP; } - - const_iterator begin() const override { NOTIMP; } - const_iterator end() const override { NOTIMP; } + std::vector&& to_points() const override; // -- Class members // None diff --git a/src/eckit/geometry/grid/RegularGG.cc b/src/eckit/geometry/grid/RegularGG.cc index d456e145d..71054bccd 100644 --- a/src/eckit/geometry/grid/RegularGG.cc +++ b/src/eckit/geometry/grid/RegularGG.cc @@ -121,6 +121,11 @@ bool RegularGG::isPeriodicWestEast() const { } +std::vector&& RegularGG::to_points() const { + NOTIMP; +} + + void RegularGG::setNiNj() { ASSERT(N_); diff --git a/src/eckit/geometry/grid/RegularGG.h b/src/eckit/geometry/grid/RegularGG.h index 6c8f64d96..86dea6569 100644 --- a/src/eckit/geometry/grid/RegularGG.h +++ b/src/eckit/geometry/grid/RegularGG.h @@ -74,6 +74,8 @@ class RegularGG final : public Gaussian { bool isPeriodicWestEast() const override; + std::vector&& to_points() const override; + // -- Class members // None diff --git a/src/eckit/geometry/grid/RegularLL.cc b/src/eckit/geometry/grid/RegularLL.cc index e1ab8e2ec..56a797082 100644 --- a/src/eckit/geometry/grid/RegularLL.cc +++ b/src/eckit/geometry/grid/RegularLL.cc @@ -164,6 +164,11 @@ size_t RegularLL::size() const { } +std::vector&& RegularLL::to_points() const { + NOTIMP; +} + + area::BoundingBox RegularLL::correctBoundingBox(const area::BoundingBox& box, size_t& ni, size_t& nj, const Increments& inc, const PointLonLat& reference) { // Latitude/longitude ranges diff --git a/src/eckit/geometry/grid/RegularLL.h b/src/eckit/geometry/grid/RegularLL.h index 8de7aa460..2e880b6da 100644 --- a/src/eckit/geometry/grid/RegularLL.h +++ b/src/eckit/geometry/grid/RegularLL.h @@ -14,7 +14,6 @@ #include "eckit/geometry/Grid.h" #include "eckit/geometry/Increments.h" -#include "eckit/types/Fraction.h" namespace eckit::geometry::grid { @@ -27,8 +26,8 @@ class RegularLL : public Grid { // -- Constructors - RegularLL(const Configuration&); - RegularLL(const Increments&, const area::BoundingBox& = {}, const PointLonLat& reference = {0, 0}); + explicit RegularLL(const Configuration&); + explicit RegularLL(const Increments&, const area::BoundingBox& = {}, const PointLonLat& reference = {0, 0}); // -- Destructor // None @@ -68,20 +67,17 @@ class RegularLL : public Grid { // -- Overridden methods - iterator begin() override { NOTIMP; } - iterator end() override { NOTIMP; } - - const_iterator cbegin() const override { NOTIMP; } - const_iterator cend() const override { NOTIMP; } - - const_iterator begin() const override { NOTIMP; } - const_iterator end() const override { NOTIMP; } + iterator cbegin() const override { NOTIMP; } + iterator cend() const override { NOTIMP; } bool isPeriodicWestEast() const override; bool includesNorthPole() const override; bool includesSouthPole() const override; + size_t size() const override; + std::vector&& to_points() const override; + // -- Class members // None diff --git a/src/eckit/geometry/grid/UnstructuredGrid.cc b/src/eckit/geometry/grid/UnstructuredGrid.cc index cb28769d9..0eada435b 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.cc +++ b/src/eckit/geometry/grid/UnstructuredGrid.cc @@ -34,143 +34,21 @@ namespace eckit::geometry::grid { -namespace detail { +static const area::BoundingBox __global; -#if 0 -class UnstructuredIterator : public Iterator { -public: - // -- Exceptions - // None - - // -- Constructors - UnstructuredIterator(const std::vector& latitudes, const std::vector& longitudes) : - count_(0), size_(latitudes.size()), latitudes_(latitudes), longitudes_(longitudes), first_(true) { - ASSERT(latitudes_.size() == longitudes_.size()); - } - - UnstructuredIterator(const UnstructuredIterator&) = delete; - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - - UnstructuredIterator& operator=(const UnstructuredIterator&) = delete; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - size_t count_; - const size_t size_; - const std::vector& latitudes_; - const std::vector& longitudes_; - bool first_; - - // -- Methods - // None - - // -- Overridden methods - - // From Iterator - - bool operator++() override { - if ((first_ ? count_ : ++count_) < size_) { - first_ = false; - // lat = latitudes_[count_]; - // lon = longitudes_[count_]; - - return true; - } - return false; - } - - size_t index() const override { return count_; } - - size_t size() const override { NOTIMP; } - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; -#endif - - -} // namespace detail - - -UnstructuredGrid::UnstructuredGrid(const Configuration& config) : - Grid(config) { - config.get("latitudes", latitudes_); - config.get("longitudes", longitudes_); - - if (latitudes_.empty() || longitudes_.empty()) { - throw UserError("UnstructuredGrid: requires 'latitudes' and 'longitudes'"); - } - ASSERT(latitudes_.size() == longitudes_.size()); +UnstructuredGrid::UnstructuredGrid(std::vector&& points) : + Grid(__global), points_(points) { } -#if 0 -UnstructuredGrid::UnstructuredGrid(const PathName& path) { - std::ifstream in(path.asString().c_str()); - if (!in) { - throw CantOpenFile(path); - } - - if (::isprint(in.peek()) == 0) { - IfstreamStream s(in); - size_t version; - s >> version; - ASSERT(version == 1); - - size_t count; - s >> count; - - latitudes_.resize(count); - longitudes_.resize(count); - - for (size_t i = 0; i < count; ++i) { - s >> latitudes_[i]; - s >> longitudes_[i]; - } - } - else { - double lat; - double lon; - while (in >> lat >> lon) { - latitudes_.push_back(lat); - longitudes_.push_back(lon); - } - } +Grid::iterator UnstructuredGrid::cbegin() const { + NOTIMP; } -#endif -UnstructuredGrid::UnstructuredGrid(const std::vector& latitudes, const std::vector& longitudes, - const area::BoundingBox& bbox) : - Grid(bbox), latitudes_(latitudes), longitudes_(longitudes) { - ASSERT(latitudes_.size() == longitudes_.size()); +Grid::iterator UnstructuredGrid::cend() const { + NOTIMP; } @@ -178,27 +56,10 @@ UnstructuredGrid::~UnstructuredGrid() = default; size_t UnstructuredGrid::size() const { - ASSERT(latitudes_.size() == longitudes_.size()); - return latitudes_.size(); -} - - -bool UnstructuredGrid::isPeriodicWestEast() const { - return bbox().east() - bbox().west() == GLOBE; -} - - -bool UnstructuredGrid::includesNorthPole() const { - return bbox().north() == NORTH_POLE; -} - - -bool UnstructuredGrid::includesSouthPole() const { - return bbox().south() == SOUTH_POLE; + return points_.size(); } -// static const GridRegisterType triangular_grid("triangular_grid"); // static const GridRegisterType unstructured_grid("unstructured_grid"); diff --git a/src/eckit/geometry/grid/UnstructuredGrid.h b/src/eckit/geometry/grid/UnstructuredGrid.h index 8742e51ac..c48b1bc90 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.h +++ b/src/eckit/geometry/grid/UnstructuredGrid.h @@ -17,11 +17,6 @@ #include "eckit/geometry/Grid.h" -namespace eckit { -class PathName; -} - - namespace eckit::geometry::grid { @@ -32,13 +27,7 @@ class UnstructuredGrid : public Grid { // -- Constructors - explicit UnstructuredGrid(const PathName&); - explicit UnstructuredGrid(const Configuration&); - UnstructuredGrid(const std::vector& latitudes, const std::vector& longitudes, - const area::BoundingBox& = {}); - - UnstructuredGrid(const UnstructuredGrid&) = delete; - UnstructuredGrid(UnstructuredGrid&&) = delete; + explicit UnstructuredGrid(std::vector&&); // -- Destructor @@ -48,24 +37,6 @@ class UnstructuredGrid : public Grid { // None // -- Operators - - void operator=(const UnstructuredGrid&) = delete; - void operator=(const UnstructuredGrid&&) = delete; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members // None // -- Methods @@ -83,19 +54,19 @@ class UnstructuredGrid : public Grid { private: // -- Members - std::vector latitudes_; - std::vector longitudes_; + std::vector points_; // -- Methods // None // -- Overridden methods - // None - // Domain operations - bool isPeriodicWestEast() const override; - bool includesNorthPole() const override; - bool includesSouthPole() const override; + iterator cbegin() const override; + iterator cend() const override; + + bool isPeriodicWestEast() const override { return true; } + bool includesNorthPole() const override { return true; } + bool includesSouthPole() const override { return true; } size_t size() const override; diff --git a/src/eckit/geometry/iterator/ListI.cc b/src/eckit/geometry/iterator/ListI.cc index 415e218b6..5f86f4325 100644 --- a/src/eckit/geometry/iterator/ListI.cc +++ b/src/eckit/geometry/iterator/ListI.cc @@ -12,8 +12,6 @@ #include "eckit/geometry/iterator/ListI.h" -#include - #include "eckit/geometry/Grid.h" @@ -23,7 +21,8 @@ namespace eckit::geometry::iterator { ListI::ListI(const Grid& grid) : Iterator(grid), points_(grid.to_points()), - index_(0) { + index_(0), + first_(true) { } @@ -34,7 +33,12 @@ bool ListI::operator==(const Iterator& other) { bool ListI::operator++() { - ++index_; + if (first_) { + first_ = false; + } + else { + index_++; + } return operator bool(); } diff --git a/src/eckit/geometry/iterator/ListI.h b/src/eckit/geometry/iterator/ListI.h index 80d3bf8d4..aceee10e2 100644 --- a/src/eckit/geometry/iterator/ListI.h +++ b/src/eckit/geometry/iterator/ListI.h @@ -56,6 +56,7 @@ class ListI final : public Iterator { const std::vector& points_; size_t index_; + bool first_; // -- Methods // None From e8760e973ee4f856b2ee02211cb126146fa24696 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 23 Aug 2023 12:40:30 +0100 Subject: [PATCH 284/737] Geoiterator: error handling --- src/grib_iterator_class_lambert_conformal.cc | 10 +++---- ...grib_iterator_class_polar_stereographic.cc | 6 ++-- src/grib_iterator_class_space_view.cc | 30 ++++++++++--------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.cc b/src/grib_iterator_class_lambert_conformal.cc index cf0000953..3e9d51055 100644 --- a/src/grib_iterator_class_lambert_conformal.cc +++ b/src/grib_iterator_class_lambert_conformal.cc @@ -204,12 +204,12 @@ static int init_sphere(grib_handle* h, /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } @@ -315,12 +315,12 @@ static int init_oblate(grib_handle* h, /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } @@ -414,7 +414,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%ld!=%ldx%ld)", ITER, iter->nv, nx, ny); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, ny); return GRIB_WRONG_GRID; } diff --git a/src/grib_iterator_class_polar_stereographic.cc b/src/grib_iterator_class_polar_stereographic.cc index 753649141..b9c0314a3 100644 --- a/src/grib_iterator_class_polar_stereographic.cc +++ b/src/grib_iterator_class_polar_stereographic.cc @@ -164,7 +164,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return ret; if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%ld!=%ldx%ld)", ITER, iter->nv, nx, ny); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, ny); return GRIB_WRONG_GRID; } if ((ret = grib_get_double_internal(h, s_latFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) @@ -244,12 +244,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, iter->nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %ld bytes", ITER, iter->nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, iter->nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } lats = self->lats; diff --git a/src/grib_iterator_class_space_view.cc b/src/grib_iterator_class_space_view.cc index c2e402e59..1622f94a5 100644 --- a/src/grib_iterator_class_space_view.cc +++ b/src/grib_iterator_class_space_view.cc @@ -81,6 +81,8 @@ static void init_class(grib_iterator_class* c) } /* END_CLASS_IMP */ +#define ITER "Space view Geoiterator" + static int next(grib_iterator* iter, double* lat, double* lon, double* val) { grib_iterator_space_view* self = (grib_iterator_space_view*)iter; @@ -178,7 +180,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) const char* sXpInGridLengths = grib_arguments_get_name(h, args, self->carg++); const char* sYpInGridLengths = grib_arguments_get_name(h, args, self->carg++); const char* sOrientationInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sNrInRadiusOfEarth = grib_arguments_get_name(h, args, self->carg++); + const char* sNrInRadiusOfEarthScaled = grib_arguments_get_name(h, args, self->carg++); const char* sXo = grib_arguments_get_name(h, args, self->carg++); const char* sYo = grib_arguments_get_name(h, args, self->carg++); @@ -206,7 +208,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Wrong number of points (%ld!=%ldx%ld)", iter->nv, nx, ny); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, ny); return GRIB_WRONG_GRID; } if ((ret = grib_get_double_internal(h, sLatOfSubSatellitePointInDegrees, &latOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) @@ -225,11 +227,11 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return ret; /* Orthographic not supported. This happens when Nr (camera altitude) is missing */ - if (grib_is_missing(h, sNrInRadiusOfEarth, &ret)) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Space View: Orthographic view (Nr missing) not supported"); - return GRIB_NOT_IMPLEMENTED; + if (grib_is_missing(h, "Nr", &ret)) { + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Orthographic view (Nr missing) not supported", ITER); + return GRIB_GEOCALCULUS_PROBLEM; } - if ((ret = grib_get_double_internal(h, sNrInRadiusOfEarth, &nrInRadiusOfEarth)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sNrInRadiusOfEarthScaled, &nrInRadiusOfEarth)) != GRIB_SUCCESS) return ret; if ((ret = grib_get_long_internal(h, sXo, &Xo)) != GRIB_SUCCESS) @@ -254,7 +256,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } if (nrInRadiusOfEarth == 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Space View: Key %s must be greater than zero", sNrInRadiusOfEarth); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Key %s must be greater than zero", ITER, sNrInRadiusOfEarthScaled); return GRIB_GEOCALCULUS_PROBLEM; } @@ -265,8 +267,8 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) lop = lonOfSubSatellitePointInDegrees; if (lap != 0.0) { grib_context_log(h->context, GRIB_LOG_ERROR, - "Space View: Key '%s' must be 0 (satellite must be located in the equator plane)", - sLatOfSubSatellitePointInDegrees); + "%s: Key %s must be 0 (satellite must be located in the equator plane)", + ITER, sLatOfSubSatellitePointInDegrees); return GRIB_GEOCALCULUS_PROBLEM; } @@ -280,7 +282,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) /* adjustBadlyEncodedEcmwfGribs(h, &nx, &ny, &dx, &dy, &xp, &yp); */ if (dx == 0 || dy == 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Space View: Keys %s and %s must be greater than zero", sDx, sDy); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Keys %s and %s must be greater than zero", ITER, sDx, sDy); return GRIB_GEOCALCULUS_PROBLEM; } rx = angular_size / dx; @@ -288,12 +290,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) self->lats = (double*)grib_context_malloc(h->context, array_size); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", array_size); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, array_size); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, array_size); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", array_size); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, array_size); return GRIB_OUT_OF_MEMORY; } lats = self->lats; @@ -318,12 +320,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) /* Store array of sin and cosine values to avoid recalculation */ s_x = (double*)grib_context_malloc(h->context, nx * sizeof(double)); if (!s_x) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nx * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nx * sizeof(double)); return GRIB_OUT_OF_MEMORY; } c_x = (double*)grib_context_malloc(h->context, nx * sizeof(double)); if (!c_x) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nx * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nx * sizeof(double)); return GRIB_OUT_OF_MEMORY; } From 0091849b5952599cf77154c9bcef43ef7167ffe1 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 20 Sep 2023 12:19:27 +0100 Subject: [PATCH 285/737] Add better error/debug messages --- ...terator_class_lambert_azimuthal_equal_area.cc | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.cc b/src/grib_iterator_class_lambert_azimuthal_equal_area.cc index f9b76d702..a945ee1d2 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.cc +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.cc @@ -81,6 +81,8 @@ static void init_class(grib_iterator_class* c) } /* END_CLASS_IMP */ +#define ITER "Lambert azimuthal equal area Geoiterator" + static int next(grib_iterator* iter, double* lat, double* lon, double* val) { grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)iter; @@ -227,12 +229,12 @@ static int init_oblate(grib_handle* h, /* Allocate latitude and longitude arrays */ self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Error allocating %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } lats = self->lats; @@ -308,14 +310,12 @@ static int init_sphere(grib_handle* h, Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "Error allocating %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "Error allocating %ld bytes", nv * sizeof(double)); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } lats = self->lats; @@ -435,9 +435,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return err; if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "Wrong number of points (%ld!=%ldx%ld)", - iter->nv, nx, ny); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, ny); return GRIB_WRONG_GRID; } if ((err = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) From 4f66a09f5f49b1d9851927fc8e864f5faff80ae2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 15 Aug 2023 01:59:51 +0100 Subject: [PATCH 286/737] eckit::geometry --- src/eckit/geometry/Area.h | 3 +- src/eckit/geometry/Grid.cc | 2 +- src/eckit/geometry/Grid.h | 8 ++-- src/eckit/geometry/Increments.h | 3 +- src/eckit/geometry/area/BoundingBox.h | 20 ++++---- src/eckit/geometry/grid/HEALPix.cc | 2 +- src/eckit/geometry/grid/HEALPix.h | 2 +- src/eckit/geometry/grid/IrregularLatlon.cc | 2 +- src/eckit/geometry/grid/IrregularLatlon.h | 2 +- src/eckit/geometry/grid/ReducedGG.cc | 2 +- src/eckit/geometry/grid/ReducedGG.h | 2 +- src/eckit/geometry/grid/ReducedLL.cc | 2 +- src/eckit/geometry/grid/ReducedLL.h | 2 +- src/eckit/geometry/grid/RegularGG.cc | 2 +- src/eckit/geometry/grid/RegularGG.h | 2 +- src/eckit/geometry/grid/RegularLL.cc | 28 +++++++++-- src/eckit/geometry/grid/RegularLL.h | 2 +- src/eckit/geometry/grid/UnstructuredGrid.cc | 51 +++++++++++++++------ src/eckit/geometry/grid/UnstructuredGrid.h | 15 +++++- src/eckit/geometry/iterator/ListI.cc | 7 +-- src/eckit/geometry/iterator/ListI.h | 4 +- 21 files changed, 108 insertions(+), 55 deletions(-) diff --git a/src/eckit/geometry/Area.h b/src/eckit/geometry/Area.h index 359b3e9b4..aa128c18c 100644 --- a/src/eckit/geometry/Area.h +++ b/src/eckit/geometry/Area.h @@ -56,8 +56,7 @@ class Area { Area& operator=(Area&&) = default; // -- Methods - - virtual area::BoundingBox bbox() const = 0; + // None // -- Overridden methods // None diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 162bcb52d..9571c574a 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -66,7 +66,7 @@ bool Grid::isPeriodicWestEast() const { } -std::vector&& Grid::to_points() const { +std::vector Grid::to_points() const { throw NotImplemented("Grid::to_points", Here()); } diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index b8dc90449..b95ca1c04 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -36,7 +36,7 @@ class Grid { struct Iterator final : std::unique_ptr { explicit Iterator(geometry::Iterator* it) : - unique_ptr(it) { ASSERT(operator bool()); } + unique_ptr(it) { ASSERT(unique_ptr::operator bool()); } Iterator(const Iterator&) = delete; Iterator(Iterator&&) = delete; @@ -51,8 +51,8 @@ class Grid { bool operator++() { return get()->operator++(); } bool operator--() { return get()->operator--(); } - explicit operator bool() { return get()->operator bool(); } - const Point& operator*() { return get()->operator*(); } + explicit operator bool() const { return get()->operator bool(); } + const Point& operator*() const { return get()->operator*(); } size_t size() const { return get()->size(); } size_t index() const { return get()->index(); } @@ -100,7 +100,7 @@ class Grid { virtual bool includesSouthPole() const; virtual bool isPeriodicWestEast() const; - virtual std::vector&& to_points() const = 0; + virtual std::vector to_points() const; // -- Overridden methods // None diff --git a/src/eckit/geometry/Increments.h b/src/eckit/geometry/Increments.h index 7df79bbfa..e4975cf18 100644 --- a/src/eckit/geometry/Increments.h +++ b/src/eckit/geometry/Increments.h @@ -58,7 +58,8 @@ class Increments : protected std::array { double& south_north = P::operator[](1); // -- Methods - // None + + std::array deconstruct() const { return {west_east, south_north}; } // -- Overridden methods // None diff --git a/src/eckit/geometry/area/BoundingBox.h b/src/eckit/geometry/area/BoundingBox.h index a0ab33cde..3609c2ed7 100644 --- a/src/eckit/geometry/area/BoundingBox.h +++ b/src/eckit/geometry/area/BoundingBox.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include "eckit/geometry/Area.h" @@ -27,7 +27,7 @@ class Projection; namespace eckit::geometry::area { -class BoundingBox : public Area { +class BoundingBox : public Area, protected std::array { public: // -- Exceptions // None @@ -39,26 +39,20 @@ class BoundingBox : public Area { BoundingBox(double north, double west, double south, double east); BoundingBox(); - BoundingBox(const BoundingBox&) = default; - BoundingBox(BoundingBox&&) = default; - // -- Destructor - - virtual ~BoundingBox() = default; + // None // -- Convertors // None // -- Operators - BoundingBox& operator=(const BoundingBox&) = default; - BoundingBox& operator=(BoundingBox&&) = default; bool operator==(const BoundingBox&) const; bool operator!=(const BoundingBox& other) const { return !operator==(other); } // -- Methods - std::tuple deconstruct() const { return {north_, west_, south_, east_}; } + std::array deconstruct() const { return {north_, west_, south_, east_}; } double north() const { return north_; } double west() const { return west_; } @@ -76,9 +70,11 @@ class BoundingBox : public Area { static BoundingBox make(const BoundingBox&, const Projection&); - // -- Overridden methods + static BoundingBox make_global_prime() { return {90., 0., -90., 360.}; } + static BoundingBox make_global_antiprime() { return {90., -180., -90., 180.}; } - area::BoundingBox bbox() const override { return *this; } + // -- Overridden methods + // None // -- Class members // None diff --git a/src/eckit/geometry/grid/HEALPix.cc b/src/eckit/geometry/grid/HEALPix.cc index 8cf191b6c..ad8fdc4a1 100644 --- a/src/eckit/geometry/grid/HEALPix.cc +++ b/src/eckit/geometry/grid/HEALPix.cc @@ -121,7 +121,7 @@ size_t HEALPix::size() const { } -std::vector&& HEALPix::to_points() const { +std::vector HEALPix::to_points() const { NOTIMP; } diff --git a/src/eckit/geometry/grid/HEALPix.h b/src/eckit/geometry/grid/HEALPix.h index 60bac4a7b..1d6157b60 100644 --- a/src/eckit/geometry/grid/HEALPix.h +++ b/src/eckit/geometry/grid/HEALPix.h @@ -92,7 +92,7 @@ class HEALPix final : public Grid { iterator cbegin() const override { NOTIMP; } iterator cend() const override { NOTIMP; } - std::vector&& to_points() const override; + std::vector to_points() const override; // -- Class members // None diff --git a/src/eckit/geometry/grid/IrregularLatlon.cc b/src/eckit/geometry/grid/IrregularLatlon.cc index 02e38df1b..92f7e0886 100644 --- a/src/eckit/geometry/grid/IrregularLatlon.cc +++ b/src/eckit/geometry/grid/IrregularLatlon.cc @@ -63,7 +63,7 @@ size_t IrregularLatlon::size() const { } -std::vector&& IrregularLatlon::to_points() const { +std::vector IrregularLatlon::to_points() const { NOTIMP; } diff --git a/src/eckit/geometry/grid/IrregularLatlon.h b/src/eckit/geometry/grid/IrregularLatlon.h index 8d0b3c5d3..fa3682215 100644 --- a/src/eckit/geometry/grid/IrregularLatlon.h +++ b/src/eckit/geometry/grid/IrregularLatlon.h @@ -63,7 +63,7 @@ class IrregularLatlon final : public Grid { size_t size() const override; - std::vector&& to_points() const override; + std::vector to_points() const override; // -- Class members // None diff --git a/src/eckit/geometry/grid/ReducedGG.cc b/src/eckit/geometry/grid/ReducedGG.cc index 8d1938890..82987fe6c 100644 --- a/src/eckit/geometry/grid/ReducedGG.cc +++ b/src/eckit/geometry/grid/ReducedGG.cc @@ -160,7 +160,7 @@ size_t ReducedGG::size() const { } -std::vector&& ReducedGG::to_points() const { +std::vector ReducedGG::to_points() const { NOTIMP; } diff --git a/src/eckit/geometry/grid/ReducedGG.h b/src/eckit/geometry/grid/ReducedGG.h index ae69602e8..b6e9169ba 100644 --- a/src/eckit/geometry/grid/ReducedGG.h +++ b/src/eckit/geometry/grid/ReducedGG.h @@ -85,7 +85,7 @@ class ReducedGG : public Gaussian { size_t size() const override; - std::vector&& to_points() const override; + std::vector to_points() const override; // -- Class members // None diff --git a/src/eckit/geometry/grid/ReducedLL.cc b/src/eckit/geometry/grid/ReducedLL.cc index e4c4dd2b5..51329359d 100644 --- a/src/eckit/geometry/grid/ReducedLL.cc +++ b/src/eckit/geometry/grid/ReducedLL.cc @@ -76,7 +76,7 @@ bool ReducedLL::includesSouthPole() const { } -std::vector&& ReducedLL::to_points() const { +std::vector ReducedLL::to_points() const { NOTIMP; } diff --git a/src/eckit/geometry/grid/ReducedLL.h b/src/eckit/geometry/grid/ReducedLL.h index 88f2ac357..c7e3e943c 100644 --- a/src/eckit/geometry/grid/ReducedLL.h +++ b/src/eckit/geometry/grid/ReducedLL.h @@ -68,7 +68,7 @@ class ReducedLL : public Grid { iterator cbegin() const override { NOTIMP; } iterator cend() const override { NOTIMP; } - std::vector&& to_points() const override; + std::vector to_points() const override; // -- Class members // None diff --git a/src/eckit/geometry/grid/RegularGG.cc b/src/eckit/geometry/grid/RegularGG.cc index 71054bccd..89c8976b9 100644 --- a/src/eckit/geometry/grid/RegularGG.cc +++ b/src/eckit/geometry/grid/RegularGG.cc @@ -121,7 +121,7 @@ bool RegularGG::isPeriodicWestEast() const { } -std::vector&& RegularGG::to_points() const { +std::vector RegularGG::to_points() const { NOTIMP; } diff --git a/src/eckit/geometry/grid/RegularGG.h b/src/eckit/geometry/grid/RegularGG.h index 86dea6569..b36f2f167 100644 --- a/src/eckit/geometry/grid/RegularGG.h +++ b/src/eckit/geometry/grid/RegularGG.h @@ -74,7 +74,7 @@ class RegularGG final : public Gaussian { bool isPeriodicWestEast() const override; - std::vector&& to_points() const override; + std::vector to_points() const override; // -- Class members // None diff --git a/src/eckit/geometry/grid/RegularLL.cc b/src/eckit/geometry/grid/RegularLL.cc index 56a797082..7c92e6151 100644 --- a/src/eckit/geometry/grid/RegularLL.cc +++ b/src/eckit/geometry/grid/RegularLL.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "eckit/config/MappedConfiguration.h" @@ -22,6 +23,7 @@ #include "eckit/geometry/Point.h" #include "eckit/geometry/Projection.h" #include "eckit/geometry/grid/RegularLL.h" +#include "eckit/geometry/util.h" #include "eckit/geometry/util/regex.h" #include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" @@ -158,14 +160,32 @@ bool RegularLL::includesSouthPole() const { size_t RegularLL::size() const { - ASSERT(ni_); - ASSERT(nj_); + ASSERT(0 < ni_); + ASSERT(0 < nj_); return ni_ * nj_; } -std::vector&& RegularLL::to_points() const { - NOTIMP; +std::vector RegularLL::to_points() const { + auto [n, w, s, e] = bbox().deconstruct(); + auto [we, sn] = increments_.deconstruct(); + + auto longitudes = util::arange(w, e, we); + ASSERT(longitudes.size() == ni_); + + auto latitudes = util::arange(n, s, -sn); + ASSERT(latitudes.size() == nj_); + + std::vector points; + points.reserve(size()); + + for (const auto lat : latitudes) { + for (const auto lon : longitudes) { + points.emplace_back(PointLonLat{lon, lat}); + } + } + + return points; } diff --git a/src/eckit/geometry/grid/RegularLL.h b/src/eckit/geometry/grid/RegularLL.h index 2e880b6da..db067c633 100644 --- a/src/eckit/geometry/grid/RegularLL.h +++ b/src/eckit/geometry/grid/RegularLL.h @@ -76,7 +76,7 @@ class RegularLL : public Grid { size_t size() const override; - std::vector&& to_points() const override; + std::vector to_points() const override; // -- Class members // None diff --git a/src/eckit/geometry/grid/UnstructuredGrid.cc b/src/eckit/geometry/grid/UnstructuredGrid.cc index 0eada435b..4b1483826 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.cc +++ b/src/eckit/geometry/grid/UnstructuredGrid.cc @@ -19,16 +19,7 @@ #include #include "eckit/exception/Exceptions.h" - -#if 0 -#include "eckit/config/Resource.h" -#include "eckit/filesystem/PathName.h" -#include "eckit/geometry/Domain.h" -#include "eckit/geometry/Iterator.h" -#include "eckit/geometry/Projection.h" -#include "eckit/serialisation/FileStream.h" -#include "eckit/serialisation/IfstreamStream.h" -#endif +#include "eckit/geometry/iterator/ListI.h" namespace eckit::geometry::grid { @@ -37,18 +28,47 @@ namespace eckit::geometry::grid { static const area::BoundingBox __global; +static std::vector lonlat_to_points(const std::vector lons, const std::vector lats) { + auto N = lats.size(); + ASSERT(N == lons.size()); + + std::vector points; + points.reserve(N); + + for (auto lon = lons.begin(), lat = lats.begin(); lon != lons.end(); ++lon, ++lat) { + points.emplace_back(PointLonLat{*lon, *lat}); + } + + return points; +} + + +UnstructuredGrid::UnstructuredGrid(const Configuration& config) : + UnstructuredGrid(config.getDoubleVector("longitudes"), config.getDoubleVector("latitudes")) { +} + + +UnstructuredGrid::UnstructuredGrid(const Grid& grid) : + UnstructuredGrid(grid.to_points()) {} + + UnstructuredGrid::UnstructuredGrid(std::vector&& points) : Grid(__global), points_(points) { } +UnstructuredGrid::UnstructuredGrid(const std::vector& longitudes, const std::vector& latitudes) : + Grid(__global), points_(lonlat_to_points(longitudes, latitudes)) { +} + + Grid::iterator UnstructuredGrid::cbegin() const { - NOTIMP; + return iterator{new geometry::iterator::ListI(*this)}; } Grid::iterator UnstructuredGrid::cend() const { - NOTIMP; + return iterator{new geometry::iterator::ListI(*this, size())}; } @@ -60,7 +80,12 @@ size_t UnstructuredGrid::size() const { } -// static const GridRegisterType unstructured_grid("unstructured_grid"); +std::vector UnstructuredGrid::to_points() const { + return points_; +} + + +static const GridRegisterType unstructured_grid("unstructured_grid"); } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/UnstructuredGrid.h b/src/eckit/geometry/grid/UnstructuredGrid.h index c48b1bc90..807a28c7d 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.h +++ b/src/eckit/geometry/grid/UnstructuredGrid.h @@ -17,6 +17,11 @@ #include "eckit/geometry/Grid.h" +namespace eckit::geometry::iterator { +class ListI; +} + + namespace eckit::geometry::grid { @@ -27,7 +32,10 @@ class UnstructuredGrid : public Grid { // -- Constructors + explicit UnstructuredGrid(const Configuration&); + explicit UnstructuredGrid(const Grid&); explicit UnstructuredGrid(std::vector&&); + UnstructuredGrid(const std::vector& longitudes, const std::vector& latitudes); // -- Destructor @@ -64,11 +72,13 @@ class UnstructuredGrid : public Grid { iterator cbegin() const override; iterator cend() const override; + size_t size() const override; + bool isPeriodicWestEast() const override { return true; } bool includesNorthPole() const override { return true; } bool includesSouthPole() const override { return true; } - size_t size() const override; + std::vector to_points() const override; // -- Class members // None @@ -77,7 +87,8 @@ class UnstructuredGrid : public Grid { // None // -- Friends - // None + + friend class geometry::iterator::ListI; }; diff --git a/src/eckit/geometry/iterator/ListI.cc b/src/eckit/geometry/iterator/ListI.cc index 5f86f4325..26cc4966b 100644 --- a/src/eckit/geometry/iterator/ListI.cc +++ b/src/eckit/geometry/iterator/ListI.cc @@ -13,15 +13,16 @@ #include "eckit/geometry/iterator/ListI.h" #include "eckit/geometry/Grid.h" +#include "eckit/geometry/grid/UnstructuredGrid.h" namespace eckit::geometry::iterator { -ListI::ListI(const Grid& grid) : +ListI::ListI(const Grid& grid, size_t index) : Iterator(grid), - points_(grid.to_points()), - index_(0), + index_(index), + points_(dynamic_cast(grid).points_), first_(true) { } diff --git a/src/eckit/geometry/iterator/ListI.h b/src/eckit/geometry/iterator/ListI.h index aceee10e2..5c299c247 100644 --- a/src/eckit/geometry/iterator/ListI.h +++ b/src/eckit/geometry/iterator/ListI.h @@ -28,7 +28,7 @@ class ListI final : public Iterator { // -- Constructors - explicit ListI(const Grid&); + explicit ListI(const Grid&, size_t index = 0); // -- Destructor // None @@ -54,8 +54,8 @@ class ListI final : public Iterator { private: // -- Members - const std::vector& points_; size_t index_; + const std::vector& points_; bool first_; // -- Methods From 864cd8990a10fef89b3a4cc037ef5444b30f2d83 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 15 Aug 2023 09:54:55 +0100 Subject: [PATCH 287/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 24 +++++++++++++++++++ src/eckit/geometry/Grid.h | 4 ++++ src/eckit/geometry/Search.h | 48 +++++++++++++++++++++++-------------- 3 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 9571c574a..560f026d6 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -71,6 +71,30 @@ std::vector Grid::to_points() const { } +SearchLonLat::Result Grid::nearest(const PointLonLat& p) const { + SearchLonLat search; + + size_t index = 0; + for (const auto& p : to_points()) { + search.insert({std::get(p), index}); + } + + return search.nearestNeighbour(p); +} + + +SearchLonLat::Results Grid::nearest(const PointLonLat& p, size_t k) const { + SearchLonLat search; + + size_t index = 0; + for (const auto& p : to_points()) { + search.insert({std::get(p), index}); + } + + return search.kNearestNeighbours(p, k); +} + + static pthread_once_t __once; static Mutex* __mutex = nullptr; diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index b95ca1c04..ede011a38 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -24,6 +24,7 @@ #include "eckit/geometry/Point.h" #include "eckit/geometry/Projection.h" #include "eckit/geometry/Renumber.h" +#include "eckit/geometry/Search.h" #include "eckit/geometry/area/BoundingBox.h" @@ -102,6 +103,9 @@ class Grid { virtual std::vector to_points() const; + virtual SearchLonLat::Result nearest(const PointLonLat&) const; + virtual SearchLonLat::Results nearest(const PointLonLat&, size_t k) const; + // -- Overridden methods // None diff --git a/src/eckit/geometry/Search.h b/src/eckit/geometry/Search.h index 31f7cc9af..bec4ca509 100644 --- a/src/eckit/geometry/Search.h +++ b/src/eckit/geometry/Search.h @@ -12,11 +12,12 @@ #pragma once +#include +#include + #include "eckit/container/KDTree.h" #include "eckit/container/sptree/SPValue.h" -#include "eckit/geometry/Point2.h" -#include "eckit/geometry/Point3.h" -#include "eckit/geometry/PointLonLat.h" +#include "eckit/geometry/Point.h" #include "eckit/geometry/UnitSphere.h" @@ -42,38 +43,49 @@ struct SearchLonLat : Search3 { using Point = PointLonLat; using Value = SPValue, KDMemory>>; + using Result = std::tuple; + using Results = std::vector; + using Search3::Search3; void insert(const SearchLonLat::Value& value) { - Search3::insert({convert(value.point()), value.payload()}); + Search3::insert({to_cartesian(value.point()), value.payload()}); } - template - void build(ITER begin, ITER end) { - for (auto it = begin; it != end; ++it) { - insert(*it); + template + void build(const Container& c) { + size_t index = 0; + for (const auto& p : c) { + insert({p, index++}); } } - template - void build(Container& c) { - build(c.begin(), c.end()); + Result nearestNeighbour(const Point& p) { + auto n = Search3::nearestNeighbour(to_cartesian(p)); + return {UnitSphere::convertCartesianToSpherical(n.point()), n.payload(), n.distance()}; } - NodeInfo nearestNeighbour(const Point& p) { return Search3::nearestNeighbour(convert(p)); } - - NodeList findInSphere(const Point& p, double radius) { - return Search3::findInSphere(convert(p), radius); + Results findInSphere(const Point& p, double radius) { + return to_spherical(Search3::findInSphere(to_cartesian(p), radius)); } - NodeList kNearestNeighbours(const Point& p, size_t k) { - return Search3::kNearestNeighbours(convert(p), k); + Results kNearestNeighbours(const Point& p, size_t k) { + return to_spherical(Search3::kNearestNeighbours(to_cartesian(p), k)); } private: - static Search3::Point convert(const Point& p) { + static Search3::Point to_cartesian(const Point& p) { return UnitSphere::convertSphericalToCartesian(p); } + + static Results to_spherical(const NodeList& nodes) { + Results list; + list.reserve(nodes.size()); + for (const auto& n : nodes) { + list.emplace_back(UnitSphere::convertCartesianToSpherical(n.point()), n.payload(), n.distance()); + } + return list; + } }; From 40177a13bd27ed42d9df43c24bc220818b0bda88 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 15 Aug 2023 12:02:25 +0100 Subject: [PATCH 288/737] eckit::geometry --- src/eckit/geometry/CMakeLists.txt | 2 ++ src/eckit/geometry/Cache.cc | 47 ++++++++++++++++++++++++++ src/eckit/geometry/Cache.h | 55 +++++++++++++++++++++++++++++++ src/eckit/geometry/Ordering.h | 40 +++++++++++----------- 4 files changed, 124 insertions(+), 20 deletions(-) create mode 100644 src/eckit/geometry/Cache.cc create mode 100644 src/eckit/geometry/Cache.h diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index a0483baf1..18dbb1151 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -1,6 +1,8 @@ list( APPEND eckit_geometry_srcs Area.cc Area.h + Cache.cc + Cache.h CoordinateHelpers.cc CoordinateHelpers.h Domain.cc diff --git a/src/eckit/geometry/Cache.cc b/src/eckit/geometry/Cache.cc new file mode 100644 index 000000000..5e847c5d0 --- /dev/null +++ b/src/eckit/geometry/Cache.cc @@ -0,0 +1,47 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/Cache.h" + + +#include +#include +#include + + +namespace eckit::geometry::cache { + + +static std::map> __cache; + + +class ClassA { +public: + void functionA() const {} +}; + + +class ClassB { +public: + void functionB() const {} +}; + + +void test() { + __cache.insert({"a", std::make_unique>(ClassA())}); + __cache.insert({"b", std::make_unique>(ClassB())}); + + __cache["b"]->call(); +} + + +} // namespace eckit::geometry::cache diff --git a/src/eckit/geometry/Cache.h b/src/eckit/geometry/Cache.h new file mode 100644 index 000000000..f0aec4cd3 --- /dev/null +++ b/src/eckit/geometry/Cache.h @@ -0,0 +1,55 @@ +/* + * (C) Copyright 1996- 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 +#include + + +namespace eckit::geometry::cache { + + +class Cache { +public: + virtual ~Cache() = default; + virtual void call() = 0; +}; + + +class ClassA; +class ClassB; + + +template +class CacheableT : public Cache { + T obj; + +public: + CacheableT(T&& o) : + obj(std::move(o)) {} + + void call() override { + if constexpr (std::is_same::value) { + obj.functionA(); + return; + } + + if constexpr (std::is_same::value) { + obj.functionB(); + return; + } + + return; + } +}; + + +} // namespace eckit::geometry::cache diff --git a/src/eckit/geometry/Ordering.h b/src/eckit/geometry/Ordering.h index 7ee940ae0..8c6392cea 100644 --- a/src/eckit/geometry/Ordering.h +++ b/src/eckit/geometry/Ordering.h @@ -18,28 +18,28 @@ namespace eckit::geometry { enum Ordering { - scan_full_i_full_j_i_positively_j_negatively_j_consecutive_i_single_direction, - scan_full_i_full_j_i_negatively_j_negatively_j_consecutive_i_single_direction, - scan_full_i_full_j_i_positively_j_positively_j_consecutive_i_single_direction, - scan_full_i_full_j_i_negatively_j_positively_j_consecutive_i_single_direction, - scan_full_i_full_j_i_positively_j_negatively_i_consecutive_i_single_direction, - scan_full_i_full_j_i_negatively_j_negatively_i_consecutive_i_single_direction, - scan_full_i_full_j_i_positively_j_positively_i_consecutive_i_single_direction, - scan_full_i_full_j_i_negatively_j_positively_i_consecutive_i_single_direction, - scan_full_i_full_j_i_positively_j_negatively_j_consecutive_i_alternating_direction, - scan_full_i_full_j_i_negatively_j_negatively_j_consecutive_i_alternating_direction, - scan_full_i_full_j_i_positively_j_positively_j_consecutive_i_alternating_direction, - scan_full_i_full_j_i_negatively_j_positively_j_consecutive_i_alternating_direction, - scan_full_i_full_j_i_positively_j_negatively_i_consecutive_i_alternating_direction, - scan_full_i_full_j_i_negatively_j_negatively_i_consecutive_i_alternating_direction, - scan_full_i_full_j_i_positively_j_positively_i_consecutive_i_alternating_direction, - scan_full_i_full_j_i_negatively_j_positively_i_consecutive_i_alternating_direction, + scan_list_i_list_j_i_positively_j_negatively_ij_i_single_direction, + scan_list_i_list_j_i_negatively_j_negatively_ij_i_single_direction, + scan_list_i_list_j_i_positively_j_positively_ij_i_single_direction, + scan_list_i_list_j_i_negatively_j_positively_ij_i_single_direction, + scan_list_i_list_j_i_positively_j_negatively_ji_i_single_direction, + scan_list_i_list_j_i_negatively_j_negatively_ji_i_single_direction, + scan_list_i_list_j_i_positively_j_positively_ji_i_single_direction, + scan_list_i_list_j_i_negatively_j_positively_ji_i_single_direction, + scan_list_i_list_j_i_positively_j_negatively_ij_i_alternating_direction, + scan_list_i_list_j_i_negatively_j_negatively_ij_i_alternating_direction, + scan_list_i_list_j_i_positively_j_positively_ij_i_alternating_direction, + scan_list_i_list_j_i_negatively_j_positively_ij_i_alternating_direction, + scan_list_i_list_j_i_positively_j_negatively_ji_i_alternating_direction, + scan_list_i_list_j_i_negatively_j_negatively_ji_i_alternating_direction, + scan_list_i_list_j_i_positively_j_positively_ji_i_alternating_direction, + scan_list_i_list_j_i_negatively_j_positively_ji_i_alternating_direction, // TODO scan_ ... shift - scan_reduced_i_full_j_i_positively_j_negatively, - scan_reduced_i_full_j_i_negatively_j_negatively, - scan_reduced_i_full_j_i_positively_j_positively, - scan_reduced_i_full_j_i_negatively_j_positively, + scan_reduced_i_list_j_i_positively_j_negatively, + scan_reduced_i_list_j_i_negatively_j_negatively, + scan_reduced_i_list_j_i_positively_j_positively, + scan_reduced_i_list_j_i_negatively_j_positively, // TODO scan_ ... shift healpix_ring, From 2b145948918b98d62f61cd27f756314891105ad1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 15 Aug 2023 16:39:14 +0100 Subject: [PATCH 289/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 7 ++- src/eckit/geometry/Grid.h | 14 +++-- src/eckit/geometry/Iterator.h | 21 +++++--- src/eckit/geometry/Ordering.h | 46 ++++++++--------- src/eckit/geometry/grid/HEALPix.cc | 53 ++++++++++++++++--- src/eckit/geometry/grid/HEALPix.h | 6 +-- src/eckit/geometry/grid/IrregularLatlon.cc | 5 -- src/eckit/geometry/grid/IrregularLatlon.h | 2 - src/eckit/geometry/grid/ReducedGG.cc | 5 -- src/eckit/geometry/grid/ReducedGG.h | 2 - src/eckit/geometry/grid/ReducedLL.cc | 5 -- src/eckit/geometry/grid/ReducedLL.h | 2 - src/eckit/geometry/grid/RegularGG.cc | 5 -- src/eckit/geometry/grid/RegularGG.h | 2 - src/eckit/geometry/grid/UnstructuredGrid.cc | 54 ++++++++------------ src/eckit/geometry/grid/UnstructuredGrid.h | 11 ++-- src/eckit/geometry/iterator/ListI.cc | 40 ++++++--------- src/eckit/geometry/iterator/ListI.h | 14 ++--- src/eckit/geometry/iterator/ListIListJ.cc | 13 ++--- src/eckit/geometry/iterator/ListIListJ.h | 9 ++-- src/eckit/geometry/iterator/ReducedIListJ.cc | 16 +++--- src/eckit/geometry/iterator/ReducedIListJ.h | 10 ++-- 22 files changed, 173 insertions(+), 169 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 560f026d6..564295b26 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -67,7 +67,12 @@ bool Grid::isPeriodicWestEast() const { std::vector Grid::to_points() const { - throw NotImplemented("Grid::to_points", Here()); + throw NotImplemented("Grid::to_points"); +} + + +std::pair, std::vector> Grid::to_latlon() const { + throw NotImplemented("Grid::to_latlon"); } diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index ede011a38..14df4ae61 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "eckit/config/Configuration.h" @@ -38,6 +39,7 @@ class Grid { struct Iterator final : std::unique_ptr { explicit Iterator(geometry::Iterator* it) : unique_ptr(it) { ASSERT(unique_ptr::operator bool()); } + using diff_t = unique_ptr::element_type::diff_t; Iterator(const Iterator&) = delete; Iterator(Iterator&&) = delete; @@ -47,15 +49,18 @@ class Grid { void operator=(const Iterator&) = delete; void operator=(Iterator&&) = delete; - bool operator==(const Iterator& other) { return get()->operator==(*(other.get())); } - bool operator!=(const Iterator& other) { return get()->operator!=(*(other.get())); } + bool operator==(const Iterator& other) const { return get()->operator==(*(other.get())); } + bool operator!=(const Iterator& other) const { return get()->operator!=(*(other.get())); } + bool operator++() { return get()->operator++(); } + bool operator+=(diff_t d) { return get()->operator+=(d); } + bool operator--() { return get()->operator--(); } + bool operator-=(diff_t d) { return get()->operator-=(d); } explicit operator bool() const { return get()->operator bool(); } - const Point& operator*() const { return get()->operator*(); } + Point operator*() const { return get()->operator*(); } - size_t size() const { return get()->size(); } size_t index() const { return get()->index(); } }; @@ -102,6 +107,7 @@ class Grid { virtual bool isPeriodicWestEast() const; virtual std::vector to_points() const; + virtual std::pair, std::vector> to_latlon() const; virtual SearchLonLat::Result nearest(const PointLonLat&) const; virtual SearchLonLat::Results nearest(const PointLonLat&, size_t k) const; diff --git a/src/eckit/geometry/Iterator.h b/src/eckit/geometry/Iterator.h index d58990070..30918d150 100644 --- a/src/eckit/geometry/Iterator.h +++ b/src/eckit/geometry/Iterator.h @@ -12,6 +12,8 @@ #pragma once +#include + #include "eckit/geometry/Point.h" @@ -26,7 +28,8 @@ namespace eckit::geometry { class Iterator { public: // -- Types - // None + + using diff_t = std::make_signed::type; // -- Exceptions // None @@ -48,18 +51,20 @@ class Iterator { void operator=(const Iterator&) = delete; void operator=(Iterator&&) = delete; - bool operator!=(const Iterator& other) { return !operator==(other); } + virtual bool operator==(const Iterator&) const = 0; + bool operator!=(const Iterator& other) const { return !operator==(other); } + + virtual bool operator++() = 0; + virtual bool operator+=(diff_t) = 0; - virtual bool operator==(const Iterator&) = 0; - virtual bool operator++() = 0; - virtual bool operator--() = 0; + virtual bool operator--() { return operator-=(1); } + virtual bool operator-=(diff_t diff) { return operator+=(-diff); } - virtual explicit operator bool() = 0; - virtual const Point& operator*() = 0; + virtual explicit operator bool() const = 0; + virtual Point operator*() const = 0; // -- Methods - virtual size_t size() const = 0; virtual size_t index() const = 0; // -- Overridden methods diff --git a/src/eckit/geometry/Ordering.h b/src/eckit/geometry/Ordering.h index 8c6392cea..3bfe41789 100644 --- a/src/eckit/geometry/Ordering.h +++ b/src/eckit/geometry/Ordering.h @@ -18,29 +18,29 @@ namespace eckit::geometry { enum Ordering { - scan_list_i_list_j_i_positively_j_negatively_ij_i_single_direction, - scan_list_i_list_j_i_negatively_j_negatively_ij_i_single_direction, - scan_list_i_list_j_i_positively_j_positively_ij_i_single_direction, - scan_list_i_list_j_i_negatively_j_positively_ij_i_single_direction, - scan_list_i_list_j_i_positively_j_negatively_ji_i_single_direction, - scan_list_i_list_j_i_negatively_j_negatively_ji_i_single_direction, - scan_list_i_list_j_i_positively_j_positively_ji_i_single_direction, - scan_list_i_list_j_i_negatively_j_positively_ji_i_single_direction, - scan_list_i_list_j_i_positively_j_negatively_ij_i_alternating_direction, - scan_list_i_list_j_i_negatively_j_negatively_ij_i_alternating_direction, - scan_list_i_list_j_i_positively_j_positively_ij_i_alternating_direction, - scan_list_i_list_j_i_negatively_j_positively_ij_i_alternating_direction, - scan_list_i_list_j_i_positively_j_negatively_ji_i_alternating_direction, - scan_list_i_list_j_i_negatively_j_negatively_ji_i_alternating_direction, - scan_list_i_list_j_i_positively_j_positively_ji_i_alternating_direction, - scan_list_i_list_j_i_negatively_j_positively_ji_i_alternating_direction, - // TODO scan_ ... shift - - scan_reduced_i_list_j_i_positively_j_negatively, - scan_reduced_i_list_j_i_negatively_j_negatively, - scan_reduced_i_list_j_i_positively_j_positively, - scan_reduced_i_list_j_i_negatively_j_positively, - // TODO scan_ ... shift + regular_scan_i_positively_j_negatively_ij_i_single_direction, + regular_scan_i_negatively_j_negatively_ij_i_single_direction, + regular_scan_i_positively_j_positively_ij_i_single_direction, + regular_scan_i_negatively_j_positively_ij_i_single_direction, + regular_scan_i_positively_j_negatively_ji_i_single_direction, + regular_scan_i_negatively_j_negatively_ji_i_single_direction, + regular_scan_i_positively_j_positively_ji_i_single_direction, + regular_scan_i_negatively_j_positively_ji_i_single_direction, + regular_scan_i_positively_j_negatively_ij_i_alternating_direction, + regular_scan_i_negatively_j_negatively_ij_i_alternating_direction, + regular_scan_i_positively_j_positively_ij_i_alternating_direction, + regular_scan_i_negatively_j_positively_ij_i_alternating_direction, + regular_scan_i_positively_j_negatively_ji_i_alternating_direction, + regular_scan_i_negatively_j_negatively_ji_i_alternating_direction, + regular_scan_i_positively_j_positively_ji_i_alternating_direction, + regular_scan_i_negatively_j_positively_ji_i_alternating_direction, + // TODO regular_scan_ ... shift + + reduced_scan_i_positively_j_negatively, + reduced_scan_i_negatively_j_negatively, + reduced_scan_i_positively_j_positively, + reduced_scan_i_negatively_j_positively, + // TODO reduced_scan_ ... shift healpix_ring, healpix_nested, diff --git a/src/eckit/geometry/grid/HEALPix.cc b/src/eckit/geometry/grid/HEALPix.cc index ad8fdc4a1..70d6fdcb0 100644 --- a/src/eckit/geometry/grid/HEALPix.cc +++ b/src/eckit/geometry/grid/HEALPix.cc @@ -17,6 +17,7 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geometry/Iterator.h" #include "eckit/geometry/area/BoundingBox.h" #include "eckit/geometry/util.h" #include "eckit/utils/Translator.h" @@ -25,22 +26,52 @@ namespace eckit::geometry::grid { -static const area::BoundingBox __global; - - static HEALPix::ordering_type ordering_type_from_string(const std::string& str) { return str == "ring" ? HEALPix::ordering_type::ring : str == "nested" ? HEALPix::ordering_type::nested : throw AssertionFailed("HEALPix::ordering_type", Here()); } +struct RingIterator final : geometry::Iterator { + explicit RingIterator(const Grid& grid, size_t index = 0) : + geometry::Iterator(grid), size_(grid.size()), index_(index) {} + + bool operator==(const Iterator& other) const override { + const auto* another = dynamic_cast(&other); + return another != nullptr && index_ == another->index_; + } + + bool operator++() override { + index_++; + return operator bool(); + } + + bool operator+=(diff_t d) override { + NOTIMP; + } + + explicit operator bool() const override { + return index_ < size_; + } + + Point operator*() const override { + NOTIMP; + } + + size_t index() const override { return index_; } + + const size_t size_; + size_t index_; +}; + + HEALPix::HEALPix(const Configuration& config) : HEALPix(config.getUnsigned("Nside"), ordering_type_from_string(config.getString("orderingConvention", "ring"))) { } HEALPix::HEALPix(size_t Nside, ordering_type ordering) : - Grid(__global), N_(Nside), ordering_(ordering) { + Grid(area::BoundingBox::make_global_prime()), N_(Nside), ordering_(ordering) { ASSERT(N_ > 0); ASSERT(ordering_ == ordering_type::ring); @@ -112,7 +143,8 @@ const std::vector& HEALPix::longitudes(size_t i) const { const area::BoundingBox& HEALPix::boundingBox() const { - return __global; + static const auto __bbox(area::BoundingBox::make_global_prime()); + return __bbox; } @@ -121,7 +153,16 @@ size_t HEALPix::size() const { } -std::vector HEALPix::to_points() const { +Grid::iterator HEALPix::cbegin() const { + if (ordering_ == ordering_type::ring) { + return iterator{new RingIterator(*this, 0)}; + } + NOTIMP; +} +Grid::iterator HEALPix::cend() const { + if (ordering_ == ordering_type::ring) { + return iterator{new RingIterator(*this, size())}; + } NOTIMP; } diff --git a/src/eckit/geometry/grid/HEALPix.h b/src/eckit/geometry/grid/HEALPix.h index 1d6157b60..23c7a940b 100644 --- a/src/eckit/geometry/grid/HEALPix.h +++ b/src/eckit/geometry/grid/HEALPix.h @@ -89,10 +89,8 @@ class HEALPix final : public Grid { bool includesSouthPole() const override { return true; } bool isPeriodicWestEast() const override { return true; } - iterator cbegin() const override { NOTIMP; } - iterator cend() const override { NOTIMP; } - - std::vector to_points() const override; + iterator cbegin() const override; + iterator cend() const override; // -- Class members // None diff --git a/src/eckit/geometry/grid/IrregularLatlon.cc b/src/eckit/geometry/grid/IrregularLatlon.cc index 92f7e0886..1a22c141c 100644 --- a/src/eckit/geometry/grid/IrregularLatlon.cc +++ b/src/eckit/geometry/grid/IrregularLatlon.cc @@ -63,11 +63,6 @@ size_t IrregularLatlon::size() const { } -std::vector IrregularLatlon::to_points() const { - NOTIMP; -} - - static const GridRegisterType irregularLatlon("irregular_latlon"); diff --git a/src/eckit/geometry/grid/IrregularLatlon.h b/src/eckit/geometry/grid/IrregularLatlon.h index fa3682215..f1dea1891 100644 --- a/src/eckit/geometry/grid/IrregularLatlon.h +++ b/src/eckit/geometry/grid/IrregularLatlon.h @@ -63,8 +63,6 @@ class IrregularLatlon final : public Grid { size_t size() const override; - std::vector to_points() const override; - // -- Class members // None diff --git a/src/eckit/geometry/grid/ReducedGG.cc b/src/eckit/geometry/grid/ReducedGG.cc index 82987fe6c..e49225481 100644 --- a/src/eckit/geometry/grid/ReducedGG.cc +++ b/src/eckit/geometry/grid/ReducedGG.cc @@ -160,11 +160,6 @@ size_t ReducedGG::size() const { } -std::vector ReducedGG::to_points() const { - NOTIMP; -} - - bool ReducedGG::isPeriodicWestEast() const { auto inc = smallest_increment(pl_); return bbox().east() - bbox().west() + inc >= GLOBE; diff --git a/src/eckit/geometry/grid/ReducedGG.h b/src/eckit/geometry/grid/ReducedGG.h index b6e9169ba..ab9f1a7c7 100644 --- a/src/eckit/geometry/grid/ReducedGG.h +++ b/src/eckit/geometry/grid/ReducedGG.h @@ -85,8 +85,6 @@ class ReducedGG : public Gaussian { size_t size() const override; - std::vector to_points() const override; - // -- Class members // None diff --git a/src/eckit/geometry/grid/ReducedLL.cc b/src/eckit/geometry/grid/ReducedLL.cc index 51329359d..e6e95115f 100644 --- a/src/eckit/geometry/grid/ReducedLL.cc +++ b/src/eckit/geometry/grid/ReducedLL.cc @@ -76,11 +76,6 @@ bool ReducedLL::includesSouthPole() const { } -std::vector ReducedLL::to_points() const { - NOTIMP; -} - - static const GridRegisterType reducedLL("reduced_ll"); diff --git a/src/eckit/geometry/grid/ReducedLL.h b/src/eckit/geometry/grid/ReducedLL.h index c7e3e943c..a6f1c0292 100644 --- a/src/eckit/geometry/grid/ReducedLL.h +++ b/src/eckit/geometry/grid/ReducedLL.h @@ -68,8 +68,6 @@ class ReducedLL : public Grid { iterator cbegin() const override { NOTIMP; } iterator cend() const override { NOTIMP; } - std::vector to_points() const override; - // -- Class members // None diff --git a/src/eckit/geometry/grid/RegularGG.cc b/src/eckit/geometry/grid/RegularGG.cc index 89c8976b9..d456e145d 100644 --- a/src/eckit/geometry/grid/RegularGG.cc +++ b/src/eckit/geometry/grid/RegularGG.cc @@ -121,11 +121,6 @@ bool RegularGG::isPeriodicWestEast() const { } -std::vector RegularGG::to_points() const { - NOTIMP; -} - - void RegularGG::setNiNj() { ASSERT(N_); diff --git a/src/eckit/geometry/grid/RegularGG.h b/src/eckit/geometry/grid/RegularGG.h index b36f2f167..6c8f64d96 100644 --- a/src/eckit/geometry/grid/RegularGG.h +++ b/src/eckit/geometry/grid/RegularGG.h @@ -74,8 +74,6 @@ class RegularGG final : public Gaussian { bool isPeriodicWestEast() const override; - std::vector to_points() const override; - // -- Class members // None diff --git a/src/eckit/geometry/grid/UnstructuredGrid.cc b/src/eckit/geometry/grid/UnstructuredGrid.cc index 4b1483826..ef0fa43bf 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.cc +++ b/src/eckit/geometry/grid/UnstructuredGrid.cc @@ -12,12 +12,6 @@ #include "eckit/geometry/grid/UnstructuredGrid.h" -#include -#include -#include -#include -#include - #include "eckit/exception/Exceptions.h" #include "eckit/geometry/iterator/ListI.h" @@ -25,40 +19,24 @@ namespace eckit::geometry::grid { -static const area::BoundingBox __global; - - -static std::vector lonlat_to_points(const std::vector lons, const std::vector lats) { - auto N = lats.size(); - ASSERT(N == lons.size()); - - std::vector points; - points.reserve(N); - - for (auto lon = lons.begin(), lat = lats.begin(); lon != lons.end(); ++lon, ++lat) { - points.emplace_back(PointLonLat{*lon, *lat}); - } - - return points; -} - - UnstructuredGrid::UnstructuredGrid(const Configuration& config) : - UnstructuredGrid(config.getDoubleVector("longitudes"), config.getDoubleVector("latitudes")) { + UnstructuredGrid(std::make_pair(config.getDoubleVector("longitudes"), config.getDoubleVector("latitudes"))) { } UnstructuredGrid::UnstructuredGrid(const Grid& grid) : - UnstructuredGrid(grid.to_points()) {} + UnstructuredGrid(grid.to_latlon()) {} -UnstructuredGrid::UnstructuredGrid(std::vector&& points) : - Grid(__global), points_(points) { +UnstructuredGrid::UnstructuredGrid(const std::vector& latitudes, const std::vector& longitudes) : + Grid(area::BoundingBox::make_global_prime()), latitudes_(latitudes), longitudes_(longitudes) { + ASSERT(!latitudes_.empty()); + ASSERT(latitudes_.size() == longitudes_.size()); } -UnstructuredGrid::UnstructuredGrid(const std::vector& longitudes, const std::vector& latitudes) : - Grid(__global), points_(lonlat_to_points(longitudes, latitudes)) { +UnstructuredGrid::UnstructuredGrid(std::pair, std::vector>&& latlon) : + Grid(area::BoundingBox::make_global_prime()), latitudes_(std::move(latlon.first)), longitudes_(std::move(latlon.second)) { } @@ -76,12 +54,24 @@ UnstructuredGrid::~UnstructuredGrid() = default; size_t UnstructuredGrid::size() const { - return points_.size(); + return latitudes_.size(); } std::vector UnstructuredGrid::to_points() const { - return points_; + std::vector points; + points.reserve(size()); + + for (auto lat = latitudes_.begin(), lon = longitudes_.begin(); lat != latitudes_.end(); ++lat, ++lon) { + points.emplace_back(PointLonLat{*lon, *lat}); + } + + return points; +} + + +std::pair, std::vector> UnstructuredGrid::to_latlon() const { + return {latitudes_, longitudes_}; } diff --git a/src/eckit/geometry/grid/UnstructuredGrid.h b/src/eckit/geometry/grid/UnstructuredGrid.h index 807a28c7d..ae43a45c5 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.h +++ b/src/eckit/geometry/grid/UnstructuredGrid.h @@ -34,8 +34,7 @@ class UnstructuredGrid : public Grid { explicit UnstructuredGrid(const Configuration&); explicit UnstructuredGrid(const Grid&); - explicit UnstructuredGrid(std::vector&&); - UnstructuredGrid(const std::vector& longitudes, const std::vector& latitudes); + UnstructuredGrid(const std::vector& latitudes, const std::vector& longitudes); // -- Destructor @@ -60,9 +59,14 @@ class UnstructuredGrid : public Grid { // None private: + // -- Constructors + + explicit UnstructuredGrid(std::pair, std::vector>&&); + // -- Members - std::vector points_; + std::vector latitudes_; + std::vector longitudes_; // -- Methods // None @@ -79,6 +83,7 @@ class UnstructuredGrid : public Grid { bool includesSouthPole() const override { return true; } std::vector to_points() const override; + std::pair, std::vector> to_latlon() const override; // -- Class members // None diff --git a/src/eckit/geometry/iterator/ListI.cc b/src/eckit/geometry/iterator/ListI.cc index 26cc4966b..838b930b1 100644 --- a/src/eckit/geometry/iterator/ListI.cc +++ b/src/eckit/geometry/iterator/ListI.cc @@ -21,51 +21,41 @@ namespace eckit::geometry::iterator { ListI::ListI(const Grid& grid, size_t index) : Iterator(grid), - index_(index), - points_(dynamic_cast(grid).points_), - first_(true) { + latitudes_(dynamic_cast(grid).latitudes_), + longitudes_(dynamic_cast(grid).longitudes_), + size_(grid.size()), + index_(index) { } -bool ListI::operator==(const Iterator& other) { +bool ListI::operator==(const Iterator& other) const { const auto* another = dynamic_cast(&other); - return another != nullptr && points_.data() == another->points_.data() && index_ == another->index_; + return another != nullptr && latitudes_.data() == another->latitudes_.data() && longitudes_.data() == another->longitudes_.data() && index_ == another->index_; } bool ListI::operator++() { - if (first_) { - first_ = false; - } - else { - index_++; - } + index_++; return operator bool(); } -bool ListI::operator--() { - if (index_ == 0) { - return false; - } - index_--; +bool ListI::operator+=(diff_t d) { + auto i = static_cast(index_); + ASSERT(static_cast(i) == index_); + index_ = i + d < 0 ? size_ : static_cast(i + d); return operator bool(); } -ListI::operator bool() { - return index_ < points_.size(); +ListI::operator bool() const { + return index_ < size_; } -const Point& ListI::operator*() { +Point ListI::operator*() const { ASSERT(operator bool()); - return points_[index_]; -} - - -size_t ListI::size() const { - return points_.size(); + return PointLonLat{longitudes_[index_], latitudes_[index_]}; } diff --git a/src/eckit/geometry/iterator/ListI.h b/src/eckit/geometry/iterator/ListI.h index 5c299c247..5f36217a3 100644 --- a/src/eckit/geometry/iterator/ListI.h +++ b/src/eckit/geometry/iterator/ListI.h @@ -54,23 +54,23 @@ class ListI final : public Iterator { private: // -- Members + const std::vector& latitudes_; + const std::vector& longitudes_; + const size_t size_; size_t index_; - const std::vector& points_; - bool first_; // -- Methods // None // -- Overridden methods - bool operator==(const Iterator&) override; + bool operator==(const Iterator&) const override; bool operator++() override; - bool operator--() override; + bool operator+=(diff_t) override; - explicit operator bool() override; - const Point& operator*() override; + explicit operator bool() const override; + Point operator*() const override; - size_t size() const override; size_t index() const override; // -- Class members diff --git a/src/eckit/geometry/iterator/ListIListJ.cc b/src/eckit/geometry/iterator/ListIListJ.cc index 722077547..5a9f9481d 100644 --- a/src/eckit/geometry/iterator/ListIListJ.cc +++ b/src/eckit/geometry/iterator/ListIListJ.cc @@ -38,7 +38,7 @@ ListIListJ::ListIListJ(const Grid& grid) : } -bool ListIListJ::operator==(const Iterator&) { +bool ListIListJ::operator==(const Iterator&) const { NOTIMP; } @@ -74,22 +74,17 @@ bool ListIListJ::operator++() { } -bool ListIListJ::operator--() { +bool ListIListJ::operator+=(diff_t) { NOTIMP; } -ListIListJ::operator bool() { +ListIListJ::operator bool() const { NOTIMP; } -const Point& ListIListJ::operator*() { - NOTIMP; -} - - -size_t ListIListJ::size() const { +Point ListIListJ::operator*() const { NOTIMP; } diff --git a/src/eckit/geometry/iterator/ListIListJ.h b/src/eckit/geometry/iterator/ListIListJ.h index 74f322afb..fb793af2b 100644 --- a/src/eckit/geometry/iterator/ListIListJ.h +++ b/src/eckit/geometry/iterator/ListIListJ.h @@ -76,14 +76,13 @@ class ListIListJ final : public Iterator { // -- Overridden methods - bool operator==(const Iterator&) override; + bool operator==(const Iterator&) const override; bool operator++() override; - bool operator--() override; + bool operator+=(diff_t) override; - explicit operator bool() override; - const Point& operator*() override; + explicit operator bool() const override; + Point operator*() const override; - size_t size() const override; size_t index() const override; // -- Class members diff --git a/src/eckit/geometry/iterator/ReducedIListJ.cc b/src/eckit/geometry/iterator/ReducedIListJ.cc index 3eea54dd1..c4d07375c 100644 --- a/src/eckit/geometry/iterator/ReducedIListJ.cc +++ b/src/eckit/geometry/iterator/ReducedIListJ.cc @@ -13,6 +13,7 @@ #include "eckit/geometry/iterator/ReducedIListJ.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geometry/Grid.h" namespace eckit::geometry::iterator { @@ -40,7 +41,8 @@ ReducedIListJ::ReducedIListJ( k_(0), // size_t k count_(0), first_(true), - p_(PointLonLat{0, 0}) { + p_(PointLonLat{0, 0}), + size_(grid.size()) { // NOTE: latitudes_ span the globe, sorted from North-to-South, k_ positions the North // NOTE: pl is global ASSERT(N_ * 2 == latitudes_.size()); @@ -74,7 +76,7 @@ size_t ReducedIListJ::resetToRow(size_t j) { } -bool ReducedIListJ::operator==(const Iterator&) { +bool ReducedIListJ::operator==(const Iterator&) const { NOTIMP; } @@ -107,25 +109,21 @@ bool ReducedIListJ::operator++() { } -bool ReducedIListJ::operator--() { +bool ReducedIListJ::operator+=(diff_t) { NOTIMP; } -ReducedIListJ::operator bool() { +ReducedIListJ::operator bool() const { NOTIMP; } -const Point& ReducedIListJ::operator*() { +Point ReducedIListJ::operator*() const { NOTIMP; } -size_t ReducedIListJ::size() const { - NOTIMP; -} - size_t ReducedIListJ::index() const { return count_; } diff --git a/src/eckit/geometry/iterator/ReducedIListJ.h b/src/eckit/geometry/iterator/ReducedIListJ.h index 4e7eee7f2..5f1edd986 100644 --- a/src/eckit/geometry/iterator/ReducedIListJ.h +++ b/src/eckit/geometry/iterator/ReducedIListJ.h @@ -72,6 +72,7 @@ class ReducedIListJ : public Iterator { size_t count_; bool first_; Point p_; + const size_t size_; // -- Methods @@ -79,14 +80,13 @@ class ReducedIListJ : public Iterator { // -- Overridden methods - bool operator==(const Iterator&) override; + bool operator==(const Iterator&) const override; bool operator++() override; - bool operator--() override; + bool operator+=(diff_t) override; - explicit operator bool() override; - const Point& operator*() override; + explicit operator bool() const override; + Point operator*() const override; - size_t size() const override; size_t index() const override; // -- Class members From e135ac4fbcbde970ac3b33c1cd06f63076b5adae Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 16 Aug 2023 01:15:23 +0100 Subject: [PATCH 290/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 10 +- src/eckit/geometry/grid/HEALPix.cc | 152 ++++++++++++++++++--------- src/eckit/geometry/grid/HEALPix.h | 42 +++++--- src/eckit/geometry/grid/RegularLL.cc | 12 ++- src/eckit/geometry/grid/RegularLL.h | 2 +- src/eckit/geometry/util/arange.cc | 2 +- 6 files changed, 149 insertions(+), 71 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 564295b26..12ebef945 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -67,7 +67,15 @@ bool Grid::isPeriodicWestEast() const { std::vector Grid::to_points() const { - throw NotImplemented("Grid::to_points"); + std::vector points; + points.reserve(size()); + + for (const auto& p : *this) { + const auto& q = std::get(p); + points.push_back(p); + } + + return points; } diff --git a/src/eckit/geometry/grid/HEALPix.cc b/src/eckit/geometry/grid/HEALPix.cc index 70d6fdcb0..f021d8153 100644 --- a/src/eckit/geometry/grid/HEALPix.cc +++ b/src/eckit/geometry/grid/HEALPix.cc @@ -17,7 +17,6 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Iterator.h" #include "eckit/geometry/area/BoundingBox.h" #include "eckit/geometry/util.h" #include "eckit/utils/Translator.h" @@ -26,54 +25,95 @@ namespace eckit::geometry::grid { -static HEALPix::ordering_type ordering_type_from_string(const std::string& str) { - return str == "ring" ? HEALPix::ordering_type::ring : str == "nested" ? HEALPix::ordering_type::nested - : throw AssertionFailed("HEALPix::ordering_type", Here()); +static Ordering ordering_from_string(const std::string& str) { + return str == "ring" ? Ordering::healpix_ring : str == "nested" ? Ordering::healpix_nested + : throw AssertionFailed("HEALPix::Ordering", Here()); } -struct RingIterator final : geometry::Iterator { - explicit RingIterator(const Grid& grid, size_t index = 0) : - geometry::Iterator(grid), size_(grid.size()), index_(index) {} +HEALPix::RingIterator::RingIterator(const Grid& grid, size_t index) : + geometry::Iterator(grid), + grid_(dynamic_cast(grid)), + index_(index), + index_size_(grid.size()) { + if (index_ < index_size_) { + ASSERT(2 <= grid_.njacc_.size()); - bool operator==(const Iterator& other) const override { - const auto* another = dynamic_cast(&other); - return another != nullptr && index_ == another->index_; - } + longitudes_j_ = grid_.longitudes(j_ = j(index_)); + ASSERT(grid_.njacc_.at(j_) <= index && index_ < grid_.njacc_.at(j_ + 1)); - bool operator++() override { - index_++; - return operator bool(); + grid_.latitudes(); + ASSERT(grid_.latitudes_.size() == grid_.ni()); } +} - bool operator+=(diff_t d) override { - NOTIMP; - } - explicit operator bool() const override { - return index_ < size_; +bool HEALPix::RingIterator::operator==(const Iterator& other) const { + const auto* another = dynamic_cast(&other); + return another != nullptr && index_ == another->index_; +} + + +bool HEALPix::RingIterator::operator++() { + if (index_++; index_ < index_size_) { + if (!(index_ < grid_.njacc_[j_ + 1])) { + longitudes_j_ = grid_.longitudes(++j_); + } + + ASSERT(grid_.njacc_[j_] <= index_ && index_ < grid_.njacc_[j_ + 1]); + return true; } - Point operator*() const override { - NOTIMP; + index_ = index_size_; // ensure it's invalid + return false; +} + + +bool HEALPix::RingIterator::operator+=(diff_t d) { + if (auto di = static_cast(index_); 0 <= di + d && di + d < static_cast(index_size_)) { + if (index_ = static_cast(di + d); !(grid_.njacc_[j_] <= index_ && index_ < grid_.njacc_[j_ + 1])) { + longitudes_j_ = grid_.longitudes(j_ = j(index_)); + } + + ASSERT(grid_.njacc_[j_] <= index_ && index_ < grid_.njacc_[j_ + 1]); + return true; } - size_t index() const override { return index_; } + index_ = index_size_; // ensure it's invalid + return false; +} + + +HEALPix::RingIterator::operator bool() const { + return index_ < index_size_; +} + + +Point HEALPix::RingIterator::operator*() const { + return PointLonLat{longitudes_j_.at(index_ - grid_.njacc_[j_]), grid_.latitudes_.at(j_)}; +} + + +size_t HEALPix::RingIterator::j(size_t index) const { + ASSERT(index < index_size_); - const size_t size_; - size_t index_; -}; + const auto& njacc = grid_.njacc_; + auto dist = std::distance(njacc.begin(), std::upper_bound(njacc.begin(), njacc.end(), index)); + ASSERT(1 <= dist && dist <= njacc.size() - 1); + + return static_cast(dist - 1); +} HEALPix::HEALPix(const Configuration& config) : - HEALPix(config.getUnsigned("Nside"), ordering_type_from_string(config.getString("orderingConvention", "ring"))) { + HEALPix(config.getUnsigned("Nside"), ordering_from_string(config.getString("orderingConvention", "ring"))) { } -HEALPix::HEALPix(size_t Nside, ordering_type ordering) : +HEALPix::HEALPix(size_t Nside, Ordering ordering) : Grid(area::BoundingBox::make_global_prime()), N_(Nside), ordering_(ordering) { ASSERT(N_ > 0); - ASSERT(ordering_ == ordering_type::ring); + ASSERT(ordering_ == Ordering::healpix_ring); // accumulated nj @@ -110,11 +150,11 @@ size_t HEALPix::nj(size_t i) const { const std::vector& HEALPix::latitudes() const { const auto Ni = ni(); - if (lats_.empty()) { - lats_.resize(Ni); + if (latitudes_.empty()) { + latitudes_.resize(Ni); - auto i = lats_.begin(); - auto j = lats_.rbegin(); + auto i = latitudes_.begin(); + auto j = latitudes_.rbegin(); for (int ring = 1; ring < 2 * N_; ++ring, ++i, ++j) { const auto f = ring < N_ ? 1. - static_cast(ring * ring) / (3 * static_cast(N_ * N_)) : 4. / 3. - 2 * static_cast(ring) / (3 * static_cast(N_)); @@ -124,21 +164,30 @@ const std::vector& HEALPix::latitudes() const { *i = 0.; } - ASSERT(lats_.size() == Ni); - return lats_; + ASSERT(latitudes_.size() == Ni); + return latitudes_; } -const std::vector& HEALPix::longitudes(size_t i) const { - const auto Nj = nj(i); +std::vector HEALPix::longitudes(size_t ring) const { + const auto Nj = nj(ring); const auto step = 360. / static_cast(Nj); - const auto start = i < N_ || 3 * N_ - 1 < i || static_cast((i + N_) % 2) ? step / 2. : 0.; + const auto start = ring < N_ || 3 * N_ - 1 < ring || static_cast((ring + N_) % 2) ? step / 2. : 0.; - lons_.reserve(N_ * 4); - lons_.resize(Nj); - std::generate_n(lons_.begin(), Nj, [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); + std::vector lons(Nj); + std::generate_n(lons.begin(), Nj, [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); - return lons_; + return lons; +} + + +Grid::iterator HEALPix::cbegin() const { + return ordering_ == Ordering::healpix_ring ? iterator{new RingIterator(*this, 0)} : NOTIMP; +} + + +Grid::iterator HEALPix::cend() const { + return ordering_ == Ordering::healpix_ring ? iterator{new RingIterator(*this, size())} : NOTIMP; } @@ -153,17 +202,18 @@ size_t HEALPix::size() const { } -Grid::iterator HEALPix::cbegin() const { - if (ordering_ == ordering_type::ring) { - return iterator{new RingIterator(*this, 0)}; - } - NOTIMP; -} -Grid::iterator HEALPix::cend() const { - if (ordering_ == ordering_type::ring) { - return iterator{new RingIterator(*this, size())}; +std::pair, std::vector> HEALPix::to_latlon() const { + std::pair, std::vector> latlon; + latlon.first.reserve(size()); + latlon.second.reserve(size()); + + for (const auto& p : to_points()) { + const auto& q = std::get(p); + latlon.first.push_back(q.lat); + latlon.second.push_back(q.lon); } - NOTIMP; + + return latlon; } diff --git a/src/eckit/geometry/grid/HEALPix.h b/src/eckit/geometry/grid/HEALPix.h index 23c7a940b..e8289cff8 100644 --- a/src/eckit/geometry/grid/HEALPix.h +++ b/src/eckit/geometry/grid/HEALPix.h @@ -15,6 +15,7 @@ #include #include "eckit/geometry/Grid.h" +#include "eckit/geometry/Ordering.h" namespace eckit::geometry::grid { @@ -24,10 +25,25 @@ class HEALPix final : public Grid { public: // -- Types - enum ordering_type - { - ring, - nested + class RingIterator final : public geometry::Iterator { + public: + explicit RingIterator(const Grid&, size_t index = 0); + + private: + bool operator==(const Iterator&) const override; + bool operator++() override; + bool operator+=(diff_t) override; + explicit operator bool() const override; + Point operator*() const override; + + size_t index() const override { return index_; } + size_t j(size_t index) const; + + const HEALPix& grid_; + std::vector longitudes_j_; + size_t j_; + size_t index_; + const size_t index_size_; }; // -- Exceptions @@ -36,7 +52,7 @@ class HEALPix final : public Grid { // -- Constructors explicit HEALPix(const Configuration&); - explicit HEALPix(size_t Nside, ordering_type); + explicit HEALPix(size_t Nside, Ordering = Ordering::healpix_ring); // -- Destructor // None @@ -64,12 +80,11 @@ class HEALPix final : public Grid { // -- Members const size_t N_; - const ordering_type ordering_; + const Ordering ordering_; std::vector njacc_; - mutable std::vector lats_; - mutable std::vector lons_; + mutable std::vector latitudes_; // -- Methods @@ -77,10 +92,13 @@ class HEALPix final : public Grid { size_t nj(size_t i) const; const std::vector& latitudes() const; - const std::vector& longitudes(size_t i) const; + std::vector longitudes(size_t ring) const; // -- Overridden methods + iterator cbegin() const override; + iterator cend() const override; + const area::BoundingBox& boundingBox() const override; size_t size() const override; @@ -89,8 +107,7 @@ class HEALPix final : public Grid { bool includesSouthPole() const override { return true; } bool isPeriodicWestEast() const override { return true; } - iterator cbegin() const override; - iterator cend() const override; + std::pair, std::vector> to_latlon() const override; // -- Class members // None @@ -99,7 +116,8 @@ class HEALPix final : public Grid { // None // -- Friends - // None + + friend class RingIterator; }; diff --git a/src/eckit/geometry/grid/RegularLL.cc b/src/eckit/geometry/grid/RegularLL.cc index 7c92e6151..1ccf67024 100644 --- a/src/eckit/geometry/grid/RegularLL.cc +++ b/src/eckit/geometry/grid/RegularLL.cc @@ -166,7 +166,7 @@ size_t RegularLL::size() const { } -std::vector RegularLL::to_points() const { +std::pair, std::vector> RegularLL::to_latlon() const { auto [n, w, s, e] = bbox().deconstruct(); auto [we, sn] = increments_.deconstruct(); @@ -176,16 +176,18 @@ std::vector RegularLL::to_points() const { auto latitudes = util::arange(n, s, -sn); ASSERT(latitudes.size() == nj_); - std::vector points; - points.reserve(size()); + std::pair, std::vector> latlon; + latlon.first.reserve(size()); + latlon.second.reserve(size()); for (const auto lat : latitudes) { for (const auto lon : longitudes) { - points.emplace_back(PointLonLat{lon, lat}); + latlon.first.push_back(lat); + latlon.second.push_back(lon); } } - return points; + return latlon; } diff --git a/src/eckit/geometry/grid/RegularLL.h b/src/eckit/geometry/grid/RegularLL.h index db067c633..0c5f229cd 100644 --- a/src/eckit/geometry/grid/RegularLL.h +++ b/src/eckit/geometry/grid/RegularLL.h @@ -76,7 +76,7 @@ class RegularLL : public Grid { size_t size() const override; - std::vector to_points() const override; + std::pair, std::vector> to_latlon() const override; // -- Class members // None diff --git a/src/eckit/geometry/util/arange.cc b/src/eckit/geometry/util/arange.cc index 820124ff5..5a3bbc5f5 100644 --- a/src/eckit/geometry/util/arange.cc +++ b/src/eckit/geometry/util/arange.cc @@ -27,7 +27,7 @@ std::vector arange(double start, double stop, double step) { const auto num = static_cast((stop - start) / step) + 1; std::vector l(num); - std::generate_n(l.begin(), num, [start, step, n = 0]() mutable { return start + static_cast(n++) * step; }); + std::generate_n(l.begin(), num, [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); return l; } From 87c6fa6cf8d3ca28f8617f39bcfaf1c32ce86bf0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 16 Aug 2023 14:58:43 +0100 Subject: [PATCH 291/737] Correctness --- src/eckit/cmd/LibEcKitCmd.h | 2 +- src/eckit/option/EckitTool.cc | 1 + src/eckit/option/EckitTool.h | 3 ++- src/tools/eckit-info.cc | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/eckit/cmd/LibEcKitCmd.h b/src/eckit/cmd/LibEcKitCmd.h index cbd1a9e95..451965a03 100644 --- a/src/eckit/cmd/LibEcKitCmd.h +++ b/src/eckit/cmd/LibEcKitCmd.h @@ -21,9 +21,9 @@ namespace eckit { //---------------------------------------------------------------------------------------------------------------------- class LibEcKitCmd : public eckit::system::Library { + LibEcKitCmd(); public: // methods - LibEcKitCmd(); static LibEcKitCmd& instance(); diff --git a/src/eckit/option/EckitTool.cc b/src/eckit/option/EckitTool.cc index 0bab88329..0d34ce379 100644 --- a/src/eckit/option/EckitTool.cc +++ b/src/eckit/option/EckitTool.cc @@ -10,6 +10,7 @@ #include "EckitTool.h" +#include "eckit/exception/Exceptions.h" #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" diff --git a/src/eckit/option/EckitTool.h b/src/eckit/option/EckitTool.h index d40b8fb59..58f5e786b 100644 --- a/src/eckit/option/EckitTool.h +++ b/src/eckit/option/EckitTool.h @@ -10,12 +10,13 @@ /// @author Baudouin Raoult /// @author Tiago Quintino +/// @author Pedro Maciel /// @date Mar 2016 #pragma once #include "eckit/filesystem/PathName.h" -#include "eckit/option/SimpleOption.h" +#include "eckit/option/Option.h" #include "eckit/runtime/Tool.h" namespace eckit { diff --git a/src/tools/eckit-info.cc b/src/tools/eckit-info.cc index 6b5e8bea8..757edbfb5 100644 --- a/src/tools/eckit-info.cc +++ b/src/tools/eckit-info.cc @@ -16,6 +16,7 @@ #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" #include "eckit/option/EckitTool.h" +#include "eckit/option/SimpleOption.h" #include "eckit/system/Library.h" #include "eckit/system/LibraryManager.h" From dfb43656b0860d5cf7768be53f44f11ad760293a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 16 Aug 2023 15:03:50 +0100 Subject: [PATCH 292/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 22 ++++------------------ src/eckit/geometry/Grid.h | 6 +++--- src/eckit/geometry/Iterator.h | 2 +- src/eckit/geometry/grid/HEALPix.h | 1 - 4 files changed, 8 insertions(+), 23 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 12ebef945..7941a4f48 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -84,27 +84,13 @@ std::pair, std::vector> Grid::to_latlon() const { } -SearchLonLat::Result Grid::nearest(const PointLonLat& p) const { - SearchLonLat search; - - size_t index = 0; - for (const auto& p : to_points()) { - search.insert({std::get(p), index}); - } - - return search.nearestNeighbour(p); +Ordering Grid::order() const { + throw NotImplemented("Grid::order"); } -SearchLonLat::Results Grid::nearest(const PointLonLat& p, size_t k) const { - SearchLonLat search; - - size_t index = 0; - for (const auto& p : to_points()) { - search.insert({std::get(p), index}); - } - - return search.kNearestNeighbours(p, k); +Renumber Grid::reorder(const PointLonLat&) const { + throw NotImplemented("Grid::reorder"); } diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 14df4ae61..e7e9b7cc1 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -22,10 +22,10 @@ #include "eckit/geometry/Area.h" #include "eckit/geometry/Increments.h" #include "eckit/geometry/Iterator.h" +#include "eckit/geometry/Ordering.h" #include "eckit/geometry/Point.h" #include "eckit/geometry/Projection.h" #include "eckit/geometry/Renumber.h" -#include "eckit/geometry/Search.h" #include "eckit/geometry/area/BoundingBox.h" @@ -109,8 +109,8 @@ class Grid { virtual std::vector to_points() const; virtual std::pair, std::vector> to_latlon() const; - virtual SearchLonLat::Result nearest(const PointLonLat&) const; - virtual SearchLonLat::Results nearest(const PointLonLat&, size_t k) const; + virtual Ordering order() const; + virtual Renumber reorder(const PointLonLat&) const; // -- Overridden methods // None diff --git a/src/eckit/geometry/Iterator.h b/src/eckit/geometry/Iterator.h index 30918d150..236b73fa5 100644 --- a/src/eckit/geometry/Iterator.h +++ b/src/eckit/geometry/Iterator.h @@ -79,7 +79,7 @@ class Iterator { protected: // -- Constructors - Iterator(const Grid&) {} + explicit Iterator(const Grid&) {} // -- Members // None diff --git a/src/eckit/geometry/grid/HEALPix.h b/src/eckit/geometry/grid/HEALPix.h index e8289cff8..065687de4 100644 --- a/src/eckit/geometry/grid/HEALPix.h +++ b/src/eckit/geometry/grid/HEALPix.h @@ -15,7 +15,6 @@ #include #include "eckit/geometry/Grid.h" -#include "eckit/geometry/Ordering.h" namespace eckit::geometry::grid { From fa7e83d65640bfe7f20298147ca0569cb9179452 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 16 Aug 2023 17:01:26 +0100 Subject: [PATCH 293/737] eckit::geometry search --- src/eckit/geometry/Search.h | 41 +++++++++++++--------------- src/tools/eckit-grid.cc | 54 +++++++++++++++++++++++-------------- 2 files changed, 52 insertions(+), 43 deletions(-) diff --git a/src/eckit/geometry/Search.h b/src/eckit/geometry/Search.h index bec4ca509..2333e916c 100644 --- a/src/eckit/geometry/Search.h +++ b/src/eckit/geometry/Search.h @@ -12,7 +12,6 @@ #pragma once -#include #include #include "eckit/container/KDTree.h" @@ -33,19 +32,16 @@ struct Traits { } // namespace search -using Search3 = KDTreeMemory>; +using Search3 = KDTreeMemory>; -using Search2 = KDTreeMemory>; +using Search2 = KDTreeMemory>; struct SearchLonLat : Search3 { - using Point = PointLonLat; + using Point = geometry::PointLonLat; using Value = SPValue, KDMemory>>; - using Result = std::tuple; - using Results = std::vector; - using Search3::Search3; void insert(const SearchLonLat::Value& value) { @@ -56,36 +52,35 @@ struct SearchLonLat : Search3 { void build(const Container& c) { size_t index = 0; for (const auto& p : c) { - insert({p, index++}); + insert({std::get(p), index++}); } } - Result nearestNeighbour(const Point& p) { + size_t nearestNeighbour(const Point& p) { auto n = Search3::nearestNeighbour(to_cartesian(p)); - return {UnitSphere::convertCartesianToSpherical(n.point()), n.payload(), n.distance()}; + return n.payload(); } - Results findInSphere(const Point& p, double radius) { - return to_spherical(Search3::findInSphere(to_cartesian(p), radius)); + std::vector findInSphere(const Point& p, double radius) { + std::vector near; + for (auto& n : Search3::findInSphere(to_cartesian(p), radius)) { + near.emplace_back(n.payload()); + } + return near; } - Results kNearestNeighbours(const Point& p, size_t k) { - return to_spherical(Search3::kNearestNeighbours(to_cartesian(p), k)); + std::vector kNearestNeighbours(const Point& p, size_t k) { + std::vector near; + for (auto& n : Search3::kNearestNeighbours(to_cartesian(p), k)) { + near.emplace_back(n.payload()); + } + return near; } private: static Search3::Point to_cartesian(const Point& p) { return UnitSphere::convertSphericalToCartesian(p); } - - static Results to_spherical(const NodeList& nodes) { - Results list; - list.reserve(nodes.size()); - for (const auto& n : nodes) { - list.emplace_back(UnitSphere::convertCartesianToSpherical(n.point()), n.payload(), n.distance()); - } - return list; - } }; diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index 816c2df4b..cb52e6170 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -15,10 +15,13 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geometry/Grid.h" #include "eckit/geometry/Point.h" -#include "eckit/log/JSON.h" +#include "eckit/geometry/Search.h" +#include "eckit/geometry/grid/UnstructuredGrid.h" #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" #include "eckit/option/EckitTool.h" +#include "eckit/option/SimpleOption.h" +#include "eckit/option/VectorOption.h" //---------------------------------------------------------------------------------------------------------------------- @@ -30,6 +33,8 @@ class EckitGrid final : public EckitTool { EckitTool(argc, argv) { options_.push_back(new option::SimpleOption("list", "List possible grids")); options_.push_back(new option::SimpleOption("uid", "by grid unique identifier, instead of name")); + options_.push_back(new option::VectorOption("nearest-point", "nearest point location (lon/lat)", 2)); + options_.push_back(new option::SimpleOption("nearest-k", "nearest k points")); } private: @@ -40,42 +45,51 @@ class EckitGrid final : public EckitTool { bool uid = false; args.get("uid", uid); + geometry::PointLonLat nearest_point{0, 0}; + size_t nearest_k = 0; + if (std::vector point; args.get("nearest-point", point)) { + ASSERT(point.size() == 2); + nearest_point = {point[0], point[1]}; + nearest_k = args.getUnsigned("nearest-k", 1); + } + if (list) { geometry::GridFactory::list(Log::info()); Log::info() << std::endl; return; } - geometry::Point x = geometry::PointLonLat(0., 90.); - std::cout << x << std::endl; - auto& out = Log::info(); - // JSON out(Log::info()); - // out.precision(args.getInt("precision", 16)); + out.precision(args.getInt("precision", 16)); - for (std::string arg : args) { + for (const auto& arg : args) { std::unique_ptr grid(uid ? geometry::GridFactoryUID::build(arg) : geometry::GridFactoryName::build(arg)); - // out << "name: " << grid->name() << std::endl; - // out << "uid: " << grid->uid() << std::endl; out << "size: " << grid->size() << std::endl; - auto it = grid->begin(); + for (const auto& p : *grid) { + out << p << std::endl; + } - std::cout << *it << std::endl; + for (const auto& p : geometry::grid::UnstructuredGrid(*grid)) { + out << p << std::endl; + } - // (*it).print(out) << std::endl; - // static_cast(out) << "first: " << q << std::endl; + if (nearest_k > 0) { + geometry::SearchLonLat search; + search.build(grid->to_points()); + + const auto* sep = ""; + for (auto& near : search.kNearestNeighbours(nearest_point, nearest_k)) { + out << sep << near; + sep = ", "; + } + out << std::endl; + } // it += grid->size() - 1; - // out << "last: " << **it << std::endl; + // out << "last: " << *it << std::endl; // ASSERT(it == grid->rbegin()); - - // out.startList(); - // for (const auto& p : *grid) { - // out << p; - // } - // out.endList(); } } From 1ee8fcfebe2639493ff75812e9801a26870a2cdd Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 16 Aug 2023 17:07:32 +0100 Subject: [PATCH 294/737] eckit::geometry --- src/tools/eckit-grid.cc | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index cb52e6170..13d20f0c4 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -39,11 +39,13 @@ class EckitGrid final : public EckitTool { private: void execute(const option::CmdArgs& args) override { - bool list = false; - args.get("list", list); + if (args.getBool("list", false)) { + geometry::GridFactory::list(Log::info()); + Log::info() << std::endl; + return; + } - bool uid = false; - args.get("uid", uid); + auto uid = args.getBool("uid", false); geometry::PointLonLat nearest_point{0, 0}; size_t nearest_k = 0; @@ -53,12 +55,6 @@ class EckitGrid final : public EckitTool { nearest_k = args.getUnsigned("nearest-k", 1); } - if (list) { - geometry::GridFactory::list(Log::info()); - Log::info() << std::endl; - return; - } - auto& out = Log::info(); out.precision(args.getInt("precision", 16)); From 9f2bf3f1e3e6a46f07f249b93b9f41b62aacfdfa Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 16 Aug 2023 23:41:29 +0100 Subject: [PATCH 295/737] eckit::geometry --- CMakeLists.txt | 2 +- etc/CMakeLists.txt | 2 + etc/eckit/CMakeLists.txt | 2 + etc/eckit/geometry/CMakeLists.txt | 9 + etc/eckit/geometry/grid.yaml | 352 ++++++++++++++++++++++++++++++ 5 files changed, 366 insertions(+), 1 deletion(-) create mode 100644 etc/CMakeLists.txt create mode 100644 etc/eckit/CMakeLists.txt create mode 100644 etc/eckit/geometry/CMakeLists.txt create mode 100644 etc/eckit/geometry/grid.yaml diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ecdfee60..28eccd71b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -277,9 +277,9 @@ include(cmake/compiler_warnings.cmake) # optionally handle compiler specific war set( PERSISTENT_NAMESPACE "eckit" CACHE INTERNAL "" ) # needed for generating .b files for persistent support add_subdirectory( src ) - add_subdirectory( bamboo ) add_subdirectory( doc ) +add_subdirectory( etc ) add_subdirectory( tests ) add_subdirectory( regressions ) diff --git a/etc/CMakeLists.txt b/etc/CMakeLists.txt new file mode 100644 index 000000000..b4521afe0 --- /dev/null +++ b/etc/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(eckit) + diff --git a/etc/eckit/CMakeLists.txt b/etc/eckit/CMakeLists.txt new file mode 100644 index 000000000..c96a3c805 --- /dev/null +++ b/etc/eckit/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(geometry) + diff --git a/etc/eckit/geometry/CMakeLists.txt b/etc/eckit/geometry/CMakeLists.txt new file mode 100644 index 000000000..b134265ac --- /dev/null +++ b/etc/eckit/geometry/CMakeLists.txt @@ -0,0 +1,9 @@ +file(GLOB _files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.yaml") +set(_destination "etc/eckit/geometry") + +install(FILES ${_files} DESTINATION ${_destination} PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) + +foreach(_file ${_files}) + configure_file(${_file} "${CMAKE_BINARY_DIR}/${_destination}/${_file}" COPYONLY) +endforeach() + diff --git a/etc/eckit/geometry/grid.yaml b/etc/eckit/geometry/grid.yaml new file mode 100644 index 000000000..6024651eb --- /dev/null +++ b/etc/eckit/geometry/grid.yaml @@ -0,0 +1,352 @@ +--- + +orca-url-prefix: "https://get.ecmwf.int/repository/atlas/grids/orca/v0" +orca-validate-uid: false # Validates UID upon grid creation +orca-compute-uid: false # Recompute UID and ignore encoded UID + +grid-names: + - LAEA-EFAS-5km: + type: lambert_azimuthal_equal_area + standardParallelInDegrees: 52. + centralLongitudeInDegrees: 10. + grid: 5000./5000. + gaussianNumber: 1280 + latitudeOfFirstGridPointInDegrees: 66.982143 + longitudeOfFirstGridPointInDegrees: -35.034024 + numberOfPointsAlongXAxis: 1000 + numberOfPointsAlongYAxis: 950 + proj: +proj=laea +lat_0=52 +lon_0=10 +ellps=GRS80 +units=m +no_defs + shapeOfTheEarth: 4 + + - SMUFF-OPERA-2km: + type: lambert_azimuthal_equal_area + proj: +proj=laea +lat_0=55 +lon_0=10 +ellps=WGS84 +units=m +no_defs + shapeOfTheEarth: 5 + grid: 2000./2000. + gaussianNumber: 1280 + latitudeOfFirstGridPointInDegrees: 67.035186732680 + longitudeOfFirstGridPointInDegrees: -39.535385563614 + numberOfPointsAlongXAxis: 1900 + numberOfPointsAlongYAxis: 2200 + + - ORCA2_F: &ORCA2_F + type: ORCA + orca_arrangement: F + orca_name: ORCA2 + dimensions: [182,149] + uid: 174487fbace54b00d959d971e88b71e7 + url: ORCA2_F.atlas + + - ORCA2_T: &ORCA2_T + type: ORCA + orca_arrangement: T + orca_name: ORCA2 + dimensions: [182,149] + uid: d5bde4f52ff3a9bea5629cd9ac514410 + url: ORCA2_T.atlas + + - ORCA2_U: &ORCA2_U + type: ORCA + orca_arrangement: U + orca_name: ORCA2 + dimensions: [182,149] + uid: 857f7affa3a381e3882d38d321384e49 + url: ORCA2_U.atlas + + - ORCA2_V: &ORCA2_V + type: ORCA + orca_arrangement: V + orca_name: ORCA2 + dimensions: [182,149] + uid: ca637bc5dc9a54e2ea4b9750e1b79e6e + url: ORCA2_V.atlas + + - ORCA2_W: &ORCA2_W + type: ORCA + orca_arrangement: W + orca_name: ORCA2 + dimensions: [182,149] + uid: edea6f71eb558dc056b5f576d5b904f7 + url: ORCA2_T.atlas + + - ORCA1_F: &ORCA1_F + type: ORCA + orca_arrangement: F + orca_name: ORCA1 + dimensions: [362,292] + uid: a832a12030c73928133553ec3a8d2a7e + url: ORCA1_F.atlas + + - ORCA1_T: &ORCA1_T + type: ORCA + orca_arrangement: T + orca_name: ORCA1 + dimensions: [362,292] + uid: f4c91b6233fe55dec992160ec12b38df + url: ORCA1_T.atlas + + - ORCA1_U: &ORCA1_U + type: ORCA + orca_arrangement: U + orca_name: ORCA1 + dimensions: [362,292] + uid: 1b0f8d234753f910197c975c906b4da5 + url: ORCA1_U.atlas + + - ORCA1_V: &ORCA1_V + type: ORCA + orca_arrangement: V + orca_name: ORCA1 + dimensions: [362,292] + uid: c637340454795b395f982851b840943d + url: ORCA1_V.atlas + + - ORCA1_W: &ORCA1_W + type: ORCA + orca_arrangement: W + orca_name: ORCA1 + dimensions: [362,292] + uid: d50061c43e83c46c3810002591ea21e1 + url: ORCA1_T.atlas + + - eORCA1_F: &eORCA1_F + type: ORCA + orca_arrangement: F + orca_name: eORCA1 + dimensions: [362,332] + uid: 3c6d95561710c6f39b394809ff6c588c + url: eORCA1_F.atlas + + - eORCA1_T: &eORCA1_T + type: ORCA + orca_arrangement: T + orca_name: eORCA1 + dimensions: [362,332] + uid: ba65665a9e68d1a8fa0352ecfcf8e496 + url: eORCA1_T.atlas + + - eORCA1_U: &eORCA1_U + type: ORCA + orca_arrangement: U + orca_name: eORCA1 + dimensions: [362,332] + uid: 4eb1054957dcae914e219faf9a4068e3 + url: eORCA1_U.atlas + + - eORCA1_V: &eORCA1_V + type: ORCA + orca_arrangement: V + orca_name: eORCA1 + dimensions: [362,332] + uid: 09131429766e7737c087d3a8d7073dc9 + url: eORCA1_V.atlas + + - eORCA1_W: &eORCA1_W + type: ORCA + orca_arrangement: W + orca_name: eORCA1 + dimensions: [362,332] + uid: 5c678d8f9aa2edfbf57246d11d9c1278 + url: eORCA1_T.atlas + + - ORCA025_F: &ORCA025_F + type: ORCA + orca_arrangement: F + orca_name: ORCA025 + dimensions: [1442,1021] + uid: efbc280d8d4b6048797880da2605bacb + url: ORCA025_F.atlas + + - ORCA025_T: &ORCA025_T + type: ORCA + orca_arrangement: T + orca_name: ORCA025 + dimensions: [1442,1021] + uid: 15c961c269ac182ca226d7195f3921ba + url: ORCA025_T.atlas + + - ORCA025_U: &ORCA025_U + type: ORCA + orca_arrangement: U + orca_name: ORCA025 + dimensions: [1442,1021] + uid: 3f4a68bc5b54c9f867fbcc12aacc723d + url: ORCA025_U.atlas + + - ORCA025_V: &ORCA025_V + type: ORCA + orca_arrangement: V + orca_name: ORCA025 + dimensions: [1442,1021] + uid: 9c87699ee2026c0feee07d2a972eaccd + url: ORCA025_V.atlas + + - ORCA025_W: &ORCA025_W + type: ORCA + orca_arrangement: W + orca_name: ORCA025 + dimensions: [1442,1021] + uid: 74ca68f1c8524811f3d3aad99536adc2 + url: ORCA025_T.atlas + + - eORCA025_F: &eORCA025_F + type: ORCA + orca_arrangement: F + orca_name: eORCA025 + dimensions: [1442,1207] + uid: 770e5bbb667a253d55db8a98a3b2d3a9 + url: eORCA025_F.atlas + + - eORCA025_T: &eORCA025_T + type: ORCA + orca_arrangement: T + orca_name: eORCA025 + dimensions: [1442,1207] + uid: 983412216c9768bc794c18dc92082895 + url: eORCA025_T.atlas + + - eORCA025_U: &eORCA025_U + type: ORCA + orca_arrangement: U + orca_name: eORCA025 + dimensions: [1442,1207] + uid: b1b2922e9b57ee9c6eeddad218b6e4f3 + url: eORCA025_U.atlas + + - eORCA025_V: &eORCA025_V + type: ORCA + orca_arrangement: V + orca_name: eORCA025 + dimensions: [1442,1207] + uid: 9b06bf73a8f14e927bd9b0f1f0c04f74 + url: eORCA025_V.atlas + + - eORCA025_W: &eORCA025_W + type: ORCA + orca_arrangement: W + orca_name: eORCA025 + dimensions: [1442,1207] + uid: 4a1ba3b11b8888aefc96992b6b1cab62 + url: eORCA025_T.atlas + + - ORCA12_F: &ORCA12_F + type: ORCA + orca_arrangement: F + orca_name: ORCA12 + dimensions: [4322,3059] + uid: 29693ad8a7af3ae3ee0f02d090f0ec7b + url: ORCA12_F.atlas + + - ORCA12_T: &ORCA12_T + type: ORCA + orca_arrangement: T + orca_name: ORCA12 + dimensions: [4322,3059] + uid: b117d01170ac77bca68560ab10e559de + url: ORCA12_T.atlas + + - ORCA12_U: &ORCA12_U + type: ORCA + orca_arrangement: U + orca_name: ORCA12 + dimensions: [4322,3059] + uid: fff193b92d94d03e847ff2fa62b493f4 + url: ORCA12_U.atlas + + - ORCA12_V: &ORCA12_V + type: ORCA + orca_arrangement: V + orca_name: ORCA12 + dimensions: [4322,3059] + uid: 986e3450774b716f6e75c1987e370b10 + url: ORCA12_V.atlas + + - ORCA12_W: &ORCA12_W + type: ORCA + orca_arrangement: W + orca_name: ORCA12 + dimensions: [4322,3059] + uid: ccfe953619a8dd49a7f765923882a274 + url: ORCA12_T.atlas + + - eORCA12_F: &eORCA12_F + type: ORCA + orca_arrangement: F + orca_name: eORCA12 + dimensions: [4322,3606] + uid: 25da53ed581b3931fa310840fa9aefd9 + url: eORCA12_F.atlas + + - eORCA12_T: &eORCA12_T + type: ORCA + orca_arrangement: T + orca_name: eORCA12 + dimensions: [4322,3606] + uid: 1553b66f5885cf5f83ad4b4fdf25f460 + url: eORCA12_T.atlas + + - eORCA12_U: &eORCA12_U + type: ORCA + orca_arrangement: U + orca_name: eORCA12 + dimensions: [4322,3606] + uid: 3e87c826643da440b4e9d9f67588a576 + url: eORCA12_U.atlas + + - eORCA12_V: &eORCA12_V + type: ORCA + orca_arrangement: V + orca_name: eORCA12 + dimensions: [4322,3606] + uid: cc1e3fc06a2cd18c0653e557510b8a71 + url: eORCA12_V.atlas + + - eORCA12_W: &eORCA12_W + type: ORCA + orca_arrangement: W + orca_name: eORCA12 + dimensions: [4322,3606] + uid: 462469edbd0e0586a0cf17424cc58c89 + url: eORCA12_T.atlas + +grid-uids: + - 174487fbace54b00d959d971e88b71e7: *ORCA2_F + - d5bde4f52ff3a9bea5629cd9ac514410: *ORCA2_T + - 857f7affa3a381e3882d38d321384e49: *ORCA2_U + - ca637bc5dc9a54e2ea4b9750e1b79e6e: *ORCA2_V + - edea6f71eb558dc056b5f576d5b904f7: *ORCA2_W + - a832a12030c73928133553ec3a8d2a7e: *ORCA1_F + - f4c91b6233fe55dec992160ec12b38df: *ORCA1_T + - 1b0f8d234753f910197c975c906b4da5: *ORCA1_U + - c637340454795b395f982851b840943d: *ORCA1_V + - d50061c43e83c46c3810002591ea21e1: *ORCA1_W + - 3c6d95561710c6f39b394809ff6c588c: *eORCA1_F + - ba65665a9e68d1a8fa0352ecfcf8e496: *eORCA1_T + - 4eb1054957dcae914e219faf9a4068e3: *eORCA1_U + - 09131429766e7737c087d3a8d7073dc9: *eORCA1_V + - 5c678d8f9aa2edfbf57246d11d9c1278: *eORCA1_W + - efbc280d8d4b6048797880da2605bacb: *ORCA025_F + - 15c961c269ac182ca226d7195f3921ba: *ORCA025_T + - 3f4a68bc5b54c9f867fbcc12aacc723d: *ORCA025_U + - 9c87699ee2026c0feee07d2a972eaccd: *ORCA025_V + - 74ca68f1c8524811f3d3aad99536adc2: *ORCA025_W + - 770e5bbb667a253d55db8a98a3b2d3a9: *eORCA025_F + - 983412216c9768bc794c18dc92082895: *eORCA025_T + - b1b2922e9b57ee9c6eeddad218b6e4f3: *eORCA025_U + - 9b06bf73a8f14e927bd9b0f1f0c04f74: *eORCA025_V + - 4a1ba3b11b8888aefc96992b6b1cab62: *eORCA025_W + - 29693ad8a7af3ae3ee0f02d090f0ec7b: *ORCA12_F + - b117d01170ac77bca68560ab10e559de: *ORCA12_T + - fff193b92d94d03e847ff2fa62b493f4: *ORCA12_U + - 986e3450774b716f6e75c1987e370b10: *ORCA12_V + - ccfe953619a8dd49a7f765923882a274: *ORCA12_W + - 25da53ed581b3931fa310840fa9aefd9: *eORCA12_F + - 1553b66f5885cf5f83ad4b4fdf25f460: *eORCA12_T + - 3e87c826643da440b4e9d9f67588a576: *eORCA12_U + - cc1e3fc06a2cd18c0653e557510b8a71: *eORCA12_V + - 462469edbd0e0586a0cf17424cc58c89: *eORCA12_W + - 16076978a048410747dd7c9876677b28: *eORCA1_T # Deprecated uid computed via multio + - 7378487847e050559b82d0792374a705: *eORCA1_U # Deprecated uid computed via multio + - d9622b55f3120eafb3dbaf5c742bc56c: *eORCA1_V # Deprecated uid computed via multio + - 0067c81a4154eaa5187f9b0f53e9df7e: *eORCA1_W # Deprecated uid computed via multio + From 53bc06446496b9f71f09262681f5980f469afb4b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 16 Aug 2023 23:55:43 +0100 Subject: [PATCH 296/737] eckit::geometry, eckit::cmd --- src/eckit/geometry/CMakeLists.txt | 2 + src/eckit/geometry/LibEcKitGeometry.cc | 50 ++++++++++++++++ src/eckit/geometry/LibEcKitGeometry.h | 81 ++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) create mode 100644 src/eckit/geometry/LibEcKitGeometry.cc create mode 100644 src/eckit/geometry/LibEcKitGeometry.h diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index 18dbb1151..d60a9d076 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -21,6 +21,8 @@ list( APPEND eckit_geometry_srcs Iterator.h KPoint.cc KPoint.h + LibEcKitGeometry.cc + LibEcKitGeometry.h Ordering.h Point.cc Point.h diff --git a/src/eckit/geometry/LibEcKitGeometry.cc b/src/eckit/geometry/LibEcKitGeometry.cc new file mode 100644 index 000000000..5eca7b64a --- /dev/null +++ b/src/eckit/geometry/LibEcKitGeometry.cc @@ -0,0 +1,50 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/LibEcKitGeometry.h" + +#include "eckit/eckit_version.h" + + +namespace eckit { + + +REGISTER_LIBRARY(LibEcKitGeometry); + + +LibEcKitGeometry::LibEcKitGeometry() : + Library("eckit_geometry") {} + + +LibEcKitGeometry& LibEcKitGeometry::instance() { + static LibEcKitGeometry lib; + return lib; +} + + +const void* LibEcKitGeometry::addr() const { + return this; +} + + +std::string LibEcKitGeometry::version() const { + return eckit_version_str(); +} + + +std::string LibEcKitGeometry::gitsha1(unsigned int count) const { + std::string sha1(eckit_git_sha1()); + return sha1.empty() ? "not available" : sha1.substr(0, std::min(count, 40U)); +} + + +} // namespace eckit diff --git a/src/eckit/geometry/LibEcKitGeometry.h b/src/eckit/geometry/LibEcKitGeometry.h new file mode 100644 index 000000000..0e1f65a1d --- /dev/null +++ b/src/eckit/geometry/LibEcKitGeometry.h @@ -0,0 +1,81 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/system/Library.h" + +namespace eckit { + + +class LibEcKitGeometry final : public system::Library { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + // None + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + static LibEcKitGeometry& instance(); + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Constructors + + LibEcKitGeometry(); + + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + const void* addr() const override; + std::string version() const override; + std::string gitsha1(unsigned int count) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit From a5bb2239aa9e854d28a7d05c07e64e4b63dee633 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 17 Aug 2023 01:39:06 +0100 Subject: [PATCH 297/737] eckit::geometry --- src/eckit/geometry/LibEcKitGeometry.cc | 8 ++++++++ src/eckit/geometry/LibEcKitGeometry.h | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/src/eckit/geometry/LibEcKitGeometry.cc b/src/eckit/geometry/LibEcKitGeometry.cc index 5eca7b64a..5213d120c 100644 --- a/src/eckit/geometry/LibEcKitGeometry.cc +++ b/src/eckit/geometry/LibEcKitGeometry.cc @@ -12,7 +12,9 @@ #include "eckit/geometry/LibEcKitGeometry.h" +#include "eckit/config/Resource.h" #include "eckit/eckit_version.h" +#include "eckit/filesystem/PathName.h" namespace eckit { @@ -31,6 +33,12 @@ LibEcKitGeometry& LibEcKitGeometry::instance() { } +PathName LibEcKitGeometry::configFileGrid() { + static const PathName path{eckit::LibResource("eckit-geometry-grid;$ECKIT_GEOMETRY_GRID", "~eckit/etc/eckit/geometry/grid.yaml")}; + return path; +} + + const void* LibEcKitGeometry::addr() const { return this; } diff --git a/src/eckit/geometry/LibEcKitGeometry.h b/src/eckit/geometry/LibEcKitGeometry.h index 0e1f65a1d..ed502e3bb 100644 --- a/src/eckit/geometry/LibEcKitGeometry.h +++ b/src/eckit/geometry/LibEcKitGeometry.h @@ -14,6 +14,12 @@ #include "eckit/system/Library.h" + +namespace eckit { +class PathName; +} + + namespace eckit { @@ -40,6 +46,7 @@ class LibEcKitGeometry final : public system::Library { // -- Methods static LibEcKitGeometry& instance(); + static eckit::PathName configFileGrid(); // -- Overridden methods // None From 94cfb525d07bfcc91443c27e8728539fc893f685 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 17 Aug 2023 01:39:46 +0100 Subject: [PATCH 298/737] eckit::geometry, eckit::config --- src/eckit/config/DynamicConfiguration.cc | 30 +++++++------- src/eckit/config/DynamicConfiguration.h | 34 ++++++++------- src/eckit/config/MappedConfiguration.cc | 30 +++++++------- src/eckit/config/MappedConfiguration.h | 34 ++++++++------- src/tools/CMakeLists.txt | 6 +++ src/tools/eckit-grid-list.cc | 53 ++++++++++++++++++++++++ src/tools/eckit-grid.cc | 13 ++---- 7 files changed, 128 insertions(+), 72 deletions(-) create mode 100644 src/tools/eckit-grid-list.cc diff --git a/src/eckit/config/DynamicConfiguration.cc b/src/eckit/config/DynamicConfiguration.cc index a82dbe7a3..5bb84f640 100644 --- a/src/eckit/config/DynamicConfiguration.cc +++ b/src/eckit/config/DynamicConfiguration.cc @@ -36,77 +36,77 @@ DynamicConfiguration::DynamicConfiguration(const Configuration& passive) : Configuration(__empty_root), passive_(passive) {} -void DynamicConfiguration::set(const std::string& name, std::string& value) { +void DynamicConfiguration::set(const std::string& name, const std::string& value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, bool& value) { +void DynamicConfiguration::set(const std::string& name, bool value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, int& value) { +void DynamicConfiguration::set(const std::string& name, int value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, long& value) { +void DynamicConfiguration::set(const std::string& name, long value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, long long& value) { +void DynamicConfiguration::set(const std::string& name, long long value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, std::size_t& value) { +void DynamicConfiguration::set(const std::string& name, std::size_t value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, float& value) { +void DynamicConfiguration::set(const std::string& name, float value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, double& value) { +void DynamicConfiguration::set(const std::string& name, double value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, std::vector& value) { +void DynamicConfiguration::set(const std::string& name, const std::vector& value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, std::vector& value) { +void DynamicConfiguration::set(const std::string& name, const std::vector& value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, std::vector& value) { +void DynamicConfiguration::set(const std::string& name, const std::vector& value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, std::vector& value) { +void DynamicConfiguration::set(const std::string& name, const std::vector& value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, std::vector& value) { +void DynamicConfiguration::set(const std::string& name, const std::vector& value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, std::vector& value) { +void DynamicConfiguration::set(const std::string& name, const std::vector& value) { __set(*this, name, value); } -void DynamicConfiguration::set(const std::string& name, std::vector& value) { +void DynamicConfiguration::set(const std::string& name, const std::vector& value) { __set(*this, name, value); } diff --git a/src/eckit/config/DynamicConfiguration.h b/src/eckit/config/DynamicConfiguration.h index ff5d5bcfa..124cbacd5 100644 --- a/src/eckit/config/DynamicConfiguration.h +++ b/src/eckit/config/DynamicConfiguration.h @@ -44,22 +44,24 @@ class DynamicConfiguration : public Configuration { // -- Methods - void set(const std::string&, std::string&); - void set(const std::string&, bool&); - void set(const std::string&, int&); - void set(const std::string&, long&); - void set(const std::string&, long long&); - void set(const std::string&, std::size_t&); - void set(const std::string&, float&); - void set(const std::string&, double&); - - void set(const std::string&, std::vector&); - void set(const std::string&, std::vector&); - void set(const std::string&, std::vector&); - void set(const std::string&, std::vector&); - void set(const std::string&, std::vector&); - void set(const std::string&, std::vector&); - void set(const std::string&, std::vector&); + // (consistent with Configured) + void set(const std::string&, const std::string&); + void set(const std::string&, bool); + void set(const std::string&, int); + void set(const std::string&, long); + void set(const std::string&, long long); + void set(const std::string&, std::size_t); + void set(const std::string&, float); + void set(const std::string&, double); + + // (consistent with Configured) + void set(const std::string&, const std::vector&); + void set(const std::string&, const std::vector&); + void set(const std::string&, const std::vector&); + void set(const std::string&, const std::vector&); + void set(const std::string&, const std::vector&); + void set(const std::string&, const std::vector&); + void set(const std::string&, const std::vector&); void hide(const std::string&); void unhide(const std::string&); diff --git a/src/eckit/config/MappedConfiguration.cc b/src/eckit/config/MappedConfiguration.cc index f03510f98..a36164cc3 100644 --- a/src/eckit/config/MappedConfiguration.cc +++ b/src/eckit/config/MappedConfiguration.cc @@ -54,77 +54,77 @@ MappedConfiguration::MappedConfiguration(container_type&& map) : map_(map) {} -void MappedConfiguration::set(const std::string& name, std::string& value) { +void MappedConfiguration::set(const std::string& name, const std::string& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, bool& value) { +void MappedConfiguration::set(const std::string& name, bool value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, int& value) { +void MappedConfiguration::set(const std::string& name, int value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, long& value) { +void MappedConfiguration::set(const std::string& name, long value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, long long& value) { +void MappedConfiguration::set(const std::string& name, long long value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, std::size_t& value) { +void MappedConfiguration::set(const std::string& name, std::size_t value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, float& value) { +void MappedConfiguration::set(const std::string& name, float value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, double& value) { +void MappedConfiguration::set(const std::string& name, double value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, std::vector& value) { +void MappedConfiguration::set(const std::string& name, const std::vector& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, std::vector& value) { +void MappedConfiguration::set(const std::string& name, const std::vector& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, std::vector& value) { +void MappedConfiguration::set(const std::string& name, const std::vector& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, std::vector& value) { +void MappedConfiguration::set(const std::string& name, const std::vector& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, std::vector& value) { +void MappedConfiguration::set(const std::string& name, const std::vector& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, std::vector& value) { +void MappedConfiguration::set(const std::string& name, const std::vector& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, std::vector& value) { +void MappedConfiguration::set(const std::string& name, const std::vector& value) { map_[name] = value; } diff --git a/src/eckit/config/MappedConfiguration.h b/src/eckit/config/MappedConfiguration.h index f4881a288..5efb24c3f 100644 --- a/src/eckit/config/MappedConfiguration.h +++ b/src/eckit/config/MappedConfiguration.h @@ -63,22 +63,24 @@ class MappedConfiguration : public Configuration { // -- Methods - void set(const std::string&, std::string&); - void set(const std::string&, bool&); - void set(const std::string&, int&); - void set(const std::string&, long&); - void set(const std::string&, long long&); - void set(const std::string&, std::size_t&); - void set(const std::string&, float&); - void set(const std::string&, double&); - - void set(const std::string&, std::vector&); - void set(const std::string&, std::vector&); - void set(const std::string&, std::vector&); - void set(const std::string&, std::vector&); - void set(const std::string&, std::vector&); - void set(const std::string&, std::vector&); - void set(const std::string&, std::vector&); + // (consistent with Configured) + void set(const std::string&, const std::string&); + void set(const std::string&, bool); + void set(const std::string&, int); + void set(const std::string&, long); + void set(const std::string&, long long); + void set(const std::string&, std::size_t); + void set(const std::string&, float); + void set(const std::string&, double); + + // (consistent with Configured) + void set(const std::string&, const std::vector&); + void set(const std::string&, const std::vector&); + void set(const std::string&, const std::vector&); + void set(const std::string&, const std::vector&); + void set(const std::string&, const std::vector&); + void set(const std::string&, const std::vector&); + void set(const std::string&, const std::vector&); // -- Overridden methods diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index b6bbb081f..9231b669e 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -16,6 +16,12 @@ ecbuild_add_executable( TARGET eckit_grid SOURCES eckit-grid.cc LIBS eckit_option eckit_geometry ) +ecbuild_add_executable( TARGET eckit_grid_list + OUTPUT_NAME eckit-grid-list + CONDITION HAVE_BUILD_TOOLS + SOURCES eckit-grid-list.cc + LIBS eckit_option eckit_geometry ) + ### NOT TO INSTALL ecbuild_add_executable( TARGET dhcopy diff --git a/src/tools/eckit-grid-list.cc b/src/tools/eckit-grid-list.cc new file mode 100644 index 000000000..abf05c699 --- /dev/null +++ b/src/tools/eckit-grid-list.cc @@ -0,0 +1,53 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/Grid.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/log/Log.h" +#include "eckit/option/EckitTool.h" +#include "eckit/option/SimpleOption.h" + +#include "eckit/geometry/GridConfig.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit { + +class EckitGrid final : public EckitTool { +public: + EckitGrid(int argc, char** argv) : + EckitTool(argc, argv) { + options_.push_back(new option::SimpleOption("list", "List possible grids")); + } + +private: + void execute(const option::CmdArgs& args) override { + + Log::info() << geometry::GridConfig::instance().config() << std::endl; + + geometry::GridFactory::list(Log::info()); + Log::info() << std::endl; + } + + void usage(const std::string& tool) const override { + Log::info() << "\n" + "Usage: " + << tool << "[options] ..." << std::endl; + } +}; + +} // namespace eckit + +//---------------------------------------------------------------------------------------------------------------------- + +int main(int argc, char** argv) { + eckit::EckitGrid app(argc, argv); + return app.start(); +} diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index 13d20f0c4..bdbbd50f9 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -31,7 +31,6 @@ class EckitGrid final : public EckitTool { public: EckitGrid(int argc, char** argv) : EckitTool(argc, argv) { - options_.push_back(new option::SimpleOption("list", "List possible grids")); options_.push_back(new option::SimpleOption("uid", "by grid unique identifier, instead of name")); options_.push_back(new option::VectorOption("nearest-point", "nearest point location (lon/lat)", 2)); options_.push_back(new option::SimpleOption("nearest-k", "nearest k points")); @@ -39,12 +38,6 @@ class EckitGrid final : public EckitTool { private: void execute(const option::CmdArgs& args) override { - if (args.getBool("list", false)) { - geometry::GridFactory::list(Log::info()); - Log::info() << std::endl; - return; - } - auto uid = args.getBool("uid", false); geometry::PointLonLat nearest_point{0, 0}; @@ -67,9 +60,9 @@ class EckitGrid final : public EckitTool { out << p << std::endl; } - for (const auto& p : geometry::grid::UnstructuredGrid(*grid)) { - out << p << std::endl; - } + // for (const auto& p : geometry::grid::UnstructuredGrid(*grid)) { + // out << p << std::endl; + // } if (nearest_k > 0) { geometry::SearchLonLat search; From 6034ba829a2be1705d5a344d759d40e0ddcde5ea Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 17 Aug 2023 11:04:49 +0100 Subject: [PATCH 299/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 9 +-------- src/eckit/geometry/util/regex.h | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 7941a4f48..5ebe8d3f0 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -226,18 +226,11 @@ const Grid* GridFactoryName::build(const std::string& name) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - auto matches = [](const std::string& s, const std::string& pattern) -> bool { - const std::regex e(pattern, std::regex_constants::extended); - std::smatch match; - std::regex_match(s, match, e); - return !match.empty(); - }; - const auto end = __grid_names->cend(); auto i = end; for (auto j = __grid_names->cbegin(); j != end; ++j) { - if (matches(name, j->second->pattern_)) { + if (util::regex_match(j->second->pattern_, name)) { if (i != end) { throw SeriousBug("Grid: name '" + name + "' matches '" + i->second->pattern_ + "' and '" + j->second->pattern_ + "'"); } diff --git a/src/eckit/geometry/util/regex.h b/src/eckit/geometry/util/regex.h index 6eb211099..c39d1ecf7 100644 --- a/src/eckit/geometry/util/regex.h +++ b/src/eckit/geometry/util/regex.h @@ -20,7 +20,7 @@ namespace eckit::geometry::util { struct regex_match_type : std::smatch { - operator bool() const { return !std::smatch::empty(); } + explicit operator bool() const { return !std::smatch::empty(); } }; From 1e3afb2a5a6fc0f0e04d12a4052fce4796270d10 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 17 Aug 2023 12:14:48 +0100 Subject: [PATCH 300/737] eckit::geometry --- src/eckit/geometry/CMakeLists.txt | 2 + src/eckit/geometry/GridConfig.cc | 107 ++++++++++++++++++++++++++++++ src/eckit/geometry/GridConfig.h | 89 +++++++++++++++++++++++++ 3 files changed, 198 insertions(+) create mode 100644 src/eckit/geometry/GridConfig.cc create mode 100644 src/eckit/geometry/GridConfig.h diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index d60a9d076..6fe0622c7 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -16,6 +16,8 @@ list( APPEND eckit_geometry_srcs GreatCircle.h Grid.cc Grid.h + GridConfig.cc + GridConfig.h Increments.cc Increments.h Iterator.h diff --git a/src/eckit/geometry/GridConfig.cc b/src/eckit/geometry/GridConfig.cc new file mode 100644 index 000000000..4ba3e59f1 --- /dev/null +++ b/src/eckit/geometry/GridConfig.cc @@ -0,0 +1,107 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/GridConfig.h" + +#include "eckit/config/MappedConfiguration.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/filesystem/PathName.h" +#include "eckit/geometry/Grid.h" +#include "eckit/geometry/LibEcKitGeometry.h" +#include "eckit/parser/YAMLParser.h" +#include "eckit/value/Value.h" + + +namespace eckit::geometry { + + +namespace { + + +template +T from_value_t(const Value& from) { + T to; + fromValue(to, from); + return to; +} + + +void set_config_value(MappedConfiguration& config, const std::string& key, const Value& value) { + auto all_values = [](const Value& value, const std::function& pred) -> bool { + ValueList list(value); + return std::all_of(list.begin(), list.end(), pred); + }; + + value.isDouble() ? config.set(key, from_value_t(value)) + : value.isNumber() ? config.set(key, from_value_t(value)) + : value.isBool() ? config.set(key, from_value_t(value)) + : all_values(value, [](const Value& value) { return value.isDouble(); }) ? config.set(key, from_value_t>(value)) + : all_values(value, [](const Value& value) { return value.isNumber(); }) ? config.set(key, from_value_t>(value)) + : all_values(value, [](const Value& value) { return value.isString(); }) ? config.set(key, from_value_t>(value)) + : config.set(key, from_value_t(value)); +} + + +MappedConfiguration* config_from_value_map(const ValueMap& map) { + auto* config = new MappedConfiguration; + for (const auto& kv : map) { + set_config_value(*config, kv.first, kv.second); + } + return config; +} + + +} // namespace + + +const GridConfig& GridConfig::instance() { + static const GridConfig __instance(LibEcKitGeometry::configFileGrid()); + return __instance; +} + + +GridConfig::GridConfig(const PathName& path) { + if (!path.exists()) { + return; + } + + auto* config = new MappedConfiguration; + config_.reset(config); + + ValueMap map(YAMLParser::decodeFile(path)); + + for (const auto& kv : map) { + ASSERT(kv.first.isString()); + const auto key = kv.first.as(); + + if (key == "grid-names") { + for (ValueMap m : static_cast(kv.second)) { + ASSERT(m.size() == 1); + GridFactoryName::insert(m.begin()->first, config_from_value_map(m.begin()->second)); + } + continue; + } + + if (key == "grid-uids") { + for (ValueMap m : static_cast(kv.second)) { + ASSERT(m.size() == 1); + GridFactoryUID::insert(m.begin()->first, config_from_value_map(m.begin()->second)); + } + continue; + } + + set_config_value(*config, key, kv.second); + } +} + + +} // namespace eckit::geometry diff --git a/src/eckit/geometry/GridConfig.h b/src/eckit/geometry/GridConfig.h new file mode 100644 index 000000000..eaf23e8d1 --- /dev/null +++ b/src/eckit/geometry/GridConfig.h @@ -0,0 +1,89 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "eckit/config/Configuration.h" + + +namespace eckit { +class PathName; +} + + +namespace eckit::geometry { + + +class GridConfig final { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + // None + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + static const GridConfig& instance(); + + const Configuration& config() const { return *config_; } + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Constructors + + explicit GridConfig(const PathName&); + + // -- Members + + std::unique_ptr config_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geometry From b5d978afe752479aff69c6a5168d9e640c9a7c17 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 17 Aug 2023 12:14:23 +0100 Subject: [PATCH 301/737] eckit::config --- src/eckit/config/MappedConfiguration.cc | 22 +++++++++++++++++++++- src/eckit/config/MappedConfiguration.h | 9 +++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/eckit/config/MappedConfiguration.cc b/src/eckit/config/MappedConfiguration.cc index a36164cc3..31831be99 100644 --- a/src/eckit/config/MappedConfiguration.cc +++ b/src/eckit/config/MappedConfiguration.cc @@ -49,11 +49,31 @@ MappedConfiguration::MappedConfiguration(const MappedConfiguration::container_ty map_(map) {} -MappedConfiguration::MappedConfiguration(container_type&& map) : +MappedConfiguration::MappedConfiguration(MappedConfiguration::container_type&& map) : Configuration(__empty_root), map_(map) {} +MappedConfiguration::MappedConfiguration(const MappedConfiguration& config) : + MappedConfiguration(config.map_) {} + + +MappedConfiguration::MappedConfiguration(MappedConfiguration&& config) : + MappedConfiguration(config.map_) {} + + +MappedConfiguration& MappedConfiguration::operator=(MappedConfiguration&& config) { + map_.swap(config.map_); + return *this; +} + + +MappedConfiguration& MappedConfiguration::operator=(const MappedConfiguration& config) { + map_ = config.map_; + return *this; +} + + void MappedConfiguration::set(const std::string& name, const std::string& value) { map_[name] = value; } diff --git a/src/eckit/config/MappedConfiguration.h b/src/eckit/config/MappedConfiguration.h index 5efb24c3f..ea8fbe609 100644 --- a/src/eckit/config/MappedConfiguration.h +++ b/src/eckit/config/MappedConfiguration.h @@ -20,7 +20,7 @@ namespace eckit { //---------------------------------------------------------------------------------------------------------------------- -class MappedConfiguration : public Configuration { +class MappedConfiguration final : public Configuration { public: // -- Types @@ -52,6 +52,9 @@ class MappedConfiguration : public Configuration { explicit MappedConfiguration(const container_type& = {}); explicit MappedConfiguration(container_type&&); + MappedConfiguration(const MappedConfiguration&); + MappedConfiguration(MappedConfiguration&&); + // -- Destructor // None @@ -59,7 +62,9 @@ class MappedConfiguration : public Configuration { // None // -- Operators - // None + + MappedConfiguration& operator=(const MappedConfiguration&); + MappedConfiguration& operator=(MappedConfiguration&&); // -- Methods From a33b212280834bf6e5abbdbc138766b5d50d948a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 17 Aug 2023 17:06:24 +0100 Subject: [PATCH 302/737] eckit::config --- src/eckit/config/Configuration.h | 2 +- src/eckit/config/MappedConfiguration.cc | 22 ++++++++++++---------- src/eckit/config/MappedConfiguration.h | 1 + 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/eckit/config/Configuration.h b/src/eckit/config/Configuration.h index 8f08f7802..86d765aa4 100644 --- a/src/eckit/config/Configuration.h +++ b/src/eckit/config/Configuration.h @@ -149,7 +149,7 @@ class Configuration : public Parametrisation { char separator_; private: // methods - void json(JSON& s) const; + virtual void json(JSON& s) const; friend JSON& operator<<(JSON& s, const Configuration& v) { v.json(s); return s; diff --git a/src/eckit/config/MappedConfiguration.cc b/src/eckit/config/MappedConfiguration.cc index 31831be99..a957d06cf 100644 --- a/src/eckit/config/MappedConfiguration.cc +++ b/src/eckit/config/MappedConfiguration.cc @@ -10,8 +10,7 @@ #include "eckit/config/MappedConfiguration.h" -#include - +#include "eckit/log/JSON.h" #include "eckit/value/Value.h" namespace eckit { @@ -35,7 +34,7 @@ bool __get(const MappedConfiguration::container_type& map, const std::string& na } -std::ostream& operator<<(std::ostream& out, const MappedConfiguration::value_type& v) { +JSON& operator<<(JSON& out, const MappedConfiguration::value_type& v) { std::visit([&](auto&& arg) { out << arg; }, v); return out; } @@ -229,16 +228,19 @@ bool MappedConfiguration::get(const std::string& name, std::vector& } -void MappedConfiguration::print(std::ostream& out) const { - out << "MappedConfiguration["; - - const auto* sep = ""; +void MappedConfiguration::json(JSON& j) const { + j.startObject(); for (const auto& nv : map_) { - out << sep << nv.first << ": " << nv.second; - sep = ", "; + j << nv.first; + j << nv.second; } + j.endObject(); +} + - out << "]"; +void MappedConfiguration::print(std::ostream& out) const { + JSON j(out); + json(j); } diff --git a/src/eckit/config/MappedConfiguration.h b/src/eckit/config/MappedConfiguration.h index ea8fbe609..db861284c 100644 --- a/src/eckit/config/MappedConfiguration.h +++ b/src/eckit/config/MappedConfiguration.h @@ -125,6 +125,7 @@ class MappedConfiguration final : public Configuration { // -- Overridden methods void print(std::ostream&) const override; + void json(JSON&) const override; // -- Class members // None From 820310d316fec1bba3231718c88b5d08c46208c0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 23 Aug 2023 01:09:11 +0100 Subject: [PATCH 303/737] eckit::config --- src/eckit/config/MappedConfiguration.cc | 130 ++++++++++++++++++++---- 1 file changed, 112 insertions(+), 18 deletions(-) diff --git a/src/eckit/config/MappedConfiguration.cc b/src/eckit/config/MappedConfiguration.cc index a957d06cf..b6b46ef68 100644 --- a/src/eckit/config/MappedConfiguration.cc +++ b/src/eckit/config/MappedConfiguration.cc @@ -24,11 +24,84 @@ namespace { const eckit::Value __empty_root; +template +bool __get_s(const From& from, To& to) { + to = static_cast(from); + return true; +} + + +template +bool __get_s(const From& from, From& to) { + to = from; + return true; +} + + +template +bool __get_v(const std::vector& from, std::vector& to) { + to.clear(); + for (const auto& f : from) { + to.emplace_back(static_cast(f)); + } + return true; +} + + +template +bool __get_v(const std::vector& from, std::vector& to) { + to = from; + return true; +} + + template -bool __get(const MappedConfiguration::container_type& map, const std::string& name, T& value) { +bool __get_s_integral(const MappedConfiguration::container_type& map, const std::string& name, T& value) { if (auto it = map.find(name); it != map.cend()) { - value = std::get(it->second); - return true; + const auto& v = it->second; + return std::holds_alternative(v) ? __get_s(std::get(v), value) + : std::holds_alternative(v) ? __get_s(std::get(v), value) + : std::holds_alternative(v) ? __get_s(std::get(v), value) + : std::holds_alternative(v) ? __get_s(std::get(v), value) + : false; + } + return false; +} + + +template +bool __get_s_real(const MappedConfiguration::container_type& map, const std::string& name, T& value) { + if (auto it = map.find(name); it != map.cend()) { + const auto& v = it->second; + return std::holds_alternative(v) ? __get_s(std::get(v), value) + : std::holds_alternative(v) ? __get_s(std::get(v), value) + : false; + } + return false; +} + + +template +bool __get_v_integral(const MappedConfiguration::container_type& map, const std::string& name, T& value) { + if (auto it = map.find(name); it != map.cend()) { + const auto& v = it->second; + return std::holds_alternative>(v) ? __get_v(std::get>(v), value) + : std::holds_alternative>(v) ? __get_v(std::get>(v), value) + : std::holds_alternative>(v) ? __get_v(std::get>(v), value) + : std::holds_alternative>(v) ? __get_v(std::get>(v), value) + : false; + } + return false; +} + + +template +bool __get_v_real(const MappedConfiguration::container_type& map, const std::string& name, T& value) { + if (auto it = map.find(name); it != map.cend()) { + const auto& v = it->second; + return std::holds_alternative>(v) ? __get_v(std::get>(v), value) + : std::holds_alternative>(v) ? __get_v(std::get>(v), value) + : false; } return false; } @@ -154,77 +227,98 @@ bool MappedConfiguration::has(const std::string& name) const { bool MappedConfiguration::get(const std::string& name, std::string& value) const { - return __get(map_, name, value); + if (auto it = map_.find(name); it != map_.cend()) { + value = std::holds_alternative(it->second) ? std::get(it->second) + : std::visit([](auto&& arg) -> std::string { return (std::ostringstream() << arg).str(); }, it->second); + return true; + } + return false; } bool MappedConfiguration::get(const std::string& name, bool& value) const { - return __get(map_, name, value); + if (auto it = map_.find(name); it != map_.cend()) { + if (std::holds_alternative(it->second)) { + std::get(it->second); + return true; + } + + if (int i = 0; __get_s_integral(map_, name, i)) { + value = i != 0; + return true; + } + } + return false; } bool MappedConfiguration::get(const std::string& name, int& value) const { - return __get(map_, name, value); + return __get_s_integral(map_, name, value); } bool MappedConfiguration::get(const std::string& name, long& value) const { - return __get(map_, name, value); + return __get_s_integral(map_, name, value); } bool MappedConfiguration::get(const std::string& name, long long& value) const { - return __get(map_, name, value); + return __get_s_integral(map_, name, value); } bool MappedConfiguration::get(const std::string& name, std::size_t& value) const { - return __get(map_, name, value); + return __get_s_integral(map_, name, value); } bool MappedConfiguration::get(const std::string& name, float& value) const { - return __get(map_, name, value); + return __get_s_real(map_, name, value); } bool MappedConfiguration::get(const std::string& name, double& value) const { - return __get(map_, name, value); + return __get_s_real(map_, name, value); } bool MappedConfiguration::get(const std::string& name, std::vector& value) const { - return __get(map_, name, value); + return __get_v_integral(map_, name, value); } bool MappedConfiguration::get(const std::string& name, std::vector& value) const { - return __get(map_, name, value); + return __get_v_integral(map_, name, value); } bool MappedConfiguration::get(const std::string& name, std::vector& value) const { - return __get(map_, name, value); + return __get_v_integral(map_, name, value); } bool MappedConfiguration::get(const std::string& name, std::vector& value) const { - return __get(map_, name, value); + return __get_v_integral(map_, name, value); } bool MappedConfiguration::get(const std::string& name, std::vector& value) const { - return __get(map_, name, value); + return __get_v_real(map_, name, value); } bool MappedConfiguration::get(const std::string& name, std::vector& value) const { - return __get(map_, name, value); + return __get_v_real(map_, name, value); } bool MappedConfiguration::get(const std::string& name, std::vector& value) const { - return __get(map_, name, value); + auto it = map_.find(name); + if (it != map_.cend() && std::holds_alternative>(it->second)) { + value = std::get>(it->second); + return true; + } + return false; } From 84289c0499a4e8bb4a63c0a9fa49e1c976745d64 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 17 Aug 2023 17:06:52 +0100 Subject: [PATCH 304/737] eckit::geometry --- src/eckit/geometry/GridConfig.cc | 68 +++++++++++++++----------------- 1 file changed, 32 insertions(+), 36 deletions(-) diff --git a/src/eckit/geometry/GridConfig.cc b/src/eckit/geometry/GridConfig.cc index 4ba3e59f1..5593e1d69 100644 --- a/src/eckit/geometry/GridConfig.cc +++ b/src/eckit/geometry/GridConfig.cc @@ -28,26 +28,25 @@ namespace { template -T from_value_t(const Value& from) { +MappedConfiguration::value_type __from_value_list(const ValueList& list) { + if (list.size() == 1) { + typename T::value_type to; + fromValue(to, list[0]); + return {to}; + } + T to; - fromValue(to, from); - return to; + fromValue(to, list); + return {to}; } void set_config_value(MappedConfiguration& config, const std::string& key, const Value& value) { - auto all_values = [](const Value& value, const std::function& pred) -> bool { - ValueList list(value); - return std::all_of(list.begin(), list.end(), pred); - }; - - value.isDouble() ? config.set(key, from_value_t(value)) - : value.isNumber() ? config.set(key, from_value_t(value)) - : value.isBool() ? config.set(key, from_value_t(value)) - : all_values(value, [](const Value& value) { return value.isDouble(); }) ? config.set(key, from_value_t>(value)) - : all_values(value, [](const Value& value) { return value.isNumber(); }) ? config.set(key, from_value_t>(value)) - : all_values(value, [](const Value& value) { return value.isString(); }) ? config.set(key, from_value_t>(value)) - : config.set(key, from_value_t(value)); + ValueList list(value); + auto val = std::all_of(list.begin(), list.end(), [](const Value& v) { return v.isDouble(); }) ? __from_value_list>(list) + : std::all_of(list.begin(), list.end(), [](const Value& v) { return v.isNumber(); }) ? __from_value_list>(list) + : __from_value_list>(list); + std::visit([&](const auto& val) { config.set(key, val); }, val); } @@ -70,36 +69,33 @@ const GridConfig& GridConfig::instance() { GridConfig::GridConfig(const PathName& path) { - if (!path.exists()) { - return; - } - auto* config = new MappedConfiguration; config_.reset(config); - ValueMap map(YAMLParser::decodeFile(path)); + if (path.exists()) { + ValueMap map(YAMLParser::decodeFile(path)); - for (const auto& kv : map) { - ASSERT(kv.first.isString()); - const auto key = kv.first.as(); + for (const auto& kv : map) { + const auto key = kv.first.as(); - if (key == "grid-names") { - for (ValueMap m : static_cast(kv.second)) { - ASSERT(m.size() == 1); - GridFactoryName::insert(m.begin()->first, config_from_value_map(m.begin()->second)); + if (key == "grid_names") { + for (ValueMap m : static_cast(kv.second)) { + ASSERT(m.size() == 1); + GridFactoryName::insert(m.begin()->first, config_from_value_map(m.begin()->second)); + } + continue; } - continue; - } - if (key == "grid-uids") { - for (ValueMap m : static_cast(kv.second)) { - ASSERT(m.size() == 1); - GridFactoryUID::insert(m.begin()->first, config_from_value_map(m.begin()->second)); + if (key == "grid_uids") { + for (ValueMap m : static_cast(kv.second)) { + ASSERT(m.size() == 1); + GridFactoryUID::insert(m.begin()->first, config_from_value_map(m.begin()->second)); + } + continue; } - continue; - } - set_config_value(*config, key, kv.second); + set_config_value(*config, key, kv.second); + } } } From c723ec0d566fc64d38e4bd12226f76c1f97fafdd Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 17 Aug 2023 17:12:01 +0100 Subject: [PATCH 305/737] eckit::geometry --- etc/eckit/geometry/grid.yaml | 125 ++++++++++++++--------- src/eckit/config/MappedConfiguration.cc | 4 +- src/eckit/geometry/Grid.cc | 127 ++++++++++++++++++------ src/eckit/geometry/Grid.h | 32 ++++-- src/eckit/geometry/grid/HEALPix.cc | 2 +- src/eckit/geometry/grid/ReducedGG.cc | 4 +- src/eckit/geometry/grid/RegularGG.cc | 2 +- src/eckit/geometry/grid/RegularLL.cc | 2 +- src/tools/eckit-grid-list.cc | 32 +++--- 9 files changed, 219 insertions(+), 111 deletions(-) diff --git a/etc/eckit/geometry/grid.yaml b/etc/eckit/geometry/grid.yaml index 6024651eb..a59e2b01d 100644 --- a/etc/eckit/geometry/grid.yaml +++ b/etc/eckit/geometry/grid.yaml @@ -1,28 +1,28 @@ --- -orca-url-prefix: "https://get.ecmwf.int/repository/atlas/grids/orca/v0" -orca-validate-uid: false # Validates UID upon grid creation -orca-compute-uid: false # Recompute UID and ignore encoded UID +orca_url_prefix: &orca_url_prefix https://get.ecmwf.int/repository/atlas/grids/orca/v0/ +orca_validate_uid: false # Validates UID upon grid creation +orca_compute_uid: false # Recompute UID and ignore encoded UID -grid-names: +grid_names: - LAEA-EFAS-5km: type: lambert_azimuthal_equal_area + proj: +proj=laea +lat_0=52 +lon_0=10 +ellps=GRS80 +units=m +no_defs + shapeOfTheEarth: 4 + grid: [5000., 5000.] + gaussianNumber: 1280 standardParallelInDegrees: 52. centralLongitudeInDegrees: 10. - grid: 5000./5000. - gaussianNumber: 1280 latitudeOfFirstGridPointInDegrees: 66.982143 longitudeOfFirstGridPointInDegrees: -35.034024 numberOfPointsAlongXAxis: 1000 numberOfPointsAlongYAxis: 950 - proj: +proj=laea +lat_0=52 +lon_0=10 +ellps=GRS80 +units=m +no_defs - shapeOfTheEarth: 4 - SMUFF-OPERA-2km: type: lambert_azimuthal_equal_area proj: +proj=laea +lat_0=55 +lon_0=10 +ellps=WGS84 +units=m +no_defs shapeOfTheEarth: 5 - grid: 2000./2000. + grid: [2000., 2000.] gaussianNumber: 1280 latitudeOfFirstGridPointInDegrees: 67.035186732680 longitudeOfFirstGridPointInDegrees: -39.535385563614 @@ -33,283 +33,318 @@ grid-names: type: ORCA orca_arrangement: F orca_name: ORCA2 - dimensions: [182,149] + dimensions: [182, 149] uid: 174487fbace54b00d959d971e88b71e7 + url_prefix: *orca_url_prefix url: ORCA2_F.atlas - ORCA2_T: &ORCA2_T type: ORCA orca_arrangement: T orca_name: ORCA2 - dimensions: [182,149] + dimensions: [182, 149] uid: d5bde4f52ff3a9bea5629cd9ac514410 + url_prefix: *orca_url_prefix url: ORCA2_T.atlas - ORCA2_U: &ORCA2_U type: ORCA orca_arrangement: U orca_name: ORCA2 - dimensions: [182,149] + dimensions: [182, 149] uid: 857f7affa3a381e3882d38d321384e49 + url_prefix: *orca_url_prefix url: ORCA2_U.atlas - ORCA2_V: &ORCA2_V type: ORCA orca_arrangement: V orca_name: ORCA2 - dimensions: [182,149] + dimensions: [182, 149] uid: ca637bc5dc9a54e2ea4b9750e1b79e6e + url_prefix: *orca_url_prefix url: ORCA2_V.atlas - ORCA2_W: &ORCA2_W type: ORCA orca_arrangement: W orca_name: ORCA2 - dimensions: [182,149] + dimensions: [182, 149] uid: edea6f71eb558dc056b5f576d5b904f7 + url_prefix: *orca_url_prefix url: ORCA2_T.atlas - ORCA1_F: &ORCA1_F type: ORCA orca_arrangement: F orca_name: ORCA1 - dimensions: [362,292] + dimensions: [362, 292] uid: a832a12030c73928133553ec3a8d2a7e + url_prefix: *orca_url_prefix url: ORCA1_F.atlas - ORCA1_T: &ORCA1_T type: ORCA orca_arrangement: T orca_name: ORCA1 - dimensions: [362,292] + dimensions: [362, 292] uid: f4c91b6233fe55dec992160ec12b38df + url_prefix: *orca_url_prefix url: ORCA1_T.atlas - ORCA1_U: &ORCA1_U type: ORCA orca_arrangement: U orca_name: ORCA1 - dimensions: [362,292] + dimensions: [362, 292] uid: 1b0f8d234753f910197c975c906b4da5 + url_prefix: *orca_url_prefix url: ORCA1_U.atlas - ORCA1_V: &ORCA1_V type: ORCA orca_arrangement: V orca_name: ORCA1 - dimensions: [362,292] + dimensions: [362, 292] uid: c637340454795b395f982851b840943d + url_prefix: *orca_url_prefix url: ORCA1_V.atlas - ORCA1_W: &ORCA1_W type: ORCA orca_arrangement: W orca_name: ORCA1 - dimensions: [362,292] + dimensions: [362, 292] uid: d50061c43e83c46c3810002591ea21e1 + url_prefix: *orca_url_prefix url: ORCA1_T.atlas - eORCA1_F: &eORCA1_F type: ORCA orca_arrangement: F orca_name: eORCA1 - dimensions: [362,332] + dimensions: [362, 332] uid: 3c6d95561710c6f39b394809ff6c588c + url_prefix: *orca_url_prefix url: eORCA1_F.atlas - eORCA1_T: &eORCA1_T type: ORCA orca_arrangement: T orca_name: eORCA1 - dimensions: [362,332] + dimensions: [362, 332] uid: ba65665a9e68d1a8fa0352ecfcf8e496 + url_prefix: *orca_url_prefix url: eORCA1_T.atlas - eORCA1_U: &eORCA1_U type: ORCA orca_arrangement: U orca_name: eORCA1 - dimensions: [362,332] + dimensions: [362, 332] uid: 4eb1054957dcae914e219faf9a4068e3 + url_prefix: *orca_url_prefix url: eORCA1_U.atlas - eORCA1_V: &eORCA1_V type: ORCA orca_arrangement: V orca_name: eORCA1 - dimensions: [362,332] + dimensions: [362, 332] uid: 09131429766e7737c087d3a8d7073dc9 + url_prefix: *orca_url_prefix url: eORCA1_V.atlas - eORCA1_W: &eORCA1_W type: ORCA orca_arrangement: W orca_name: eORCA1 - dimensions: [362,332] + dimensions: [362, 332] uid: 5c678d8f9aa2edfbf57246d11d9c1278 + url_prefix: *orca_url_prefix url: eORCA1_T.atlas - ORCA025_F: &ORCA025_F type: ORCA orca_arrangement: F orca_name: ORCA025 - dimensions: [1442,1021] + dimensions: [1442, 1021] uid: efbc280d8d4b6048797880da2605bacb + url_prefix: *orca_url_prefix url: ORCA025_F.atlas - ORCA025_T: &ORCA025_T type: ORCA orca_arrangement: T orca_name: ORCA025 - dimensions: [1442,1021] + dimensions: [1442, 1021] uid: 15c961c269ac182ca226d7195f3921ba + url_prefix: *orca_url_prefix url: ORCA025_T.atlas - ORCA025_U: &ORCA025_U type: ORCA orca_arrangement: U orca_name: ORCA025 - dimensions: [1442,1021] + dimensions: [1442, 1021] uid: 3f4a68bc5b54c9f867fbcc12aacc723d + url_prefix: *orca_url_prefix url: ORCA025_U.atlas - ORCA025_V: &ORCA025_V type: ORCA orca_arrangement: V orca_name: ORCA025 - dimensions: [1442,1021] + dimensions: [1442, 1021] uid: 9c87699ee2026c0feee07d2a972eaccd + url_prefix: *orca_url_prefix url: ORCA025_V.atlas - ORCA025_W: &ORCA025_W type: ORCA orca_arrangement: W orca_name: ORCA025 - dimensions: [1442,1021] + dimensions: [1442, 1021] uid: 74ca68f1c8524811f3d3aad99536adc2 + url_prefix: *orca_url_prefix url: ORCA025_T.atlas - eORCA025_F: &eORCA025_F type: ORCA orca_arrangement: F orca_name: eORCA025 - dimensions: [1442,1207] + dimensions: [1442, 1207] uid: 770e5bbb667a253d55db8a98a3b2d3a9 + url_prefix: *orca_url_prefix url: eORCA025_F.atlas - eORCA025_T: &eORCA025_T type: ORCA orca_arrangement: T orca_name: eORCA025 - dimensions: [1442,1207] + dimensions: [1442, 1207] uid: 983412216c9768bc794c18dc92082895 + url_prefix: *orca_url_prefix url: eORCA025_T.atlas - eORCA025_U: &eORCA025_U type: ORCA orca_arrangement: U orca_name: eORCA025 - dimensions: [1442,1207] + dimensions: [1442, 1207] uid: b1b2922e9b57ee9c6eeddad218b6e4f3 + url_prefix: *orca_url_prefix url: eORCA025_U.atlas - eORCA025_V: &eORCA025_V type: ORCA orca_arrangement: V orca_name: eORCA025 - dimensions: [1442,1207] + dimensions: [1442, 1207] uid: 9b06bf73a8f14e927bd9b0f1f0c04f74 + url_prefix: *orca_url_prefix url: eORCA025_V.atlas - eORCA025_W: &eORCA025_W type: ORCA orca_arrangement: W orca_name: eORCA025 - dimensions: [1442,1207] + dimensions: [1442, 1207] uid: 4a1ba3b11b8888aefc96992b6b1cab62 + url_prefix: *orca_url_prefix url: eORCA025_T.atlas - ORCA12_F: &ORCA12_F type: ORCA orca_arrangement: F orca_name: ORCA12 - dimensions: [4322,3059] + dimensions: [4322, 3059] uid: 29693ad8a7af3ae3ee0f02d090f0ec7b + url_prefix: *orca_url_prefix url: ORCA12_F.atlas - ORCA12_T: &ORCA12_T type: ORCA orca_arrangement: T orca_name: ORCA12 - dimensions: [4322,3059] + dimensions: [4322, 3059] uid: b117d01170ac77bca68560ab10e559de + url_prefix: *orca_url_prefix url: ORCA12_T.atlas - ORCA12_U: &ORCA12_U type: ORCA orca_arrangement: U orca_name: ORCA12 - dimensions: [4322,3059] + dimensions: [4322, 3059] uid: fff193b92d94d03e847ff2fa62b493f4 + url_prefix: *orca_url_prefix url: ORCA12_U.atlas - ORCA12_V: &ORCA12_V type: ORCA orca_arrangement: V orca_name: ORCA12 - dimensions: [4322,3059] + dimensions: [4322, 3059] uid: 986e3450774b716f6e75c1987e370b10 + url_prefix: *orca_url_prefix url: ORCA12_V.atlas - ORCA12_W: &ORCA12_W type: ORCA orca_arrangement: W orca_name: ORCA12 - dimensions: [4322,3059] + dimensions: [4322, 3059] uid: ccfe953619a8dd49a7f765923882a274 + url_prefix: *orca_url_prefix url: ORCA12_T.atlas - eORCA12_F: &eORCA12_F type: ORCA orca_arrangement: F orca_name: eORCA12 - dimensions: [4322,3606] + dimensions: [4322, 3606] uid: 25da53ed581b3931fa310840fa9aefd9 + url_prefix: *orca_url_prefix url: eORCA12_F.atlas - eORCA12_T: &eORCA12_T type: ORCA orca_arrangement: T orca_name: eORCA12 - dimensions: [4322,3606] + dimensions: [4322, 3606] uid: 1553b66f5885cf5f83ad4b4fdf25f460 + url_prefix: *orca_url_prefix url: eORCA12_T.atlas - eORCA12_U: &eORCA12_U type: ORCA orca_arrangement: U orca_name: eORCA12 - dimensions: [4322,3606] + dimensions: [4322, 3606] uid: 3e87c826643da440b4e9d9f67588a576 + url_prefix: *orca_url_prefix url: eORCA12_U.atlas - eORCA12_V: &eORCA12_V type: ORCA orca_arrangement: V orca_name: eORCA12 - dimensions: [4322,3606] + dimensions: [4322, 3606] uid: cc1e3fc06a2cd18c0653e557510b8a71 + url_prefix: *orca_url_prefix url: eORCA12_V.atlas - eORCA12_W: &eORCA12_W type: ORCA orca_arrangement: W orca_name: eORCA12 - dimensions: [4322,3606] + dimensions: [4322, 3606] uid: 462469edbd0e0586a0cf17424cc58c89 + url_prefix: *orca_url_prefix url: eORCA12_T.atlas -grid-uids: +grid_uids: - 174487fbace54b00d959d971e88b71e7: *ORCA2_F - d5bde4f52ff3a9bea5629cd9ac514410: *ORCA2_T - 857f7affa3a381e3882d38d321384e49: *ORCA2_U diff --git a/src/eckit/config/MappedConfiguration.cc b/src/eckit/config/MappedConfiguration.cc index b6b46ef68..13140e0e8 100644 --- a/src/eckit/config/MappedConfiguration.cc +++ b/src/eckit/config/MappedConfiguration.cc @@ -107,8 +107,8 @@ bool __get_v_real(const MappedConfiguration::container_type& map, const std::str } -JSON& operator<<(JSON& out, const MappedConfiguration::value_type& v) { - std::visit([&](auto&& arg) { out << arg; }, v); +JSON& operator<<(JSON& out, const MappedConfiguration::value_type& value) { + std::visit([&](const auto& arg) { out << arg; }, value); return out; } diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 5ebe8d3f0..ebb6bff5f 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -15,10 +15,12 @@ #include #include #include -#include #include +#include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geometry/GridConfig.h" +#include "eckit/geometry/util/regex.h" #include "eckit/log/JSON.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" @@ -113,6 +115,8 @@ const Grid* GridFactory::build(const Configuration& config) { pthread_once(&__once, __init); AutoLock lock(*__mutex); + GridConfig::instance(); + if (std::string uid; config.get("uid", uid)) { return GridFactoryUID::build(uid); } @@ -134,30 +138,29 @@ void GridFactory::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - JSON j(out); - j.startObject(); + GridConfig::instance(); - j << "uid"; - j.startList(); - for (const auto& p : *__grid_uids) { - j << p.first; - } - j.endList(); + GridFactoryUID::list(out << "uid: "); + out << std::endl; - j << "name"; - j.startList(); - for (const auto& p : *__grid_names) { - j << p.first; - } - j.endList(); + GridFactoryName::list(out << "name: "); + out << std::endl; - j << "type"; - j.startList(); - for (const auto& p : *__grid_types) { - j << p.first; - } - j.endList(); + GridFactoryType::list(out << "type: "); + out << std::endl; +} + + +void GridFactory::json(JSON& j) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + GridConfig::instance(); + + j.startObject(); + GridFactoryUID::json(j << "uid"); + GridFactoryName::json(j << "name"); + GridFactoryType::json(j << "type"); j.endObject(); } @@ -187,7 +190,8 @@ const Grid* GridFactoryUID::build(const std::string& uid) { AutoLock lock(*__mutex); if (auto j = __grid_uids->find(uid); j != __grid_uids->end()) { - return j->second->make(); + std::unique_ptr config(j->second->config()); + return GridFactory::build(*config); } list(Log::error() << "Grid: unknown identifier '" << uid << "', choices are: "); @@ -200,16 +204,42 @@ void GridFactoryUID::list(std::ostream& out) { AutoLock lock(*__mutex); JSON j(out); - j.startList(); + json(j); +} + + +void GridFactoryUID::json(JSON& j) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + j.startObject(); for (const auto& p : *__grid_uids) { - out << p.first; + j << p.first; + + std::unique_ptr config(p.second->config()); + j << *config; } - j.endList(); + j.endObject(); +} + + +void GridFactoryUID::insert(const std::string& uid, MappedConfiguration* config) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + struct Insert final : GridFactoryUID { + Insert(const std::string& uid, MappedConfiguration* config) : + GridFactoryUID(uid), config_(config) {} + Configuration* config() override { return new MappedConfiguration(*config_); } + const std::unique_ptr config_; + }; + + new Insert(uid, config); } -GridFactoryName::GridFactoryName(const std::string& pattern) : - pattern_(pattern) { +GridFactoryName::GridFactoryName(const std::string& pattern, const std::string& example) : + pattern_(pattern), example_(example) { pthread_once(&__once, __init); AutoLock lock(*__mutex); @@ -253,11 +283,38 @@ void GridFactoryName::list(std::ostream& out) { AutoLock lock(*__mutex); JSON j(out); - j.startList(); + json(j); +} + + +void GridFactoryName::json(JSON& j) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + j.startObject(); for (const auto& p : *__grid_names) { - out << p.first; + j << p.first; + + std::unique_ptr config(p.second->config()); + j << *config; } - j.endList(); + j.endObject(); +} + + +void GridFactoryName::insert(const std::string& name, MappedConfiguration* config) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + + struct Insert final : GridFactoryName { + Insert(const std::string& name, const std::string& example, MappedConfiguration* config) : + GridFactoryName(name, example), config_(config) {} + Configuration* config(const std::string&) const override { return new MappedConfiguration(*config_); } + const std::unique_ptr config_; + }; + + ASSERT(config != nullptr); + new Insert(name, config->getString("example", ""), config); } @@ -308,9 +365,17 @@ void GridFactoryType::list(std::ostream& out) { AutoLock lock(*__mutex); JSON j(out); + json(j); +} + + +void GridFactoryType::json(JSON& j) { + pthread_once(&__once, __init); + AutoLock lock(*__mutex); + j.startList(); for (const auto& p : *__grid_types) { - out << p.first; + j << p.first; } j.endList(); } diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index e7e9b7cc1..7b60a6e4b 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -18,7 +18,7 @@ #include #include -#include "eckit/config/Configuration.h" +#include "eckit/config/MappedConfiguration.h" #include "eckit/geometry/Area.h" #include "eckit/geometry/Increments.h" #include "eckit/geometry/Iterator.h" @@ -29,6 +29,11 @@ #include "eckit/geometry/area/BoundingBox.h" +namespace eckit { +class JSON; +} + + namespace eckit::geometry { @@ -166,6 +171,7 @@ struct GridFactory { // This is 'const' as Grid should always be immutable static const Grid* build(const Configuration&); static void list(std::ostream&); + static void json(JSON&); }; @@ -177,14 +183,17 @@ struct GridFactoryUID { // This is 'const' as Grid should always be immutable static const Grid* build(const std::string&); + static void list(std::ostream&); + static void json(JSON&); + static void insert(const std::string& name, MappedConfiguration*); protected: explicit GridFactoryUID(const std::string& uid); virtual ~GridFactoryUID(); private: - virtual const Grid* make() = 0; + virtual Configuration* config() = 0; const std::string uid_; }; @@ -198,16 +207,21 @@ struct GridFactoryName { // This is 'const' as Grid should always be immutable static const Grid* build(const std::string& name); + static void list(std::ostream&); + static void json(JSON&); + static void insert(const std::string& name, MappedConfiguration*); protected: - explicit GridFactoryName(const std::string& pattern); + explicit GridFactoryName(const std::string& pattern, const std::string& example = ""); virtual ~GridFactoryName(); private: - virtual Configuration* config(const std::string& name) = 0; + Configuration* config() const { return config(example_); } + virtual Configuration* config(const std::string& name) const = 0; const std::string pattern_; + const std::string example_; }; @@ -219,7 +233,9 @@ struct GridFactoryType { // This is 'const' as Grid should always be immutable static const Grid* build(const Configuration&); + static void list(std::ostream&); + static void json(JSON&); protected: explicit GridFactoryType(const std::string& type); @@ -236,15 +252,15 @@ template struct GridRegisterUID final : GridFactoryUID { explicit GridRegisterUID(const std::string& uid) : GridFactoryUID(uid) {} - const Grid* make() override { return new T(); } + Configuration* config() override { return T::config(); } }; template struct GridRegisterName final : GridFactoryName { - explicit GridRegisterName(const std::string& pattern) : - GridFactoryName(pattern) {} - Configuration* config(const std::string& name) override { return T::config(name); } + explicit GridRegisterName(const std::string& pattern, const std::string& example) : + GridFactoryName(pattern, example) {} + Configuration* config(const std::string& name) const override { return T::config(name); } }; diff --git a/src/eckit/geometry/grid/HEALPix.cc b/src/eckit/geometry/grid/HEALPix.cc index f021d8153..4393a32f8 100644 --- a/src/eckit/geometry/grid/HEALPix.cc +++ b/src/eckit/geometry/grid/HEALPix.cc @@ -218,7 +218,7 @@ std::pair, std::vector> HEALPix::to_latlon() const { static const GridRegisterType __grid_type("healpix"); -static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); +static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*", "H2"); } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/ReducedGG.cc b/src/eckit/geometry/grid/ReducedGG.cc index e49225481..b365ec42c 100644 --- a/src/eckit/geometry/grid/ReducedGG.cc +++ b/src/eckit/geometry/grid/ReducedGG.cc @@ -187,8 +187,8 @@ struct ReducedGGOctahedral { static const GridRegisterType __grid_type("reduced_gg"); -static const GridRegisterName __grid_pattern_1("[nN][1-9][0-9]*"); -static const GridRegisterName __grid_pattern_2("[oO][1-9][0-9]*"); +static const GridRegisterName __grid_pattern_1("[nN][1-9][0-9]*", "N16"); +static const GridRegisterName __grid_pattern_2("[oO][1-9][0-9]*", "O2"); } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/RegularGG.cc b/src/eckit/geometry/grid/RegularGG.cc index d456e145d..6645f123d 100644 --- a/src/eckit/geometry/grid/RegularGG.cc +++ b/src/eckit/geometry/grid/RegularGG.cc @@ -182,7 +182,7 @@ Iterator* RegularGG::iterator() const { static const GridRegisterType __grid_type("regular_gg"); -static const GridRegisterName __grid_pattern("[fF][1-9][0-9]*"); +static const GridRegisterName __grid_pattern("[fF][1-9][0-9]*", "F2"); } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/RegularLL.cc b/src/eckit/geometry/grid/RegularLL.cc index 1ccf67024..12ee11c01 100644 --- a/src/eckit/geometry/grid/RegularLL.cc +++ b/src/eckit/geometry/grid/RegularLL.cc @@ -250,7 +250,7 @@ Configuration* RegularLL::config(const std::string& name) { } -static const GridRegisterName __grid_pattern(POSITIVE_REAL "/" POSITIVE_REAL); +static const GridRegisterName __grid_pattern(POSITIVE_REAL "/" POSITIVE_REAL, "30/45"); #undef POSITIVE_REAL diff --git a/src/tools/eckit-grid-list.cc b/src/tools/eckit-grid-list.cc index abf05c699..e040be658 100644 --- a/src/tools/eckit-grid-list.cc +++ b/src/tools/eckit-grid-list.cc @@ -8,31 +8,23 @@ * does it submit to any jurisdiction. */ + #include "eckit/geometry/Grid.h" -#include "eckit/exception/Exceptions.h" +#include "eckit/log/JSON.h" #include "eckit/log/Log.h" #include "eckit/option/EckitTool.h" -#include "eckit/option/SimpleOption.h" - -#include "eckit/geometry/GridConfig.h" -//---------------------------------------------------------------------------------------------------------------------- -namespace eckit { +namespace eckit::tools { -class EckitGrid final : public EckitTool { -public: - EckitGrid(int argc, char** argv) : - EckitTool(argc, argv) { - options_.push_back(new option::SimpleOption("list", "List possible grids")); - } -private: - void execute(const option::CmdArgs& args) override { +struct EckitGridList final : EckitTool { + EckitGridList(int argc, char** argv) : + EckitTool(argc, argv) {} - Log::info() << geometry::GridConfig::instance().config() << std::endl; - - geometry::GridFactory::list(Log::info()); + void execute(const option::CmdArgs&) override { + JSON j(Log::info()); + geometry::GridFactory::json(j); Log::info() << std::endl; } @@ -43,11 +35,11 @@ class EckitGrid final : public EckitTool { } }; -} // namespace eckit -//---------------------------------------------------------------------------------------------------------------------- +} // namespace eckit::tools + int main(int argc, char** argv) { - eckit::EckitGrid app(argc, argv); + eckit::tools::EckitGridList app(argc, argv); return app.start(); } From d89531fcd2983ba0eb17f4c40efff3a41da4d86f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 17 Aug 2023 23:41:19 +0100 Subject: [PATCH 306/737] eckit::geometry --- src/eckit/geometry/GridConfig.cc | 28 ++++++++++++++++------------ src/eckit/geometry/GridConfig.h | 5 ++--- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/src/eckit/geometry/GridConfig.cc b/src/eckit/geometry/GridConfig.cc index 5593e1d69..e2ec18223 100644 --- a/src/eckit/geometry/GridConfig.cc +++ b/src/eckit/geometry/GridConfig.cc @@ -12,11 +12,14 @@ #include "eckit/geometry/GridConfig.h" +#include + #include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "eckit/geometry/Grid.h" #include "eckit/geometry/LibEcKitGeometry.h" +#include "eckit/geometry/util.h" #include "eckit/parser/YAMLParser.h" #include "eckit/value/Value.h" @@ -28,24 +31,25 @@ namespace { template -MappedConfiguration::value_type __from_value_list(const ValueList& list) { - if (list.size() == 1) { - typename T::value_type to; - fromValue(to, list[0]); - return {to}; - } - +MappedConfiguration::value_type __from_value(const Value& value) { T to; - fromValue(to, list); + fromValue(to, value); return {to}; } void set_config_value(MappedConfiguration& config, const std::string& key, const Value& value) { - ValueList list(value); - auto val = std::all_of(list.begin(), list.end(), [](const Value& v) { return v.isDouble(); }) ? __from_value_list>(list) - : std::all_of(list.begin(), list.end(), [](const Value& v) { return v.isNumber(); }) ? __from_value_list>(list) - : __from_value_list>(list); + using number_type = pl_type::value_type; + + auto list_of = [](const ValueList& list, auto pred) { return std::all_of(list.begin(), list.end(), pred); }; + + auto val = value.isList() && list_of(value, [](const Value& v) { return v.isDouble(); }) ? __from_value>(value) + : value.isList() && list_of(value, [](const Value& v) { return v.isNumber(); }) ? __from_value>(value) + : value.isList() ? __from_value>(value) + : value.isDouble() ? __from_value(value) + : value.isNumber() ? __from_value(value) + : __from_value(value); + std::visit([&](const auto& val) { config.set(key, val); }, val); } diff --git a/src/eckit/geometry/GridConfig.h b/src/eckit/geometry/GridConfig.h index eaf23e8d1..4bd0641a8 100644 --- a/src/eckit/geometry/GridConfig.h +++ b/src/eckit/geometry/GridConfig.h @@ -14,12 +14,11 @@ #include -#include "eckit/config/Configuration.h" - namespace eckit { +class Configuration; class PathName; -} +} // namespace eckit namespace eckit::geometry { From 5dcf3e19577491f2b7a40443385d2ad33aefd7cd Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 18 Aug 2023 16:16:23 +0100 Subject: [PATCH 307/737] eckit::memory::Factory, Builder modernised --- src/eckit/CMakeLists.txt | 1 - src/eckit/memory/Builder.cc | 21 --- src/eckit/memory/Builder.h | 248 +++++++++++++++++++++--------------- src/eckit/memory/Factory.h | 99 +++++++------- 4 files changed, 202 insertions(+), 167 deletions(-) delete mode 100644 src/eckit/memory/Builder.cc diff --git a/src/eckit/CMakeLists.txt b/src/eckit/CMakeLists.txt index ab7d88ddc..2f7a9180a 100644 --- a/src/eckit/CMakeLists.txt +++ b/src/eckit/CMakeLists.txt @@ -762,7 +762,6 @@ endif() list( APPEND eckit_memory_srcs -memory/Builder.cc memory/Builder.h memory/Counted.cc memory/Counted.h diff --git a/src/eckit/memory/Builder.cc b/src/eckit/memory/Builder.cc deleted file mode 100644 index 990e2de58..000000000 --- a/src/eckit/memory/Builder.cc +++ /dev/null @@ -1,21 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/memory/Builder.h" - -//---------------------------------------------------------------------------------------------------------------------- - -namespace eckit { - -Builder::~Builder() {} - -//---------------------------------------------------------------------------------------------------------------------- - -} // namespace eckit diff --git a/src/eckit/memory/Builder.h b/src/eckit/memory/Builder.h index 898e3ff39..100c036a8 100644 --- a/src/eckit/memory/Builder.h +++ b/src/eckit/memory/Builder.h @@ -8,25 +8,24 @@ * does it submit to any jurisdiction. */ -#ifndef eckit_memory_Builder_h -#define eckit_memory_Builder_h - /// @file Builder.h /// @author Tiago Quintino +/// @author Pedro Maciel /// @date Jul 2014 -#include "eckit/exception/Exceptions.h" + +#pragma once + #include "eckit/memory/Factory.h" -#include "eckit/value/Params.h" // #define DEBUG_ECKIT_BUILDERS #ifdef DEBUG_ECKIT_BUILDERS +#include "eckit/exception/Exceptions.h" #define DEBUG_BUILDER(x) std::cerr << " DEBUG (" << x << ") " << Here() << std::endl; #else #define DEBUG_BUILDER(x) #endif -//----------------------------------------------------------------------------- namespace eckit { @@ -34,129 +33,158 @@ namespace eckit { class Builder : private NonCopyable { public: - typedef std::string key_t; + // -- Types + + using key_t = std::string; + + // -- Constructors - virtual ~Builder(); + Builder() = default; + Builder(const Builder&) = delete; + Builder(Builder&&) = delete; + + // -- Destructor + + virtual ~Builder() = default; + + // -- Operators + + void operator=(const Builder&) = delete; + void operator=(Builder&&) = delete; + + // -- Methods virtual key_t name() const = 0; virtual key_t build_type() const = 0; +private: + // -- Methods + + virtual void print(std::ostream& os) const { os << "Builder(" << build_type() << "):" << name(); } + + // -- Friends + friend std::ostream& operator<<(std::ostream& os, const Builder& o) { o.print(os); return os; } - -private: // methods - virtual void print(std::ostream& os) const { os << "Builder(" << build_type() << "):" << name(); } }; //------------------------------------------------------------------------------------------------------ template class BuilderT0 : public Builder { +public: + // -- Types -public: // types - BuilderT0() {} - - ~BuilderT0() {} + using product_t = Base; + using product_ptr = product_t*; + using builder_ptr = typename Factory::builder_ptr; - typedef Base product_t; - typedef product_t* product_ptr; - typedef Builder::key_t key_t; - typedef typename Factory::builder_ptr builder_ptr; + // -- Methods virtual product_ptr create() const = 0; -public: // methods - virtual key_t build_type() const { return Base::className(); } + // -- Overridden methods + + typename Builder::key_t build_type() const override { return Base::className(); } }; //------------------------------------------------------------------------------------------------------ template class BuilderT1 : public Builder { +public: + // -- Types -public: // types - BuilderT1() {} - - ~BuilderT1() {} + using product_t = Base; + using product_ptr = product_t*; + using builder_ptr = typename Factory::builder_ptr; + using ARG1 = typename product_t::ARG1; - typedef Base product_t; - typedef product_t* product_ptr; - typedef Builder::key_t key_t; - typedef typename Factory::builder_ptr builder_ptr; + // -- Methods - typedef typename product_t::ARG1 ARG1; + virtual product_ptr create(ARG1) const = 0; - virtual product_ptr create(ARG1 p1) const = 0; + // -- Overridden methods -public: // methods - virtual key_t build_type() const { return Base::className(); } + typename Builder::key_t build_type() const override { return Base::className(); } }; //------------------------------------------------------------------------------------------------------ template class BuilderT2 : public Builder { +public: + // -- Types -public: // types - BuilderT2(){}; + using product_t = Base; + using product_ptr = product_t*; + using builder_ptr = typename Factory::builder_ptr; - ~BuilderT2() {} + using ARG1 = typename product_t::ARG1; + using ARG2 = typename product_t::ARG2; - typedef Base product_t; - typedef product_t* product_ptr; - typedef Builder::key_t key_t; - typedef typename Factory::builder_ptr builder_ptr; + // -- Methods - typedef typename product_t::ARG1 ARG1; - typedef typename product_t::ARG2 ARG2; + virtual product_ptr create(ARG1, ARG2) const = 0; - virtual product_ptr create(ARG1 p1, ARG2 p2) const = 0; + // -- Overridden methods -public: // methods - virtual key_t build_type() const { return Base::className(); } + typename Builder::key_t build_type() const override { return Base::className(); } }; + //------------------------------------------------------------------------------------------------------ template -class ConcreteBuilderT0 : public BuilderT0 { +class ConcreteBuilderT0 final : public BuilderT0 { +public: + // -- Types -public: // types - typedef BuilderT0 base_t; + using base_t = BuilderT0; - typedef typename base_t::key_t key_t; - typedef typename base_t::product_t product_t; - typedef typename base_t::product_ptr product_ptr; - typedef typename base_t::builder_ptr builder_ptr; + // -- Constructors -public: // methods ConcreteBuilderT0() : - k_(name()) { + key_(name()) { DEBUG_BUILDER("ConcreteBuilderT0() -- " << T::className()); - Factory::instance().regist(k_, builder_ptr(this)); + Factory::instance().regist(key_, this); } - ConcreteBuilderT0(const key_t& k) : - k_(k) { + explicit ConcreteBuilderT0(const typename base_t::key_t& k) : + key_(k) { DEBUG_BUILDER("ConcreteBuilderT0() -- " << T::className()); - Factory::instance().regist(k_, builder_ptr(this)); + Factory::instance().regist(key_, this); } + ConcreteBuilderT0(const ConcreteBuilderT0&) = delete; + ConcreteBuilderT0(ConcreteBuilderT0&&) = delete; + + // -- Destructor + ~ConcreteBuilderT0() override { DEBUG_BUILDER("~ConcreteBuilderT0() -- " << T::className()); - Factory::instance().unregist(k_); + Factory::instance().unregist(key_); } - typename base_t::key_t name() const override { return T::className(); } + // -- Operators - product_ptr create() const override { return new T(); } + void operator=(const ConcreteBuilderT0&) = delete; + void operator=(ConcreteBuilderT0&&) = delete; + + // -- Overridden methods + + typename base_t::key_t name() const override { return T::className(); } + typename base_t::product_ptr create() const override { return new T(); } private: - key_t k_; + // -- Members + + typename base_t::key_t key_; }; + #define register_BuilderT0(ABSTRACT, CONCRETE, NAME) \ static struct Register__##ABSTRACT##__##CONCRETE##__T0 { \ Register__##ABSTRACT##__##CONCRETE##__T0() { \ @@ -164,46 +192,58 @@ class ConcreteBuilderT0 : public BuilderT0 { } \ } register_##ABSTRACT##__##CONCRETE##_T0 + //------------------------------------------------------------------------------------------------------ template -class ConcreteBuilderT1 : public BuilderT1 { -public: // types - typedef BuilderT1 base_t; +class ConcreteBuilderT1 final : public BuilderT1 { +public: + // -- Types - typedef typename base_t::key_t key_t; - typedef typename base_t::product_t product_t; - typedef typename base_t::product_ptr product_ptr; - typedef typename base_t::builder_ptr builder_ptr; + using base_t = BuilderT1; - typedef typename base_t::ARG1 ARG1; + // -- Constructors -public: // methods ConcreteBuilderT1() : - k_(name()) { + key_(name()) { DEBUG_BUILDER("ConcreteBuilderT1() -- " << T::className()); - Factory::instance().regist(k_, builder_ptr(this)); + Factory::instance().regist(key_, this); } - ConcreteBuilderT1(const key_t& k) : - k_(k) { + explicit ConcreteBuilderT1(const typename base_t::key_t& k) : + key_(k) { DEBUG_BUILDER("ConcreteBuilderT1() -- " << T::className()); - Factory::instance().regist(k_, builder_ptr(this)); + Factory::instance().regist(key_, this); } + ConcreteBuilderT1(const ConcreteBuilderT1&) = delete; + ConcreteBuilderT1(ConcreteBuilderT1&&) = delete; + + // -- Destructor + ~ConcreteBuilderT1() override { DEBUG_BUILDER("~ConcreteBuilderT1() -- " << T::className()); - Factory::instance().unregist(k_); + Factory::instance().unregist(key_); } + // -- Operators + + void operator=(const ConcreteBuilderT1&) = delete; + void operator=(ConcreteBuilderT1&&) = delete; + + // -- Overridden methods + typename base_t::key_t name() const override { return T::className(); } + typename base_t::product_ptr create(typename base_t::ARG1 p1) const override { return new T(p1); } - product_ptr create(ARG1 p1) const override { return new T(p1); } private: - key_t k_; + // -- Members + + typename base_t::key_t key_; }; + #define register_BuilderT1(ABSTRACT, CONCRETE, NAME) \ static struct Register__##ABSTRACT##__##CONCRETE##__T1 { \ Register__##ABSTRACT##__##CONCRETE##__T1() { \ @@ -211,48 +251,58 @@ class ConcreteBuilderT1 : public BuilderT1 { } \ } register_##ABSTRACT##__##CONCRETE##_T1 + //------------------------------------------------------------------------------------------------------ template -class ConcreteBuilderT2 : public BuilderT2 { - -public: // types - typedef BuilderT2 base_t; +class ConcreteBuilderT2 final : public BuilderT2 { +public: + // -- Types - typedef typename base_t::key_t key_t; - typedef typename base_t::product_t product_t; - typedef typename base_t::product_ptr product_ptr; - typedef typename base_t::builder_ptr builder_ptr; + using base_t = BuilderT2; - typedef typename base_t::ARG1 ARG1; - typedef typename base_t::ARG2 ARG2; + // -- Constructors -public: // methods ConcreteBuilderT2() : - k_(name()) { + key_(name()) { DEBUG_BUILDER("ConcreteBuilderT2() -- " << T::className()); - Factory::instance().regist(k_, builder_ptr(this)); + Factory::instance().regist(key_, this); } - ConcreteBuilderT2(const key_t& k) : - k_(k) { + explicit ConcreteBuilderT2(const typename base_t::key_t& k) : + key_(k) { DEBUG_BUILDER("ConcreteBuilderT2() -- " << T::className()); - Factory::instance().regist(k_, builder_ptr(this)); + Factory::instance().regist(key_, this); } + ConcreteBuilderT2(const ConcreteBuilderT2&) = delete; + ConcreteBuilderT2(ConcreteBuilderT2&&) = delete; + + // -- Destructor + ~ConcreteBuilderT2() override { DEBUG_BUILDER("~ConcreteBuilderT2() -- " << T::className()); - Factory::instance().unregist(k_); + Factory::instance().unregist(key_); } + // -- Operators + + void operator=(const ConcreteBuilderT2&) = delete; + void operator=(ConcreteBuilderT2&&) = delete; + + // -- Overridden methods + typename base_t::key_t name() const override { return T::className(); } + typename base_t::product_ptr create(typename base_t::ARG1 p1, typename base_t::ARG2 p2) const override { return new T(p1, p2); } - product_ptr create(ARG1 p1, ARG2 p2) const override { return new T(p1, p2); } private: - key_t k_; + // -- Members + + typename base_t::key_t key_; }; + #define register_BuilderT2(ABSTRACT, CONCRETE, NAME) \ static struct Register__##ABSTRACT##__##CONCRETE##__T2 { \ Register__##ABSTRACT##__##CONCRETE##__T2() { \ @@ -263,5 +313,3 @@ class ConcreteBuilderT2 : public BuilderT2 { //------------------------------------------------------------------------------------------------------ } // namespace eckit - -#endif // eckit_memory_Builder_h diff --git a/src/eckit/memory/Factory.h b/src/eckit/memory/Factory.h index 380fa5c05..5b5481ffb 100644 --- a/src/eckit/memory/Factory.h +++ b/src/eckit/memory/Factory.h @@ -3,18 +3,20 @@ * * 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. */ -#ifndef eckit_memory_Factory_h -#define eckit_memory_Factory_h - /// @file Factory.h /// @author Tiago Quintino +/// @author Pedro Maciel /// @date Jul 2014 + +#pragma once + #include #include #include @@ -23,23 +25,34 @@ #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" + namespace eckit { //------------------------------------------------------------------------------------------------------ template class Factory { +public: + // -- Types + + using product_t = T; + using key_t = std::string; + using builder_t = typename product_t::builder_t; + using builder_ptr = builder_t*; + using storage_t = std::map; + + // -- Constructors -public: // types - typedef std::string key_t; + Factory(const Factory&) = delete; + Factory(Factory&&) = delete; - typedef T product_t; - typedef typename product_t::builder_t builder_t; - typedef builder_t* builder_ptr; + // -- Operators - typedef std::map storage_t; + void operator=(const Factory&) = delete; + void operator=(Factory&&) = delete; + + // -- Methods -public: // methods /// @return the instance of this singleton factory static Factory& instance(); @@ -48,7 +61,7 @@ class Factory { /// Checks if a builder is registered /// @param name of the builder - bool exists(const key_t& k) const; + bool exists(const key_t&) const; /// Registers a builder /// @param builder pointer @@ -61,39 +74,37 @@ class Factory { /// Gets the builder registered to the associated key /// @param name of the builder - const builder_t& get(const key_t& name) const; + const builder_t& get(const key_t&) const; /// @returns the number of builders registered to the factory size_t size() const; std::vector keys() const; - friend std::ostream& operator<<(std::ostream& os, const Factory& o) { - o.print(os); - return os; - } +private: + // Constructors -private: // methods - void print(std::ostream&) const; + Factory() = default; - Factory() { - // std::cout << "Building Factory of " << build_type() << std::endl; - } + // Destructor - ~Factory() { - // std::cout << "Destroying Factory of " << build_type() << std::endl; - // if( store_.size() != 0 ) - // { - // std::cout << "WARNING : Factory of " << build_type() << " still has " << size() << " providers" << - // std::endl; std::cout << *this << std::endl; - // } + ~Factory() { ASSERT(store_.empty()); } - ASSERT(store_.size() == 0); - } + // -- Members -private: // members mutable Mutex mutex_; ///< mutex protecting Factory singleton storage_t store_; ///< storage for the builders in a map indexed by key_t + + // -- Methods + + void print(std::ostream&) const; + + // -- Friends + + friend std::ostream& operator<<(std::ostream& os, const Factory& o) { + o.print(os); + return os; + } }; //------------------------------------------------------------------------------------------------------ @@ -113,9 +124,9 @@ bool Factory::exists(const key_t& k) const { template void Factory::regist(const key_t& k, builder_ptr b) { AutoLock lock(mutex_); - ASSERT(b); + ASSERT(b != nullptr); if (exists(k)) { - throw BadParameter("Factory of " + build_type() + " has already a builder for " + k, Here()); + throw BadParameter("Factory(" + build_type() + ") has already a builder for " + k, Here()); } store_[k] = b; } @@ -124,7 +135,7 @@ template void Factory::unregist(const key_t& k) { AutoLock lock(mutex_); if (!exists(k)) { - throw BadParameter("Factory of " + build_type() + " has no builder for " + k, Here()); + throw BadParameter("Factory(" + build_type() + ") has no builder for " + k, Here()); } store_.erase(k); } @@ -139,9 +150,9 @@ template const typename Factory::builder_t& Factory::get(const key_t& k) const { AutoLock lock(mutex_); if (!exists(k)) { - throw BadParameter("Factory of " + build_type() + " has no builder for " + k, Here()); + throw BadParameter("Factory(" + build_type() + ") has no builder for " + k, Here()); } - return *store_.find(k)->second; + return *(store_.find(k)->second); } template @@ -149,13 +160,13 @@ void Factory::print(std::ostream& os) const { AutoLock lock(mutex_); os << "Factory(" << build_type() << ")" << std::endl; - size_t key_width = 0; - for (typename storage_t::const_iterator i = store_.begin(); i != store_.end(); ++i) { - key_width = std::max(i->first.size(), key_width); + int key_width = 0; + for (const auto& i : store_) { + key_width = std::max(static_cast(i.first.size()), key_width); } - for (typename storage_t::const_iterator i = store_.begin(); i != store_.end(); ++i) { - os << " " << std::setw(key_width) << std::left << i->first << " -- " << (*(*i).second) << std::endl; + for (const auto& i : store_) { + os << " " << std::setw(key_width) << std::left << i.first << " -- " << i.second << std::endl; } } @@ -165,8 +176,8 @@ std::vector::key_t> Factory::keys() const { std::vector keysv; keysv.reserve(store_.size()); - for (typename storage_t::const_iterator i = store_.begin(); i != store_.end(); ++i) { - keysv.push_back(i->first); + for (const auto& i : store_) { + keysv.push_back(i.first); } return keysv; } @@ -174,5 +185,3 @@ std::vector::key_t> Factory::keys() const { //------------------------------------------------------------------------------------------------------ } // namespace eckit - -#endif // eckit_memory_Factory_h From 3084276bb8c2c57937c077b3e71f3af697ce35c0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 21 Aug 2023 12:17:43 +0100 Subject: [PATCH 308/737] eckit::memory::Factory, Builder modernised --- src/eckit/memory/Builder.h | 29 ++++++++++++----------------- src/eckit/memory/Factory.h | 14 +++++++------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/src/eckit/memory/Builder.h b/src/eckit/memory/Builder.h index 100c036a8..f429d97a6 100644 --- a/src/eckit/memory/Builder.h +++ b/src/eckit/memory/Builder.h @@ -31,7 +31,7 @@ namespace eckit { //------------------------------------------------------------------------------------------------------ -class Builder : private NonCopyable { +class Builder { public: // -- Types @@ -77,13 +77,11 @@ class BuilderT0 : public Builder { public: // -- Types - using product_t = Base; - using product_ptr = product_t*; - using builder_ptr = typename Factory::builder_ptr; + using product_t = Base; // -- Methods - virtual product_ptr create() const = 0; + virtual product_t* create() const = 0; // -- Overridden methods @@ -97,14 +95,13 @@ class BuilderT1 : public Builder { public: // -- Types - using product_t = Base; - using product_ptr = product_t*; - using builder_ptr = typename Factory::builder_ptr; - using ARG1 = typename product_t::ARG1; + using product_t = Base; + + using ARG1 = typename product_t::ARG1; // -- Methods - virtual product_ptr create(ARG1) const = 0; + virtual product_t* create(ARG1) const = 0; // -- Overridden methods @@ -118,16 +115,14 @@ class BuilderT2 : public Builder { public: // -- Types - using product_t = Base; - using product_ptr = product_t*; - using builder_ptr = typename Factory::builder_ptr; + using product_t = Base; using ARG1 = typename product_t::ARG1; using ARG2 = typename product_t::ARG2; // -- Methods - virtual product_ptr create(ARG1, ARG2) const = 0; + virtual product_t* create(ARG1, ARG2) const = 0; // -- Overridden methods @@ -176,7 +171,7 @@ class ConcreteBuilderT0 final : public BuilderT0 { // -- Overridden methods typename base_t::key_t name() const override { return T::className(); } - typename base_t::product_ptr create() const override { return new T(); } + typename base_t::product_t* create() const override { return new T(); } private: // -- Members @@ -234,7 +229,7 @@ class ConcreteBuilderT1 final : public BuilderT1 { // -- Overridden methods typename base_t::key_t name() const override { return T::className(); } - typename base_t::product_ptr create(typename base_t::ARG1 p1) const override { return new T(p1); } + typename base_t::product_t* create(typename base_t::ARG1 p1) const override { return new T(p1); } private: @@ -293,7 +288,7 @@ class ConcreteBuilderT2 final : public BuilderT2 { // -- Overridden methods typename base_t::key_t name() const override { return T::className(); } - typename base_t::product_ptr create(typename base_t::ARG1 p1, typename base_t::ARG2 p2) const override { return new T(p1, p2); } + typename base_t::product_t* create(typename base_t::ARG1 p1, typename base_t::ARG2 p2) const override { return new T(p1, p2); } private: diff --git a/src/eckit/memory/Factory.h b/src/eckit/memory/Factory.h index 5b5481ffb..ab2b468f7 100644 --- a/src/eckit/memory/Factory.h +++ b/src/eckit/memory/Factory.h @@ -35,11 +35,10 @@ class Factory { public: // -- Types - using product_t = T; - using key_t = std::string; - using builder_t = typename product_t::builder_t; - using builder_ptr = builder_t*; - using storage_t = std::map; + using product_t = T; + using builder_t = typename product_t::builder_t; + using key_t = std::string; + using storage_t = std::map; // -- Constructors @@ -66,7 +65,7 @@ class Factory { /// Registers a builder /// @param builder pointer /// @throw BadParameter if the builder already registered - void regist(const key_t&, builder_ptr); + void regist(const key_t&, builder_t*); /// Remove a registered builder /// @throw BadParameter if the builder is not registered @@ -79,6 +78,7 @@ class Factory { /// @returns the number of builders registered to the factory size_t size() const; + /// @returns the builder keys registered to the factory std::vector keys() const; private: @@ -122,7 +122,7 @@ bool Factory::exists(const key_t& k) const { } template -void Factory::regist(const key_t& k, builder_ptr b) { +void Factory::regist(const key_t& k, builder_t* b) { AutoLock lock(mutex_); ASSERT(b != nullptr); if (exists(k)) { From a29f0284175e96404acb857ff3f3e0b46a004f6a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 18 Aug 2023 01:12:05 +0100 Subject: [PATCH 309/737] eckit::geometry instance()-based factories --- src/eckit/geometry/Area.cc | 100 -------- src/eckit/geometry/Area.h | 47 +--- src/eckit/geometry/CMakeLists.txt | 3 - src/eckit/geometry/Figure.cc | 112 --------- src/eckit/geometry/Figure.h | 54 ++--- src/eckit/geometry/Grid.cc | 1 - src/eckit/geometry/Grid.h | 2 +- src/eckit/geometry/Projection.cc | 302 ------------------------- src/eckit/geometry/Projection.h | 42 +--- src/eckit/geometry/grid/RegularGrid.cc | 16 +- tests/geometry/test_projection.cc | 10 +- 11 files changed, 52 insertions(+), 637 deletions(-) delete mode 100644 src/eckit/geometry/Area.cc delete mode 100644 src/eckit/geometry/Figure.cc delete mode 100644 src/eckit/geometry/Projection.cc diff --git a/src/eckit/geometry/Area.cc b/src/eckit/geometry/Area.cc deleted file mode 100644 index 6106463db..000000000 --- a/src/eckit/geometry/Area.cc +++ /dev/null @@ -1,100 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/Area.h" - -#include -#include - -#include "eckit/config/Configuration.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/log/Log.h" -#include "eckit/thread/AutoLock.h" -#include "eckit/thread/Mutex.h" - - -namespace eckit::geometry { - - -static pthread_once_t __once = PTHREAD_ONCE_INIT; -static Mutex* __mutex = nullptr; -static std::map* __factories = nullptr; - - -static void __init() { - __mutex = new Mutex; - __factories = new std::map(); -} - - -Area* AreaFactory::build(const Configuration& config) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - Area::Type type; - ASSERT(config.get("type", type)); - - return build(type, config); -} - - -Area* AreaFactory::build(const Area::Type& type, - const Configuration& config) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - if (auto f = __factories->find(type); f != __factories->end()) { - return f->second->make(config); - } - - list(Log::error() << "AreaFactory: unknown '" << type << "', choices are: "); - throw BadValue("AreaFactory: unknown '" + type + "'"); -} - - -std::ostream& AreaFactory::list(std::ostream& out) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - const char* sep = "'"; - for (const auto& j : *__factories) { - out << sep << j.first << '\''; - sep = ", '"; - } - - return out; -} - - -AreaFactory::AreaFactory(const Area::Type& key) : - key_(key) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - if (auto f = __factories->find(key); f != __factories->end()) { - throw BadValue("AreaFactory: duplicate '" + key + "'"); - } - - (*__factories)[key] = this; -} - - -AreaFactory::~AreaFactory() { - AutoLock lock(*__mutex); - - if (__factories != nullptr) { - __factories->erase(key_); - } -} - - -} // namespace eckit::geometry diff --git a/src/eckit/geometry/Area.h b/src/eckit/geometry/Area.h index aa128c18c..29bffc36e 100644 --- a/src/eckit/geometry/Area.h +++ b/src/eckit/geometry/Area.h @@ -12,16 +12,15 @@ #pragma once -#include #include +#include "eckit/memory/Builder.h" +#include "eckit/memory/Factory.h" + namespace eckit { class Configuration; -namespace geometry::area { -class BoundingBox; } -} // namespace eckit namespace eckit::geometry { @@ -31,15 +30,15 @@ class Area { public: // -- Types - using Type = std::string; + using builder_t = BuilderT1; + using ARG1 = const Configuration&; // -- Exceptions // None // -- Constructors - Area() noexcept = default; - + Area() noexcept = default; Area(const Area&) = default; Area(Area&&) = default; @@ -56,7 +55,8 @@ class Area { Area& operator=(Area&&) = default; // -- Methods - // None + + static std::string className() { return "area"; } // -- Overridden methods // None @@ -104,35 +104,10 @@ class Area { }; -struct AreaFactory { - static Area* build(const Configuration&); - static Area* build(const Area::Type&, const Configuration&); - static std::ostream& list(std::ostream&); - - AreaFactory(const AreaFactory&) = delete; - AreaFactory(AreaFactory&&) = delete; - AreaFactory& operator=(const AreaFactory&) = delete; - AreaFactory& operator=(AreaFactory&&) = delete; - - virtual Area* make(const Configuration&) = 0; - -protected: - explicit AreaFactory(const Area::Type&); - virtual ~AreaFactory(); +using AreaFactory = Factory; -private: - const Area::Type key_; -}; - - -template -class AreaBuilder final : public AreaFactory { - Area* make(const Configuration& config) override { return new T(config); } - -public: - explicit AreaBuilder(const Area::Type& key) : - AreaFactory(key) {} -}; +template +using AreaBuilder = ConcreteBuilderT1; } // namespace eckit::geometry diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index 6fe0622c7..ee9ed6337 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -1,5 +1,4 @@ list( APPEND eckit_geometry_srcs - Area.cc Area.h Cache.cc Cache.h @@ -10,7 +9,6 @@ list( APPEND eckit_geometry_srcs Earth.h EllipsoidOfRevolution.cc EllipsoidOfRevolution.h - Figure.cc Figure.h GreatCircle.cc GreatCircle.h @@ -34,7 +32,6 @@ list( APPEND eckit_geometry_srcs Point3.h PointLonLat.cc PointLonLat.h - Projection.cc Projection.h Range.cc Range.h diff --git a/src/eckit/geometry/Figure.cc b/src/eckit/geometry/Figure.cc deleted file mode 100644 index 948c8c98f..000000000 --- a/src/eckit/geometry/Figure.cc +++ /dev/null @@ -1,112 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/Figure.h" - -#include -#include - -#include "eckit/config/Configuration.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/log/JSON.h" -#include "eckit/log/Log.h" -#include "eckit/thread/AutoLock.h" -#include "eckit/thread/Mutex.h" - - -namespace eckit::geometry { - - -Figure::Figure(const Configuration& config) /*: - Figure(config.getDouble("a"), config.getDouble("b"))*/ -{ -} - - -static pthread_once_t __once = PTHREAD_ONCE_INIT; -static Mutex* __mutex = nullptr; -static std::map* __factories = nullptr; - - -static void __init() { - __mutex = new Mutex; - __factories = new std::map(); -} - - -Figure* FigureFactory::build(const Configuration& config) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - std::string type; - ASSERT(config.get("type", type)); - - return build(type, config); -} - - -Figure* FigureFactory::build(const std::string& type, const Configuration& config) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - if (auto f = __factories->find(type); f != __factories->end()) { - return f->second->make(config); - } - - list(Log::error() << "FigureFactory: unknown '" << type << "', choices are: "); - throw BadValue("FigureFactory: unknown '" + type + "'"); -} - - -std::ostream& FigureFactory::list(std::ostream& out) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - JSON j(out); - j.startObject(); - - j << "type"; - j.startList(); - for (const auto& p : *__factories) { - j << p.first; - } - j.endList(); - - j.endObject(); - - return out; -} - - -FigureFactory::FigureFactory(const std::string& key) : - key_(key) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - if (auto f = __factories->find(key); f != __factories->end()) { - throw BadValue("FigureFactory: duplicate '" + key + "'"); - } - - (*__factories)[key] = this; -} - - -FigureFactory::~FigureFactory() { - AutoLock lock(*__mutex); - - if (__factories != nullptr) { - __factories->erase(key_); - } -} - - -} // namespace eckit::geometry diff --git a/src/eckit/geometry/Figure.h b/src/eckit/geometry/Figure.h index d5b5aaea3..d77d8405b 100644 --- a/src/eckit/geometry/Figure.h +++ b/src/eckit/geometry/Figure.h @@ -12,9 +12,11 @@ #pragma once -#include #include +#include "eckit/memory/Builder.h" +#include "eckit/memory/Factory.h" + namespace eckit { class Configuration; @@ -27,23 +29,34 @@ namespace eckit::geometry { class Figure { public: // -- Types - // None + + using builder_t = BuilderT1
; + using ARG1 = const Configuration&; // -- Exceptions // None // -- Constructors - Figure(const Configuration&); + Figure() noexcept = default; + Figure(const Figure&) = default; + Figure(Figure&&) = default; + + // -- Destructor + + virtual ~Figure() = default; // -- Convertors // None // -- Operators - // None + + Figure& operator=(const Figure&) = default; + Figure& operator=(Figure&&) = default; // -- Methods - // None + + static std::string className() { return "figure"; } // -- Overridden methods // None @@ -91,35 +104,10 @@ class Figure { }; -struct FigureFactory { - static Figure* build(const Configuration&); - static Figure* build(const std::string&, const Configuration&); - static std::ostream& list(std::ostream&); - - FigureFactory(const FigureFactory&) = delete; - FigureFactory(FigureFactory&&) = delete; - FigureFactory& operator=(const FigureFactory&) = delete; - FigureFactory& operator=(FigureFactory&&) = delete; - - virtual Figure* make(const Configuration&) = 0; - -protected: - explicit FigureFactory(const std::string&); - virtual ~FigureFactory(); - -private: - const std::string key_; -}; - - -template -class FigureBuilder final : public FigureFactory { - Figure* make(const Configuration& config) override { return new T(config); } +using FigureFactory = Factory
; -public: - explicit FigureBuilder(const std::string& key) : - FigureFactory(key) {} -}; +template +using FigureBuilder = ConcreteBuilderT1; } // namespace eckit::geometry diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index ebb6bff5f..aecb69b08 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -12,7 +12,6 @@ #include "eckit/geometry/Grid.h" -#include #include #include #include diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 7b60a6e4b..808493061 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include #include #include @@ -24,7 +25,6 @@ #include "eckit/geometry/Iterator.h" #include "eckit/geometry/Ordering.h" #include "eckit/geometry/Point.h" -#include "eckit/geometry/Projection.h" #include "eckit/geometry/Renumber.h" #include "eckit/geometry/area/BoundingBox.h" diff --git a/src/eckit/geometry/Projection.cc b/src/eckit/geometry/Projection.cc deleted file mode 100644 index c93178a18..000000000 --- a/src/eckit/geometry/Projection.cc +++ /dev/null @@ -1,302 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/Projection.h" - -#include -#include - -#include "eckit/config/Configuration.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/log/JSON.h" -#include "eckit/log/Log.h" -#include "eckit/thread/AutoLock.h" -#include "eckit/thread/Mutex.h" - - -namespace eckit::geometry { - - -#if 0 -- mercator: - double DiInMetres - double DjInMetres - double LaDInDegrees - double latitudeOfFirstPointInDegrees - double longitudeOfFirstPointInDegrees - double projectionOrientationInDegrees - size_t n_i - size_t n_j -- polar_stereographic: - double DiInMetres - double DjInMetres - double LaDInDegrees - double latitudeOfFirstPointInDegrees - double longitudeOfFirstPointInDegrees - double projectionOrientationInDegrees - flags projectionCentreFlag - size_t n_i - size_t n_j -- lambert: - double DiInMetres - double DjInMetres - double LaDInDegrees - double Latin1InDegrees - double Latin2InDegrees - double LoVInDegrees - double latitudeOfFirstPointInDegrees - double latitudeOfSouthernPoleInDegrees - double longitudeOfFirstPointInDegrees - double longitudeOfSouthernPoleInDegrees - flags projectionCentreFlag - size_t n_i - size_t n_j -- albers: - double DiInMetres - double DjInMetres - double LaDInDegrees - double Latin1InDegrees - double Latin2InDegrees - double LoVInDegrees - double latitudeOfFirstPointInDegrees - double latitudeOfSouthernPoleInDegrees - double longitudeOfFirstPointInDegrees - double longitudeOfSouthernPoleInDegrees - flags projectionCentreFlag - size_t n_i - size_t n_j -- space_view: - double DiInMetres - double DjInMetres - double altitudeFromEarthCentreInMetres - double latitudeOfSubSatellitePointInDegrees - double longitudeOfSubSatellitePointInDegrees - double projectionOrientationInDegrees - double xOriginOfSectorImageInMetres - double xSubSatellitePointInMetres - double yOriginOfSectorImageInMetres - double ySubSatellitePointInMetres - size_t n_i - size_t n_j -- lambert_azimuthal_equal_area: - double DiInMetres - double DjInMetres - double centralLongitudeInDegrees - double latitudeOfFirstPointInDegrees - double longitudeOfFirstPointInDegrees - double standardParallelInDegrees -- equatorial_azimuthal_equidistant: - double DiInMetres - double DjInMetres - double latitudeOfTangencyPointInDegrees - double longitudeOfTangencyPointInDegrees - flags projectionCentreFlag -- unstructured_grid (grib2/localConcepts/[centre:s]/unstructuredGrid*): - string unstructuredGridSubtype = undefined/T/U/V/W/F (numberOfGridInReference) - string unstructuredGridType = undefined/ORCA2/ORCA1/ORCA025/ORCA12/eORCA1/eORCA025/eORCA12 (numberOfGridInReference) - string uuidOfHGrid -- irregular_latlon - - -// to instantiate ecCodes iterators -- regular_gg: - - latitudeFirstInDegrees, longitudeFirstInDegrees - - latitudeLastInDegrees - - DiInDegrees - - Ni - - Nj - - N - - iScansNegatively, jScansPositively -- reduced_gg: - - latitudeOfFirstGridPointInDegrees, longitudeOfFirstGridPointInDegrees - - latitudeOfLastGridPointInDegrees, longitudeOfLastGridPointInDegrees - - N - - pl - - Nj -- lambert_azimuthal_equal_area: - - latitudeOfFirstGridPointInDegrees, longitudeOfFirstGridPointInDegrees - - radius - - Nx - - Ny - - standardParallelInDegrees - - centralLongitudeInDegrees - - Dx - - Dy - - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning -- lambert: - - latitudeOfFirstGridPointInDegrees, longitudeOfFirstGridPointInDegrees - - radius - - Nx - - Ny - - LoVInDegrees - - LaDInDegrees - - Latin1InDegrees - - Latin2InDegrees - - DxInMetres - - DyInMetres - - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning -- regular_ll, rotated_ll: - - latitudeFirstInDegrees, longitudeFirstInDegrees - - DiInDegrees - - Ni - - Nj - - DjInDegrees - - isRotatedGrid - - angleOfRotation, latitudeOfSouthernPoleInDegrees, longitudeOfSouthernPoleInDegrees - - iScansNegatively, jScansPositively, jPointsAreConsecutive -- reduced_ll: - - latitudeFirstInDegrees, longitudeFirstInDegrees - - latitudeLastInDegrees, longitudeLastInDegrees - - Nj - - DjInDegrees - - pl -- mercator: - - latitudeOfFirstGridPointInDegrees, longitudeOfFirstGridPointInDegrees - - latitudeOfLastGridPointInDegrees, longitudeOfLastGridPointInDegrees - - radius - - Ni - - Nj - - LaDInDegrees - - orientationOfTheGridInDegrees - - DiInMetres - - DjInMetres - - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning -- polar_stereographic: - - latitudeOfFirstGridPointInDegrees, longitudeOfFirstGridPointInDegrees - - radius - - Nx - - Ny - - southPoleOnProjectionPlane - - orientationOfTheGridInDegrees - - LaDInDegrees - - DxInMetres - - DyInMetres - - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning -- space_view: - - radius - - earthIsOblate - - earthMajorAxis - - earthMinorAxis - - Nx - - Ny - - latitudeOfSubSatellitePointInDegrees - - longitudeOfSubSatellitePointInDegrees - - dx - - dy - - XpInGridLengths - - YpInGridLengths - - orientationOfTheGridInDegrees - - NrInRadiusOfEarthScaled - - Xo - - Yo - - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning - - -Projection, rotation, shape (grib2/template.3.(rotation|shape_of_the_earth).def) -- projSourceString, projTargetString, projString=projTargetString - - double latitudeOfSouthernPoleInDegrees - double longitudeOfSouthernPoleInDegrees - double angleOfRotationInDegrees - - bool is_oblate - double majorAxisInMetres - double minorAxisInMetres - double radiusInMetres - -Projection centre (grib2/tables/30/3.5.table) - 1 0 North Pole is on the projection plane - 1 1 South Pole is on the projection plane - 2 0 Only one projection centre is used - 2 1 Projection is bipolar and symmetric -#endif - - -static pthread_once_t __once = PTHREAD_ONCE_INIT; -static Mutex* __mutex = nullptr; -static std::map* __factories = nullptr; - - -static void __init() { - __mutex = new Mutex; - __factories = new std::map(); -} - - -Projection* ProjectionFactory::build(const Configuration& config) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - Projection::Type type; - ASSERT(config.get("type", type)); - - return build(type, config); -} - - -Projection* ProjectionFactory::build(const Projection::Type& type, - const Configuration& config) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - if (auto f = __factories->find(type); f != __factories->end()) { - return f->second->make(config); - } - - list(Log::error() << "ProjectionFactory: unknown '" << type << "', choices are: "); - throw BadValue("ProjectionFactory: unknown '" + type + "'"); -} - - -std::ostream& ProjectionFactory::list(std::ostream& out) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - JSON j(out); - j.startObject(); - - j << "type"; - j.startList(); - for (const auto& p : *__factories) { - j << p.first; - } - j.endList(); - - j.endObject(); - - return out; -} - - -ProjectionFactory::ProjectionFactory(const Projection::Type& key) : - key_(key) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - if (auto f = __factories->find(key); f != __factories->end()) { - throw BadValue("ProjectionFactory: duplicate '" + key + "'"); - } - - (*__factories)[key] = this; -} - - -ProjectionFactory::~ProjectionFactory() { - AutoLock lock(*__mutex); - - if (__factories != nullptr) { - __factories->erase(key_); - } -} - - -} // namespace eckit::geometry diff --git a/src/eckit/geometry/Projection.h b/src/eckit/geometry/Projection.h index 1964aeaba..32fe7ae87 100644 --- a/src/eckit/geometry/Projection.h +++ b/src/eckit/geometry/Projection.h @@ -12,10 +12,11 @@ #pragma once -#include #include #include "eckit/geometry/Point.h" +#include "eckit/memory/Builder.h" +#include "eckit/memory/Factory.h" namespace eckit { @@ -30,15 +31,15 @@ class Projection { public: // -- Types - using Type = std::string; + using builder_t = BuilderT1; + using ARG1 = const Configuration&; // -- Exceptions // None // -- Constructors - Projection() noexcept = default; - + Projection() noexcept = default; Projection(const Projection&) = default; Projection(Projection&&) = default; @@ -59,6 +60,8 @@ class Projection { virtual Point fwd(const Point&) const = 0; virtual Point inv(const Point&) const = 0; + static std::string className() { return "projection"; } + // -- Overridden methods // None @@ -105,35 +108,10 @@ class Projection { }; -struct ProjectionFactory { - static Projection* build(const Configuration&); - static Projection* build(const Projection::Type&, const Configuration&); - static std::ostream& list(std::ostream&); - - ProjectionFactory(const ProjectionFactory&) = delete; - ProjectionFactory(ProjectionFactory&&) = delete; - ProjectionFactory& operator=(const ProjectionFactory&) = delete; - ProjectionFactory& operator=(ProjectionFactory&&) = delete; - - virtual Projection* make(const Configuration&) = 0; +using ProjectionFactory = Factory; -protected: - explicit ProjectionFactory(const Projection::Type&); - virtual ~ProjectionFactory(); - -private: - const Projection::Type key_; -}; - - -template -class ProjectionBuilder final : public ProjectionFactory { - Projection* make(const Configuration& config) override { return new T(config); } - -public: - explicit ProjectionBuilder(const Projection::Type& key) : - ProjectionFactory(key) {} -}; +template +using ProjectionBuilder = ConcreteBuilderT1; } // namespace eckit::geometry diff --git a/src/eckit/geometry/grid/RegularGrid.cc b/src/eckit/geometry/grid/RegularGrid.cc index 09c905e67..a2f79d764 100644 --- a/src/eckit/geometry/grid/RegularGrid.cc +++ b/src/eckit/geometry/grid/RegularGrid.cc @@ -29,7 +29,6 @@ namespace eckit::geometry::grid { RegularGrid::RegularGrid(Projection* projection, const Configuration& config) : Grid(config), projection_(projection), - figure_(config), xPlus_(true), yPlus_(false) { ASSERT(projection_); @@ -95,9 +94,8 @@ RegularGrid::~RegularGrid() = default; Projection* RegularGrid::make_projection_from_proj(const Configuration& config) { - if (std::string proj; - config.get("proj", proj)) { - return ProjectionFactory::build("proj", config); + if (config.has("proj")) { + return ProjectionFactory::instance().get("proj").create(config); } return nullptr; @@ -193,11 +191,7 @@ struct Lambert : RegularGrid { auto Latin1InDegrees = config.getDouble("Latin1InDegrees", LaDInDegrees); auto Latin2InDegrees = config.getDouble("Latin2InDegrees", LaDInDegrees); - return ProjectionFactory::build("lambert_conformal_conic", - MappedConfiguration({{"latitude1", Latin1InDegrees}, - {"latitude2", Latin2InDegrees}, - {"latitude0", LaDInDegrees}, - {"longitude0", LoVInDegrees}})); + return ProjectionFactory::instance().get("lambert_conformal_conic").create(MappedConfiguration({{"latitude1", Latin1InDegrees}, {"latitude2", Latin2InDegrees}, {"latitude0", LaDInDegrees}, {"longitude0", LoVInDegrees}})); } }; @@ -222,9 +216,7 @@ struct LambertAzimuthalEqualArea : RegularGrid { ASSERT(config.get("centralLongitudeInDegrees", centralLongitude)); config.get("radius", radius = Earth::radius()); - return ProjectionFactory::build("lambert_azimuthal_equal_area", MappedConfiguration({{"standard_parallel", standardParallel}, - {"central_longitude", centralLongitude}, - {"radius", radius}})); + return ProjectionFactory::instance().get("lambert_azimuthal_equal_area").create(MappedConfiguration({{"standard_parallel", standardParallel}, {"central_longitude", centralLongitude}, {"radius", radius}})); } }; diff --git a/tests/geometry/test_projection.cc b/tests/geometry/test_projection.cc index 671fb8f69..31e0c721c 100644 --- a/tests/geometry/test_projection.cc +++ b/tests/geometry/test_projection.cc @@ -32,7 +32,7 @@ int main(int argc, char* argv[]) { Point p = PointLonLat{1, 1}; { - Projection projection(ProjectionFactory::build("none", MappedConfiguration{})); + Projection projection(ProjectionFactory::instance().get("none").create(MappedConfiguration{})); EXPECT(points_equal(p, projection->inv(p))); EXPECT(points_equal(p, projection->fwd(p))); } @@ -44,16 +44,16 @@ int main(int argc, char* argv[]) { {"south_pole_lon", -361.}, }); - Projection projection(ProjectionFactory::build(param.getString("projection"), param)); + Projection projection(ProjectionFactory::instance().get(param.getString("projection")).create(param)); EXPECT(points_equal(p, projection->inv(projection->fwd(p)))); EXPECT(points_equal(p, projection->fwd(projection->inv(p)))); } { - Projection s1(ProjectionFactory::build("ll_to_xyz", MappedConfiguration({{"R", 1.}}))); - Projection s2(ProjectionFactory::build("ll_to_xyz", MappedConfiguration({{"a", 1.}, {"b", 1.}}))); - Projection s3(ProjectionFactory::build("ll_to_xyz", MappedConfiguration({{"a", 1.}, {"b", 0.5}}))); + Projection s1(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"R", 1.}}))); + Projection s2(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 1.}}))); + Projection s3(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 0.5}}))); EXPECT(points_equal(p, s1->inv(s1->fwd(p)))); EXPECT(points_equal(p, s2->inv(s2->fwd(p)))); From f2e6ddf0df1edd782c05ecb623e7850e66655b14 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 18 Aug 2023 17:39:20 +0100 Subject: [PATCH 310/737] eckit::geometry instance()-based factories --- src/eckit/geometry/Grid.cc | 117 ++--------------------------------- src/eckit/geometry/Grid.h | 53 ++++------------ src/tools/eckit-grid-list.cc | 5 +- 3 files changed, 19 insertions(+), 156 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index aecb69b08..b19110528 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -20,7 +20,6 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geometry/GridConfig.h" #include "eckit/geometry/util/regex.h" -#include "eckit/log/JSON.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -100,13 +99,11 @@ static pthread_once_t __once; static Mutex* __mutex = nullptr; static std::map* __grid_uids = nullptr; static std::map* __grid_names = nullptr; -static std::map* __grid_types = nullptr; static void __init() { __mutex = new Mutex; __grid_uids = new std::remove_reference::type; __grid_names = new std::remove_reference::type; - __grid_types = new std::remove_reference::type; } @@ -124,8 +121,8 @@ const Grid* GridFactory::build(const Configuration& config) { return GridFactoryName::build(name); } - if (config.has("type")) { - return GridFactoryType::build(config); + if (std::string type; config.get("type", type)) { + return GridFactoryType::instance().get(type).create(config); } list(Log::error() << "Grid: cannot build grid, choices are: "); @@ -145,22 +142,7 @@ void GridFactory::list(std::ostream& out) { GridFactoryName::list(out << "name: "); out << std::endl; - GridFactoryType::list(out << "type: "); - out << std::endl; -} - - -void GridFactory::json(JSON& j) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - GridConfig::instance(); - - j.startObject(); - GridFactoryUID::json(j << "uid"); - GridFactoryName::json(j << "name"); - GridFactoryType::json(j << "type"); - j.endObject(); + out << GridFactoryType::instance() << std::endl; } @@ -202,23 +184,7 @@ void GridFactoryUID::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - JSON j(out); - json(j); -} - - -void GridFactoryUID::json(JSON& j) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - j.startObject(); - for (const auto& p : *__grid_uids) { - j << p.first; - - std::unique_ptr config(p.second->config()); - j << *config; - } - j.endObject(); + out << "..." << std::endl; } @@ -281,23 +247,7 @@ void GridFactoryName::list(std::ostream& out) { pthread_once(&__once, __init); AutoLock lock(*__mutex); - JSON j(out); - json(j); -} - - -void GridFactoryName::json(JSON& j) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - j.startObject(); - for (const auto& p : *__grid_names) { - j << p.first; - - std::unique_ptr config(p.second->config()); - j << *config; - } - j.endObject(); + out << "..." << std::endl; } @@ -323,61 +273,4 @@ GridFactoryName::~GridFactoryName() { } -GridFactoryType::GridFactoryType(const std::string& type) : - type_(type) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - if (__grid_types->find(type) == __grid_types->end()) { - (*__grid_types)[type] = this; - return; - } - - throw SeriousBug("Grid: duplicate type '" + type + "'"); -} - - -GridFactoryType::~GridFactoryType() { - AutoLock lock(*__mutex); - __grid_types->erase(type_); -} - - -const Grid* GridFactoryType::build(const Configuration& config) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - std::string type; - if (config.get("type", type)) { - if (auto j = __grid_types->find(type); j != __grid_types->end()) { - return j->second->make(config); - } - } - - list(Log::error() << "Grid: unknown type '" << type << "', choices are: "); - throw SeriousBug("Grid: unknown type '" + type + "'"); -} - - -void GridFactoryType::list(std::ostream& out) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - JSON j(out); - json(j); -} - - -void GridFactoryType::json(JSON& j) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - j.startList(); - for (const auto& p : *__grid_types) { - j << p.first; - } - j.endList(); -} - - } // namespace eckit::geometry diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 808493061..7e35cb8a1 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -27,11 +27,8 @@ #include "eckit/geometry/Point.h" #include "eckit/geometry/Renumber.h" #include "eckit/geometry/area/BoundingBox.h" - - -namespace eckit { -class JSON; -} +#include "eckit/memory/Builder.h" +#include "eckit/memory/Factory.h" namespace eckit::geometry { @@ -41,6 +38,9 @@ class Grid { public: // -- Types + using builder_t = BuilderT1; + using ARG1 = const Configuration&; + struct Iterator final : std::unique_ptr { explicit Iterator(geometry::Iterator* it) : unique_ptr(it) { ASSERT(unique_ptr::operator bool()); } @@ -124,7 +124,8 @@ class Grid { // None // -- Class methods - // None + + static std::string className() { return "grid"; } protected: // -- Constructors @@ -167,11 +168,16 @@ class Grid { }; +using GridFactoryType = Factory; + +template +using GridRegisterType = ConcreteBuilderT1; + + struct GridFactory { // This is 'const' as Grid should always be immutable static const Grid* build(const Configuration&); static void list(std::ostream&); - static void json(JSON&); }; @@ -185,7 +191,6 @@ struct GridFactoryUID { static const Grid* build(const std::string&); static void list(std::ostream&); - static void json(JSON&); static void insert(const std::string& name, MappedConfiguration*); protected: @@ -209,7 +214,6 @@ struct GridFactoryName { static const Grid* build(const std::string& name); static void list(std::ostream&); - static void json(JSON&); static void insert(const std::string& name, MappedConfiguration*); protected: @@ -225,29 +229,6 @@ struct GridFactoryName { }; -struct GridFactoryType { - GridFactoryType(const GridFactoryType&) = delete; - GridFactoryType(GridFactoryType&&) = delete; - GridFactoryType& operator=(const GridFactoryType&) = delete; - GridFactoryType& operator=(GridFactoryType&&) = delete; - - // This is 'const' as Grid should always be immutable - static const Grid* build(const Configuration&); - - static void list(std::ostream&); - static void json(JSON&); - -protected: - explicit GridFactoryType(const std::string& type); - virtual ~GridFactoryType(); - -private: - virtual const Grid* make(const Configuration&) = 0; - - const std::string type_; -}; - - template struct GridRegisterUID final : GridFactoryUID { explicit GridRegisterUID(const std::string& uid) : @@ -264,12 +245,4 @@ struct GridRegisterName final : GridFactoryName { }; -template -struct GridRegisterType final : GridFactoryType { - explicit GridRegisterType(const std::string& type) : - GridFactoryType(type) {} - const Grid* make(const Configuration& config) override { return new T(config); } -}; - - } // namespace eckit::geometry diff --git a/src/tools/eckit-grid-list.cc b/src/tools/eckit-grid-list.cc index e040be658..bd96224dc 100644 --- a/src/tools/eckit-grid-list.cc +++ b/src/tools/eckit-grid-list.cc @@ -10,7 +10,6 @@ #include "eckit/geometry/Grid.h" -#include "eckit/log/JSON.h" #include "eckit/log/Log.h" #include "eckit/option/EckitTool.h" @@ -23,9 +22,7 @@ struct EckitGridList final : EckitTool { EckitTool(argc, argv) {} void execute(const option::CmdArgs&) override { - JSON j(Log::info()); - geometry::GridFactory::json(j); - Log::info() << std::endl; + Log::info() << geometry::GridFactoryType::instance() << std::endl; } void usage(const std::string& tool) const override { From 835289f681f5cb9104f23438a108510fd1623a92 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 21 Aug 2023 12:17:43 +0100 Subject: [PATCH 311/737] eckit::geometry instance()-based factories --- src/eckit/geometry/CMakeLists.txt | 1 + src/eckit/geometry/Configurator.h | 343 ++++++++++++++++++++++++++++++ 2 files changed, 344 insertions(+) create mode 100644 src/eckit/geometry/Configurator.h diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index ee9ed6337..d376f3d4c 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -2,6 +2,7 @@ list( APPEND eckit_geometry_srcs Area.h Cache.cc Cache.h + Configurator.h CoordinateHelpers.cc CoordinateHelpers.h Domain.cc diff --git a/src/eckit/geometry/Configurator.h b/src/eckit/geometry/Configurator.h new file mode 100644 index 000000000..75ac22a17 --- /dev/null +++ b/src/eckit/geometry/Configurator.h @@ -0,0 +1,343 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include +#include +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/thread/AutoLock.h" +#include "eckit/thread/Mutex.h" +#include "eckit/utils/Regex.h" + + +namespace eckit { +class Configuration; +} + + +namespace eckit::geometry { + +//------------------------------------------------------------------------------------------------------ + +template +class Configurator { +public: + // -- Types + + using configurator_t = C; + using key_t = std::string; + using storage_t = std::map; + + // -- Constructors + + Configurator(const Configurator&) = delete; + Configurator(Configurator&&) = delete; + + // -- Operators + + void operator=(const Configurator&) = delete; + void operator=(Configurator&&) = delete; + + // -- Methods + + static Configurator& instance(); + + bool exists(const key_t&) const; + void regist(const key_t&, configurator_t*); + void unregist(const key_t&); + + const configurator_t& get(const key_t&) const; + const configurator_t& match(const std::string&) const; + +private: + // -- Constructors + + Configurator() = default; + + // -- Destructor + + ~Configurator() = default; + + // -- Members + + mutable Mutex mutex_; + storage_t store_; + + // -- Methods + + void print(std::ostream&) const; + + // -- Friends + + friend std::ostream& operator<<(std::ostream& os, const Configurator& o) { + o.print(os); + return os; + } +}; + +//------------------------------------------------------------------------------------------------------ + +template +Configurator& Configurator::instance() { + static Configurator obj; + return obj; +} + +template +bool Configurator::exists(const key_t& k) const { + AutoLock lock(mutex_); + return (store_.find(k) != store_.end()); +} + +template +void Configurator::regist(const key_t& k, configurator_t* c) { + AutoLock lock(mutex_); + if (exists(k)) { + throw BadParameter("Configurator has already a builder for " + k, Here()); + } + ASSERT(c != nullptr); + store_[k] = c; +} + +template +void Configurator::unregist(const key_t& k) { + AutoLock lock(mutex_); + if (!exists(k)) { + throw BadParameter("Configurator unknown: '" + k + "'", Here()); + } + store_.erase(k); +} + +template +const typename Configurator::configurator_t& Configurator::get(const key_t& k) const { + AutoLock lock(mutex_); + if (!exists(k)) { + throw BadParameter("Configurator unknown: '" + k + "'", Here()); + } + return *(store_.find(k)->second); +} + +template +const typename Configurator::configurator_t& Configurator::match(const std::string& k) const { + AutoLock lock(mutex_); + + auto end = store_.cend(); + auto i = end; + for (auto j = store_.cbegin(); j != end; ++j) { + if (Regex(j->first).match(k)) { + if (i != end) { + throw SeriousBug("Configurator name '" + k + "' matches '" + i->first + "' and '" + j->first + "'"); + } + i = j; + } + } + + if (i != end) { + return *(i->second); + } + + throw BadParameter("Configurator unknown: '" + k + "'", Here()); +} + +template +void Configurator::print(std::ostream& os) const { + AutoLock lock(mutex_); + os << "Configurator" << std::endl; + + int key_width = 0; + for (const auto& i : store_) { + key_width = std::max(static_cast(i.first.size()), key_width); + } + + for (const auto& i : store_) { + os << " " << std::setw(key_width) << std::left << i.first << " -- " << i.second << std::endl; + } +} + +//------------------------------------------------------------------------------------------------------ + +class ConfigurationGenerator { +public: + // -- Types + + using key_t = std::string; + + // -- Constructors + + ConfigurationGenerator() = default; + ConfigurationGenerator(const ConfigurationGenerator&) = delete; + ConfigurationGenerator(ConfigurationGenerator&&) = delete; + + // -- Destructor + + virtual ~ConfigurationGenerator() = default; + + // -- Operators + + void operator=(const ConfigurationGenerator&) = delete; + void operator=(ConfigurationGenerator&&) = delete; +}; + +//------------------------------------------------------------------------------------------------------ + +class ConfigurationGeneratorT0 : public ConfigurationGenerator { +public: + // -- Methods + + virtual Configuration* config() const = 0; +}; + +//------------------------------------------------------------------------------------------------------ + +template +class ConfigurationGeneratorT1 : public ConfigurationGenerator { +public: + // -- Types + + using arg1_t = ARG1; + + // -- Methods + + virtual Configuration* config(arg1_t) const = 0; +}; + +//------------------------------------------------------------------------------------------------------ + +template +class ConfigurationGeneratorT2 : public ConfigurationGenerator { +public: + // -- Types + + using arg1_t = ARG1; + using arg2_t = ARG2; + + // -- Methods + + virtual Configuration* config(arg1_t, arg2_t) const = 0; +}; + +//------------------------------------------------------------------------------------------------------ + +template +class ConcreteConfigurationGeneratorT0 final : public ConfigurationGeneratorT0 { +public: + // -- Constructors + + explicit ConcreteConfigurationGeneratorT0(const ConfigurationGeneratorT0::key_t& k) : + key_(k) { + Configurator::instance().regist(key_, this); + } + + ConcreteConfigurationGeneratorT0(const ConcreteConfigurationGeneratorT0&) = delete; + ConcreteConfigurationGeneratorT0(ConcreteConfigurationGeneratorT0&&) = delete; + + // -- Destructor + + ~ConcreteConfigurationGeneratorT0() override { + Configurator::instance().unregist(key_); + } + + // -- Operators + + void operator=(const ConcreteConfigurationGeneratorT0&) = delete; + void operator=(ConcreteConfigurationGeneratorT0&&) = delete; + + // -- Overridden methods + + Configuration* config() const override { return T::config(); } + +private: + // -- Members + + ConfigurationGeneratorT0::key_t key_; +}; + +//------------------------------------------------------------------------------------------------------ + +template +class ConcreteConfigurationGeneratorT1 final : public ConfigurationGeneratorT1 { +public: + // -- Constructors + + explicit ConcreteConfigurationGeneratorT1(const typename ConfigurationGeneratorT1::key_t& k) : + key_(k) { + Configurator>::instance().regist(key_, this); + } + + ConcreteConfigurationGeneratorT1(const ConcreteConfigurationGeneratorT1&) = delete; + ConcreteConfigurationGeneratorT1(ConcreteConfigurationGeneratorT1&&) = delete; + + // -- Destructor + + ~ConcreteConfigurationGeneratorT1() override { + Configurator>::instance().unregist(key_); + } + + // -- Operators + + void operator=(const ConcreteConfigurationGeneratorT1&) = delete; + void operator=(ConcreteConfigurationGeneratorT1&&) = delete; + + // -- Overridden methods + + Configuration* config(typename ConfigurationGeneratorT1::arg1_t p1) const override { return T::config(p1); } + +private: + // -- Members + + typename ConfigurationGeneratorT1::key_t key_; +}; + +//------------------------------------------------------------------------------------------------------ + +template +class ConcreteConfigurationGeneratorT2 final : public ConfigurationGeneratorT2 { +public: + // -- Constructors + + explicit ConcreteConfigurationGeneratorT2(const typename ConfigurationGeneratorT2::key_t& k) : + key_(k) { + Configurator>::instance().regist(key_, this); + } + + ConcreteConfigurationGeneratorT2(const ConcreteConfigurationGeneratorT2&) = delete; + ConcreteConfigurationGeneratorT2(ConcreteConfigurationGeneratorT2&&) = delete; + + // -- Destructor + + ~ConcreteConfigurationGeneratorT2() override { + Configurator>::instance().unregist(key_); + } + + // -- Operators + + void operator=(const ConcreteConfigurationGeneratorT2&) = delete; + void operator=(ConcreteConfigurationGeneratorT2&&) = delete; + + // -- Overridden methods + + Configuration* config(typename ConfigurationGeneratorT1::arg1_t p1, typename ConfigurationGeneratorT1::arg2_t p2) const override { return T::config(p1, p2); } + +private: + // -- Members + + typename ConfigurationGeneratorT2::key_t key_; +}; + +//------------------------------------------------------------------------------------------------------ + +} // namespace eckit::geometry From 1d44aa790f776195f162a15a2723e6e225ec89dd Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 21 Aug 2023 12:20:00 +0100 Subject: [PATCH 312/737] eckit::geometry instance()-based factories --- src/eckit/geometry/Grid.cc | 167 +++------------------------ src/eckit/geometry/Grid.h | 77 +++--------- src/eckit/geometry/GridConfig.cc | 23 +++- src/eckit/geometry/grid/HEALPix.cc | 2 +- src/eckit/geometry/grid/ReducedGG.cc | 4 +- src/eckit/geometry/grid/RegularGG.cc | 2 +- src/eckit/geometry/grid/RegularLL.cc | 2 +- src/tools/eckit-grid-list.cc | 3 +- src/tools/eckit-grid.cc | 5 +- tests/geometry/test_grid.cc | 3 +- 10 files changed, 60 insertions(+), 228 deletions(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index b19110528..465420242 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -14,12 +14,9 @@ #include #include -#include -#include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geometry/GridConfig.h" -#include "eckit/geometry/util/regex.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -94,31 +91,25 @@ Renumber Grid::reorder(const PointLonLat&) const { } -static pthread_once_t __once; - -static Mutex* __mutex = nullptr; -static std::map* __grid_uids = nullptr; -static std::map* __grid_names = nullptr; - -static void __init() { - __mutex = new Mutex; - __grid_uids = new std::remove_reference::type; - __grid_names = new std::remove_reference::type; +GridFactory& GridFactory::instance() { + static GridFactory obj; + return obj; } -const Grid* GridFactory::build(const Configuration& config) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); +const Grid* GridFactory::build_(const Configuration& config) const { + AutoLock lock(mutex_); GridConfig::instance(); if (std::string uid; config.get("uid", uid)) { - return GridFactoryUID::build(uid); + std::unique_ptr cfg(GridConfigurationUID::instance().get(uid).config()); + return build(*cfg); } if (std::string name; config.get("name", name)) { - return GridFactoryName::build(name); + std::unique_ptr cfg(GridConfigurationName::instance().match(name).config(name)); + return build(*cfg); } if (std::string type; config.get("type", type)) { @@ -130,147 +121,15 @@ const Grid* GridFactory::build(const Configuration& config) { } -void GridFactory::list(std::ostream& out) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); +void GridFactory::list_(std::ostream& out) const { + AutoLock lock(mutex_); GridConfig::instance(); - GridFactoryUID::list(out << "uid: "); - out << std::endl; - - GridFactoryName::list(out << "name: "); - out << std::endl; - + out << GridConfigurationUID::instance() << std::endl; + out << GridConfigurationName::instance() << std::endl; out << GridFactoryType::instance() << std::endl; } -GridFactoryUID::GridFactoryUID(const std::string& uid) : - uid_(uid) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - if (__grid_uids->find(uid) == __grid_uids->end()) { - (*__grid_uids)[uid] = this; - return; - } - - throw SeriousBug("Grid: duplicate identifier '" + uid + "'"); -} - - -GridFactoryUID::~GridFactoryUID() { - AutoLock lock(*__mutex); - __grid_uids->erase(uid_); -} - - -const Grid* GridFactoryUID::build(const std::string& uid) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - if (auto j = __grid_uids->find(uid); j != __grid_uids->end()) { - std::unique_ptr config(j->second->config()); - return GridFactory::build(*config); - } - - list(Log::error() << "Grid: unknown identifier '" << uid << "', choices are: "); - throw SeriousBug("Grid: unknown identifier '" + uid + "'"); -} - - -void GridFactoryUID::list(std::ostream& out) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - out << "..." << std::endl; -} - - -void GridFactoryUID::insert(const std::string& uid, MappedConfiguration* config) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - struct Insert final : GridFactoryUID { - Insert(const std::string& uid, MappedConfiguration* config) : - GridFactoryUID(uid), config_(config) {} - Configuration* config() override { return new MappedConfiguration(*config_); } - const std::unique_ptr config_; - }; - - new Insert(uid, config); -} - - -GridFactoryName::GridFactoryName(const std::string& pattern, const std::string& example) : - pattern_(pattern), example_(example) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - if (__grid_names->find(pattern) == __grid_names->end()) { - (*__grid_names)[pattern] = this; - return; - } - - throw SeriousBug("Grid: duplicate name '" + pattern + "'"); -} - - -const Grid* GridFactoryName::build(const std::string& name) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - const auto end = __grid_names->cend(); - - auto i = end; - for (auto j = __grid_names->cbegin(); j != end; ++j) { - if (util::regex_match(j->second->pattern_, name)) { - if (i != end) { - throw SeriousBug("Grid: name '" + name + "' matches '" + i->second->pattern_ + "' and '" + j->second->pattern_ + "'"); - } - i = j; - } - } - - if (i != end) { - std::unique_ptr config(i->second->config(name)); - return GridFactory::build(*config); - } - - list(Log::error() << "Grid: unknown name '" << name << "', choices are: "); - throw SeriousBug("Grid: unknown name '" + name + "'"); -} - - -void GridFactoryName::list(std::ostream& out) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - out << "..." << std::endl; -} - - -void GridFactoryName::insert(const std::string& name, MappedConfiguration* config) { - pthread_once(&__once, __init); - AutoLock lock(*__mutex); - - struct Insert final : GridFactoryName { - Insert(const std::string& name, const std::string& example, MappedConfiguration* config) : - GridFactoryName(name, example), config_(config) {} - Configuration* config(const std::string&) const override { return new MappedConfiguration(*config_); } - const std::unique_ptr config_; - }; - - ASSERT(config != nullptr); - new Insert(name, config->getString("example", ""), config); -} - - -GridFactoryName::~GridFactoryName() { - AutoLock lock(*__mutex); - __grid_names->erase(pattern_); -} - - } // namespace eckit::geometry diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 7e35cb8a1..84f2627e6 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -21,6 +21,7 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/geometry/Area.h" +#include "eckit/geometry/Configurator.h" #include "eckit/geometry/Increments.h" #include "eckit/geometry/Iterator.h" #include "eckit/geometry/Ordering.h" @@ -168,80 +169,34 @@ class Grid { }; -using GridFactoryType = Factory; +using GridFactoryType = Factory; +using GridConfigurationName = Configurator>; +using GridConfigurationUID = Configurator; + template using GridRegisterType = ConcreteBuilderT1; +template +using GridRegisterUID = ConcreteConfigurationGeneratorT0; -struct GridFactory { - // This is 'const' as Grid should always be immutable - static const Grid* build(const Configuration&); - static void list(std::ostream&); -}; - +template +using GridRegisterName = ConcreteConfigurationGeneratorT1; -struct GridFactoryUID { - GridFactoryUID(const GridFactoryUID&) = delete; - GridFactoryUID(GridFactoryUID&&) = delete; - GridFactoryUID& operator=(const GridFactoryUID&) = delete; - GridFactoryUID& operator=(GridFactoryUID&&) = delete; +struct GridFactory { // This is 'const' as Grid should always be immutable - static const Grid* build(const std::string&); - - static void list(std::ostream&); - static void insert(const std::string& name, MappedConfiguration*); - -protected: - explicit GridFactoryUID(const std::string& uid); - virtual ~GridFactoryUID(); + static const Grid* build(const Configuration& config) { return instance().build_(config); } + static void list(std::ostream& out) { return instance().list_(out); } private: - virtual Configuration* config() = 0; - - const std::string uid_; -}; - - -struct GridFactoryName { - GridFactoryName(const GridFactoryName&) = delete; - GridFactoryName(GridFactoryName&&) = delete; - GridFactoryName& operator=(const GridFactoryName&) = delete; - GridFactoryName& operator=(GridFactoryName&&) = delete; + static GridFactory& instance(); // This is 'const' as Grid should always be immutable - static const Grid* build(const std::string& name); - - static void list(std::ostream&); - static void insert(const std::string& name, MappedConfiguration*); - -protected: - explicit GridFactoryName(const std::string& pattern, const std::string& example = ""); - virtual ~GridFactoryName(); - -private: - Configuration* config() const { return config(example_); } - virtual Configuration* config(const std::string& name) const = 0; - - const std::string pattern_; - const std::string example_; -}; - - -template -struct GridRegisterUID final : GridFactoryUID { - explicit GridRegisterUID(const std::string& uid) : - GridFactoryUID(uid) {} - Configuration* config() override { return T::config(); } -}; - + const Grid* build_(const Configuration&) const; + void list_(std::ostream&) const; -template -struct GridRegisterName final : GridFactoryName { - explicit GridRegisterName(const std::string& pattern, const std::string& example) : - GridFactoryName(pattern, example) {} - Configuration* config(const std::string& name) const override { return T::config(name); } + mutable Mutex mutex_; }; diff --git a/src/eckit/geometry/GridConfig.cc b/src/eckit/geometry/GridConfig.cc index e2ec18223..70363ca63 100644 --- a/src/eckit/geometry/GridConfig.cc +++ b/src/eckit/geometry/GridConfig.cc @@ -13,6 +13,7 @@ #include "eckit/geometry/GridConfig.h" #include +#include #include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" @@ -76,24 +77,38 @@ GridConfig::GridConfig(const PathName& path) { auto* config = new MappedConfiguration; config_.reset(config); + struct ConfigurationFromUID final : GridConfigurationUID::configurator_t { + explicit ConfigurationFromUID(MappedConfiguration* config) : + config_(config) {} + Configuration* config() const override { return new MappedConfiguration(*config_); } + std::unique_ptr config_; + }; + + struct ConfigurationFromName final : GridConfigurationName::configurator_t { + explicit ConfigurationFromName(MappedConfiguration* config) : + config_(config) {} + Configuration* config(GridConfigurationName::configurator_t::arg1_t) const override { return new MappedConfiguration(*config_); } + std::unique_ptr config_; + }; + if (path.exists()) { ValueMap map(YAMLParser::decodeFile(path)); for (const auto& kv : map) { const auto key = kv.first.as(); - if (key == "grid_names") { + if (key == "grid_uids") { for (ValueMap m : static_cast(kv.second)) { ASSERT(m.size() == 1); - GridFactoryName::insert(m.begin()->first, config_from_value_map(m.begin()->second)); + GridConfigurationUID::instance().regist(m.begin()->first.as(), new ConfigurationFromUID(config_from_value_map(m.begin()->second))); } continue; } - if (key == "grid_uids") { + if (key == "grid_names") { for (ValueMap m : static_cast(kv.second)) { ASSERT(m.size() == 1); - GridFactoryUID::insert(m.begin()->first, config_from_value_map(m.begin()->second)); + GridConfigurationName::instance().regist(m.begin()->first.as(), new ConfigurationFromName(config_from_value_map(m.begin()->second))); } continue; } diff --git a/src/eckit/geometry/grid/HEALPix.cc b/src/eckit/geometry/grid/HEALPix.cc index 4393a32f8..f021d8153 100644 --- a/src/eckit/geometry/grid/HEALPix.cc +++ b/src/eckit/geometry/grid/HEALPix.cc @@ -218,7 +218,7 @@ std::pair, std::vector> HEALPix::to_latlon() const { static const GridRegisterType __grid_type("healpix"); -static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*", "H2"); +static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/ReducedGG.cc b/src/eckit/geometry/grid/ReducedGG.cc index b365ec42c..e49225481 100644 --- a/src/eckit/geometry/grid/ReducedGG.cc +++ b/src/eckit/geometry/grid/ReducedGG.cc @@ -187,8 +187,8 @@ struct ReducedGGOctahedral { static const GridRegisterType __grid_type("reduced_gg"); -static const GridRegisterName __grid_pattern_1("[nN][1-9][0-9]*", "N16"); -static const GridRegisterName __grid_pattern_2("[oO][1-9][0-9]*", "O2"); +static const GridRegisterName __grid_pattern_1("[nN][1-9][0-9]*"); +static const GridRegisterName __grid_pattern_2("[oO][1-9][0-9]*"); } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/RegularGG.cc b/src/eckit/geometry/grid/RegularGG.cc index 6645f123d..d456e145d 100644 --- a/src/eckit/geometry/grid/RegularGG.cc +++ b/src/eckit/geometry/grid/RegularGG.cc @@ -182,7 +182,7 @@ Iterator* RegularGG::iterator() const { static const GridRegisterType __grid_type("regular_gg"); -static const GridRegisterName __grid_pattern("[fF][1-9][0-9]*", "F2"); +static const GridRegisterName __grid_pattern("[fF][1-9][0-9]*"); } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/RegularLL.cc b/src/eckit/geometry/grid/RegularLL.cc index 12ee11c01..1ccf67024 100644 --- a/src/eckit/geometry/grid/RegularLL.cc +++ b/src/eckit/geometry/grid/RegularLL.cc @@ -250,7 +250,7 @@ Configuration* RegularLL::config(const std::string& name) { } -static const GridRegisterName __grid_pattern(POSITIVE_REAL "/" POSITIVE_REAL, "30/45"); +static const GridRegisterName __grid_pattern(POSITIVE_REAL "/" POSITIVE_REAL); #undef POSITIVE_REAL diff --git a/src/tools/eckit-grid-list.cc b/src/tools/eckit-grid-list.cc index bd96224dc..149e0d1bd 100644 --- a/src/tools/eckit-grid-list.cc +++ b/src/tools/eckit-grid-list.cc @@ -22,7 +22,8 @@ struct EckitGridList final : EckitTool { EckitTool(argc, argv) {} void execute(const option::CmdArgs&) override { - Log::info() << geometry::GridFactoryType::instance() << std::endl; + geometry::GridFactory::list(Log::info()); + Log::info() << std::endl; } void usage(const std::string& tool) const override { diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index bdbbd50f9..998942595 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -11,7 +11,7 @@ #include #include -#include "eckit/config/Resource.h" +#include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geometry/Grid.h" #include "eckit/geometry/Point.h" @@ -52,7 +52,8 @@ class EckitGrid final : public EckitTool { out.precision(args.getInt("precision", 16)); for (const auto& arg : args) { - std::unique_ptr grid(uid ? geometry::GridFactoryUID::build(arg) : geometry::GridFactoryName::build(arg)); + std::unique_ptr cfg(new MappedConfiguration({{uid ? "uid" : "name", std::string(arg)}})); + std::unique_ptr grid(geometry::GridFactory::build(*cfg)); out << "size: " << grid->size() << std::endl; diff --git a/tests/geometry/test_grid.cc b/tests/geometry/test_grid.cc index e18dcafb9..f2280b577 100644 --- a/tests/geometry/test_grid.cc +++ b/tests/geometry/test_grid.cc @@ -32,7 +32,8 @@ CASE("GridFactory::build") { SECTION("GridFactory::build_from_name") { for (const auto& test : {test_t{"O2", 88}, {"f2", 32}, {"h2", 48}}) { - std::unique_ptr grid(geometry::GridFactoryName::build(test.name)); + std::unique_ptr cfg(new MappedConfiguration({{"name", test.name}})); + std::unique_ptr grid(geometry::GridFactory::build(*cfg)); auto size = grid->size(); EXPECT_EQUAL(size, test.size); } From 64af07e5f59e8678ad1ebb447a6af57a7e282dde Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 22 Aug 2023 16:39:47 +0100 Subject: [PATCH 313/737] eckit::geometry::grid::ORCA --- etc/eckit/geometry/grid.yaml | 74 ++++++++-------- src/eckit/geometry/CMakeLists.txt | 2 + src/eckit/geometry/Configurator.h | 2 + src/eckit/geometry/grid/ORCA.cc | 136 ++++++++++++++++++++++++++++++ src/eckit/geometry/grid/ORCA.h | 134 +++++++++++++++++++++++++++++ 5 files changed, 309 insertions(+), 39 deletions(-) create mode 100644 src/eckit/geometry/grid/ORCA.cc create mode 100644 src/eckit/geometry/grid/ORCA.h diff --git a/etc/eckit/geometry/grid.yaml b/etc/eckit/geometry/grid.yaml index a59e2b01d..db9faf47a 100644 --- a/etc/eckit/geometry/grid.yaml +++ b/etc/eckit/geometry/grid.yaml @@ -34,7 +34,7 @@ grid_names: orca_arrangement: F orca_name: ORCA2 dimensions: [182, 149] - uid: 174487fbace54b00d959d971e88b71e7 + orca_uid: 174487fbace54b00d959d971e88b71e7 url_prefix: *orca_url_prefix url: ORCA2_F.atlas @@ -43,7 +43,7 @@ grid_names: orca_arrangement: T orca_name: ORCA2 dimensions: [182, 149] - uid: d5bde4f52ff3a9bea5629cd9ac514410 + orca_uid: d5bde4f52ff3a9bea5629cd9ac514410 url_prefix: *orca_url_prefix url: ORCA2_T.atlas @@ -52,7 +52,7 @@ grid_names: orca_arrangement: U orca_name: ORCA2 dimensions: [182, 149] - uid: 857f7affa3a381e3882d38d321384e49 + orca_uid: 857f7affa3a381e3882d38d321384e49 url_prefix: *orca_url_prefix url: ORCA2_U.atlas @@ -61,7 +61,7 @@ grid_names: orca_arrangement: V orca_name: ORCA2 dimensions: [182, 149] - uid: ca637bc5dc9a54e2ea4b9750e1b79e6e + orca_uid: ca637bc5dc9a54e2ea4b9750e1b79e6e url_prefix: *orca_url_prefix url: ORCA2_V.atlas @@ -70,7 +70,7 @@ grid_names: orca_arrangement: W orca_name: ORCA2 dimensions: [182, 149] - uid: edea6f71eb558dc056b5f576d5b904f7 + orca_uid: edea6f71eb558dc056b5f576d5b904f7 url_prefix: *orca_url_prefix url: ORCA2_T.atlas @@ -79,7 +79,7 @@ grid_names: orca_arrangement: F orca_name: ORCA1 dimensions: [362, 292] - uid: a832a12030c73928133553ec3a8d2a7e + orca_uid: a832a12030c73928133553ec3a8d2a7e url_prefix: *orca_url_prefix url: ORCA1_F.atlas @@ -88,7 +88,7 @@ grid_names: orca_arrangement: T orca_name: ORCA1 dimensions: [362, 292] - uid: f4c91b6233fe55dec992160ec12b38df + orca_uid: f4c91b6233fe55dec992160ec12b38df url_prefix: *orca_url_prefix url: ORCA1_T.atlas @@ -97,7 +97,7 @@ grid_names: orca_arrangement: U orca_name: ORCA1 dimensions: [362, 292] - uid: 1b0f8d234753f910197c975c906b4da5 + orca_uid: 1b0f8d234753f910197c975c906b4da5 url_prefix: *orca_url_prefix url: ORCA1_U.atlas @@ -106,7 +106,7 @@ grid_names: orca_arrangement: V orca_name: ORCA1 dimensions: [362, 292] - uid: c637340454795b395f982851b840943d + orca_uid: c637340454795b395f982851b840943d url_prefix: *orca_url_prefix url: ORCA1_V.atlas @@ -115,7 +115,7 @@ grid_names: orca_arrangement: W orca_name: ORCA1 dimensions: [362, 292] - uid: d50061c43e83c46c3810002591ea21e1 + orca_uid: d50061c43e83c46c3810002591ea21e1 url_prefix: *orca_url_prefix url: ORCA1_T.atlas @@ -124,7 +124,7 @@ grid_names: orca_arrangement: F orca_name: eORCA1 dimensions: [362, 332] - uid: 3c6d95561710c6f39b394809ff6c588c + orca_uid: 3c6d95561710c6f39b394809ff6c588c url_prefix: *orca_url_prefix url: eORCA1_F.atlas @@ -133,7 +133,7 @@ grid_names: orca_arrangement: T orca_name: eORCA1 dimensions: [362, 332] - uid: ba65665a9e68d1a8fa0352ecfcf8e496 + orca_uid: ba65665a9e68d1a8fa0352ecfcf8e496 url_prefix: *orca_url_prefix url: eORCA1_T.atlas @@ -142,7 +142,7 @@ grid_names: orca_arrangement: U orca_name: eORCA1 dimensions: [362, 332] - uid: 4eb1054957dcae914e219faf9a4068e3 + orca_uid: 4eb1054957dcae914e219faf9a4068e3 url_prefix: *orca_url_prefix url: eORCA1_U.atlas @@ -151,7 +151,7 @@ grid_names: orca_arrangement: V orca_name: eORCA1 dimensions: [362, 332] - uid: 09131429766e7737c087d3a8d7073dc9 + orca_uid: 09131429766e7737c087d3a8d7073dc9 url_prefix: *orca_url_prefix url: eORCA1_V.atlas @@ -160,7 +160,7 @@ grid_names: orca_arrangement: W orca_name: eORCA1 dimensions: [362, 332] - uid: 5c678d8f9aa2edfbf57246d11d9c1278 + orca_uid: 5c678d8f9aa2edfbf57246d11d9c1278 url_prefix: *orca_url_prefix url: eORCA1_T.atlas @@ -169,7 +169,7 @@ grid_names: orca_arrangement: F orca_name: ORCA025 dimensions: [1442, 1021] - uid: efbc280d8d4b6048797880da2605bacb + orca_uid: efbc280d8d4b6048797880da2605bacb url_prefix: *orca_url_prefix url: ORCA025_F.atlas @@ -178,7 +178,7 @@ grid_names: orca_arrangement: T orca_name: ORCA025 dimensions: [1442, 1021] - uid: 15c961c269ac182ca226d7195f3921ba + orca_uid: 15c961c269ac182ca226d7195f3921ba url_prefix: *orca_url_prefix url: ORCA025_T.atlas @@ -187,7 +187,7 @@ grid_names: orca_arrangement: U orca_name: ORCA025 dimensions: [1442, 1021] - uid: 3f4a68bc5b54c9f867fbcc12aacc723d + orca_uid: 3f4a68bc5b54c9f867fbcc12aacc723d url_prefix: *orca_url_prefix url: ORCA025_U.atlas @@ -196,7 +196,7 @@ grid_names: orca_arrangement: V orca_name: ORCA025 dimensions: [1442, 1021] - uid: 9c87699ee2026c0feee07d2a972eaccd + orca_uid: 9c87699ee2026c0feee07d2a972eaccd url_prefix: *orca_url_prefix url: ORCA025_V.atlas @@ -205,7 +205,7 @@ grid_names: orca_arrangement: W orca_name: ORCA025 dimensions: [1442, 1021] - uid: 74ca68f1c8524811f3d3aad99536adc2 + orca_uid: 74ca68f1c8524811f3d3aad99536adc2 url_prefix: *orca_url_prefix url: ORCA025_T.atlas @@ -214,7 +214,7 @@ grid_names: orca_arrangement: F orca_name: eORCA025 dimensions: [1442, 1207] - uid: 770e5bbb667a253d55db8a98a3b2d3a9 + orca_uid: 770e5bbb667a253d55db8a98a3b2d3a9 url_prefix: *orca_url_prefix url: eORCA025_F.atlas @@ -223,7 +223,7 @@ grid_names: orca_arrangement: T orca_name: eORCA025 dimensions: [1442, 1207] - uid: 983412216c9768bc794c18dc92082895 + orca_uid: 983412216c9768bc794c18dc92082895 url_prefix: *orca_url_prefix url: eORCA025_T.atlas @@ -232,7 +232,7 @@ grid_names: orca_arrangement: U orca_name: eORCA025 dimensions: [1442, 1207] - uid: b1b2922e9b57ee9c6eeddad218b6e4f3 + orca_uid: b1b2922e9b57ee9c6eeddad218b6e4f3 url_prefix: *orca_url_prefix url: eORCA025_U.atlas @@ -241,7 +241,7 @@ grid_names: orca_arrangement: V orca_name: eORCA025 dimensions: [1442, 1207] - uid: 9b06bf73a8f14e927bd9b0f1f0c04f74 + orca_uid: 9b06bf73a8f14e927bd9b0f1f0c04f74 url_prefix: *orca_url_prefix url: eORCA025_V.atlas @@ -250,7 +250,7 @@ grid_names: orca_arrangement: W orca_name: eORCA025 dimensions: [1442, 1207] - uid: 4a1ba3b11b8888aefc96992b6b1cab62 + orca_uid: 4a1ba3b11b8888aefc96992b6b1cab62 url_prefix: *orca_url_prefix url: eORCA025_T.atlas @@ -259,7 +259,7 @@ grid_names: orca_arrangement: F orca_name: ORCA12 dimensions: [4322, 3059] - uid: 29693ad8a7af3ae3ee0f02d090f0ec7b + orca_uid: 29693ad8a7af3ae3ee0f02d090f0ec7b url_prefix: *orca_url_prefix url: ORCA12_F.atlas @@ -268,7 +268,7 @@ grid_names: orca_arrangement: T orca_name: ORCA12 dimensions: [4322, 3059] - uid: b117d01170ac77bca68560ab10e559de + orca_uid: b117d01170ac77bca68560ab10e559de url_prefix: *orca_url_prefix url: ORCA12_T.atlas @@ -277,7 +277,7 @@ grid_names: orca_arrangement: U orca_name: ORCA12 dimensions: [4322, 3059] - uid: fff193b92d94d03e847ff2fa62b493f4 + orca_uid: fff193b92d94d03e847ff2fa62b493f4 url_prefix: *orca_url_prefix url: ORCA12_U.atlas @@ -286,7 +286,7 @@ grid_names: orca_arrangement: V orca_name: ORCA12 dimensions: [4322, 3059] - uid: 986e3450774b716f6e75c1987e370b10 + orca_uid: 986e3450774b716f6e75c1987e370b10 url_prefix: *orca_url_prefix url: ORCA12_V.atlas @@ -295,7 +295,7 @@ grid_names: orca_arrangement: W orca_name: ORCA12 dimensions: [4322, 3059] - uid: ccfe953619a8dd49a7f765923882a274 + orca_uid: ccfe953619a8dd49a7f765923882a274 url_prefix: *orca_url_prefix url: ORCA12_T.atlas @@ -304,7 +304,7 @@ grid_names: orca_arrangement: F orca_name: eORCA12 dimensions: [4322, 3606] - uid: 25da53ed581b3931fa310840fa9aefd9 + orca_uid: 25da53ed581b3931fa310840fa9aefd9 url_prefix: *orca_url_prefix url: eORCA12_F.atlas @@ -313,7 +313,7 @@ grid_names: orca_arrangement: T orca_name: eORCA12 dimensions: [4322, 3606] - uid: 1553b66f5885cf5f83ad4b4fdf25f460 + orca_uid: 1553b66f5885cf5f83ad4b4fdf25f460 url_prefix: *orca_url_prefix url: eORCA12_T.atlas @@ -322,7 +322,7 @@ grid_names: orca_arrangement: U orca_name: eORCA12 dimensions: [4322, 3606] - uid: 3e87c826643da440b4e9d9f67588a576 + orca_uid: 3e87c826643da440b4e9d9f67588a576 url_prefix: *orca_url_prefix url: eORCA12_U.atlas @@ -331,7 +331,7 @@ grid_names: orca_arrangement: V orca_name: eORCA12 dimensions: [4322, 3606] - uid: cc1e3fc06a2cd18c0653e557510b8a71 + orca_uid: cc1e3fc06a2cd18c0653e557510b8a71 url_prefix: *orca_url_prefix url: eORCA12_V.atlas @@ -340,7 +340,7 @@ grid_names: orca_arrangement: W orca_name: eORCA12 dimensions: [4322, 3606] - uid: 462469edbd0e0586a0cf17424cc58c89 + orca_uid: 462469edbd0e0586a0cf17424cc58c89 url_prefix: *orca_url_prefix url: eORCA12_T.atlas @@ -380,8 +380,4 @@ grid_uids: - 3e87c826643da440b4e9d9f67588a576: *eORCA12_U - cc1e3fc06a2cd18c0653e557510b8a71: *eORCA12_V - 462469edbd0e0586a0cf17424cc58c89: *eORCA12_W - - 16076978a048410747dd7c9876677b28: *eORCA1_T # Deprecated uid computed via multio - - 7378487847e050559b82d0792374a705: *eORCA1_U # Deprecated uid computed via multio - - d9622b55f3120eafb3dbaf5c742bc56c: *eORCA1_V # Deprecated uid computed via multio - - 0067c81a4154eaa5187f9b0f53e9df7e: *eORCA1_W # Deprecated uid computed via multio diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index d376f3d4c..66972c5cd 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -52,6 +52,8 @@ list( APPEND eckit_geometry_srcs grid/HEALPix.h grid/IrregularLatlon.cc grid/IrregularLatlon.h + grid/ORCA.cc + grid/ORCA.h grid/ReducedGG.cc grid/ReducedGG.h grid/ReducedLL.cc diff --git a/src/eckit/geometry/Configurator.h b/src/eckit/geometry/Configurator.h index 75ac22a17..304a1164b 100644 --- a/src/eckit/geometry/Configurator.h +++ b/src/eckit/geometry/Configurator.h @@ -176,6 +176,8 @@ class ConfigurationGenerator { using key_t = std::string; + static constexpr const char* uid_pattern = "[0-9a-fA-F]{32}"; + // -- Constructors ConfigurationGenerator() = default; diff --git a/src/eckit/geometry/grid/ORCA.cc b/src/eckit/geometry/grid/ORCA.cc new file mode 100644 index 000000000..92344ca1f --- /dev/null +++ b/src/eckit/geometry/grid/ORCA.cc @@ -0,0 +1,136 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/grid/ORCA.h" + +#include "eckit/exception/Exceptions.h" +#include "eckit/geometry/area/BoundingBox.h" + + +namespace eckit::geometry::grid { + + +namespace { + + +ORCA::Arrangement arrangement_from_string(const std::string& str) { + return str == "F" ? ORCA::Arrangement::F + : str == "T" ? ORCA::Arrangement::T + : str == "U" ? ORCA::Arrangement::U + : str == "V" ? ORCA::Arrangement::V + : str == "W" ? ORCA::Arrangement::W + : throw AssertionFailed("ORCA::Arrangement", Here()); +} + + +size_t dimension(const std::vector& dim, size_t index) { + ASSERT(dim.size() == 2 && index < 2); + return dim[index]; +} + + +} // namespace + + +ORCA::Iterator::Iterator(const Grid& grid, size_t index) : + geometry::Iterator(grid), + index_(index), + index_size_(grid.size()), + longitudes_(dynamic_cast(grid).longitudes_), + latitudes_(dynamic_cast(grid).latitudes_), + uid_(dynamic_cast(grid).uid_) { +} + + +bool ORCA::Iterator::operator==(const geometry::Iterator& other) const { + const auto* another = dynamic_cast(&other); + return another != nullptr && uid_ == another->uid_; +} + + +bool ORCA::Iterator::operator++() { + if (index_++; index_ < index_size_) { + return true; + } + + index_ = index_size_; // ensure it's invalid + return false; +} + + +bool ORCA::Iterator::operator+=(diff_t d) { + if (auto di = static_cast(index_); 0 <= di + d && di + d < static_cast(index_size_)) { + index_ = static_cast(di + d); + return true; + } + + index_ = index_size_; // ensure it's invalid + return false; +} + + +ORCA::Iterator::operator bool() const { + return index_ < index_size_; +} + + +Point ORCA::Iterator::operator*() const { + return PointLonLat{longitudes_.at(index_), latitudes_.at(index_)}; +} + + +ORCA::ORCA(const Configuration& config) : + Grid(config), + ni_(dimension(config.getUnsignedVector("dimensions"), 0)), + nj_(dimension(config.getUnsignedVector("dimensions"), 1)), + name_(config.getString("orca_name")), + uid_(config.getString("orca_uid")), + arrangement_(arrangement_from_string(config.getString("orca_arrangement"))) { + ASSERT(0 < ni_); + ASSERT(0 < nj_); + + auto url = config.getString("url_prefix", "") + config.getString("url"); + Log::info() << "url: '" << url << "'" << std::endl; +} + + +Configuration* ORCA::config(const std::string& name) { + return GridConfigurationUID::instance().get(name).config(); +} + + +Grid::iterator ORCA::cbegin() const { + return iterator{new Iterator(*this, 0)}; +} + + +Grid::iterator ORCA::cend() const { + return iterator{new Iterator(*this, size())}; +} + + +const area::BoundingBox& ORCA::boundingBox() const { + static const auto __bbox(area::BoundingBox::make_global_prime()); + return __bbox; +} + + +std::pair, std::vector> ORCA::to_latlon() const { + return {latitudes_, longitudes_}; +} + + +static const GridRegisterType __grid_type("ORCA"); +static const GridRegisterName __grid_pattern(GridRegisterName::uid_pattern); + + +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/ORCA.h b/src/eckit/geometry/grid/ORCA.h new file mode 100644 index 000000000..2c2fb2842 --- /dev/null +++ b/src/eckit/geometry/grid/ORCA.h @@ -0,0 +1,134 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "eckit/geometry/Grid.h" + + +namespace eckit::geometry::grid { + + +class ORCA final : public Grid { +public: + // -- Types + + enum Arrangement + { + F, + T, + U, + V, + W, + }; + + class Iterator final : public geometry::Iterator { + public: + explicit Iterator(const Grid&, size_t index = 0); + + private: + bool operator==(const geometry::Iterator&) const override; + bool operator++() override; + bool operator+=(diff_t) override; + explicit operator bool() const override; + Point operator*() const override; + + size_t index() const override { return index_; } + + size_t index_; + const size_t index_size_; + + const std::vector& longitudes_; + const std::vector& latitudes_; + const std::string uid_; + }; + + // -- Exceptions + // None + + // -- Constructors + + explicit ORCA(const Configuration&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + + static Configuration* config(const std::string& name); + + // -- Class methods + // None + +private: + // -- Members + + const size_t ni_; + const size_t nj_; + const std::string name_; + const std::string uid_; + const Arrangement arrangement_; + + std::vector longitudes_; + std::vector latitudes_; + + // -- Methods + + size_t ni() const { return ni_; } + size_t nj() const { return nj_; } + + std::vector longitudes(size_t ring) const; + + // -- Overridden methods + + iterator cbegin() const override; + iterator cend() const override; + + const area::BoundingBox& boundingBox() const override; + + size_t size() const override { + return ni_ * nj_; + } + + bool includesNorthPole() const override { return true; } + bool includesSouthPole() const override { return true; } // FIXME: not sure this is semanticaly correct + bool isPeriodicWestEast() const override { return true; } + + std::pair, std::vector> to_latlon() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + + friend class RingIterator; +}; + + +} // namespace eckit::geometry::grid From e4a51829c0945853307c73f0f64be9436a26fc2a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 22 Aug 2023 16:40:40 +0100 Subject: [PATCH 314/737] eckit::geometry --- src/eckit/geometry/CMakeLists.txt | 6 +-- src/eckit/geometry/Increments.cc | 26 ---------- .../grid/{RegularLL.cc => Regular.cc} | 33 +++++++------ .../geometry/grid/{RegularLL.h => Regular.h} | 49 +++++++++++++++++-- 4 files changed, 66 insertions(+), 48 deletions(-) delete mode 100644 src/eckit/geometry/Increments.cc rename src/eckit/geometry/grid/{RegularLL.cc => Regular.cc} (85%) rename src/eckit/geometry/grid/{RegularLL.h => Regular.h} (53%) diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index 66972c5cd..f5d3c6f5a 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -17,8 +17,6 @@ list( APPEND eckit_geometry_srcs Grid.h GridConfig.cc GridConfig.h - Increments.cc - Increments.h Iterator.h KPoint.cc KPoint.h @@ -58,12 +56,12 @@ list( APPEND eckit_geometry_srcs grid/ReducedGG.h grid/ReducedLL.cc grid/ReducedLL.h + grid/Regular.cc + grid/Regular.h grid/RegularGG.cc grid/RegularGG.h grid/RegularGrid.cc grid/RegularGrid.h - grid/RegularLL.cc - grid/RegularLL.h grid/UnstructuredGrid.cc grid/UnstructuredGrid.h iterator/ListI.cc diff --git a/src/eckit/geometry/Increments.cc b/src/eckit/geometry/Increments.cc deleted file mode 100644 index ab95f6edc..000000000 --- a/src/eckit/geometry/Increments.cc +++ /dev/null @@ -1,26 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/Increments.h" - -#include "eckit/config/Configuration.h" - - -namespace eckit::geometry { - - -Increments::Increments(const Configuration& config) : - Increments(config.getDouble("west_east_increment"), config.getDouble("south_north_increment")) { -} - - -} // namespace eckit::geometry diff --git a/src/eckit/geometry/grid/RegularLL.cc b/src/eckit/geometry/grid/Regular.cc similarity index 85% rename from src/eckit/geometry/grid/RegularLL.cc rename to src/eckit/geometry/grid/Regular.cc index 1ccf67024..c923ed295 100644 --- a/src/eckit/geometry/grid/RegularLL.cc +++ b/src/eckit/geometry/grid/Regular.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/grid/RegularLL.h" +#include "eckit/geometry/grid/Regular.h" #include #include @@ -22,7 +22,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geometry/Point.h" #include "eckit/geometry/Projection.h" -#include "eckit/geometry/grid/RegularLL.h" +#include "eckit/geometry/grid/Regular.h" #include "eckit/geometry/util.h" #include "eckit/geometry/util/regex.h" #include "eckit/types/Fraction.h" @@ -116,7 +116,12 @@ RegularIterator::RegularIterator(const Fraction& a, const Fraction& b, const Fra } // namespace detail -RegularLL::RegularLL(const Configuration& config) : +Regular::Increments::Increments(const Configuration& config) : + Increments(config.getDouble("west_east_increment"), config.getDouble("south_north_increment")) { +} + + +Regular::Regular(const Configuration& config) : Grid(config), increments_(config), reference_(bbox().south(), bbox().west()), ni_(0), nj_(0) { bbox(correctBoundingBox(bbox(), ni_, nj_, increments_, reference_)); ASSERT(ni_ != 0); @@ -133,7 +138,7 @@ RegularLL::RegularLL(const Configuration& config) : } -RegularLL::RegularLL(const Increments& increments, const area::BoundingBox& bb, const PointLonLat& reference) : +Regular::Regular(const Increments& increments, const area::BoundingBox& bb, const PointLonLat& reference) : Grid(bb), increments_(increments), reference_(reference), ni_(0), nj_(0) { bbox(correctBoundingBox(bbox(), ni_, nj_, increments_, reference_)); ASSERT(ni_ != 0); @@ -141,32 +146,32 @@ RegularLL::RegularLL(const Increments& increments, const area::BoundingBox& bb, } -bool RegularLL::isPeriodicWestEast() const { +bool Regular::isPeriodicWestEast() const { // if range West-East is within one increment (or greater than) 360 degree return bbox().east() - bbox().west() + increments_.west_east >= GLOBE; } -bool RegularLL::includesNorthPole() const { +bool Regular::includesNorthPole() const { // if North latitude is within one increment from North Pole return bbox().north() + increments_.south_north > NORTH_POLE; } -bool RegularLL::includesSouthPole() const { +bool Regular::includesSouthPole() const { // if South latitude is within one increment from South Pole return bbox().south() - increments_.south_north < SOUTH_POLE; } -size_t RegularLL::size() const { +size_t Regular::size() const { ASSERT(0 < ni_); ASSERT(0 < nj_); return ni_ * nj_; } -std::pair, std::vector> RegularLL::to_latlon() const { +std::pair, std::vector> Regular::to_latlon() const { auto [n, w, s, e] = bbox().deconstruct(); auto [we, sn] = increments_.deconstruct(); @@ -191,8 +196,8 @@ std::pair, std::vector> RegularLL::to_latlon() const } -area::BoundingBox RegularLL::correctBoundingBox(const area::BoundingBox& box, size_t& ni, size_t& nj, const Increments& inc, - const PointLonLat& reference) { +area::BoundingBox Regular::correctBoundingBox(const area::BoundingBox& box, size_t& ni, size_t& nj, const Increments& inc, + const PointLonLat& reference) { // Latitude/longitude ranges detail::RegularIterator lat{Fraction{box.south()}, Fraction{box.north()}, @@ -223,13 +228,13 @@ area::BoundingBox RegularLL::correctBoundingBox(const area::BoundingBox& box, si } -static const GridRegisterType __grid_type("regular_ll"); +static const GridRegisterType __grid_type("regular_ll"); #define POSITIVE_REAL "[+]?([0-9]*[.])?[0-9]+([eE][-+][0-9]+)?" -Configuration* RegularLL::config(const std::string& name) { +Configuration* Regular::config(const std::string& name) { static const std::string pattern("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); auto match = util::regex_match(pattern, name); @@ -250,7 +255,7 @@ Configuration* RegularLL::config(const std::string& name) { } -static const GridRegisterName __grid_pattern(POSITIVE_REAL "/" POSITIVE_REAL); +static const GridRegisterName __grid_pattern(POSITIVE_REAL "/" POSITIVE_REAL); #undef POSITIVE_REAL diff --git a/src/eckit/geometry/grid/RegularLL.h b/src/eckit/geometry/grid/Regular.h similarity index 53% rename from src/eckit/geometry/grid/RegularLL.h rename to src/eckit/geometry/grid/Regular.h index 0c5f229cd..2fa1a5156 100644 --- a/src/eckit/geometry/grid/RegularLL.h +++ b/src/eckit/geometry/grid/Regular.h @@ -13,21 +13,62 @@ #pragma once #include "eckit/geometry/Grid.h" -#include "eckit/geometry/Increments.h" +#include "eckit/geometry/Point.h" + + +namespace eckit { +class Configuration; +} namespace eckit::geometry::grid { -class RegularLL : public Grid { +class Regular : public Grid { public: + // -- Types + +#if 0 + struct Increments { + template , int> = 0> + explicit Increments(const Configuration& config) : + P(config.getDouble("west_east_increment"), config.getDouble("south_north_increment")) { + } + + template , int> = 0> + explicit Increments(const Configuration& config) : + P(config.getDouble("dx"), config.getDouble("dy")) { + } + + std::array deconstruct() const { return {P::operator[](0), P::operator[](0)}; } + + const P point_; + }; +#else + struct Increments : protected std::array { + using P = std::array; + + Increments(double west_east, double south_north) : + P{west_east, south_north} {}; + + explicit Increments(const Configuration& config); + + double& west_east = P::operator[](0); + double& south_north = P::operator[](1); + + std::array deconstruct() const { return {west_east, south_north}; } + }; +#endif + // -- Exceptions // None // -- Constructors - explicit RegularLL(const Configuration&); - explicit RegularLL(const Increments&, const area::BoundingBox& = {}, const PointLonLat& reference = {0, 0}); + explicit Regular(const Configuration&); + explicit Regular(const Increments&, const area::BoundingBox& = {}, const PointLonLat& reference = {0, 0}); // -- Destructor // None From 8d665a77c437c4cce17d660e1afcd9b682622b43 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 23 Aug 2023 14:04:49 +0100 Subject: [PATCH 315/737] eckit::geometry config file --- CMakeLists.txt | 8 ++++++ src/eckit/geometry/CMakeLists.txt | 26 ++++++++++++++----- src/eckit/geometry/LibEcKitGeometry.cc | 15 ++++++++++- src/eckit/geometry/LibEcKitGeometry.h | 4 +++ src/eckit/geometry/eckit_geometry_config.h.in | 5 ++++ 5 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 src/eckit/geometry/eckit_geometry_config.h.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 28eccd71b..541a7131c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,6 +142,14 @@ ecbuild_add_option( FEATURE AEC ecbuild_add_option( FEATURE XXHASH DESCRIPTION "xxHash support for hashing" ) +### Geometry options + +ecbuild_add_option( FEATURE GEOMETRY_CACHING + DEFAULT OFF + DESCRIPTION "eckit::geometry default caching behaviour" ) + +set( eckit_GEOMETRY_CACHE_PATH "/tmp/cache" ) + ### LAPACK if( eckit_HAVE_MKL ) diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index f5d3c6f5a..947d013f7 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -1,4 +1,12 @@ + +configure_file( eckit_geometry_config.h.in eckit_geometry_config.h @ONLY ) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/eckit_geometry_config.h + DESTINATION ${INSTALL_INCLUDE_DIR}/eckit +) + list( APPEND eckit_geometry_srcs + ${CMAKE_CURRENT_BINARY_DIR}/eckit_geometry_config.h Area.h Cache.cc Cache.h @@ -92,8 +100,12 @@ list( APPEND eckit_geometry_srcs util/regex.h ) -set(eckit_geometry_include_dirs ) -set(eckit_geometry_libs eckit_maths) +set(eckit_geometry_include_dirs + $ + $ +) + +set(eckit_geometry_libs eckit_maths eckit_codec) if(HAVE_PROJ) list(APPEND eckit_geometry_srcs projection/PROJ.cc projection/PROJ.h) @@ -103,11 +115,13 @@ endif() ecbuild_add_library( TARGET eckit_geometry - TYPE SHARED - INSTALL_HEADERS ALL + TYPE SHARED + + INSTALL_HEADERS ALL HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geometry + PUBLIC_LIBS ${eckit_geometry_libs} + PUBLIC_INCLUDES ${eckit_geometry_include_dirs} + SOURCES ${eckit_geometry_srcs} - PUBLIC_LIBS ${eckit_geometry_libs} - PUBLIC_INCLUDES ${eckit_geometry_include_dirs} ) diff --git a/src/eckit/geometry/LibEcKitGeometry.cc b/src/eckit/geometry/LibEcKitGeometry.cc index 5213d120c..a68ec86ad 100644 --- a/src/eckit/geometry/LibEcKitGeometry.cc +++ b/src/eckit/geometry/LibEcKitGeometry.cc @@ -15,6 +15,7 @@ #include "eckit/config/Resource.h" #include "eckit/eckit_version.h" #include "eckit/filesystem/PathName.h" +#include "eckit/geometry/eckit_geometry_config.h" namespace eckit { @@ -34,7 +35,19 @@ LibEcKitGeometry& LibEcKitGeometry::instance() { PathName LibEcKitGeometry::configFileGrid() { - static const PathName path{eckit::LibResource("eckit-geometry-grid;$ECKIT_GEOMETRY_GRID", "~eckit/etc/eckit/geometry/grid.yaml")}; + static const PathName path{LibResource("eckit-geometry-grid;$ECKIT_GEOMETRY_GRID", "~eckit/etc/eckit/geometry/grid.yaml")}; + return path; +} + + +bool LibEcKitGeometry::caching() { + static const bool yes{LibResource("eckit-geometry-caching;$ECKIT_GEOMETRY_CACHING", eckit_HAVE_GEOMETRY_CACHING != 0 ? true : false)}; + return yes; +} + + +std::string LibEcKitGeometry::cacheDir() { + static std::string path = PathName{LibResource("eckit-geometry-cache-path;$ECKIT_GEOMETRY_CACHE_PATH", eckit_GEOMETRY_CACHE_PATH)}; return path; } diff --git a/src/eckit/geometry/LibEcKitGeometry.h b/src/eckit/geometry/LibEcKitGeometry.h index ed502e3bb..dff590814 100644 --- a/src/eckit/geometry/LibEcKitGeometry.h +++ b/src/eckit/geometry/LibEcKitGeometry.h @@ -46,8 +46,12 @@ class LibEcKitGeometry final : public system::Library { // -- Methods static LibEcKitGeometry& instance(); + static eckit::PathName configFileGrid(); + static bool caching(); + static std::string cacheDir(); + // -- Overridden methods // None diff --git a/src/eckit/geometry/eckit_geometry_config.h.in b/src/eckit/geometry/eckit_geometry_config.h.in new file mode 100644 index 000000000..3e330e013 --- /dev/null +++ b/src/eckit/geometry/eckit_geometry_config.h.in @@ -0,0 +1,5 @@ +#pragma once + +#cmakedefine01 eckit_HAVE_GEOMETRY_CACHING +#cmakedefine eckit_GEOMETRY_CACHE_PATH "@eckit_GEOMETRY_CACHE_PATH@" + From db5f7a1d1a4611224fed51d1b0c1fd35e9e35d2d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 23 Aug 2023 17:20:10 +0100 Subject: [PATCH 316/737] eckit::geometry --- src/eckit/geometry/Grid.cc | 1 + src/eckit/geometry/Grid.h | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 465420242..17f8e343a 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -15,6 +15,7 @@ #include #include +#include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geometry/GridConfig.h" #include "eckit/log/Log.h" diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 84f2627e6..0b7ab74df 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -19,7 +19,6 @@ #include #include -#include "eckit/config/MappedConfiguration.h" #include "eckit/geometry/Area.h" #include "eckit/geometry/Configurator.h" #include "eckit/geometry/Increments.h" @@ -32,6 +31,11 @@ #include "eckit/memory/Factory.h" +namespace eckit { +class Configuration; +} + + namespace eckit::geometry { From 6178bd912282760b18463011e855f84ceb7b51cc Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 23 Aug 2023 17:26:51 +0100 Subject: [PATCH 317/737] eckit::geometry ORCA --- src/eckit/geometry/grid/ORCA.cc | 160 ++++++++++++++++++++++++++++++-- src/eckit/geometry/grid/ORCA.h | 37 ++++++-- 2 files changed, 180 insertions(+), 17 deletions(-) diff --git a/src/eckit/geometry/grid/ORCA.cc b/src/eckit/geometry/grid/ORCA.cc index 92344ca1f..095821a4b 100644 --- a/src/eckit/geometry/grid/ORCA.cc +++ b/src/eckit/geometry/grid/ORCA.cc @@ -12,8 +12,21 @@ #include "eckit/geometry/grid/ORCA.h" +#include "eckit/codec/codec.h" #include "eckit/exception/Exceptions.h" +#include "eckit/filesystem/PathName.h" +#include "eckit/filesystem/URI.h" +#include "eckit/geometry/LibEcKitGeometry.h" #include "eckit/geometry/area/BoundingBox.h" +#include "eckit/io/Length.h" +#include "eckit/log/Bytes.h" +#include "eckit/log/Timer.h" +#include "eckit/utils/ByteSwap.h" +#include "eckit/utils/MD5.h" + +#ifdef eckit_HAVE_CURL +#include "eckit/io/URLHandle.h" +#endif namespace eckit::geometry::grid { @@ -32,9 +45,13 @@ ORCA::Arrangement arrangement_from_string(const std::string& str) { } -size_t dimension(const std::vector& dim, size_t index) { - ASSERT(dim.size() == 2 && index < 2); - return dim[index]; +std::string arrangement_to_string(ORCA::Arrangement a) { + return a == ORCA::Arrangement::F ? "F" + : a == ORCA::Arrangement::T ? "T" + : a == ORCA::Arrangement::U ? "U" + : a == ORCA::Arrangement::V ? "V" + : a == ORCA::Arrangement::W ? "W" + : throw AssertionFailed("ORCA::Arrangement", Here()); } @@ -90,19 +107,148 @@ Point ORCA::Iterator::operator*() const { ORCA::ORCA(const Configuration& config) : Grid(config), - ni_(dimension(config.getUnsignedVector("dimensions"), 0)), - nj_(dimension(config.getUnsignedVector("dimensions"), 1)), name_(config.getString("orca_name")), uid_(config.getString("orca_uid")), arrangement_(arrangement_from_string(config.getString("orca_arrangement"))) { - ASSERT(0 < ni_); - ASSERT(0 < nj_); + + + // TODO + ASSERT(0 < dimensions_[0]); + ASSERT(0 < dimensions_[1]); + + ASSERT(halo_[0] >= 0); + ASSERT(halo_[1] >= 0); + ASSERT(halo_[2] >= 0); + ASSERT(halo_[3] >= 0); + + ASSERT(pivot_[0] >= 0); + ASSERT(pivot_[1] >= 0); + + size_t size = dimensions_[0] * dimensions_[1]; + ASSERT(0 < size); + ASSERT(longitudes_.size() == size); + ASSERT(latitudes_.size() == size); + ASSERT(flags_.size() == size); + auto url = config.getString("url_prefix", "") + config.getString("url"); Log::info() << "url: '" << url << "'" << std::endl; } +ORCA::ORCA(const URI& uri) : + Grid(area::BoundingBox::make_global_prime()) { + if (uri.scheme().find("http") == 0) { + PathName path = "..."; // from url + + if (!path.exists() && LibEcKitGeometry::caching()) { + Timer timer; + + + Log::debug() << "Downloading " << uri << " to " << path << std::endl; + + path.dirName().mkdir(); + + PathName tmp = path + ".download"; + Length length = 0; + +#if eckit_HAVE_CURL + try { + length = URLHandle(uri.asRawString()).saveInto(tmp); + } + catch (...) { + length = 0; + } +#endif + + if (length <= 0) { + if (tmp.exists()) { + tmp.unlink(true); + } + + throw UserError("Could not download file from url " + uri.asRawString()); + } + + if (!path.exists()) { + throw UserError("Could not locate orca grid data file " + path); + } + + PathName::rename(tmp, path); + + Log::info() << "Download of " << Bytes(length) << " took " << timer.elapsed() << " s." << std::endl; + } + else { + throw UserError("Could not locate orca grid data file " + path); + } + } + else { + if (!uri.path().exists()) { + throw UserError("Could not locate orca grid data file " + uri.asRawString()); + } + } +} + + +void ORCA::read(const PathName& p) { + codec::RecordReader reader(p); + + int version = -1; + reader.read("version", version).wait(); + + if (version == 0) { + reader.read("dimensions", dimensions_); + reader.read("pivot", pivot_); + reader.read("halo", halo_); + reader.read("longitude", longitudes_); + reader.read("latitude", latitudes_); + reader.read("flags", flags_); + reader.wait(); + } + else { + ASSERT_MSG(false, "Unsupported version "); + } +} + + +size_t ORCA::write(const PathName& p, const std::string& compression) { + codec::RecordWriter record; + + record.compression(compression); + record.set("version", 0); + record.set("dimensions", dimensions_); + record.set("halo", halo_); + record.set("pivot", pivot_); + record.set("longitude", codec::ArrayReference(longitudes_.data(), dimensions_)); + record.set("latitude", codec::ArrayReference(latitudes_.data(), dimensions_)); + record.set("flags", codec::ArrayReference(flags_.data(), dimensions_)); + + return record.write(p); +} + + +std::string ORCA::uid(const Configuration& config) const { + MD5 hash; + hash.add(arrangement_to_string(arrangement_)); + + auto sized = static_cast(longitudes_.size() * sizeof(double)); + + if constexpr (eckit_LITTLE_ENDIAN) { + hash.add(latitudes_.data(), sized); + hash.add(longitudes_.data(), sized); + } + else { + auto lonsw = longitudes_; + auto latsw = latitudes_; + eckit::byteswap(latsw.data(), latsw.size()); + eckit::byteswap(lonsw.data(), lonsw.size()); + hash.add(latsw.data(), sized); + hash.add(lonsw.data(), sized); + } + + return hash.digest(); +} + + Configuration* ORCA::config(const std::string& name) { return GridConfigurationUID::instance().get(name).config(); } diff --git a/src/eckit/geometry/grid/ORCA.h b/src/eckit/geometry/grid/ORCA.h index 2c2fb2842..9ee05d045 100644 --- a/src/eckit/geometry/grid/ORCA.h +++ b/src/eckit/geometry/grid/ORCA.h @@ -12,11 +12,21 @@ #pragma once +#include +#include +#include +#include #include #include "eckit/geometry/Grid.h" +namespace eckit { +class PathName; +class URI; +} // namespace eckit + + namespace eckit::geometry::grid { @@ -60,6 +70,7 @@ class ORCA final : public Grid { // -- Constructors explicit ORCA(const Configuration&); + explicit ORCA(const URI&); // -- Destructor // None @@ -71,7 +82,11 @@ class ORCA final : public Grid { // None // -- Methods - // None + + void read(const PathName&); + size_t write(const PathName&, const std::string& compression = "none"); + + std::string uid(const Configuration& config) const; // -- Overridden methods // None @@ -86,19 +101,22 @@ class ORCA final : public Grid { private: // -- Members - const size_t ni_; - const size_t nj_; - const std::string name_; - const std::string uid_; - const Arrangement arrangement_; + std::string name_; + std::string uid_; + Arrangement arrangement_; std::vector longitudes_; std::vector latitudes_; + std::array dimensions_{-1, -1}; + std::array halo_{-1, -1, -1, -1}; + std::array pivot_{-1, -1}; + std::vector flags_; + // -- Methods - size_t ni() const { return ni_; } - size_t nj() const { return nj_; } + size_t ni() const { return static_cast(dimensions_[0]); } + size_t nj() const { return static_cast(dimensions_[1]); } std::vector longitudes(size_t ring) const; @@ -126,8 +144,7 @@ class ORCA final : public Grid { // None // -- Friends - - friend class RingIterator; + // None }; From bbaa132c3a9a007b1a4e178372102ad2dffbd340 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 23 Aug 2023 17:30:42 +0100 Subject: [PATCH 318/737] eckit::geometry --- src/eckit/geometry/grid/Gaussian.cc | 1 + src/eckit/geometry/grid/IrregularLatlon.cc | 1 + src/eckit/geometry/grid/ORCA.cc | 12 +++++++----- src/eckit/geometry/grid/ORCA.h | 4 +--- src/eckit/geometry/grid/ReducedLL.cc | 1 + src/eckit/geometry/grid/UnstructuredGrid.cc | 1 + 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/eckit/geometry/grid/Gaussian.cc b/src/eckit/geometry/grid/Gaussian.cc index 11a720df2..74a7296c9 100644 --- a/src/eckit/geometry/grid/Gaussian.cc +++ b/src/eckit/geometry/grid/Gaussian.cc @@ -16,6 +16,7 @@ #include #include +#include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geometry/Domain.h" #include "eckit/geometry/util.h" diff --git a/src/eckit/geometry/grid/IrregularLatlon.cc b/src/eckit/geometry/grid/IrregularLatlon.cc index 1a22c141c..8dfcf8a92 100644 --- a/src/eckit/geometry/grid/IrregularLatlon.cc +++ b/src/eckit/geometry/grid/IrregularLatlon.cc @@ -14,6 +14,7 @@ #include +#include "eckit/config/Configuration.h" #include "eckit/geometry/area/BoundingBox.h" diff --git a/src/eckit/geometry/grid/ORCA.cc b/src/eckit/geometry/grid/ORCA.cc index 095821a4b..90af54513 100644 --- a/src/eckit/geometry/grid/ORCA.cc +++ b/src/eckit/geometry/grid/ORCA.cc @@ -113,6 +113,7 @@ ORCA::ORCA(const Configuration& config) : // TODO + ASSERT(dimensions_.size() == 2); ASSERT(0 < dimensions_[0]); ASSERT(0 < dimensions_[1]); @@ -124,11 +125,12 @@ ORCA::ORCA(const Configuration& config) : ASSERT(pivot_[0] >= 0); ASSERT(pivot_[1] >= 0); - size_t size = dimensions_[0] * dimensions_[1]; - ASSERT(0 < size); - ASSERT(longitudes_.size() == size); - ASSERT(latitudes_.size() == size); - ASSERT(flags_.size() == size); + auto n = static_cast(dimensions_[0] & dimensions_[1]); + ASSERT(0 < n); + + ASSERT(longitudes_.size() == n); + ASSERT(latitudes_.size() == n); + ASSERT(flags_.size() == n); auto url = config.getString("url_prefix", "") + config.getString("url"); diff --git a/src/eckit/geometry/grid/ORCA.h b/src/eckit/geometry/grid/ORCA.h index 9ee05d045..732744b00 100644 --- a/src/eckit/geometry/grid/ORCA.h +++ b/src/eckit/geometry/grid/ORCA.h @@ -127,9 +127,7 @@ class ORCA final : public Grid { const area::BoundingBox& boundingBox() const override; - size_t size() const override { - return ni_ * nj_; - } + size_t size() const override { return ni() * nj(); } bool includesNorthPole() const override { return true; } bool includesSouthPole() const override { return true; } // FIXME: not sure this is semanticaly correct diff --git a/src/eckit/geometry/grid/ReducedLL.cc b/src/eckit/geometry/grid/ReducedLL.cc index e6e95115f..29585121c 100644 --- a/src/eckit/geometry/grid/ReducedLL.cc +++ b/src/eckit/geometry/grid/ReducedLL.cc @@ -16,6 +16,7 @@ #include #include +#include "eckit/config/Configuration.h" #include "eckit/geometry/Domain.h" #include "eckit/geometry/Projection.h" #include "eckit/types/FloatCompare.h" diff --git a/src/eckit/geometry/grid/UnstructuredGrid.cc b/src/eckit/geometry/grid/UnstructuredGrid.cc index ef0fa43bf..9656a43b5 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.cc +++ b/src/eckit/geometry/grid/UnstructuredGrid.cc @@ -12,6 +12,7 @@ #include "eckit/geometry/grid/UnstructuredGrid.h" +#include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geometry/iterator/ListI.h" From 8bef2ae52976345eb74ab77381469ed76749dfdb Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 24 Aug 2023 01:22:12 +0100 Subject: [PATCH 319/737] eckit::geometry ORCA --- etc/eckit/geometry/grid.yaml | 70 +++++++------- src/eckit/geometry/grid/ORCA.cc | 162 ++++++++++++++++---------------- src/eckit/geometry/grid/ORCA.h | 24 ++--- 3 files changed, 125 insertions(+), 131 deletions(-) diff --git a/etc/eckit/geometry/grid.yaml b/etc/eckit/geometry/grid.yaml index db9faf47a..108a977ab 100644 --- a/etc/eckit/geometry/grid.yaml +++ b/etc/eckit/geometry/grid.yaml @@ -34,7 +34,7 @@ grid_names: orca_arrangement: F orca_name: ORCA2 dimensions: [182, 149] - orca_uid: 174487fbace54b00d959d971e88b71e7 + orca_uid: "174487fbace54b00d959d971e88b71e7" url_prefix: *orca_url_prefix url: ORCA2_F.atlas @@ -43,7 +43,7 @@ grid_names: orca_arrangement: T orca_name: ORCA2 dimensions: [182, 149] - orca_uid: d5bde4f52ff3a9bea5629cd9ac514410 + orca_uid: "d5bde4f52ff3a9bea5629cd9ac514410" url_prefix: *orca_url_prefix url: ORCA2_T.atlas @@ -52,7 +52,7 @@ grid_names: orca_arrangement: U orca_name: ORCA2 dimensions: [182, 149] - orca_uid: 857f7affa3a381e3882d38d321384e49 + orca_uid: "857f7affa3a381e3882d38d321384e49" url_prefix: *orca_url_prefix url: ORCA2_U.atlas @@ -61,7 +61,7 @@ grid_names: orca_arrangement: V orca_name: ORCA2 dimensions: [182, 149] - orca_uid: ca637bc5dc9a54e2ea4b9750e1b79e6e + orca_uid: "ca637bc5dc9a54e2ea4b9750e1b79e6e" url_prefix: *orca_url_prefix url: ORCA2_V.atlas @@ -70,7 +70,7 @@ grid_names: orca_arrangement: W orca_name: ORCA2 dimensions: [182, 149] - orca_uid: edea6f71eb558dc056b5f576d5b904f7 + orca_uid: "edea6f71eb558dc056b5f576d5b904f7" url_prefix: *orca_url_prefix url: ORCA2_T.atlas @@ -79,7 +79,7 @@ grid_names: orca_arrangement: F orca_name: ORCA1 dimensions: [362, 292] - orca_uid: a832a12030c73928133553ec3a8d2a7e + orca_uid: "a832a12030c73928133553ec3a8d2a7e" url_prefix: *orca_url_prefix url: ORCA1_F.atlas @@ -88,7 +88,7 @@ grid_names: orca_arrangement: T orca_name: ORCA1 dimensions: [362, 292] - orca_uid: f4c91b6233fe55dec992160ec12b38df + orca_uid: "f4c91b6233fe55dec992160ec12b38df" url_prefix: *orca_url_prefix url: ORCA1_T.atlas @@ -97,7 +97,7 @@ grid_names: orca_arrangement: U orca_name: ORCA1 dimensions: [362, 292] - orca_uid: 1b0f8d234753f910197c975c906b4da5 + orca_uid: "1b0f8d234753f910197c975c906b4da5" url_prefix: *orca_url_prefix url: ORCA1_U.atlas @@ -106,7 +106,7 @@ grid_names: orca_arrangement: V orca_name: ORCA1 dimensions: [362, 292] - orca_uid: c637340454795b395f982851b840943d + orca_uid: "c637340454795b395f982851b840943d" url_prefix: *orca_url_prefix url: ORCA1_V.atlas @@ -115,7 +115,7 @@ grid_names: orca_arrangement: W orca_name: ORCA1 dimensions: [362, 292] - orca_uid: d50061c43e83c46c3810002591ea21e1 + orca_uid: "d50061c43e83c46c3810002591ea21e1" url_prefix: *orca_url_prefix url: ORCA1_T.atlas @@ -124,7 +124,7 @@ grid_names: orca_arrangement: F orca_name: eORCA1 dimensions: [362, 332] - orca_uid: 3c6d95561710c6f39b394809ff6c588c + orca_uid: "3c6d95561710c6f39b394809ff6c588c" url_prefix: *orca_url_prefix url: eORCA1_F.atlas @@ -133,7 +133,7 @@ grid_names: orca_arrangement: T orca_name: eORCA1 dimensions: [362, 332] - orca_uid: ba65665a9e68d1a8fa0352ecfcf8e496 + orca_uid: "ba65665a9e68d1a8fa0352ecfcf8e496" url_prefix: *orca_url_prefix url: eORCA1_T.atlas @@ -142,7 +142,7 @@ grid_names: orca_arrangement: U orca_name: eORCA1 dimensions: [362, 332] - orca_uid: 4eb1054957dcae914e219faf9a4068e3 + orca_uid: "4eb1054957dcae914e219faf9a4068e3" url_prefix: *orca_url_prefix url: eORCA1_U.atlas @@ -151,7 +151,7 @@ grid_names: orca_arrangement: V orca_name: eORCA1 dimensions: [362, 332] - orca_uid: 09131429766e7737c087d3a8d7073dc9 + orca_uid: "09131429766e7737c087d3a8d7073dc9" url_prefix: *orca_url_prefix url: eORCA1_V.atlas @@ -160,7 +160,7 @@ grid_names: orca_arrangement: W orca_name: eORCA1 dimensions: [362, 332] - orca_uid: 5c678d8f9aa2edfbf57246d11d9c1278 + orca_uid: "5c678d8f9aa2edfbf57246d11d9c1278" url_prefix: *orca_url_prefix url: eORCA1_T.atlas @@ -169,7 +169,7 @@ grid_names: orca_arrangement: F orca_name: ORCA025 dimensions: [1442, 1021] - orca_uid: efbc280d8d4b6048797880da2605bacb + orca_uid: "efbc280d8d4b6048797880da2605bacb" url_prefix: *orca_url_prefix url: ORCA025_F.atlas @@ -178,7 +178,7 @@ grid_names: orca_arrangement: T orca_name: ORCA025 dimensions: [1442, 1021] - orca_uid: 15c961c269ac182ca226d7195f3921ba + orca_uid: "15c961c269ac182ca226d7195f3921ba" url_prefix: *orca_url_prefix url: ORCA025_T.atlas @@ -187,7 +187,7 @@ grid_names: orca_arrangement: U orca_name: ORCA025 dimensions: [1442, 1021] - orca_uid: 3f4a68bc5b54c9f867fbcc12aacc723d + orca_uid: "3f4a68bc5b54c9f867fbcc12aacc723d" url_prefix: *orca_url_prefix url: ORCA025_U.atlas @@ -196,7 +196,7 @@ grid_names: orca_arrangement: V orca_name: ORCA025 dimensions: [1442, 1021] - orca_uid: 9c87699ee2026c0feee07d2a972eaccd + orca_uid: "9c87699ee2026c0feee07d2a972eaccd" url_prefix: *orca_url_prefix url: ORCA025_V.atlas @@ -205,7 +205,7 @@ grid_names: orca_arrangement: W orca_name: ORCA025 dimensions: [1442, 1021] - orca_uid: 74ca68f1c8524811f3d3aad99536adc2 + orca_uid: "74ca68f1c8524811f3d3aad99536adc2" url_prefix: *orca_url_prefix url: ORCA025_T.atlas @@ -214,7 +214,7 @@ grid_names: orca_arrangement: F orca_name: eORCA025 dimensions: [1442, 1207] - orca_uid: 770e5bbb667a253d55db8a98a3b2d3a9 + orca_uid: "770e5bbb667a253d55db8a98a3b2d3a9" url_prefix: *orca_url_prefix url: eORCA025_F.atlas @@ -223,7 +223,7 @@ grid_names: orca_arrangement: T orca_name: eORCA025 dimensions: [1442, 1207] - orca_uid: 983412216c9768bc794c18dc92082895 + orca_uid: "983412216c9768bc794c18dc92082895" url_prefix: *orca_url_prefix url: eORCA025_T.atlas @@ -232,7 +232,7 @@ grid_names: orca_arrangement: U orca_name: eORCA025 dimensions: [1442, 1207] - orca_uid: b1b2922e9b57ee9c6eeddad218b6e4f3 + orca_uid: "b1b2922e9b57ee9c6eeddad218b6e4f3" url_prefix: *orca_url_prefix url: eORCA025_U.atlas @@ -241,7 +241,7 @@ grid_names: orca_arrangement: V orca_name: eORCA025 dimensions: [1442, 1207] - orca_uid: 9b06bf73a8f14e927bd9b0f1f0c04f74 + orca_uid: "9b06bf73a8f14e927bd9b0f1f0c04f74" url_prefix: *orca_url_prefix url: eORCA025_V.atlas @@ -250,7 +250,7 @@ grid_names: orca_arrangement: W orca_name: eORCA025 dimensions: [1442, 1207] - orca_uid: 4a1ba3b11b8888aefc96992b6b1cab62 + orca_uid: "4a1ba3b11b8888aefc96992b6b1cab62" url_prefix: *orca_url_prefix url: eORCA025_T.atlas @@ -259,7 +259,7 @@ grid_names: orca_arrangement: F orca_name: ORCA12 dimensions: [4322, 3059] - orca_uid: 29693ad8a7af3ae3ee0f02d090f0ec7b + orca_uid: "29693ad8a7af3ae3ee0f02d090f0ec7b" url_prefix: *orca_url_prefix url: ORCA12_F.atlas @@ -268,7 +268,7 @@ grid_names: orca_arrangement: T orca_name: ORCA12 dimensions: [4322, 3059] - orca_uid: b117d01170ac77bca68560ab10e559de + orca_uid: "b117d01170ac77bca68560ab10e559de" url_prefix: *orca_url_prefix url: ORCA12_T.atlas @@ -277,7 +277,7 @@ grid_names: orca_arrangement: U orca_name: ORCA12 dimensions: [4322, 3059] - orca_uid: fff193b92d94d03e847ff2fa62b493f4 + orca_uid: "fff193b92d94d03e847ff2fa62b493f4" url_prefix: *orca_url_prefix url: ORCA12_U.atlas @@ -286,7 +286,7 @@ grid_names: orca_arrangement: V orca_name: ORCA12 dimensions: [4322, 3059] - orca_uid: 986e3450774b716f6e75c1987e370b10 + orca_uid: "986e3450774b716f6e75c1987e370b10" url_prefix: *orca_url_prefix url: ORCA12_V.atlas @@ -295,7 +295,7 @@ grid_names: orca_arrangement: W orca_name: ORCA12 dimensions: [4322, 3059] - orca_uid: ccfe953619a8dd49a7f765923882a274 + orca_uid: "ccfe953619a8dd49a7f765923882a274" url_prefix: *orca_url_prefix url: ORCA12_T.atlas @@ -304,7 +304,7 @@ grid_names: orca_arrangement: F orca_name: eORCA12 dimensions: [4322, 3606] - orca_uid: 25da53ed581b3931fa310840fa9aefd9 + orca_uid: "25da53ed581b3931fa310840fa9aefd9" url_prefix: *orca_url_prefix url: eORCA12_F.atlas @@ -313,7 +313,7 @@ grid_names: orca_arrangement: T orca_name: eORCA12 dimensions: [4322, 3606] - orca_uid: 1553b66f5885cf5f83ad4b4fdf25f460 + orca_uid: "1553b66f5885cf5f83ad4b4fdf25f460" url_prefix: *orca_url_prefix url: eORCA12_T.atlas @@ -322,7 +322,7 @@ grid_names: orca_arrangement: U orca_name: eORCA12 dimensions: [4322, 3606] - orca_uid: 3e87c826643da440b4e9d9f67588a576 + orca_uid: "3e87c826643da440b4e9d9f67588a576" url_prefix: *orca_url_prefix url: eORCA12_U.atlas @@ -331,7 +331,7 @@ grid_names: orca_arrangement: V orca_name: eORCA12 dimensions: [4322, 3606] - orca_uid: cc1e3fc06a2cd18c0653e557510b8a71 + orca_uid: "cc1e3fc06a2cd18c0653e557510b8a71" url_prefix: *orca_url_prefix url: eORCA12_V.atlas @@ -340,7 +340,7 @@ grid_names: orca_arrangement: W orca_name: eORCA12 dimensions: [4322, 3606] - orca_uid: 462469edbd0e0586a0cf17424cc58c89 + orca_uid: "462469edbd0e0586a0cf17424cc58c89" url_prefix: *orca_url_prefix url: eORCA12_T.atlas diff --git a/src/eckit/geometry/grid/ORCA.cc b/src/eckit/geometry/grid/ORCA.cc index 90af54513..e858d0540 100644 --- a/src/eckit/geometry/grid/ORCA.cc +++ b/src/eckit/geometry/grid/ORCA.cc @@ -15,12 +15,12 @@ #include "eckit/codec/codec.h" #include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" -#include "eckit/filesystem/URI.h" #include "eckit/geometry/LibEcKitGeometry.h" #include "eckit/geometry/area/BoundingBox.h" #include "eckit/io/Length.h" #include "eckit/log/Bytes.h" #include "eckit/log/Timer.h" +#include "eckit/types/FloatCompare.h" #include "eckit/utils/ByteSwap.h" #include "eckit/utils/MD5.h" @@ -65,12 +65,14 @@ ORCA::Iterator::Iterator(const Grid& grid, size_t index) : longitudes_(dynamic_cast(grid).longitudes_), latitudes_(dynamic_cast(grid).latitudes_), uid_(dynamic_cast(grid).uid_) { + ASSERT(index_size_ == longitudes_.size()); + ASSERT(index_size_ == latitudes_.size()); } bool ORCA::Iterator::operator==(const geometry::Iterator& other) const { const auto* another = dynamic_cast(&other); - return another != nullptr && uid_ == another->uid_; + return another != nullptr && index_ == another->index_ && uid_ == another->uid_; } @@ -109,85 +111,50 @@ ORCA::ORCA(const Configuration& config) : Grid(config), name_(config.getString("orca_name")), uid_(config.getString("orca_uid")), - arrangement_(arrangement_from_string(config.getString("orca_arrangement"))) { - - - // TODO - ASSERT(dimensions_.size() == 2); - ASSERT(0 < dimensions_[0]); - ASSERT(0 < dimensions_[1]); - - ASSERT(halo_[0] >= 0); - ASSERT(halo_[1] >= 0); - ASSERT(halo_[2] >= 0); - ASSERT(halo_[3] >= 0); - - ASSERT(pivot_[0] >= 0); - ASSERT(pivot_[1] >= 0); - - auto n = static_cast(dimensions_[0] & dimensions_[1]); - ASSERT(0 < n); - - ASSERT(longitudes_.size() == n); - ASSERT(latitudes_.size() == n); - ASSERT(flags_.size() == n); - - - auto url = config.getString("url_prefix", "") + config.getString("url"); - Log::info() << "url: '" << url << "'" << std::endl; -} - - -ORCA::ORCA(const URI& uri) : - Grid(area::BoundingBox::make_global_prime()) { - if (uri.scheme().find("http") == 0) { - PathName path = "..."; // from url - - if (!path.exists() && LibEcKitGeometry::caching()) { - Timer timer; - - - Log::debug() << "Downloading " << uri << " to " << path << std::endl; - - path.dirName().mkdir(); - - PathName tmp = path + ".download"; - Length length = 0; + arrangement_(arrangement_from_string(config.getString("orca_arrangement"))), + dimensions_{-1, -1}, + halo_{-1, -1, -1, -1}, + pivot_{-1, -1} { + PathName path = config.getString("path", LibEcKitGeometry::cacheDir() + "/eckit/geometry/orca/" + uid_ + ".atlas"); + +#if eckit_HAVE_CURL // for eckit::URLHandle + if (!path.exists() && LibEcKitGeometry::caching()) { + auto dir = path.dirName(); + dir.mkdir(); + ASSERT(dir.exists()); + + auto tmp = path + ".download"; + auto url = config.getString("url_prefix", "") + config.getString("url"); + + Timer timer; + Log::info() << "ORCA: downloading '" << url << "' to '" << path << "'..." << std::endl; + + Length length = 0; + try { + length = URLHandle(url).saveInto(tmp); + } + catch (...) { + length = 0; + } -#if eckit_HAVE_CURL - try { - length = URLHandle(uri.asRawString()).saveInto(tmp); + if (length <= 0) { + if (tmp.exists()) { + tmp.unlink(true); } - catch (...) { - length = 0; - } -#endif - - if (length <= 0) { - if (tmp.exists()) { - tmp.unlink(true); - } - throw UserError("Could not download file from url " + uri.asRawString()); - } + throw UserError("ORCA: download error"); + } - if (!path.exists()) { - throw UserError("Could not locate orca grid data file " + path); - } + PathName::rename(tmp, path); + Log::info() << "ORCA: download of " << Bytes(static_cast(length)) << " took " << timer.elapsed() << " s." << std::endl; + } - PathName::rename(tmp, path); + ASSERT_MSG(path.exists(), "ORCA: file '" + path + "' not found"); +#endif - Log::info() << "Download of " << Bytes(length) << " took " << timer.elapsed() << " s." << std::endl; - } - else { - throw UserError("Could not locate orca grid data file " + path); - } - } - else { - if (!uri.path().exists()) { - throw UserError("Could not locate orca grid data file " + uri.asRawString()); - } - } + // read and check against metadata (if present) + read(path); + check(config); } @@ -199,16 +166,46 @@ void ORCA::read(const PathName& p) { if (version == 0) { reader.read("dimensions", dimensions_); - reader.read("pivot", pivot_); - reader.read("halo", halo_); + reader.read("pivot", pivot_); // different order from writer + reader.read("halo", halo_); //... reader.read("longitude", longitudes_); reader.read("latitude", latitudes_); reader.read("flags", flags_); reader.wait(); + return; } - else { - ASSERT_MSG(false, "Unsupported version "); + + throw SeriousBug("ORCA::read: unsupported version"); +} + + +void ORCA::check(const Configuration& config) { + ASSERT(uid_.length() == 32); + if (config.getBool("orca_uid_check", false)) { + ASSERT(uid_ == uid()); } + + if (std::vector d; config.get("dimensions", d)) { + ASSERT(d.size() == 2); + ASSERT(d[0] == dimensions_[0] && d[1] == dimensions_[1]); + } + + if (std::vector h; config.get("halo", h)) { + ASSERT(h.size() == 4); + ASSERT(h[0] == halo_[0] && h[1] == halo_[1] && h[2] == halo_[2] && h[3] == halo_[3]); + } + + if (std::vector p; config.get("pivot", p)) { + ASSERT(p.size() == 2); + ASSERT(types::is_approximately_equal(p[0], pivot_[0])); + ASSERT(types::is_approximately_equal(p[1], pivot_[1])); + } + + auto n = static_cast(dimensions_[0] * dimensions_[1]); + ASSERT(n > 0); + ASSERT(n == longitudes_.size()); + ASSERT(n == latitudes_.size()); + ASSERT(n == flags_.size()); } @@ -228,7 +225,7 @@ size_t ORCA::write(const PathName& p, const std::string& compression) { } -std::string ORCA::uid(const Configuration& config) const { +std::string ORCA::uid() const { MD5 hash; hash.add(arrangement_to_string(arrangement_)); @@ -247,7 +244,10 @@ std::string ORCA::uid(const Configuration& config) const { hash.add(lonsw.data(), sized); } - return hash.digest(); + auto d = hash.digest(); + ASSERT(d.length() == 32); + + return d; } diff --git a/src/eckit/geometry/grid/ORCA.h b/src/eckit/geometry/grid/ORCA.h index 732744b00..7fd3e280d 100644 --- a/src/eckit/geometry/grid/ORCA.h +++ b/src/eckit/geometry/grid/ORCA.h @@ -15,16 +15,13 @@ #include #include #include -#include -#include #include "eckit/geometry/Grid.h" namespace eckit { class PathName; -class URI; -} // namespace eckit +} namespace eckit::geometry::grid { @@ -70,7 +67,6 @@ class ORCA final : public Grid { // -- Constructors explicit ORCA(const Configuration&); - explicit ORCA(const URI&); // -- Destructor // None @@ -83,10 +79,7 @@ class ORCA final : public Grid { // -- Methods - void read(const PathName&); - size_t write(const PathName&, const std::string& compression = "none"); - - std::string uid(const Configuration& config) const; + std::string uid() const; // -- Overridden methods // None @@ -105,21 +98,22 @@ class ORCA final : public Grid { std::string uid_; Arrangement arrangement_; + std::array dimensions_; + std::array halo_; + std::array pivot_; std::vector longitudes_; std::vector latitudes_; - - std::array dimensions_{-1, -1}; - std::array halo_{-1, -1, -1, -1}; - std::array pivot_{-1, -1}; std::vector flags_; // -- Methods + void read(const PathName&); + void check(const Configuration&); + size_t write(const PathName&, const std::string& compression = "none"); + size_t ni() const { return static_cast(dimensions_[0]); } size_t nj() const { return static_cast(dimensions_[1]); } - std::vector longitudes(size_t ring) const; - // -- Overridden methods iterator cbegin() const override; From f9ab2ca3f819051e1bdd8dd6c2827ab2d3648c9c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 25 Aug 2023 12:27:13 +0100 Subject: [PATCH 320/737] eckit::geometry --- src/eckit/geometry/PointLonLat.cc | 9 +++++++++ src/eckit/geometry/PointLonLat.h | 2 ++ src/eckit/geometry/grid/HEALPix.cc | 4 ++-- src/eckit/geometry/grid/ORCA.cc | 2 +- src/eckit/geometry/grid/UnstructuredGrid.cc | 19 +++++++++++++++++++ src/eckit/geometry/grid/UnstructuredGrid.h | 3 ++- 6 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/eckit/geometry/PointLonLat.cc b/src/eckit/geometry/PointLonLat.cc index 6ef284aba..068a52540 100644 --- a/src/eckit/geometry/PointLonLat.cc +++ b/src/eckit/geometry/PointLonLat.cc @@ -46,4 +46,13 @@ double PointLonLat::normalise_angle_to_maximum(double a, double maximum) { } +bool operator<(const PointLonLat& a, const PointLonLat& b) { + if (types::is_approximately_equal(a.lon, b.lon) || types::is_approximately_equal(a.lat, b.lat)) { + return false; + } + + return a.lon < b.lon && a.lat < b.lat; +} + + } // namespace eckit::geometry diff --git a/src/eckit/geometry/PointLonLat.h b/src/eckit/geometry/PointLonLat.h index e1edd6f94..2cf4917b4 100644 --- a/src/eckit/geometry/PointLonLat.h +++ b/src/eckit/geometry/PointLonLat.h @@ -111,4 +111,6 @@ class PointLonLat final : protected std::array { bool points_equal(const PointLonLat&, const PointLonLat&); +bool operator<(const PointLonLat&, const PointLonLat&); + } // namespace eckit::geometry diff --git a/src/eckit/geometry/grid/HEALPix.cc b/src/eckit/geometry/grid/HEALPix.cc index f021d8153..e3ff6298e 100644 --- a/src/eckit/geometry/grid/HEALPix.cc +++ b/src/eckit/geometry/grid/HEALPix.cc @@ -131,7 +131,7 @@ HEALPix::HEALPix(size_t Nside, Ordering ordering) : Configuration* HEALPix::config(const std::string& name) { auto Nside = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "healpix"}, {"Nside", Nside}, {"orderingConvention", "ring"}}); + return new MappedConfiguration({{"type", "HEALPix"}, {"Nside", Nside}, {"orderingConvention", "ring"}}); } @@ -217,7 +217,7 @@ std::pair, std::vector> HEALPix::to_latlon() const { } -static const GridRegisterType __grid_type("healpix"); +static const GridRegisterType __grid_type("HEALPix"); static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); diff --git a/src/eckit/geometry/grid/ORCA.cc b/src/eckit/geometry/grid/ORCA.cc index e858d0540..ac44c470c 100644 --- a/src/eckit/geometry/grid/ORCA.cc +++ b/src/eckit/geometry/grid/ORCA.cc @@ -148,9 +148,9 @@ ORCA::ORCA(const Configuration& config) : PathName::rename(tmp, path); Log::info() << "ORCA: download of " << Bytes(static_cast(length)) << " took " << timer.elapsed() << " s." << std::endl; } +#endif ASSERT_MSG(path.exists(), "ORCA: file '" + path + "' not found"); -#endif // read and check against metadata (if present) read(path); diff --git a/src/eckit/geometry/grid/UnstructuredGrid.cc b/src/eckit/geometry/grid/UnstructuredGrid.cc index 9656a43b5..4f18ec24a 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.cc +++ b/src/eckit/geometry/grid/UnstructuredGrid.cc @@ -12,6 +12,8 @@ #include "eckit/geometry/grid/UnstructuredGrid.h" +#include + #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geometry/iterator/ListI.h" @@ -36,8 +38,25 @@ UnstructuredGrid::UnstructuredGrid(const std::vector& latitudes, const s } +Renumber UnstructuredGrid::list_duplicates() const { + std::vector dupes; + + std::set seen; + + for (auto i = cbegin(); i != cend(); ++i) { + if (!seen.insert(std::get(*i)).second) { + dupes.push_back(i->index()); + } + } + + return dupes; +} + + UnstructuredGrid::UnstructuredGrid(std::pair, std::vector>&& latlon) : Grid(area::BoundingBox::make_global_prime()), latitudes_(std::move(latlon.first)), longitudes_(std::move(latlon.second)) { + ASSERT(!latitudes_.empty()); + ASSERT(latitudes_.size() == longitudes_.size()); } diff --git a/src/eckit/geometry/grid/UnstructuredGrid.h b/src/eckit/geometry/grid/UnstructuredGrid.h index ae43a45c5..083686ee6 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.h +++ b/src/eckit/geometry/grid/UnstructuredGrid.h @@ -47,7 +47,8 @@ class UnstructuredGrid : public Grid { // None // -- Methods - // None + + Renumber list_duplicates() const; // -- Overridden methods // None From edbd9643c7999281d3c411db8024821b3fe1b36e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 25 Aug 2023 14:36:49 +0100 Subject: [PATCH 321/737] eckit::geometry --- src/eckit/geometry/Point.h | 3 +- src/eckit/geometry/Point2.cc | 6 +- src/eckit/geometry/Point2.h | 2 + src/eckit/geometry/Point3.cc | 9 +- src/eckit/geometry/Point3.h | 2 + src/eckit/geometry/PointLonLat.cc | 18 +- src/eckit/geometry/PointLonLat.h | 1 + tests/geometry/CMakeLists.txt | 9 - tests/geometry/test_projection.cc | 246 +++++++++++++++++++- tests/geometry/test_projection_ll_to_xyz.cc | 46 ---- tests/geometry/test_projection_proj.cc | 72 ------ tests/geometry/test_projection_rotation.cc | 183 --------------- 12 files changed, 274 insertions(+), 323 deletions(-) delete mode 100644 tests/geometry/test_projection_ll_to_xyz.cc delete mode 100644 tests/geometry/test_projection_proj.cc delete mode 100644 tests/geometry/test_projection_rotation.cc diff --git a/src/eckit/geometry/Point.h b/src/eckit/geometry/Point.h index e5eb55783..b3036643b 100644 --- a/src/eckit/geometry/Point.h +++ b/src/eckit/geometry/Point.h @@ -24,8 +24,8 @@ namespace eckit::geometry { using Point = std::variant; -bool points_equal(const Point&, const Point&); +bool points_equal(const Point&, const Point&); std::ostream& operator<<(std::ostream&, const Point&); @@ -36,6 +36,7 @@ constexpr double NORTH_POLE = 90.; constexpr double SOUTH_POLE = -90.; +// FIXME remove using Longitude = double; using Latitude = double; diff --git a/src/eckit/geometry/Point2.cc b/src/eckit/geometry/Point2.cc index 92edebc5e..73aff5363 100644 --- a/src/eckit/geometry/Point2.cc +++ b/src/eckit/geometry/Point2.cc @@ -21,7 +21,11 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- bool points_equal(const Point2& a, const Point2& b) { - return eckit::types::is_approximately_equal(Point2::distance2(a, b), 0.0); + return eckit::types::is_approximately_equal(Point2::distance2(a, b), 0.0); +} + +bool operator<(const Point2& a, const Point2& b) { + return eckit::types::is_approximately_equal(Point2::distance2(a, b), 0.0); } Point2::operator Value() const { diff --git a/src/eckit/geometry/Point2.h b/src/eckit/geometry/Point2.h index 054731c91..07f1cb27f 100644 --- a/src/eckit/geometry/Point2.h +++ b/src/eckit/geometry/Point2.h @@ -94,6 +94,8 @@ class Point2 : public KPoint<2> { bool points_equal(const Point2&, const Point2&); +bool operator<(const Point2&, const Point2&); + //------------------------------------------------------------------------------------------------------ } // namespace eckit::geometry diff --git a/src/eckit/geometry/Point3.cc b/src/eckit/geometry/Point3.cc index 811bf1cd6..44dee0493 100644 --- a/src/eckit/geometry/Point3.cc +++ b/src/eckit/geometry/Point3.cc @@ -19,7 +19,14 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- bool points_equal(const Point3& a, const Point3& b) { - return eckit::types::is_approximately_equal(Point3::distance2(a, b), 0.0); + auto eps = 1e-6; + return types::is_approximately_equal(a.X, b.X, eps) && + types::is_approximately_equal(a.Y, b.Y, eps) && + types::is_approximately_equal(a.Z, b.Z, eps); + +} + +bool operator<(const Point3& a, const Point3& b) { } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geometry/Point3.h b/src/eckit/geometry/Point3.h index 20ba41648..d02bc26da 100644 --- a/src/eckit/geometry/Point3.h +++ b/src/eckit/geometry/Point3.h @@ -88,6 +88,8 @@ class Point3 : public KPoint<3> { bool points_equal(const Point3&, const Point3&); +bool operator<(const Point3&, const Point3&); + //------------------------------------------------------------------------------------------------------ } // namespace eckit::geometry diff --git a/src/eckit/geometry/PointLonLat.cc b/src/eckit/geometry/PointLonLat.cc index 068a52540..b68b8196c 100644 --- a/src/eckit/geometry/PointLonLat.cc +++ b/src/eckit/geometry/PointLonLat.cc @@ -12,18 +12,12 @@ #include "eckit/geometry/PointLonLat.h" -#include "eckit/geometry/UnitSphere.h" #include "eckit/types/FloatCompare.h" namespace eckit::geometry { -bool points_equal(const PointLonLat& a, const PointLonLat& b) { - return types::is_approximately_equal(UnitSphere::centralAngle(a, b), 0.0); -} - - double PointLonLat::normalise_angle_to_minimum(double a, double minimum) { while (a < minimum) { a += 360.; @@ -46,6 +40,18 @@ double PointLonLat::normalise_angle_to_maximum(double a, double maximum) { } +bool points_equal(const PointLonLat& a, const PointLonLat& b) { + // FIXME + // solved {180., 0.} == {-180., 0.} + // could be more performant + auto c = PointLonLat::make(a.lon, a.lat); + auto d = PointLonLat::make(b.lon, b.lat); + auto eps = 1e-6; + return types::is_approximately_equal(c.lon, d.lon, eps) && + types::is_approximately_equal(c.lat, d.lat, eps); +} + + bool operator<(const PointLonLat& a, const PointLonLat& b) { if (types::is_approximately_equal(a.lon, b.lon) || types::is_approximately_equal(a.lat, b.lat)) { return false; diff --git a/src/eckit/geometry/PointLonLat.h b/src/eckit/geometry/PointLonLat.h index 2cf4917b4..c6499b09f 100644 --- a/src/eckit/geometry/PointLonLat.h +++ b/src/eckit/geometry/PointLonLat.h @@ -83,6 +83,7 @@ class PointLonLat final : protected std::array { static PointLonLat make(double lon, double lat, double lon_minimum = 0) { lat = normalise_angle_to_minimum(lat, -90.); + // FIXME problems with lat << -90 and lat >> 90 if (lat > 90.) { lat = 180. - lat; lon += 180.; diff --git a/tests/geometry/CMakeLists.txt b/tests/geometry/CMakeLists.txt index 2ce209265..ab0ae8747 100644 --- a/tests/geometry/CMakeLists.txt +++ b/tests/geometry/CMakeLists.txt @@ -9,8 +9,6 @@ foreach( _test points polygon projection - projection_ll_to_xyz - projection_rotation search sphere types @@ -21,10 +19,3 @@ foreach( _test LIBS eckit_geometry ) endforeach() -if(HAVE_PROJ) - ecbuild_add_test( - TARGET eckit_test_geometry_projection_proj - SOURCES test_projection_proj.cc - LIBS eckit_geometry ) -endif() - diff --git a/tests/geometry/test_projection.cc b/tests/geometry/test_projection.cc index 31e0c721c..b503e4c79 100644 --- a/tests/geometry/test_projection.cc +++ b/tests/geometry/test_projection.cc @@ -15,16 +15,15 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/geometry/Projection.h" +#include "eckit/geometry/projection/LonLatToXYZ.h" +#include "eckit/geometry/projection/Rotation.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { using eckit::MappedConfiguration; - using eckit::geometry::Point; - using eckit::geometry::Point3; - using eckit::geometry::PointLonLat; - using eckit::geometry::points_equal; + using namespace eckit::geometry; using Projection = std::unique_ptr; using eckit::geometry::ProjectionFactory; @@ -82,4 +81,243 @@ int main(int argc, char* argv[]) { EXPECT(points_equal(s3->fwd(test.a), test.b)); } } + + + { + + const PointLonLat p(723., 1.); // <- FIXME + + { projection::LonLatToXYZ to_xyz(1.); + + auto q = to_xyz.fwd(p); + auto r = to_xyz.inv(q); + std::cout << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; + + EXPECT(points_equal(p, r)); + } + + + { + projection::LonLatToXYZ to_xyz_ab(3., 2.); // oblate + projection::LonLatToXYZ to_xyz_ba(2., 3.); // problate + + for (const auto& lon : {0., 90., 180., 270.}) { + PointLonLat p{lon, 0.}; + std::cout << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) + << ", p_ba(x,y,z): " << to_xyz_ba.fwd(p) << std::endl; + } + } + } + + + { + const PointLonLat p(1, 1); + int delta[] = {-360, -180, -1, 0, 1, 90, 91, 180}; + + for (auto a : delta) { + for (auto b : delta) { + for (auto c : delta) { + projection::Rotation rot(0. + static_cast(b), -90. + static_cast(a), static_cast(c)); + EXPECT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); + + EXPECT(points_equal(p, rot.inv(rot.fwd(p)))); + EXPECT(points_equal(p, rot.fwd(rot.inv(p)))); + } + } + } + } + + + { + const int Ni = 12; + const int Nj = 3; + + projection::Rotation rot(182., -46.7, 0.); + const PointLonLat ref[]{ + {-178., -46.7}, + {-178., -16.7}, + {-178., 13.3}, + {-178., 43.3}, + {-178., 73.3}, + {2., 76.7}, + {2., 46.7}, + {-178., -46.7}, + {-162.62343, -19.46929}, + {-152.02366, 8.65459}, + {-139.57464, 36.43683}, + {-113.10894, 61.43199}, + {-39.88245, 68.00825}, + {2., 46.7}, + {-178., -46.7}, + {-148.83443, -27.31067}, + {-129.26346, -3.837}, + {-110.79116, 20.05422}, + {-85.87917, 41.36507}, + {-44.42496, 53.29508}, + {2., 46.7}, + {-178., -46.7}, + {-137.90794, -39.07002}, + {-109.60146, -21.33906}, + {-88., 0.}, + {-66.39854, 21.33906}, + {-38.09206, 39.07002}, + {2., 46.7}, + {-178., -46.7}, + {-131.57504, -53.29508}, + {-90.12083, -41.36507}, + {-65.20884, -20.05422}, + {-46.73654, 3.837}, + {-27.16557, 27.31067}, + {2., 46.7}, + {-178., -46.7}, + {-136.11755, -68.00825}, + {-62.89106, -61.43199}, + {-36.42536, -36.43683}, + {-23.97634, -8.65459}, + {-13.37657, 19.46929}, + {2., 46.7}, + {-178., -46.7}, + {-178., -76.7}, + {2., -73.3}, + {2., -43.3}, + {2., -13.3}, + {2., 16.7}, + {2., 46.7}, + {-178., -46.7}, + {140.11755, -68.00825}, + {66.89106, -61.43199}, + {40.42536, -36.43683}, + {27.97634, -8.65459}, + {17.37657, 19.46929}, + {2., 46.7}, + {-178., -46.7}, + {135.57504, -53.29508}, + {94.12083, -41.36507}, + {69.20884, -20.05422}, + {50.73654, 3.837}, + {31.16557, 27.31067}, + {2., 46.7}, + {-178., -46.7}, + {141.90794, -39.07002}, + {113.60146, -21.33906}, + {92., 0.}, + {70.39854, 21.33906}, + {42.09206, 39.07002}, + {2., 46.7}, + {-178., -46.7}, + {152.83443, -27.31067}, + {133.26346, -3.837}, + {114.79116, 20.05422}, + {89.87917, 41.36507}, + {48.42496, 53.29508}, + {2., 46.7}, + {-178., -46.7}, + {166.62343, -19.46929}, + {156.02366, 8.65459}, + {143.57464, 36.43683}, + {117.10894, 61.43199}, + {43.88245, 68.00825}, + {2., 46.7}, + }; + + for (int i = 0, k = 0; i < Ni; i++) { + for (int j = 0; j < 2 * Nj + 1; j++, k++) { + PointLonLat a(static_cast(i) * 360. / static_cast(Ni), + static_cast(j - Nj) * 90. / static_cast(Nj)); + auto b = rot.fwd(a); + EXPECT(points_equal(b, ref[k])); + EXPECT(points_equal(a, rot.inv(b))); + } + } + } + + + { + const projection::Rotation non_rotated(0., -90., 0.); + const projection::Rotation rotation_angle(0., -90., -180.); + const projection::Rotation rotation_matrix(4., -40., 180.); + + EXPECT(not non_rotated.rotated()); + EXPECT(rotation_angle.rotated()); + EXPECT(rotation_matrix.rotated()); + + const PointLonLat p[] = {{0., 90.}, {0., 0.}, {270., 25.}, {-180., 45.}}; + + struct { + const projection::Rotation& rotation; + const PointLonLat a; + const PointLonLat b; + } tests[] = { + {non_rotated, p[0], p[0]}, + {non_rotated, p[1], p[1]}, + {non_rotated, p[2], p[2]}, + {non_rotated, p[3], p[3]}, + {rotation_angle, p[0], {p[0].lon - 180., p[0].lat}}, + {rotation_angle, p[1], {p[1].lon - 180., p[1].lat}}, + {rotation_angle, p[2], {p[2].lon - 180., p[2].lat}}, + {rotation_angle, p[3], {p[3].lon - 180., p[3].lat}}, + {rotation_matrix, p[0], {-176., 40.}}, + {rotation_matrix, p[1], {-176., -50.}}, + {rotation_matrix, p[2], {113.657357, 15.762700}}, + {rotation_matrix, p[3], {-176., 85.}}, + }; + + for (const auto& test : tests) { + auto b = test.rotation.fwd(test.a); + EXPECT(points_equal(b, test.b)); + + auto a = test.rotation.inv(b); + EXPECT(points_equal(a, test.a)); + } + } + + + if (ProjectionFactory::instance().exists("proj")) { + std::cout.precision(14); + + PointLonLat a{12., 55.}; + + struct { + const Point b; + const std::string target; + } tests[] = { + {Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, + {Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, + {a, "EPSG:4326"}, + {a, "EPSG:4979"}, + {Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, + {Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, + "+proj=cart +R=6371229."}, + {Point3{3574399.5431832, 759762.07693392, 5218815.216709}, + "+proj=cart +ellps=sphere"}, + {a, "+proj=latlon +ellps=sphere"}, + }; + + for (const auto& test : tests) { + Projection projection(ProjectionFactory::instance().get("proj").create(MappedConfiguration{{{"source", "EPSG:4326"}, {"target", test.target}}})); + +#if 0 + std::cout << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) + << std::endl; +#endif + + auto b = projection->fwd(a); + auto c = projection->inv(b); + + std::cout << "-> a:" << a << " -> fwd(a):" << b << " -> inv(fwd(a)):" << c << std::endl; + + EXPECT(points_equal(b, test.b)); + EXPECT(points_equal(c, a)); + + Projection reverse(ProjectionFactory::instance().get("proj").create(MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}}))); + + auto d = reverse->fwd(test.b); + auto e = reverse->inv(d); + + std::cout << "-> b:" << test.b << " -> fwd(b):" << d << " -> inv(fwd(b)):" << e << std::endl; + + EXPECT(points_equal(d, a)); + EXPECT(points_equal(e, test.b)); + } + } } diff --git a/tests/geometry/test_projection_ll_to_xyz.cc b/tests/geometry/test_projection_ll_to_xyz.cc deleted file mode 100644 index b16ade496..000000000 --- a/tests/geometry/test_projection_ll_to_xyz.cc +++ /dev/null @@ -1,46 +0,0 @@ -/* - * (C) Copyright 1996- 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 - -#include "eckit/geometry/projection/LonLatToXYZ.h" -#include "eckit/testing/Test.h" - - -int main(int argc, char* argv[]) { - using eckit::geometry::PointLonLat; - using eckit::geometry::projection::LonLatToXYZ; - - const PointLonLat p(1., 723.); - - { - LonLatToXYZ to_xyz(1.); - - auto q = to_xyz.fwd(p); - auto r = to_xyz.inv(q); - std::cout << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; - - EXPECT(points_equal(p, r)); - } - - - { - LonLatToXYZ to_xyz_ab(3., 2.); // oblate - LonLatToXYZ to_xyz_ba(2., 3.); // problate - - for (const auto& lon : {0., 90., 180., 270.}) { - PointLonLat p{0., lon}; - std::cout << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) - << ", p_ba(x,y,z): " << to_xyz_ba.fwd(p) << std::endl; - } - } -} diff --git a/tests/geometry/test_projection_proj.cc b/tests/geometry/test_projection_proj.cc deleted file mode 100644 index e0ec41703..000000000 --- a/tests/geometry/test_projection_proj.cc +++ /dev/null @@ -1,72 +0,0 @@ -/* - * (C) Copyright 1996- 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 - -#include "eckit/config/MappedConfiguration.h" -#include "eckit/geometry/projection/PROJ.h" -#include "eckit/testing/Test.h" - - -int main(int argc, char* argv[]) { - using eckit::geometry::Point; - using eckit::geometry::Point2; - using eckit::geometry::Point3; - using eckit::geometry::PointLonLat; - using eckit::geometry::points_equal; - using eckit::geometry::projection::PROJ; - - std::cout.precision(14); - - PointLonLat a{12., 55.}; - - struct { - const Point b; - const std::string target; - } tests[] = { - {Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, - {Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, - {a, "EPSG:4326"}, - {a, "EPSG:4979"}, - {Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, - {Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, - "+proj=cart +R=6371229."}, - {Point3{3574399.5431832, 759762.07693392, 5218815.216709}, - "+proj=cart +ellps=sphere"}, - {a, "+proj=latlon +ellps=sphere"}, - }; - - for (const auto& test : tests) { - PROJ projection(eckit::MappedConfiguration({{"source", "EPSG:4326"}, {"target", test.target}})); - - std::cout << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) - << std::endl; - - auto b = projection.fwd(a); - auto c = projection.inv(b); - - std::cout << "-> a:" << a << " -> fwd(a):" << b << " -> inv(fwd(a)):" << c << std::endl; - - EXPECT(points_equal(b, test.b)); - EXPECT(points_equal(c, a)); - - PROJ reverse(eckit::MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}})); - - auto d = reverse.fwd(test.b); - auto e = reverse.inv(d); - - std::cout << "-> b:" << test.b << " -> fwd(b):" << d << " -> inv(fwd(b)):" << e << std::endl; - - EXPECT(points_equal(d, a)); - EXPECT(points_equal(e, test.b)); - } -} diff --git a/tests/geometry/test_projection_rotation.cc b/tests/geometry/test_projection_rotation.cc deleted file mode 100644 index 68b848cc8..000000000 --- a/tests/geometry/test_projection_rotation.cc +++ /dev/null @@ -1,183 +0,0 @@ -/* - * (C) Copyright 1996- 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 - -#include "eckit/geometry/projection/Rotation.h" -#include "eckit/testing/Test.h" - - -int main(int argc, char* argv[]) { - using eckit::geometry::Point; - using eckit::geometry::PointLonLat; - using eckit::geometry::points_equal; - using eckit::geometry::projection::Rotation; - - { - const PointLonLat p(1, 1); - int delta[] = {-360, -180, -1, 0, 1, 90, 91, 180}; - - for (auto a : delta) { - for (auto b : delta) { - for (auto c : delta) { - Rotation rot(0. + static_cast(b), -90. + static_cast(a), static_cast(c)); - EXPECT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); - - EXPECT(points_equal(p, rot.inv(rot.fwd(p)))); - EXPECT(points_equal(p, rot.fwd(rot.inv(p)))); - } - } - } - } - - { - const int Ni = 12; - const int Nj = 3; - - Rotation rot(182., -46.7, 0.); - const PointLonLat ref[]{ - {-178., -46.7}, - {-178., -16.7}, - {-178., 13.3}, - {-178., 43.3}, - {-178., 73.3}, - {2., 76.7}, - {2., 46.7}, - {-178., -46.7}, - {-162.62343, -19.46929}, - {-152.02366, 8.65459}, - {-139.57464, 36.43683}, - {-113.10894, 61.43199}, - {-39.88245, 68.00825}, - {2., 46.7}, - {-178., -46.7}, - {-148.83443, -27.31067}, - {-129.26346, -3.837}, - {-110.79116, 20.05422}, - {-85.87917, 41.36507}, - {-44.42496, 53.29508}, - {2., 46.7}, - {-178., -46.7}, - {-137.90794, -39.07002}, - {-109.60146, -21.33906}, - {-88., 0.}, - {-66.39854, 21.33906}, - {-38.09206, 39.07002}, - {2., 46.7}, - {-178., -46.7}, - {-131.57504, -53.29508}, - {-90.12083, -41.36507}, - {-65.20884, -20.05422}, - {-46.73654, 3.837}, - {-27.16557, 27.31067}, - {2., 46.7}, - {-178., -46.7}, - {-136.11755, -68.00825}, - {-62.89106, -61.43199}, - {-36.42536, -36.43683}, - {-23.97634, -8.65459}, - {-13.37657, 19.46929}, - {2., 46.7}, - {-178., -46.7}, - {-178., -76.7}, - {2., -73.3}, - {2., -43.3}, - {2., -13.3}, - {2., 16.7}, - {2., 46.7}, - {-178., -46.7}, - {140.11755, -68.00825}, - {66.89106, -61.43199}, - {40.42536, -36.43683}, - {27.97634, -8.65459}, - {17.37657, 19.46929}, - {2., 46.7}, - {-178., -46.7}, - {135.57504, -53.29508}, - {94.12083, -41.36507}, - {69.20884, -20.05422}, - {50.73654, 3.837}, - {31.16557, 27.31067}, - {2., 46.7}, - {-178., -46.7}, - {141.90794, -39.07002}, - {113.60146, -21.33906}, - {92., 0.}, - {70.39854, 21.33906}, - {42.09206, 39.07002}, - {2., 46.7}, - {-178., -46.7}, - {152.83443, -27.31067}, - {133.26346, -3.837}, - {114.79116, 20.05422}, - {89.87917, 41.36507}, - {48.42496, 53.29508}, - {2., 46.7}, - {-178., -46.7}, - {166.62343, -19.46929}, - {156.02366, 8.65459}, - {143.57464, 36.43683}, - {117.10894, 61.43199}, - {43.88245, 68.00825}, - {2., 46.7}, - }; - - for (int i = 0, k = 0; i < Ni; i++) { - for (int j = 0; j < 2 * Nj + 1; j++, k++) { - PointLonLat a(static_cast(i) * 360. / static_cast(Ni), - static_cast(j - Nj) * 90. / static_cast(Nj)); - auto b = rot.fwd(a); - EXPECT(points_equal(b, ref[k])); - EXPECT(points_equal(a, rot.inv(b))); - } - } - } - - { - const Rotation non_rotated(0., -90., 0.); - const Rotation rotation_angle(0., -90., -180.); - const Rotation rotation_matrix(4., -40., 180.); - - EXPECT(not non_rotated.rotated()); - EXPECT(rotation_angle.rotated()); - EXPECT(rotation_matrix.rotated()); - - const PointLonLat p[] = {{0., 90.}, {0., 0.}, {270., 25.}, {-180., 45.}}; - - struct { - const Rotation& rotation; - const PointLonLat a; - const PointLonLat b; - } tests[] = { - {non_rotated, p[0], p[0]}, - {non_rotated, p[1], p[1]}, - {non_rotated, p[2], p[2]}, - {non_rotated, p[3], p[3]}, - {rotation_angle, p[0], {p[0].lon - 180., p[0].lat}}, - {rotation_angle, p[1], {p[1].lon - 180., p[1].lat}}, - {rotation_angle, p[2], {p[2].lon - 180., p[2].lat}}, - {rotation_angle, p[3], {p[3].lon - 180., p[3].lat}}, - {rotation_matrix, p[0], {-176., 40.}}, - {rotation_matrix, p[1], {-176., -50.}}, - {rotation_matrix, p[2], {113.657357, 15.762700}}, - {rotation_matrix, p[3], {-176., 85.}}, - }; - - for (const auto& test : tests) { - auto b = test.rotation.fwd(test.a); - EXPECT(points_equal(b, test.b)); - - auto a = test.rotation.inv(b); - EXPECT(points_equal(a, test.a)); - } - } -} From 7193d5c042eea4b5147d2e2ec77c77081115200d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 25 Aug 2023 21:05:49 +0100 Subject: [PATCH 322/737] eckit::geometry refactor --- src/eckit/geometry/Area.h | 6 +- src/eckit/geometry/CMakeLists.txt | 57 +++-- src/eckit/geometry/Grid.cc | 5 + src/eckit/geometry/Grid.h | 2 + src/eckit/geometry/Point3.cc | 5 +- src/eckit/geometry/PointLonLat.cc | 7 +- src/eckit/geometry/PointLonLat.h | 1 - src/eckit/geometry/Range.cc | 86 +------ src/eckit/geometry/Range.h | 56 ++-- src/eckit/geometry/grid/Gaussian.cc | 122 --------- src/eckit/geometry/grid/GaussianIterator.cc | 112 -------- src/eckit/geometry/grid/GaussianIterator.h | 61 ----- src/eckit/geometry/grid/HEALPix.cc | 224 ---------------- src/eckit/geometry/grid/HEALPix.h | 123 --------- src/eckit/geometry/grid/IrregularLatlon.cc | 70 ----- src/eckit/geometry/grid/Reduced.cc | 53 ++++ .../geometry/grid/{Gaussian.h => Reduced.h} | 50 ++-- src/eckit/geometry/grid/ReducedGG.cc | 194 -------------- src/eckit/geometry/grid/ReducedLL.cc | 83 ------ src/eckit/geometry/grid/Regular.cc | 241 +---------------- src/eckit/geometry/grid/Regular.h | 92 +++---- src/eckit/geometry/grid/RegularGG.cc | 188 -------------- src/eckit/geometry/grid/RegularGrid.cc | 242 ------------------ src/eckit/geometry/grid/RegularGrid.h | 103 -------- src/eckit/geometry/grid/Unstructured.cc | 36 +++ .../grid/{ReducedGG.h => Unstructured.h} | 48 ++-- src/eckit/geometry/grid/UnstructuredGrid.cc | 101 -------- src/eckit/geometry/grid/reduced/HEALPix.cc | 134 ++++++++++ .../{UnstructuredGrid.h => reduced/HEALPix.h} | 61 +++-- .../geometry/grid/reduced/ReducedGaussian.cc | 103 ++++++++ .../geometry/grid/reduced/ReducedGaussian.h | 93 +++++++ .../geometry/grid/reduced/ReducedLatLon.cc | 56 ++++ .../{RegularGG.h => reduced/ReducedLatLon.h} | 40 ++- .../geometry/grid/regular/IrregularLatLon.cc | 56 ++++ .../geometry/grid/regular/IrregularLatLon.h | 82 ++++++ .../geometry/grid/regular/RegularGaussian.cc | 78 ++++++ .../geometry/grid/regular/RegularGaussian.h | 89 +++++++ .../geometry/grid/regular/RegularLatLon.cc | 56 ++++ .../geometry/grid/regular/RegularLatLon.h | 82 ++++++ .../geometry/grid/{ => unstructured}/ORCA.cc | 124 +++------ .../geometry/grid/{ => unstructured}/ORCA.h | 83 +++--- src/eckit/geometry/iterator/ListI.cc | 67 ----- src/eckit/geometry/iterator/ListIListJ.cc | 97 ------- src/eckit/geometry/iterator/Reduced.cc | 96 +++++++ .../iterator/{ListIListJ.h => Reduced.h} | 38 ++- src/eckit/geometry/iterator/ReducedIListJ.cc | 132 ---------- src/eckit/geometry/iterator/Regular.cc | 75 ++++++ .../geometry/iterator/{ListI.h => Regular.h} | 21 +- src/eckit/geometry/iterator/Unstructured.cc | 71 +++++ .../{ReducedIListJ.h => Unstructured.h} | 37 +-- src/eckit/geometry/range/Gaussian.cc | 84 ++++++ .../{grid/ReducedLL.h => range/Gaussian.h} | 36 +-- src/eckit/geometry/range/GlobalRegular.cc | 43 ++++ .../GlobalRegular.h} | 26 +- src/eckit/geometry/range/LocalRegular.cc | 40 +++ src/eckit/geometry/range/LocalRegular.h | 80 ++++++ src/tools/eckit-grid.cc | 2 +- 57 files changed, 1784 insertions(+), 2666 deletions(-) delete mode 100644 src/eckit/geometry/grid/Gaussian.cc delete mode 100644 src/eckit/geometry/grid/GaussianIterator.cc delete mode 100644 src/eckit/geometry/grid/GaussianIterator.h delete mode 100644 src/eckit/geometry/grid/HEALPix.cc delete mode 100644 src/eckit/geometry/grid/HEALPix.h delete mode 100644 src/eckit/geometry/grid/IrregularLatlon.cc create mode 100644 src/eckit/geometry/grid/Reduced.cc rename src/eckit/geometry/grid/{Gaussian.h => Reduced.h} (64%) delete mode 100644 src/eckit/geometry/grid/ReducedGG.cc delete mode 100644 src/eckit/geometry/grid/ReducedLL.cc delete mode 100644 src/eckit/geometry/grid/RegularGG.cc delete mode 100644 src/eckit/geometry/grid/RegularGrid.cc delete mode 100644 src/eckit/geometry/grid/RegularGrid.h create mode 100644 src/eckit/geometry/grid/Unstructured.cc rename src/eckit/geometry/grid/{ReducedGG.h => Unstructured.h} (70%) delete mode 100644 src/eckit/geometry/grid/UnstructuredGrid.cc create mode 100644 src/eckit/geometry/grid/reduced/HEALPix.cc rename src/eckit/geometry/grid/{UnstructuredGrid.h => reduced/HEALPix.h} (62%) create mode 100644 src/eckit/geometry/grid/reduced/ReducedGaussian.cc create mode 100644 src/eckit/geometry/grid/reduced/ReducedGaussian.h create mode 100644 src/eckit/geometry/grid/reduced/ReducedLatLon.cc rename src/eckit/geometry/grid/{RegularGG.h => reduced/ReducedLatLon.h} (60%) create mode 100644 src/eckit/geometry/grid/regular/IrregularLatLon.cc create mode 100644 src/eckit/geometry/grid/regular/IrregularLatLon.h create mode 100644 src/eckit/geometry/grid/regular/RegularGaussian.cc create mode 100644 src/eckit/geometry/grid/regular/RegularGaussian.h create mode 100644 src/eckit/geometry/grid/regular/RegularLatLon.cc create mode 100644 src/eckit/geometry/grid/regular/RegularLatLon.h rename src/eckit/geometry/grid/{ => unstructured}/ORCA.cc (80%) rename src/eckit/geometry/grid/{ => unstructured}/ORCA.h (73%) delete mode 100644 src/eckit/geometry/iterator/ListI.cc delete mode 100644 src/eckit/geometry/iterator/ListIListJ.cc create mode 100644 src/eckit/geometry/iterator/Reduced.cc rename src/eckit/geometry/iterator/{ListIListJ.h => Reduced.h} (73%) delete mode 100644 src/eckit/geometry/iterator/ReducedIListJ.cc create mode 100644 src/eckit/geometry/iterator/Regular.cc rename src/eckit/geometry/iterator/{ListI.h => Regular.h} (80%) create mode 100644 src/eckit/geometry/iterator/Unstructured.cc rename src/eckit/geometry/iterator/{ReducedIListJ.h => Unstructured.h} (67%) create mode 100644 src/eckit/geometry/range/Gaussian.cc rename src/eckit/geometry/{grid/ReducedLL.h => range/Gaussian.h} (64%) create mode 100644 src/eckit/geometry/range/GlobalRegular.cc rename src/eckit/geometry/{grid/IrregularLatlon.h => range/GlobalRegular.h} (70%) create mode 100644 src/eckit/geometry/range/LocalRegular.cc create mode 100644 src/eckit/geometry/range/LocalRegular.h diff --git a/src/eckit/geometry/Area.h b/src/eckit/geometry/Area.h index 29bffc36e..21555298d 100644 --- a/src/eckit/geometry/Area.h +++ b/src/eckit/geometry/Area.h @@ -104,10 +104,10 @@ class Area { }; -using AreaFactory = Factory; +// using AreaFactory = Factory; -template -using AreaBuilder = ConcreteBuilderT1; +// template +// using AreaBuilder = ConcreteBuilderT1; } // namespace eckit::geometry diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index 947d013f7..cba479256 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -50,34 +50,32 @@ list( APPEND eckit_geometry_srcs UnitSphere.h area/BoundingBox.cc area/BoundingBox.h - grid/Gaussian.cc - grid/Gaussian.h - grid/GaussianIterator.cc - grid/GaussianIterator.h - grid/HEALPix.cc - grid/HEALPix.h - grid/IrregularLatlon.cc - grid/IrregularLatlon.h - grid/ORCA.cc - grid/ORCA.h - grid/ReducedGG.cc - grid/ReducedGG.h - grid/ReducedLL.cc - grid/ReducedLL.h + grid/Reduced.cc + grid/Reduced.h grid/Regular.cc grid/Regular.h - grid/RegularGG.cc - grid/RegularGG.h - grid/RegularGrid.cc - grid/RegularGrid.h - grid/UnstructuredGrid.cc - grid/UnstructuredGrid.h - iterator/ListI.cc - iterator/ListI.h - iterator/ListIListJ.cc - iterator/ListIListJ.h - iterator/ReducedIListJ.cc - iterator/ReducedIListJ.h + grid/Unstructured.cc + grid/Unstructured.h + grid/reduced/HEALPix.cc + grid/reduced/HEALPix.h + grid/reduced/ReducedGaussian.cc + grid/reduced/ReducedGaussian.h + grid/reduced/ReducedLatLon.cc + grid/reduced/ReducedLatLon.h + grid/regular/IrregularLatLon.cc + grid/regular/IrregularLatLon.h + grid/regular/RegularGaussian.cc + grid/regular/RegularGaussian.h + grid/regular/RegularLatLon.cc + grid/regular/RegularLatLon.h + grid/unstructured/ORCA.cc + grid/unstructured/ORCA.h + iterator/Reduced.cc + iterator/Reduced.h + iterator/Regular.cc + iterator/Regular.h + iterator/Unstructured.cc + iterator/Unstructured.h polygon/LonLatPolygon.cc polygon/LonLatPolygon.h polygon/Polygon.cc @@ -88,6 +86,12 @@ list( APPEND eckit_geometry_srcs projection/None.h projection/Rotation.cc projection/Rotation.h + range/Gaussian.cc + range/Gaussian.h + range/GlobalRegular.cc + range/GlobalRegular.h + range/LocalRegular.cc + range/LocalRegular.h util.cc util.h util/arange.cc @@ -124,4 +128,3 @@ ecbuild_add_library( SOURCES ${eckit_geometry_srcs} ) - diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geometry/Grid.cc index 17f8e343a..2d3b1f224 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geometry/Grid.cc @@ -49,6 +49,11 @@ size_t Grid::size() const { } +Grid::uid_t Grid::uid() const { + throw NotImplemented("Grid::uid", Here()); +} + + bool Grid::includesNorthPole() const { throw NotImplemented("Grid::includesNorthPole", Here()); } diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geometry/Grid.h index 0b7ab74df..860cd064c 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geometry/Grid.h @@ -43,6 +43,7 @@ class Grid { public: // -- Types + using uid_t = std::string; using builder_t = BuilderT1; using ARG1 = const Configuration&; @@ -111,6 +112,7 @@ class Grid { void boundingBox(const area::BoundingBox&); virtual size_t size() const; + virtual uid_t uid() const; virtual bool includesNorthPole() const; virtual bool includesSouthPole() const; diff --git a/src/eckit/geometry/Point3.cc b/src/eckit/geometry/Point3.cc index 44dee0493..4b1469d2e 100644 --- a/src/eckit/geometry/Point3.cc +++ b/src/eckit/geometry/Point3.cc @@ -20,10 +20,7 @@ namespace eckit::geometry { bool points_equal(const Point3& a, const Point3& b) { auto eps = 1e-6; - return types::is_approximately_equal(a.X, b.X, eps) && - types::is_approximately_equal(a.Y, b.Y, eps) && - types::is_approximately_equal(a.Z, b.Z, eps); - + return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps) && types::is_approximately_equal(a.Z, b.Z, eps); } bool operator<(const Point3& a, const Point3& b) { diff --git a/src/eckit/geometry/PointLonLat.cc b/src/eckit/geometry/PointLonLat.cc index b68b8196c..c35153efc 100644 --- a/src/eckit/geometry/PointLonLat.cc +++ b/src/eckit/geometry/PointLonLat.cc @@ -44,11 +44,10 @@ bool points_equal(const PointLonLat& a, const PointLonLat& b) { // FIXME // solved {180., 0.} == {-180., 0.} // could be more performant - auto c = PointLonLat::make(a.lon, a.lat); - auto d = PointLonLat::make(b.lon, b.lat); + auto c = PointLonLat::make(a.lon, a.lat); + auto d = PointLonLat::make(b.lon, b.lat); auto eps = 1e-6; - return types::is_approximately_equal(c.lon, d.lon, eps) && - types::is_approximately_equal(c.lat, d.lat, eps); + return types::is_approximately_equal(c.lon, d.lon, eps) && types::is_approximately_equal(c.lat, d.lat, eps); } diff --git a/src/eckit/geometry/PointLonLat.h b/src/eckit/geometry/PointLonLat.h index c6499b09f..2cf4917b4 100644 --- a/src/eckit/geometry/PointLonLat.h +++ b/src/eckit/geometry/PointLonLat.h @@ -83,7 +83,6 @@ class PointLonLat final : protected std::array { static PointLonLat make(double lon, double lat, double lon_minimum = 0) { lat = normalise_angle_to_minimum(lat, -90.); - // FIXME problems with lat << -90 and lat >> 90 if (lat > 90.) { lat = 180. - lat; lon += 180.; diff --git a/src/eckit/geometry/Range.cc b/src/eckit/geometry/Range.cc index 54e1479e9..9aad25c99 100644 --- a/src/eckit/geometry/Range.cc +++ b/src/eckit/geometry/Range.cc @@ -12,95 +12,21 @@ #include "eckit/geometry/Range.h" +#include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" -#include "eckit/types/FloatCompare.h" - - -namespace eckit::geometry::util { -std::vector arange(double start, double stop, double step); -} namespace eckit::geometry { -static Fraction adjust(const Fraction& target, const Fraction& inc, bool up) { - ASSERT(inc > 0); - - auto r = target / inc; - auto n = r.integralPart(); - - if (!r.integer() && (r > 0) == up) { - n += (up ? 1 : -1); - } - - return (n * inc); -} - - -Range::Range(double _a, double _b, double _inc, double _ref, double period) : - Range(_a, _b, _inc, _ref) { - ASSERT(0 < period); - - if ((n_ - 1) * inc_ >= period) { - n_ -= 1; - ASSERT(n_ * inc_ == period || (n_ - 1) * inc_ < period); - - b_ = a_ + (n_ - 1) * inc_; - } -} - - -Range::Range(double _a, double _b, double _inc, double _ref) { - ASSERT(0 <= _inc); - - if (types::is_approximately_equal(_inc, 0.) || types::is_approximately_equal(_a, _b)) { - a_ = b_ = _ref; - n_ = 1; - inc_ = Fraction{0}; - return; - } - - ASSERT(_a <= _b); // FIXME remove - - inc_ = Fraction{_inc}; - - const Fraction a(_a); - const Fraction b(_b); - const Fraction ref(_ref); - - auto shift = (ref / inc_).decimalPart() * inc_; - a_ = shift + adjust(a - shift, inc_, true); - - auto c = shift + adjust(b - shift, inc_, false); - c = a_ + ((c - a_) / inc_).integralPart() * inc_; - b_ = c < a_ ? a_ : c; - - n_ = static_cast(((b_ - a_) / inc_).integralPart() + 1); - - ASSERT(a_ <= b_); - ASSERT(1 <= n_); +Range::Range(const Configuration& config) : + Range(config.getUnsigned("n")) { } -std::vector Range::to_vector() const { - if (inc_ == 0) { - std::vector l(1, a_); - return l; - } - - double step = inc_; - - const auto num = static_cast((b_ - a_) / step) + 1; - - std::vector l(num); - std::generate_n(l.begin(), num, [this, n = 0]() mutable { - auto delta_num = static_cast(n++) * inc_.numerator(); - auto delta_den = inc_.denominator(); - return a_ + static_cast(delta_num) / static_cast(delta_den); - }); - - return l; +Range::Range(size_t n) : + n_(n) { + ASSERT(n > 0); } diff --git a/src/eckit/geometry/Range.h b/src/eckit/geometry/Range.h index ee4e3cf22..0bd892e3a 100644 --- a/src/eckit/geometry/Range.h +++ b/src/eckit/geometry/Range.h @@ -12,29 +12,35 @@ #pragma once +#include #include -#include "eckit/types/Fraction.h" +#include "eckit/memory/Builder.h" +#include "eckit/memory/Factory.h" + + +namespace eckit { +class Configuration; +} namespace eckit::geometry { -class Range { +class Range : protected std::vector { public: // -- Types - // None + + using builder_t = BuilderT1; + using ARG1 = const Configuration&; // -- Exceptions // None // -- Constructors - Range(double a, double b, double inc, double ref, double period); - Range(double a, double b, double inc, double ref); - - Range(const Range&) = delete; - Range(Range&&) = delete; + Range(const Range&) = default; + Range(Range&&) = default; // -- Destructor @@ -45,16 +51,17 @@ class Range { // -- Operators - Range& operator=(const Range&) = delete; - Range& operator=(Range&&) = delete; + Range& operator=(const Range&) = default; + Range& operator=(Range&&) = default; // -- Methods - size_t n() const { return n_; } - double a() const { return a_; } - double b() const { return b_; } + static std::string className() { return "range"; } + + bool empty() const { return vector::empty(); } + size_t size() const { return empty() ? n_ : vector::size(); } - std::vector to_vector() const; + virtual const std::vector& values() const = 0; // -- Overridden methods // None @@ -66,11 +73,19 @@ class Range { // None protected: + // -- Constructors + + explicit Range(const Configuration&); + explicit Range(size_t n); + // -- Members // None // -- Methods - // None + + virtual const std::vector& valuesVector() const { + return *this; + } // -- Overridden methods // None @@ -84,10 +99,7 @@ class Range { private: // -- Members - size_t n_; - double a_; - double b_; - Fraction inc_; + const size_t n_; // -- Methods // None @@ -106,4 +118,10 @@ class Range { }; +// using RangeFactory = Factory; + +// template +// using RangeBuilder = ConcreteBuilderT1; + + } // namespace eckit::geometry diff --git a/src/eckit/geometry/grid/Gaussian.cc b/src/eckit/geometry/grid/Gaussian.cc deleted file mode 100644 index 74a7296c9..000000000 --- a/src/eckit/geometry/grid/Gaussian.cc +++ /dev/null @@ -1,122 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/grid/Gaussian.h" - -#include -#include -#include - -#include "eckit/config/Configuration.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Domain.h" -#include "eckit/geometry/util.h" -#include "eckit/types/FloatCompare.h" - - -namespace eckit::geometry::grid { - - -Gaussian::Gaussian(size_t N, const area::BoundingBox& bbox) : - Grid(bbox), N_(N), angularPrecision_(0) { - ASSERT(N_ > 0); -} - - -Gaussian::Gaussian(const Configuration& config) : - Grid(config), N_(config.getUnsigned("N")), angularPrecision_(config.getDouble("angular_precision", 0)) { - ASSERT(N_ > 0); - ASSERT(angularPrecision_ >= 0); -} - - -const std::vector& Gaussian::latitudes() const { - return latitudes_.empty() ? (latitudes_ = util::gaussian_latitudes(N_, false)) : latitudes_; -} - - -Gaussian::~Gaussian() = default; - - -bool Gaussian::includesNorthPole() const { - return bbox().north() >= latitudes().front(); -} - - -bool Gaussian::includesSouthPole() const { - return bbox().south() <= latitudes().back(); -} - - -bool Gaussian::angleApproximatelyEqual(const double& A, const double& B) const { - return angularPrecision_ > 0 ? types::is_approximately_equal(A, B, angularPrecision_) - : A == B; -} - - -void Gaussian::correctSouthNorth(double& s, double& n, bool in) const { - ASSERT(s <= n); - - const std::vector& lats = latitudes(); - ASSERT(!lats.empty()); - - const bool same(s == n); - if (n < lats.back()) { - n = lats.back(); - } - else if (in) { - auto best = std::lower_bound(lats.begin(), lats.end(), n, [this](double l1, double l2) { - if (angleApproximatelyEqual(l1, l2)) { - return false; - } - return !(l1 < l2); - }); - ASSERT(best != lats.end()); - n = *best; - } - else if (n > lats.front()) { - // extend 'outwards': don't change, it's already above the Gaussian latitudes - } - else { - auto best = std::lower_bound(lats.rbegin(), lats.rend(), n); - n = *best; - } - - if (same && in) { - s = n; - } - else if (s > lats.front()) { - s = lats.front(); - } - else if (in) { - auto best = std::lower_bound(lats.rbegin(), lats.rend(), s, [this](double l1, double l2) { - if (angleApproximatelyEqual(l1, l2)) { - return false; - } - return !(l1 > l2); - }); - ASSERT(best != lats.rend()); - s = *best; - } - else if (s < lats.back()) { - // extend 'outwards': don't change, it's already below the Gaussian latitudes - } - else { - auto best = std::lower_bound(lats.begin(), lats.end(), s, [](double l1, double l2) { return l1 > l2; }); - s = *best; - } - - ASSERT(s <= n); -} - - -} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/GaussianIterator.cc b/src/eckit/geometry/grid/GaussianIterator.cc deleted file mode 100644 index 27ead3a63..000000000 --- a/src/eckit/geometry/grid/GaussianIterator.cc +++ /dev/null @@ -1,112 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/grid/GaussianIterator.h" - -#if 0 -#include "eckit/exception/Exceptions.h" -#endif - - -namespace eckit::geometry::grid { - - -#if 0 -GaussianIterator::GaussianIterator(const std::vector& latitudes, std::vector&& pl, - const area::BoundingBox& bbox, size_t N, size_t Nj, size_t k) : - latitudes_(latitudes), - pl_(pl), - bbox_(bbox), - N_(N), - Ni_(0), - Nj_(Nj), - i_(0), - j_(0), - k_(k), - count_(0), - first_(true) { - - // NOTE: latitudes_ span the globe, sorted from North-to-South, k_ positions the North - // NOTE: pl is global - ASSERT(N_ * 2 == latitudes_.size()); - ASSERT(Nj_ > 0); -} - - -GaussianIterator::~GaussianIterator() = default; - - -size_t GaussianIterator::resetToRow(size_t j) { - ASSERT(j < latitudes_.size()); - lat_ = latitudes_[j]; - - auto Ni_globe = pl_[j]; - ASSERT(Ni_globe > 1); - - inc_ = Fraction(GLOBE) / Ni_globe; - - const auto w = Fraction(bbox_.west()); - auto Nw = (w / inc_).integralPart(); - if (Nw * inc_ < w) { - Nw += 1; - } - - const auto e = Fraction(bbox_.east()); - auto Ne = (e / inc_).integralPart(); - if (Ne * inc_ > e) { - Ne -= 1; - } - - lon_ = Nw * inc_; - return Nw > Ne ? 0 : std::min(size_t(Ni_globe), size_t(Ne - Nw + 1)); -} - - -bool GaussianIterator::operator++() { - while (Ni_ == 0 && j_ < Nj_) { - Ni_ = resetToRow(k_ + j_++); - } - - if (0 < Nj_ && i_ < Ni_) { - lon_ += inc_; - - if (first_) { - first_ = false; - } - else { - count_++; - } - - if (++i_ == Ni_) { - i_ = 0; - Ni_ = 0; - } - - return true; - } - - return false; -} - - -size_t GaussianIterator::index() const { - return count_; -} - - -size_t GaussianIterator::size() const { - NOTIMP; -} -#endif - - -} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/GaussianIterator.h b/src/eckit/geometry/grid/GaussianIterator.h deleted file mode 100644 index 5b4377641..000000000 --- a/src/eckit/geometry/grid/GaussianIterator.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include - -#if 0 -#include "eckit/types/Fraction.h" - -#include "eckit/geometry/Iterator.h" -#include "eckit/geometry/Projection.h" -#include "eckit/geometry/area/BoundingBox.h" -#endif - - -namespace eckit::geometry::grid { - - -#if 0 -class GaussianIterator : public Iterator { -public: - GaussianIterator(const std::vector& latitudes, std::vector&& pl, const area::BoundingBox&, size_t N, - size_t Nj, size_t k); - ~GaussianIterator() override; - -private: - const std::vector& latitudes_; - const std::vector pl_; - const area::BoundingBox& bbox_; - const size_t N_; - size_t Ni_; - size_t Nj_; - Fraction lon_; - Latitude lat_; - Fraction inc_; - size_t i_; - size_t j_; - size_t k_; - size_t count_; - bool first_; - - bool operator++() override; - size_t index() const override; - size_t size() const override; - - size_t resetToRow(size_t j); -}; -#endif - - -} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/HEALPix.cc b/src/eckit/geometry/grid/HEALPix.cc deleted file mode 100644 index e3ff6298e..000000000 --- a/src/eckit/geometry/grid/HEALPix.cc +++ /dev/null @@ -1,224 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/grid/HEALPix.h" - -#include -#include - -#include "eckit/config/MappedConfiguration.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/geometry/area/BoundingBox.h" -#include "eckit/geometry/util.h" -#include "eckit/utils/Translator.h" - - -namespace eckit::geometry::grid { - - -static Ordering ordering_from_string(const std::string& str) { - return str == "ring" ? Ordering::healpix_ring : str == "nested" ? Ordering::healpix_nested - : throw AssertionFailed("HEALPix::Ordering", Here()); -} - - -HEALPix::RingIterator::RingIterator(const Grid& grid, size_t index) : - geometry::Iterator(grid), - grid_(dynamic_cast(grid)), - index_(index), - index_size_(grid.size()) { - if (index_ < index_size_) { - ASSERT(2 <= grid_.njacc_.size()); - - longitudes_j_ = grid_.longitudes(j_ = j(index_)); - ASSERT(grid_.njacc_.at(j_) <= index && index_ < grid_.njacc_.at(j_ + 1)); - - grid_.latitudes(); - ASSERT(grid_.latitudes_.size() == grid_.ni()); - } -} - - -bool HEALPix::RingIterator::operator==(const Iterator& other) const { - const auto* another = dynamic_cast(&other); - return another != nullptr && index_ == another->index_; -} - - -bool HEALPix::RingIterator::operator++() { - if (index_++; index_ < index_size_) { - if (!(index_ < grid_.njacc_[j_ + 1])) { - longitudes_j_ = grid_.longitudes(++j_); - } - - ASSERT(grid_.njacc_[j_] <= index_ && index_ < grid_.njacc_[j_ + 1]); - return true; - } - - index_ = index_size_; // ensure it's invalid - return false; -} - - -bool HEALPix::RingIterator::operator+=(diff_t d) { - if (auto di = static_cast(index_); 0 <= di + d && di + d < static_cast(index_size_)) { - if (index_ = static_cast(di + d); !(grid_.njacc_[j_] <= index_ && index_ < grid_.njacc_[j_ + 1])) { - longitudes_j_ = grid_.longitudes(j_ = j(index_)); - } - - ASSERT(grid_.njacc_[j_] <= index_ && index_ < grid_.njacc_[j_ + 1]); - return true; - } - - index_ = index_size_; // ensure it's invalid - return false; -} - - -HEALPix::RingIterator::operator bool() const { - return index_ < index_size_; -} - - -Point HEALPix::RingIterator::operator*() const { - return PointLonLat{longitudes_j_.at(index_ - grid_.njacc_[j_]), grid_.latitudes_.at(j_)}; -} - - -size_t HEALPix::RingIterator::j(size_t index) const { - ASSERT(index < index_size_); - - const auto& njacc = grid_.njacc_; - auto dist = std::distance(njacc.begin(), std::upper_bound(njacc.begin(), njacc.end(), index)); - ASSERT(1 <= dist && dist <= njacc.size() - 1); - - return static_cast(dist - 1); -} - - -HEALPix::HEALPix(const Configuration& config) : - HEALPix(config.getUnsigned("Nside"), ordering_from_string(config.getString("orderingConvention", "ring"))) { -} - - -HEALPix::HEALPix(size_t Nside, Ordering ordering) : - Grid(area::BoundingBox::make_global_prime()), N_(Nside), ordering_(ordering) { - ASSERT(N_ > 0); - ASSERT(ordering_ == Ordering::healpix_ring); - - - // accumulated nj - njacc_.resize(1 + ni()); - njacc_.front() = 0; - - size_t i = 0; - for (auto j = njacc_.begin(), k = j + 1; k != njacc_.end(); ++i, ++j, ++k) { - *k = *j + nj(i); - } - - ASSERT(njacc_.back() == size()); -} - - -Configuration* HEALPix::config(const std::string& name) { - auto Nside = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "HEALPix"}, {"Nside", Nside}, {"orderingConvention", "ring"}}); -} - - -size_t HEALPix::ni() const { - return 4 * N_ - 1; -} - - -size_t HEALPix::nj(size_t i) const { - ASSERT(i < ni()); - return i < N_ ? 4 * (i + 1) : i < 3 * N_ ? 4 * N_ - : nj(ni() - 1 - i); -} - - -const std::vector& HEALPix::latitudes() const { - const auto Ni = ni(); - - if (latitudes_.empty()) { - latitudes_.resize(Ni); - - auto i = latitudes_.begin(); - auto j = latitudes_.rbegin(); - for (int ring = 1; ring < 2 * N_; ++ring, ++i, ++j) { - const auto f = ring < N_ ? 1. - static_cast(ring * ring) / (3 * static_cast(N_ * N_)) : 4. / 3. - 2 * static_cast(ring) / (3 * static_cast(N_)); - - *i = 90. - util::radian_to_degree * std::acos(f); - *j = -*i; - } - *i = 0.; - } - - ASSERT(latitudes_.size() == Ni); - return latitudes_; -} - - -std::vector HEALPix::longitudes(size_t ring) const { - const auto Nj = nj(ring); - const auto step = 360. / static_cast(Nj); - const auto start = ring < N_ || 3 * N_ - 1 < ring || static_cast((ring + N_) % 2) ? step / 2. : 0.; - - std::vector lons(Nj); - std::generate_n(lons.begin(), Nj, [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); - - return lons; -} - - -Grid::iterator HEALPix::cbegin() const { - return ordering_ == Ordering::healpix_ring ? iterator{new RingIterator(*this, 0)} : NOTIMP; -} - - -Grid::iterator HEALPix::cend() const { - return ordering_ == Ordering::healpix_ring ? iterator{new RingIterator(*this, size())} : NOTIMP; -} - - -const area::BoundingBox& HEALPix::boundingBox() const { - static const auto __bbox(area::BoundingBox::make_global_prime()); - return __bbox; -} - - -size_t HEALPix::size() const { - return 12 * N_ * N_; -} - - -std::pair, std::vector> HEALPix::to_latlon() const { - std::pair, std::vector> latlon; - latlon.first.reserve(size()); - latlon.second.reserve(size()); - - for (const auto& p : to_points()) { - const auto& q = std::get(p); - latlon.first.push_back(q.lat); - latlon.second.push_back(q.lon); - } - - return latlon; -} - - -static const GridRegisterType __grid_type("HEALPix"); -static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); - - -} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/HEALPix.h b/src/eckit/geometry/grid/HEALPix.h deleted file mode 100644 index 065687de4..000000000 --- a/src/eckit/geometry/grid/HEALPix.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include - -#include "eckit/geometry/Grid.h" - - -namespace eckit::geometry::grid { - - -class HEALPix final : public Grid { -public: - // -- Types - - class RingIterator final : public geometry::Iterator { - public: - explicit RingIterator(const Grid&, size_t index = 0); - - private: - bool operator==(const Iterator&) const override; - bool operator++() override; - bool operator+=(diff_t) override; - explicit operator bool() const override; - Point operator*() const override; - - size_t index() const override { return index_; } - size_t j(size_t index) const; - - const HEALPix& grid_; - std::vector longitudes_j_; - size_t j_; - size_t index_; - const size_t index_size_; - }; - - // -- Exceptions - // None - - // -- Constructors - - explicit HEALPix(const Configuration&); - explicit HEALPix(size_t Nside, Ordering = Ordering::healpix_ring); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - - static Configuration* config(const std::string& name); - - // -- Class methods - // None - -private: - // -- Members - - const size_t N_; - const Ordering ordering_; - - std::vector njacc_; - - mutable std::vector latitudes_; - - // -- Methods - - size_t ni() const; - size_t nj(size_t i) const; - - const std::vector& latitudes() const; - std::vector longitudes(size_t ring) const; - - // -- Overridden methods - - iterator cbegin() const override; - iterator cend() const override; - - const area::BoundingBox& boundingBox() const override; - - size_t size() const override; - - bool includesNorthPole() const override { return true; } - bool includesSouthPole() const override { return true; } - bool isPeriodicWestEast() const override { return true; } - - std::pair, std::vector> to_latlon() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - - friend class RingIterator; -}; - - -} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/IrregularLatlon.cc b/src/eckit/geometry/grid/IrregularLatlon.cc deleted file mode 100644 index 8dfcf8a92..000000000 --- a/src/eckit/geometry/grid/IrregularLatlon.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/grid/IrregularLatlon.h" - -#include - -#include "eckit/config/Configuration.h" -#include "eckit/geometry/area/BoundingBox.h" - - -namespace eckit::geometry::grid { - - -static void range(const std::vector& v, double& mn, double& mx) { - ASSERT(!v.empty()); - - mx = v[0]; - mn = v[0]; - for (size_t i = 1; i < v.size(); ++i) { - mx = std::max(v[i], mx); - mn = std::min(v[i], mn); - } -} - - -IrregularLatlon::IrregularLatlon(const Configuration& config) : - Grid(config) { - double south = 0; - double north = 0; - ASSERT(config.get("latitudes", latitudes_)); - range(latitudes_, south, north); - - double west = 0; - double east = 0; - ASSERT(config.get("longitudes", longitudes_)); - range(longitudes_, west, east); - - Grid::boundingBox({north, west, south, east}); -} - - -Grid::iterator IrregularLatlon::cbegin() const { - NOTIMP; -} - - -Grid::iterator IrregularLatlon::cend() const { - NOTIMP; -} - - -size_t IrregularLatlon::size() const { - return latitudes_.size() * longitudes_.size(); -} - - -static const GridRegisterType irregularLatlon("irregular_latlon"); - - -} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/Reduced.cc b/src/eckit/geometry/grid/Reduced.cc new file mode 100644 index 000000000..8f143dd3a --- /dev/null +++ b/src/eckit/geometry/grid/Reduced.cc @@ -0,0 +1,53 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/grid/Reduced.h" + +// #include <> + + +namespace eckit::geometry::grid { + + +size_t Reduced::size() const { + return niacc().back(); +} + + +Reduced::Reduced(const Configuration& config) : + Grid(config) { +} + + +Reduced::Reduced(const area::BoundingBox& bbox) : + Grid(bbox) { +} + + +const std::vector& Reduced::niacc() const { + if (niacc_.empty()) { + niacc_.resize(1 + nj()); + niacc_.front() = 0; + + size_t j = 0; + for (auto a = niacc_.begin(), b = a + 1; b != niacc_.end(); ++j, ++a, ++b) { + *b = *a + ni(j); + } + + ASSERT(niacc_.back() == size()); + } + + return niacc_; +} + + +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/Gaussian.h b/src/eckit/geometry/grid/Reduced.h similarity index 64% rename from src/eckit/geometry/grid/Gaussian.h rename to src/eckit/geometry/grid/Reduced.h index 2ab163bb2..72983165e 100644 --- a/src/eckit/geometry/grid/Gaussian.h +++ b/src/eckit/geometry/grid/Reduced.h @@ -15,22 +15,28 @@ #include "eckit/geometry/Grid.h" +namespace eckit::geometry::iterator { +class Reduced; +} + + namespace eckit::geometry::grid { -class Gaussian : public Grid { +class Reduced : public Grid { public: + // -- Types + // None + // -- Exceptions // None // -- Constructors - - Gaussian(size_t N, const area::BoundingBox& = {}); - Gaussian(const Configuration&); + // None // -- Destructor - ~Gaussian() override; + ~Reduced() override = default; // -- Convertors // None @@ -42,7 +48,8 @@ class Gaussian : public Grid { // None // -- Overridden methods - // None + + size_t size() const override; // -- Class members // None @@ -51,27 +58,26 @@ class Gaussian : public Grid { // None protected: - // -- Members + // -- Constructors - size_t N_; - double angularPrecision_; - mutable std::vector latitudes_; + explicit Reduced(const Configuration&); + explicit Reduced(const area::BoundingBox&); + + // -- Members + // None // -- Methods - const std::vector& latitudes() const; + const std::vector& niacc() const; - bool angleApproximatelyEqual(const double&, const double&) const; + virtual size_t ni(size_t j) const = 0; + virtual size_t nj() const = 0; - void correctSouthNorth(double& s, double& n, bool in = true) const; + virtual const std::vector& latitudes() const = 0; + virtual std::vector longitudes(size_t i) const = 0; // -- Overridden methods - - bool includesNorthPole() const override; - bool includesSouthPole() const override; - - iterator cbegin() const override { NOTIMP; } - iterator cend() const override { NOTIMP; } + // None // -- Class members // None @@ -81,7 +87,8 @@ class Gaussian : public Grid { private: // -- Members - // None + + mutable std::vector niacc_; // -- Methods // None @@ -96,7 +103,8 @@ class Gaussian : public Grid { // None // -- Friends - // None + + friend class ::eckit::geometry::iterator::Reduced; }; diff --git a/src/eckit/geometry/grid/ReducedGG.cc b/src/eckit/geometry/grid/ReducedGG.cc deleted file mode 100644 index e49225481..000000000 --- a/src/eckit/geometry/grid/ReducedGG.cc +++ /dev/null @@ -1,194 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/grid/ReducedGG.h" - -#include -#include -#include -#include - -#include "eckit/config/MappedConfiguration.h" -#include "eckit/geometry/Projection.h" -#include "eckit/geometry/grid/GaussianIterator.h" -#include "eckit/types/Fraction.h" -#include "eckit/utils/Translator.h" - - -namespace eckit::geometry::grid { - - -static Fraction smallest_increment(const pl_type& pl) { - auto maxpl = *std::max_element(pl.begin(), pl.end()); - ASSERT(maxpl >= 2); - return Fraction(GLOBE) / maxpl; -} - - -ReducedGG::ReducedGG(const Configuration& config) : - ReducedGG(config.getUnsigned("N"), config.getLongVector("pl")) {} - - -ReducedGG::ReducedGG(size_t N, const pl_type& pl) : - Gaussian(N), pl_(pl), k_(0), Nj_(N_ * 2) { - // adjust latitudes, longitudes and re-set bounding box - auto n = bbox().north(); - auto s = bbox().south(); - correctSouthNorth(s, n); - - const auto& lats = latitudes(); - - // check internal assumptions - ASSERT(pl_.size() == N_ * 2); - ASSERT(pl_.size() >= k_ + Nj_); - ASSERT(Nj_ > 0); - - // set-up North/South - ASSERT(0 < N_ && N_ * 2 == pl_.size()); - - // position to first latitude and first/last longitude - // NOTE: latitudes() spans the globe, sorted from North-to-South, k_ positions the North - // NOTE: pl spans the globe - k_ = 0; - Nj_ = N_ * 2; - - if (n < lats.front() || s > lats.back()) { - Nj_ = 0; - for (const auto& lat : lats) { - Latitude ll(lat); - if (n < ll && !angleApproximatelyEqual(n, ll)) { - ++k_; - } - else if (s < ll || angleApproximatelyEqual(s, ll)) { - ASSERT(pl_[k_ + Nj_] >= 2); - ++Nj_; - } - else { - break; - } - } - } - - - // correct West/East - auto w = bbox().west(); - auto e = bbox().east(); - ASSERT(w <= e); - - const Fraction inc = smallest_increment(pl_); - ASSERT(inc > 0); - - if (angleApproximatelyEqual(GREENWICH, w) && (angleApproximatelyEqual(GLOBE - inc, e - w) || GLOBE - inc < e - w || (e != w && PointLonLat::normalise_angle_to_minimum(e, w) == w))) { - w = GREENWICH; - e = GLOBE - inc; - } - else { - const Fraction west{w}; - const Fraction east{e}; - Fraction W = west; - Fraction E = east; - - bool first = true; - std::set NiTried; - - for (size_t j = k_; j < k_ + Nj_; ++j) { - - // crop longitude-wise, track distinct attempts - const long Ni(pl_[j]); - ASSERT(Ni >= 2); - if (NiTried.insert(Ni).second) { - Fraction inc = Fraction{GLOBE} / Ni; - - auto Nw = (west / inc).integralPart(); - if (Nw * inc < west) { - Nw += 1; - } - - auto Ne = (east / inc).integralPart(); - if (Ne * inc > east || Nw + Ne == Ni) { - Ne -= 1; - } - - if (Nw <= Ne) { - ASSERT(w <= Longitude(Nw * inc)); - ASSERT(Longitude(Ne * inc) <= e); - - if (W > static_cast(Nw * inc) || first) { - W = Nw * inc; - } - if (E < static_cast(Ne * inc) || first) { - E = Ne * inc; - } - first = false; - } - } - } - - ASSERT(!first); - ASSERT(W <= E); - w = W; - e = E; - } - - - // bounding box - bbox({n, w, s, e}); - - - // accumulated pl - placc_.resize(1 + pl_.size()); - placc_.front() = 0; - - auto i = pl_.begin(); - for (auto j = placc_.begin(), k = j + 1; k != placc_.end(); ++i, ++j, ++k) { - *k = *i + *j; - } -} - - -size_t ReducedGG::size() const { - return static_cast(placc_.back()); -} - - -bool ReducedGG::isPeriodicWestEast() const { - auto inc = smallest_increment(pl_); - return bbox().east() - bbox().west() + inc >= GLOBE; -} - - -struct ReducedGGClassical { - static Configuration* config(const std::string& name) { - auto N = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "reduced_gg"}, - {"N", N}, - {"pl", util::reduced_classical_pl(N)}}); - } -}; - - -struct ReducedGGOctahedral { - static Configuration* config(const std::string& name) { - auto N = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "reduced_gg"}, - {"N", N}, - {"pl", util::reduced_octahedral_pl(N)}}); - } -}; - - -static const GridRegisterType __grid_type("reduced_gg"); -static const GridRegisterName __grid_pattern_1("[nN][1-9][0-9]*"); -static const GridRegisterName __grid_pattern_2("[oO][1-9][0-9]*"); - - -} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/ReducedLL.cc b/src/eckit/geometry/grid/ReducedLL.cc deleted file mode 100644 index 29585121c..000000000 --- a/src/eckit/geometry/grid/ReducedLL.cc +++ /dev/null @@ -1,83 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/grid/ReducedLL.h" - -#include -#include -#include - -#include "eckit/config/Configuration.h" -#include "eckit/geometry/Domain.h" -#include "eckit/geometry/Projection.h" -#include "eckit/types/FloatCompare.h" -#include "eckit/types/Fraction.h" - - -namespace eckit::geometry::grid { - - -static bool checkPl(const std::vector& pl) { - ASSERT(!pl.empty()); - return *std::min_element(pl.begin(), pl.end()) >= 2; -} - - -ReducedLL::ReducedLL(const Configuration& config) : - Grid(config) { - ASSERT(config.get("pl", pl_)); - checkPl(pl_); - - size_t Nj = 0; - ASSERT(config.get("Nj", Nj)); - ASSERT(Nj == pl_.size()); -} - - -ReducedLL::~ReducedLL() = default; - - -size_t ReducedLL::size() const { - size_t total = 0; - for (const auto& j : pl_) { - total += size_t(j); - } - return total; -} - - -bool ReducedLL::isPeriodicWestEast() const { - ASSERT(!pl_.empty()); - - auto maxpl = *std::max_element(pl_.begin(), pl_.end()); - ASSERT(maxpl >= 2); - - // if range West-East is within one increment (or greater than) 360 degree - const Fraction inc(360, maxpl); - return bbox().east() - bbox().west() + inc >= GLOBE; -} - - -bool ReducedLL::includesNorthPole() const { - return bbox().north() == NORTH_POLE; -} - - -bool ReducedLL::includesSouthPole() const { - return bbox().south() == SOUTH_POLE; -} - - -static const GridRegisterType reducedLL("reduced_ll"); - - -} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/Regular.cc b/src/eckit/geometry/grid/Regular.cc index c923ed295..9861105c6 100644 --- a/src/eckit/geometry/grid/Regular.cc +++ b/src/eckit/geometry/grid/Regular.cc @@ -12,253 +12,20 @@ #include "eckit/geometry/grid/Regular.h" -#include -#include -#include -#include -#include - -#include "eckit/config/MappedConfiguration.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Point.h" -#include "eckit/geometry/Projection.h" -#include "eckit/geometry/grid/Regular.h" -#include "eckit/geometry/util.h" -#include "eckit/geometry/util/regex.h" -#include "eckit/types/Fraction.h" -#include "eckit/utils/Translator.h" +// #include <> namespace eckit::geometry::grid { -namespace detail { - - -class RegularIterator { -public: - RegularIterator(const Fraction& a, const Fraction& b, const Fraction& inc, const Fraction& ref); - RegularIterator(const Fraction& a, const Fraction& b, const Fraction& inc, const Fraction& ref, const Fraction& period); - - static Fraction adjust(const Fraction& target, const Fraction& inc, bool up) { - ASSERT(inc > 0); - - auto r = target / inc; - auto n = r.integralPart(); - - if (!r.integer() && (r > 0) == up) { - n += (up ? 1 : -1); - } - - return (n * inc); - } - - const Fraction& a() const { return a_; } - const Fraction& b() const { return b_; } - const Fraction& inc() const { return inc_; } - size_t n() const { return n_; } - -private: - Fraction a_; - Fraction b_; - Fraction inc_; - size_t n_; -}; - - -RegularIterator::RegularIterator(const Fraction& a, const Fraction& b, const Fraction& inc, - const Fraction& ref) : - inc_(inc) { - ASSERT(a <= b); - ASSERT(inc >= 0); - - if (inc_ == 0) { - - b_ = a_ = a; - n_ = 1; - } - else { - - auto shift = (ref / inc_).decimalPart() * inc; - a_ = shift + adjust(a - shift, inc_, true); - - if (b == a) { - b_ = a_; - } - else { - - auto c = shift + adjust(b - shift, inc_, false); - c = a_ + ((c - a_) / inc_).integralPart() * inc_; - b_ = c < a_ ? a_ : c; - } - - n_ = size_t(((b_ - a_) / inc_).integralPart() + 1); - } - ASSERT(a_ <= b_); - ASSERT(n_ >= 1); -} - - -RegularIterator::RegularIterator(const Fraction& a, const Fraction& b, const Fraction& inc, - const Fraction& ref, const Fraction& period) : - RegularIterator(a, b, inc, ref) { - ASSERT(period > 0); - - if ((n_ - 1) * inc_ >= period) { - n_ -= 1; - ASSERT(n_ * inc_ == period || (n_ - 1) * inc_ < period); - - b_ = a_ + (n_ - 1) * inc_; - } -} - - -} // namespace detail - - -Regular::Increments::Increments(const Configuration& config) : - Increments(config.getDouble("west_east_increment"), config.getDouble("south_north_increment")) { -} - - Regular::Regular(const Configuration& config) : - Grid(config), increments_(config), reference_(bbox().south(), bbox().west()), ni_(0), nj_(0) { - bbox(correctBoundingBox(bbox(), ni_, nj_, increments_, reference_)); - ASSERT(ni_ != 0); - ASSERT(nj_ != 0); - - // confirm Ni/Nj from config (input) - size_t ni = 0; - size_t nj = 0; - ASSERT(config.get("ni", ni)); - ASSERT(config.get("nj", nj)); - - ASSERT(ni == ni_); - ASSERT(nj == nj_); -} - - -Regular::Regular(const Increments& increments, const area::BoundingBox& bb, const PointLonLat& reference) : - Grid(bb), increments_(increments), reference_(reference), ni_(0), nj_(0) { - bbox(correctBoundingBox(bbox(), ni_, nj_, increments_, reference_)); - ASSERT(ni_ != 0); - ASSERT(nj_ != 0); -} - - -bool Regular::isPeriodicWestEast() const { - // if range West-East is within one increment (or greater than) 360 degree - return bbox().east() - bbox().west() + increments_.west_east >= GLOBE; -} - - -bool Regular::includesNorthPole() const { - // if North latitude is within one increment from North Pole - return bbox().north() + increments_.south_north > NORTH_POLE; -} - - -bool Regular::includesSouthPole() const { - // if South latitude is within one increment from South Pole - return bbox().south() - increments_.south_north < SOUTH_POLE; -} - - -size_t Regular::size() const { - ASSERT(0 < ni_); - ASSERT(0 < nj_); - return ni_ * nj_; -} - - -std::pair, std::vector> Regular::to_latlon() const { - auto [n, w, s, e] = bbox().deconstruct(); - auto [we, sn] = increments_.deconstruct(); - - auto longitudes = util::arange(w, e, we); - ASSERT(longitudes.size() == ni_); - - auto latitudes = util::arange(n, s, -sn); - ASSERT(latitudes.size() == nj_); - - std::pair, std::vector> latlon; - latlon.first.reserve(size()); - latlon.second.reserve(size()); - - for (const auto lat : latitudes) { - for (const auto lon : longitudes) { - latlon.first.push_back(lat); - latlon.second.push_back(lon); - } - } - - return latlon; -} - - -area::BoundingBox Regular::correctBoundingBox(const area::BoundingBox& box, size_t& ni, size_t& nj, const Increments& inc, - const PointLonLat& reference) { - // Latitude/longitude ranges - detail::RegularIterator lat{Fraction{box.south()}, - Fraction{box.north()}, - Fraction{inc.south_north}, - Fraction{reference.lat}}; - auto n = lat.b(); - auto s = lat.a(); - - nj = lat.n(); - ASSERT(nj > 0); - - detail::RegularIterator lon{Fraction{box.west()}, - Fraction{box.east()}, - Fraction{inc.west_east}, - Fraction{reference.lon}, - Fraction{GLOBE}}; - auto w = lon.a(); - auto e = lon.b(); - - ni = lon.n(); - ASSERT(ni > 0); - - // checks - ASSERT(w + (ni - 1) * lon.inc() == e || ni * lon.inc() == GLOBE); - ASSERT(s + (nj - 1) * lat.inc() == n); - - return {n, w, s, e}; + Grid(config) { } -static const GridRegisterType __grid_type("regular_ll"); - - -#define POSITIVE_REAL "[+]?([0-9]*[.])?[0-9]+([eE][-+][0-9]+)?" - - -Configuration* Regular::config(const std::string& name) { - static const std::string pattern("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); - - auto match = util::regex_match(pattern, name); - ASSERT(match); - ASSERT(match.size() == 7); // because of sub-matches - - auto d = Translator{}; - std::vector increments{d(match[1]), d(match[4])}; - - auto ni = detail::RegularIterator(Fraction(0), Fraction(360), Fraction(increments[0]), Fraction(0), Fraction(360)).n(); - auto nj = detail::RegularIterator(Fraction(-90), Fraction(90), Fraction(increments[1]), Fraction(0)).n(); - - return new MappedConfiguration({{"type", "regular_ll"}, - {"west_east_increment", increments[0]}, - {"south_north_increment", increments[1]}, - {"ni", ni}, - {"nj", nj}}); +Regular::Regular(const area::BoundingBox& bbox) : + Grid(bbox) { } -static const GridRegisterName __grid_pattern(POSITIVE_REAL "/" POSITIVE_REAL); - - -#undef POSITIVE_REAL - - } // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/Regular.h b/src/eckit/geometry/grid/Regular.h index 2fa1a5156..39fcf00e4 100644 --- a/src/eckit/geometry/grid/Regular.h +++ b/src/eckit/geometry/grid/Regular.h @@ -13,11 +13,10 @@ #pragma once #include "eckit/geometry/Grid.h" -#include "eckit/geometry/Point.h" -namespace eckit { -class Configuration; +namespace eckit::geometry::iterator { +class Regular; } @@ -27,64 +26,52 @@ namespace eckit::geometry::grid { class Regular : public Grid { public: // -- Types + // None -#if 0 - struct Increments { - template , int> = 0> - explicit Increments(const Configuration& config) : - P(config.getDouble("west_east_increment"), config.getDouble("south_north_increment")) { - } - - template , int> = 0> - explicit Increments(const Configuration& config) : - P(config.getDouble("dx"), config.getDouble("dy")) { - } + // -- Exceptions + // None - std::array deconstruct() const { return {P::operator[](0), P::operator[](0)}; } + // -- Constructors + // None - const P point_; - }; -#else - struct Increments : protected std::array { - using P = std::array; + // -- Destructor - Increments(double west_east, double south_north) : - P{west_east, south_north} {}; + ~Regular() override = default; - explicit Increments(const Configuration& config); + // -- Convertors + // None - double& west_east = P::operator[](0); - double& south_north = P::operator[](1); + // -- Operators + // None - std::array deconstruct() const { return {west_east, south_north}; } - }; -#endif + // -- Methods - // -- Exceptions - // None + virtual size_t ni() const = 0; + virtual size_t nj() const = 0; - // -- Constructors + // -- Overridden methods - explicit Regular(const Configuration&); - explicit Regular(const Increments&, const area::BoundingBox& = {}, const PointLonLat& reference = {0, 0}); + size_t size() const override { return ni() * nj(); } - // -- Destructor + // -- Class members // None - // -- Convertors + // -- Class methods // None - // -- Operators +protected: + // -- Constructors + + explicit Regular(const Configuration&); + explicit Regular(const area::BoundingBox&); + + // -- Members // None // -- Methods - static area::BoundingBox correctBoundingBox(const area::BoundingBox&, size_t& ni, size_t& nj, const Increments&, - const PointLonLat& reference = {0, 0}); - - static Configuration* config(const std::string& name); + virtual const std::vector& longitudes() const = 0; + virtual const std::vector& latitudes() const = 0; // -- Overridden methods // None @@ -97,27 +84,13 @@ class Regular : public Grid { private: // -- Members - - const Increments increments_; - const PointLonLat reference_; - size_t ni_; - size_t nj_; + // None // -- Methods // None // -- Overridden methods - - iterator cbegin() const override { NOTIMP; } - iterator cend() const override { NOTIMP; } - - bool isPeriodicWestEast() const override; - bool includesNorthPole() const override; - bool includesSouthPole() const override; - - size_t size() const override; - - std::pair, std::vector> to_latlon() const override; + // None // -- Class members // None @@ -126,7 +99,8 @@ class Regular : public Grid { // None // -- Friends - // None + + friend class ::eckit::geometry::iterator::Regular; }; diff --git a/src/eckit/geometry/grid/RegularGG.cc b/src/eckit/geometry/grid/RegularGG.cc deleted file mode 100644 index d456e145d..000000000 --- a/src/eckit/geometry/grid/RegularGG.cc +++ /dev/null @@ -1,188 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/grid/RegularGG.h" - -#include -#include - -#include "eckit/config/MappedConfiguration.h" -#include "eckit/geometry/grid/GaussianIterator.h" -#include "eckit/geometry/grid/RegularGG.h" -#include "eckit/geometry/util.h" -#include "eckit/types/FloatCompare.h" -#include "eckit/types/Fraction.h" -#include "eckit/utils/Translator.h" - - -namespace eckit::geometry::grid { - - -RegularGG::RegularGG(const Configuration& config) : - Gaussian(config), k_(0), Ni_(0), Nj_(0) { - // adjust latitudes, longitudes and re-set bounding box - auto n = bbox().north(); - auto s = bbox().south(); - correctSouthNorth(s, n); - - auto e = bbox().east(); - auto w = bbox().west(); - correctWestEast(w, e); - - bbox({n, w, s, e}); - - setNiNj(); -} - - -RegularGG::RegularGG(size_t N, const area::BoundingBox& box) : - Gaussian(N, box), k_(0), Ni_(0), Nj_(0) { - - // adjust latitudes, longitudes and re-set bounding box - auto n = box.north(); - auto s = box.south(); - correctSouthNorth(s, n); - - auto w = box.west(); - auto e = box.east(); - correctWestEast(w, e); - - bbox({n, w, s, e}); - - setNiNj(); -} - - -Configuration* RegularGG::config(const std::string& name) { - auto N = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "regular_gg"}, - {"N", N}, - {"Ni", 2 * N}, - {"Nj", 4 * N}}); -} - - -void RegularGG::correctWestEast(double& w, double& e) const { - ASSERT(w <= e); - - auto inc = getSmallestIncrement(); - ASSERT(inc > 0); - - if (angleApproximatelyEqual(GREENWICH, w) && (angleApproximatelyEqual(GLOBE - inc, e - w) || GLOBE - inc < e - w || (e != w && PointLonLat::normalise_angle_to_minimum(e, w) == w))) { - w = GREENWICH; - e = GLOBE - inc; - return; - } - - const Fraction west{w}; - const Fraction east{e}; - - Fraction::value_type Nw = (west / inc).integralPart(); - if (Nw * inc < west) { - Nw += 1; - } - - Fraction::value_type Ne = (east / inc).integralPart(); - if (Ne * inc > east) { - Ne -= 1; - } - - ASSERT(Nw <= Ne); - w = Nw * inc; - e = Ne * inc; -} - - -Fraction RegularGG::getSmallestIncrement() const { - ASSERT(N_); - return {90, Fraction::value_type(N_)}; -} - - -size_t RegularGG::size() const { - ASSERT(Ni_); - ASSERT(Nj_); - return Ni_ * Nj_; -} - - -bool RegularGG::isPeriodicWestEast() const { - auto inc = getSmallestIncrement(); - return bbox().east() - bbox().west() + inc >= GLOBE; -} - - -void RegularGG::setNiNj() { - ASSERT(N_); - - const auto inc = getSmallestIncrement(); - const auto& lats = latitudes(); - - Fraction w(bbox().west()); - Fraction e(bbox().east()); - Fraction s(bbox().south()); - Fraction n(bbox().north()); - - Ni_ = N_ * 4; - - if (e - w + inc < GLOBE) { - - auto Nw = (w / inc).integralPart(); - if (Nw * inc < w) { - Nw += 1; - } - - auto Ne = (e / inc).integralPart(); - if (Ne * inc > e) { - Ne -= 1; - } - - ASSERT(Ne - Nw + 1 > 0); - Ni_ = size_t(Ne - Nw + 1); - - ASSERT(2 <= Ni_ && Ni_ <= N_ * 4); - } - - k_ = 0; - Nj_ = N_ * 2; - - if (n < lats.front() || s > lats.back()) { - Nj_ = 0; - for (auto lat : lats) { - if (n < lat && !angleApproximatelyEqual(n, lat)) { - ++k_; - } - else if (s <= lat || angleApproximatelyEqual(s, lat)) { - ++Nj_; - } - else { - break; - } - } - ASSERT(Nj_ > 0); - } -} - - -#if 0 -Iterator* RegularGG::iterator() const { - std::vector pl(N_ * 2, long(4 * N_)); - return new GaussianIterator(latitudes(), std::move(pl), bbox(), N_, Nj_, k_); -} -#endif - - -static const GridRegisterType __grid_type("regular_gg"); -static const GridRegisterName __grid_pattern("[fF][1-9][0-9]*"); - - -} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/RegularGrid.cc b/src/eckit/geometry/grid/RegularGrid.cc deleted file mode 100644 index a2f79d764..000000000 --- a/src/eckit/geometry/grid/RegularGrid.cc +++ /dev/null @@ -1,242 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/grid/RegularGrid.h" - -#include -#include -#include -#include - -#include "eckit/config/MappedConfiguration.h" -#include "eckit/config/Resource.h" -#include "eckit/geometry/Earth.h" -#include "eckit/utils/StringTools.h" - - -namespace eckit::geometry::grid { - - -RegularGrid::RegularGrid(Projection* projection, const Configuration& config) : - Grid(config), - projection_(projection), - xPlus_(true), - yPlus_(false) { - ASSERT(projection_); - - auto get_long_first_key = [](const Configuration& config, const std::vector& keys) -> long { - long value = 0; - for (const auto& key : keys) { - if (config.get(key, value)) { - return value; - } - } - throw SeriousBug("RegularGrid: couldn't find any key: " + StringTools::join(", ", keys)); - }; - - long nx = get_long_first_key(config, {"numberOfPointsAlongXAxis", "Ni"}); - long ny = get_long_first_key(config, {"numberOfPointsAlongYAxis", "Nj"}); - ASSERT(nx > 0); - ASSERT(ny > 0); - - auto grid = config.getDoubleVector("grid"); - ASSERT(grid.size() == 2); - - auto first = projection->fwd(PointLonLat{config.getDouble("longitudeOfFirstGridPointInDegrees"), config.getDouble("latitudeOfFirstGridPointInDegrees")}); - auto first_xy = std::get(first); - - config.get("iScansPositively", xPlus_); // iScansPositively != 0 - config.get("jScansPositively", yPlus_); // jScansPositively == 0 - - auto firstPointBottomLeft_ = config.getBool("first_point_bottom_left", false); - - auto linspace = [](double start, double step, long num, bool plus) -> LinearSpacing { - ASSERT(step >= 0.); - // return {start, start + step * double(plus ? num - 1 : 1 - num), num}; - NOTIMP; - }; - - x_ = linspace(first_xy.X, grid[0], nx, firstPointBottomLeft_ || xPlus_); - y_ = linspace(first_xy.Y, grid[1], ny, firstPointBottomLeft_ || yPlus_); - - ASSERT(!x_.empty()); - ASSERT(!y_.empty()); - auto n = y_.front() > y_.back() ? y_.front() : y_.back(); - auto s = y_.front() > y_.back() ? y_.back() : y_.front(); - auto w = x_.front() > x_.back() ? x_.back() : x_.front(); - auto e = x_.front() > x_.back() ? x_.front() : x_.back(); - - bbox(area::BoundingBox::make({n, w, s, e}, *projection_)); -} - - -RegularGrid::RegularGrid(Projection* projection, const area::BoundingBox& bbox, const LinearSpacing& x, - const LinearSpacing& y, const Figure& figure) : - Grid(bbox), - x_(x), - y_(y), - figure_(figure), - xPlus_(x.front() <= x.back()), - yPlus_(y.front() < y.back()) { -} - - -RegularGrid::~RegularGrid() = default; - - -Projection* RegularGrid::make_projection_from_proj(const Configuration& config) { - if (config.has("proj")) { - return ProjectionFactory::instance().get("proj").create(config); - } - - return nullptr; -} - - -size_t RegularGrid::size() const { - return x_.size() * y_.size(); -} - - -bool RegularGrid::isPeriodicWestEast() const { - return false; -} - - -bool RegularGrid::includesNorthPole() const { - return bbox().north() == NORTH_POLE; -} - - -bool RegularGrid::includesSouthPole() const { - return bbox().south() == SOUTH_POLE; -} - - -#if 0 -Iterator* RegularGrid::iterator() const { - class RegularGridIterator : public Iterator { - const Projection& projection_; - const LinearSpacing& x_; - const LinearSpacing& y_; - - size_t ni_; - size_t nj_; - size_t i_; - size_t j_; - size_t count_; - - bool operator++() override { - if (j_ < nj_ && i_ < ni_) { - const auto p = projection_.inv(Point2{x_[i_], y_[j_]}); - const auto ll = std::get(p); - // _lat = ll.lat; - // _lon = ll.lon; - - if (i_ > 0 || j_ > 0) { - count_++; - } - - if (++i_ == ni_) { - i_ = 0; - j_++; - } - - return true; - } - return false; - } - - size_t index() const override { return count_; } - - size_t size() const override { NOTIMP; } - - public: - RegularGridIterator(const Projection& projection, const LinearSpacing& x, const LinearSpacing& y) : - projection_(projection), x_(x), y_(y), ni_(x.size()), nj_(y.size()), i_(0), j_(0), count_(0) {} - ~RegularGridIterator() override = default; - - RegularGridIterator(const RegularGridIterator&) = delete; - RegularGridIterator(RegularGridIterator&&) = delete; - RegularGridIterator& operator=(const RegularGridIterator&) = delete; - RegularGridIterator& operator=(RegularGridIterator&&) = delete; - }; - - return new RegularGridIterator(*projection_, x_, y_); -} -#endif - - -struct Lambert : RegularGrid { - Lambert(const Configuration& config) : - RegularGrid(make_projection(config), config) { - } - - static Projection* make_projection(const Configuration& config) { - if (auto p = RegularGrid::make_projection_from_proj(config); p != nullptr) { - return p; - } - - auto LaDInDegrees = config.getDouble("LaDInDegrees"); - auto LoVInDegrees = config.getDouble("LoVInDegrees"); - auto Latin1InDegrees = config.getDouble("Latin1InDegrees", LaDInDegrees); - auto Latin2InDegrees = config.getDouble("Latin2InDegrees", LaDInDegrees); - - return ProjectionFactory::instance().get("lambert_conformal_conic").create(MappedConfiguration({{"latitude1", Latin1InDegrees}, {"latitude2", Latin2InDegrees}, {"latitude0", LaDInDegrees}, {"longitude0", LoVInDegrees}})); - } -}; - - -struct LambertAzimuthalEqualArea : RegularGrid { - - LambertAzimuthalEqualArea(const Configuration& config) : - RegularGrid(make_projection(config), config) {} - - LambertAzimuthalEqualArea(Projection* projection, const area::BoundingBox& bbox, const LinearSpacing& x, const LinearSpacing& y, const Figure& shape) : - RegularGrid(projection, bbox, x, y, shape) {} - - static Projection* make_projection(const Configuration& config) { - if (auto p = RegularGrid::make_projection_from_proj(config); p != nullptr) { - return p; - } - - double standardParallel = 0.; - double centralLongitude = 0.; - double radius = 0.; - ASSERT(config.get("standardParallelInDegrees", standardParallel)); - ASSERT(config.get("centralLongitudeInDegrees", centralLongitude)); - config.get("radius", radius = Earth::radius()); - - return ProjectionFactory::instance().get("lambert_azimuthal_equal_area").create(MappedConfiguration({{"standard_parallel", standardParallel}, {"central_longitude", centralLongitude}, {"radius", radius}})); - } -}; - - -struct Mercator : RegularGrid { - Mercator(const Configuration& config) : - RegularGrid(RegularGrid::make_projection_from_proj(config), config) {} -}; - - -struct PolarStereographic : RegularGrid { - PolarStereographic(const Configuration& config) : - RegularGrid(RegularGrid::make_projection_from_proj(config), config) {} -}; - - -// static const GridRegisterType __builder1("lambert"); -// static const GridRegisterType __builder2("lambert_azimuthal_equal_area"); -// static const GridRegisterType __builder3("mercator"); -// static const GridRegisterType __builder4("polar_stereographic"); - - -} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/RegularGrid.h b/src/eckit/geometry/grid/RegularGrid.h deleted file mode 100644 index 55d235a0d..000000000 --- a/src/eckit/geometry/grid/RegularGrid.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include - -#include "eckit/geometry/Figure.h" -#include "eckit/geometry/Grid.h" -#include "eckit/geometry/Projection.h" - - -namespace eckit::geometry::grid { - - -class RegularGrid : public Grid { -public: - // -- Types - - using LinearSpacing = std::vector; - - // -- Exceptions - // None - - // -- Constructors - - RegularGrid(const RegularGrid&) = delete; - RegularGrid(RegularGrid&&) = delete; - - // -- Destructor - - ~RegularGrid() override; - - // -- Convertors - // None - - // -- Operators - - RegularGrid& operator=(const RegularGrid&) = delete; - RegularGrid& operator=(RegularGrid&&) = delete; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Constructors - - RegularGrid(Projection*, const Configuration&); - RegularGrid(Projection*, const area::BoundingBox&, const LinearSpacing& x, const LinearSpacing& y, - const Figure&); - - // -- Members - - std::unique_ptr projection_; - LinearSpacing x_; - LinearSpacing y_; - Figure figure_; - bool xPlus_; - bool yPlus_; - - // -- Methods - - static Projection* make_projection_from_proj(const Configuration&); - - // -- Overridden methods - - bool includesNorthPole() const override; - bool includesSouthPole() const override; - bool isPeriodicWestEast() const override; - - size_t size() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/Unstructured.cc b/src/eckit/geometry/grid/Unstructured.cc new file mode 100644 index 000000000..42f6284aa --- /dev/null +++ b/src/eckit/geometry/grid/Unstructured.cc @@ -0,0 +1,36 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/grid/Unstructured.h" + +#include "eckit/geometry/iterator/Unstructured.h" + + +namespace eckit::geometry::grid { + + +Grid::iterator Unstructured::cbegin() const { + return iterator{new geometry::iterator::Unstructured(*this)}; +} + + +Grid::iterator Unstructured::cend() const { + return iterator{new geometry::iterator::Unstructured(*this, size())}; +} + + +Unstructured::Unstructured(const Configuration& config) : + Grid(config) { +} + + +} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/ReducedGG.h b/src/eckit/geometry/grid/Unstructured.h similarity index 70% rename from src/eckit/geometry/grid/ReducedGG.h rename to src/eckit/geometry/grid/Unstructured.h index ab9f1a7c7..87b64bea9 100644 --- a/src/eckit/geometry/grid/ReducedGG.h +++ b/src/eckit/geometry/grid/Unstructured.h @@ -12,25 +12,31 @@ #pragma once -#include "eckit/geometry/grid/Gaussian.h" -#include "eckit/geometry/util.h" +#include "eckit/geometry/Grid.h" + + +namespace eckit::geometry::iterator { +class Unstructured; +} namespace eckit::geometry::grid { -class ReducedGG : public Gaussian { +class Unstructured : public Grid { public: + // -- Types + // None + // -- Exceptions // None // -- Constructors - - explicit ReducedGG(const Configuration&); - ReducedGG(size_t N, const pl_type& pl); + // None // -- Destructor - // None + + ~Unstructured() override = default; // -- Convertors // None @@ -42,7 +48,9 @@ class ReducedGG : public Gaussian { // None // -- Overridden methods - // None + + iterator cbegin() const override; + iterator cend() const override; // -- Class members // None @@ -52,38 +60,35 @@ class ReducedGG : public Gaussian { protected: // -- Constructors - // None + + explicit Unstructured(const Configuration&); // -- Members // None // -- Methods - // None - // -- Overridden methods + virtual const std::vector& longitudes() const = 0; + virtual const std::vector& latitudes() const = 0; - bool isPeriodicWestEast() const override; + // -- Overridden methods + // None // -- Class members + // None // -- Class methods // None private: // -- Members - - const pl_type& pl_; - pl_type placc_; - - size_t k_; - size_t Nj_; + // None // -- Methods // None // -- Overridden methods - - size_t size() const override; + // None // -- Class members // None @@ -92,7 +97,8 @@ class ReducedGG : public Gaussian { // None // -- Friends - // None + + friend class ::eckit::geometry::iterator::Unstructured; }; diff --git a/src/eckit/geometry/grid/UnstructuredGrid.cc b/src/eckit/geometry/grid/UnstructuredGrid.cc deleted file mode 100644 index 4f18ec24a..000000000 --- a/src/eckit/geometry/grid/UnstructuredGrid.cc +++ /dev/null @@ -1,101 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/grid/UnstructuredGrid.h" - -#include - -#include "eckit/config/Configuration.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/geometry/iterator/ListI.h" - - -namespace eckit::geometry::grid { - - -UnstructuredGrid::UnstructuredGrid(const Configuration& config) : - UnstructuredGrid(std::make_pair(config.getDoubleVector("longitudes"), config.getDoubleVector("latitudes"))) { -} - - -UnstructuredGrid::UnstructuredGrid(const Grid& grid) : - UnstructuredGrid(grid.to_latlon()) {} - - -UnstructuredGrid::UnstructuredGrid(const std::vector& latitudes, const std::vector& longitudes) : - Grid(area::BoundingBox::make_global_prime()), latitudes_(latitudes), longitudes_(longitudes) { - ASSERT(!latitudes_.empty()); - ASSERT(latitudes_.size() == longitudes_.size()); -} - - -Renumber UnstructuredGrid::list_duplicates() const { - std::vector dupes; - - std::set seen; - - for (auto i = cbegin(); i != cend(); ++i) { - if (!seen.insert(std::get(*i)).second) { - dupes.push_back(i->index()); - } - } - - return dupes; -} - - -UnstructuredGrid::UnstructuredGrid(std::pair, std::vector>&& latlon) : - Grid(area::BoundingBox::make_global_prime()), latitudes_(std::move(latlon.first)), longitudes_(std::move(latlon.second)) { - ASSERT(!latitudes_.empty()); - ASSERT(latitudes_.size() == longitudes_.size()); -} - - -Grid::iterator UnstructuredGrid::cbegin() const { - return iterator{new geometry::iterator::ListI(*this)}; -} - - -Grid::iterator UnstructuredGrid::cend() const { - return iterator{new geometry::iterator::ListI(*this, size())}; -} - - -UnstructuredGrid::~UnstructuredGrid() = default; - - -size_t UnstructuredGrid::size() const { - return latitudes_.size(); -} - - -std::vector UnstructuredGrid::to_points() const { - std::vector points; - points.reserve(size()); - - for (auto lat = latitudes_.begin(), lon = longitudes_.begin(); lat != latitudes_.end(); ++lat, ++lon) { - points.emplace_back(PointLonLat{*lon, *lat}); - } - - return points; -} - - -std::pair, std::vector> UnstructuredGrid::to_latlon() const { - return {latitudes_, longitudes_}; -} - - -static const GridRegisterType unstructured_grid("unstructured_grid"); - - -} // namespace eckit::geometry::grid diff --git a/src/eckit/geometry/grid/reduced/HEALPix.cc b/src/eckit/geometry/grid/reduced/HEALPix.cc new file mode 100644 index 000000000..ed828c83c --- /dev/null +++ b/src/eckit/geometry/grid/reduced/HEALPix.cc @@ -0,0 +1,134 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/grid/reduced/HEALPix.h" + +#include "eckit/config/MappedConfiguration.h" +#include "eckit/geometry/iterator/Reduced.h" +#include "eckit/geometry/util.h" +#include "eckit/utils/Translator.h" + + +namespace eckit::geometry::grid::reduced { + + +static Ordering ordering_from_string(const std::string& str) { + return str == "ring" ? Ordering::healpix_ring : str == "nested" ? Ordering::healpix_nested + : throw AssertionFailed("HEALPix::Ordering", Here()); +} + + +HEALPix::HEALPix(const Configuration& config) : + HEALPix(config.getUnsigned("Nside"), ordering_from_string(config.getString("orderingConvention", "ring"))) { +} + + +HEALPix::HEALPix(size_t Nside, Ordering ordering) : + Reduced(area::BoundingBox::make_global_prime()), N_(Nside), ordering_(ordering) { + ASSERT(N_ > 0); + ASSERT(ordering_ == Ordering::healpix_ring); +} + + +Grid::iterator HEALPix::cbegin() const { + return ordering_ == Ordering::healpix_ring ? iterator{new geometry::iterator::Reduced(*this, 0)} : NOTIMP; +} + + +Grid::iterator HEALPix::cend() const { + return ordering_ == Ordering::healpix_ring ? iterator{new geometry::iterator::Reduced(*this, size())} : NOTIMP; +} + + +size_t HEALPix::ni(size_t j) const { + ASSERT(j < nj()); + return j < N_ ? 4 * (j + 1) : j < 3 * N_ ? 4 * N_ + : ni(nj() - 1 - j); +} + + +size_t HEALPix::nj() const { + return 4 * N_ - 1; +} + + +Configuration* HEALPix::config(const std::string& name) { + auto Nside = Translator{}(name.substr(1)); + return new MappedConfiguration({{"type", "HEALPix"}, {"Nside", Nside}, {"orderingConvention", "ring"}}); +} + + +const area::BoundingBox& HEALPix::boundingBox() const { + static const auto __bbox(area::BoundingBox::make_global_prime()); + return __bbox; +} + + +size_t HEALPix::size() const { + return 12 * N_ * N_; +} + + +std::pair, std::vector> HEALPix::to_latlon() const { + std::pair, std::vector> latlon; + latlon.first.reserve(size()); + latlon.second.reserve(size()); + + for (const auto& p : to_points()) { + const auto& q = std::get(p); + latlon.first.push_back(q.lat); + latlon.second.push_back(q.lon); + } + + return latlon; +} + + +const std::vector& HEALPix::latitudes() const { + const auto Nj = nj(); + + if (latitudes_.empty()) { + latitudes_.resize(Nj); + + auto i = latitudes_.begin(); + auto j = latitudes_.rbegin(); + for (size_t ring = 1; ring < 2 * N_; ++ring, ++i, ++j) { + const auto f = ring < N_ ? 1. - static_cast(ring * ring) / (3 * static_cast(N_ * N_)) : 4. / 3. - 2 * static_cast(ring) / (3 * static_cast(N_)); + + *i = 90. - util::radian_to_degree * std::acos(f); + *j = -*i; + } + *i = 0.; + } + + ASSERT(latitudes_.size() == Nj); + return latitudes_; +} + + +std::vector HEALPix::longitudes(size_t j) const { + const auto Ni = ni(j); + const auto step = 360. / static_cast(Ni); + const auto start = j < N_ || 3 * N_ - 1 < j || static_cast((j + N_) % 2) ? step / 2. : 0.; + + std::vector lons(Ni); + std::generate_n(lons.begin(), Ni, [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); + + return lons; +} + + +static const GridRegisterType __grid_type("HEALPix"); +static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); + + +} // namespace eckit::geometry::grid::reduced diff --git a/src/eckit/geometry/grid/UnstructuredGrid.h b/src/eckit/geometry/grid/reduced/HEALPix.h similarity index 62% rename from src/eckit/geometry/grid/UnstructuredGrid.h rename to src/eckit/geometry/grid/reduced/HEALPix.h index 083686ee6..e80dc06a5 100644 --- a/src/eckit/geometry/grid/UnstructuredGrid.h +++ b/src/eckit/geometry/grid/reduced/HEALPix.h @@ -12,33 +12,27 @@ #pragma once -#include +#include "eckit/geometry/grid/Reduced.h" -#include "eckit/geometry/Grid.h" +namespace eckit::geometry::grid::reduced { -namespace eckit::geometry::iterator { -class ListI; -} - -namespace eckit::geometry::grid { - - -class UnstructuredGrid : public Grid { +class HEALPix final : public Reduced { public: + // -- Types + // None + // -- Exceptions // None // -- Constructors - explicit UnstructuredGrid(const Configuration&); - explicit UnstructuredGrid(const Grid&); - UnstructuredGrid(const std::vector& latitudes, const std::vector& longitudes); + explicit HEALPix(const Configuration&); + explicit HEALPix(size_t Nside, Ordering = Ordering::healpix_ring); // -- Destructor - - ~UnstructuredGrid() override; + // None // -- Convertors // None @@ -47,45 +41,49 @@ class UnstructuredGrid : public Grid { // None // -- Methods - - Renumber list_duplicates() const; + // None // -- Overridden methods - // None + + iterator cbegin() const override; + iterator cend() const override; + + size_t ni(size_t j) const override; + size_t nj() const override; // -- Class members - // None + + static Configuration* config(const std::string& name); // -- Class methods // None private: - // -- Constructors - - explicit UnstructuredGrid(std::pair, std::vector>&&); - // -- Members - std::vector latitudes_; - std::vector longitudes_; + const size_t N_; + const Ordering ordering_; + + mutable std::vector latitudes_; // -- Methods // None // -- Overridden methods - iterator cbegin() const override; - iterator cend() const override; + const area::BoundingBox& boundingBox() const override; size_t size() const override; - bool isPeriodicWestEast() const override { return true; } bool includesNorthPole() const override { return true; } bool includesSouthPole() const override { return true; } + bool isPeriodicWestEast() const override { return true; } - std::vector to_points() const override; std::pair, std::vector> to_latlon() const override; + const std::vector& latitudes() const override; + std::vector longitudes(size_t j) const override; + // -- Class members // None @@ -93,9 +91,8 @@ class UnstructuredGrid : public Grid { // None // -- Friends - - friend class geometry::iterator::ListI; + // None }; -} // namespace eckit::geometry::grid +} // namespace eckit::geometry::grid::reduced diff --git a/src/eckit/geometry/grid/reduced/ReducedGaussian.cc b/src/eckit/geometry/grid/reduced/ReducedGaussian.cc new file mode 100644 index 000000000..0b5f25b3f --- /dev/null +++ b/src/eckit/geometry/grid/reduced/ReducedGaussian.cc @@ -0,0 +1,103 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/grid/reduced/ReducedGaussian.h" + +#include "eckit/config/MappedConfiguration.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geometry/iterator/Reduced.h" +#include "eckit/geometry/range/Gaussian.h" +#include "eckit/geometry/range/GlobalRegular.h" +#include "eckit/utils/Translator.h" + + +namespace eckit::geometry::grid::reduced { + + +ReducedGaussian::ReducedGaussian(const Configuration& config) : + ReducedGaussian(config.getUnsigned("N"), config.getLongVector("pl"), + area::BoundingBox(config)) {} + + +ReducedGaussian::ReducedGaussian(size_t N, const pl_type& pl, const area::BoundingBox& bbox) : + Reduced(bbox), + pl_(pl), + j_(0), + Nj_(N * 2), + y_(new range::Gaussian(N, bbox.north(), bbox.south())) { + ASSERT(y_); +} + + +Grid::iterator ReducedGaussian::cbegin() const { + return iterator{new geometry::iterator::Reduced(*this, 0)}; +} + + +Grid::iterator ReducedGaussian::cend() const { + return iterator{new geometry::iterator::Reduced(*this, size())}; +} + + +size_t ReducedGaussian::ni(size_t j) const { + ASSERT(j < Nj_); + return pl_.at(j + j_); +} + + +size_t ReducedGaussian::nj() const { + return y_->size(); +} + + +const std::vector& ReducedGaussian::latitudes() const { + return y_->values(); +} + + +std::vector ReducedGaussian::longitudes(size_t j) const { + auto Ni = ni(j); + if (!x_ || x_->size() != Ni) { + const_cast&>(x_).reset( + new range::GlobalRegular(Ni, bbox().west(), bbox().east())); + } + + return x_->values(); +} + + +struct ReducedGaussianClassical { + static Configuration* config(const std::string& name) { + auto N = Translator{}(name.substr(1)); + return new MappedConfiguration({{"type", "reduced_gg"}, + {"N", N}, + {"pl", util::reduced_classical_pl(N)}}); + } +}; + + +struct ReducedGaussianOctahedral { + static Configuration* config(const std::string& name) { + auto N = Translator{}(name.substr(1)); + return new MappedConfiguration({{"type", "reduced_gg"}, + {"N", N}, + {"pl", util::reduced_octahedral_pl(N)}}); + } +}; + + +static const GridRegisterType __grid_type("reduced_gg"); +static const GridRegisterName __grid_pattern_1("[nN][1-9][0-9]*"); +static const GridRegisterName __grid_pattern_2("[oO][1-9][0-9]*"); + + +} // namespace eckit::geometry::grid::reduced diff --git a/src/eckit/geometry/grid/reduced/ReducedGaussian.h b/src/eckit/geometry/grid/reduced/ReducedGaussian.h new file mode 100644 index 000000000..64c5429ab --- /dev/null +++ b/src/eckit/geometry/grid/reduced/ReducedGaussian.h @@ -0,0 +1,93 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "eckit/geometry/Range.h" +#include "eckit/geometry/grid/Reduced.h" +#include "eckit/geometry/util.h" + + +namespace eckit::geometry::grid::reduced { + + +class ReducedGaussian : public Reduced { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit ReducedGaussian(const Configuration&); + ReducedGaussian(size_t N, const pl_type& pl, const area::BoundingBox& = area::BoundingBox::make_global_prime()); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + iterator cbegin() const override; + iterator cend() const override; + + size_t ni(size_t j) const override; + size_t nj() const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + const pl_type pl_; + size_t j_; + size_t Nj_; + + std::unique_ptr x_; + std::unique_ptr y_; + + // -- Methods + // None + + // -- Overridden methods + + const std::vector& latitudes() const override; + std::vector longitudes(size_t j) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geometry::grid::reduced diff --git a/src/eckit/geometry/grid/reduced/ReducedLatLon.cc b/src/eckit/geometry/grid/reduced/ReducedLatLon.cc new file mode 100644 index 000000000..252e4f33a --- /dev/null +++ b/src/eckit/geometry/grid/reduced/ReducedLatLon.cc @@ -0,0 +1,56 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/grid/reduced/ReducedLatLon.h" + +#include "eckit/geometry/iterator/Reduced.h" + + +namespace eckit::geometry::grid::reduced { + + +ReducedLatLon::ReducedLatLon(const Configuration& config) : + Reduced(config) { +} + + +Grid::iterator ReducedLatLon::cbegin() const { + return iterator{new geometry::iterator::Reduced(*this, 0)}; +} + + +Grid::iterator ReducedLatLon::cend() const { + return iterator{new geometry::iterator::Reduced(*this, size())}; +} + + +size_t ReducedLatLon::ni(size_t j) const { + NOTIMP; +} + + +size_t ReducedLatLon::nj() const { + NOTIMP; +} + + +const std::vector& ReducedLatLon::latitudes() const { + NOTIMP; +} + + +std::vector ReducedLatLon::longitudes(size_t j) const { + NOTIMP; +} + + +} // namespace eckit::geometry::grid::reduced diff --git a/src/eckit/geometry/grid/RegularGG.h b/src/eckit/geometry/grid/reduced/ReducedLatLon.h similarity index 60% rename from src/eckit/geometry/grid/RegularGG.h rename to src/eckit/geometry/grid/reduced/ReducedLatLon.h index 6c8f64d96..8cffad4d9 100644 --- a/src/eckit/geometry/grid/RegularGG.h +++ b/src/eckit/geometry/grid/reduced/ReducedLatLon.h @@ -12,26 +12,23 @@ #pragma once -#include "eckit/geometry/grid/Gaussian.h" +#include "eckit/geometry/grid/Reduced.h" -namespace eckit { -class Fraction; -} +namespace eckit::geometry::grid::reduced { -namespace eckit::geometry::grid { - - -class RegularGG final : public Gaussian { +class ReducedLatLon : public Reduced { public: + // -- Types + // None + // -- Exceptions // None // -- Constructors - RegularGG(const Configuration&); - RegularGG(size_t N, const area::BoundingBox& = {}); + explicit ReducedLatLon(const Configuration&); // -- Destructor // None @@ -47,7 +44,11 @@ class RegularGG final : public Gaussian { // -- Overridden methods - static Configuration* config(const std::string& name); + iterator cbegin() const override; + iterator cend() const override; + + size_t ni(size_t j) const override; + size_t nj() const override; // -- Class members // None @@ -57,22 +58,15 @@ class RegularGG final : public Gaussian { private: // -- Members - - size_t k_; - size_t Ni_; - size_t Nj_; + // None // -- Methods - - Fraction getSmallestIncrement() const; - void correctWestEast(double& w, double& e) const; - void setNiNj(); + // None // -- Overridden methods - size_t size() const override; - - bool isPeriodicWestEast() const override; + const std::vector& latitudes() const override; + std::vector longitudes(size_t j) const override; // -- Class members // None @@ -85,4 +79,4 @@ class RegularGG final : public Gaussian { }; -} // namespace eckit::geometry::grid +} // namespace eckit::geometry::grid::reduced diff --git a/src/eckit/geometry/grid/regular/IrregularLatLon.cc b/src/eckit/geometry/grid/regular/IrregularLatLon.cc new file mode 100644 index 000000000..8a1999122 --- /dev/null +++ b/src/eckit/geometry/grid/regular/IrregularLatLon.cc @@ -0,0 +1,56 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/grid/regular/IrregularLatLon.h" + +// #include <> + + +namespace eckit::geometry::grid::regular { + + +IrregularLatLon::IrregularLatLon(const Configuration& config) : + Regular(config) { +} + + +Grid::iterator IrregularLatLon::cbegin() const { + NOTIMP; +} + + +Grid::iterator IrregularLatLon::cend() const { + NOTIMP; +} + + +size_t IrregularLatLon::ni() const { + NOTIMP; +} + + +size_t IrregularLatLon::nj() const { + NOTIMP; +} + + +const std::vector& IrregularLatLon::longitudes() const { + NOTIMP; +} + + +const std::vector& IrregularLatLon::latitudes() const { + NOTIMP; +} + + +} // namespace eckit::geometry::grid::regular diff --git a/src/eckit/geometry/grid/regular/IrregularLatLon.h b/src/eckit/geometry/grid/regular/IrregularLatLon.h new file mode 100644 index 000000000..f7558bfb3 --- /dev/null +++ b/src/eckit/geometry/grid/regular/IrregularLatLon.h @@ -0,0 +1,82 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geometry/grid/Regular.h" + + +namespace eckit::geometry::grid::regular { + + +class IrregularLatLon final : public Regular { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit IrregularLatLon(const Configuration&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + iterator cbegin() const override; + iterator cend() const override; + + size_t ni() const override; + size_t nj() const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + const std::vector& longitudes() const override; + const std::vector& latitudes() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geometry::grid::regular diff --git a/src/eckit/geometry/grid/regular/RegularGaussian.cc b/src/eckit/geometry/grid/regular/RegularGaussian.cc new file mode 100644 index 000000000..a68e9c262 --- /dev/null +++ b/src/eckit/geometry/grid/regular/RegularGaussian.cc @@ -0,0 +1,78 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/grid/regular/RegularGaussian.h" + +#include "eckit/config/MappedConfiguration.h" +#include "eckit/geometry/iterator/Regular.h" +#include "eckit/geometry/range/Gaussian.h" +#include "eckit/geometry/range/LocalRegular.h" +#include "eckit/utils/Translator.h" + + +namespace eckit::geometry::grid::regular { +// LocalRegular(size_t n, double a, double b, bool endpoint, double precision = 0.); + + +RegularGaussian::RegularGaussian(const Configuration& config) : + Regular(config), + ni_(config.getUnsigned("ni", config.getUnsigned("ni"))), + x_(new range::LocalRegular(ni_, config.getDouble("west", 0.), config.getDouble("east", 360.), true /*FIXME*/)), + y_(new range::Gaussian(config.getUnsigned("N"), + config.getDouble("north", 90.), + config.getDouble("south", -90.))) { + ASSERT(ni_ > 0); +} + + +RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : + Regular(bbox), + ni_(4 * N), + x_(new range::LocalRegular(ni_, bbox.west(), bbox.east(), true /*FIXME*/)), + y_(new range::Gaussian(N, bbox.west(), bbox.east())) { +} + + +Grid::iterator RegularGaussian::cbegin() const { + return iterator{new geometry::iterator::Regular(*this, 0)}; +} + + +Grid::iterator RegularGaussian::cend() const { + return iterator{new geometry::iterator::Regular(*this, size())}; +} + + +Configuration* RegularGaussian::config(const std::string& name) { + auto N = Translator{}(name.substr(1)); + return new MappedConfiguration({{"type", "regular_gg"}, + {"N", N}, + {"Ni", 2 * N}, + {"Nj", 4 * N}}); +} + + +const std::vector& RegularGaussian::longitudes() const { + return x_->values(); +} + + +const std::vector& RegularGaussian::latitudes() const { + return x_->values(); +} + + +static const GridRegisterType __grid_type("regular_gg"); +static const GridRegisterName __grid_pattern("[fF][1-9][0-9]*"); + + +} // namespace eckit::geometry::grid::regular diff --git a/src/eckit/geometry/grid/regular/RegularGaussian.h b/src/eckit/geometry/grid/regular/RegularGaussian.h new file mode 100644 index 000000000..15bb2a07d --- /dev/null +++ b/src/eckit/geometry/grid/regular/RegularGaussian.h @@ -0,0 +1,89 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geometry/Range.h" +#include "eckit/geometry/grid/Regular.h" + + +namespace eckit::geometry::grid::regular { + + +class RegularGaussian final : public Regular { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit RegularGaussian(const Configuration&); + explicit RegularGaussian(size_t N, const area::BoundingBox& = area::BoundingBox::make_global_prime()); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + iterator cbegin() const override; + iterator cend() const override; + + size_t ni() const override { return x_->size(); } + size_t nj() const override { return y_->size(); } + + // -- Class members + // None + + // -- Class methods + + static Configuration* config(const std::string& name); + +private: + // -- Members + + size_t ni_; + + std::unique_ptr x_; + std::unique_ptr y_; + + // -- Methods + // None + + // -- Overridden methods + + const std::vector& longitudes() const override; + const std::vector& latitudes() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geometry::grid::regular diff --git a/src/eckit/geometry/grid/regular/RegularLatLon.cc b/src/eckit/geometry/grid/regular/RegularLatLon.cc new file mode 100644 index 000000000..955695f89 --- /dev/null +++ b/src/eckit/geometry/grid/regular/RegularLatLon.cc @@ -0,0 +1,56 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/grid/regular/RegularLatLon.h" + +#include "eckit/geometry/iterator/Regular.h" + + +namespace eckit::geometry::grid::regular { + + +RegularLatLon::RegularLatLon(const Configuration& config) : + Regular(config) { +} + + +Grid::iterator RegularLatLon::cbegin() const { + return iterator{new geometry::iterator::Regular(*this, 0)}; +} + + +Grid::iterator RegularLatLon::cend() const { + return iterator{new geometry::iterator::Regular(*this, size())}; +} + + +size_t RegularLatLon::ni() const { + NOTIMP; +} + + +size_t RegularLatLon::nj() const { + NOTIMP; +} + + +const std::vector& RegularLatLon::longitudes() const { + NOTIMP; +} + + +const std::vector& RegularLatLon::latitudes() const { + NOTIMP; +} + + +} // namespace eckit::geometry::grid::regular diff --git a/src/eckit/geometry/grid/regular/RegularLatLon.h b/src/eckit/geometry/grid/regular/RegularLatLon.h new file mode 100644 index 000000000..9bd4fc9fc --- /dev/null +++ b/src/eckit/geometry/grid/regular/RegularLatLon.h @@ -0,0 +1,82 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geometry/grid/Regular.h" + + +namespace eckit::geometry::grid::regular { + + +class RegularLatLon final : public Regular { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit RegularLatLon(const Configuration&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + iterator cbegin() const override; + iterator cend() const override; + + size_t ni() const override; + size_t nj() const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + const std::vector& longitudes() const override; + const std::vector& latitudes() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geometry::grid::regular diff --git a/src/eckit/geometry/grid/ORCA.cc b/src/eckit/geometry/grid/unstructured/ORCA.cc similarity index 80% rename from src/eckit/geometry/grid/ORCA.cc rename to src/eckit/geometry/grid/unstructured/ORCA.cc index ac44c470c..24181920a 100644 --- a/src/eckit/geometry/grid/ORCA.cc +++ b/src/eckit/geometry/grid/unstructured/ORCA.cc @@ -10,13 +10,14 @@ */ -#include "eckit/geometry/grid/ORCA.h" +#include "eckit/geometry/grid/unstructured/ORCA.h" #include "eckit/codec/codec.h" #include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "eckit/geometry/LibEcKitGeometry.h" #include "eckit/geometry/area/BoundingBox.h" +#include "eckit/geometry/iterator/Unstructured.h" #include "eckit/io/Length.h" #include "eckit/log/Bytes.h" #include "eckit/log/Timer.h" @@ -29,7 +30,7 @@ #endif -namespace eckit::geometry::grid { +namespace eckit::geometry::grid::unstructured { namespace { @@ -58,57 +59,8 @@ std::string arrangement_to_string(ORCA::Arrangement a) { } // namespace -ORCA::Iterator::Iterator(const Grid& grid, size_t index) : - geometry::Iterator(grid), - index_(index), - index_size_(grid.size()), - longitudes_(dynamic_cast(grid).longitudes_), - latitudes_(dynamic_cast(grid).latitudes_), - uid_(dynamic_cast(grid).uid_) { - ASSERT(index_size_ == longitudes_.size()); - ASSERT(index_size_ == latitudes_.size()); -} - - -bool ORCA::Iterator::operator==(const geometry::Iterator& other) const { - const auto* another = dynamic_cast(&other); - return another != nullptr && index_ == another->index_ && uid_ == another->uid_; -} - - -bool ORCA::Iterator::operator++() { - if (index_++; index_ < index_size_) { - return true; - } - - index_ = index_size_; // ensure it's invalid - return false; -} - - -bool ORCA::Iterator::operator+=(diff_t d) { - if (auto di = static_cast(index_); 0 <= di + d && di + d < static_cast(index_size_)) { - index_ = static_cast(di + d); - return true; - } - - index_ = index_size_; // ensure it's invalid - return false; -} - - -ORCA::Iterator::operator bool() const { - return index_ < index_size_; -} - - -Point ORCA::Iterator::operator*() const { - return PointLonLat{longitudes_.at(index_), latitudes_.at(index_)}; -} - - ORCA::ORCA(const Configuration& config) : - Grid(config), + Unstructured(config), name_(config.getString("orca_name")), uid_(config.getString("orca_uid")), arrangement_(arrangement_from_string(config.getString("orca_arrangement"))), @@ -158,6 +110,32 @@ ORCA::ORCA(const Configuration& config) : } +Grid::uid_t ORCA::calculate_uid() const { + MD5 hash; + hash.add(arrangement_to_string(arrangement_)); + + auto sized = static_cast(longitudes_.size() * sizeof(double)); + + if constexpr (eckit_LITTLE_ENDIAN) { + hash.add(latitudes_.data(), sized); + hash.add(longitudes_.data(), sized); + } + else { + auto lonsw = longitudes_; + auto latsw = latitudes_; + eckit::byteswap(latsw.data(), latsw.size()); + eckit::byteswap(lonsw.data(), lonsw.size()); + hash.add(latsw.data(), sized); + hash.add(lonsw.data(), sized); + } + + auto d = hash.digest(); + ASSERT(d.length() == 32); + + return {d}; +} + + void ORCA::read(const PathName& p) { codec::RecordReader reader(p); @@ -225,44 +203,13 @@ size_t ORCA::write(const PathName& p, const std::string& compression) { } -std::string ORCA::uid() const { - MD5 hash; - hash.add(arrangement_to_string(arrangement_)); - - auto sized = static_cast(longitudes_.size() * sizeof(double)); - - if constexpr (eckit_LITTLE_ENDIAN) { - hash.add(latitudes_.data(), sized); - hash.add(longitudes_.data(), sized); - } - else { - auto lonsw = longitudes_; - auto latsw = latitudes_; - eckit::byteswap(latsw.data(), latsw.size()); - eckit::byteswap(lonsw.data(), lonsw.size()); - hash.add(latsw.data(), sized); - hash.add(lonsw.data(), sized); - } - - auto d = hash.digest(); - ASSERT(d.length() == 32); - - return d; -} - - -Configuration* ORCA::config(const std::string& name) { - return GridConfigurationUID::instance().get(name).config(); -} - - Grid::iterator ORCA::cbegin() const { - return iterator{new Iterator(*this, 0)}; + return iterator{new geometry::iterator::Unstructured(*this, 0)}; } Grid::iterator ORCA::cend() const { - return iterator{new Iterator(*this, size())}; + return iterator{new geometry::iterator::Unstructured(*this, size())}; } @@ -277,8 +224,13 @@ std::pair, std::vector> ORCA::to_latlon() const { } +Configuration* ORCA::config(const std::string& name) { + return GridConfigurationUID::instance().get(name).config(); +} + + static const GridRegisterType __grid_type("ORCA"); static const GridRegisterName __grid_pattern(GridRegisterName::uid_pattern); -} // namespace eckit::geometry::grid +} // namespace eckit::geometry::grid::unstructured diff --git a/src/eckit/geometry/grid/ORCA.h b/src/eckit/geometry/grid/unstructured/ORCA.h similarity index 73% rename from src/eckit/geometry/grid/ORCA.h rename to src/eckit/geometry/grid/unstructured/ORCA.h index 7fd3e280d..018c03980 100644 --- a/src/eckit/geometry/grid/ORCA.h +++ b/src/eckit/geometry/grid/unstructured/ORCA.h @@ -16,7 +16,7 @@ #include #include -#include "eckit/geometry/Grid.h" +#include "eckit/geometry/grid/Unstructured.h" namespace eckit { @@ -24,10 +24,10 @@ class PathName; } -namespace eckit::geometry::grid { +namespace eckit::geometry::grid::unstructured { -class ORCA final : public Grid { +class ORCA final : public Unstructured { public: // -- Types @@ -40,27 +40,6 @@ class ORCA final : public Grid { W, }; - class Iterator final : public geometry::Iterator { - public: - explicit Iterator(const Grid&, size_t index = 0); - - private: - bool operator==(const geometry::Iterator&) const override; - bool operator++() override; - bool operator+=(diff_t) override; - explicit operator bool() const override; - Point operator*() const override; - - size_t index() const override { return index_; } - - size_t index_; - const size_t index_size_; - - const std::vector& longitudes_; - const std::vector& latitudes_; - const std::string uid_; - }; - // -- Exceptions // None @@ -69,7 +48,8 @@ class ORCA final : public Grid { explicit ORCA(const Configuration&); // -- Destructor - // None + + ~ORCA() override = default; // -- Convertors // None @@ -79,10 +59,33 @@ class ORCA final : public Grid { // -- Methods - std::string uid() const; + uid_t calculate_uid() const; + + void read(const PathName&); + void check(const Configuration&); + size_t write(const PathName&, const std::string& compression = "none"); + + size_t ni() const { return static_cast(dimensions_[0]); } + size_t nj() const { return static_cast(dimensions_[1]); } // -- Overridden methods - // None + + iterator cbegin() const override; + iterator cend() const override; + + const area::BoundingBox& boundingBox() const override; + + size_t size() const override { return ni() * nj(); } + uid_t uid() const override { return uid_; } + + bool includesNorthPole() const override { return true; } + bool includesSouthPole() const override { return true; } // FIXME: not sure this is semanticaly correct + bool isPeriodicWestEast() const override { return true; } + + std::pair, std::vector> to_latlon() const override; + + const std::vector& longitudes() const override { return longitudes_; } + const std::vector& latitudes() const override { return latitudes_; } // -- Class members @@ -95,7 +98,7 @@ class ORCA final : public Grid { // -- Members std::string name_; - std::string uid_; + uid_t uid_; Arrangement arrangement_; std::array dimensions_; @@ -106,28 +109,10 @@ class ORCA final : public Grid { std::vector flags_; // -- Methods - - void read(const PathName&); - void check(const Configuration&); - size_t write(const PathName&, const std::string& compression = "none"); - - size_t ni() const { return static_cast(dimensions_[0]); } - size_t nj() const { return static_cast(dimensions_[1]); } + // None // -- Overridden methods - - iterator cbegin() const override; - iterator cend() const override; - - const area::BoundingBox& boundingBox() const override; - - size_t size() const override { return ni() * nj(); } - - bool includesNorthPole() const override { return true; } - bool includesSouthPole() const override { return true; } // FIXME: not sure this is semanticaly correct - bool isPeriodicWestEast() const override { return true; } - - std::pair, std::vector> to_latlon() const override; + // None // -- Class members // None @@ -140,4 +125,4 @@ class ORCA final : public Grid { }; -} // namespace eckit::geometry::grid +} // namespace eckit::geometry::grid::unstructured diff --git a/src/eckit/geometry/iterator/ListI.cc b/src/eckit/geometry/iterator/ListI.cc deleted file mode 100644 index 838b930b1..000000000 --- a/src/eckit/geometry/iterator/ListI.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/iterator/ListI.h" - -#include "eckit/geometry/Grid.h" -#include "eckit/geometry/grid/UnstructuredGrid.h" - - -namespace eckit::geometry::iterator { - - -ListI::ListI(const Grid& grid, size_t index) : - Iterator(grid), - latitudes_(dynamic_cast(grid).latitudes_), - longitudes_(dynamic_cast(grid).longitudes_), - size_(grid.size()), - index_(index) { -} - - -bool ListI::operator==(const Iterator& other) const { - const auto* another = dynamic_cast(&other); - return another != nullptr && latitudes_.data() == another->latitudes_.data() && longitudes_.data() == another->longitudes_.data() && index_ == another->index_; -} - - -bool ListI::operator++() { - index_++; - return operator bool(); -} - - -bool ListI::operator+=(diff_t d) { - auto i = static_cast(index_); - ASSERT(static_cast(i) == index_); - index_ = i + d < 0 ? size_ : static_cast(i + d); - return operator bool(); -} - - -ListI::operator bool() const { - return index_ < size_; -} - - -Point ListI::operator*() const { - ASSERT(operator bool()); - return PointLonLat{longitudes_[index_], latitudes_[index_]}; -} - - -size_t ListI::index() const { - return index_; -} - - -} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/iterator/ListIListJ.cc b/src/eckit/geometry/iterator/ListIListJ.cc deleted file mode 100644 index 5a9f9481d..000000000 --- a/src/eckit/geometry/iterator/ListIListJ.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/iterator/ListIListJ.h" - -#include "eckit/exception/Exceptions.h" - - -namespace eckit::geometry::iterator { - - -ListIListJ::ListIListJ(const Grid& grid) : - Iterator(grid), - ni_(0), // size_t ni - nj_(0), // size_t nj - north_(0), // double north - west_(0), // double west - we_(0), // double we - ns_(0), // double ns - i_(0), - j_(0), - lat_(north_), - lon_(west_), - count_(0), - first_(true), - p_(PointLonLat{0, 0}) { - latValue_ = lat_; - lonValue_ = lon_; -} - - -bool ListIListJ::operator==(const Iterator&) const { - NOTIMP; -} - - -bool ListIListJ::operator++() { - if (j_ < nj_) { - if (i_ < ni_) { - p_ = PointLonLat{lonValue_, latValue_}; - - lon_ += we_; - - if (first_) { - first_ = false; - } - else { - count_++; - } - - if (++i_ == ni_) { - j_++; - i_ = 0; - lat_ -= ns_; - lon_ = west_; - latValue_ = lat_; - } - - lonValue_ = lon_; - - return true; - } - } - return false; -} - - -bool ListIListJ::operator+=(diff_t) { - NOTIMP; -} - - -ListIListJ::operator bool() const { - NOTIMP; -} - - -Point ListIListJ::operator*() const { - NOTIMP; -} - - -size_t ListIListJ::index() const { - NOTIMP; -} - - -} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/iterator/Reduced.cc b/src/eckit/geometry/iterator/Reduced.cc new file mode 100644 index 000000000..7bf3654ca --- /dev/null +++ b/src/eckit/geometry/iterator/Reduced.cc @@ -0,0 +1,96 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/iterator/Reduced.h" + +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geometry/grid/Reduced.h" + + +namespace eckit::geometry::iterator { + + +Reduced::Reduced(const Grid& grid, size_t index) : + geometry::Iterator(grid), + grid_(dynamic_cast(grid)), + latitudes_(grid_.latitudes()), + niacc_(grid_.niacc()), + index_(index), + index_size_(grid.size()) { + if (index_ < index_size_) { + longitudes_j_ = grid_.longitudes(j_ = j(index_)); + ASSERT(niacc_[j_] <= index && index_ < niacc_[j_ + 1]); + ASSERT(latitudes_.size() == grid_.nj()); + } +} + + +bool Reduced::operator==(const Iterator& other) const { + const auto* another = dynamic_cast(&other); + return another != nullptr && index_ == another->index_; +} + + +bool Reduced::operator++() { + if (index_++; index_ < index_size_) { + if (!(index_ < niacc_[j_ + 1])) { + longitudes_j_ = grid_.longitudes(++j_); + } + + ASSERT(niacc_[j_] <= index_ && index_ < niacc_[j_ + 1]); + return true; + } + + index_ = index_size_; // ensure it's invalid + return false; +} + + +bool Reduced::operator+=(diff_t d) { + if (auto di = static_cast(index_); 0 <= di + d && di + d < static_cast(index_size_)) { + if (index_ = static_cast(di + d); !(niacc_[j_] <= index_ && index_ < niacc_[j_ + 1])) { + longitudes_j_ = grid_.longitudes(j_ = j(index_)); + } + + ASSERT(niacc_[j_] <= index_ && index_ < niacc_[j_ + 1]); + return true; + } + + index_ = index_size_; // ensure it's invalid + return false; +} + + +Reduced::operator bool() const { + return index_ < index_size_; +} + + +Point Reduced::operator*() const { + return PointLonLat{longitudes_j_.at(index_ - niacc_[j_]), latitudes_.at(j_)}; +} + + +size_t Reduced::j(size_t idx) const { + ASSERT(idx < index_size_); + + auto dist = std::distance(niacc_.begin(), std::upper_bound(niacc_.begin(), niacc_.end(), idx)); + ASSERT(1 <= dist && dist <= niacc_.size() - 1); + + return static_cast(dist - 1); +} + + +} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/iterator/ListIListJ.h b/src/eckit/geometry/iterator/Reduced.h similarity index 73% rename from src/eckit/geometry/iterator/ListIListJ.h rename to src/eckit/geometry/iterator/Reduced.h index fb793af2b..6a55de6bc 100644 --- a/src/eckit/geometry/iterator/ListIListJ.h +++ b/src/eckit/geometry/iterator/Reduced.h @@ -13,13 +13,17 @@ #pragma once #include "eckit/geometry/Iterator.h" -#include "eckit/types/Fraction.h" + + +namespace eckit::geometry::grid { +class Reduced; +} namespace eckit::geometry::iterator { -class ListIListJ final : public Iterator { +class Reduced final : public geometry::Iterator { public: // -- Types // None @@ -29,7 +33,7 @@ class ListIListJ final : public Iterator { // -- Constructors - explicit ListIListJ(const Grid&); + explicit Reduced(const Grid&, size_t index = 0); // -- Destructor // None @@ -55,35 +59,29 @@ class ListIListJ final : public Iterator { private: // -- Members - size_t ni_; - size_t nj_; - Fraction north_; - Fraction west_; - Fraction we_; - Fraction ns_; - size_t i_; + const grid::Reduced& grid_; + std::vector longitudes_j_; + const std::vector& latitudes_; + const std::vector& niacc_; size_t j_; - double latValue_; - double lonValue_; - Fraction lat_; - Fraction lon_; - size_t count_; - bool first_; - Point p_; + size_t index_; + const size_t index_size_; // -- Methods // None - // -- Overridden methods + // -- Overridden operators bool operator==(const Iterator&) const override; bool operator++() override; bool operator+=(diff_t) override; - explicit operator bool() const override; Point operator*() const override; - size_t index() const override; + // -- Overridden methods + + size_t index() const override { return index_; } + size_t j(size_t idx) const; // -- Class members // None diff --git a/src/eckit/geometry/iterator/ReducedIListJ.cc b/src/eckit/geometry/iterator/ReducedIListJ.cc deleted file mode 100644 index c4d07375c..000000000 --- a/src/eckit/geometry/iterator/ReducedIListJ.cc +++ /dev/null @@ -1,132 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/iterator/ReducedIListJ.h" - -#include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Grid.h" - - -namespace eckit::geometry::iterator { - - -// FIXME -static const std::vector __latitudes; -static const area::BoundingBox __bbox; -static const pl_type __pl; - - -ReducedIListJ::ReducedIListJ( - const Grid& grid) : - Iterator(grid), - latitudes_(__latitudes), // const std::vector& latitudes - pl_(__pl), // pl_type&& pl - bbox_(__bbox), // const area::BoundingBox& bbox - N_(0), // size_t N - Ni_(0), - Nj_(0), // size_t Nj - lon_(0), - lat_(0), // lat_(latitudes[k]) - i_(0), - j_(0), - k_(0), // size_t k - count_(0), - first_(true), - p_(PointLonLat{0, 0}), - size_(grid.size()) { - // NOTE: latitudes_ span the globe, sorted from North-to-South, k_ positions the North - // NOTE: pl is global - ASSERT(N_ * 2 == latitudes_.size()); - ASSERT(Nj_ > 0); -} - - -size_t ReducedIListJ::resetToRow(size_t j) { - ASSERT(j < latitudes_.size()); - lat_ = latitudes_[j]; - - auto Ni_globe = static_cast(pl_[j]); - ASSERT(Ni_globe > 1); - - inc_ = {360, Ni_globe}; - - const auto w = Fraction{bbox_.west()}; - auto Nw = (w / inc_).integralPart(); - if (Nw * inc_ < w) { - Nw += 1; - } - - const auto e = Fraction{bbox_.east()}; - auto Ne = (e / inc_).integralPart(); - if (Ne * inc_ > e) { - Ne -= 1; - } - - lon_ = Nw * inc_; - return Nw > Ne ? 0 : std::min(static_cast(Ni_globe), static_cast(Ne - Nw + 1)); -} - - -bool ReducedIListJ::operator==(const Iterator&) const { - NOTIMP; -} - - -bool ReducedIListJ::operator++() { - while (Ni_ == 0 && j_ < Nj_) { - Ni_ = resetToRow(k_ + j_++); - } - - if (0 < Nj_ && i_ < Ni_) { - p_ = PointLonLat{lon_, lat_}; - - lon_ += inc_; - - if (first_) { - first_ = false; - } - else { - count_++; - } - - if (++i_ == Ni_) { - i_ = 0; - Ni_ = 0; - } - - return true; - } - return false; -} - - -bool ReducedIListJ::operator+=(diff_t) { - NOTIMP; -} - - -ReducedIListJ::operator bool() const { - NOTIMP; -} - - -Point ReducedIListJ::operator*() const { - NOTIMP; -} - - -size_t ReducedIListJ::index() const { - return count_; -} - - -} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/iterator/Regular.cc b/src/eckit/geometry/iterator/Regular.cc new file mode 100644 index 000000000..eedc3fae8 --- /dev/null +++ b/src/eckit/geometry/iterator/Regular.cc @@ -0,0 +1,75 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/iterator/Regular.h" + +#include "eckit/exception/Exceptions.h" +#include "eckit/geometry/grid/Regular.h" + + +namespace eckit::geometry::iterator { + + +Regular::Regular(const Grid& grid, size_t index) : + geometry::Iterator(grid), + grid_(dynamic_cast(grid)), + longitudes_(grid_.longitudes()), + latitudes_(grid_.latitudes()), + i_(0), + j_(0), + index_(index), + ni_(grid_.ni()), + nj_(grid_.nj()), + index_size_(ni_ * nj_) { + if (index_ < index_size_) { + ASSERT(latitudes_.size() == grid_.nj()); + } +} + + +bool Regular::operator==(const Iterator& other) const { + const auto* another = dynamic_cast(&other); + return another != nullptr && index_ == another->index_; +} + + +bool Regular::operator++() { + if (index_++, i_++; index_ < index_size_) { + if (i_ >= ni_) { + i_ = 0; + j_++; + } + + return true; + } + + index_ = index_size_; // ensure it's invalid + return false; +} + + +bool Regular::operator+=(diff_t d) { + NOTIMP; +} + + +Regular::operator bool() const { + return index_ < index_size_; +} + + +Point Regular::operator*() const { + return PointLonLat{longitudes_.at(i_), latitudes_.at(j_)}; +} + + +} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/iterator/ListI.h b/src/eckit/geometry/iterator/Regular.h similarity index 80% rename from src/eckit/geometry/iterator/ListI.h rename to src/eckit/geometry/iterator/Regular.h index 5f36217a3..1ff22b59d 100644 --- a/src/eckit/geometry/iterator/ListI.h +++ b/src/eckit/geometry/iterator/Regular.h @@ -15,10 +15,15 @@ #include "eckit/geometry/Iterator.h" +namespace eckit::geometry::grid { +class Regular; +} + + namespace eckit::geometry::iterator { -class ListI final : public Iterator { +class Regular final : public Iterator { public: // -- Types // None @@ -28,7 +33,7 @@ class ListI final : public Iterator { // -- Constructors - explicit ListI(const Grid&, size_t index = 0); + explicit Regular(const Grid&, size_t index = 0); // -- Destructor // None @@ -54,10 +59,15 @@ class ListI final : public Iterator { private: // -- Members - const std::vector& latitudes_; + const grid::Regular& grid_; const std::vector& longitudes_; - const size_t size_; + const std::vector& latitudes_; + size_t i_; + size_t j_; size_t index_; + const size_t ni_; + const size_t nj_; + const size_t index_size_; // -- Methods // None @@ -67,11 +77,10 @@ class ListI final : public Iterator { bool operator==(const Iterator&) const override; bool operator++() override; bool operator+=(diff_t) override; - explicit operator bool() const override; Point operator*() const override; - size_t index() const override; + size_t index() const override { return index_; } // -- Class members // None diff --git a/src/eckit/geometry/iterator/Unstructured.cc b/src/eckit/geometry/iterator/Unstructured.cc new file mode 100644 index 000000000..ab5379403 --- /dev/null +++ b/src/eckit/geometry/iterator/Unstructured.cc @@ -0,0 +1,71 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/iterator/Unstructured.h" + +#include "eckit/geometry/Grid.h" +#include "eckit/geometry/grid/Unstructured.h" + + +namespace eckit::geometry::iterator { + + +Unstructured::Unstructured(const Grid& grid, size_t index) : + geometry::Iterator(grid), + index_(index), + index_size_(grid.size()), + longitudes_(dynamic_cast(grid).longitudes()), + latitudes_(dynamic_cast(grid).latitudes()), + uid_(dynamic_cast(grid).uid()) { + ASSERT(index_size_ == longitudes_.size()); + ASSERT(index_size_ == latitudes_.size()); +} + + +bool Unstructured::operator==(const geometry::Iterator& other) const { + const auto* another = dynamic_cast(&other); + return another != nullptr && index_ == another->index_ && uid_ == another->uid_; +} + + +bool Unstructured::operator++() { + if (index_++; index_ < index_size_) { + return true; + } + + index_ = index_size_; // ensure it's invalid + return false; +} + + +bool Unstructured::operator+=(diff_t d) { + if (auto di = static_cast(index_); 0 <= di + d && di + d < static_cast(index_size_)) { + index_ = static_cast(di + d); + return true; + } + + index_ = index_size_; // ensure it's invalid + return false; +} + + +Unstructured::operator bool() const { + return index_ < index_size_; +} + + +Point Unstructured::operator*() const { + return PointLonLat{longitudes_.at(index_), latitudes_.at(index_)}; +} + + +} // namespace eckit::geometry::iterator diff --git a/src/eckit/geometry/iterator/ReducedIListJ.h b/src/eckit/geometry/iterator/Unstructured.h similarity index 67% rename from src/eckit/geometry/iterator/ReducedIListJ.h rename to src/eckit/geometry/iterator/Unstructured.h index 5f1edd986..b3f998c1a 100644 --- a/src/eckit/geometry/iterator/ReducedIListJ.h +++ b/src/eckit/geometry/iterator/Unstructured.h @@ -13,15 +13,12 @@ #pragma once #include "eckit/geometry/Iterator.h" -#include "eckit/geometry/area/BoundingBox.h" -#include "eckit/geometry/util.h" -#include "eckit/types/Fraction.h" namespace eckit::geometry::iterator { -class ReducedIListJ : public Iterator { +class Unstructured final : public Iterator { public: // -- Types // None @@ -31,7 +28,7 @@ class ReducedIListJ : public Iterator { // -- Constructors - explicit ReducedIListJ(const Grid&); + explicit Unstructured(const Grid&, size_t index = 0); // -- Destructor // None @@ -45,6 +42,9 @@ class ReducedIListJ : public Iterator { // -- Methods // None + // -- Overridden operators + // None + // -- Overridden methods // None @@ -57,37 +57,26 @@ class ReducedIListJ : public Iterator { private: // -- Members + size_t index_; + const size_t index_size_; + + const std::vector& longitudes_; const std::vector& latitudes_; - const pl_type pl_; - const area::BoundingBox& bbox_; - const size_t N_; - size_t Ni_; - size_t Nj_; - Fraction lon_; - double lat_; - Fraction inc_; - size_t i_; - size_t j_; - size_t k_; - size_t count_; - bool first_; - Point p_; - const size_t size_; + const std::string uid_; // -- Methods - - size_t resetToRow(size_t); + // None // -- Overridden methods - bool operator==(const Iterator&) const override; + bool operator==(const geometry::Iterator&) const override; bool operator++() override; bool operator+=(diff_t) override; explicit operator bool() const override; Point operator*() const override; - size_t index() const override; + size_t index() const override { return index_; } // -- Class members // None diff --git a/src/eckit/geometry/range/Gaussian.cc b/src/eckit/geometry/range/Gaussian.cc new file mode 100644 index 000000000..71378bac5 --- /dev/null +++ b/src/eckit/geometry/range/Gaussian.cc @@ -0,0 +1,84 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/range/Gaussian.h" + +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geometry/util.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geometry::range { + + +Gaussian::Gaussian(size_t N) : + Gaussian(N, 90., -90) { +} + + +Gaussian::Gaussian(size_t N, double a, double b, double precision) : + Range(2 * N), + N_(N), + a_(a), + b_(b), + precision_(precision) { + ASSERT(N > 0); + ASSERT(precision_ >= 0.); +} + + +const std::vector& Gaussian::values() const { + if (empty()) { + auto& v = const_cast&>(valuesVector()); + v = util::gaussian_latitudes(N_, a_ < b_); + ASSERT(v.size() == 2 * N_); + + const bool same(a_ == b_); + + auto a = a_; + auto b = b_; + + if (a < v.back()) { + a = v.back(); + } + else { + auto best = std::lower_bound(v.begin(), v.end(), a, [&](double l1, double l2) { + return !types::is_approximately_equal(l1, l2, precision_) && !(l1 < l2); + }); + ASSERT(best != v.end()); + a = *best; + } + + if (same) { + b = a; + } + else if (b > v.front()) { + b = v.front(); + } + else { + auto best = std::lower_bound(v.rbegin(), v.rend(), b, [&](double l1, double l2) { + return !types::is_approximately_equal(l1, l2, precision_) && !(l1 > l2); + }); + ASSERT(best != v.rend()); + b = *best; + } + + ASSERT((a_ <= b_) == (a <= b)); + } + + return *this; +} + + +} // namespace eckit::geometry::range diff --git a/src/eckit/geometry/grid/ReducedLL.h b/src/eckit/geometry/range/Gaussian.h similarity index 64% rename from src/eckit/geometry/grid/ReducedLL.h rename to src/eckit/geometry/range/Gaussian.h index a6f1c0292..d8206398c 100644 --- a/src/eckit/geometry/grid/ReducedLL.h +++ b/src/eckit/geometry/range/Gaussian.h @@ -12,24 +12,27 @@ #pragma once -#include "eckit/geometry/Grid.h" +#include "eckit/geometry/Range.h" -namespace eckit::geometry::grid { +namespace eckit::geometry::range { -class ReducedLL : public Grid { +class Gaussian final : public Range { public: + // -- Types + // None + // -- Exceptions // None // -- Constructors - ReducedLL(const Configuration&); + explicit Gaussian(size_t N); + Gaussian(size_t N, double a, double b, double precision = 0.); // -- Destructor - - ~ReducedLL() override; + // None // -- Convertors // None @@ -38,7 +41,9 @@ class ReducedLL : public Grid { // None // -- Methods - // None + + size_t N() const { return N_; } + const std::vector& values() const override; // -- Overridden methods // None @@ -52,21 +57,16 @@ class ReducedLL : public Grid { private: // -- Members - std::vector pl_; + const size_t N_; + const double a_; + const double b_; + const double precision_; // -- Methods // None // -- Overridden methods - - size_t size() const override; - - bool isPeriodicWestEast() const override; - bool includesNorthPole() const override; - bool includesSouthPole() const override; - - iterator cbegin() const override { NOTIMP; } - iterator cend() const override { NOTIMP; } + // None // -- Class members // None @@ -79,4 +79,4 @@ class ReducedLL : public Grid { }; -} // namespace eckit::geometry::grid +} // namespace eckit::geometry::range diff --git a/src/eckit/geometry/range/GlobalRegular.cc b/src/eckit/geometry/range/GlobalRegular.cc new file mode 100644 index 000000000..d9e98b433 --- /dev/null +++ b/src/eckit/geometry/range/GlobalRegular.cc @@ -0,0 +1,43 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/range/GlobalRegular.h" + +#include "eckit/geometry/util.h" + + +namespace eckit::geometry::range { + + +GlobalRegular::GlobalRegular(size_t n, double a, double b, double precision) : + Range(n), + a_(a), + b_(b), + precision_(precision) { +} + + +const std::vector& GlobalRegular::values() const { + if (empty()) { + auto& v = const_cast&>(valuesVector()); + v = util::linspace(0., 360., size(), false); + + auto mm = util::monotonic_crop(v, a_, b_, 1e-3); + v.erase(mm.second, v.end()); + v.erase(v.begin(), mm.first); + } + + return *this; +} + + +} // namespace eckit::geometry::range diff --git a/src/eckit/geometry/grid/IrregularLatlon.h b/src/eckit/geometry/range/GlobalRegular.h similarity index 70% rename from src/eckit/geometry/grid/IrregularLatlon.h rename to src/eckit/geometry/range/GlobalRegular.h index f1dea1891..8909ab615 100644 --- a/src/eckit/geometry/grid/IrregularLatlon.h +++ b/src/eckit/geometry/range/GlobalRegular.h @@ -12,20 +12,23 @@ #pragma once -#include "eckit/geometry/Grid.h" +#include "eckit/geometry/Range.h" -namespace eckit::geometry::grid { +namespace eckit::geometry::range { -class IrregularLatlon final : public Grid { +class GlobalRegular final : public Range { public: + // -- Types + // None + // -- Exceptions // None // -- Constructors - explicit IrregularLatlon(const Configuration&); + GlobalRegular(size_t n, double a, double b, double precision = 0.); // -- Destructor // None @@ -38,6 +41,8 @@ class IrregularLatlon final : public Grid { // -- Methods + const std::vector& values() const override; + // -- Overridden methods // None @@ -50,18 +55,15 @@ class IrregularLatlon final : public Grid { private: // -- Members - std::vector latitudes_; - std::vector longitudes_; + const double a_; + const double b_; + const double precision_; // -- Methods // None // -- Overridden methods - - iterator cbegin() const override; - iterator cend() const override; - - size_t size() const override; + // None // -- Class members // None @@ -74,4 +76,4 @@ class IrregularLatlon final : public Grid { }; -} // namespace eckit::geometry::grid +} // namespace eckit::geometry::range diff --git a/src/eckit/geometry/range/LocalRegular.cc b/src/eckit/geometry/range/LocalRegular.cc new file mode 100644 index 000000000..34de92f5d --- /dev/null +++ b/src/eckit/geometry/range/LocalRegular.cc @@ -0,0 +1,40 @@ +/* + * (C) Copyright 1996- 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 "eckit/geometry/range/LocalRegular.h" + +#include "eckit/geometry/util.h" + + +namespace eckit::geometry::range { + + +LocalRegular::LocalRegular(size_t n, double a, double b, bool endpoint, double precision) : + Range(n), + a_(a), + b_(b), + endpoint_(endpoint), + precision_(precision) { +} + + +const std::vector& LocalRegular::values() const { + if (empty()) { + auto& v = const_cast&>(valuesVector()); + v = util::linspace(a_, b_, size(), endpoint_); + } + + return *this; +} + + +} // namespace eckit::geometry::range diff --git a/src/eckit/geometry/range/LocalRegular.h b/src/eckit/geometry/range/LocalRegular.h new file mode 100644 index 000000000..e1eb93518 --- /dev/null +++ b/src/eckit/geometry/range/LocalRegular.h @@ -0,0 +1,80 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geometry/Range.h" + + +namespace eckit::geometry::range { + + +class LocalRegular final : public Range { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + LocalRegular(size_t n, double a, double b, bool endpoint, double precision = 0.); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + const std::vector& values() const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + const double a_; + const double b_; + const bool endpoint_; + const double precision_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geometry::range diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index 998942595..dd3ea720f 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -16,7 +16,7 @@ #include "eckit/geometry/Grid.h" #include "eckit/geometry/Point.h" #include "eckit/geometry/Search.h" -#include "eckit/geometry/grid/UnstructuredGrid.h" +#include "eckit/geometry/grid/Unstructured.h" #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" #include "eckit/option/EckitTool.h" From 20e250d1f07b5e1f4ee3e463560dfe8517b1decd Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 26 Aug 2023 12:25:46 +0100 Subject: [PATCH 323/737] eckit::geo --- CMakeLists.txt | 17 +- etc/eckit/CMakeLists.txt | 2 +- etc/eckit/{geometry => geo}/CMakeLists.txt | 2 +- etc/eckit/{geometry => geo}/grid.yaml | 0 src/eckit/CMakeLists.txt | 23 +- src/eckit/{geometry => geo}/Area.h | 4 +- src/eckit/geo/CMakeLists.txt | 130 ++++++ src/eckit/{geometry => geo}/Cache.cc | 6 +- src/eckit/{geometry => geo}/Cache.h | 4 +- src/eckit/{geometry => geo}/Configurator.h | 4 +- src/eckit/geo/CoordinateHelpers.cc | 55 +++ src/eckit/geo/CoordinateHelpers.h | 47 +++ src/eckit/{geometry => geo}/Domain.cc | 12 +- src/eckit/{geometry => geo}/Domain.h | 4 +- src/eckit/{geometry => geo}/Earth.h | 6 +- src/eckit/geo/EllipsoidOfRevolution.cc | 65 +++ src/eckit/geo/EllipsoidOfRevolution.h | 38 ++ src/eckit/{geometry => geo}/Figure.h | 4 +- src/eckit/geo/GreatCircle.cc | 122 ++++++ src/eckit/geo/GreatCircle.h | 48 +++ src/eckit/{geometry => geo}/Grid.cc | 8 +- src/eckit/{geometry => geo}/Grid.h | 24 +- src/eckit/{geometry => geo}/GridConfig.cc | 14 +- src/eckit/{geometry => geo}/GridConfig.h | 4 +- src/eckit/{geometry => geo}/Increments.h | 4 +- src/eckit/{geometry => geo}/Iterator.h | 8 +- src/eckit/geo/KPoint.cc | 27 ++ src/eckit/geo/KPoint.h | 282 +++++++++++++ .../LibEcKitGeo.cc} | 32 +- .../LibEcKitGeometry.h => geo/LibEcKitGeo.h} | 6 +- src/eckit/{geometry => geo}/Ordering.h | 4 +- src/eckit/{geometry => geo}/Point.cc | 6 +- src/eckit/{geometry => geo}/Point.h | 10 +- src/eckit/geo/Point2.cc | 37 ++ src/eckit/geo/Point2.h | 101 +++++ src/eckit/geo/Point3.cc | 31 ++ src/eckit/geo/Point3.h | 95 +++++ src/eckit/{geometry => geo}/PointLonLat.cc | 6 +- src/eckit/{geometry => geo}/PointLonLat.h | 4 +- src/eckit/{geometry => geo}/Projection.h | 6 +- src/eckit/{geometry => geo}/Range.cc | 6 +- src/eckit/{geometry => geo}/Range.h | 4 +- src/eckit/{geometry => geo}/Renumber.h | 4 +- src/eckit/{geometry => geo}/Search.h | 14 +- src/eckit/geo/Sphere.cc | 215 ++++++++++ src/eckit/geo/Sphere.h | 62 +++ src/eckit/geo/SphereT.h | 88 ++++ src/eckit/geo/UnitSphere.h | 36 ++ .../{geometry => geo}/area/BoundingBox.cc | 12 +- .../{geometry => geo}/area/BoundingBox.h | 10 +- src/eckit/geo/eckit_geo_config.h.in | 5 + src/eckit/{geometry => geo}/grid/Reduced.cc | 6 +- src/eckit/{geometry => geo}/grid/Reduced.h | 10 +- src/eckit/{geometry => geo}/grid/Regular.cc | 6 +- src/eckit/{geometry => geo}/grid/Regular.h | 10 +- .../{geometry => geo}/grid/Unstructured.cc | 12 +- .../{geometry => geo}/grid/Unstructured.h | 10 +- .../{geometry => geo}/grid/reduced/HEALPix.cc | 14 +- .../{geometry => geo}/grid/reduced/HEALPix.h | 6 +- .../grid/reduced/ReducedGaussian.cc | 16 +- .../grid/reduced/ReducedGaussian.h | 10 +- .../grid/reduced/ReducedLatLon.cc | 12 +- .../grid/reduced/ReducedLatLon.h | 6 +- .../grid/regular/IrregularLatLon.cc | 6 +- .../grid/regular/IrregularLatLon.h | 6 +- .../grid/regular/RegularGaussian.cc | 16 +- .../grid/regular/RegularGaussian.h | 8 +- .../grid/regular/RegularLatLon.cc | 12 +- .../grid/regular/RegularLatLon.h | 6 +- .../grid/unstructured/ORCA.cc | 20 +- .../grid/unstructured/ORCA.h | 6 +- .../{geometry => geo}/iterator/Reduced.cc | 10 +- .../{geometry => geo}/iterator/Reduced.h | 10 +- .../{geometry => geo}/iterator/Regular.cc | 10 +- .../{geometry => geo}/iterator/Regular.h | 8 +- .../iterator/Unstructured.cc | 14 +- .../{geometry => geo}/iterator/Unstructured.h | 8 +- src/eckit/geo/polygon/LonLatPolygon.cc | 175 ++++++++ src/eckit/geo/polygon/LonLatPolygon.h | 82 ++++ src/eckit/geo/polygon/Polygon.cc | 66 +++ src/eckit/geo/polygon/Polygon.h | 55 +++ .../projection/LonLatToXYZ.cc | 10 +- .../projection/LonLatToXYZ.h | 6 +- .../{geometry => geo}/projection/None.cc | 6 +- src/eckit/{geometry => geo}/projection/None.h | 6 +- .../{geometry => geo}/projection/PROJ.cc | 6 +- src/eckit/{geometry => geo}/projection/PROJ.h | 6 +- .../{geometry => geo}/projection/Rotation.cc | 10 +- .../{geometry => geo}/projection/Rotation.h | 6 +- src/eckit/{geometry => geo}/range/Gaussian.cc | 8 +- src/eckit/{geometry => geo}/range/Gaussian.h | 6 +- .../{geometry => geo}/range/GlobalRegular.cc | 8 +- .../{geometry => geo}/range/GlobalRegular.h | 6 +- .../{geometry => geo}/range/LocalRegular.cc | 8 +- .../{geometry => geo}/range/LocalRegular.h | 6 +- src/eckit/{geometry => geo}/util.cc | 6 +- src/eckit/{geometry => geo}/util.h | 4 +- src/eckit/{geometry => geo}/util/arange.cc | 4 +- .../util/gaussian_latitudes.cc | 4 +- src/eckit/{geometry => geo}/util/linspace.cc | 4 +- .../{geometry => geo}/util/monotonic_crop.cc | 4 +- .../util/reduced_classical_pl.cc | 6 +- .../util/reduced_octahedral_pl.cc | 6 +- src/eckit/{geometry => geo}/util/regex.cc | 6 +- src/eckit/{geometry => geo}/util/regex.h | 4 +- src/eckit/geometry/CMakeLists.txt | 155 ++----- src/eckit/geometry/EllipsoidOfRevolution.cc | 49 ++- src/eckit/geometry/EllipsoidOfRevolution.h | 13 +- src/eckit/geometry/GreatCircle.cc | 76 ++-- src/eckit/geometry/GreatCircle.h | 9 +- src/eckit/geometry/KPoint.h | 7 +- src/eckit/geometry/Point2.cc | 21 +- src/eckit/geometry/Point2.h | 57 +-- src/eckit/geometry/Point3.cc | 16 +- src/eckit/geometry/Point3.h | 56 +-- src/eckit/geometry/Sphere.cc | 138 +++---- src/eckit/geometry/Sphere.h | 65 +-- src/eckit/geometry/SphereT.h | 64 +-- src/eckit/geometry/UnitSphere.h | 11 +- src/eckit/geometry/eckit_geometry_config.h.in | 5 - src/eckit/maths/CMakeLists.txt | 20 +- src/eckit/maths/Matrix3.h | 4 +- src/tools/CMakeLists.txt | 8 +- src/tools/eckit-grid-list.cc | 4 +- src/tools/eckit-grid.cc | 16 +- tests/CMakeLists.txt | 6 +- tests/geo/CMakeLists.txt | 21 + tests/geo/test_coordinate_helpers.cc | 68 +++ tests/geo/test_great_circle.cc | 238 +++++++++++ tests/{geometry => geo}/test_grid.cc | 8 +- tests/{geometry => geo}/test_iterator.cc | 8 +- tests/geo/test_kdtree.cc | 374 +++++++++++++++++ tests/geo/test_kpoint.cc | 115 ++++++ tests/{geometry => geo}/test_param.cc | 0 tests/geo/test_points.cc | 156 +++++++ tests/geo/test_polygon.cc | 388 ++++++++++++++++++ tests/{geometry => geo}/test_projection.cc | 15 +- tests/{geometry => geo}/test_search.cc | 4 +- tests/geo/test_sphere.cc | 278 +++++++++++++ tests/{geometry => geo}/test_types.cc | 4 +- tests/{geometry => geo}/test_util.cc | 4 +- tests/geometry/CMakeLists.txt | 24 +- tests/geometry/test_great_circle.cc | 24 +- tests/geometry/test_kdtree.cc | 2 +- tests/geometry/test_sphere.cc | 232 +++++++---- 145 files changed, 4356 insertions(+), 947 deletions(-) rename etc/eckit/{geometry => geo}/CMakeLists.txt (88%) rename etc/eckit/{geometry => geo}/grid.yaml (100%) rename src/eckit/{geometry => geo}/Area.h (96%) create mode 100644 src/eckit/geo/CMakeLists.txt rename src/eckit/{geometry => geo}/Cache.cc (88%) rename src/eckit/{geometry => geo}/Cache.h (92%) rename src/eckit/{geometry => geo}/Configurator.h (99%) create mode 100644 src/eckit/geo/CoordinateHelpers.cc create mode 100644 src/eckit/geo/CoordinateHelpers.h rename src/eckit/{geometry => geo}/Domain.cc (93%) rename src/eckit/{geometry => geo}/Domain.h (97%) rename src/eckit/{geometry => geo}/Earth.h (88%) create mode 100644 src/eckit/geo/EllipsoidOfRevolution.cc create mode 100644 src/eckit/geo/EllipsoidOfRevolution.h rename src/eckit/{geometry => geo}/Figure.h (96%) create mode 100644 src/eckit/geo/GreatCircle.cc create mode 100644 src/eckit/geo/GreatCircle.h rename src/eckit/{geometry => geo}/Grid.cc (95%) rename src/eckit/{geometry => geo}/Grid.h (90%) rename src/eckit/{geometry => geo}/GridConfig.cc (93%) rename src/eckit/{geometry => geo}/GridConfig.h (95%) rename src/eckit/{geometry => geo}/Increments.h (96%) rename src/eckit/{geometry => geo}/Iterator.h (94%) create mode 100644 src/eckit/geo/KPoint.cc create mode 100644 src/eckit/geo/KPoint.h rename src/eckit/{geometry/LibEcKitGeometry.cc => geo/LibEcKitGeo.cc} (50%) rename src/eckit/{geometry/LibEcKitGeometry.h => geo/LibEcKitGeo.h} (91%) rename src/eckit/{geometry => geo}/Ordering.h (96%) rename src/eckit/{geometry => geo}/Point.cc (89%) rename src/eckit/{geometry => geo}/Point.h (82%) create mode 100644 src/eckit/geo/Point2.cc create mode 100644 src/eckit/geo/Point2.h create mode 100644 src/eckit/geo/Point3.cc create mode 100644 src/eckit/geo/Point3.h rename src/eckit/{geometry => geo}/PointLonLat.cc (93%) rename src/eckit/{geometry => geo}/PointLonLat.h (97%) rename src/eckit/{geometry => geo}/Projection.h (95%) rename src/eckit/{geometry => geo}/Range.cc (86%) rename src/eckit/{geometry => geo}/Range.h (97%) rename src/eckit/{geometry => geo}/Renumber.h (88%) rename src/eckit/{geometry => geo}/Search.h (85%) create mode 100644 src/eckit/geo/Sphere.cc create mode 100644 src/eckit/geo/Sphere.h create mode 100644 src/eckit/geo/SphereT.h create mode 100644 src/eckit/geo/UnitSphere.h rename src/eckit/{geometry => geo}/area/BoundingBox.cc (95%) rename src/eckit/{geometry => geo}/area/BoundingBox.h (93%) create mode 100644 src/eckit/geo/eckit_geo_config.h.in rename src/eckit/{geometry => geo}/grid/Reduced.cc (89%) rename src/eckit/{geometry => geo}/grid/Reduced.h (89%) rename src/eckit/{geometry => geo}/grid/Regular.cc (83%) rename src/eckit/{geometry => geo}/grid/Regular.h (88%) rename src/eckit/{geometry => geo}/grid/Unstructured.cc (65%) rename src/eckit/{geometry => geo}/grid/Unstructured.h (88%) rename src/eckit/{geometry => geo}/grid/reduced/HEALPix.cc (92%) rename src/eckit/{geometry => geo}/grid/reduced/HEALPix.h (93%) rename src/eckit/{geometry => geo}/grid/reduced/ReducedGaussian.cc (86%) rename src/eckit/{geometry => geo}/grid/reduced/ReducedGaussian.h (88%) rename src/eckit/{geometry => geo}/grid/reduced/ReducedLatLon.cc (72%) rename src/eckit/{geometry => geo}/grid/reduced/ReducedLatLon.h (90%) rename src/eckit/{geometry => geo}/grid/regular/IrregularLatLon.cc (85%) rename src/eckit/{geometry => geo}/grid/regular/IrregularLatLon.h (90%) rename src/eckit/{geometry => geo}/grid/regular/RegularGaussian.cc (83%) rename src/eckit/{geometry => geo}/grid/regular/RegularGaussian.h (90%) rename src/eckit/{geometry => geo}/grid/regular/RegularLatLon.cc (72%) rename src/eckit/{geometry => geo}/grid/regular/RegularLatLon.h (90%) rename src/eckit/{geometry => geo}/grid/unstructured/ORCA.cc (91%) rename src/eckit/{geometry => geo}/grid/unstructured/ORCA.h (94%) rename src/eckit/{geometry => geo}/iterator/Reduced.cc (92%) rename src/eckit/{geometry => geo}/iterator/Reduced.h (88%) rename src/eckit/{geometry => geo}/iterator/Regular.cc (88%) rename src/eckit/{geometry => geo}/iterator/Regular.h (91%) rename src/eckit/{geometry => geo}/iterator/Unstructured.cc (84%) rename src/eckit/{geometry => geo}/iterator/Unstructured.h (89%) create mode 100644 src/eckit/geo/polygon/LonLatPolygon.cc create mode 100644 src/eckit/geo/polygon/LonLatPolygon.h create mode 100644 src/eckit/geo/polygon/Polygon.cc create mode 100644 src/eckit/geo/polygon/Polygon.h rename src/eckit/{geometry => geo}/projection/LonLatToXYZ.cc (90%) rename src/eckit/{geometry => geo}/projection/LonLatToXYZ.h (94%) rename src/eckit/{geometry => geo}/projection/None.cc (84%) rename src/eckit/{geometry => geo}/projection/None.h (90%) rename src/eckit/{geometry => geo}/projection/PROJ.cc (96%) rename src/eckit/{geometry => geo}/projection/PROJ.h (95%) rename src/eckit/{geometry => geo}/projection/Rotation.cc (95%) rename src/eckit/{geometry => geo}/projection/Rotation.h (94%) rename src/eckit/{geometry => geo}/range/Gaussian.cc (92%) rename src/eckit/{geometry => geo}/range/Gaussian.h (92%) rename src/eckit/{geometry => geo}/range/GlobalRegular.cc (85%) rename src/eckit/{geometry => geo}/range/GlobalRegular.h (91%) rename src/eckit/{geometry => geo}/range/LocalRegular.cc (84%) rename src/eckit/{geometry => geo}/range/LocalRegular.h (91%) rename src/eckit/{geometry => geo}/util.cc (81%) rename src/eckit/{geometry => geo}/util.h (96%) rename src/eckit/{geometry => geo}/util/arange.cc (93%) rename src/eckit/{geometry => geo}/util/gaussian_latitudes.cc (97%) rename src/eckit/{geometry => geo}/util/linspace.cc (92%) rename src/eckit/{geometry => geo}/util/monotonic_crop.cc (95%) rename src/eckit/{geometry => geo}/util/reduced_classical_pl.cc (99%) rename src/eckit/{geometry => geo}/util/reduced_octahedral_pl.cc (89%) rename src/eckit/{geometry => geo}/util/regex.cc (94%) rename src/eckit/{geometry => geo}/util/regex.h (89%) delete mode 100644 src/eckit/geometry/eckit_geometry_config.h.in create mode 100644 tests/geo/CMakeLists.txt create mode 100644 tests/geo/test_coordinate_helpers.cc create mode 100644 tests/geo/test_great_circle.cc rename tests/{geometry => geo}/test_grid.cc (85%) rename tests/{geometry => geo}/test_iterator.cc (77%) create mode 100644 tests/geo/test_kdtree.cc create mode 100644 tests/geo/test_kpoint.cc rename tests/{geometry => geo}/test_param.cc (100%) create mode 100644 tests/geo/test_points.cc create mode 100644 tests/geo/test_polygon.cc rename tests/{geometry => geo}/test_projection.cc (96%) rename tests/{geometry => geo}/test_search.cc (95%) create mode 100644 tests/geo/test_sphere.cc rename tests/{geometry => geo}/test_types.cc (96%) rename tests/{geometry => geo}/test_util.cc (97%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 541a7131c..c84e73327 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,13 +142,16 @@ ecbuild_add_option( FEATURE AEC ecbuild_add_option( FEATURE XXHASH DESCRIPTION "xxHash support for hashing" ) -### Geometry options - -ecbuild_add_option( FEATURE GEOMETRY_CACHING - DEFAULT OFF - DESCRIPTION "eckit::geometry default caching behaviour" ) - -set( eckit_GEOMETRY_CACHE_PATH "/tmp/cache" ) +if ( HAVE_EXPERIMENTAL ) + ### eckit::geo options + + ecbuild_add_option( FEATURE GEO_CACHING + CONDITION HAVE_EXPERIMENTAL + DEFAULT OFF + DESCRIPTION "eckit::geo default caching behaviour" ) + + set( eckit_GEO_CACHE_PATH "/tmp/cache" ) +endif() ### LAPACK diff --git a/etc/eckit/CMakeLists.txt b/etc/eckit/CMakeLists.txt index c96a3c805..de5f754ae 100644 --- a/etc/eckit/CMakeLists.txt +++ b/etc/eckit/CMakeLists.txt @@ -1,2 +1,2 @@ -add_subdirectory(geometry) +add_subdirectory(geo) diff --git a/etc/eckit/geometry/CMakeLists.txt b/etc/eckit/geo/CMakeLists.txt similarity index 88% rename from etc/eckit/geometry/CMakeLists.txt rename to etc/eckit/geo/CMakeLists.txt index b134265ac..c4b764e98 100644 --- a/etc/eckit/geometry/CMakeLists.txt +++ b/etc/eckit/geo/CMakeLists.txt @@ -1,5 +1,5 @@ file(GLOB _files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.yaml") -set(_destination "etc/eckit/geometry") +set(_destination "etc/eckit/geo") install(FILES ${_files} DESTINATION ${_destination} PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) diff --git a/etc/eckit/geometry/grid.yaml b/etc/eckit/geo/grid.yaml similarity index 100% rename from etc/eckit/geometry/grid.yaml rename to etc/eckit/geo/grid.yaml diff --git a/src/eckit/CMakeLists.txt b/src/eckit/CMakeLists.txt index 2f7a9180a..9644df4f6 100644 --- a/src/eckit/CMakeLists.txt +++ b/src/eckit/CMakeLists.txt @@ -347,8 +347,6 @@ config/Configuration.cc config/Configuration.h config/Configured.cc config/Configured.h -config/DynamicConfiguration.cc -config/DynamicConfiguration.h config/EtcTable.cc config/EtcTable.h config/JSONConfiguration.h @@ -356,8 +354,6 @@ config/LibEcKit.cc config/LibEcKit.h config/LocalConfiguration.cc config/LocalConfiguration.h -config/MappedConfiguration.cc -config/MappedConfiguration.h config/Parametrisation.cc config/Parametrisation.h config/Resource.h @@ -369,6 +365,15 @@ config/YAMLConfiguration.cc config/YAMLConfiguration.h ) +if( HAVE_EXPERIMENTAL ) + list( APPEND eckit_config_srcs + config/DynamicConfiguration.cc + config/DynamicConfiguration.h + config/MappedConfiguration.cc + config/MappedConfiguration.h + ) +endif() + list( APPEND eckit_runtime_srcs runtime/Application.cc runtime/Application.h @@ -963,11 +968,11 @@ ecbuild_add_library( ### sub-directories if( HAVE_ECKIT_CMD ) - add_subdirectory( cmd ) + add_subdirectory( cmd ) endif() if( HAVE_ECKIT_SQL ) - add_subdirectory( sql ) + add_subdirectory( sql ) endif() add_subdirectory( distributed ) @@ -977,3 +982,9 @@ add_subdirectory( maths ) add_subdirectory( mpi ) add_subdirectory( option ) add_subdirectory( web ) + +if( HAVE_EXPERIMENTAL ) + add_subdirectory( codec ) + add_subdirectory( geo ) +endif() + diff --git a/src/eckit/geometry/Area.h b/src/eckit/geo/Area.h similarity index 96% rename from src/eckit/geometry/Area.h rename to src/eckit/geo/Area.h index 21555298d..595ab9d27 100644 --- a/src/eckit/geometry/Area.h +++ b/src/eckit/geo/Area.h @@ -23,7 +23,7 @@ class Configuration; } -namespace eckit::geometry { +namespace eckit::geo { class Area { @@ -110,4 +110,4 @@ class Area { // using AreaBuilder = ConcreteBuilderT1; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt new file mode 100644 index 000000000..8c881c98c --- /dev/null +++ b/src/eckit/geo/CMakeLists.txt @@ -0,0 +1,130 @@ + +configure_file( eckit_geo_config.h.in eckit_geo_config.h @ONLY ) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_config.h + DESTINATION ${INSTALL_INCLUDE_DIR}/eckit +) + +list( APPEND eckit_geo_srcs + ${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_config.h + Area.h + Cache.cc + Cache.h + Configurator.h + CoordinateHelpers.cc + CoordinateHelpers.h + Domain.cc + Domain.h + Earth.h + EllipsoidOfRevolution.cc + EllipsoidOfRevolution.h + Figure.h + GreatCircle.cc + GreatCircle.h + Grid.cc + Grid.h + GridConfig.cc + GridConfig.h + Iterator.h + KPoint.cc + KPoint.h + LibEcKitGeo.cc + LibEcKitGeo.h + Ordering.h + Point.cc + Point.h + Point2.cc + Point2.h + Point3.cc + Point3.h + PointLonLat.cc + PointLonLat.h + Projection.h + Range.cc + Range.h + Renumber.h + Search.h + Sphere.cc + Sphere.h + SphereT.h + UnitSphere.h + area/BoundingBox.cc + area/BoundingBox.h + grid/Reduced.cc + grid/Reduced.h + grid/Regular.cc + grid/Regular.h + grid/Unstructured.cc + grid/Unstructured.h + grid/reduced/HEALPix.cc + grid/reduced/HEALPix.h + grid/reduced/ReducedGaussian.cc + grid/reduced/ReducedGaussian.h + grid/reduced/ReducedLatLon.cc + grid/reduced/ReducedLatLon.h + grid/regular/IrregularLatLon.cc + grid/regular/IrregularLatLon.h + grid/regular/RegularGaussian.cc + grid/regular/RegularGaussian.h + grid/regular/RegularLatLon.cc + grid/regular/RegularLatLon.h + grid/unstructured/ORCA.cc + grid/unstructured/ORCA.h + iterator/Reduced.cc + iterator/Reduced.h + iterator/Regular.cc + iterator/Regular.h + iterator/Unstructured.cc + iterator/Unstructured.h + polygon/LonLatPolygon.cc + polygon/LonLatPolygon.h + polygon/Polygon.cc + polygon/Polygon.h + projection/LonLatToXYZ.cc + projection/LonLatToXYZ.h + projection/None.cc + projection/None.h + projection/Rotation.cc + projection/Rotation.h + range/Gaussian.cc + range/Gaussian.h + range/GlobalRegular.cc + range/GlobalRegular.h + range/LocalRegular.cc + range/LocalRegular.h + util.cc + util.h + util/arange.cc + util/gaussian_latitudes.cc + util/linspace.cc + util/monotonic_crop.cc + util/reduced_classical_pl.cc + util/reduced_octahedral_pl.cc + util/regex.cc + util/regex.h +) + +set(eckit_geo_include_dirs + $ + $ +) + +set(eckit_geo_libs eckit_maths eckit_codec) + +if(HAVE_PROJ) + list(APPEND eckit_geo_srcs projection/PROJ.cc projection/PROJ.h) + list(APPEND eckit_geo_libs PROJ::proj) + list(APPEND eckit_geo_include_dirs ${PROJ_INCLUDE_DIRS}) +endif() + +ecbuild_add_library( + TARGET eckit_geo + TYPE SHARED + + INSTALL_HEADERS ALL + HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geo + PUBLIC_LIBS ${eckit_geo_libs} + PUBLIC_INCLUDES ${eckit_geo_include_dirs} + + SOURCES ${eckit_geo_srcs} +) diff --git a/src/eckit/geometry/Cache.cc b/src/eckit/geo/Cache.cc similarity index 88% rename from src/eckit/geometry/Cache.cc rename to src/eckit/geo/Cache.cc index 5e847c5d0..c04830fd4 100644 --- a/src/eckit/geometry/Cache.cc +++ b/src/eckit/geo/Cache.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/Cache.h" +#include "eckit/geo/Cache.h" #include @@ -18,7 +18,7 @@ #include -namespace eckit::geometry::cache { +namespace eckit::geo::cache { static std::map> __cache; @@ -44,4 +44,4 @@ void test() { } -} // namespace eckit::geometry::cache +} // namespace eckit::geo::cache diff --git a/src/eckit/geometry/Cache.h b/src/eckit/geo/Cache.h similarity index 92% rename from src/eckit/geometry/Cache.h rename to src/eckit/geo/Cache.h index f0aec4cd3..22481469b 100644 --- a/src/eckit/geometry/Cache.h +++ b/src/eckit/geo/Cache.h @@ -14,7 +14,7 @@ #include -namespace eckit::geometry::cache { +namespace eckit::geo::cache { class Cache { @@ -52,4 +52,4 @@ class CacheableT : public Cache { }; -} // namespace eckit::geometry::cache +} // namespace eckit::geo::cache diff --git a/src/eckit/geometry/Configurator.h b/src/eckit/geo/Configurator.h similarity index 99% rename from src/eckit/geometry/Configurator.h rename to src/eckit/geo/Configurator.h index 304a1164b..dc526094b 100644 --- a/src/eckit/geometry/Configurator.h +++ b/src/eckit/geo/Configurator.h @@ -29,7 +29,7 @@ class Configuration; } -namespace eckit::geometry { +namespace eckit::geo { //------------------------------------------------------------------------------------------------------ @@ -342,4 +342,4 @@ class ConcreteConfigurationGeneratorT2 final : public ConfigurationGeneratorT2 +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/CoordinateHelpers.h" +#include "eckit/geo/Point2.h" + +namespace eckit::geo { + +//---------------------------------------------------------------------------------------------------------------------- + +double normalise_angle(double a, const double minimum) { + while (a < minimum) { + a += 360.; + } + while (a >= minimum + 360.) { + a -= 360.; + } + return a; +} + +//---------------------------------------------------------------------------------------------------------------------- + +Point2 canonicaliseOnSphere(const Point2& lonlat, const double minimum_lon) { + const double lat = normalise_angle(lonlat[1], -90.); + const bool across_pole = (lat > 90.); + + if (!across_pole) { + return {normalise_angle(lonlat[0], minimum_lon), lat}; + } + + return {normalise_angle(lonlat[0] + 180., minimum_lon), 180. - lat}; +} + +//---------------------------------------------------------------------------------------------------------------------- + +void assert_latitude_range(double lat) { + if (!(-90. <= lat && lat <= 90.)) { + std::ostringstream oss; + oss.precision(std::numeric_limits::max_digits10); + oss << "Invalid latitude " << lat; + throw BadValue(oss.str(), Here()); + } +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo diff --git a/src/eckit/geo/CoordinateHelpers.h b/src/eckit/geo/CoordinateHelpers.h new file mode 100644 index 000000000..52358ffda --- /dev/null +++ b/src/eckit/geo/CoordinateHelpers.h @@ -0,0 +1,47 @@ +/* + * (C) Copyright 2023 UCAR. + * + * 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. + */ + +#ifndef CoordinateHelpers_H +#define CoordinateHelpers_H + +namespace eckit::geo { + +class Point2; + +//---------------------------------------------------------------------------------------------------------------------- + +/// Shift angle in increments of 360° until it lies in [minimum, minimum+360°). +/// +/// Inputs angle and minimum are in degrees, returned angle is in degrees. +double normalise_angle(double angle, double minimum); + +//---------------------------------------------------------------------------------------------------------------------- + +/// Shift input point on sphere so its longitude lies in [minimum_lon, minimum_lon+360°) +/// and its latitude lies in [-90°, 90°]. +/// +/// Latitudes outside the canonical interval [-90°,90°] are first shifted into the interval +/// [-90°,270°], then any points with latitudes in [90°,270°] are flagged as "across the pole". +/// Such points are re-labeled with equivalent coordinates that lie within the canonical coordinate +/// patch by the transformation: (λ, ϕ) -> (λ+180°, 180°-ϕ). +/// +/// Finally, the longitude is shifted into [minimum_lon, minimum_lon+360°). +/// +/// Inputs lonlat and minimum_lon are in degrees, returned angles are in degrees. +Point2 canonicaliseOnSphere(const Point2& lonlat, double minimum_lon = 0.); + +//---------------------------------------------------------------------------------------------------------------------- + +/// Assert latitude lies in [-90°, 90°]. +void assert_latitude_range(double lat); + + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo + +#endif // CoordinateHelpers_H diff --git a/src/eckit/geometry/Domain.cc b/src/eckit/geo/Domain.cc similarity index 93% rename from src/eckit/geometry/Domain.cc rename to src/eckit/geo/Domain.cc index a93336b91..9cbf16653 100644 --- a/src/eckit/geometry/Domain.cc +++ b/src/eckit/geo/Domain.cc @@ -10,19 +10,19 @@ */ -#include "eckit/geometry/Domain.h" +#include "eckit/geo/Domain.h" #include #include #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Point.h" -#include "eckit/geometry/Sphere.h" -#include "eckit/geometry/util.h" +#include "eckit/geo/Point.h" +#include "eckit/geo/Sphere.h" +#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geometry { +namespace eckit::geo { Domain::Domain(double north, double west, double south, double east) : @@ -99,4 +99,4 @@ double Domain::area(double radius) const { } -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/Domain.h b/src/eckit/geo/Domain.h similarity index 97% rename from src/eckit/geometry/Domain.h rename to src/eckit/geo/Domain.h index e8dfd1253..e920bb9af 100644 --- a/src/eckit/geometry/Domain.h +++ b/src/eckit/geo/Domain.h @@ -13,7 +13,7 @@ #pragma once -namespace eckit::geometry { +namespace eckit::geo { class Domain { @@ -111,4 +111,4 @@ class Domain { }; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/Earth.h b/src/eckit/geo/Earth.h similarity index 88% rename from src/eckit/geometry/Earth.h rename to src/eckit/geo/Earth.h index d892e22e2..25e8b0d74 100644 --- a/src/eckit/geometry/Earth.h +++ b/src/eckit/geo/Earth.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geometry/SphereT.h" +#include "eckit/geo/SphereT.h" -namespace eckit::geometry { +namespace eckit::geo { struct DatumIFS { @@ -36,4 +36,4 @@ struct DatumWGS84SemiMajorAxis { using Earth = SphereT; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geo/EllipsoidOfRevolution.cc b/src/eckit/geo/EllipsoidOfRevolution.cc new file mode 100644 index 000000000..0da29eac5 --- /dev/null +++ b/src/eckit/geo/EllipsoidOfRevolution.cc @@ -0,0 +1,65 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/EllipsoidOfRevolution.h" + +#include +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/Point3.h" +#include "eckit/geo/PointLonLat.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit::geo { + +//---------------------------------------------------------------------------------------------------------------------- + +Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, + double b, + const PointLonLat& P, + double height, + bool normalise_angle) { + ASSERT(a > 0.); + ASSERT(b > 0.); + + if (!(-90. <= P.lat && P.lat <= 90.)) { + std::ostringstream oss; + oss.precision(std::numeric_limits::max_digits10); + oss << "Invalid latitude " << P.lat; + throw BadValue(oss.str(), Here()); + } + + static const double degrees_to_radians = M_PI / 180.; + + // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates + // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) + + const double lambda_deg = PointLonLat::normalise_angle_to_minimum(P.lon, -180.); + const double lambda = degrees_to_radians * lambda_deg; + const double phi = degrees_to_radians * P.lat; + + const double sin_phi = std::sin(phi); + const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); + const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; + const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); + + const double N_phi = a * a / std::sqrt(a * a * cos_phi * cos_phi + b * b * sin_phi * sin_phi); + + return {(N_phi + height) * cos_phi * cos_lambda, + (N_phi + height) * cos_phi * sin_lambda, + (N_phi * (b * b) / (a * a) + height) * sin_phi}; +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo diff --git a/src/eckit/geo/EllipsoidOfRevolution.h b/src/eckit/geo/EllipsoidOfRevolution.h new file mode 100644 index 000000000..798bd40bd --- /dev/null +++ b/src/eckit/geo/EllipsoidOfRevolution.h @@ -0,0 +1,38 @@ +/* + * (C) Copyright 1996- 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. + */ + +#ifndef EllipsoidOfRevolution_H +#define EllipsoidOfRevolution_H + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit::geo { + +//---------------------------------------------------------------------------------------------------------------------- + +class Point3; +class PointLonLat; + +//---------------------------------------------------------------------------------------------------------------------- + +struct EllipsoidOfRevolution { + // Convert elliptic coordinates to Cartesian + static Point3 convertSphericalToCartesian(double a, + double b, + const PointLonLat&, + double height = 0., + bool normalise_angle = false); +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo + +#endif diff --git a/src/eckit/geometry/Figure.h b/src/eckit/geo/Figure.h similarity index 96% rename from src/eckit/geometry/Figure.h rename to src/eckit/geo/Figure.h index d77d8405b..705f194b2 100644 --- a/src/eckit/geometry/Figure.h +++ b/src/eckit/geo/Figure.h @@ -23,7 +23,7 @@ class Configuration; } -namespace eckit::geometry { +namespace eckit::geo { class Figure { @@ -110,4 +110,4 @@ template using FigureBuilder = ConcreteBuilderT1; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geo/GreatCircle.cc b/src/eckit/geo/GreatCircle.cc new file mode 100644 index 000000000..4aa433f12 --- /dev/null +++ b/src/eckit/geo/GreatCircle.cc @@ -0,0 +1,122 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/GreatCircle.h" + +#include +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/types/FloatCompare.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit::geo { + +//---------------------------------------------------------------------------------------------------------------------- + +using types::is_approximately_equal; + +static const double radians_to_degrees = 180. * M_1_PI; + +static const double degrees_to_radians = M_PI / 180.; + +static bool pole(const double lat) { + return is_approximately_equal(std::abs(lat), 90.); +} + +//---------------------------------------------------------------------------------------------------------------------- + +GreatCircle::GreatCircle(const PointLonLat& Alonlat, const PointLonLat& Blonlat) : + A_(Alonlat), B_(Blonlat) { + const bool Apole = pole(A_.lat); + const bool Bpole = pole(B_.lat); + const double lon12_deg = PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); + + const bool lon_same = Apole || Bpole || is_approximately_equal(lon12_deg, 0.); + const bool lon_opposite = Apole || Bpole || is_approximately_equal(std::abs(lon12_deg), 180.); + const bool lat_same = is_approximately_equal(A_.lat, B_.lat); + const bool lat_opposite = is_approximately_equal(A_.lat, -B_.lat); + + if ((lat_same && lon_same) || (lat_opposite && lon_opposite)) { + std::ostringstream oss; + oss.precision(std::numeric_limits::max_digits10); + oss << "Great circle cannot be defined by points collinear with the centre, " << A_ << " and " << B_; + throw BadValue(oss.str(), Here()); + } + + crossesPoles_ = lon_same || lon_opposite; +} + +std::vector GreatCircle::latitude(double lon) const { + if (crossesPoles()) { + return {}; + } + + const double lat1 = degrees_to_radians * A_.lat; + const double lat2 = degrees_to_radians * B_.lat; + const double lambda1p = degrees_to_radians * (lon - A_.lon); + const double lambda2p = degrees_to_radians * (lon - B_.lon); + const double lambda = degrees_to_radians * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, -180.); + + double lat = std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); + return {radians_to_degrees * lat}; +} + +std::vector GreatCircle::longitude(double lat) const { + if (crossesPoles()) { + const double lon = pole(A_.lat) ? B_.lon : A_.lon; + if (pole(lat)) { + return {lon}; + } + + return {lon, lon + 180.}; + } + + const double lon12 = degrees_to_radians * PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); + const double lon1 = degrees_to_radians * A_.lon; + const double lat1 = degrees_to_radians * A_.lat; + const double lat2 = degrees_to_radians * B_.lat; + const double lat3 = degrees_to_radians * lat; + + const double X = std::sin(lat1) * std::cos(lat2) * std::sin(lon12); + const double Y = std::sin(lat1) * std::cos(lat2) * std::cos(lon12) - std::cos(lat1) * std::sin(lat2); + + if (is_approximately_equal(X, 0.) && is_approximately_equal(Y, 0.)) { + return {}; // parallel (that is, equator) + } + + const double lon0 = lon1 + atan2(Y, X); + const double C = std::cos(lat1) * std::cos(lat2) * std::tan(lat3) * std::sin(lon12) / std::sqrt(X * X + Y * Y); + + if (is_approximately_equal(C, -1.)) { + return {radians_to_degrees * (lon0 + M_PI)}; + } + + if (is_approximately_equal(C, 1.)) { + return {radians_to_degrees * lon0}; + } + + if (-1 < C && C < 1) { + const double dlon = std::acos(C); + return {radians_to_degrees * (lon0 - dlon + 2 * M_PI), radians_to_degrees * (lon0 + dlon)}; + } + + return {}; +} + +bool GreatCircle::crossesPoles() const { + return crossesPoles_; +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo diff --git a/src/eckit/geo/GreatCircle.h b/src/eckit/geo/GreatCircle.h new file mode 100644 index 000000000..55b8e627f --- /dev/null +++ b/src/eckit/geo/GreatCircle.h @@ -0,0 +1,48 @@ +/* + * (C) Copyright 1996- 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. + */ + +#ifndef GreatCircle_H +#define GreatCircle_H + +#include + +#include "eckit/geo/PointLonLat.h" + +//------------------------------------------------------------------------------------------------------ + +namespace eckit::geo { + +//------------------------------------------------------------------------------------------------------ + +class GreatCircle { +public: + /// Great circle given two points in geographic coordinates + GreatCircle(const PointLonLat&, const PointLonLat&); + + /// Great circle latitude given longitude, see http://www.edwilliams.org/avform.htm#Int + std::vector latitude(double lon) const; + + /// Great circle longitude given latitude, see http://www.edwilliams.org/avform.htm#Par + std::vector longitude(double lat) const; + + bool crossesPoles() const; + +private: + const PointLonLat A_; + const PointLonLat B_; + + bool crossesPoles_; +}; + +//------------------------------------------------------------------------------------------------------ + +} // namespace eckit::geo + +#endif diff --git a/src/eckit/geometry/Grid.cc b/src/eckit/geo/Grid.cc similarity index 95% rename from src/eckit/geometry/Grid.cc rename to src/eckit/geo/Grid.cc index 2d3b1f224..077dd4d00 100644 --- a/src/eckit/geometry/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -10,20 +10,20 @@ */ -#include "eckit/geometry/Grid.h" +#include "eckit/geo/Grid.h" #include #include #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/GridConfig.h" +#include "eckit/geo/GridConfig.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" -namespace eckit::geometry { +namespace eckit::geo { Grid::Grid(const Configuration& config) : @@ -138,4 +138,4 @@ void GridFactory::list_(std::ostream& out) const { } -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/Grid.h b/src/eckit/geo/Grid.h similarity index 90% rename from src/eckit/geometry/Grid.h rename to src/eckit/geo/Grid.h index 860cd064c..bf289fc17 100644 --- a/src/eckit/geometry/Grid.h +++ b/src/eckit/geo/Grid.h @@ -19,14 +19,14 @@ #include #include -#include "eckit/geometry/Area.h" -#include "eckit/geometry/Configurator.h" -#include "eckit/geometry/Increments.h" -#include "eckit/geometry/Iterator.h" -#include "eckit/geometry/Ordering.h" -#include "eckit/geometry/Point.h" -#include "eckit/geometry/Renumber.h" -#include "eckit/geometry/area/BoundingBox.h" +#include "eckit/geo/Area.h" +#include "eckit/geo/Configurator.h" +#include "eckit/geo/Increments.h" +#include "eckit/geo/Iterator.h" +#include "eckit/geo/Ordering.h" +#include "eckit/geo/Point.h" +#include "eckit/geo/Renumber.h" +#include "eckit/geo/area/BoundingBox.h" #include "eckit/memory/Builder.h" #include "eckit/memory/Factory.h" @@ -36,7 +36,7 @@ class Configuration; } -namespace eckit::geometry { +namespace eckit::geo { class Grid { @@ -47,8 +47,8 @@ class Grid { using builder_t = BuilderT1; using ARG1 = const Configuration&; - struct Iterator final : std::unique_ptr { - explicit Iterator(geometry::Iterator* it) : + struct Iterator final : std::unique_ptr { + explicit Iterator(geo::Iterator* it) : unique_ptr(it) { ASSERT(unique_ptr::operator bool()); } using diff_t = unique_ptr::element_type::diff_t; @@ -206,4 +206,4 @@ struct GridFactory { }; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/GridConfig.cc b/src/eckit/geo/GridConfig.cc similarity index 93% rename from src/eckit/geometry/GridConfig.cc rename to src/eckit/geo/GridConfig.cc index 70363ca63..a831a95de 100644 --- a/src/eckit/geometry/GridConfig.cc +++ b/src/eckit/geo/GridConfig.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geometry/GridConfig.h" +#include "eckit/geo/GridConfig.h" #include #include @@ -18,14 +18,14 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" -#include "eckit/geometry/Grid.h" -#include "eckit/geometry/LibEcKitGeometry.h" -#include "eckit/geometry/util.h" +#include "eckit/geo/Grid.h" +#include "eckit/geo/LibEcKitGeo.h" +#include "eckit/geo/util.h" #include "eckit/parser/YAMLParser.h" #include "eckit/value/Value.h" -namespace eckit::geometry { +namespace eckit::geo { namespace { @@ -68,7 +68,7 @@ MappedConfiguration* config_from_value_map(const ValueMap& map) { const GridConfig& GridConfig::instance() { - static const GridConfig __instance(LibEcKitGeometry::configFileGrid()); + static const GridConfig __instance(LibEcKitGeo::configFileGrid()); return __instance; } @@ -119,4 +119,4 @@ GridConfig::GridConfig(const PathName& path) { } -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/GridConfig.h b/src/eckit/geo/GridConfig.h similarity index 95% rename from src/eckit/geometry/GridConfig.h rename to src/eckit/geo/GridConfig.h index 4bd0641a8..e17808663 100644 --- a/src/eckit/geometry/GridConfig.h +++ b/src/eckit/geo/GridConfig.h @@ -21,7 +21,7 @@ class PathName; } // namespace eckit -namespace eckit::geometry { +namespace eckit::geo { class GridConfig final { @@ -85,4 +85,4 @@ class GridConfig final { }; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/Increments.h b/src/eckit/geo/Increments.h similarity index 96% rename from src/eckit/geometry/Increments.h rename to src/eckit/geo/Increments.h index e4975cf18..39dc0edab 100644 --- a/src/eckit/geometry/Increments.h +++ b/src/eckit/geo/Increments.h @@ -20,7 +20,7 @@ class Configuration; } -namespace eckit::geometry { +namespace eckit::geo { class Increments : protected std::array { @@ -107,4 +107,4 @@ class Increments : protected std::array { }; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/Iterator.h b/src/eckit/geo/Iterator.h similarity index 94% rename from src/eckit/geometry/Iterator.h rename to src/eckit/geo/Iterator.h index 236b73fa5..e34f76799 100644 --- a/src/eckit/geometry/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -14,15 +14,15 @@ #include -#include "eckit/geometry/Point.h" +#include "eckit/geo/Point.h" -namespace eckit::geometry { +namespace eckit::geo { class Grid; } -namespace eckit::geometry { +namespace eckit::geo { class Iterator { @@ -117,4 +117,4 @@ class Iterator { }; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geo/KPoint.cc b/src/eckit/geo/KPoint.cc new file mode 100644 index 000000000..34e0b0b3c --- /dev/null +++ b/src/eckit/geo/KPoint.cc @@ -0,0 +1,27 @@ + +#include + +#include "eckit/geo/KPoint.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit::geo { + +//---------------------------------------------------------------------------------------------------------------------- + +template +void KPoint::print(std::ostream& s) const { + char z = '{'; + for (size_t i = 0; i < SIZE; ++i) { + s << z << x_[i]; + z = ','; + } + s << '}'; +} + +template void KPoint<2>::print(std::ostream&) const; +template void KPoint<3>::print(std::ostream&) const; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo diff --git a/src/eckit/geo/KPoint.h b/src/eckit/geo/KPoint.h new file mode 100644 index 000000000..5a39acc7d --- /dev/null +++ b/src/eckit/geo/KPoint.h @@ -0,0 +1,282 @@ +/* + * (C) Copyright 1996- 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +//------------------------------------------------------------------------------------------------------ + +namespace eckit::geo { + +//------------------------------------------------------------------------------------------------------ + +enum XYZCOORDS +{ + XX = 0, + YY = 1, + ZZ = 2 +}; +enum LLCOORDS +{ + LON = XX, + LAT = YY +}; + +/// A generic point in K dimension cartesian space + +template +class KPoint { +protected: + double x_[SIZE] = {0}; + +public: + static const size_t DIMS = SIZE; + + double x(size_t axis) const { return x_[axis]; } + + KPoint() = default; + + KPoint(const double* x) { std::copy(x, x + dimensions(), x_); } + + template + explicit KPoint(Container c) { + std::copy(c.begin(), c.end(), x_); + } + + const KPoint& point() const { return *this; } + + KPoint& point() { return *this; } + + double* data() { return x_; } + const double* data() const { return x_; } + + double operator()(const size_t& i) const { + assert(i < SIZE); + return x_[i]; + } + + bool operator<(const KPoint& other) const { + return std::lexicographical_compare(x_, x_ + SIZE, other.x_, other.x_ + SIZE); + } + + static size_t dimensions() { return SIZE; } + + void print(std::ostream& s) const; + + friend std::ostream& operator<<(std::ostream& s, const KPoint& p) { + p.print(s); + return s; + } + + static double distance(const KPoint& p1, const KPoint& p2) { + double d = 0; + for (size_t i = 0; i < dimensions(); i++) { + double dx = p1.x_[i] - p2.x_[i]; + d += dx * dx; + } + return std::sqrt(d); + } + + double distance(const KPoint& p) const { return distance(*this, p); } + + static double distance2(const KPoint& p1, const KPoint& p2) { + double d = 0; + for (size_t i = 0; i < dimensions(); i++) { + double dx = p1.x_[i] - p2.x_[i]; + d += dx * dx; + } + return d; + } + + double distance2(const KPoint& p) const { return distance2(*this, p); } + + static bool equal(const KPoint& p1, const KPoint& p2) { + for (size_t i = 0; i < dimensions(); i++) { + if (p1.x_[i] != p2.x_[i]) { + return false; + } + } + return true; + } + + bool operator==(const KPoint& other) const { return equal(*this, other); } + + bool operator!=(const KPoint& other) const { return !equal(*this, other); } + + static double norm(const KPoint& p1) { + double n = 0.0; + for (size_t i = 0; i < dimensions(); i++) { + double dx = p1.x_[i]; + n += dx * dx; + } + return std::sqrt(n); + } + + // Distance along one axis + static double distance(const KPoint& p1, const KPoint& p2, unsigned int axis) { + return std::abs(p1.x_[axis] - p2.x_[axis]); + } + + // For projecting a point on a line + static double dot(const KPoint& p1, const KPoint& p2) { + double m = 0.0; + for (size_t i = 0; i < dimensions(); i++) { + m += p1.x_[i] * p2.x_[i]; + } + return m; + } + + static KPoint add(const KPoint& p1, const KPoint& p2) { + KPoint q(p1); + for (size_t i = 0; i < dimensions(); i++) { + q.x_[i] += p2.x_[i]; + } + return q; + } + + static KPoint middle(const KPoint& p1, const KPoint& p2) { + KPoint q(p1); + for (size_t i = 0; i < dimensions(); i++) { + q.x_[i] += p2.x_[i]; + q.x_[i] /= 2.0; + } + return q; + } + + static KPoint sub(const KPoint& p1, const KPoint& p2) { + KPoint q(p1); + for (size_t i = 0; i < dimensions(); i++) { + q.x_[i] -= p2.x_[i]; + } + return q; + } + + static KPoint mul(const KPoint& p, double m) { + KPoint q(p); + for (size_t i = 0; i < dimensions(); i++) { + q.x_[i] *= m; + } + return q; + } + + static KPoint div(const KPoint& p, double m) { + KPoint q(p); + for (size_t i = 0; i < dimensions(); i++) { + q.x_[i] /= m; + } + return q; + } + + static KPoint componentsMin(const KPoint& p1, const KPoint& p2) { + KPoint q; + for (size_t i = 0; i < dimensions(); i++) { + q.x_[i] = std::min(p1.x_[i], p2.x_[i]); + } + return q; + } + + static KPoint componentsMax(const KPoint& p1, const KPoint& p2) { + KPoint q; + for (size_t i = 0; i < dimensions(); i++) { + q.x_[i] = std::max(p1.x_[i], p2.x_[i]); + } + return q; + } + + static KPoint normalize(const KPoint& p) { + KPoint zero; + return div(p, distance(p, zero)); + } + + template + static typename Container::value_type mean(const Container& points) { + typename Container::const_iterator j = points.begin(); + typename Container::value_type result(*j); + + ++j; + + for (; j != points.end(); ++j) { + for (size_t i = 0; i < dimensions(); i++) { + result.point().x_[i] += (*j).point().x_[i]; + } + } + for (size_t i = 0; i < dimensions(); i++) { + result.point().x_[i] /= points.size(); + } + return result; + } + + static KPoint symetrical(const KPoint& w, const KPoint& c) { + KPoint result(w); + for (size_t i = 0; i < dimensions(); i++) { + result.x_[i] -= (c.x_[i] - w.x_[i]); + } + return result; + } + + const double* begin() const { return x_; } + const double* end() const { return x_ + dimensions(); } + + KPoint operator+(const KPoint& other) const { return add(*this, other); } + + KPoint operator-(const KPoint& other) const { return sub(*this, other); } + + KPoint operator*(const double s) const { return mul(*this, s); } + + void normalize(const KPoint& offset, const KPoint& scale) { + for (size_t i = 0; i < DIMS; ++i) { + x_[i] = (x_[i] - offset.x_[i]) / scale.x_[i]; + } + } + + template + static void normalizeAll(Container& c, KPoint& offset, KPoint& scale) { + std::vector mins(DIMS, std::numeric_limits::max()); + std::vector maxs(DIMS, -std::numeric_limits::max()); + + for (typename Container::const_iterator j = c.begin(); j != c.end(); ++j) { + const typename Container::value_type& v = (*j); + for (size_t i = 0; i < DIMS; ++i) { + mins[i] = std::min(mins[i], v.point().x_[i]); + maxs[i] = std::max(maxs[i], v.point().x_[i]); + } + } + + for (size_t i = 0; i < DIMS; ++i) { + maxs[i] -= mins[i]; + } + + + for (typename Container::iterator j = c.begin(); j != c.end(); ++j) { + typename Container::value_type& v = (*j); + for (size_t i = 0; i < DIMS; ++i) { + v.point().x_[i] = (v.point().x_[i] - mins[i]) / maxs[i]; + } + } + + offset = KPoint(mins); + scale = KPoint(maxs); + } +}; + +//------------------------------------------------------------------------------------------------------ + +template +const size_t KPoint::DIMS; + +//------------------------------------------------------------------------------------------------------ + +} // namespace eckit::geo diff --git a/src/eckit/geometry/LibEcKitGeometry.cc b/src/eckit/geo/LibEcKitGeo.cc similarity index 50% rename from src/eckit/geometry/LibEcKitGeometry.cc rename to src/eckit/geo/LibEcKitGeo.cc index a68ec86ad..e40364dcb 100644 --- a/src/eckit/geometry/LibEcKitGeometry.cc +++ b/src/eckit/geo/LibEcKitGeo.cc @@ -10,59 +10,59 @@ */ -#include "eckit/geometry/LibEcKitGeometry.h" +#include "eckit/geo/LibEcKitGeo.h" #include "eckit/config/Resource.h" #include "eckit/eckit_version.h" #include "eckit/filesystem/PathName.h" -#include "eckit/geometry/eckit_geometry_config.h" +#include "eckit/geo/eckit_geo_config.h" namespace eckit { -REGISTER_LIBRARY(LibEcKitGeometry); +REGISTER_LIBRARY(LibEcKitGeo); -LibEcKitGeometry::LibEcKitGeometry() : - Library("eckit_geometry") {} +LibEcKitGeo::LibEcKitGeo() : + Library("eckit_geo") {} -LibEcKitGeometry& LibEcKitGeometry::instance() { - static LibEcKitGeometry lib; +LibEcKitGeo& LibEcKitGeo::instance() { + static LibEcKitGeo lib; return lib; } -PathName LibEcKitGeometry::configFileGrid() { - static const PathName path{LibResource("eckit-geometry-grid;$ECKIT_GEOMETRY_GRID", "~eckit/etc/eckit/geometry/grid.yaml")}; +PathName LibEcKitGeo::configFileGrid() { + static const PathName path{LibResource("eckit-geo-grid;$ECKIT_GEO_GRID", "~eckit/etc/eckit/geo/grid.yaml")}; return path; } -bool LibEcKitGeometry::caching() { - static const bool yes{LibResource("eckit-geometry-caching;$ECKIT_GEOMETRY_CACHING", eckit_HAVE_GEOMETRY_CACHING != 0 ? true : false)}; +bool LibEcKitGeo::caching() { + static const bool yes{LibResource("eckit-geo-caching;$ECKIT_GEO_CACHING", eckit_HAVE_GEO_CACHING != 0 ? true : false)}; return yes; } -std::string LibEcKitGeometry::cacheDir() { - static std::string path = PathName{LibResource("eckit-geometry-cache-path;$ECKIT_GEOMETRY_CACHE_PATH", eckit_GEOMETRY_CACHE_PATH)}; +std::string LibEcKitGeo::cacheDir() { + static std::string path = PathName{LibResource("eckit-geo-cache-path;$ECKIT_GEO_CACHE_PATH", eckit_GEO_CACHE_PATH)}; return path; } -const void* LibEcKitGeometry::addr() const { +const void* LibEcKitGeo::addr() const { return this; } -std::string LibEcKitGeometry::version() const { +std::string LibEcKitGeo::version() const { return eckit_version_str(); } -std::string LibEcKitGeometry::gitsha1(unsigned int count) const { +std::string LibEcKitGeo::gitsha1(unsigned int count) const { std::string sha1(eckit_git_sha1()); return sha1.empty() ? "not available" : sha1.substr(0, std::min(count, 40U)); } diff --git a/src/eckit/geometry/LibEcKitGeometry.h b/src/eckit/geo/LibEcKitGeo.h similarity index 91% rename from src/eckit/geometry/LibEcKitGeometry.h rename to src/eckit/geo/LibEcKitGeo.h index dff590814..aaf3ed7c3 100644 --- a/src/eckit/geometry/LibEcKitGeometry.h +++ b/src/eckit/geo/LibEcKitGeo.h @@ -23,7 +23,7 @@ class PathName; namespace eckit { -class LibEcKitGeometry final : public system::Library { +class LibEcKitGeo final : public system::Library { public: // -- Types // None @@ -45,7 +45,7 @@ class LibEcKitGeometry final : public system::Library { // -- Methods - static LibEcKitGeometry& instance(); + static LibEcKitGeo& instance(); static eckit::PathName configFileGrid(); @@ -64,7 +64,7 @@ class LibEcKitGeometry final : public system::Library { private: // -- Constructors - LibEcKitGeometry(); + LibEcKitGeo(); // -- Members // None diff --git a/src/eckit/geometry/Ordering.h b/src/eckit/geo/Ordering.h similarity index 96% rename from src/eckit/geometry/Ordering.h rename to src/eckit/geo/Ordering.h index 3bfe41789..955645e86 100644 --- a/src/eckit/geometry/Ordering.h +++ b/src/eckit/geo/Ordering.h @@ -13,7 +13,7 @@ #pragma once -namespace eckit::geometry { +namespace eckit::geo { enum Ordering @@ -47,4 +47,4 @@ enum Ordering }; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/Point.cc b/src/eckit/geo/Point.cc similarity index 89% rename from src/eckit/geometry/Point.cc rename to src/eckit/geo/Point.cc index 34b94967c..4ff741b5a 100644 --- a/src/eckit/geometry/Point.cc +++ b/src/eckit/geo/Point.cc @@ -10,14 +10,14 @@ */ -#include "eckit/geometry/Point.h" +#include "eckit/geo/Point.h" #include #include "eckit/exception/Exceptions.h" -namespace eckit::geometry { +namespace eckit::geo { bool points_equal(const Point& p, const Point& q) { @@ -32,4 +32,4 @@ std::ostream& operator<<(std::ostream& out, const Point& p) { } -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/Point.h b/src/eckit/geo/Point.h similarity index 82% rename from src/eckit/geometry/Point.h rename to src/eckit/geo/Point.h index b3036643b..91dd3e436 100644 --- a/src/eckit/geometry/Point.h +++ b/src/eckit/geo/Point.h @@ -15,12 +15,12 @@ #include #include -#include "eckit/geometry/Point2.h" -#include "eckit/geometry/Point3.h" -#include "eckit/geometry/PointLonLat.h" +#include "eckit/geo/Point2.h" +#include "eckit/geo/Point3.h" +#include "eckit/geo/PointLonLat.h" -namespace eckit::geometry { +namespace eckit::geo { using Point = std::variant; @@ -41,4 +41,4 @@ using Longitude = double; using Latitude = double; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geo/Point2.cc b/src/eckit/geo/Point2.cc new file mode 100644 index 000000000..6c32315c8 --- /dev/null +++ b/src/eckit/geo/Point2.cc @@ -0,0 +1,37 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/geo/Point2.h" +#include "eckit/types/FloatCompare.h" +#include "eckit/value/Value.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit::geo { + +//---------------------------------------------------------------------------------------------------------------------- + +bool points_equal(const Point2& a, const Point2& b) { + return eckit::types::is_approximately_equal(Point2::distance2(a, b), 0.0); +} + +bool operator<(const Point2& a, const Point2& b) { + return eckit::types::is_approximately_equal(Point2::distance2(a, b), 0.0); +} + +Point2::operator Value() const { + return Value::makeList(std::vector{x_[XX], x_[YY]}); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo diff --git a/src/eckit/geo/Point2.h b/src/eckit/geo/Point2.h new file mode 100644 index 000000000..2f8f28d5c --- /dev/null +++ b/src/eckit/geo/Point2.h @@ -0,0 +1,101 @@ +/* + * (C) Copyright 1996- 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. + */ + +#pragma once + +#include + +#include "eckit/geo/KPoint.h" + +//------------------------------------------------------------------------------------------------------ + +namespace eckit { +class Value; +} + +//------------------------------------------------------------------------------------------------------ + +namespace eckit::geo { + +//------------------------------------------------------------------------------------------------------ + +class Point2 : public KPoint<2> { + using BasePoint = KPoint<2>; + +public: + Point2() = default; + + Point2(const BasePoint& p) : + BasePoint(p) {} + + explicit Point2(const double* p) : + BasePoint(p) {} + + Point2(double x, double y) { + x_[XX] = x; + x_[YY] = y; + } + + Point2(const Point2& other) : + Point2(other.X, other.Y) {} + + Point2(Point2&& other) : + Point2(other.X, other.Y) {} + + double x() const { return x_[XX]; } + + double y() const { return x_[YY]; } + + double& X = x_[XX]; + + double& Y = x_[YY]; + + double x(size_t axis) const { return KPoint<2>::x(axis); } + + Point2& operator=(const Point2& other) { + x_[0] = other[0]; + x_[1] = other[1]; + return *this; + } + + Point2& operator=(Point2&& other) { + x_[0] = other[0]; + x_[1] = other[1]; + return *this; + } + + double operator[](const size_t& i) const { + assert(i < 2); + return x_[i]; + } + + double& operator[](const size_t& i) { + assert(i < 2); + return x_[i]; + } + + template + void assign(const T& p) { + x_[XX] = p[XX]; + x_[YY] = p[YY]; + } + + operator eckit::Value() const; +}; + +//------------------------------------------------------------------------------------------------------ + +bool points_equal(const Point2&, const Point2&); + +bool operator<(const Point2&, const Point2&); + +//------------------------------------------------------------------------------------------------------ + +} // namespace eckit::geo diff --git a/src/eckit/geo/Point3.cc b/src/eckit/geo/Point3.cc new file mode 100644 index 000000000..9d3951b49 --- /dev/null +++ b/src/eckit/geo/Point3.cc @@ -0,0 +1,31 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Point3.h" + +#include "eckit/types/FloatCompare.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit::geo { + +//---------------------------------------------------------------------------------------------------------------------- + +bool points_equal(const Point3& a, const Point3& b) { + auto eps = 1e-6; + return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps) && types::is_approximately_equal(a.Z, b.Z, eps); +} + +bool operator<(const Point3& a, const Point3& b) { +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo diff --git a/src/eckit/geo/Point3.h b/src/eckit/geo/Point3.h new file mode 100644 index 000000000..191b56b36 --- /dev/null +++ b/src/eckit/geo/Point3.h @@ -0,0 +1,95 @@ +/* + * (C) Copyright 1996- 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. + */ + +#pragma once + +#include "eckit/geo/KPoint.h" + +//------------------------------------------------------------------------------------------------------ + +namespace eckit::geo { + +//------------------------------------------------------------------------------------------------------ + +class Point3 : public KPoint<3> { + using BasePoint = KPoint<3>; + +public: + Point3() = default; + + Point3(const BasePoint& p) : + BasePoint(p) {} + + explicit Point3(const double* p) : + BasePoint(p) {} + + Point3(double x, double y, double z) { + x_[XX] = x; + x_[YY] = y; + x_[ZZ] = z; + } + + Point3(const Point3& other) : + Point3(other.X, other.Y, other.Z) {} + + Point3(Point3&& other) : + Point3(other.X, other.Y, other.Z) {} + + double& X = x_[XX]; + + double& Y = x_[YY]; + + double& Z = x_[ZZ]; + + Point3& operator=(const Point3& other) { + x_[0] = other[0]; + x_[1] = other[1]; + x_[2] = other[2]; + return *this; + } + + Point3& operator=(Point3&& other) { + x_[0] = other[0]; + x_[1] = other[1]; + x_[2] = other[2]; + return *this; + } + + double operator[](const size_t& i) const { + assert(i < 3); + return x_[i]; + } + double& operator[](const size_t& i) { + assert(i < 3); + return x_[i]; + } + + template + void assign(const T& p) { + x_[XX] = p[XX]; + x_[YY] = p[YY]; + x_[ZZ] = p[ZZ]; + } + + static Point3 cross(const Point3& p1, const Point3& p2) { + return Point3(p1[YY] * p2[ZZ] - p1[ZZ] * p2[YY], p1[ZZ] * p2[XX] - p1[XX] * p2[ZZ], + p1[XX] * p2[YY] - p1[YY] * p2[XX]); + } +}; + +//------------------------------------------------------------------------------------------------------ + +bool points_equal(const Point3&, const Point3&); + +bool operator<(const Point3&, const Point3&); + +//------------------------------------------------------------------------------------------------------ + +} // namespace eckit::geo diff --git a/src/eckit/geometry/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc similarity index 93% rename from src/eckit/geometry/PointLonLat.cc rename to src/eckit/geo/PointLonLat.cc index c35153efc..069cc08ff 100644 --- a/src/eckit/geometry/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geometry/PointLonLat.h" +#include "eckit/geo/PointLonLat.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geometry { +namespace eckit::geo { double PointLonLat::normalise_angle_to_minimum(double a, double minimum) { @@ -60,4 +60,4 @@ bool operator<(const PointLonLat& a, const PointLonLat& b) { } -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/PointLonLat.h b/src/eckit/geo/PointLonLat.h similarity index 97% rename from src/eckit/geometry/PointLonLat.h rename to src/eckit/geo/PointLonLat.h index 2cf4917b4..53101d7f8 100644 --- a/src/eckit/geometry/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -19,7 +19,7 @@ #include "eckit/exception/Exceptions.h" -namespace eckit::geometry { +namespace eckit::geo { class PointLonLat final : protected std::array { @@ -113,4 +113,4 @@ bool points_equal(const PointLonLat&, const PointLonLat&); bool operator<(const PointLonLat&, const PointLonLat&); -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/Projection.h b/src/eckit/geo/Projection.h similarity index 95% rename from src/eckit/geometry/Projection.h rename to src/eckit/geo/Projection.h index 32fe7ae87..b5ca1fc66 100644 --- a/src/eckit/geometry/Projection.h +++ b/src/eckit/geo/Projection.h @@ -14,7 +14,7 @@ #include -#include "eckit/geometry/Point.h" +#include "eckit/geo/Point.h" #include "eckit/memory/Builder.h" #include "eckit/memory/Factory.h" @@ -24,7 +24,7 @@ class Configuration; } -namespace eckit::geometry { +namespace eckit::geo { class Projection { @@ -114,4 +114,4 @@ template using ProjectionBuilder = ConcreteBuilderT1; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/Range.cc b/src/eckit/geo/Range.cc similarity index 86% rename from src/eckit/geometry/Range.cc rename to src/eckit/geo/Range.cc index 9aad25c99..10277273c 100644 --- a/src/eckit/geometry/Range.cc +++ b/src/eckit/geo/Range.cc @@ -10,13 +10,13 @@ */ -#include "eckit/geometry/Range.h" +#include "eckit/geo/Range.h" #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" -namespace eckit::geometry { +namespace eckit::geo { Range::Range(const Configuration& config) : @@ -30,4 +30,4 @@ Range::Range(size_t n) : } -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/Range.h b/src/eckit/geo/Range.h similarity index 97% rename from src/eckit/geometry/Range.h rename to src/eckit/geo/Range.h index 0bd892e3a..a29506c47 100644 --- a/src/eckit/geometry/Range.h +++ b/src/eckit/geo/Range.h @@ -24,7 +24,7 @@ class Configuration; } -namespace eckit::geometry { +namespace eckit::geo { class Range : protected std::vector { @@ -124,4 +124,4 @@ class Range : protected std::vector { // using RangeBuilder = ConcreteBuilderT1; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/Renumber.h b/src/eckit/geo/Renumber.h similarity index 88% rename from src/eckit/geometry/Renumber.h rename to src/eckit/geo/Renumber.h index 7ffec908f..e0c7c92c0 100644 --- a/src/eckit/geometry/Renumber.h +++ b/src/eckit/geo/Renumber.h @@ -15,10 +15,10 @@ #include -namespace eckit::geometry { +namespace eckit::geo { using Renumber = std::vector; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/Search.h b/src/eckit/geo/Search.h similarity index 85% rename from src/eckit/geometry/Search.h rename to src/eckit/geo/Search.h index 2333e916c..f506d73a2 100644 --- a/src/eckit/geometry/Search.h +++ b/src/eckit/geo/Search.h @@ -16,11 +16,11 @@ #include "eckit/container/KDTree.h" #include "eckit/container/sptree/SPValue.h" -#include "eckit/geometry/Point.h" -#include "eckit/geometry/UnitSphere.h" +#include "eckit/geo/Point.h" +#include "eckit/geo/UnitSphere.h" -namespace eckit::geometry { +namespace eckit::geo { namespace search { @@ -32,14 +32,14 @@ struct Traits { } // namespace search -using Search3 = KDTreeMemory>; +using Search3 = KDTreeMemory>; -using Search2 = KDTreeMemory>; +using Search2 = KDTreeMemory>; struct SearchLonLat : Search3 { - using Point = geometry::PointLonLat; + using Point = geo::PointLonLat; using Value = SPValue, KDMemory>>; using Search3::Search3; @@ -84,4 +84,4 @@ struct SearchLonLat : Search3 { }; -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geo/Sphere.cc b/src/eckit/geo/Sphere.cc new file mode 100644 index 000000000..eb7d93425 --- /dev/null +++ b/src/eckit/geo/Sphere.cc @@ -0,0 +1,215 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Sphere.h" + +#include +#include +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/GreatCircle.h" +#include "eckit/geo/Point3.h" +#include "eckit/geo/PointLonLat.h" +#include "eckit/types/FloatCompare.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit::geo { + +//---------------------------------------------------------------------------------------------------------------------- + +using types::is_approximately_equal; + +static constexpr double radians_to_degrees = 180. * M_1_PI; + +static constexpr double degrees_to_radians = M_PI / 180.; + +void assert_latitude(double lat) { + if (!(-90. <= lat && lat <= 90.)) { + std::ostringstream oss; + oss.precision(std::numeric_limits::max_digits10); + oss << "Invalid latitude " << lat; + throw BadValue(oss.str(), Here()); + } +} + +inline double squared(double x) { + return x * x; +} + +//---------------------------------------------------------------------------------------------------------------------- + +double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { + assert_latitude(A.lat); + assert_latitude(B.lat); + + /* + * Δσ = atan( ((cos(ϕ2) * sin(Δλ))^2 + (cos(ϕ1) * sin(ϕ2) - sin(ϕ1) * cos(ϕ2) * cos(Δλ))^2) / + * (sin(ϕ1) * sin(ϕ2) + cos(ϕ1) * cos(ϕ2) * cos(Δλ)) ) + * + * @article{doi:10.1179/sre.1975.23.176.88, + * author = {T. Vincenty}, + * title = {Direct and Inverse Solutions of Geodesics on the Ellipsoid With Application of Nested Equations}, + * journal = {Survey Review}, + * volume = {23}, + * number = {176}, + * pages = {88-93}, + * year = {1975}, + * doi = {10.1179/sre.1975.23.176.88} + * } + */ + + const double phi1 = degrees_to_radians * A.lat; + const double phi2 = degrees_to_radians * B.lat; + const double lambda = degrees_to_radians * (B.lon - A.lon); + + const double cos_phi1 = cos(phi1); + const double sin_phi1 = sin(phi1); + const double cos_phi2 = cos(phi2); + const double sin_phi2 = sin(phi2); + const double cos_lambda = cos(lambda); + const double sin_lambda = sin(lambda); + + const double angle = std::atan2(std::sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), + sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); + + if (is_approximately_equal(angle, 0.)) { + return 0.; + } + + ASSERT(angle > 0.); + return angle; +} + +double Sphere::centralAngle(double radius, const Point3& A, const Point3& B) { + ASSERT(radius > 0.); + + // Δσ = 2 * asin( chord / 2 ) + + const double d2 = Point3::distance2(A, B); + if (is_approximately_equal(d2, 0.)) { + return 0.; + } + + const double chord = std::sqrt(d2) / radius; + const double angle = std::asin(chord * 0.5) * 2.; + + return angle; +} + +double Sphere::distance(double radius, const PointLonLat& A, const PointLonLat& B) { + return radius * centralAngle(A, B); +} + +double Sphere::distance(double radius, const Point3& A, const Point3& B) { + return radius * centralAngle(radius, A, B); +} + +double Sphere::area(double radius) { + ASSERT(radius > 0.); + return 4. * M_PI * radius * radius; +} + +double Sphere::area(double radius, const PointLonLat& WestNorth, const PointLonLat& EastSouth) { + ASSERT(radius > 0.); + assert_latitude(WestNorth.lat); + assert_latitude(EastSouth.lat); + + // Set longitude fraction + double W = WestNorth.lon; + double E = PointLonLat::normalise_angle_to_minimum(EastSouth.lon, W); + double longitude_range(is_approximately_equal(W, E) + && !is_approximately_equal(EastSouth.lon, WestNorth.lon) + ? 360. + : E - W); + ASSERT(longitude_range <= 360.); + + double longitude_fraction = longitude_range / 360.; + + // Set latitude fraction + double N = WestNorth.lat; + double S = EastSouth.lat; + ASSERT(S <= N); + + double latitude_fraction = 0.5 * (std::sin(degrees_to_radians * N) - std::sin(degrees_to_radians * S)); + + // Calculate area + return area(radius) * latitude_fraction * longitude_fraction; +} + +double Sphere::greatCircleLatitudeGivenLongitude(const PointLonLat& A, + const PointLonLat& B, + double Clon) { + GreatCircle gc(A, B); + auto lat = gc.latitude(Clon); + return lat.size() == 1 ? lat[0] : std::numeric_limits::signaling_NaN(); +} + +void Sphere::greatCircleLongitudeGivenLatitude( + const PointLonLat& A, const PointLonLat& B, double Clat, double& Clon1, double& Clon2) { + GreatCircle gc(A, B); + auto lon = gc.longitude(Clat); + + Clon1 = lon.size() > 0 ? lon[0] : std::numeric_limits::signaling_NaN(); + Clon2 = lon.size() > 1 ? lon[1] : std::numeric_limits::signaling_NaN(); +} + +Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, double height, bool normalise_angle) { + ASSERT(radius > 0.); + + /* + * See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates + * numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line). + * + * cos α = sqrt( 1 - sin^2 α) is better conditioned than explicit cos α, and + * coupled with λ in [-180°, 180°[ the accuracy of the trigonometric + * functions is the same (before converting/multiplying its angle argument + * to radian) and explicitly chosing -180° over 180° for longitude. + * + * These three conditionings combined project very accurately to the sphere + * poles and quadrants. + */ + + if (!normalise_angle) { + assert_latitude(A.lat); + } + + const auto P = PointLonLat::make(A.lon, A.lat, -180.); + const auto lambda = degrees_to_radians * P.lon; + const auto phi = degrees_to_radians * P.lat; + + const auto sin_phi = std::sin(phi); + const auto cos_phi = std::sqrt(1. - sin_phi * sin_phi); + const auto sin_lambda = std::abs(P.lon) < 180. ? std::sin(lambda) : 0.; + const auto cos_lambda = std::abs(P.lon) > 90. ? std::cos(lambda) + : std::sqrt(1. - sin_lambda * sin_lambda); + + return {(radius + height) * cos_phi * cos_lambda, + (radius + height) * cos_phi * sin_lambda, + (radius + height) * sin_phi}; +} + +PointLonLat Sphere::convertCartesianToSpherical(double radius, const Point3& A) { + ASSERT(radius > 0.); + + // numerical conditioning for both z (poles) and y + + const double x = A[0]; + const double y = is_approximately_equal(A[1], 0.) ? 0. : A[1]; + const double z = std::min(radius, std::max(-radius, A[2])) / radius; + + return {radians_to_degrees * std::atan2(y, x), radians_to_degrees * std::asin(z)}; +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo diff --git a/src/eckit/geo/Sphere.h b/src/eckit/geo/Sphere.h new file mode 100644 index 000000000..cd6d75724 --- /dev/null +++ b/src/eckit/geo/Sphere.h @@ -0,0 +1,62 @@ +/* + * (C) Copyright 1996- 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. + */ + +#pragma once + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit::geo { + +//---------------------------------------------------------------------------------------------------------------------- + +class Point3; +class PointLonLat; + +//---------------------------------------------------------------------------------------------------------------------- + +struct Sphere { + /// Great-circle central angle between two points in radians + static double centralAngle(const PointLonLat&, + const PointLonLat&); + + /// Great-circle central angle between two points (Cartesian coordinates) in radians + static double centralAngle(double radius, const Point3&, const Point3&); + + /// Great-circle distance between two points in metres + static double distance(double radius, const PointLonLat&, const PointLonLat&); + + /// Great-circle distance between two points (Cartesian coordinates) in metres + static double distance(double radius, const Point3&, const Point3&); + + /// Surface area in square metres + static double area(double radius); + + /// Surface area between parallels and meridians defined by two points in square metres + static double area(double radius, const PointLonLat&, const PointLonLat&); + + // Great-circle intermediate latitude provided two circle points and intermediate longitude in degrees + static double greatCircleLatitudeGivenLongitude(const PointLonLat&, const PointLonLat&, double lon); + + // Great-circle intermediate longitude(s) provided two circle points and intermediate latitude in degrees + static void greatCircleLongitudeGivenLatitude(const PointLonLat&, const PointLonLat&, double lat, double& lon1, double& lon2); + + // Convert spherical to Cartesian coordinates + static Point3 convertSphericalToCartesian(double radius, + const PointLonLat&, + double height = 0., + bool normalise_angle = false); + + // Convert Cartesian to spherical coordinates + static PointLonLat convertCartesianToSpherical(double radius, const Point3&); +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo diff --git a/src/eckit/geo/SphereT.h b/src/eckit/geo/SphereT.h new file mode 100644 index 000000000..d638588dc --- /dev/null +++ b/src/eckit/geo/SphereT.h @@ -0,0 +1,88 @@ +/* + * (C) Copyright 1996- 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. + */ + +#pragma once + +#include "eckit/geo/Point3.h" +#include "eckit/geo/PointLonLat.h" +#include "eckit/geo/Sphere.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit::geo { + +//---------------------------------------------------------------------------------------------------------------------- + +class Point3; +class PointLonLat; + +//---------------------------------------------------------------------------------------------------------------------- + +/// Definition of a sphere parametrised with a geodetic datum +template +struct SphereT { + + /// Sphere radius in metres + inline static double radius() { return DATUM::radius(); } + + /// Great-circle central angle between two points in radians + inline static double centralAngle(const PointLonLat& A, + const PointLonLat& B) { + return Sphere::centralAngle(A, B); + } + + /// Great-circle central angle between two points (Cartesian coordinates) in radians + inline static double centralAngle(const Point3& A, const Point3& B) { + return Sphere::centralAngle(DATUM::radius(), A, B); + } + + /// Great-circle distance between two points in metres + inline static double distance(const PointLonLat& A, const PointLonLat& B) { + return Sphere::distance(DATUM::radius(), A, B); + } + + /// Great-circle distance between two points (Cartesian coordinates) in metres + inline static double distance(const Point3& A, const Point3& B) { return Sphere::distance(DATUM::radius(), A, B); } + + /// Surface area in square metres + inline static double area() { return Sphere::area(DATUM::radius()); } + + /// Surface area between parallels and meridians defined by two points in square metres + inline static double area(const PointLonLat& WestNorth, const PointLonLat& EastSouth) { + return Sphere::area(DATUM::radius(), WestNorth, EastSouth); + } + + // Great-circle intermediate latitude provided two circle points and intermediate longitude in degrees + inline static double greatCircleLatitudeGivenLongitude(const PointLonLat& A, const PointLonLat& B, double lon) { + return Sphere::greatCircleLatitudeGivenLongitude(A, B, lon); + } + + // Great-circle intermediate longitude(s) provided two circle points and intermediate latitude in degrees + inline static void greatCircleLongitudeGivenLatitude(const PointLonLat& A, const PointLonLat& B, + double lat, double& lon1, double& lon2) { + return Sphere::greatCircleLongitudeGivenLatitude(A, B, lat, lon1, lon2); + } + + // Convert spherical to Cartesian coordinates + inline static Point3 convertSphericalToCartesian(const PointLonLat& P, + double height = 0., + bool normalise_angle = false) { + return Sphere::convertSphericalToCartesian(DATUM::radius(), P, height, normalise_angle); + } + + // Convert Cartesian to spherical coordinates + inline static PointLonLat convertCartesianToSpherical(const Point3& P) { + return Sphere::convertCartesianToSpherical(DATUM::radius(), P); + } +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo diff --git a/src/eckit/geo/UnitSphere.h b/src/eckit/geo/UnitSphere.h new file mode 100644 index 000000000..380a981cc --- /dev/null +++ b/src/eckit/geo/UnitSphere.h @@ -0,0 +1,36 @@ +/* + * (C) Copyright 1996- 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. + */ + +#ifndef UnitSphere_H +#define UnitSphere_H + +#include "eckit/geo/SphereT.h" + +//------------------------------------------------------------------------------------------------------ + +namespace eckit::geo { + +//------------------------------------------------------------------------------------------------------ + +/// Definition of a unit datum +struct DatumUnit { + static constexpr double radius() { return 1.; } +}; + +//------------------------------------------------------------------------------------------------------ + +/// Definition of a unit sphere +using UnitSphere = SphereT; + +//------------------------------------------------------------------------------------------------------ + +} // namespace eckit::geo + +#endif diff --git a/src/eckit/geometry/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc similarity index 95% rename from src/eckit/geometry/area/BoundingBox.cc rename to src/eckit/geo/area/BoundingBox.cc index 2eaef3f5a..976e6db73 100644 --- a/src/eckit/geometry/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -10,20 +10,20 @@ */ -#include "eckit/geometry/area/BoundingBox.h" +#include "eckit/geo/area/BoundingBox.h" #include #include #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Point.h" -#include "eckit/geometry/Sphere.h" -#include "eckit/geometry/util.h" +#include "eckit/geo/Point.h" +#include "eckit/geo/Sphere.h" +#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geometry::area { +namespace eckit::geo::area { BoundingBox::BoundingBox(const Configuration& config) : @@ -148,4 +148,4 @@ BoundingBox BoundingBox::make(const BoundingBox&, const Projection&) { } -} // namespace eckit::geometry::area +} // namespace eckit::geo::area diff --git a/src/eckit/geometry/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h similarity index 93% rename from src/eckit/geometry/area/BoundingBox.h rename to src/eckit/geo/area/BoundingBox.h index 3609c2ed7..3964b749e 100644 --- a/src/eckit/geometry/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -14,17 +14,15 @@ #include -#include "eckit/geometry/Area.h" +#include "eckit/geo/Area.h" -namespace eckit { -namespace geometry { +namespace eckit::geo { class Projection; } -} // namespace eckit -namespace eckit::geometry::area { +namespace eckit::geo::area { class BoundingBox : public Area, protected std::array { @@ -126,4 +124,4 @@ class BoundingBox : public Area, protected std::array { }; -} // namespace eckit::geometry::area +} // namespace eckit::geo::area diff --git a/src/eckit/geo/eckit_geo_config.h.in b/src/eckit/geo/eckit_geo_config.h.in new file mode 100644 index 000000000..42ad9b678 --- /dev/null +++ b/src/eckit/geo/eckit_geo_config.h.in @@ -0,0 +1,5 @@ +#pragma once + +#cmakedefine01 eckit_HAVE_GEO_CACHING +#cmakedefine eckit_GEO_CACHE_PATH "@eckit_GEO_CACHE_PATH@" + diff --git a/src/eckit/geometry/grid/Reduced.cc b/src/eckit/geo/grid/Reduced.cc similarity index 89% rename from src/eckit/geometry/grid/Reduced.cc rename to src/eckit/geo/grid/Reduced.cc index 8f143dd3a..a738fffa5 100644 --- a/src/eckit/geometry/grid/Reduced.cc +++ b/src/eckit/geo/grid/Reduced.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geometry/grid/Reduced.h" +#include "eckit/geo/grid/Reduced.h" // #include <> -namespace eckit::geometry::grid { +namespace eckit::geo::grid { size_t Reduced::size() const { @@ -50,4 +50,4 @@ const std::vector& Reduced::niacc() const { } -} // namespace eckit::geometry::grid +} // namespace eckit::geo::grid diff --git a/src/eckit/geometry/grid/Reduced.h b/src/eckit/geo/grid/Reduced.h similarity index 89% rename from src/eckit/geometry/grid/Reduced.h rename to src/eckit/geo/grid/Reduced.h index 72983165e..5a7f6eb19 100644 --- a/src/eckit/geometry/grid/Reduced.h +++ b/src/eckit/geo/grid/Reduced.h @@ -12,15 +12,15 @@ #pragma once -#include "eckit/geometry/Grid.h" +#include "eckit/geo/Grid.h" -namespace eckit::geometry::iterator { +namespace eckit::geo::iterator { class Reduced; } -namespace eckit::geometry::grid { +namespace eckit::geo::grid { class Reduced : public Grid { @@ -104,8 +104,8 @@ class Reduced : public Grid { // -- Friends - friend class ::eckit::geometry::iterator::Reduced; + friend class ::eckit::geo::iterator::Reduced; }; -} // namespace eckit::geometry::grid +} // namespace eckit::geo::grid diff --git a/src/eckit/geometry/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc similarity index 83% rename from src/eckit/geometry/grid/Regular.cc rename to src/eckit/geo/grid/Regular.cc index 9861105c6..526bb6231 100644 --- a/src/eckit/geometry/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geometry/grid/Regular.h" +#include "eckit/geo/grid/Regular.h" // #include <> -namespace eckit::geometry::grid { +namespace eckit::geo::grid { Regular::Regular(const Configuration& config) : @@ -28,4 +28,4 @@ Regular::Regular(const area::BoundingBox& bbox) : } -} // namespace eckit::geometry::grid +} // namespace eckit::geo::grid diff --git a/src/eckit/geometry/grid/Regular.h b/src/eckit/geo/grid/Regular.h similarity index 88% rename from src/eckit/geometry/grid/Regular.h rename to src/eckit/geo/grid/Regular.h index 39fcf00e4..9607c43ac 100644 --- a/src/eckit/geometry/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -12,15 +12,15 @@ #pragma once -#include "eckit/geometry/Grid.h" +#include "eckit/geo/Grid.h" -namespace eckit::geometry::iterator { +namespace eckit::geo::iterator { class Regular; } -namespace eckit::geometry::grid { +namespace eckit::geo::grid { class Regular : public Grid { @@ -100,8 +100,8 @@ class Regular : public Grid { // -- Friends - friend class ::eckit::geometry::iterator::Regular; + friend class ::eckit::geo::iterator::Regular; }; -} // namespace eckit::geometry::grid +} // namespace eckit::geo::grid diff --git a/src/eckit/geometry/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc similarity index 65% rename from src/eckit/geometry/grid/Unstructured.cc rename to src/eckit/geo/grid/Unstructured.cc index 42f6284aa..de22d5745 100644 --- a/src/eckit/geometry/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -10,21 +10,21 @@ */ -#include "eckit/geometry/grid/Unstructured.h" +#include "eckit/geo/grid/Unstructured.h" -#include "eckit/geometry/iterator/Unstructured.h" +#include "eckit/geo/iterator/Unstructured.h" -namespace eckit::geometry::grid { +namespace eckit::geo::grid { Grid::iterator Unstructured::cbegin() const { - return iterator{new geometry::iterator::Unstructured(*this)}; + return iterator{new geo::iterator::Unstructured(*this)}; } Grid::iterator Unstructured::cend() const { - return iterator{new geometry::iterator::Unstructured(*this, size())}; + return iterator{new geo::iterator::Unstructured(*this, size())}; } @@ -33,4 +33,4 @@ Unstructured::Unstructured(const Configuration& config) : } -} // namespace eckit::geometry::grid +} // namespace eckit::geo::grid diff --git a/src/eckit/geometry/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h similarity index 88% rename from src/eckit/geometry/grid/Unstructured.h rename to src/eckit/geo/grid/Unstructured.h index 87b64bea9..bc9ce7ef5 100644 --- a/src/eckit/geometry/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -12,15 +12,15 @@ #pragma once -#include "eckit/geometry/Grid.h" +#include "eckit/geo/Grid.h" -namespace eckit::geometry::iterator { +namespace eckit::geo::iterator { class Unstructured; } -namespace eckit::geometry::grid { +namespace eckit::geo::grid { class Unstructured : public Grid { @@ -98,8 +98,8 @@ class Unstructured : public Grid { // -- Friends - friend class ::eckit::geometry::iterator::Unstructured; + friend class ::eckit::geo::iterator::Unstructured; }; -} // namespace eckit::geometry::grid +} // namespace eckit::geo::grid diff --git a/src/eckit/geometry/grid/reduced/HEALPix.cc b/src/eckit/geo/grid/reduced/HEALPix.cc similarity index 92% rename from src/eckit/geometry/grid/reduced/HEALPix.cc rename to src/eckit/geo/grid/reduced/HEALPix.cc index ed828c83c..32fc02347 100644 --- a/src/eckit/geometry/grid/reduced/HEALPix.cc +++ b/src/eckit/geo/grid/reduced/HEALPix.cc @@ -10,15 +10,15 @@ */ -#include "eckit/geometry/grid/reduced/HEALPix.h" +#include "eckit/geo/grid/reduced/HEALPix.h" #include "eckit/config/MappedConfiguration.h" -#include "eckit/geometry/iterator/Reduced.h" -#include "eckit/geometry/util.h" +#include "eckit/geo/iterator/Reduced.h" +#include "eckit/geo/util.h" #include "eckit/utils/Translator.h" -namespace eckit::geometry::grid::reduced { +namespace eckit::geo::grid::reduced { static Ordering ordering_from_string(const std::string& str) { @@ -40,12 +40,12 @@ HEALPix::HEALPix(size_t Nside, Ordering ordering) : Grid::iterator HEALPix::cbegin() const { - return ordering_ == Ordering::healpix_ring ? iterator{new geometry::iterator::Reduced(*this, 0)} : NOTIMP; + return ordering_ == Ordering::healpix_ring ? iterator{new geo::iterator::Reduced(*this, 0)} : NOTIMP; } Grid::iterator HEALPix::cend() const { - return ordering_ == Ordering::healpix_ring ? iterator{new geometry::iterator::Reduced(*this, size())} : NOTIMP; + return ordering_ == Ordering::healpix_ring ? iterator{new geo::iterator::Reduced(*this, size())} : NOTIMP; } @@ -131,4 +131,4 @@ static const GridRegisterType __grid_type("HEALPix"); static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); -} // namespace eckit::geometry::grid::reduced +} // namespace eckit::geo::grid::reduced diff --git a/src/eckit/geometry/grid/reduced/HEALPix.h b/src/eckit/geo/grid/reduced/HEALPix.h similarity index 93% rename from src/eckit/geometry/grid/reduced/HEALPix.h rename to src/eckit/geo/grid/reduced/HEALPix.h index e80dc06a5..d3a2599fb 100644 --- a/src/eckit/geometry/grid/reduced/HEALPix.h +++ b/src/eckit/geo/grid/reduced/HEALPix.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geometry/grid/Reduced.h" +#include "eckit/geo/grid/Reduced.h" -namespace eckit::geometry::grid::reduced { +namespace eckit::geo::grid::reduced { class HEALPix final : public Reduced { @@ -95,4 +95,4 @@ class HEALPix final : public Reduced { }; -} // namespace eckit::geometry::grid::reduced +} // namespace eckit::geo::grid::reduced diff --git a/src/eckit/geometry/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc similarity index 86% rename from src/eckit/geometry/grid/reduced/ReducedGaussian.cc rename to src/eckit/geo/grid/reduced/ReducedGaussian.cc index 0b5f25b3f..903d1dd29 100644 --- a/src/eckit/geometry/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -10,17 +10,17 @@ */ -#include "eckit/geometry/grid/reduced/ReducedGaussian.h" +#include "eckit/geo/grid/reduced/ReducedGaussian.h" #include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/iterator/Reduced.h" -#include "eckit/geometry/range/Gaussian.h" -#include "eckit/geometry/range/GlobalRegular.h" +#include "eckit/geo/iterator/Reduced.h" +#include "eckit/geo/range/Gaussian.h" +#include "eckit/geo/range/GlobalRegular.h" #include "eckit/utils/Translator.h" -namespace eckit::geometry::grid::reduced { +namespace eckit::geo::grid::reduced { ReducedGaussian::ReducedGaussian(const Configuration& config) : @@ -39,12 +39,12 @@ ReducedGaussian::ReducedGaussian(size_t N, const pl_type& pl, const area::Boundi Grid::iterator ReducedGaussian::cbegin() const { - return iterator{new geometry::iterator::Reduced(*this, 0)}; + return iterator{new geo::iterator::Reduced(*this, 0)}; } Grid::iterator ReducedGaussian::cend() const { - return iterator{new geometry::iterator::Reduced(*this, size())}; + return iterator{new geo::iterator::Reduced(*this, size())}; } @@ -100,4 +100,4 @@ static const GridRegisterName __grid_pattern_1("[nN][1 static const GridRegisterName __grid_pattern_2("[oO][1-9][0-9]*"); -} // namespace eckit::geometry::grid::reduced +} // namespace eckit::geo::grid::reduced diff --git a/src/eckit/geometry/grid/reduced/ReducedGaussian.h b/src/eckit/geo/grid/reduced/ReducedGaussian.h similarity index 88% rename from src/eckit/geometry/grid/reduced/ReducedGaussian.h rename to src/eckit/geo/grid/reduced/ReducedGaussian.h index 64c5429ab..eda111c14 100644 --- a/src/eckit/geometry/grid/reduced/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.h @@ -14,12 +14,12 @@ #include -#include "eckit/geometry/Range.h" -#include "eckit/geometry/grid/Reduced.h" -#include "eckit/geometry/util.h" +#include "eckit/geo/Range.h" +#include "eckit/geo/grid/Reduced.h" +#include "eckit/geo/util.h" -namespace eckit::geometry::grid::reduced { +namespace eckit::geo::grid::reduced { class ReducedGaussian : public Reduced { @@ -90,4 +90,4 @@ class ReducedGaussian : public Reduced { }; -} // namespace eckit::geometry::grid::reduced +} // namespace eckit::geo::grid::reduced diff --git a/src/eckit/geometry/grid/reduced/ReducedLatLon.cc b/src/eckit/geo/grid/reduced/ReducedLatLon.cc similarity index 72% rename from src/eckit/geometry/grid/reduced/ReducedLatLon.cc rename to src/eckit/geo/grid/reduced/ReducedLatLon.cc index 252e4f33a..e09eb61c4 100644 --- a/src/eckit/geometry/grid/reduced/ReducedLatLon.cc +++ b/src/eckit/geo/grid/reduced/ReducedLatLon.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geometry/grid/reduced/ReducedLatLon.h" +#include "eckit/geo/grid/reduced/ReducedLatLon.h" -#include "eckit/geometry/iterator/Reduced.h" +#include "eckit/geo/iterator/Reduced.h" -namespace eckit::geometry::grid::reduced { +namespace eckit::geo::grid::reduced { ReducedLatLon::ReducedLatLon(const Configuration& config) : @@ -24,12 +24,12 @@ ReducedLatLon::ReducedLatLon(const Configuration& config) : Grid::iterator ReducedLatLon::cbegin() const { - return iterator{new geometry::iterator::Reduced(*this, 0)}; + return iterator{new geo::iterator::Reduced(*this, 0)}; } Grid::iterator ReducedLatLon::cend() const { - return iterator{new geometry::iterator::Reduced(*this, size())}; + return iterator{new geo::iterator::Reduced(*this, size())}; } @@ -53,4 +53,4 @@ std::vector ReducedLatLon::longitudes(size_t j) const { } -} // namespace eckit::geometry::grid::reduced +} // namespace eckit::geo::grid::reduced diff --git a/src/eckit/geometry/grid/reduced/ReducedLatLon.h b/src/eckit/geo/grid/reduced/ReducedLatLon.h similarity index 90% rename from src/eckit/geometry/grid/reduced/ReducedLatLon.h rename to src/eckit/geo/grid/reduced/ReducedLatLon.h index 8cffad4d9..8fc6b306e 100644 --- a/src/eckit/geometry/grid/reduced/ReducedLatLon.h +++ b/src/eckit/geo/grid/reduced/ReducedLatLon.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geometry/grid/Reduced.h" +#include "eckit/geo/grid/Reduced.h" -namespace eckit::geometry::grid::reduced { +namespace eckit::geo::grid::reduced { class ReducedLatLon : public Reduced { @@ -79,4 +79,4 @@ class ReducedLatLon : public Reduced { }; -} // namespace eckit::geometry::grid::reduced +} // namespace eckit::geo::grid::reduced diff --git a/src/eckit/geometry/grid/regular/IrregularLatLon.cc b/src/eckit/geo/grid/regular/IrregularLatLon.cc similarity index 85% rename from src/eckit/geometry/grid/regular/IrregularLatLon.cc rename to src/eckit/geo/grid/regular/IrregularLatLon.cc index 8a1999122..e43d55e6f 100644 --- a/src/eckit/geometry/grid/regular/IrregularLatLon.cc +++ b/src/eckit/geo/grid/regular/IrregularLatLon.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geometry/grid/regular/IrregularLatLon.h" +#include "eckit/geo/grid/regular/IrregularLatLon.h" // #include <> -namespace eckit::geometry::grid::regular { +namespace eckit::geo::grid::regular { IrregularLatLon::IrregularLatLon(const Configuration& config) : @@ -53,4 +53,4 @@ const std::vector& IrregularLatLon::latitudes() const { } -} // namespace eckit::geometry::grid::regular +} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geometry/grid/regular/IrregularLatLon.h b/src/eckit/geo/grid/regular/IrregularLatLon.h similarity index 90% rename from src/eckit/geometry/grid/regular/IrregularLatLon.h rename to src/eckit/geo/grid/regular/IrregularLatLon.h index f7558bfb3..47db1c1f3 100644 --- a/src/eckit/geometry/grid/regular/IrregularLatLon.h +++ b/src/eckit/geo/grid/regular/IrregularLatLon.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geometry/grid/Regular.h" +#include "eckit/geo/grid/Regular.h" -namespace eckit::geometry::grid::regular { +namespace eckit::geo::grid::regular { class IrregularLatLon final : public Regular { @@ -79,4 +79,4 @@ class IrregularLatLon final : public Regular { }; -} // namespace eckit::geometry::grid::regular +} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geometry/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc similarity index 83% rename from src/eckit/geometry/grid/regular/RegularGaussian.cc rename to src/eckit/geo/grid/regular/RegularGaussian.cc index a68e9c262..b78468439 100644 --- a/src/eckit/geometry/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -10,16 +10,16 @@ */ -#include "eckit/geometry/grid/regular/RegularGaussian.h" +#include "eckit/geo/grid/regular/RegularGaussian.h" #include "eckit/config/MappedConfiguration.h" -#include "eckit/geometry/iterator/Regular.h" -#include "eckit/geometry/range/Gaussian.h" -#include "eckit/geometry/range/LocalRegular.h" +#include "eckit/geo/iterator/Regular.h" +#include "eckit/geo/range/Gaussian.h" +#include "eckit/geo/range/LocalRegular.h" #include "eckit/utils/Translator.h" -namespace eckit::geometry::grid::regular { +namespace eckit::geo::grid::regular { // LocalRegular(size_t n, double a, double b, bool endpoint, double precision = 0.); @@ -43,12 +43,12 @@ RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : Grid::iterator RegularGaussian::cbegin() const { - return iterator{new geometry::iterator::Regular(*this, 0)}; + return iterator{new geo::iterator::Regular(*this, 0)}; } Grid::iterator RegularGaussian::cend() const { - return iterator{new geometry::iterator::Regular(*this, size())}; + return iterator{new geo::iterator::Regular(*this, size())}; } @@ -75,4 +75,4 @@ static const GridRegisterType __grid_type("regular_gg"); static const GridRegisterName __grid_pattern("[fF][1-9][0-9]*"); -} // namespace eckit::geometry::grid::regular +} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geometry/grid/regular/RegularGaussian.h b/src/eckit/geo/grid/regular/RegularGaussian.h similarity index 90% rename from src/eckit/geometry/grid/regular/RegularGaussian.h rename to src/eckit/geo/grid/regular/RegularGaussian.h index 15bb2a07d..d62ace883 100644 --- a/src/eckit/geometry/grid/regular/RegularGaussian.h +++ b/src/eckit/geo/grid/regular/RegularGaussian.h @@ -12,11 +12,11 @@ #pragma once -#include "eckit/geometry/Range.h" -#include "eckit/geometry/grid/Regular.h" +#include "eckit/geo/Range.h" +#include "eckit/geo/grid/Regular.h" -namespace eckit::geometry::grid::regular { +namespace eckit::geo::grid::regular { class RegularGaussian final : public Regular { @@ -86,4 +86,4 @@ class RegularGaussian final : public Regular { }; -} // namespace eckit::geometry::grid::regular +} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geometry/grid/regular/RegularLatLon.cc b/src/eckit/geo/grid/regular/RegularLatLon.cc similarity index 72% rename from src/eckit/geometry/grid/regular/RegularLatLon.cc rename to src/eckit/geo/grid/regular/RegularLatLon.cc index 955695f89..d286b7b5f 100644 --- a/src/eckit/geometry/grid/regular/RegularLatLon.cc +++ b/src/eckit/geo/grid/regular/RegularLatLon.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geometry/grid/regular/RegularLatLon.h" +#include "eckit/geo/grid/regular/RegularLatLon.h" -#include "eckit/geometry/iterator/Regular.h" +#include "eckit/geo/iterator/Regular.h" -namespace eckit::geometry::grid::regular { +namespace eckit::geo::grid::regular { RegularLatLon::RegularLatLon(const Configuration& config) : @@ -24,12 +24,12 @@ RegularLatLon::RegularLatLon(const Configuration& config) : Grid::iterator RegularLatLon::cbegin() const { - return iterator{new geometry::iterator::Regular(*this, 0)}; + return iterator{new geo::iterator::Regular(*this, 0)}; } Grid::iterator RegularLatLon::cend() const { - return iterator{new geometry::iterator::Regular(*this, size())}; + return iterator{new geo::iterator::Regular(*this, size())}; } @@ -53,4 +53,4 @@ const std::vector& RegularLatLon::latitudes() const { } -} // namespace eckit::geometry::grid::regular +} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geometry/grid/regular/RegularLatLon.h b/src/eckit/geo/grid/regular/RegularLatLon.h similarity index 90% rename from src/eckit/geometry/grid/regular/RegularLatLon.h rename to src/eckit/geo/grid/regular/RegularLatLon.h index 9bd4fc9fc..7e61a8034 100644 --- a/src/eckit/geometry/grid/regular/RegularLatLon.h +++ b/src/eckit/geo/grid/regular/RegularLatLon.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geometry/grid/Regular.h" +#include "eckit/geo/grid/Regular.h" -namespace eckit::geometry::grid::regular { +namespace eckit::geo::grid::regular { class RegularLatLon final : public Regular { @@ -79,4 +79,4 @@ class RegularLatLon final : public Regular { }; -} // namespace eckit::geometry::grid::regular +} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geometry/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc similarity index 91% rename from src/eckit/geometry/grid/unstructured/ORCA.cc rename to src/eckit/geo/grid/unstructured/ORCA.cc index 24181920a..401401208 100644 --- a/src/eckit/geometry/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -10,14 +10,14 @@ */ -#include "eckit/geometry/grid/unstructured/ORCA.h" +#include "eckit/geo/grid/unstructured/ORCA.h" #include "eckit/codec/codec.h" #include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" -#include "eckit/geometry/LibEcKitGeometry.h" -#include "eckit/geometry/area/BoundingBox.h" -#include "eckit/geometry/iterator/Unstructured.h" +#include "eckit/geo/LibEcKitGeo.h" +#include "eckit/geo/area/BoundingBox.h" +#include "eckit/geo/iterator/Unstructured.h" #include "eckit/io/Length.h" #include "eckit/log/Bytes.h" #include "eckit/log/Timer.h" @@ -30,7 +30,7 @@ #endif -namespace eckit::geometry::grid::unstructured { +namespace eckit::geo::grid::unstructured { namespace { @@ -67,10 +67,10 @@ ORCA::ORCA(const Configuration& config) : dimensions_{-1, -1}, halo_{-1, -1, -1, -1}, pivot_{-1, -1} { - PathName path = config.getString("path", LibEcKitGeometry::cacheDir() + "/eckit/geometry/orca/" + uid_ + ".atlas"); + PathName path = config.getString("path", LibEcKitGeo::cacheDir() + "/eckit/geo/orca/" + uid_ + ".atlas"); #if eckit_HAVE_CURL // for eckit::URLHandle - if (!path.exists() && LibEcKitGeometry::caching()) { + if (!path.exists() && LibEcKitGeo::caching()) { auto dir = path.dirName(); dir.mkdir(); ASSERT(dir.exists()); @@ -204,12 +204,12 @@ size_t ORCA::write(const PathName& p, const std::string& compression) { Grid::iterator ORCA::cbegin() const { - return iterator{new geometry::iterator::Unstructured(*this, 0)}; + return iterator{new geo::iterator::Unstructured(*this, 0)}; } Grid::iterator ORCA::cend() const { - return iterator{new geometry::iterator::Unstructured(*this, size())}; + return iterator{new geo::iterator::Unstructured(*this, size())}; } @@ -233,4 +233,4 @@ static const GridRegisterType __grid_type("ORCA"); static const GridRegisterName __grid_pattern(GridRegisterName::uid_pattern); -} // namespace eckit::geometry::grid::unstructured +} // namespace eckit::geo::grid::unstructured diff --git a/src/eckit/geometry/grid/unstructured/ORCA.h b/src/eckit/geo/grid/unstructured/ORCA.h similarity index 94% rename from src/eckit/geometry/grid/unstructured/ORCA.h rename to src/eckit/geo/grid/unstructured/ORCA.h index 018c03980..aff86a991 100644 --- a/src/eckit/geometry/grid/unstructured/ORCA.h +++ b/src/eckit/geo/grid/unstructured/ORCA.h @@ -16,7 +16,7 @@ #include #include -#include "eckit/geometry/grid/Unstructured.h" +#include "eckit/geo/grid/Unstructured.h" namespace eckit { @@ -24,7 +24,7 @@ class PathName; } -namespace eckit::geometry::grid::unstructured { +namespace eckit::geo::grid::unstructured { class ORCA final : public Unstructured { @@ -125,4 +125,4 @@ class ORCA final : public Unstructured { }; -} // namespace eckit::geometry::grid::unstructured +} // namespace eckit::geo::grid::unstructured diff --git a/src/eckit/geometry/iterator/Reduced.cc b/src/eckit/geo/iterator/Reduced.cc similarity index 92% rename from src/eckit/geometry/iterator/Reduced.cc rename to src/eckit/geo/iterator/Reduced.cc index 7bf3654ca..a2b39dc8e 100644 --- a/src/eckit/geometry/iterator/Reduced.cc +++ b/src/eckit/geo/iterator/Reduced.cc @@ -10,20 +10,20 @@ */ -#include "eckit/geometry/iterator/Reduced.h" +#include "eckit/geo/iterator/Reduced.h" #include #include #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/grid/Reduced.h" +#include "eckit/geo/grid/Reduced.h" -namespace eckit::geometry::iterator { +namespace eckit::geo::iterator { Reduced::Reduced(const Grid& grid, size_t index) : - geometry::Iterator(grid), + geo::Iterator(grid), grid_(dynamic_cast(grid)), latitudes_(grid_.latitudes()), niacc_(grid_.niacc()), @@ -93,4 +93,4 @@ size_t Reduced::j(size_t idx) const { } -} // namespace eckit::geometry::iterator +} // namespace eckit::geo::iterator diff --git a/src/eckit/geometry/iterator/Reduced.h b/src/eckit/geo/iterator/Reduced.h similarity index 88% rename from src/eckit/geometry/iterator/Reduced.h rename to src/eckit/geo/iterator/Reduced.h index 6a55de6bc..3f84e3079 100644 --- a/src/eckit/geometry/iterator/Reduced.h +++ b/src/eckit/geo/iterator/Reduced.h @@ -12,18 +12,18 @@ #pragma once -#include "eckit/geometry/Iterator.h" +#include "eckit/geo/Iterator.h" -namespace eckit::geometry::grid { +namespace eckit::geo::grid { class Reduced; } -namespace eckit::geometry::iterator { +namespace eckit::geo::iterator { -class Reduced final : public geometry::Iterator { +class Reduced final : public geo::Iterator { public: // -- Types // None @@ -94,4 +94,4 @@ class Reduced final : public geometry::Iterator { }; -} // namespace eckit::geometry::iterator +} // namespace eckit::geo::iterator diff --git a/src/eckit/geometry/iterator/Regular.cc b/src/eckit/geo/iterator/Regular.cc similarity index 88% rename from src/eckit/geometry/iterator/Regular.cc rename to src/eckit/geo/iterator/Regular.cc index eedc3fae8..06d000b05 100644 --- a/src/eckit/geometry/iterator/Regular.cc +++ b/src/eckit/geo/iterator/Regular.cc @@ -10,17 +10,17 @@ */ -#include "eckit/geometry/iterator/Regular.h" +#include "eckit/geo/iterator/Regular.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/grid/Regular.h" +#include "eckit/geo/grid/Regular.h" -namespace eckit::geometry::iterator { +namespace eckit::geo::iterator { Regular::Regular(const Grid& grid, size_t index) : - geometry::Iterator(grid), + geo::Iterator(grid), grid_(dynamic_cast(grid)), longitudes_(grid_.longitudes()), latitudes_(grid_.latitudes()), @@ -72,4 +72,4 @@ Point Regular::operator*() const { } -} // namespace eckit::geometry::iterator +} // namespace eckit::geo::iterator diff --git a/src/eckit/geometry/iterator/Regular.h b/src/eckit/geo/iterator/Regular.h similarity index 91% rename from src/eckit/geometry/iterator/Regular.h rename to src/eckit/geo/iterator/Regular.h index 1ff22b59d..c4b925bb3 100644 --- a/src/eckit/geometry/iterator/Regular.h +++ b/src/eckit/geo/iterator/Regular.h @@ -12,15 +12,15 @@ #pragma once -#include "eckit/geometry/Iterator.h" +#include "eckit/geo/Iterator.h" -namespace eckit::geometry::grid { +namespace eckit::geo::grid { class Regular; } -namespace eckit::geometry::iterator { +namespace eckit::geo::iterator { class Regular final : public Iterator { @@ -93,4 +93,4 @@ class Regular final : public Iterator { }; -} // namespace eckit::geometry::iterator +} // namespace eckit::geo::iterator diff --git a/src/eckit/geometry/iterator/Unstructured.cc b/src/eckit/geo/iterator/Unstructured.cc similarity index 84% rename from src/eckit/geometry/iterator/Unstructured.cc rename to src/eckit/geo/iterator/Unstructured.cc index ab5379403..27ad5cb60 100644 --- a/src/eckit/geometry/iterator/Unstructured.cc +++ b/src/eckit/geo/iterator/Unstructured.cc @@ -10,17 +10,17 @@ */ -#include "eckit/geometry/iterator/Unstructured.h" +#include "eckit/geo/iterator/Unstructured.h" -#include "eckit/geometry/Grid.h" -#include "eckit/geometry/grid/Unstructured.h" +#include "eckit/geo/Grid.h" +#include "eckit/geo/grid/Unstructured.h" -namespace eckit::geometry::iterator { +namespace eckit::geo::iterator { Unstructured::Unstructured(const Grid& grid, size_t index) : - geometry::Iterator(grid), + geo::Iterator(grid), index_(index), index_size_(grid.size()), longitudes_(dynamic_cast(grid).longitudes()), @@ -31,7 +31,7 @@ Unstructured::Unstructured(const Grid& grid, size_t index) : } -bool Unstructured::operator==(const geometry::Iterator& other) const { +bool Unstructured::operator==(const geo::Iterator& other) const { const auto* another = dynamic_cast(&other); return another != nullptr && index_ == another->index_ && uid_ == another->uid_; } @@ -68,4 +68,4 @@ Point Unstructured::operator*() const { } -} // namespace eckit::geometry::iterator +} // namespace eckit::geo::iterator diff --git a/src/eckit/geometry/iterator/Unstructured.h b/src/eckit/geo/iterator/Unstructured.h similarity index 89% rename from src/eckit/geometry/iterator/Unstructured.h rename to src/eckit/geo/iterator/Unstructured.h index b3f998c1a..57109f1b2 100644 --- a/src/eckit/geometry/iterator/Unstructured.h +++ b/src/eckit/geo/iterator/Unstructured.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geometry/Iterator.h" +#include "eckit/geo/Iterator.h" -namespace eckit::geometry::iterator { +namespace eckit::geo::iterator { class Unstructured final : public Iterator { @@ -69,7 +69,7 @@ class Unstructured final : public Iterator { // -- Overridden methods - bool operator==(const geometry::Iterator&) const override; + bool operator==(const geo::Iterator&) const override; bool operator++() override; bool operator+=(diff_t) override; @@ -89,4 +89,4 @@ class Unstructured final : public Iterator { }; -} // namespace eckit::geometry::iterator +} // namespace eckit::geo::iterator diff --git a/src/eckit/geo/polygon/LonLatPolygon.cc b/src/eckit/geo/polygon/LonLatPolygon.cc new file mode 100644 index 000000000..a39bad3ff --- /dev/null +++ b/src/eckit/geo/polygon/LonLatPolygon.cc @@ -0,0 +1,175 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/polygon/LonLatPolygon.h" + +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/CoordinateHelpers.h" +#include "eckit/types/FloatCompare.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit::geo::polygon { + +//---------------------------------------------------------------------------------------------------------------------- + +namespace { + +inline bool is_approximately_equal(double a, double b) { + return types::is_approximately_equal(a, b, 1e-10); +} + +inline bool is_approximately_greater_or_equal(double a, double b) { + return a >= b || is_approximately_equal(a, b); +} + +inline double cross_product_analog(const Point2& A, const Point2& B, const Point2& C) { + return (A.x() - C.x()) * (B.y() - C.y()) - (A.y() - C.y()) * (B.x() - C.x()); +} + +inline int on_direction(double a, double b, double c) { + return a <= b && b <= c ? 1 : c <= b && b <= a ? -1 + : 0; +}; + +inline int on_side(const Point2& P, const Point2& A, const Point2& B) { + const auto p = cross_product_analog(P, A, B); + return is_approximately_equal(p, 0) ? 0 : p > 0 ? 1 + : -1; +} + +} // namespace + +//---------------------------------------------------------------------------------------------------------------------- + +LonLatPolygon::LonLatPolygon(const std::vector& points, bool includePoles) : + container_type(points) { + ASSERT(points.size() > 1); + ASSERT(is_approximately_equal(points.front()[LON], points.back()[LON]) && is_approximately_equal(points.front()[LAT], points.back()[LAT])); + + if (points.size() > 2) { + clear(); // assumes reserved size is kept + push_back(points.front()); + push_back(points[1]); + + for (size_t i = 2; i < points.size(); ++i) { + auto A = points[i]; + + // if new point is aligned with existing edge (cross product ~= 0) make the edge longer + const auto& B = back(); + const auto& C = operator[](size() - 2); + if (is_approximately_equal(0., cross_product_analog(A, B, C))) { + back() = A; + continue; + } + + push_back(A); + } + } + + max_ = min_ = front(); + for (const auto& p : *this) { + min_ = value_type::componentsMin(min_, p); + max_ = value_type::componentsMax(max_, p); + } + + includeNorthPole_ = includePoles && is_approximately_equal(max_[LAT], 90); + includeSouthPole_ = includePoles && is_approximately_equal(min_[LAT], -90); + ASSERT(is_approximately_greater_or_equal(min_[LAT], -90)); + ASSERT(is_approximately_greater_or_equal(90, max_[LAT])); + + quickCheckLongitude_ = is_approximately_greater_or_equal(360, max_[LON] - min_[LON]); +} + +void LonLatPolygon::print(std::ostream& out) const { + out << "["; + const auto* sep = ""; + for (const auto& p : *this) { + out << sep << p; + sep = ", "; + } + out << "]"; +} + +std::ostream& operator<<(std::ostream& out, const LonLatPolygon& pc) { + pc.print(out); + return out; +} + +bool LonLatPolygon::contains(const Point2& Plonlat, bool normalise_angle) const { + if (!normalise_angle) { + assert_latitude_range(Plonlat[LAT]); + } + + const Point2 p = canonicaliseOnSphere(Plonlat, min_[LON]); + auto lat = p[LAT]; + auto lon = p[LON]; + + // check poles + if (includeNorthPole_ && is_approximately_equal(lat, 90)) { + return true; + } + if (includeSouthPole_ && is_approximately_equal(lat, -90)) { + return true; + } + + // check bounding box + if (!is_approximately_greater_or_equal(lat, min_[LAT]) || !is_approximately_greater_or_equal(max_[LAT], lat)) { + return false; + } + if (quickCheckLongitude_) { + if (!is_approximately_greater_or_equal(lon, min_[LON]) || !is_approximately_greater_or_equal(max_[LON], lon)) { + return false; + } + } + + do { + // winding number + int wn = 0; + int prev = 0; + + // loop on polygon edges + for (size_t i = 1; i < size(); ++i) { + const auto& A = operator[](i - 1); + const auto& B = operator[](i); + + // check point-edge side and direction, testing if P is on|above|below (in latitude) of a A,B polygon edge, by: + // - intersecting "up" on forward crossing & P above edge, or + // - intersecting "down" on backward crossing & P below edge + const auto direction = on_direction(A[LAT], lat, B[LAT]); + if (direction != 0) { + const auto side = on_side({lon, lat}, A, B); + if (side == 0 && on_direction(A[LON], lon, B[LON]) != 0) { + return true; + } + if ((prev != 1 && direction > 0 && side > 0) || (prev != -1 && direction < 0 && side < 0)) { + prev = direction; + wn += direction; + } + } + } + + // wn == 0 only when P is outside + if (wn != 0) { + return true; + } + + lon += 360; + } while (lon <= max_[LON]); + + return false; +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo::polygon diff --git a/src/eckit/geo/polygon/LonLatPolygon.h b/src/eckit/geo/polygon/LonLatPolygon.h new file mode 100644 index 000000000..f82282f2d --- /dev/null +++ b/src/eckit/geo/polygon/LonLatPolygon.h @@ -0,0 +1,82 @@ +/* + * (C) Copyright 1996- 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. + */ + +#pragma once + +#include +#include + +#include "eckit/geo/Point2.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit::geo::polygon { + +//---------------------------------------------------------------------------------------------------------------------- + +class LonLatPolygon : protected std::vector { +public: + // -- Types + using container_type = std::vector; + using container_type::value_type; + + // -- Constructors + + explicit LonLatPolygon(const container_type& points, bool includePoles = true); + + template + LonLatPolygon(Point2Iterator begin, Point2Iterator end, bool includePoles = true) : + LonLatPolygon(container_type(begin, end), includePoles) {} + + LonLatPolygon(const LonLatPolygon&) = default; + LonLatPolygon(LonLatPolygon&&) = default; + + // -- Destructor + + virtual ~LonLatPolygon() = default; + + // -- Operators + + LonLatPolygon& operator=(const LonLatPolygon&) = default; + LonLatPolygon& operator=(LonLatPolygon&&) = default; + + // -- Methods + + const Point2& max() const { return max_; } + const Point2& min() const { return min_; } + + using container_type::operator[]; + using container_type::size; + + /// @brief Point-in-polygon test based on winding number + /// @note reference Inclusion of a Point in a Polygon + /// @param[in] P given point + /// @param[in] normalise_angle normalise point angles + /// @return if point (lon,lat) is in polygon + bool contains(const Point2& Plonlat, bool normalise_angle = false) const; + +private: + // -- Methods + + void print(std::ostream&) const; + friend std::ostream& operator<<(std::ostream&, const LonLatPolygon&); + + // -- Members + + Point2 max_; + Point2 min_; + bool includeNorthPole_; + bool includeSouthPole_; + bool quickCheckLongitude_; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo::polygon diff --git a/src/eckit/geo/polygon/Polygon.cc b/src/eckit/geo/polygon/Polygon.cc new file mode 100644 index 000000000..6b5da73d2 --- /dev/null +++ b/src/eckit/geo/polygon/Polygon.cc @@ -0,0 +1,66 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/geo/polygon/Polygon.h" + +//---------------------------------------------------------------------------------------------------------------------- + +namespace eckit::geo::polygon { + +//---------------------------------------------------------------------------------------------------------------------- + +bool Polygon::congruent(const Polygon& p) const { + if (empty()) { + return true; + } + + if (size() != p.size()) { + return false; + } + + int offset = -1; + for (int i = 0; i < size(); i++) { + if (at(i) == p.at(0)) { + offset = i; + break; + } + } + + if (offset == -1) { + return false; + } + + for (int i = 1; i < size(); i++) { + if (at((i + offset) % size()) != p.at(i)) { + return false; + } + } + return true; +} + +void Polygon::print(std::ostream& s) const { + if (empty()) { + s << "[]"; + return; + } + + char z = '['; + for (const auto& v : *this) { + s << z << v; + z = ','; + } + s << ']'; +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::geo::polygon diff --git a/src/eckit/geo/polygon/Polygon.h b/src/eckit/geo/polygon/Polygon.h new file mode 100644 index 000000000..4664be43e --- /dev/null +++ b/src/eckit/geo/polygon/Polygon.h @@ -0,0 +1,55 @@ +/* + * (C) Copyright 1996- 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. + */ + +#pragma once + +#include +#include + +#include "eckit/geo/Point2.h" + +//------------------------------------------------------------------------------------------------------ + +namespace eckit::geo::polygon { + +//------------------------------------------------------------------------------------------------------ + +class Polygon : protected std::deque { +public: + using container_type = std::deque; + using container_type::value_type; + + Polygon() = default; + + Polygon(std::initializer_list l) : + container_type(l) {} + + using container_type::push_back; + using container_type::push_front; + + size_t num_vertices() const { return size(); } + + const value_type& vertex(size_t idx) const { return at(idx); } + + bool sameAs(const Polygon& p) const { return *this == p; } + + bool congruent(const Polygon&) const; + + void print(std::ostream&) const; + + friend std::ostream& operator<<(std::ostream& s, const Polygon& p) { + p.print(s); + return s; + } +}; + +//------------------------------------------------------------------------------------------------------ + +} // namespace eckit::geo::polygon diff --git a/src/eckit/geometry/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc similarity index 90% rename from src/eckit/geometry/projection/LonLatToXYZ.cc rename to src/eckit/geo/projection/LonLatToXYZ.cc index c3d76abff..d7a4e7ec3 100644 --- a/src/eckit/geometry/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -10,15 +10,15 @@ */ -#include "eckit/geometry/projection/LonLatToXYZ.h" +#include "eckit/geo/projection/LonLatToXYZ.h" #include "eckit/config/Configuration.h" -#include "eckit/geometry/EllipsoidOfRevolution.h" -#include "eckit/geometry/Sphere.h" +#include "eckit/geo/EllipsoidOfRevolution.h" +#include "eckit/geo/Sphere.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geometry::projection { +namespace eckit::geo::projection { static ProjectionBuilder __projection("ll_to_xyz"); @@ -69,4 +69,4 @@ LonLatToXYZ::LonLatToXYZ(const Configuration& config) : config.getDouble("b", config.getDouble("R", 1.))) {} -} // namespace eckit::geometry::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geometry/projection/LonLatToXYZ.h b/src/eckit/geo/projection/LonLatToXYZ.h similarity index 94% rename from src/eckit/geometry/projection/LonLatToXYZ.h rename to src/eckit/geo/projection/LonLatToXYZ.h index 4c8c49cf8..c47061fd0 100644 --- a/src/eckit/geometry/projection/LonLatToXYZ.h +++ b/src/eckit/geo/projection/LonLatToXYZ.h @@ -14,10 +14,10 @@ #include -#include "eckit/geometry/Projection.h" +#include "eckit/geo/Projection.h" -namespace eckit::geometry::projection { +namespace eckit::geo::projection { /// Calculate coordinates of a point on a sphere or spheroid, in [x, y, z] @@ -94,4 +94,4 @@ class LonLatToXYZ final : public Projection { }; -} // namespace eckit::geometry::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geometry/projection/None.cc b/src/eckit/geo/projection/None.cc similarity index 84% rename from src/eckit/geometry/projection/None.cc rename to src/eckit/geo/projection/None.cc index 387f41d4e..c3df3b4ad 100644 --- a/src/eckit/geometry/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -10,10 +10,10 @@ */ -#include "eckit/geometry/projection/None.h" +#include "eckit/geo/projection/None.h" -namespace eckit::geometry::projection { +namespace eckit::geo::projection { static ProjectionBuilder __projection1(""); @@ -25,4 +25,4 @@ static ProjectionBuilder __projection4("plate-carree"); None::None(const Configuration&) {} -} // namespace eckit::geometry::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geometry/projection/None.h b/src/eckit/geo/projection/None.h similarity index 90% rename from src/eckit/geometry/projection/None.h rename to src/eckit/geo/projection/None.h index f6c332e09..1a9fc3ff5 100644 --- a/src/eckit/geometry/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geometry/Projection.h" +#include "eckit/geo/Projection.h" -namespace eckit::geometry::projection { +namespace eckit::geo::projection { class None final : public Projection { @@ -75,4 +75,4 @@ class None final : public Projection { }; -} // namespace eckit::geometry::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geometry/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc similarity index 96% rename from src/eckit/geometry/projection/PROJ.cc rename to src/eckit/geo/projection/PROJ.cc index 880472d6f..f84130307 100644 --- a/src/eckit/geometry/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -10,13 +10,13 @@ */ -#include "eckit/geometry/projection/PROJ.h" +#include "eckit/geo/projection/PROJ.h" #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" -namespace eckit::geometry::projection { +namespace eckit::geo::projection { static ProjectionBuilder __projection("proj"); @@ -123,4 +123,4 @@ Point PROJ::inv(const Point& q) const { } -} // namespace eckit::geometry::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geometry/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h similarity index 95% rename from src/eckit/geometry/projection/PROJ.h rename to src/eckit/geo/projection/PROJ.h index 5b5f0ae7b..fe87a74c2 100644 --- a/src/eckit/geometry/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -16,10 +16,10 @@ #include -#include "eckit/geometry/Projection.h" +#include "eckit/geo/Projection.h" -namespace eckit::geometry::projection { +namespace eckit::geo::projection { /// Calculate coordinates using PROJ @@ -118,4 +118,4 @@ class PROJ final : public Projection { }; -} // namespace eckit::geometry::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geometry/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc similarity index 95% rename from src/eckit/geometry/projection/Rotation.cc rename to src/eckit/geo/projection/Rotation.cc index 7871a4fdd..cac28fba1 100644 --- a/src/eckit/geometry/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -10,19 +10,19 @@ */ -#include "eckit/geometry/projection/Rotation.h" +#include "eckit/geo/projection/Rotation.h" #include #include #include "eckit/config/Configuration.h" -#include "eckit/geometry/UnitSphere.h" -#include "eckit/geometry/util.h" +#include "eckit/geo/UnitSphere.h" +#include "eckit/geo/util.h" #include "eckit/maths/Matrix3.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geometry::projection { +namespace eckit::geo::projection { static ProjectionBuilder __projection("rotation"); @@ -105,4 +105,4 @@ Rotation::Rotation(const Configuration& config) : config.getDouble("angle", 0)) {} -} // namespace eckit::geometry::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geometry/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h similarity index 94% rename from src/eckit/geometry/projection/Rotation.h rename to src/eckit/geo/projection/Rotation.h index 4a69450dd..2ad36a4da 100644 --- a/src/eckit/geometry/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -14,10 +14,10 @@ #include -#include "eckit/geometry/Projection.h" +#include "eckit/geo/Projection.h" -namespace eckit::geometry::projection { +namespace eckit::geo::projection { /// Calculate coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle @@ -96,4 +96,4 @@ class Rotation final : public Projection { }; -} // namespace eckit::geometry::projection +} // namespace eckit::geo::projection diff --git a/src/eckit/geometry/range/Gaussian.cc b/src/eckit/geo/range/Gaussian.cc similarity index 92% rename from src/eckit/geometry/range/Gaussian.cc rename to src/eckit/geo/range/Gaussian.cc index 71378bac5..e5db373e0 100644 --- a/src/eckit/geometry/range/Gaussian.cc +++ b/src/eckit/geo/range/Gaussian.cc @@ -10,16 +10,16 @@ */ -#include "eckit/geometry/range/Gaussian.h" +#include "eckit/geo/range/Gaussian.h" #include #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/util.h" +#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geometry::range { +namespace eckit::geo::range { Gaussian::Gaussian(size_t N) : @@ -81,4 +81,4 @@ const std::vector& Gaussian::values() const { } -} // namespace eckit::geometry::range +} // namespace eckit::geo::range diff --git a/src/eckit/geometry/range/Gaussian.h b/src/eckit/geo/range/Gaussian.h similarity index 92% rename from src/eckit/geometry/range/Gaussian.h rename to src/eckit/geo/range/Gaussian.h index d8206398c..34cf76ed9 100644 --- a/src/eckit/geometry/range/Gaussian.h +++ b/src/eckit/geo/range/Gaussian.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geometry/Range.h" +#include "eckit/geo/Range.h" -namespace eckit::geometry::range { +namespace eckit::geo::range { class Gaussian final : public Range { @@ -79,4 +79,4 @@ class Gaussian final : public Range { }; -} // namespace eckit::geometry::range +} // namespace eckit::geo::range diff --git a/src/eckit/geometry/range/GlobalRegular.cc b/src/eckit/geo/range/GlobalRegular.cc similarity index 85% rename from src/eckit/geometry/range/GlobalRegular.cc rename to src/eckit/geo/range/GlobalRegular.cc index d9e98b433..7571bcaa2 100644 --- a/src/eckit/geometry/range/GlobalRegular.cc +++ b/src/eckit/geo/range/GlobalRegular.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geometry/range/GlobalRegular.h" +#include "eckit/geo/range/GlobalRegular.h" -#include "eckit/geometry/util.h" +#include "eckit/geo/util.h" -namespace eckit::geometry::range { +namespace eckit::geo::range { GlobalRegular::GlobalRegular(size_t n, double a, double b, double precision) : @@ -40,4 +40,4 @@ const std::vector& GlobalRegular::values() const { } -} // namespace eckit::geometry::range +} // namespace eckit::geo::range diff --git a/src/eckit/geometry/range/GlobalRegular.h b/src/eckit/geo/range/GlobalRegular.h similarity index 91% rename from src/eckit/geometry/range/GlobalRegular.h rename to src/eckit/geo/range/GlobalRegular.h index 8909ab615..9043240f3 100644 --- a/src/eckit/geometry/range/GlobalRegular.h +++ b/src/eckit/geo/range/GlobalRegular.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geometry/Range.h" +#include "eckit/geo/Range.h" -namespace eckit::geometry::range { +namespace eckit::geo::range { class GlobalRegular final : public Range { @@ -76,4 +76,4 @@ class GlobalRegular final : public Range { }; -} // namespace eckit::geometry::range +} // namespace eckit::geo::range diff --git a/src/eckit/geometry/range/LocalRegular.cc b/src/eckit/geo/range/LocalRegular.cc similarity index 84% rename from src/eckit/geometry/range/LocalRegular.cc rename to src/eckit/geo/range/LocalRegular.cc index 34de92f5d..dc78b8c56 100644 --- a/src/eckit/geometry/range/LocalRegular.cc +++ b/src/eckit/geo/range/LocalRegular.cc @@ -10,12 +10,12 @@ */ -#include "eckit/geometry/range/LocalRegular.h" +#include "eckit/geo/range/LocalRegular.h" -#include "eckit/geometry/util.h" +#include "eckit/geo/util.h" -namespace eckit::geometry::range { +namespace eckit::geo::range { LocalRegular::LocalRegular(size_t n, double a, double b, bool endpoint, double precision) : @@ -37,4 +37,4 @@ const std::vector& LocalRegular::values() const { } -} // namespace eckit::geometry::range +} // namespace eckit::geo::range diff --git a/src/eckit/geometry/range/LocalRegular.h b/src/eckit/geo/range/LocalRegular.h similarity index 91% rename from src/eckit/geometry/range/LocalRegular.h rename to src/eckit/geo/range/LocalRegular.h index e1eb93518..9b6e48087 100644 --- a/src/eckit/geometry/range/LocalRegular.h +++ b/src/eckit/geo/range/LocalRegular.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geometry/Range.h" +#include "eckit/geo/Range.h" -namespace eckit::geometry::range { +namespace eckit::geo::range { class LocalRegular final : public Range { @@ -77,4 +77,4 @@ class LocalRegular final : public Range { }; -} // namespace eckit::geometry::range +} // namespace eckit::geo::range diff --git a/src/eckit/geometry/util.cc b/src/eckit/geo/util.cc similarity index 81% rename from src/eckit/geometry/util.cc rename to src/eckit/geo/util.cc index a34f97f52..5937054c6 100644 --- a/src/eckit/geometry/util.cc +++ b/src/eckit/geo/util.cc @@ -10,10 +10,10 @@ */ -#include "eckit/geometry/util.h" +#include "eckit/geo/util.h" -namespace eckit::geometry::util { +namespace eckit::geo::util { template <> @@ -22,4 +22,4 @@ pl_type pl_convert(const pl_type& pl) { } -} // namespace eckit::geometry::util +} // namespace eckit::geo::util diff --git a/src/eckit/geometry/util.h b/src/eckit/geo/util.h similarity index 96% rename from src/eckit/geometry/util.h rename to src/eckit/geo/util.h index 0c315cb54..e9586d6c9 100644 --- a/src/eckit/geometry/util.h +++ b/src/eckit/geo/util.h @@ -19,7 +19,7 @@ #include -namespace eckit::geometry { +namespace eckit::geo { using pl_type = std::vector; @@ -69,4 +69,4 @@ const pl_type& reduced_octahedral_pl(size_t N); } // namespace util -} // namespace eckit::geometry +} // namespace eckit::geo diff --git a/src/eckit/geometry/util/arange.cc b/src/eckit/geo/util/arange.cc similarity index 93% rename from src/eckit/geometry/util/arange.cc rename to src/eckit/geo/util/arange.cc index 5a3bbc5f5..e7b0a0c9c 100644 --- a/src/eckit/geometry/util/arange.cc +++ b/src/eckit/geo/util/arange.cc @@ -15,7 +15,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geometry::util { +namespace eckit::geo::util { std::vector arange(double start, double stop, double step) { @@ -33,4 +33,4 @@ std::vector arange(double start, double stop, double step) { } -} // namespace eckit::geometry::util +} // namespace eckit::geo::util diff --git a/src/eckit/geometry/util/gaussian_latitudes.cc b/src/eckit/geo/util/gaussian_latitudes.cc similarity index 97% rename from src/eckit/geometry/util/gaussian_latitudes.cc rename to src/eckit/geo/util/gaussian_latitudes.cc index 692238508..4fd5a8ba6 100644 --- a/src/eckit/geometry/util/gaussian_latitudes.cc +++ b/src/eckit/geo/util/gaussian_latitudes.cc @@ -18,7 +18,7 @@ #include "eckit/exception/Exceptions.h" -namespace eckit::geometry::util { +namespace eckit::geo::util { std::vector gaussian_latitudes(size_t N, bool increasing) { @@ -95,4 +95,4 @@ std::vector gaussian_latitudes(size_t N, bool increasing) { } -} // namespace eckit::geometry::util +} // namespace eckit::geo::util diff --git a/src/eckit/geometry/util/linspace.cc b/src/eckit/geo/util/linspace.cc similarity index 92% rename from src/eckit/geometry/util/linspace.cc rename to src/eckit/geo/util/linspace.cc index b4eb9c691..5f8948a67 100644 --- a/src/eckit/geometry/util/linspace.cc +++ b/src/eckit/geo/util/linspace.cc @@ -14,7 +14,7 @@ #include -namespace eckit::geometry::util { +namespace eckit::geo::util { std::vector linspace(double start, double stop, size_t num, bool endpoint) { @@ -32,4 +32,4 @@ std::vector linspace(double start, double stop, size_t num, bool endpoin } -} // namespace eckit::geometry::util +} // namespace eckit::geo::util diff --git a/src/eckit/geometry/util/monotonic_crop.cc b/src/eckit/geo/util/monotonic_crop.cc similarity index 95% rename from src/eckit/geometry/util/monotonic_crop.cc rename to src/eckit/geo/util/monotonic_crop.cc index e5cfb4679..d636a5d14 100644 --- a/src/eckit/geometry/util/monotonic_crop.cc +++ b/src/eckit/geo/util/monotonic_crop.cc @@ -18,7 +18,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geometry::util { +namespace eckit::geo::util { std::pair::const_iterator, std::vector::const_iterator> monotonic_crop( @@ -48,4 +48,4 @@ std::pair::const_iterator, std::vector::const_iterat } -} // namespace eckit::geometry::util +} // namespace eckit::geo::util diff --git a/src/eckit/geometry/util/reduced_classical_pl.cc b/src/eckit/geo/util/reduced_classical_pl.cc similarity index 99% rename from src/eckit/geometry/util/reduced_classical_pl.cc rename to src/eckit/geo/util/reduced_classical_pl.cc index fe8df7c98..46441eb54 100644 --- a/src/eckit/geometry/util/reduced_classical_pl.cc +++ b/src/eckit/geo/util/reduced_classical_pl.cc @@ -14,10 +14,10 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/util.h" +#include "eckit/geo/util.h" -namespace eckit::geometry::util { +namespace eckit::geo::util { static const std::map __classical_pls{ @@ -1341,4 +1341,4 @@ const pl_type& reduced_classical_pl(size_t N) { } -} // namespace eckit::geometry::util +} // namespace eckit::geo::util diff --git a/src/eckit/geometry/util/reduced_octahedral_pl.cc b/src/eckit/geo/util/reduced_octahedral_pl.cc similarity index 89% rename from src/eckit/geometry/util/reduced_octahedral_pl.cc rename to src/eckit/geo/util/reduced_octahedral_pl.cc index 0e6a3460d..a6223dd22 100644 --- a/src/eckit/geometry/util/reduced_octahedral_pl.cc +++ b/src/eckit/geo/util/reduced_octahedral_pl.cc @@ -13,10 +13,10 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/util.h" +#include "eckit/geo/util.h" -namespace eckit::geometry::util { +namespace eckit::geo::util { const pl_type& reduced_octahedral_pl(size_t N) { @@ -40,4 +40,4 @@ const pl_type& reduced_octahedral_pl(size_t N) { } -} // namespace eckit::geometry::util +} // namespace eckit::geo::util diff --git a/src/eckit/geometry/util/regex.cc b/src/eckit/geo/util/regex.cc similarity index 94% rename from src/eckit/geometry/util/regex.cc rename to src/eckit/geo/util/regex.cc index 2d8f2fee3..900d3ca38 100644 --- a/src/eckit/geometry/util/regex.cc +++ b/src/eckit/geo/util/regex.cc @@ -10,14 +10,14 @@ */ -#include "eckit/geometry/util/regex.h" +#include "eckit/geo/util/regex.h" #include #include "eckit/log/Log.h" -namespace eckit::geometry::util { +namespace eckit::geo::util { regex_match_type regex_match(const std::string& pattern, const std::string& s) { @@ -52,4 +52,4 @@ regex_match_type regex_match(const std::string& pattern, const std::string& s) { } -} // namespace eckit::geometry::util +} // namespace eckit::geo::util diff --git a/src/eckit/geometry/util/regex.h b/src/eckit/geo/util/regex.h similarity index 89% rename from src/eckit/geometry/util/regex.h rename to src/eckit/geo/util/regex.h index c39d1ecf7..5ffba6261 100644 --- a/src/eckit/geometry/util/regex.h +++ b/src/eckit/geo/util/regex.h @@ -16,7 +16,7 @@ #include -namespace eckit::geometry::util { +namespace eckit::geo::util { struct regex_match_type : std::smatch { @@ -27,4 +27,4 @@ struct regex_match_type : std::smatch { regex_match_type regex_match(const std::string& pattern, const std::string&); -} // namespace eckit::geometry::util +} // namespace eckit::geo::util diff --git a/src/eckit/geometry/CMakeLists.txt b/src/eckit/geometry/CMakeLists.txt index cba479256..2c53097e4 100644 --- a/src/eckit/geometry/CMakeLists.txt +++ b/src/eckit/geometry/CMakeLists.txt @@ -1,130 +1,33 @@ - -configure_file( eckit_geometry_config.h.in eckit_geometry_config.h @ONLY ) -install( - FILES ${CMAKE_CURRENT_BINARY_DIR}/eckit_geometry_config.h - DESTINATION ${INSTALL_INCLUDE_DIR}/eckit -) - list( APPEND eckit_geometry_srcs - ${CMAKE_CURRENT_BINARY_DIR}/eckit_geometry_config.h - Area.h - Cache.cc - Cache.h - Configurator.h - CoordinateHelpers.cc - CoordinateHelpers.h - Domain.cc - Domain.h - Earth.h - EllipsoidOfRevolution.cc - EllipsoidOfRevolution.h - Figure.h - GreatCircle.cc - GreatCircle.h - Grid.cc - Grid.h - GridConfig.cc - GridConfig.h - Iterator.h - KPoint.cc - KPoint.h - LibEcKitGeometry.cc - LibEcKitGeometry.h - Ordering.h - Point.cc - Point.h - Point2.cc - Point2.h - Point3.cc - Point3.h - PointLonLat.cc - PointLonLat.h - Projection.h - Range.cc - Range.h - Renumber.h - Search.h - Sphere.cc - Sphere.h - SphereT.h - UnitSphere.h - area/BoundingBox.cc - area/BoundingBox.h - grid/Reduced.cc - grid/Reduced.h - grid/Regular.cc - grid/Regular.h - grid/Unstructured.cc - grid/Unstructured.h - grid/reduced/HEALPix.cc - grid/reduced/HEALPix.h - grid/reduced/ReducedGaussian.cc - grid/reduced/ReducedGaussian.h - grid/reduced/ReducedLatLon.cc - grid/reduced/ReducedLatLon.h - grid/regular/IrregularLatLon.cc - grid/regular/IrregularLatLon.h - grid/regular/RegularGaussian.cc - grid/regular/RegularGaussian.h - grid/regular/RegularLatLon.cc - grid/regular/RegularLatLon.h - grid/unstructured/ORCA.cc - grid/unstructured/ORCA.h - iterator/Reduced.cc - iterator/Reduced.h - iterator/Regular.cc - iterator/Regular.h - iterator/Unstructured.cc - iterator/Unstructured.h - polygon/LonLatPolygon.cc - polygon/LonLatPolygon.h - polygon/Polygon.cc - polygon/Polygon.h - projection/LonLatToXYZ.cc - projection/LonLatToXYZ.h - projection/None.cc - projection/None.h - projection/Rotation.cc - projection/Rotation.h - range/Gaussian.cc - range/Gaussian.h - range/GlobalRegular.cc - range/GlobalRegular.h - range/LocalRegular.cc - range/LocalRegular.h - util.cc - util.h - util/arange.cc - util/gaussian_latitudes.cc - util/linspace.cc - util/monotonic_crop.cc - util/reduced_classical_pl.cc - util/reduced_octahedral_pl.cc - util/regex.cc - util/regex.h -) - -set(eckit_geometry_include_dirs - $ - $ +CoordinateHelpers.cc +CoordinateHelpers.h +EllipsoidOfRevolution.cc +EllipsoidOfRevolution.h +GreatCircle.cc +GreatCircle.h +KPoint.cc +KPoint.h +Point2.cc +Point2.h +Point3.cc +Point3.h +Sphere.cc +Sphere.h +SphereT.h +UnitSphere.h +polygon/LonLatPolygon.cc +polygon/LonLatPolygon.h +polygon/Polygon.cc +polygon/Polygon.h ) -set(eckit_geometry_libs eckit_maths eckit_codec) - -if(HAVE_PROJ) - list(APPEND eckit_geometry_srcs projection/PROJ.cc projection/PROJ.h) - list(APPEND eckit_geometry_libs PROJ::proj) - list(APPEND eckit_geometry_include_dirs ${PROJ_INCLUDE_DIRS}) -endif() - ecbuild_add_library( - TARGET eckit_geometry - TYPE SHARED - - INSTALL_HEADERS ALL - HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geometry - PUBLIC_LIBS ${eckit_geometry_libs} - PUBLIC_INCLUDES ${eckit_geometry_include_dirs} - - SOURCES ${eckit_geometry_srcs} -) + TARGET eckit_geometry + TYPE SHARED + INSTALL_HEADERS ALL + HEADER_DESTINATION + ${INSTALL_INCLUDE_DIR}/eckit/geometry + SOURCES + ${eckit_geometry_srcs} + PUBLIC_LIBS + eckit ) diff --git a/src/eckit/geometry/EllipsoidOfRevolution.cc b/src/eckit/geometry/EllipsoidOfRevolution.cc index a20080836..3e094f62d 100644 --- a/src/eckit/geometry/EllipsoidOfRevolution.cc +++ b/src/eckit/geometry/EllipsoidOfRevolution.cc @@ -11,12 +11,11 @@ #include "eckit/geometry/EllipsoidOfRevolution.h" #include -#include -#include #include "eckit/exception/Exceptions.h" +#include "eckit/geometry/CoordinateHelpers.h" +#include "eckit/geometry/Point2.h" #include "eckit/geometry/Point3.h" -#include "eckit/geometry/PointLonLat.h" //---------------------------------------------------------------------------------------------------------------------- @@ -24,29 +23,35 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- -Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, - double b, - const PointLonLat& P, - double height, - bool normalise_angle) { - ASSERT(a > 0.); - ASSERT(b > 0.); +namespace { - if (!(-90. <= P.lat && P.lat <= 90.)) { - std::ostringstream oss; - oss.precision(std::numeric_limits::max_digits10); - oss << "Invalid latitude " << P.lat; - throw BadValue(oss.str(), Here()); - } +static const double degrees_to_radians = M_PI / 180.; - static const double degrees_to_radians = M_PI / 180.; +} // namespace + +//---------------------------------------------------------------------------------------------------------------------- + +void EllipsoidOfRevolution::convertSphericalToCartesian(const double& a, + const double& b, + const Point2& Alonlat, + Point3& B, + double height, + bool normalise_angle) { + ASSERT(a > 0.); + ASSERT(b > 0.); // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) - const double lambda_deg = PointLonLat::normalise_angle_to_minimum(P.lon, -180.); + if (!normalise_angle) { + assert_latitude_range(Alonlat[1]); + } + + const Point2 alonlat = canonicaliseOnSphere(Alonlat, -180.); + + const double lambda_deg = alonlat[0]; const double lambda = degrees_to_radians * lambda_deg; - const double phi = degrees_to_radians * P.lat; + const double phi = degrees_to_radians * alonlat[1]; const double sin_phi = std::sin(phi); const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); @@ -55,9 +60,9 @@ Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, const double N_phi = a * a / std::sqrt(a * a * cos_phi * cos_phi + b * b * sin_phi * sin_phi); - return {(N_phi + height) * cos_phi * cos_lambda, - (N_phi + height) * cos_phi * sin_lambda, - (N_phi * (b * b) / (a * a) + height) * sin_phi}; + B[0] = (N_phi + height) * cos_phi * cos_lambda; + B[1] = (N_phi + height) * cos_phi * sin_lambda; + B[2] = (N_phi * (b * b) / (a * a) + height) * sin_phi; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geometry/EllipsoidOfRevolution.h b/src/eckit/geometry/EllipsoidOfRevolution.h index 03a7f980b..7b30159ff 100644 --- a/src/eckit/geometry/EllipsoidOfRevolution.h +++ b/src/eckit/geometry/EllipsoidOfRevolution.h @@ -17,18 +17,19 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- +class Point2; class Point3; -class PointLonLat; //---------------------------------------------------------------------------------------------------------------------- struct EllipsoidOfRevolution { // Convert elliptic coordinates to Cartesian - static Point3 convertSphericalToCartesian(double a, - double b, - const PointLonLat&, - double height = 0., - bool normalise_angle = false); + static void convertSphericalToCartesian(const double& radiusA, + const double& radiusB, + const Point2& Alonlat, + Point3& B, + double height = 0., + bool normalise_angle = false); }; //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geometry/GreatCircle.cc b/src/eckit/geometry/GreatCircle.cc index bd895faf6..abc71a318 100644 --- a/src/eckit/geometry/GreatCircle.cc +++ b/src/eckit/geometry/GreatCircle.cc @@ -23,32 +23,45 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- -using types::is_approximately_equal; +static double normalise_longitude(double a, const double& minimum) { + while (a < minimum) { + a += 360; + } + while (a >= minimum + 360) { + a -= 360; + } + return a; +} static const double radians_to_degrees = 180. * M_1_PI; static const double degrees_to_radians = M_PI / 180.; +static constexpr std::streamsize max_digits10 = std::numeric_limits::max_digits10; + static bool pole(const double lat) { - return is_approximately_equal(std::abs(lat), 90.); + return types::is_approximately_equal(std::abs(lat), 90.); } //---------------------------------------------------------------------------------------------------------------------- -GreatCircle::GreatCircle(const PointLonLat& Alonlat, const PointLonLat& Blonlat) : +GreatCircle::GreatCircle(const Point2& Alonlat, const Point2& Blonlat) : A_(Alonlat), B_(Blonlat) { - const bool Apole = pole(A_.lat); - const bool Bpole = pole(B_.lat); - const double lon12_deg = PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); + using namespace std; + using types::is_approximately_equal; + + const bool Apole = pole(A_[1]); + const bool Bpole = pole(B_[1]); + const double lon12_deg = normalise_longitude(A_[0] - B_[0], -180); const bool lon_same = Apole || Bpole || is_approximately_equal(lon12_deg, 0.); - const bool lon_opposite = Apole || Bpole || is_approximately_equal(std::abs(lon12_deg), 180.); - const bool lat_same = is_approximately_equal(A_.lat, B_.lat); - const bool lat_opposite = is_approximately_equal(A_.lat, -B_.lat); + const bool lon_opposite = Apole || Bpole || is_approximately_equal(abs(lon12_deg), 180.); + const bool lat_same = is_approximately_equal(A_[1], B_[1]); + const bool lat_opposite = is_approximately_equal(A_[1], -B_[1]); if ((lat_same && lon_same) || (lat_opposite && lon_opposite)) { - std::ostringstream oss; - oss.precision(std::numeric_limits::max_digits10); + ostringstream oss; + oss.precision(max_digits10); oss << "Great circle cannot be defined by points collinear with the centre, " << A_ << " and " << B_; throw BadValue(oss.str(), Here()); } @@ -57,45 +70,46 @@ GreatCircle::GreatCircle(const PointLonLat& Alonlat, const PointLonLat& Blonlat) } std::vector GreatCircle::latitude(double lon) const { + using namespace std; + if (crossesPoles()) { return {}; } - const double lat1 = degrees_to_radians * A_.lat; - const double lat2 = degrees_to_radians * B_.lat; - const double lambda1p = degrees_to_radians * (lon - A_.lon); - const double lambda2p = degrees_to_radians * (lon - B_.lon); - const double lambda = degrees_to_radians * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, -180.); + const double lat1 = degrees_to_radians * A_[1]; + const double lat2 = degrees_to_radians * B_[1]; + const double lambda1p = degrees_to_radians * (lon - A_[0]); + const double lambda2p = degrees_to_radians * (lon - B_[0]); + const double lambda = degrees_to_radians * normalise_longitude(B_[0] - A_[0], -180); - double lat = std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); + double lat = atan((tan(lat2) * sin(lambda1p) - tan(lat1) * sin(lambda2p)) / (sin(lambda))); return {radians_to_degrees * lat}; } std::vector GreatCircle::longitude(double lat) const { - if (crossesPoles()) { - const double lon = pole(A_.lat) ? B_.lon : A_.lon; - if (pole(lat)) { - return {lon}; - } + using namespace std; + using types::is_approximately_equal; - return {lon, lon + 180.}; + if (crossesPoles()) { + const double lon = pole(A_[1]) ? B_[0] : A_[0]; + return pole(lat) ? vector{lon} : vector{lon, lon + 180}; } - const double lon12 = degrees_to_radians * PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); - const double lon1 = degrees_to_radians * A_.lon; - const double lat1 = degrees_to_radians * A_.lat; - const double lat2 = degrees_to_radians * B_.lat; + const double lon12 = degrees_to_radians * normalise_longitude(A_[0] - B_[0], -180); + const double lon1 = degrees_to_radians * A_[0]; + const double lat1 = degrees_to_radians * A_[1]; + const double lat2 = degrees_to_radians * B_[1]; const double lat3 = degrees_to_radians * lat; - const double X = std::sin(lat1) * std::cos(lat2) * std::sin(lon12); - const double Y = std::sin(lat1) * std::cos(lat2) * std::cos(lon12) - std::cos(lat1) * std::sin(lat2); + const double X = sin(lat1) * cos(lat2) * sin(lon12); + const double Y = sin(lat1) * cos(lat2) * cos(lon12) - cos(lat1) * sin(lat2); if (is_approximately_equal(X, 0.) && is_approximately_equal(Y, 0.)) { return {}; // parallel (that is, equator) } const double lon0 = lon1 + atan2(Y, X); - const double C = std::cos(lat1) * std::cos(lat2) * std::tan(lat3) * std::sin(lon12) / std::sqrt(X * X + Y * Y); + const double C = cos(lat1) * cos(lat2) * tan(lat3) * sin(lon12) / sqrt(X * X + Y * Y); if (is_approximately_equal(C, -1.)) { return {radians_to_degrees * (lon0 + M_PI)}; @@ -106,7 +120,7 @@ std::vector GreatCircle::longitude(double lat) const { } if (-1 < C && C < 1) { - const double dlon = std::acos(C); + const double dlon = acos(C); return {radians_to_degrees * (lon0 - dlon + 2 * M_PI), radians_to_degrees * (lon0 + dlon)}; } diff --git a/src/eckit/geometry/GreatCircle.h b/src/eckit/geometry/GreatCircle.h index 818e0a45d..6d38f9c20 100644 --- a/src/eckit/geometry/GreatCircle.h +++ b/src/eckit/geometry/GreatCircle.h @@ -12,8 +12,7 @@ #define GreatCircle_H #include - -#include "eckit/geometry/PointLonLat.h" +#include "eckit/geometry/Point2.h" //------------------------------------------------------------------------------------------------------ @@ -24,7 +23,7 @@ namespace eckit::geometry { class GreatCircle { public: /// Great circle given two points in geographic coordinates - GreatCircle(const PointLonLat&, const PointLonLat&); + GreatCircle(const Point2&, const Point2&); /// Great circle latitude given longitude, see http://www.edwilliams.org/avform.htm#Int std::vector latitude(double lon) const; @@ -35,8 +34,8 @@ class GreatCircle { bool crossesPoles() const; private: - const PointLonLat A_; - const PointLonLat B_; + const Point2 A_; + const Point2 B_; bool crossesPoles_; }; diff --git a/src/eckit/geometry/KPoint.h b/src/eckit/geometry/KPoint.h index c3f381253..2d4aa9214 100644 --- a/src/eckit/geometry/KPoint.h +++ b/src/eckit/geometry/KPoint.h @@ -8,7 +8,8 @@ * does it submit to any jurisdiction. */ -#pragma once +#ifndef KPoint_H +#define KPoint_H #include #include @@ -47,7 +48,7 @@ class KPoint { double x(size_t axis) const { return x_[axis]; } - KPoint() = default; + KPoint() {} KPoint(const double* x) { std::copy(x, x + dimensions(), x_); } @@ -280,3 +281,5 @@ const size_t KPoint::DIMS; //------------------------------------------------------------------------------------------------------ } // namespace eckit::geometry + +#endif diff --git a/src/eckit/geometry/Point2.cc b/src/eckit/geometry/Point2.cc index 73aff5363..219ce99cc 100644 --- a/src/eckit/geometry/Point2.cc +++ b/src/eckit/geometry/Point2.cc @@ -1,13 +1,3 @@ -/* - * (C) Copyright 1996- 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 #include "eckit/geometry/Point2.h" @@ -21,15 +11,14 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- bool points_equal(const Point2& a, const Point2& b) { - return eckit::types::is_approximately_equal(Point2::distance2(a, b), 0.0); -} - -bool operator<(const Point2& a, const Point2& b) { - return eckit::types::is_approximately_equal(Point2::distance2(a, b), 0.0); + return eckit::types::is_approximately_equal(Point2::distance2(a, b), 0.0); } Point2::operator Value() const { - return Value::makeList(std::vector{x_[XX], x_[YY]}); + std::vector pts; + pts.push_back(x_[XX]); + pts.push_back(x_[YY]); + return Value::makeList(pts); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geometry/Point2.h b/src/eckit/geometry/Point2.h index 07f1cb27f..e094a0abb 100644 --- a/src/eckit/geometry/Point2.h +++ b/src/eckit/geometry/Point2.h @@ -1,14 +1,5 @@ -/* - * (C) Copyright 1996- 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. - */ - -#pragma once +#ifndef eckit_geometry_Point2_h +#define eckit_geometry_Point2_h #include @@ -26,50 +17,30 @@ namespace eckit::geometry { //------------------------------------------------------------------------------------------------------ -class Point2 : public KPoint<2> { - using BasePoint = KPoint<2>; +class Point2 : public eckit::geometry::KPoint<2> { + typedef KPoint<2> BasePoint; public: - Point2() = default; + Point2() : + BasePoint() {} Point2(const BasePoint& p) : BasePoint(p) {} - explicit Point2(const double* p) : + Point2(const double* p) : BasePoint(p) {} - Point2(double x, double y) { + Point2(double x, double y) : + BasePoint() { x_[XX] = x; x_[YY] = y; } - Point2(const Point2& other) : - Point2(other.X, other.Y) {} + double x() const { return x_[0]; } - Point2(Point2&& other) : - Point2(other.X, other.Y) {} + double y() const { return x_[1]; } - double x() const { return x_[XX]; } - - double y() const { return x_[YY]; } - - double& X = x_[XX]; - - double& Y = x_[YY]; - - double x(size_t axis) const { return KPoint<2>::x(axis); } - - Point2& operator=(const Point2& other) { - x_[0] = other[0]; - x_[1] = other[1]; - return *this; - } - - Point2& operator=(Point2&& other) { - x_[0] = other[0]; - x_[1] = other[1]; - return *this; - } + double x(size_t axis) const { return eckit::geometry::KPoint<2>::x(axis); } double operator[](const size_t& i) const { assert(i < 2); @@ -94,8 +65,8 @@ class Point2 : public KPoint<2> { bool points_equal(const Point2&, const Point2&); -bool operator<(const Point2&, const Point2&); - //------------------------------------------------------------------------------------------------------ } // namespace eckit::geometry + +#endif diff --git a/src/eckit/geometry/Point3.cc b/src/eckit/geometry/Point3.cc index 4b1469d2e..d9739198e 100644 --- a/src/eckit/geometry/Point3.cc +++ b/src/eckit/geometry/Point3.cc @@ -1,13 +1,3 @@ -/* - * (C) Copyright 1996- 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 "eckit/geometry/Point3.h" #include "eckit/types/FloatCompare.h" @@ -19,11 +9,7 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- bool points_equal(const Point3& a, const Point3& b) { - auto eps = 1e-6; - return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps) && types::is_approximately_equal(a.Z, b.Z, eps); -} - -bool operator<(const Point3& a, const Point3& b) { + return eckit::types::is_approximately_equal(Point3::distance2(a, b), 0.0); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geometry/Point3.h b/src/eckit/geometry/Point3.h index d02bc26da..30fa6d280 100644 --- a/src/eckit/geometry/Point3.h +++ b/src/eckit/geometry/Point3.h @@ -1,14 +1,5 @@ -/* - * (C) Copyright 1996- 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. - */ - -#pragma once +#ifndef eckit_geometry_Point3_h +#define eckit_geometry_Point3_h #include "eckit/geometry/KPoint.h" @@ -18,50 +9,27 @@ namespace eckit::geometry { //------------------------------------------------------------------------------------------------------ -class Point3 : public KPoint<3> { - using BasePoint = KPoint<3>; +class Point3 : public eckit::geometry::KPoint<3> { + + typedef KPoint<3> BasePoint; public: - Point3() = default; + Point3() : + BasePoint() {} Point3(const BasePoint& p) : BasePoint(p) {} - explicit Point3(const double* p) : + Point3(const double* p) : BasePoint(p) {} - Point3(double x, double y, double z) { + Point3(double x, double y, double z) : + BasePoint() { x_[XX] = x; x_[YY] = y; x_[ZZ] = z; } - Point3(const Point3& other) : - Point3(other.X, other.Y, other.Z) {} - - Point3(Point3&& other) : - Point3(other.X, other.Y, other.Z) {} - - double& X = x_[XX]; - - double& Y = x_[YY]; - - double& Z = x_[ZZ]; - - Point3& operator=(const Point3& other) { - x_[0] = other[0]; - x_[1] = other[1]; - x_[2] = other[2]; - return *this; - } - - Point3& operator=(Point3&& other) { - x_[0] = other[0]; - x_[1] = other[1]; - x_[2] = other[2]; - return *this; - } - double operator[](const size_t& i) const { assert(i < 3); return x_[i]; @@ -88,8 +56,8 @@ class Point3 : public KPoint<3> { bool points_equal(const Point3&, const Point3&); -bool operator<(const Point3&, const Point3&); - //------------------------------------------------------------------------------------------------------ } // namespace eckit::geometry + +#endif diff --git a/src/eckit/geometry/Sphere.cc b/src/eckit/geometry/Sphere.cc index bb738d040..b1ac42a96 100644 --- a/src/eckit/geometry/Sphere.cc +++ b/src/eckit/geometry/Sphere.cc @@ -13,12 +13,12 @@ #include #include #include -#include #include "eckit/exception/Exceptions.h" +#include "eckit/geometry/CoordinateHelpers.h" #include "eckit/geometry/GreatCircle.h" +#include "eckit/geometry/Point2.h" #include "eckit/geometry/Point3.h" -#include "eckit/geometry/PointLonLat.h" #include "eckit/types/FloatCompare.h" //---------------------------------------------------------------------------------------------------------------------- @@ -27,20 +27,9 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- -using types::is_approximately_equal; +static const double radians_to_degrees = 180. * M_1_PI; -static constexpr double radians_to_degrees = 180. * M_1_PI; - -static constexpr double degrees_to_radians = M_PI / 180.; - -void assert_latitude(double lat) { - if (!(-90. <= lat && lat <= 90.)) { - std::ostringstream oss; - oss.precision(std::numeric_limits::max_digits10); - oss << "Invalid latitude " << lat; - throw BadValue(oss.str(), Here()); - } -} +static const double degrees_to_radians = M_PI / 180.; inline double squared(double x) { return x * x; @@ -48,10 +37,7 @@ inline double squared(double x) { //---------------------------------------------------------------------------------------------------------------------- -double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { - assert_latitude(A.lat); - assert_latitude(B.lat); - +double Sphere::centralAngle(const Point2& Alonlat, const Point2& Blonlat, bool normalise_angle) { /* * Δσ = atan( ((cos(ϕ2) * sin(Δλ))^2 + (cos(ϕ1) * sin(ϕ2) - sin(ϕ1) * cos(ϕ2) * cos(Δλ))^2) / * (sin(ϕ1) * sin(ϕ2) + cos(ϕ1) * cos(ϕ2) * cos(Δλ)) ) @@ -68,21 +54,31 @@ double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { * } */ - const double phi1 = degrees_to_radians * A.lat; - const double phi2 = degrees_to_radians * B.lat; - const double lambda = degrees_to_radians * (B.lon - A.lon); + if (!normalise_angle) { + assert_latitude_range(Alonlat[1]); + assert_latitude_range(Blonlat[1]); + } + + const Point2 alonlat = canonicaliseOnSphere(Alonlat); + const Point2 blonlat = canonicaliseOnSphere(Blonlat); - const double cos_phi1 = cos(phi1); - const double sin_phi1 = sin(phi1); - const double cos_phi2 = cos(phi2); - const double sin_phi2 = sin(phi2); - const double cos_lambda = cos(lambda); - const double sin_lambda = sin(lambda); + const double phi1 = degrees_to_radians * alonlat[1]; + const double phi2 = degrees_to_radians * blonlat[1]; + const double lambda = degrees_to_radians * (blonlat[0] - alonlat[0]); - const double angle = std::atan2(std::sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), + const double cos_phi1 = std::cos(phi1); + const double sin_phi1 = std::sin(phi1); + const double cos_phi2 = std::cos(phi2); + const double sin_phi2 = std::sin(phi2); + const double cos_lambda = std::cos(lambda); + const double sin_lambda = std::sin(lambda); + + const double angle = std::atan2(std::sqrt(squared(cos_phi2 * sin_lambda) + + squared(cos_phi1 * sin_phi2 + - sin_phi1 * cos_phi2 * cos_lambda)), sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); - if (is_approximately_equal(angle, 0.)) { + if (types::is_approximately_equal(angle, 0.)) { return 0.; } @@ -90,13 +86,13 @@ double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { return angle; } -double Sphere::centralAngle(double radius, const Point3& A, const Point3& B) { +double Sphere::centralAngle(const double& radius, const Point3& A, const Point3& B) { ASSERT(radius > 0.); // Δσ = 2 * asin( chord / 2 ) const double d2 = Point3::distance2(A, B); - if (is_approximately_equal(d2, 0.)) { + if (types::is_approximately_equal(d2, 0.)) { return 0.; } @@ -106,39 +102,38 @@ double Sphere::centralAngle(double radius, const Point3& A, const Point3& B) { return angle; } -double Sphere::distance(double radius, const PointLonLat& A, const PointLonLat& B) { - return radius * centralAngle(A, B); +double Sphere::distance(const double& radius, const Point2& Alonlat, const Point2& Blonlat) { + return radius * centralAngle(Alonlat, Blonlat, true); } -double Sphere::distance(double radius, const Point3& A, const Point3& B) { +double Sphere::distance(const double& radius, const Point3& A, const Point3& B) { return radius * centralAngle(radius, A, B); } -double Sphere::area(double radius) { +double Sphere::area(const double& radius) { ASSERT(radius > 0.); return 4. * M_PI * radius * radius; } -double Sphere::area(double radius, const PointLonLat& WestNorth, const PointLonLat& EastSouth) { +double Sphere::area(const double& radius, const Point2& WestNorth, const Point2& EastSouth) { ASSERT(radius > 0.); - assert_latitude(WestNorth.lat); - assert_latitude(EastSouth.lat); // Set longitude fraction - double W = WestNorth.lon; - double E = PointLonLat::normalise_angle_to_minimum(EastSouth.lon, W); - double longitude_range(is_approximately_equal(W, E) - && !is_approximately_equal(EastSouth.lon, WestNorth.lon) - ? 360. - : E - W); + double W = WestNorth[0]; + double E = normalise_angle(EastSouth[0], W); + double longitude_range( + types::is_approximately_equal(W, E) && !types::is_approximately_equal(EastSouth[0], WestNorth[0]) ? 360. + : E - W); ASSERT(longitude_range <= 360.); double longitude_fraction = longitude_range / 360.; // Set latitude fraction - double N = WestNorth.lat; - double S = EastSouth.lat; - ASSERT(S <= N); + double N = WestNorth[1]; + double S = EastSouth[1]; + ASSERT(-90. <= N && N <= 90.); + ASSERT(-90. <= S && S <= 90.); + ASSERT(N >= S); double latitude_fraction = 0.5 * (std::sin(degrees_to_radians * N) - std::sin(degrees_to_radians * S)); @@ -146,24 +141,23 @@ double Sphere::area(double radius, const PointLonLat& WestNorth, const PointLonL return area(radius) * latitude_fraction * longitude_fraction; } -double Sphere::greatCircleLatitudeGivenLongitude(const PointLonLat& A, - const PointLonLat& B, - double Clon) { - GreatCircle gc(A, B); +double Sphere::greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clon) { + GreatCircle gc(Alonlat, Blonlat); auto lat = gc.latitude(Clon); return lat.size() == 1 ? lat[0] : std::numeric_limits::signaling_NaN(); } -void Sphere::greatCircleLongitudeGivenLatitude( - const PointLonLat& A, const PointLonLat& B, double Clat, double& Clon1, double& Clon2) { - GreatCircle gc(A, B); +void Sphere::greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clat, + double& Clon1, double& Clon2) { + GreatCircle gc(Alonlat, Blonlat); auto lon = gc.longitude(Clat); Clon1 = lon.size() > 0 ? lon[0] : std::numeric_limits::signaling_NaN(); Clon2 = lon.size() > 1 ? lon[1] : std::numeric_limits::signaling_NaN(); } -Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, double height, bool normalise_angle) { +void Sphere::convertSphericalToCartesian( + const double& radius, const Point2& Alonlat, Point3& B, double height, bool normalise_angle) { ASSERT(radius > 0.); /* @@ -180,34 +174,36 @@ Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, */ if (!normalise_angle) { - assert_latitude(A.lat); + assert_latitude_range(Alonlat[1]); } - const auto P = PointLonLat::make(A.lon, A.lat, -180.); - const auto lambda = degrees_to_radians * P.lon; - const auto phi = degrees_to_radians * P.lat; + const Point2 alonlat = canonicaliseOnSphere(Alonlat, -180.); + + const double lambda_deg = alonlat[0]; + const double lambda = degrees_to_radians * lambda_deg; + const double phi = degrees_to_radians * alonlat[1]; - const auto sin_phi = std::sin(phi); - const auto cos_phi = std::sqrt(1. - sin_phi * sin_phi); - const auto sin_lambda = std::abs(P.lon) < 180. ? std::sin(lambda) : 0.; - const auto cos_lambda = std::abs(P.lon) > 90. ? std::cos(lambda) - : std::sqrt(1. - sin_lambda * sin_lambda); + const double sin_phi = std::sin(phi); + const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); + const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; + const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); - return {(radius + height) * cos_phi * cos_lambda, - (radius + height) * cos_phi * sin_lambda, - (radius + height) * sin_phi}; + B[0] = (radius + height) * cos_phi * cos_lambda; + B[1] = (radius + height) * cos_phi * sin_lambda; + B[2] = (radius + height) * sin_phi; } -PointLonLat Sphere::convertCartesianToSpherical(double radius, const Point3& A) { +void Sphere::convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat) { ASSERT(radius > 0.); // numerical conditioning for both z (poles) and y const double x = A[0]; - const double y = is_approximately_equal(A[1], 0.) ? 0. : A[1]; + const double y = types::is_approximately_equal(A[1], 0.) ? 0. : A[1]; const double z = std::min(radius, std::max(-radius, A[2])) / radius; - return {radians_to_degrees * std::atan2(y, x), radians_to_degrees * std::asin(z)}; + Blonlat[0] = radians_to_degrees * std::atan2(y, x); + Blonlat[1] = radians_to_degrees * std::asin(z); } //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geometry/Sphere.h b/src/eckit/geometry/Sphere.h index c23e6be25..dfc74f342 100644 --- a/src/eckit/geometry/Sphere.h +++ b/src/eckit/geometry/Sphere.h @@ -8,7 +8,8 @@ * does it submit to any jurisdiction. */ -#pragma once +#ifndef Sphere_H +#define Sphere_H //---------------------------------------------------------------------------------------------------------------------- @@ -16,47 +17,55 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- +class Point2; class Point3; -class PointLonLat; //---------------------------------------------------------------------------------------------------------------------- struct Sphere { - /// Great-circle central angle between two points in radians - static double centralAngle(const PointLonLat&, - const PointLonLat&); + /// Great-circle central angle between two points (latitude/longitude coordinates) in radians + static double centralAngle(const Point2& Alonlat, + const Point2& Blonlat, + bool normalise_angle = false); /// Great-circle central angle between two points (Cartesian coordinates) in radians - static double centralAngle(double radius, const Point3&, const Point3&); + static double centralAngle(const double& radius, const Point3& A, const Point3& B); - /// Great-circle distance between two points in metres - static double distance(double radius, const PointLonLat&, const PointLonLat&); + /// Great-circle distance between two points (latitude/longitude coordinates) in metres + static double distance(const double& radius, const Point2& Alonlat, const Point2& Blonlat); /// Great-circle distance between two points (Cartesian coordinates) in metres - static double distance(double radius, const Point3&, const Point3&); + static double distance(const double& radius, const Point3& A, const Point3& B); /// Surface area in square metres - static double area(double radius); - - /// Surface area between parallels and meridians defined by two points in square metres - static double area(double radius, const PointLonLat&, const PointLonLat&); - - // Great-circle intermediate latitude provided two circle points and intermediate longitude in degrees - static double greatCircleLatitudeGivenLongitude(const PointLonLat&, const PointLonLat&, double lon); - - // Great-circle intermediate longitude(s) provided two circle points and intermediate latitude in degrees - static void greatCircleLongitudeGivenLatitude(const PointLonLat&, const PointLonLat&, double lat, double& lon1, double& lon2); - - // Convert spherical to Cartesian coordinates - static Point3 convertSphericalToCartesian(double radius, - const PointLonLat&, - double height = 0., - bool normalise_angle = false); - - // Convert Cartesian to spherical coordinates - static PointLonLat convertCartesianToSpherical(double radius, const Point3&); + static double area(const double& radius); + + /// Surface area between parallels and meridians defined by two points (longitude/latitude + /// coordinates) in square metres + static double area(const double& radius, const Point2& Alonlat, const Point2& Blonlat); + + // Great-circle intermediate latitude provided two circle points (A, B) and intermediate + // longitude (C) in degrees + static double greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clon); + + // Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate + // latitude (C) in degrees + static void greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, const double& Clat, + double& Clon1, double& Clon2); + + // Convert spherical coordinates to Cartesian + static void convertSphericalToCartesian(const double& radius, + const Point2& Alonlat, + Point3& B, + double height = 0., + bool normalise_angle = false); + + // Convert Cartesian coordinates to spherical + static void convertCartesianToSpherical(const double& radius, const Point3& A, Point2& Blonlat); }; //---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geometry + +#endif diff --git a/src/eckit/geometry/SphereT.h b/src/eckit/geometry/SphereT.h index 7b2632b8b..b76e9e49c 100644 --- a/src/eckit/geometry/SphereT.h +++ b/src/eckit/geometry/SphereT.h @@ -8,10 +8,9 @@ * does it submit to any jurisdiction. */ -#pragma once +#ifndef SphereT_H +#define SphereT_H -#include "eckit/geometry/Point3.h" -#include "eckit/geometry/PointLonLat.h" #include "eckit/geometry/Sphere.h" //---------------------------------------------------------------------------------------------------------------------- @@ -20,11 +19,6 @@ namespace eckit::geometry { //---------------------------------------------------------------------------------------------------------------------- -class Point3; -class PointLonLat; - -//---------------------------------------------------------------------------------------------------------------------- - /// Definition of a sphere parametrised with a geodetic datum template struct SphereT { @@ -32,10 +26,11 @@ struct SphereT { /// Sphere radius in metres inline static double radius() { return DATUM::radius(); } - /// Great-circle central angle between two points in radians - inline static double centralAngle(const PointLonLat& A, - const PointLonLat& B) { - return Sphere::centralAngle(A, B); + /// Great-circle central angle between two points (longitude/latitude coordinates) in radians + inline static double centralAngle(const Point2& Alonlat, + const Point2& Blonlat, + bool normalise_angle = false) { + return Sphere::centralAngle(Alonlat, Blonlat, normalise_angle); } /// Great-circle central angle between two points (Cartesian coordinates) in radians @@ -43,9 +38,9 @@ struct SphereT { return Sphere::centralAngle(DATUM::radius(), A, B); } - /// Great-circle distance between two points in metres - inline static double distance(const PointLonLat& A, const PointLonLat& B) { - return Sphere::distance(DATUM::radius(), A, B); + /// Great-circle distance between two points (longitude/latitude coordinates) in metres + inline static double distance(const Point2& Alonlat, const Point2& Blonlat) { + return Sphere::distance(DATUM::radius(), Alonlat, Blonlat); } /// Great-circle distance between two points (Cartesian coordinates) in metres @@ -54,35 +49,40 @@ struct SphereT { /// Surface area in square metres inline static double area() { return Sphere::area(DATUM::radius()); } - /// Surface area between parallels and meridians defined by two points in square metres - inline static double area(const PointLonLat& WestNorth, const PointLonLat& EastSouth) { + /// Surface area between parallels and meridians defined by two points (longitude/latitude coordinates) in square + /// metres + inline static double area(const Point2& WestNorth, const Point2& EastSouth) { return Sphere::area(DATUM::radius(), WestNorth, EastSouth); } - // Great-circle intermediate latitude provided two circle points and intermediate longitude in degrees - inline static double greatCircleLatitudeGivenLongitude(const PointLonLat& A, const PointLonLat& B, double lon) { - return Sphere::greatCircleLatitudeGivenLongitude(A, B, lon); + // Great-circle intermediate latitude provided two circle points (A, B) and intermediate longitude (C) in degrees + inline static double greatCircleLatitudeGivenLongitude(const Point2& Alonlat, const Point2& Blonlat, + const double& Clon) { + return Sphere::greatCircleLatitudeGivenLongitude(Alonlat, Blonlat, Clon); } - // Great-circle intermediate longitude(s) provided two circle points and intermediate latitude in degrees - inline static void greatCircleLongitudeGivenLatitude(const PointLonLat& A, const PointLonLat& B, - double lat, double& lon1, double& lon2) { - return Sphere::greatCircleLongitudeGivenLatitude(A, B, lat, lon1, lon2); + // Great-circle intermediate longitude(s) provided two circle points (A, B) and intermediate latitude (C) in degrees + inline static void greatCircleLongitudeGivenLatitude(const Point2& Alonlat, const Point2& Blonlat, + const double& Clat, double& Clon1, double& Clon2) { + return Sphere::greatCircleLongitudeGivenLatitude(Alonlat, Blonlat, Clat, Clon1, Clon2); } - // Convert spherical to Cartesian coordinates - inline static Point3 convertSphericalToCartesian(const PointLonLat& P, - double height = 0., - bool normalise_angle = false) { - return Sphere::convertSphericalToCartesian(DATUM::radius(), P, height, normalise_angle); + // Convert spherical coordinates to Cartesian + inline static void convertSphericalToCartesian(const Point2& Alonlat, + Point3& B, + double height = 0., + bool normalise_angle = false) { + Sphere::convertSphericalToCartesian(DATUM::radius(), Alonlat, B, height, normalise_angle); } - // Convert Cartesian to spherical coordinates - inline static PointLonLat convertCartesianToSpherical(const Point3& P) { - return Sphere::convertCartesianToSpherical(DATUM::radius(), P); + // Convert Cartesian coordinates to spherical + inline static void convertCartesianToSpherical(const Point3& A, Point2& Blonlat) { + Sphere::convertCartesianToSpherical(DATUM::radius(), A, Blonlat); } }; //---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geometry + +#endif diff --git a/src/eckit/geometry/UnitSphere.h b/src/eckit/geometry/UnitSphere.h index de4075de0..7a567255a 100644 --- a/src/eckit/geometry/UnitSphere.h +++ b/src/eckit/geometry/UnitSphere.h @@ -21,13 +21,20 @@ namespace eckit::geometry { /// Definition of a unit datum struct DatumUnit { - static constexpr double radius() { return 1.; } + + /* C++-11: + static constexpr double radius() { + return 1.; + } + */ + + static double radius() { return 1.; } }; //------------------------------------------------------------------------------------------------------ /// Definition of a unit sphere -using UnitSphere = SphereT; +typedef SphereT UnitSphere; //------------------------------------------------------------------------------------------------------ diff --git a/src/eckit/geometry/eckit_geometry_config.h.in b/src/eckit/geometry/eckit_geometry_config.h.in deleted file mode 100644 index 3e330e013..000000000 --- a/src/eckit/geometry/eckit_geometry_config.h.in +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#cmakedefine01 eckit_HAVE_GEOMETRY_CACHING -#cmakedefine eckit_GEOMETRY_CACHE_PATH "@eckit_GEOMETRY_CACHE_PATH@" - diff --git a/src/eckit/maths/CMakeLists.txt b/src/eckit/maths/CMakeLists.txt index 6c730016b..b5ab82098 100644 --- a/src/eckit/maths/CMakeLists.txt +++ b/src/eckit/maths/CMakeLists.txt @@ -1,13 +1,19 @@ list( APPEND eckit_maths_lib_srcs -Eigen.h -Lapack.cc -Lapack.h -Matrix.h -Matrix3.h -MatrixEigen.h -MatrixLapack.h + Eigen.h + Lapack.cc + Lapack.h + Matrix.h + MatrixEigen.h + MatrixLapack.h ) +if( HAVE_EXPERIMENTAL ) + # for eckit::geo + list( APPEND eckit_maths_lib_srcs + Matrix3.h + ) +endif() + ecbuild_add_library( TARGET eckit_maths TYPE SHARED INSTALL_HEADERS ALL HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/maths diff --git a/src/eckit/maths/Matrix3.h b/src/eckit/maths/Matrix3.h index 379da26ff..f5bec5854 100644 --- a/src/eckit/maths/Matrix3.h +++ b/src/eckit/maths/Matrix3.h @@ -16,7 +16,7 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Point3.h" +#include "eckit/geo/Point3.h" namespace eckit::maths { @@ -62,7 +62,7 @@ class Matrix3 final : protected std::array { return *this; } - geometry::Point3 operator*(const geometry::Point3& p) const { + geo::Point3 operator*(const geo::Point3& p) const { return {XX * p.X + XY * p.Y + XZ * p.Z, YX * p.X + YY * p.Y + YZ * p.Z, ZX * p.X + ZY * p.Y + ZZ * p.Z}; } diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 9231b669e..76f75dd9a 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -12,15 +12,15 @@ ecbuild_add_executable( TARGET eckit_info ecbuild_add_executable( TARGET eckit_grid OUTPUT_NAME eckit-grid - CONDITION HAVE_BUILD_TOOLS + CONDITION HAVE_BUILD_TOOLS AND HAVE_EXPERIMENTAL SOURCES eckit-grid.cc - LIBS eckit_option eckit_geometry ) + LIBS eckit_geo eckit_option ) ecbuild_add_executable( TARGET eckit_grid_list OUTPUT_NAME eckit-grid-list - CONDITION HAVE_BUILD_TOOLS + CONDITION HAVE_BUILD_TOOLS AND HAVE_EXPERIMENTAL SOURCES eckit-grid-list.cc - LIBS eckit_option eckit_geometry ) + LIBS eckit_geo eckit_option ) ### NOT TO INSTALL diff --git a/src/tools/eckit-grid-list.cc b/src/tools/eckit-grid-list.cc index 149e0d1bd..40c8f6f7c 100644 --- a/src/tools/eckit-grid-list.cc +++ b/src/tools/eckit-grid-list.cc @@ -9,7 +9,7 @@ */ -#include "eckit/geometry/Grid.h" +#include "eckit/geo/Grid.h" #include "eckit/log/Log.h" #include "eckit/option/EckitTool.h" @@ -22,7 +22,7 @@ struct EckitGridList final : EckitTool { EckitTool(argc, argv) {} void execute(const option::CmdArgs&) override { - geometry::GridFactory::list(Log::info()); + geo::GridFactory::list(Log::info()); Log::info() << std::endl; } diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index dd3ea720f..2c330bd0f 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -13,10 +13,10 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geometry/Grid.h" -#include "eckit/geometry/Point.h" -#include "eckit/geometry/Search.h" -#include "eckit/geometry/grid/Unstructured.h" +#include "eckit/geo/Grid.h" +#include "eckit/geo/Point.h" +#include "eckit/geo/Search.h" +#include "eckit/geo/grid/Unstructured.h" #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" #include "eckit/option/EckitTool.h" @@ -40,7 +40,7 @@ class EckitGrid final : public EckitTool { void execute(const option::CmdArgs& args) override { auto uid = args.getBool("uid", false); - geometry::PointLonLat nearest_point{0, 0}; + geo::PointLonLat nearest_point{0, 0}; size_t nearest_k = 0; if (std::vector point; args.get("nearest-point", point)) { ASSERT(point.size() == 2); @@ -53,7 +53,7 @@ class EckitGrid final : public EckitTool { for (const auto& arg : args) { std::unique_ptr cfg(new MappedConfiguration({{uid ? "uid" : "name", std::string(arg)}})); - std::unique_ptr grid(geometry::GridFactory::build(*cfg)); + std::unique_ptr grid(geo::GridFactory::build(*cfg)); out << "size: " << grid->size() << std::endl; @@ -61,12 +61,12 @@ class EckitGrid final : public EckitTool { out << p << std::endl; } - // for (const auto& p : geometry::grid::UnstructuredGrid(*grid)) { + // for (const auto& p : geo::grid::UnstructuredGrid(*grid)) { // out << p << std::endl; // } if (nearest_k > 0) { - geometry::SearchLonLat search; + geo::SearchLonLat search; search.build(grid->to_points()); const auto* sep = ""; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f540219bb..fbc86e82e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -22,9 +22,11 @@ add_subdirectory( utils ) add_subdirectory( value ) if( HAVE_ECKIT_SQL ) - add_subdirectory( sql ) + add_subdirectory( sql ) endif() if( HAVE_EXPERIMENTAL ) - add_subdirectory( experimental ) + add_subdirectory( codec ) + add_subdirectory( geo ) + add_subdirectory( experimental ) endif() diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt new file mode 100644 index 000000000..eb75f851f --- /dev/null +++ b/tests/geo/CMakeLists.txt @@ -0,0 +1,21 @@ +foreach( _test + coordinate_helpers + great_circle + grid + iterator + kdtree + kpoint + param + points + polygon + projection + search + sphere + types + util ) + ecbuild_add_test( + TARGET eckit_test_geo_${_test} + SOURCES test_${_test}.cc + LIBS eckit_geo ) +endforeach() + diff --git a/tests/geo/test_coordinate_helpers.cc b/tests/geo/test_coordinate_helpers.cc new file mode 100644 index 000000000..2cf204f31 --- /dev/null +++ b/tests/geo/test_coordinate_helpers.cc @@ -0,0 +1,68 @@ +/* + * (C) Copyright 2023 UCAR + * + * 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. + */ + +#include "eckit/geo/CoordinateHelpers.h" +#include "eckit/geo/Point2.h" +#include "eckit/testing/Test.h" + + +namespace eckit::test { + +using namespace geo; + +// ----------------------------------------------------------------------------- + +CASE("normalise angles") { + EXPECT(0. == normalise_angle(360., 0.)); + EXPECT(14. == normalise_angle(374., 0.)); + EXPECT(14. == normalise_angle(374., -90.)); + EXPECT(374. == normalise_angle(374., 90.)); +} + +CASE("canonicalise on sphere") { + using types::is_approximately_equal; + + const Point2 p1(108., 32.); + + // Worse coordinates for the same point: + const Point2 p2(-252., 32.); + const Point2 p3(288., 148.); + const Point2 p4(108., -328.); + + // Check each of these is correctly shifted back to original point: + const Point2 q2 = canonicaliseOnSphere(p2); + const Point2 q3 = canonicaliseOnSphere(p3); + const Point2 q4 = canonicaliseOnSphere(p4); + + EXPECT(p1.x() == q2.x()); + EXPECT(p1.y() == q2.y()); + EXPECT(p1.x() == q3.x()); + EXPECT(p1.y() == q3.y()); + EXPECT(p1.x() == q4.x()); + EXPECT(p1.y() == q4.y()); + + // Check with longitude offset + const Point2 q2b = canonicaliseOnSphere(p2, -90.); + EXPECT(q2b.x() == 108.); + EXPECT(q2b.y() == 32.); + + const Point2 q2c = canonicaliseOnSphere(p2, 90.); + EXPECT(q2c.x() == 108.); + EXPECT(q2c.y() == 32.); + + const Point2 q2d = canonicaliseOnSphere(p2, 180.); + EXPECT(q2d.x() == 468.); + EXPECT(q2d.y() == 32.); +} + +// ----------------------------------------------------------------------------- + +} // namespace eckit::test + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/test_great_circle.cc b/tests/geo/test_great_circle.cc new file mode 100644 index 000000000..66bbab069 --- /dev/null +++ b/tests/geo/test_great_circle.cc @@ -0,0 +1,238 @@ +/* + * (C) Copyright 1996- 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 +#include +#include + +#include "eckit/geo/GreatCircle.h" +#include "eckit/geo/PointLonLat.h" +#include "eckit/testing/Test.h" + +namespace eckit::test { + +using namespace geo; + +// ----------------------------------------------------------------------------- +// test great circles + +CASE("test great circles intersections") { + using types::is_approximately_equal; + using types::is_approximately_greater_or_equal; + + auto is_approximately_equal_longitude = [](double lon1, double lon2, + double epsilon = std::numeric_limits::epsilon()) -> bool { + while (lon2 < lon1) { + lon2 += 360; + } + while (lon1 >= lon1 + 360) { + lon2 -= 360; + } + return is_approximately_equal(lon1, lon2, epsilon) || is_approximately_equal(lon1, lon2 - 360, epsilon); + }; + + auto is_approximately_pole = [](double lat, double epsilon = std::numeric_limits::epsilon()) -> bool { + return is_approximately_equal(std::abs(lat), 90., epsilon); + }; + + auto is_approximately_equator = [](double lat, double epsilon = std::numeric_limits::epsilon()) -> bool { + return is_approximately_equal(lat, 0., epsilon); + }; + + const std::vector latitudes{ + 90, + 60, + 45, + 30, + 0, + -30, + -45, + -60, + -90, + }; + + const std::vector longitudes{ + -181, + -180, + -135, + -90, + -45, + 0, + 45, + 90, + 135, + 180, + 225, + 270, + 315, + 360, + 361, + }; + + const std::vector antipodes{ + {0, 0}, + {180, 0}, + {-180, 0}, + {0, 0}, + {-90, 0}, + {90, 0}, + {90, 0}, + {-90, 0}, + {0, 90}, + {0, -90}, + {0, -90}, + {0, 90}, + {45, 45}, + {225, -45}, + }; + + SECTION("example intersection with meridian and parallel") { + // latitude at Valparaíso-Shanghai mid-point + const PointLonLat P1(-71.6, -33.); + const PointLonLat P2(121.8, 31.4); + GreatCircle gc(P1, P2); + + const PointLonLat mid(-159.18, -6.81); + + auto lats = gc.latitude(mid.lon); + EXPECT(lats.size() == 1 && is_approximately_equal(lats[0], mid.lat, 0.01)); + + auto lons = gc.longitude(mid.lat); + EXPECT(lons.size() == 2); + EXPECT(is_approximately_equal_longitude(lons[0], mid.lon, 0.01) + || is_approximately_equal_longitude(lons[1], mid.lon, 0.01)); + } + + SECTION("mal-formed great circle") { + for (size_t i = 0; i < antipodes.size(); i += 2) { + const PointLonLat& A(antipodes[i]); + const PointLonLat& B(antipodes[i + 1]); + + EXPECT_THROWS_AS(GreatCircle(A, A), BadValue); + EXPECT_THROWS_AS(GreatCircle(B, B), BadValue); + + EXPECT_THROWS_AS(GreatCircle(A, B), BadValue); + + if (is_approximately_pole(A.lat)) { + for (double lon1_gc : longitudes) { + for (double lon2_gc : longitudes) { + EXPECT_THROWS_AS(GreatCircle({lon1_gc, A.lat}, {lon2_gc, A.lat}), BadValue); + EXPECT_THROWS_AS(GreatCircle({lon1_gc, B.lat}, {lon2_gc, B.lat}), BadValue); + } + } + } + } + } + + SECTION("intersection at quadrants") { + for (double lat_gc : latitudes) { + if (!is_approximately_pole(lat_gc) && !is_approximately_equator(lat_gc)) { + for (double lon_gc : longitudes) { + + GreatCircle gc({lon_gc, lat_gc}, {lon_gc + 90, 0}); + EXPECT(!gc.crossesPoles()); + + auto lon_at_equator = gc.longitude(0); + EXPECT(lon_at_equator.size() == 2); + EXPECT((is_approximately_equal_longitude(lon_gc + 90, lon_at_equator[0]) && is_approximately_equal_longitude(lon_gc - 90, lon_at_equator[1])) || (is_approximately_equal_longitude(lon_gc - 90, lon_at_equator[0]) && is_approximately_equal_longitude(lon_gc + 90, lon_at_equator[1]))); + + auto lon_extrema1 = gc.longitude(lat_gc); + EXPECT(lon_extrema1.size() == 1 && is_approximately_equal_longitude(lon_extrema1[0], lon_gc, 0.01)); + + auto lon_extrema2 = gc.longitude(-lat_gc); + EXPECT(lon_extrema2.size() == 1 && is_approximately_equal_longitude(lon_extrema2[0], lon_gc + 180, 0.01)); + } + } + } + } + + SECTION("intersection with parallels when crossing the poles") { + for (double lon : longitudes) { + for (double lat : latitudes) { + + { + GreatCircle gc({lon, -10}, {lon, 10}); + EXPECT(gc.crossesPoles()); + + auto lons = gc.longitude(lat); + size_t N = is_approximately_pole(lat) ? 1 : 2; + EXPECT(lons.size() == N); + + if (N == 1) { + EXPECT(is_approximately_equal_longitude(lons[0], lon)); + } + else { + EXPECT(is_approximately_equal_longitude(lons[0] + 180, lons[1])); + EXPECT(is_approximately_equal_longitude(lons[0], lon) || is_approximately_equal_longitude(lons[1], lon)); + } + } + + if (!is_approximately_pole(lat) && !is_approximately_equator(lat)) { + GreatCircle gc({lon, lat}, {lon + 180, lat}); + EXPECT(gc.crossesPoles()); + + auto lons = gc.longitude(lat); + EXPECT(lons.size() == 2); + + EXPECT(is_approximately_equal_longitude(lons[0] + 180, lons[1])); + EXPECT(is_approximately_equal_longitude(lons[0], lon) || is_approximately_equal_longitude(lons[1], lon)); + } + } + } + } + + SECTION("intersection with parallels") { + for (double lat_gc : latitudes) { + if (/* avoid mal-forming */ !is_approximately_pole(lat_gc)) { + for (double lat : latitudes) { + + GreatCircle gc({-1, lat_gc}, {1, lat_gc}); + EXPECT(!gc.crossesPoles()); + + auto lons = gc.longitude(lat); + size_t N = is_approximately_equator(lat_gc) ? 0. + : is_approximately_greater_or_equal(std::abs(lat_gc), std::abs(lat)) ? 2 + : 0; + EXPECT(lons.size() == N); + + for (auto lon : lons) { + auto lats = gc.latitude(lon); + EXPECT(lats.size() == 1 && is_approximately_equal(lats[0], lat, 0.01)); + } + } + } + } + } + + SECTION("equator great circle intersection with meridian and parallel") { + for (double lon : longitudes) { + + GreatCircle eq({lon - 1, 0}, {lon + 1, 0}); + EXPECT(!eq.crossesPoles()); + + // non-intersection with parallels + for (double lat : latitudes) { + EXPECT(eq.longitude(lat).empty()); + } + + // intersect one latitude only, for specific longitudes + auto lats = eq.latitude(lon); + EXPECT(lats.size() == 1 && is_approximately_equator(lats[0])); + } + } +} + +// ----------------------------------------------------------------------------- + +} // namespace eckit::test + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geometry/test_grid.cc b/tests/geo/test_grid.cc similarity index 85% rename from tests/geometry/test_grid.cc rename to tests/geo/test_grid.cc index f2280b577..961f1bcfa 100644 --- a/tests/geometry/test_grid.cc +++ b/tests/geo/test_grid.cc @@ -13,7 +13,7 @@ #include #include "eckit/config/MappedConfiguration.h" -#include "eckit/geometry/Grid.h" +#include "eckit/geo/Grid.h" #include "eckit/testing/Test.h" @@ -21,7 +21,7 @@ namespace eckit::test { CASE("GridFactory::build") { - using geometry::Grid; + using geo::Grid; struct test_t { @@ -33,7 +33,7 @@ CASE("GridFactory::build") { SECTION("GridFactory::build_from_name") { for (const auto& test : {test_t{"O2", 88}, {"f2", 32}, {"h2", 48}}) { std::unique_ptr cfg(new MappedConfiguration({{"name", test.name}})); - std::unique_ptr grid(geometry::GridFactory::build(*cfg)); + std::unique_ptr grid(geo::GridFactory::build(*cfg)); auto size = grid->size(); EXPECT_EQUAL(size, test.size); } @@ -49,7 +49,7 @@ CASE("GridFactory::build") { SECTION("Grid::build") { - std::unique_ptr grid(geometry::GridFactory::build(MappedConfiguration{ + std::unique_ptr grid(geo::GridFactory::build(MappedConfiguration{ {{"name", "O2"}}})); // auto size = grid->size(); diff --git a/tests/geometry/test_iterator.cc b/tests/geo/test_iterator.cc similarity index 77% rename from tests/geometry/test_iterator.cc rename to tests/geo/test_iterator.cc index 79ea3a516..31c80c183 100644 --- a/tests/geometry/test_iterator.cc +++ b/tests/geo/test_iterator.cc @@ -13,13 +13,13 @@ #include #include "eckit/exception/Exceptions.h" -// #include "eckit/geometry/Scanner.h" -// #include "eckit/geometry/iterator/IteratorAggregator.h" -// #include "eckit/geometry/iterator/IteratorComposer.h" +// #include "eckit/geo/Scanner.h" +// #include "eckit/geo/iterator/IteratorAggregator.h" +// #include "eckit/geo/iterator/IteratorComposer.h" int main(int argc, const char* argv[]) { - // eckit::geometry::iterator::IteratorComposer i(nullptr); + // eckit::geo::iterator::IteratorComposer i(nullptr); // struct ScannerTest : public eckit::grid::Scanner { // bool operator++() override { NOTIMP; } diff --git a/tests/geo/test_kdtree.cc b/tests/geo/test_kdtree.cc new file mode 100644 index 000000000..ef5212779 --- /dev/null +++ b/tests/geo/test_kdtree.cc @@ -0,0 +1,374 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/container/KDTree.h" +#include "eckit/geo/Point2.h" +#include "eckit/os/Semaphore.h" +#include "eckit/testing/Test.h" + +using namespace std; +using namespace eckit; +using namespace eckit::testing; +using namespace eckit::geo; + +namespace eckit::test { + +//---------------------------------------------------------------------------------------------------------------------- + +struct TestTreeTrait { + typedef Point2 Point; + typedef double Payload; +}; + +//---------------------------------------------------------------------------------------------------------------------- + +/// \brief Class used to test whether any point in a kd-tree lies in the interior of an +/// axis-aligned box. +template +class PointInBoxInteriorFinder { +public: + typedef eckit::KDTreeX KDTree; + typedef typename KDTree::Point Point; + +private: + typedef typename KDTree::Alloc Alloc; + typedef typename KDTree::Node Node; + +public: + /// \brief Returns true if any point in \p tree lies in the interior of the specified + /// axis-aligned box. + /// + /// \param tree + /// Tree to search. + /// \param lbound + /// Lower-left corner of the axis-aligned box. + /// \param ubound + /// Upper-right corner of the axis-aligned box. + static bool isAnyPointInBoxInterior(const KDTree& tree, const Point& lbound, const Point& ubound) { + if (!tree.root_) { + return false; + } + Alloc& alloc = tree.alloc_; + Node* root = alloc.convert(tree.root_, static_cast(nullptr)); + + return isAnyPointInBoxInterior(root, alloc, lbound, ubound); + } + +private: + /// \brief Returns true if the point stored in \p node or any of its descendants lies in the + /// interior of the axis-aligned box with bottom-left and top-right corners at + /// \p lbound and \p ubound. + static bool isAnyPointInBoxInterior(const Node* node, Alloc& alloc, const Point& lbound, const Point& ubound) { + const Point& point = node->value().point(); + + if (isPointInBoxInterior(point, lbound, ubound)) { + return true; + } + + const size_t axis = node->axis(); + + if (lbound.x(axis) < point.x(axis)) { + if (Node* left = node->left(alloc)) { + if (isAnyPointInBoxInterior(left, alloc, lbound, ubound)) { + return true; + } + } + } + + if (ubound.x(axis) > point.x(axis)) { + if (Node* right = node->right(alloc)) { + if (isAnyPointInBoxInterior(right, alloc, lbound, ubound)) { + return true; + } + } + } + + return false; + } + + /// \brief Returns true if \p point is in the interior of the axis-aligned box + /// with bottom-left and top-right corners at \p lbound and \p ubound. + static bool isPointInBoxInterior(const Point& point, const Point& lbound, const Point& ubound) { + for (size_t d = 0; d < Point::DIMS; ++d) { + if (point.x(d) <= lbound.x(d) || point.x(d) >= ubound.x(d)) { + return false; + } + } + return true; + } +}; + +//---------------------------------------------------------------------------------------------------------------------- + +/// \brief Returns true if any point in \p tree is in the interior of the axis-aligned box +/// with bottom-left and top-right corners at \p lbound and \p ubound. +template +bool isAnyPointInBoxInterior(const eckit::KDTreeX& tree, + const typename eckit::KDTreeX::Point& lbound, + const typename eckit::KDTreeX::Point& ubound) { + return PointInBoxInteriorFinder::isAnyPointInBoxInterior(tree, lbound, ubound); +} + +//---------------------------------------------------------------------------------------------------------------------- + +CASE("test_eckit_container_kdtree_constructor") { + typedef KDTreeMemory Tree; + + Tree kd; + using Point = Tree::PointType; + + std::vector points; + + // test it for single closest point + + for (unsigned int i = 0; i < 10; i++) { + for (unsigned int j = 0; j < 10; j++) { + Point p = Point(double(i), double(j)); + Tree::Value v(p, 99.9); + points.push_back(v); + } + } + + kd.build(points.begin(), points.end()); + + // pick some point from the vector + Point refPoint = points[points.size() / 2].point(); + + // perturb it a little + Point delta(0.1, 0.1); + Point testPoint = Point::add(refPoint, delta); + Log::info() << "testPoint perturb " << testPoint.x(0) << ", " << testPoint.x(1) << std::endl; + + Point nr = kd.nearestNeighbour(testPoint).point(); + + // we should find the same point + for (unsigned int i = 0; i < Point::dimensions(); i++) { + EXPECT(nr.x(i) == refPoint.x(i)); + } + + // test exact match to a point + + nr = kd.nearestNeighbour(refPoint).point(); + for (unsigned int i = 0; i < Point::dimensions(); i++) { + EXPECT(nr.x(i) == refPoint.x(i)); + } + + // test "off the scale" - i.e. not within a group of points + delta = Point(1000.0, 0.0); + // add it to the last point + testPoint = Point::add(points.back().point(), delta); + nr = kd.nearestNeighbour(testPoint).point(); + + for (unsigned int i = 0; i < Point::dimensions(); i++) { + EXPECT(nr.x(i) == points.back().point().x(i)); + } + + // and negatively + // + delta = Point(-1000.0, 0.0); + // add it to the point() point + testPoint = Point::add(points.front().point(), delta); + nr = kd.nearestNeighbour(testPoint).point(); + + for (unsigned int i = 0; i < Point::dimensions(); i++) { + EXPECT(nr.x(i) == points.front().point().x(i)); + } + + // test N nearest + refPoint = points[points.size() / 2].point(); + // move this point so it lies between four equally + delta = Point(0.5, 0.5); + testPoint = Point::add(refPoint, delta); + + Tree::NodeList nn = kd.kNearestNeighbours(testPoint, 4); + for (Tree::NodeList::iterator it = nn.begin(); it != nn.end(); ++it) { + Point diff = Point::sub(it->point(), testPoint); + // make sure we differ by 0.5 along each axis + for (unsigned int i = 0; i < Point::dimensions(); ++i) { + Log::info() << "distance along point " << Point::distance(Point(0.0, 0.0), diff, i) << std::endl; + EXPECT(Point::distance(Point(0.0, 0.0), diff, i) == 0.5); + } + } + + // Test a custom visitor. The purpose of doing that in this test is to ensure that the public + // interface of KDTree is sufficient to write a custom class traversing the tree. + delta = Point(0.25, 0.25); + Point lbound = Point::sub(refPoint, delta); + Point ubound = Point::add(refPoint, delta); + EXPECT(isAnyPointInBoxInterior(kd, lbound, ubound)); + + delta = Point(0.5, 0.5); + lbound = Point::add(lbound, delta); + ubound = Point::add(ubound, delta); + EXPECT_NOT(isAnyPointInBoxInterior(kd, lbound, ubound)); + + // Test size() + EXPECT_EQUAL(kd.size(), points.size()); +} + +CASE("test_eckit_container_kdtree_insert") { + typedef KDTreeMemory Tree; + + Tree kd; + typedef Tree::PointType Point; + + std::vector points; + + // test it for single closest point + + for (unsigned int i = 0; i < 10; i++) { + for (unsigned int j = 0; j < 10; j++) { + Point p = Point(double(i), double(j)); + Tree::Value v(p, 99.9); + points.push_back(v); + kd.insert(v); + } + } + + + // pick some point from the vector + Point refPoint = points[points.size() / 2].point(); + + // perturb it a little + Point delta(0.1, 0.1); + Point testPoint = Point::add(refPoint, delta); + Log::info() << "testPoint perturb " << testPoint.x(0) << ", " << testPoint.x(1) << std::endl; + + Point nr = kd.nearestNeighbour(testPoint).point(); + + // we should find the same point + for (unsigned int i = 0; i < Point::dimensions(); i++) { + EXPECT(nr.x(i) == refPoint.x(i)); + } + + // test exact match to a point + + nr = kd.nearestNeighbour(refPoint).point(); + for (unsigned int i = 0; i < Point::dimensions(); i++) { + EXPECT(nr.x(i) == refPoint.x(i)); + } + + // test "off the scale" - i.e. not within a group of points + delta = Point(1000.0, 0.0); + // add it to the last point + testPoint = Point::add(points.back().point(), delta); + nr = kd.nearestNeighbour(testPoint).point(); + + for (unsigned int i = 0; i < Point::dimensions(); i++) { + EXPECT(nr.x(i) == points.back().point().x(i)); + } + + // and negatively + // + delta = Point(-1000.0, 0.0); + // add it to the point() point + testPoint = Point::add(points.front().point(), delta); + nr = kd.nearestNeighbour(testPoint).point(); + + for (unsigned int i = 0; i < Point::dimensions(); i++) { + EXPECT(nr.x(i) == points.front().point().x(i)); + } + + // test N nearest + refPoint = points[points.size() / 2].point(); + // move this point so it lies between four equally + delta = Point(0.5, 0.5); + testPoint = Point::add(refPoint, delta); + + Tree::NodeList nn = kd.kNearestNeighbours(testPoint, 4); + for (Tree::NodeList::iterator it = nn.begin(); it != nn.end(); ++it) { + Point diff = Point::sub(it->point(), testPoint); + // make sure we differ by 0.5 along each axis + for (unsigned int i = 0; i < Point::dimensions(); ++i) { + Log::info() << "distance along point " << Point::distance(Point(0.0, 0.0), diff, i) << std::endl; + EXPECT(Point::distance(Point(0.0, 0.0), diff, i) == 0.5); + } + } +} + +CASE("test_kdtree_mapped") { + using Tree = KDTreeMapped; + using Point = Tree::PointType; + std::vector points; + for (unsigned int i = 0; i < 10; i++) { + for (unsigned int j = 0; j < 10; j++) { + Point p = Point(double(i), double(j)); + Tree::Value v(p, 99.9); + points.push_back(v); + } + } + auto passTest = [&](Tree& kd) -> bool { + // pick some point from the vector + Point refPoint = points[points.size() / 2].point(); + + // perturb it a little + Point delta(0.1, 0.1); + Point testPoint = Point::add(refPoint, delta); + + Point nr = kd.nearestNeighbour(testPoint).point(); + + // we should find the same point + for (unsigned int i = 0; i < Point::dimensions(); i++) { + if (nr.x(i) != refPoint.x(i)) { + return false; + } + } + return true; + }; + + eckit::PathName path("test_kdtree_mapped.kdtree"); + + // Write file with kdtree + { + if (path.exists()) { + path.unlink(); + } + Tree kd(path, points.size(), 0); + EXPECT_EQUAL(kd.size(), 0); + kd.build(points); + EXPECT_EQUAL(kd.size(), points.size()); + EXPECT(passTest(kd)); + } + + // Load file with kdtree + { + Tree kd(path, 0, 0); + + // Cannot insert point as the tree is readonly + EXPECT_THROWS_AS(kd.insert(points.front()), eckit::AssertionFailed); + + // Cannot build with points as the tree is readonly + EXPECT_THROWS_AS(kd.build(points), eckit::AssertionFailed); + + EXPECT_EQUAL(kd.size(), points.size()); + EXPECT(passTest(kd)); + } +} + +CASE("test_kdtree_iterate_empty") { + using Tree = KDTreeMemory; + + Tree kd; + size_t count{0}; + for (auto& item : kd) { + count++; + } + EXPECT_EQUAL(count, 0); +} + +//---------------------------------------------------------------------------------------------------------------------- + +} // namespace eckit::test + +int main(int argc, char** argv) { + return run_tests(argc, argv); +} diff --git a/tests/geo/test_kpoint.cc b/tests/geo/test_kpoint.cc new file mode 100644 index 000000000..8075c03cd --- /dev/null +++ b/tests/geo/test_kpoint.cc @@ -0,0 +1,115 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Point3.h" +#include "eckit/testing/Test.h" + +using namespace std; +using namespace eckit; +using namespace eckit::testing; +using namespace eckit::geo; + +namespace eckit::test { + +CASE("KPoint Inits to Zero") { + Point3 p; + + EXPECT(p[XX] == 0.); + EXPECT(p[YY] == 0.); + EXPECT(p[ZZ] == 0.); +} + +CASE("KPoint Inits to Array") { + Point3 p = {1.0, 2.0, 3.0}; + + EXPECT(p[XX] == 1.0); + EXPECT(p[YY] == 2.0); + EXPECT(p[ZZ] == 3.0); +} + +CASE("KPoint addition") { + Point3 p1 = {1.0, 2.0, 3.0}; + Point3 p2 = {1.0, 2.0, 3.0}; + + Point3 r = p1 + p2; + + EXPECT(r[XX] == 2.0); + EXPECT(r[YY] == 4.0); + EXPECT(r[ZZ] == 6.0); +} + +CASE("KPoint subtraction") { + Point3 p1 = {2.0, 5.0, 7.0}; + Point3 p2 = {1.0, 2.0, 3.0}; + + Point3 r = p1 - p2; + + EXPECT(r[XX] == 1.0); + EXPECT(r[YY] == 3.0); + EXPECT(r[ZZ] == 4.0); +} + +CASE("KPoint subtraction") { + Point3 p1 = {2.0, 5.0, 7.0}; + Point3 p2 = {1.0, 2.0, 3.0}; + + Point3 r = p1 - p2; + + EXPECT(r[XX] == 1.0); + EXPECT(r[YY] == 3.0); + EXPECT(r[ZZ] == 4.0); +} + +CASE("KPoint scaling") { + Point3 p1 = {1.0, 2.0, 3.0}; + + Point3 r = p1 * 42.0; + + EXPECT(r[XX] == 42.0); + EXPECT(r[YY] == 84.0); + EXPECT(r[ZZ] == 126.0); +} + +CASE("KPoint equality") { + Point3 p1 = {1.0, 2.0, 3.0}; + Point3 p2 = {1.0, 2.0, 3.0}; + + EXPECT(p1 == p2); +} + +CASE("KPoint inequality") { + Point3 p1 = {1.0, 2.0, 3.0}; + Point3 p2 = {1.0, 2.0, 4.0}; + + EXPECT(p1 != p2); +} + +CASE("KPoint comparison") { + Point3 p1 = {2.0, 1.0, 0.0}; + Point3 p2 = {1.0, 2.0, 4.0}; + + EXPECT(p2 < p1); +} + +CASE("KPoint distance2 comparison") { + Point3 zz; + Point3 p1 = {2.0, 1.0, 0.0}; + Point3 p2 = {1.0, 2.0, 4.0}; + + EXPECT(p1.distance2(zz) < p2.distance2(zz)); +} + +} // namespace eckit::test + +//---------------------------------------------------------------------------------------------------------------------- + +int main(int argc, char** argv) { + return run_tests(argc, argv); +} diff --git a/tests/geometry/test_param.cc b/tests/geo/test_param.cc similarity index 100% rename from tests/geometry/test_param.cc rename to tests/geo/test_param.cc diff --git a/tests/geo/test_points.cc b/tests/geo/test_points.cc new file mode 100644 index 000000000..e501676be --- /dev/null +++ b/tests/geo/test_points.cc @@ -0,0 +1,156 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Point2.h" +#include "eckit/geo/Point3.h" +#include "eckit/testing/Test.h" + +using namespace std; +using namespace eckit; +using namespace eckit::testing; +using namespace eckit::geo; + +namespace eckit::test { + +CASE("Inits to Zero") { + Point2 q; + + EXPECT(q[XX] == 0.); + EXPECT(q[YY] == 0.); +} + +CASE("Inits to Array/Point") { + Point2 q = {4.0, 5.0}; + + EXPECT(q[XX] == 4.0); + EXPECT(q[YY] == 5.0); + + EXPECT(q[LON] == 4.0); + EXPECT(q[LAT] == 5.0); + + Point2 r(q); + EXPECT(r[XX] == 4.0); + EXPECT(r[YY] == 5.0); + + Point3 p = {1.0, 2.0, 3.0}; + Point3 s(p); + EXPECT(s[XX] == 1.0); + EXPECT(s[YY] == 2.0); + EXPECT(s[ZZ] == 3.0); +} + +CASE("Point2 addition") { + Point2 p1 = {1.0, 2.0}; + Point2 p2 = {2.0, 4.0}; + + Point2 r = p1 + p2; + + EXPECT(r[XX] == 3.0); + EXPECT(r[YY] == 6.0); +} + +CASE("Point2 subtraction") { + Point2 p1 = {2.0, 5.0}; + Point2 p2 = {1.0, 2.0}; + + Point2 r = p1 - p2; + + EXPECT(r[XX] == 1.0); + EXPECT(r[YY] == 3.0); +} + +CASE("Point2 scaling") { + Point2 p1 = {1.0, 2.0}; + Point2 p2(p1); + + Point2 r = p1 * 42.0; + + EXPECT(r[XX] == 42.0); + EXPECT(r[YY] == 84.0); + + Point2 oo; + + Point2 p3 = p2 * 2.0; + Point2 p4 = p3 + p2; + Point2 p5 = p4 - p2 * 3; + EXPECT(p5 == oo); +} + +CASE("Point2 equality") { + Point2 p1 = {1.0, 2.0}; + Point2 p2 = {1.0, 2.0}; + + EXPECT(p1 == p2); +} + +CASE("Point2 inequality") { + Point2 p1 = {1.0, 3.0}; + Point2 p2 = {1.0, 4.0}; + + EXPECT(p1 != p2); +} + +CASE("Point2 comparison") { + Point2 p1 = {2.0, 1.0}; + Point2 p2 = {1.0, 2.0}; + + EXPECT(p2 < p1); +} + +CASE("Point distance comparison") { + Point2 p1 = {2.0, 1.0}; + Point2 p2 = {1.0, 2.0}; + + EXPECT(types::is_approximately_equal(sqrt(2.0), p1.distance(p2))); + + Point2 p3 = {5.0, 5.0}; + + EXPECT(types::is_approximately_equal(p1.distance(p3), 5.0)); +} + +CASE("Point distance2 comparison") { + Point2 p1 = {2.0, 1.0}; + Point2 p2 = {1.0, 2.0}; + + EXPECT(types::is_approximately_equal(p1.distance2(p2), 2.0)); + + Point2 p3 = {5.0, 5.0}; + + EXPECT(types::is_approximately_equal(p1.distance2(p3), 25.0)); +} + + +CASE("Point3 cross") { + Point3 p1 = {1.0, 0.0, 0.0}; + Point3 p2 = {0.0, 1.0, 0.0}; + Point3 p3 = {0.0, 0.0, 1.0}; + + EXPECT(p3 == Point3::cross(p1, p2)); + EXPECT(p1 == Point3::cross(p2, p3)); + + Point3 p4 = {1.0, 2.0, 3.0}; + Point3 p5 = {-1.0, -2.0, 4.0}; + Point3 p6 = {2.0, -1.0, 0.0}; + + Point3 p7 = Point3::normalize(Point3::cross(p4, p5)); + Point3 p8 = Point3::normalize(p6); + + EXPECT(types::is_approximately_equal(p7[XX], p8[XX])); + EXPECT(types::is_approximately_equal(p7[YY], p8[YY])); + EXPECT(types::is_approximately_equal(p7[ZZ], p8[ZZ])); +} + +} // namespace eckit::test + +//---------------------------------------------------------------------------------------------------------------------- + +int main(int argc, char** argv) { + return run_tests(argc, argv); +} diff --git a/tests/geo/test_polygon.cc b/tests/geo/test_polygon.cc new file mode 100644 index 000000000..f50e3654c --- /dev/null +++ b/tests/geo/test_polygon.cc @@ -0,0 +1,388 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/geo/Point2.h" +#include "eckit/geo/polygon/LonLatPolygon.h" +#include "eckit/geo/polygon/Polygon.h" +#include "eckit/testing/Test.h" + +namespace eckit::test { + +CASE("Polygon") { + using geo::polygon::Polygon; + + SECTION("empty polygon") { + Polygon poly1; + Polygon poly2; + + EXPECT(poly1.sameAs(poly2)); + } + + SECTION("equality") { + Polygon poly1; + Polygon poly2; + + EXPECT(poly1.num_vertices() == 0); + + Polygon::value_type p1 = {1.0, 2.0}; + poly1.push_front(p1); + EXPECT(poly1.num_vertices() == 1); + EXPECT(poly1.vertex(0) == p1); + + EXPECT(!poly1.sameAs(poly2)); + + poly2.push_back(p1); + EXPECT(poly1.sameAs(poly2)); + + Polygon::value_type p2 = {2.0, 1.0}; + poly1.push_front(p2); + EXPECT(!poly1.sameAs(poly2)); + + poly2.push_back(p2); + EXPECT(!poly1.sameAs(poly2)); + } + + SECTION("congruence") { + Polygon poly1; + Polygon poly2; + EXPECT(poly1.congruent(poly2)); + + Polygon::value_type p1 = {1.0, 2.0}; + poly1.push_front(p1); + EXPECT(!poly1.congruent(poly2)); + + poly2.push_back(p1); + EXPECT(poly1.congruent(poly2)); + + Polygon::value_type p2 = {2.0, 1.0}; + poly1.push_front(p2); + EXPECT(!poly1.congruent(poly2)); + + poly2.push_back(p2); + EXPECT(poly1.congruent(poly2)); + + Polygon::value_type p3 = {3.0, 4.0}; + poly2.push_back(p3); + Polygon poly3 = {p2, p3, p1}; + EXPECT(!poly2.sameAs(poly3)); + EXPECT(poly2.congruent(poly3)); + + EXPECT(poly2.num_vertices() == 3); + EXPECT(poly2.vertex(2) == poly3.vertex(1)); + + Polygon poly4 = {p3, p1, p2}; + EXPECT(!poly2.sameAs(poly4)); + EXPECT(poly2.congruent(poly4)); + } +} + +CASE("LonLatPolygon") { + using Polygon = geo::polygon::LonLatPolygon; + + SECTION("Construction") { + const std::vector points1{{0, 0}, {1, 1}, {2, 2}, {0, 0}}; + const std::vector points2{{0, 0}, {1, 0}, {2, 0}, {2, 1}, {2, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 0}}; + + EXPECT_EQUAL(Polygon(points1).size(), 2); + EXPECT_EQUAL(Polygon(points1.begin(), points1.end()).size(), 2); + + EXPECT_EQUAL(Polygon(points2).size(), 5); + EXPECT_EQUAL(Polygon(points2.begin(), points2.end()).size(), 5); + } + + SECTION("Contains North pole") { + const std::vector points{{0, 90}, {0, 0}, {1, 0}, {1, 90}, {0, 90}}; + + Polygon poly1(points); + EXPECT(poly1.contains({0, 90})); + EXPECT(poly1.contains({10, 90})); + EXPECT_NOT(poly1.contains({0, -90})); + EXPECT_NOT(poly1.contains({10, -90})); + + Polygon poly2(points, false); + EXPECT(poly2.contains({0, 90})); + EXPECT_NOT(poly2.contains({10, 90})); + EXPECT_NOT(poly2.contains({0, -90})); + EXPECT_NOT(poly2.contains({10, -90})); + } + + SECTION("Contains South pole") { + const std::vector points{{0, -90}, {0, 0}, {1, 0}, {1, -90}, {0, -90}}; + + Polygon poly1(points); + EXPECT_NOT(poly1.contains({0, 90})); + EXPECT_NOT(poly1.contains({10, 90})); + EXPECT(poly1.contains({0, -90})); + EXPECT(poly1.contains({10, -90})); + + Polygon poly2(points, false); + EXPECT_NOT(poly2.contains({0, 90})); + EXPECT_NOT(poly2.contains({10, 90})); + EXPECT(poly2.contains({0, -90})); + EXPECT_NOT(poly2.contains({10, -90})); + } + + SECTION("Contains South and North poles") { + Polygon poly({{0, -90}, {0, 90}, {1, 90}, {1, -90}, {0, -90}}); + EXPECT(poly.contains({0, 90})); + EXPECT(poly.contains({10, 90})); + EXPECT(poly.contains({0, 0})); + EXPECT_NOT(poly.contains({10, 0})); + EXPECT(poly.contains({0, -90})); + EXPECT(poly.contains({10, -90})); + } + + SECTION("MIR-566: wide polygon") { + Polygon poly1({{0, 0}, {361, 0}, {361, 2}, {0, 2}, {0, 0}}); + EXPECT(poly1.contains({0, 1})); + EXPECT(poly1.contains({2, 1})); + EXPECT(poly1.contains({362, 1})); + EXPECT(poly1.contains({722, 1})); + + Polygon poly2({{0, 0}, {11, 0}, {11, 2}, {0, 2}, {0, 0}}); + EXPECT(poly2.contains({0, 1})); + EXPECT(poly2.contains({2, 1})); + EXPECT(poly2.contains({362, 1})); + EXPECT(poly2.contains({722, 1})); + + Polygon poly3({{0, 0}, {360, 0}, {360, 2}, {0, 2}, {0, 0}}); + EXPECT(poly3.contains({0, 1})); + EXPECT(poly3.contains({2 - 360, 1})); + EXPECT(poly3.contains({2, 1})); + EXPECT(poly3.contains({2 + 360, 1})); + + Polygon poly4({{-100, 18}, {21, 30}, {150, 50}, {260, 18}, {-100, 18}}); + EXPECT(poly4.contains({-10 - 360, 18})); + EXPECT(poly4.contains({-10, 18})); + EXPECT(poly4.contains({-10 + 360, 18})); + + Polygon poly5({{-44.2299698513, 44.8732496764}, + {-12.2849279262, 75.2545011911}, + {72.2148603917, 76.7993105902}, + {196.903572422, 71.1350094603}, + {304.194105814, 52.8269579527}, + {266.886210026, -17.7495991714}, + {108.327652927, 34.8499103834}, + {-96.2694736324, -17.4340627522}, + {-99.8761719143, 7.28288763265}, + {-44.2299698513, 44.8732496764}}); + for (double lon = -1, lat = 10; lat < 70; lat += 1) { + EXPECT(poly5.contains({lon - 360, lat})); + EXPECT(poly5.contains({lon, lat})); + EXPECT(poly5.contains({lon + 360, lat})); + } + + constexpr double eps = 0.001; + constexpr double globe = 360; + Polygon poly6({{0 * globe, 4 + eps}, + {1 * globe, 2 + eps}, + {2 * globe, 0 + eps}, + {3 * globe, -2 + eps}, + {4 * globe, -4 + eps}, + {4 * globe, -4 - eps}, + {3 * globe, -2 - eps}, + {2 * globe, 0 - eps}, + {1 * globe, 2 - eps}, + {0 * globe, 4 - eps}, + {0 * globe, 4 + eps}}); + + const std::vector list_lons{-2. * globe, -globe, 0., globe, 2. * globe}; + const std::vector list_lats1{4., 2., 0., -2.}; + const std::vector list_lats2{5., 3., 1., -1., -3., -5.}; + for (double lon : list_lons) { + for (double lat : list_lats1) { + EXPECT(poly6.contains({lon + 180., lat - 1.})); + EXPECT(poly6.contains({lon, lat})); + } + for (double lat : list_lats2) { + EXPECT_NOT(poly6.contains({lon, lat})); + EXPECT_NOT(poly6.contains({lon + 180., lat - 1.})); + } + } + + // HEALPix-like equator wedge in longitude + Polygon poly({{0, 1}, {0, 90}, {360, 90}, {360, 1}, {361, 0}, {360, -1}, {360, -90}, {0, -90}, {0, -1}, {1, 0}, {0, 1}}); + EXPECT(poly.contains({0, 0})); + EXPECT(poly.contains({1, 0})); + EXPECT(poly.contains({360, 0})); + EXPECT(poly.contains({361, 0})); + EXPECT(poly.contains({720, 0})); + EXPECT(poly.contains({721, 0})); + } + + SECTION("MIR-566: winding number strict check of edges") { + Polygon poly({{110, -34}, {90, -62}, {100, -59}, {110, -50}, {132, -40}, {110, -34}}); + EXPECT_NOT(poly.contains({90, -40})); + EXPECT_NOT(poly.contains({90, -34})); + } + + SECTION("Simple rectangular polygon") { + double lonmin = 0; + double lonmax = 360; + double lonmid = 0.5 * (lonmin + lonmax); + + double latmax = 80; + double latmin = 0; + double latmid = 0.5 * (latmin + latmax); + + Polygon poly({{lonmin, latmax}, {lonmax, latmax}, {lonmax, latmin}, {lonmin, latmin}, {lonmin, latmax}}); + + SECTION("Contains edges") { + EXPECT(poly.contains({lonmin, latmax})); + EXPECT(poly.contains({lonmid, latmax})); + EXPECT(poly.contains({lonmax, latmax})); + EXPECT(poly.contains({lonmax, latmid})); + EXPECT(poly.contains({lonmax, latmin})); + EXPECT(poly.contains({lonmid, latmin})); + EXPECT(poly.contains({lonmin, latmin})); + EXPECT(poly.contains({lonmin, latmid})); + } + + SECTION("Contains in/outward of edges") { + constexpr auto eps = 0.001; + + for (size_t i = 0; i <= 100; ++i) { + const auto lon = lonmin + static_cast(i) * (lonmax - lonmin) / 99.; + EXPECT(poly.contains({lon, latmin + eps})); + EXPECT(poly.contains({lon, latmax - eps})); + EXPECT_NOT(poly.contains({lon, latmin - eps})); + EXPECT_NOT(poly.contains({lon, latmax + eps})); + + const auto lat = latmin + static_cast(i) * (latmax - latmin) / 99.; + EXPECT(poly.contains({lonmin + eps, lat})); + EXPECT(poly.contains({lonmax - eps, lat})); + EXPECT_NOT(poly.contains({lonmin - eps, lat})); + EXPECT_NOT(poly.contains({lonmax + eps, lat})); + } + } + + // Test points at non-canonical coordinates + // Default behavior throws + EXPECT_THROWS_AS(poly.contains({lonmid, 180. - latmid}), eckit::BadValue); + + EXPECT(poly.contains({lonmid + 360., latmid}, true)); + EXPECT(poly.contains({lonmid, 180. - latmid}, true)); + } + + SECTION("Parallelogram") { + const std::vector points{{0, 0}, {1, 1}, {2, 1}, {1, 0}, {0, 0}}; + Polygon poly(points); + + for (const auto& p : points) { + EXPECT(poly.contains(p)); + } + EXPECT_NOT(poly.contains({0, 1})); + EXPECT_NOT(poly.contains({2, 0})); + } + + SECTION("Degenerate polygon") { + const std::vector points{{0, 0}, {2, 0}, {2, 0} /*duplicate*/, {0, 2}, {0, 0}}; + + Polygon poly(points); + + for (const auto& p : points) { + EXPECT(poly.contains(p)); + } + + for (const auto& p : std::vector{{2, 2}}) { + EXPECT_NOT(poly.contains(p)); + } + } + + SECTION("Self-intersecting polygon") { + Polygon poly1({{-1, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}); + + EXPECT(poly1.contains({0, 0})); + EXPECT(poly1.contains({-1, 0})); + EXPECT(poly1.contains({1, 0})); + EXPECT_NOT(poly1.contains({0, 1})); + EXPECT_NOT(poly1.contains({0, -1})); + + Polygon poly2({{-1, -1}, {1, -1}, {-1, 1}, {1, 1}, {-1, -1}}); + + EXPECT(poly2.contains({0, 0})); + EXPECT_NOT(poly2.contains({-1, 0})); + EXPECT_NOT(poly2.contains({1, 0})); + EXPECT(poly2.contains({0, 1})); + EXPECT(poly2.contains({0, -1})); + + Polygon poly3({{-1, 89}, {1, 89}, {0, 90}, {181, 89}, {179, 89}, {0, 90}, {-1, 89}}); + EXPECT(poly3.size() == 7); + + const std::vector list_lons{-720., -360., 0., 360., 720.}; + for (const auto& lon : list_lons) { + EXPECT(poly3.contains({lon, 89.})); + EXPECT(poly3.contains({lon + 180, 89.})); + EXPECT_NOT(poly3.contains({lon + 90, 89.})); + EXPECT_NOT(poly3.contains({lon + 270, 89.})); + } + } + + SECTION("Partitioning (includePoles=false)") { + auto mid = [](double a, double b) { + return (a + b) / 2.; + }; + + constexpr double lon[] = {0, 90, 180, 270, 360}; + constexpr double lat[] = {90, 0, -90}; + + Polygon polys[] = { + Polygon({{lon[0], lat[1]}, {lon[1], lat[1]}, {lon[1], lat[0]}, {lon[0], lat[0]}, {lon[0], lat[1]}}, false), + Polygon({{lon[1], lat[1]}, {lon[2], lat[1]}, {lon[2], lat[0]}, {lon[1], lat[0]}, {lon[1], lat[1]}}, false), + Polygon({{lon[2], lat[1]}, {lon[3], lat[1]}, {lon[3], lat[0]}, {lon[2], lat[0]}, {lon[2], lat[1]}}, false), + Polygon({{lon[3], lat[1]}, {lon[4], lat[1]}, {lon[4], lat[0]}, {lon[3], lat[0]}, {lon[3], lat[1]}}, false), + Polygon({{lon[0], lat[1]}, {lon[1], lat[1]}, {lon[1], lat[2]}, {lon[0], lat[2]}, {lon[0], lat[1]}}, false), + Polygon({{lon[1], lat[1]}, {lon[2], lat[1]}, {lon[2], lat[2]}, {lon[1], lat[2]}, {lon[1], lat[1]}}, false), + Polygon({{lon[2], lat[1]}, {lon[3], lat[1]}, {lon[3], lat[2]}, {lon[2], lat[2]}, {lon[2], lat[1]}}, false), + Polygon({{lon[3], lat[1]}, {lon[4], lat[1]}, {lon[4], lat[2]}, {lon[3], lat[2]}, {lon[3], lat[1]}}, false)}; + + + std::vector points; + const std::vector list_lons{lon[0], mid(lon[0], lon[1]), lon[1], mid(lon[1], lon[2]), lon[2], mid(lon[2], lon[3]), lon[3], mid(lon[3], lon[4])}; + const std::vector list_lats{lat[0], mid(lat[0], lat[1]), lat[1], mid(lat[1], lat[2]), lat[2]}; + + for (double lon : list_lons) { + for (double lat : list_lats) { + points.emplace_back(lon, lat); + } + } + + std::vector counts(points.size(), 0); + for (size_t i = 0; i < points.size(); ++i) { + for (const auto& poly : polys) { + if (poly.contains(points[i])) { + ++counts[i]; + } + } + } + + for (size_t i = 0; i < counts.size(); i += list_lats.size() * 2) { + EXPECT(counts[i + 0] == 2); + EXPECT(counts[i + 1] == 2); + EXPECT(counts[i + 2] == 4); + EXPECT(counts[i + 3] == 2); + EXPECT(counts[i + 4] == 2); + + EXPECT(counts[i + 5] == 1); + EXPECT(counts[i + 6] == 1); + EXPECT(counts[i + 7] == 2); + EXPECT(counts[i + 8] == 1); + EXPECT(counts[i + 9] == 1); + } + } +} + +} // namespace eckit::test + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geometry/test_projection.cc b/tests/geo/test_projection.cc similarity index 96% rename from tests/geometry/test_projection.cc rename to tests/geo/test_projection.cc index b503e4c79..c9da06c1c 100644 --- a/tests/geometry/test_projection.cc +++ b/tests/geo/test_projection.cc @@ -14,19 +14,19 @@ #include #include "eckit/config/MappedConfiguration.h" -#include "eckit/geometry/Projection.h" -#include "eckit/geometry/projection/LonLatToXYZ.h" -#include "eckit/geometry/projection/Rotation.h" +#include "eckit/geo/Projection.h" +#include "eckit/geo/projection/LonLatToXYZ.h" +#include "eckit/geo/projection/Rotation.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { using eckit::MappedConfiguration; - using namespace eckit::geometry; + using namespace eckit::geo; - using Projection = std::unique_ptr; - using eckit::geometry::ProjectionFactory; + using Projection = std::unique_ptr; + using eckit::geo::ProjectionFactory; Point p = PointLonLat{1, 1}; @@ -87,7 +87,8 @@ int main(int argc, char* argv[]) { const PointLonLat p(723., 1.); // <- FIXME - { projection::LonLatToXYZ to_xyz(1.); + { + projection::LonLatToXYZ to_xyz(1.); auto q = to_xyz.fwd(p); auto r = to_xyz.inv(q); diff --git a/tests/geometry/test_search.cc b/tests/geo/test_search.cc similarity index 95% rename from tests/geometry/test_search.cc rename to tests/geo/test_search.cc index 1f9d2b0f6..afab1f0e4 100644 --- a/tests/geometry/test_search.cc +++ b/tests/geo/test_search.cc @@ -13,11 +13,11 @@ #include #include -#include "eckit/geometry/Search.h" +#include "eckit/geo/Search.h" int main(int argc, const char* argv[]) { - using namespace eckit::geometry; + using namespace eckit::geo; { diff --git a/tests/geo/test_sphere.cc b/tests/geo/test_sphere.cc new file mode 100644 index 000000000..3c9ef38c7 --- /dev/null +++ b/tests/geo/test_sphere.cc @@ -0,0 +1,278 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "eckit/geo/Point3.h" +#include "eckit/geo/PointLonLat.h" +#include "eckit/geo/SphereT.h" +#include "eckit/geo/UnitSphere.h" +#include "eckit/testing/Test.h" + +namespace eckit::tests::geo { + +// set sphere +struct DatumTwoUnits { + static double radius() { return 2.; } +}; + +using TwoUnitsSphere = eckit::geo::SphereT; + +using eckit::geo::Point3; +using eckit::geo::PointLonLat; + +using eckit::geo::UnitSphere; +const double R = UnitSphere::radius(); + + +// ----------------------------------------------------------------------------- +// test unit sphere radius + +CASE("test unit sphere radius") { + EXPECT(UnitSphere::radius() == 1.); +} + +// ----------------------------------------------------------------------------- +// test unit sphere poles + +CASE("test unit sphere north pole") { + auto p = UnitSphere::convertSphericalToCartesian({0., 90.}); + + EXPECT(p.X == 0); + EXPECT(p.Y == 0); + EXPECT(p.Z == R); +} + +CASE("test unit sphere south pole") { + auto p = UnitSphere::convertSphericalToCartesian({0., -90.}); + + EXPECT(p.X == 0); + EXPECT(p.Y == 0); + EXPECT(p.Z == -R); +} + +// ----------------------------------------------------------------------------- +// test unit sphere quadrants + +CASE("test unit sphere lon 0") { + auto p = UnitSphere::convertSphericalToCartesian({0., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-360., 0.}); + + EXPECT(p.X == R); + EXPECT(p.Y == 0); + EXPECT(p.Z == 0); + + EXPECT(Point3::equal(p, q)); +} + +CASE("test unit sphere lon 90") { + auto p = UnitSphere::convertSphericalToCartesian({90., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-270., 0.}); + + EXPECT(p.X == 0); + EXPECT(p.Y == R); + EXPECT(p.Z == 0); + + EXPECT(Point3::equal(p, q)); +} + +CASE("test unit sphere lon 180") { + auto p = UnitSphere::convertSphericalToCartesian({180., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-180., 0.}); + + EXPECT(p.X == -R); + EXPECT(p.Y == 0); + EXPECT(p.Z == 0); + + EXPECT(Point3::equal(p, q)); +} + +CASE("test unit sphere lon 270") { + auto p = UnitSphere::convertSphericalToCartesian({270., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-90., 0.}); + + EXPECT(p.X == 0); + EXPECT(p.Y == -R); + EXPECT(p.Z == 0); + + EXPECT(Point3::equal(p, q)); +} + + +// ----------------------------------------------------------------------------- +// test unit sphere octants + +const double L = R * std::sqrt(2) / 2.; + +CASE("test unit sphere lon 45") { + auto p = UnitSphere::convertSphericalToCartesian({45., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-315., 0.}); + + EXPECT(eckit::types::is_approximately_equal(p.X, L)); + EXPECT(eckit::types::is_approximately_equal(p.Y, L)); + EXPECT(p.Z == 0); + + EXPECT(Point3::equal(p, q)); +} + +CASE("test unit sphere lon 135") { + auto p = UnitSphere::convertSphericalToCartesian({135., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-225., 0.}); + + EXPECT(eckit::types::is_approximately_equal(p.X, -L)); + EXPECT(eckit::types::is_approximately_equal(p.Y, L)); + EXPECT(p.Z == 0); + + EXPECT(Point3::equal(p, q)); +} + +CASE("test unit sphere lon 225") { + auto p = UnitSphere::convertSphericalToCartesian({225., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-135., 0.}); + + EXPECT(eckit::types::is_approximately_equal(p.X, -L)); + EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); + EXPECT(p.Z == 0); + + EXPECT(Point3::equal(p, q)); +} + +CASE("test unit sphere lon 315") { + auto p = UnitSphere::convertSphericalToCartesian({315., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-45., 0.}); + + EXPECT(eckit::types::is_approximately_equal(p.X, L)); + EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); + EXPECT(p.Z == 0); + + EXPECT(Point3::equal(p, q)); +} + +// ----------------------------------------------------------------------------- +// test unit sphere with non-canonical latitudes outside [-90, 90] + +CASE("test unit sphere lat 100") { + // Default behavior throws + EXPECT_THROWS_AS(PointLonLat(0., 100.), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({0., 100.}), eckit::BadValue); + + auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(0., 100.), 0.); + auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(180., 80.), 0.); + + // sin(x) and sin(pi-x) are not bitwise identical + EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); + EXPECT(eckit::types::is_approximately_equal(p.Y, q.Y)); + EXPECT(eckit::types::is_approximately_equal(p.Z, q.Z)); +} + +CASE("test unit sphere lat 290") { + // Default behavior throws + EXPECT_THROWS_AS(PointLonLat(15., 290.), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({15., 290.}), eckit::BadValue); + + auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., 290.), 0.); + auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., -70.), 0.); + + // sin(x) and sin(pi-x) are not bitwise identical + EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); + EXPECT(eckit::types::is_approximately_equal(p.Y, q.Y)); + EXPECT(eckit::types::is_approximately_equal(p.Z, q.Z)); +} + +CASE("test unit sphere lat -120") { + // Default behavior throws + EXPECT_THROWS_AS(PointLonLat(45., -120.), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({45., -120.}), eckit::BadValue); + + auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(45., -120.), 0.); + auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(225., -60.), 0.); + + // sin(x) and sin(pi-x) are not bitwise identical + EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); + EXPECT(eckit::types::is_approximately_equal(p.Y, q.Y)); + EXPECT(eckit::types::is_approximately_equal(p.Z, q.Z)); +} + +// ----------------------------------------------------------------------------- +// test unit sphere distances with non-canonical coordinates + +CASE("test unit sphere distances") { + const PointLonLat P1(-71.6, -33.); // Valparaíso + const PointLonLat P2(121.8, 31.4); // Shanghai + + // Same points with added shifts + const auto P1b = PointLonLat::make(288.4, -33.); // Valparaíso + longitude shift + const auto P2b = PointLonLat::make(301.8, 148.6); // Shanghai + latitude/longitude shift + const auto P2c = PointLonLat::make(-58.2, -211.4); // Shanghai + latitude/longitude shift + + const double d0 = UnitSphere::distance(P1, P2); + const double d1 = UnitSphere::distance(P1b, P2); + const double d2 = UnitSphere::distance(P1, P2b); + const double d3 = UnitSphere::distance(P1, P2c); + + EXPECT(eckit::types::is_approximately_equal(d0, d1)); + EXPECT(eckit::types::is_approximately_equal(d0, d2)); + EXPECT(eckit::types::is_approximately_equal(d0, d3)); +} + +// ----------------------------------------------------------------------------- +// test unit sphere area + +CASE("test unit sphere area globe") { + EXPECT(UnitSphere::area() == 4. * M_PI * R * R); +} + +CASE("test unit sphere area hemispheres") { + const double area_hemisphere_north = UnitSphere::area({-180., 90.}, {180., 0.}); + const double area_hemisphere_south = UnitSphere::area({-180., 0.}, {180., -90.}); + + EXPECT(area_hemisphere_north == 0.5 * UnitSphere::area()); + EXPECT(area_hemisphere_north == area_hemisphere_south); +} + +// ----------------------------------------------------------------------------- +// test two units sphere + +CASE("test two units sphere radius") { + EXPECT(TwoUnitsSphere::radius() == 2.); +} + +CASE("test two units sphere distances") { + const PointLonLat P1(-71.6, -33.); // Valparaíso + const PointLonLat P2(121.8, 31.4); // Shanghai + + const double d_sphere_1 = UnitSphere::distance(P1, P2); + const double d_sphere_2 = TwoUnitsSphere::distance(P1, P2); + EXPECT(2. * d_sphere_1 == d_sphere_2); +} + +CASE("test two units sphere areas") { + const double area_sphere_1 = UnitSphere::area(); + const double area_sphere_2 = TwoUnitsSphere::area(); + EXPECT(4. * area_sphere_1 == area_sphere_2); +} + +CASE("test two units sphere sub areas") { + const PointLonLat P1(-71.6, -33.); // Valparaíso + const PointLonLat P2(121.8, 31.4); // Shanghai + + const double sub_area_sphere_1 = UnitSphere::area(P2, P1); + const double sub_area_sphere_2 = TwoUnitsSphere::area(P2, P1); + EXPECT(4. * sub_area_sphere_1 == sub_area_sphere_2); +} + +// ----------------------------------------------------------------------------- + +} // namespace eckit::tests::geo + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geometry/test_types.cc b/tests/geo/test_types.cc similarity index 96% rename from tests/geometry/test_types.cc rename to tests/geo/test_types.cc index 64494e236..f0d88a86d 100644 --- a/tests/geometry/test_types.cc +++ b/tests/geo/test_types.cc @@ -12,13 +12,13 @@ #include -#include "eckit/geometry/Point.h" +#include "eckit/geo/Point.h" #include "eckit/maths/Matrix3.h" #include "eckit/testing/Test.h" int main(int argc, char* argv[]) { - using namespace eckit::geometry; + using namespace eckit::geo; PointLonLat p(1, 90.); diff --git a/tests/geometry/test_util.cc b/tests/geo/test_util.cc similarity index 97% rename from tests/geometry/test_util.cc rename to tests/geo/test_util.cc index 7be4704b2..383df4315 100644 --- a/tests/geometry/test_util.cc +++ b/tests/geo/test_util.cc @@ -13,7 +13,7 @@ #include #include -#include "eckit/geometry/util.h" +#include "eckit/geo/util.h" template @@ -68,7 +68,7 @@ class iterable_t : public std::vector { int main(int argc, char* argv[]) { - using namespace eckit::geometry::util; + using namespace eckit::geo::util; #if 0 std::cout << linspace(1, 2, 2, true) << std::endl; diff --git a/tests/geometry/CMakeLists.txt b/tests/geometry/CMakeLists.txt index ab0ae8747..45673e9f9 100644 --- a/tests/geometry/CMakeLists.txt +++ b/tests/geometry/CMakeLists.txt @@ -1,21 +1,5 @@ -foreach( _test - coordinate_helpers - great_circle - grid - iterator - kdtree - kpoint - param - points - polygon - projection - search - sphere - types - util ) - ecbuild_add_test( - TARGET eckit_test_geometry_${_test} - SOURCES test_${_test}.cc - LIBS eckit_geometry ) +foreach( _test coordinate_helpers great_circle kdtree sphere kpoint points polygon ) + ecbuild_add_test( TARGET eckit_test_geometry_${_test} + SOURCES test_${_test}.cc + LIBS eckit_geometry ) endforeach() - diff --git a/tests/geometry/test_great_circle.cc b/tests/geometry/test_great_circle.cc index 4049930fd..d2af045de 100644 --- a/tests/geometry/test_great_circle.cc +++ b/tests/geometry/test_great_circle.cc @@ -13,13 +13,20 @@ #include #include "eckit/geometry/GreatCircle.h" -#include "eckit/geometry/PointLonLat.h" +#include "eckit/geometry/Point2.h" #include "eckit/testing/Test.h" namespace eckit::test { using namespace geometry; +struct PointLonLat : Point2 { + PointLonLat(double x, double y) : + Point2(x, y) {} + const double& lon() const { return x_[0]; } + const double& lat() const { return x_[1]; } +}; + // ----------------------------------------------------------------------------- // test great circles @@ -101,13 +108,12 @@ CASE("test great circles intersections") { const PointLonLat mid(-159.18, -6.81); - auto lats = gc.latitude(mid.lon); - EXPECT(lats.size() == 1 && is_approximately_equal(lats[0], mid.lat, 0.01)); + auto lats = gc.latitude(mid.lon()); + EXPECT(lats.size() == 1 && is_approximately_equal(lats[0], mid.lat(), 0.01)); - auto lons = gc.longitude(mid.lat); + auto lons = gc.longitude(mid.lat()); EXPECT(lons.size() == 2); - EXPECT(is_approximately_equal_longitude(lons[0], mid.lon, 0.01) - || is_approximately_equal_longitude(lons[1], mid.lon, 0.01)); + EXPECT(is_approximately_equal_longitude(lons[0], mid.lon(), 0.01) || is_approximately_equal_longitude(lons[1], mid.lon(), 0.01)); } SECTION("mal-formed great circle") { @@ -120,11 +126,11 @@ CASE("test great circles intersections") { EXPECT_THROWS_AS(GreatCircle(A, B), BadValue); - if (is_approximately_pole(A.lat)) { + if (is_approximately_pole(A.lat())) { for (double lon1_gc : longitudes) { for (double lon2_gc : longitudes) { - EXPECT_THROWS_AS(GreatCircle({lon1_gc, A.lat}, {lon2_gc, A.lat}), BadValue); - EXPECT_THROWS_AS(GreatCircle({lon1_gc, B.lat}, {lon2_gc, B.lat}), BadValue); + EXPECT_THROWS_AS(GreatCircle({lon1_gc, A.lat()}, {lon2_gc, A.lat()}), BadValue); + EXPECT_THROWS_AS(GreatCircle({lon1_gc, B.lat()}, {lon2_gc, B.lat()}), BadValue); } } } diff --git a/tests/geometry/test_kdtree.cc b/tests/geometry/test_kdtree.cc index a64a801d6..3b33e54c2 100644 --- a/tests/geometry/test_kdtree.cc +++ b/tests/geometry/test_kdtree.cc @@ -124,7 +124,7 @@ CASE("test_eckit_container_kdtree_constructor") { typedef KDTreeMemory Tree; Tree kd; - using Point = Tree::PointType; + typedef Tree::PointType Point; std::vector points; diff --git a/tests/geometry/test_sphere.cc b/tests/geometry/test_sphere.cc index a8b31a443..4e761f8a8 100644 --- a/tests/geometry/test_sphere.cc +++ b/tests/geometry/test_sphere.cc @@ -11,25 +11,36 @@ #include #include +#include "eckit/geometry/Point2.h" #include "eckit/geometry/Point3.h" -#include "eckit/geometry/PointLonLat.h" #include "eckit/geometry/SphereT.h" #include "eckit/geometry/UnitSphere.h" #include "eckit/testing/Test.h" -namespace eckit::tests::geometry { +namespace eckit::test { + +using namespace geometry; + +struct PointLonLat : Point2 { + PointLonLat(double x, double y) : + Point2(x, y) {} + const double& lon() const { return x_[0]; } + const double& lat() const { return x_[1]; } +}; + +struct PointXYZ : Point3 { + const double& x() const { return x_[0]; } + const double& y() const { return x_[1]; } + const double& z() const { return x_[2]; } +}; // set sphere struct DatumTwoUnits { static double radius() { return 2.; } }; -using TwoUnitsSphere = eckit::geometry::SphereT; +using TwoUnitsSphere = SphereT; -using eckit::geometry::Point3; -using eckit::geometry::PointLonLat; - -using eckit::geometry::UnitSphere; const double R = UnitSphere::radius(); @@ -44,66 +55,82 @@ CASE("test unit sphere radius") { // test unit sphere poles CASE("test unit sphere north pole") { - auto p = UnitSphere::convertSphericalToCartesian({0., 90.}); + const PointLonLat ll1(0., 90.); + PointXYZ p; + UnitSphere::convertSphericalToCartesian(ll1, p); - EXPECT(p.X == 0); - EXPECT(p.Y == 0); - EXPECT(p.Z == R); + EXPECT(p.x() == 0); + EXPECT(p.y() == 0); + EXPECT(p.z() == R); } CASE("test unit sphere south pole") { - auto p = UnitSphere::convertSphericalToCartesian({0., -90.}); + const PointLonLat ll1(0., -90.); + PointXYZ p; + UnitSphere::convertSphericalToCartesian(ll1, p); - EXPECT(p.X == 0); - EXPECT(p.Y == 0); - EXPECT(p.Z == -R); + EXPECT(p.x() == 0); + EXPECT(p.y() == 0); + EXPECT(p.z() == -R); } // ----------------------------------------------------------------------------- // test unit sphere quadrants CASE("test unit sphere lon 0") { - auto p = UnitSphere::convertSphericalToCartesian({0., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-360., 0.}); + const PointLonLat ll1(0., 0.); + const PointLonLat ll2(-360., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(p.X == R); - EXPECT(p.Y == 0); - EXPECT(p.Z == 0); + EXPECT(p.x() == R); + EXPECT(p.y() == 0); + EXPECT(p.z() == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } CASE("test unit sphere lon 90") { - auto p = UnitSphere::convertSphericalToCartesian({90., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-270., 0.}); + const PointLonLat ll1(90., 0.); + const PointLonLat ll2(-270., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(p.X == 0); - EXPECT(p.Y == R); - EXPECT(p.Z == 0); + EXPECT(p.x() == 0); + EXPECT(p.y() == R); + EXPECT(p.z() == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } CASE("test unit sphere lon 180") { - auto p = UnitSphere::convertSphericalToCartesian({180., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-180., 0.}); + const PointLonLat ll1(180., 0.); + const PointLonLat ll2(-180., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(p.X == -R); - EXPECT(p.Y == 0); - EXPECT(p.Z == 0); + EXPECT(p.x() == -R); + EXPECT(p.y() == 0); + EXPECT(p.z() == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } CASE("test unit sphere lon 270") { - auto p = UnitSphere::convertSphericalToCartesian({270., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-90., 0.}); + const PointLonLat ll1(270., 0.); + const PointLonLat ll2(-90., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(p.X == 0); - EXPECT(p.Y == -R); - EXPECT(p.Z == 0); + EXPECT(p.x() == 0); + EXPECT(p.y() == -R); + EXPECT(p.z() == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } @@ -113,92 +140,113 @@ CASE("test unit sphere lon 270") { const double L = R * std::sqrt(2) / 2.; CASE("test unit sphere lon 45") { - auto p = UnitSphere::convertSphericalToCartesian({45., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-315., 0.}); + const PointLonLat ll1(45., 0.); + const PointLonLat ll2(-315., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(eckit::types::is_approximately_equal(p.X, L)); - EXPECT(eckit::types::is_approximately_equal(p.Y, L)); - EXPECT(p.Z == 0); + EXPECT(eckit::types::is_approximately_equal(p.x(), L)); + EXPECT(eckit::types::is_approximately_equal(p.y(), L)); + EXPECT(p.z() == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } CASE("test unit sphere lon 135") { - auto p = UnitSphere::convertSphericalToCartesian({135., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-225., 0.}); + const PointLonLat ll1(135., 0.); + const PointLonLat ll2(-225., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(eckit::types::is_approximately_equal(p.X, -L)); - EXPECT(eckit::types::is_approximately_equal(p.Y, L)); - EXPECT(p.Z == 0); + EXPECT(eckit::types::is_approximately_equal(p.x(), -L)); + EXPECT(eckit::types::is_approximately_equal(p.y(), L)); + EXPECT(p.z() == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } CASE("test unit sphere lon 225") { - auto p = UnitSphere::convertSphericalToCartesian({225., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-135., 0.}); + const PointLonLat ll1(225., 0.); + const PointLonLat ll2(-135., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(eckit::types::is_approximately_equal(p.X, -L)); - EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); - EXPECT(p.Z == 0); + EXPECT(eckit::types::is_approximately_equal(p.x(), -L)); + EXPECT(eckit::types::is_approximately_equal(p.y(), -L)); + EXPECT(p.z() == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } CASE("test unit sphere lon 315") { - auto p = UnitSphere::convertSphericalToCartesian({315., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-45., 0.}); + const PointLonLat ll1(315., 0.); + const PointLonLat ll2(-45., 0.); + PointXYZ p, q; + UnitSphere::convertSphericalToCartesian(ll1, p); + UnitSphere::convertSphericalToCartesian(ll2, q); - EXPECT(eckit::types::is_approximately_equal(p.X, L)); - EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); - EXPECT(p.Z == 0); + EXPECT(eckit::types::is_approximately_equal(p.x(), L)); + EXPECT(eckit::types::is_approximately_equal(p.y(), -L)); + EXPECT(p.z() == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(PointXYZ::equal(p, q)); } // ----------------------------------------------------------------------------- // test unit sphere with non-canonical latitudes outside [-90, 90] CASE("test unit sphere lat 100") { + const PointLonLat ll1(0., 100.); + const PointLonLat ll2(180., 80.); + PointXYZ p, q; + // Default behavior throws - EXPECT_THROWS_AS(PointLonLat(0., 100.), eckit::BadValue); - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({0., 100.}), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian(ll1, p), eckit::BadValue); - auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(0., 100.), 0.); - auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(180., 80.), 0.); + UnitSphere::convertSphericalToCartesian(ll1, p, 0., true); + UnitSphere::convertSphericalToCartesian(ll2, q, 0., true); // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); - EXPECT(eckit::types::is_approximately_equal(p.Y, q.Y)); - EXPECT(eckit::types::is_approximately_equal(p.Z, q.Z)); + EXPECT(eckit::types::is_approximately_equal(p.x(), q.x())); + EXPECT(eckit::types::is_approximately_equal(p.y(), q.y())); + EXPECT(eckit::types::is_approximately_equal(p.z(), q.z())); } CASE("test unit sphere lat 290") { + const PointLonLat ll1(15., 290.); + const PointLonLat ll2(15., -70.); + PointXYZ p, q; + // Default behavior throws - EXPECT_THROWS_AS(PointLonLat(15., 290.), eckit::BadValue); - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({15., 290.}), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian(ll1, p), eckit::BadValue); - auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., 290.), 0.); - auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., -70.), 0.); + UnitSphere::convertSphericalToCartesian(ll1, p, 0., true); + UnitSphere::convertSphericalToCartesian(ll2, q, 0., true); // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); - EXPECT(eckit::types::is_approximately_equal(p.Y, q.Y)); - EXPECT(eckit::types::is_approximately_equal(p.Z, q.Z)); + EXPECT(eckit::types::is_approximately_equal(p.x(), q.x())); + EXPECT(eckit::types::is_approximately_equal(p.y(), q.y())); + EXPECT(eckit::types::is_approximately_equal(p.z(), q.z())); } CASE("test unit sphere lat -120") { + const PointLonLat ll1(45., -120.); + const PointLonLat ll2(225., -60.); + PointXYZ p, q; + // Default behavior throws - EXPECT_THROWS_AS(PointLonLat(45., -120.), eckit::BadValue); - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({45., -120.}), eckit::BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian(ll1, p), eckit::BadValue); - auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(45., -120.), 0.); - auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(225., -60.), 0.); + UnitSphere::convertSphericalToCartesian(ll1, p, 0., true); + UnitSphere::convertSphericalToCartesian(ll2, q, 0., true); // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); - EXPECT(eckit::types::is_approximately_equal(p.Y, q.Y)); - EXPECT(eckit::types::is_approximately_equal(p.Z, q.Z)); + EXPECT(eckit::types::is_approximately_equal(p.x(), q.x())); + EXPECT(eckit::types::is_approximately_equal(p.y(), q.y())); + EXPECT(eckit::types::is_approximately_equal(p.z(), q.z())); } // ----------------------------------------------------------------------------- @@ -209,9 +257,9 @@ CASE("test unit sphere distances") { const PointLonLat P2(121.8, 31.4); // Shanghai // Same points with added shifts - const auto P1b = PointLonLat::make(288.4, -33.); // Valparaíso + longitude shift - const auto P2b = PointLonLat::make(301.8, 148.6); // Shanghai + latitude/longitude shift - const auto P2c = PointLonLat::make(-58.2, -211.4); // Shanghai + latitude/longitude shift + const PointLonLat P1b(288.4, -33.); // Valparaíso + longitude shift + const PointLonLat P2b(301.8, 148.6); // Shanghai + latitude/longitude shift + const PointLonLat P2c(-58.2, -211.4); // Shanghai + latitude/longitude shift const double d0 = UnitSphere::distance(P1, P2); const double d1 = UnitSphere::distance(P1b, P2); @@ -231,8 +279,12 @@ CASE("test unit sphere area globe") { } CASE("test unit sphere area hemispheres") { - const double area_hemisphere_north = UnitSphere::area({-180., 90.}, {180., 0.}); - const double area_hemisphere_south = UnitSphere::area({-180., 0.}, {180., -90.}); + const PointLonLat ll1(-180., 90.); + const PointLonLat ll2(180., 0.); + const PointLonLat ll3(-180., 0.); + const PointLonLat ll4(180., -90.); + const double area_hemisphere_north = UnitSphere::area(ll1, ll2); + const double area_hemisphere_south = UnitSphere::area(ll3, ll4); EXPECT(area_hemisphere_north == 0.5 * UnitSphere::area()); EXPECT(area_hemisphere_north == area_hemisphere_south); @@ -271,7 +323,7 @@ CASE("test two units sphere sub areas") { // ----------------------------------------------------------------------------- -} // namespace eckit::tests::geometry +} // namespace eckit::test int main(int argc, char** argv) { return eckit::testing::run_tests(argc, argv); From eb3b7efa35c8b31ee7484581a0846cb7a83a7a22 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 31 Aug 2023 14:41:39 +0100 Subject: [PATCH 324/737] eckit::geo --- src/eckit/geo/grid/regular/RegularLatLon.cc | 31 +++++++++++++++++++++ src/eckit/geo/grid/regular/RegularLatLon.h | 3 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/grid/regular/RegularLatLon.cc b/src/eckit/geo/grid/regular/RegularLatLon.cc index d286b7b5f..5570c5da6 100644 --- a/src/eckit/geo/grid/regular/RegularLatLon.cc +++ b/src/eckit/geo/grid/regular/RegularLatLon.cc @@ -12,7 +12,10 @@ #include "eckit/geo/grid/regular/RegularLatLon.h" +#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/iterator/Regular.h" +#include "eckit/geo/util/regex.h" +#include "eckit/utils/Translator.h" namespace eckit::geo::grid::regular { @@ -53,4 +56,32 @@ const std::vector& RegularLatLon::latitudes() const { } +#define POSITIVE_REAL "[+]?([0-9]*[.])?[0-9]+([eE][-+][0-9]+)?" + + +Configuration* RegularLatLon::config(const std::string& name) { + static const std::string pattern("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); + + auto match = util::regex_match(pattern, name); + ASSERT(match); + ASSERT(match.size() == 7); // because of sub-matches + + auto d = Translator{}; + std::vector increments{d(match[1]), d(match[4])}; + + auto ni = 1; // detail::RegularIterator(Fraction(0), Fraction(360), Fraction(increments[0]), Fraction(0), Fraction(360)).n(); + auto nj = 1; // detail::RegularIterator(Fraction(-90), Fraction(90), Fraction(increments[1]), Fraction(0)).n(); + + return new MappedConfiguration({{"type", "regular_ll"}, + {"west_east_increment", increments[0]}, + {"south_north_increment", increments[1]}, + {"ni", ni}, + {"nj", nj}}); +} + + +static const GridRegisterType __grid_type("regular_ll"); +static const GridRegisterName __grid_pattern(POSITIVE_REAL "/" POSITIVE_REAL); + + } // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/grid/regular/RegularLatLon.h b/src/eckit/geo/grid/regular/RegularLatLon.h index 7e61a8034..db3c3394a 100644 --- a/src/eckit/geo/grid/regular/RegularLatLon.h +++ b/src/eckit/geo/grid/regular/RegularLatLon.h @@ -54,7 +54,8 @@ class RegularLatLon final : public Regular { // None // -- Class methods - // None + + static Configuration* config(const std::string& name); private: // -- Members From 45343a1705953a2a66d46127c75194f6a069a8c4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 31 Aug 2023 14:42:14 +0100 Subject: [PATCH 325/737] eckit::geo --- src/eckit/geo/Range.h | 3 +- src/eckit/geo/range/Gaussian.cc | 60 ++++++++++--------------------- src/eckit/geo/range/Gaussian.h | 6 ++-- tests/geo/CMakeLists.txt | 1 + tests/geo/test_range.cc | 64 +++++++++++++++++++++++++++++++++ tests/geo/test_util.cc | 40 --------------------- 6 files changed, 89 insertions(+), 85 deletions(-) create mode 100644 tests/geo/test_range.cc diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index a29506c47..9345ddcfe 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -58,7 +58,8 @@ class Range : protected std::vector { static std::string className() { return "range"; } - bool empty() const { return vector::empty(); } + using vector::empty; + size_t size() const { return empty() ? n_ : vector::size(); } virtual const std::vector& values() const = 0; diff --git a/src/eckit/geo/range/Gaussian.cc b/src/eckit/geo/range/Gaussian.cc index e5db373e0..dc3d8fca0 100644 --- a/src/eckit/geo/range/Gaussian.cc +++ b/src/eckit/geo/range/Gaussian.cc @@ -22,59 +22,35 @@ namespace eckit::geo::range { -Gaussian::Gaussian(size_t N) : - Gaussian(N, 90., -90) { -} - - Gaussian::Gaussian(size_t N, double a, double b, double precision) : Range(2 * N), N_(N), a_(a), b_(b), - precision_(precision) { + eps_(precision) { ASSERT(N > 0); - ASSERT(precision_ >= 0.); + ASSERT(eps_ >= 0.); + + // pre-calculate on cropping + auto [min, max] = std::minmax(a_, b_); + if (!types::is_approximately_equal(min, -90., eps_) || !types::is_approximately_equal(max, 90., eps_)) { + auto [from, to] = util::monotonic_crop(values(), min, max, precision); + if (to != end()) { + erase(to); + } + if (from != begin()) { + erase(begin(), from); + } + ASSERT(!empty()); + } } const std::vector& Gaussian::values() const { if (empty()) { - auto& v = const_cast&>(valuesVector()); - v = util::gaussian_latitudes(N_, a_ < b_); - ASSERT(v.size() == 2 * N_); - - const bool same(a_ == b_); - - auto a = a_; - auto b = b_; - - if (a < v.back()) { - a = v.back(); - } - else { - auto best = std::lower_bound(v.begin(), v.end(), a, [&](double l1, double l2) { - return !types::is_approximately_equal(l1, l2, precision_) && !(l1 < l2); - }); - ASSERT(best != v.end()); - a = *best; - } - - if (same) { - b = a; - } - else if (b > v.front()) { - b = v.front(); - } - else { - auto best = std::lower_bound(v.rbegin(), v.rend(), b, [&](double l1, double l2) { - return !types::is_approximately_equal(l1, l2, precision_) && !(l1 > l2); - }); - ASSERT(best != v.rend()); - b = *best; - } - - ASSERT((a_ <= b_) == (a <= b)); + const_cast&>(valuesVector()) = util::gaussian_latitudes(N_, a_ < b_); + ASSERT(!empty()); + ASSERT(size() == 2 * N_); } return *this; diff --git a/src/eckit/geo/range/Gaussian.h b/src/eckit/geo/range/Gaussian.h index 34cf76ed9..8a4fd6001 100644 --- a/src/eckit/geo/range/Gaussian.h +++ b/src/eckit/geo/range/Gaussian.h @@ -28,7 +28,9 @@ class Gaussian final : public Range { // -- Constructors - explicit Gaussian(size_t N); + explicit Gaussian(size_t N, double precision = 0.) : + Gaussian(N, 90., -90., precision) {} + Gaussian(size_t N, double a, double b, double precision = 0.); // -- Destructor @@ -60,7 +62,7 @@ class Gaussian final : public Range { const size_t N_; const double a_; const double b_; - const double precision_; + const double eps_; // -- Methods // None diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index eb75f851f..103d9779d 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -9,6 +9,7 @@ foreach( _test points polygon projection + range search sphere types diff --git a/tests/geo/test_range.cc b/tests/geo/test_range.cc new file mode 100644 index 000000000..fbb65be33 --- /dev/null +++ b/tests/geo/test_range.cc @@ -0,0 +1,64 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "eckit/geo/range/Gaussian.h" +#include "eckit/geo/range/GlobalRegular.h" +#include "eckit/geo/range/LocalRegular.h" +#include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" + + +#define EXPECT_APPROX(a, b) EXPECT(::eckit::types::is_approximately_equal((a), (b), 1e-12)) + + +int main(int argc, const char* argv[]) { + using namespace eckit::geo::range; + + + { + std::vector ref{59.44440828916676, + 19.87571914744090, + -19.87571914744090, + -59.44440828916676}; + + auto global = Gaussian(2); + EXPECT(global.size() == ref.size()); + + size_t i = 0; + for (const auto& test : global.values()) { + EXPECT_APPROX(test, ref[i++]); + } + + auto cropped = Gaussian(2, 50., -50., 1e-3); + EXPECT(cropped.size() == ref.size() - 2); + + i = 1; + for (const auto& test : cropped.values()) { + EXPECT_APPROX(test, ref[i++]); + } + + EXPECT(Gaussian(2, 59.444, -59.444, 1e-3).size() == 4); + EXPECT(Gaussian(2, 59.444, -59.444, 1e-6).size() == 2); + EXPECT(Gaussian(2, 59.444, -59.445, 1e-6).size() == 3); + + auto single = Gaussian(2, -59.444, -59.444, 1e-3); + EXPECT(single.size() == 1); + + EXPECT_APPROX(single.values().front(), ref.back()); + } + + + return 0; +} diff --git a/tests/geo/test_util.cc b/tests/geo/test_util.cc index 383df4315..11513d6ba 100644 --- a/tests/geo/test_util.cc +++ b/tests/geo/test_util.cc @@ -27,46 +27,6 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) { } -template -struct iterator_t { - X& cnt; - size_t pos; - - bool operator!=(const iterator_t& other) const { return &cnt != &other.cnt || pos != other.pos; } - - iterator_t& operator++() { - pos++; - return *this; - } - - iterator_t operator++(int) { - auto old = *this; - operator++(); - return old; - } - - typename X::value_type& operator*() { return cnt.at(pos); } - - const typename X::value_type& operator*() const { return cnt.at(pos); } -}; - - -class iterable_t : public std::vector { - using iterator = iterator_t; - using const_iterator = iterator_t; - -public: - using vector::vector; - - iterator begin() { return {*this, 0}; } - iterator end() { return {*this, this->size()}; } - const_iterator cbegin() const { return {*this, 0}; } - const_iterator cend() const { return {*this, this->size()}; } - const_iterator begin() const { return cbegin(); } - const_iterator end() const { return cend(); } -}; - - int main(int argc, char* argv[]) { using namespace eckit::geo::util; From c4da94455c2c12fef5ccfef61756e03e1b06f07b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 19 Sep 2023 16:00:15 +0100 Subject: [PATCH 326/737] eckit::geo --- src/eckit/geo/CMakeLists.txt | 6 +- src/eckit/geo/Range.h | 24 ++---- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 4 +- src/eckit/geo/grid/regular/RegularGaussian.cc | 8 +- src/eckit/geo/grid/unstructured/ORCA.cc | 8 +- src/eckit/geo/grid/unstructured/ORCA.h | 9 +-- src/eckit/geo/range/Gaussian.cc | 15 ++-- src/eckit/geo/range/GlobalRegular.h | 79 ------------------- src/eckit/geo/range/LocalRegular.cc | 40 ---------- .../range/{GlobalRegular.cc => Regular.cc} | 24 ++++-- .../geo/range/{LocalRegular.h => Regular.h} | 7 +- src/eckit/geo/util.h | 7 +- src/eckit/geo/util/monotonic_crop.cc | 23 ++++-- tests/geo/test_range.cc | 3 +- 14 files changed, 76 insertions(+), 181 deletions(-) delete mode 100644 src/eckit/geo/range/GlobalRegular.h delete mode 100644 src/eckit/geo/range/LocalRegular.cc rename src/eckit/geo/range/{GlobalRegular.cc => Regular.cc} (57%) rename src/eckit/geo/range/{LocalRegular.h => Regular.h} (85%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 8c881c98c..fc4624c7f 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -88,10 +88,8 @@ list( APPEND eckit_geo_srcs projection/Rotation.h range/Gaussian.cc range/Gaussian.h - range/GlobalRegular.cc - range/GlobalRegular.h - range/LocalRegular.cc - range/LocalRegular.h + range/Regular.cc + range/Regular.h util.cc util.h util/arange.cc diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 9345ddcfe..07e90b3fd 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -15,9 +15,6 @@ #include #include -#include "eckit/memory/Builder.h" -#include "eckit/memory/Factory.h" - namespace eckit { class Configuration; @@ -30,17 +27,15 @@ namespace eckit::geo { class Range : protected std::vector { public: // -- Types - - using builder_t = BuilderT1; - using ARG1 = const Configuration&; + // None // -- Exceptions // None // -- Constructors - Range(const Range&) = default; - Range(Range&&) = default; + Range(const Range&) = delete; + Range(Range&&) = delete; // -- Destructor @@ -51,12 +46,11 @@ class Range : protected std::vector { // -- Operators - Range& operator=(const Range&) = default; - Range& operator=(Range&&) = default; + Range& operator=(const Range&) = delete; + Range& operator=(Range&&) = delete; // -- Methods - - static std::string className() { return "range"; } + // None using vector::empty; @@ -119,10 +113,4 @@ class Range : protected std::vector { }; -// using RangeFactory = Factory; - -// template -// using RangeBuilder = ConcreteBuilderT1; - - } // namespace eckit::geo diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 903d1dd29..5c7230467 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -16,7 +16,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/iterator/Reduced.h" #include "eckit/geo/range/Gaussian.h" -#include "eckit/geo/range/GlobalRegular.h" +#include "eckit/geo/range/Regular.h" #include "eckit/utils/Translator.h" @@ -68,7 +68,7 @@ std::vector ReducedGaussian::longitudes(size_t j) const { auto Ni = ni(j); if (!x_ || x_->size() != Ni) { const_cast&>(x_).reset( - new range::GlobalRegular(Ni, bbox().west(), bbox().east())); + new range::Regular(Ni, bbox().west(), bbox().east())); } return x_->values(); diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index b78468439..ce1c89ce7 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -15,18 +15,18 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/range/Gaussian.h" -#include "eckit/geo/range/LocalRegular.h" +#include "eckit/geo/range/Regular.h" #include "eckit/utils/Translator.h" namespace eckit::geo::grid::regular { -// LocalRegular(size_t n, double a, double b, bool endpoint, double precision = 0.); +// Regular(size_t n, double a, double b, bool endpoint, double precision = 0.); RegularGaussian::RegularGaussian(const Configuration& config) : Regular(config), ni_(config.getUnsigned("ni", config.getUnsigned("ni"))), - x_(new range::LocalRegular(ni_, config.getDouble("west", 0.), config.getDouble("east", 360.), true /*FIXME*/)), + x_(new range::Regular(ni_, config.getDouble("west", 0.), config.getDouble("east", 360.), true /*FIXME*/)), y_(new range::Gaussian(config.getUnsigned("N"), config.getDouble("north", 90.), config.getDouble("south", -90.))) { @@ -37,7 +37,7 @@ RegularGaussian::RegularGaussian(const Configuration& config) : RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : Regular(bbox), ni_(4 * N), - x_(new range::LocalRegular(ni_, bbox.west(), bbox.east(), true /*FIXME*/)), + x_(new range::Regular(ni_, bbox.west(), bbox.east(), true /*FIXME*/)), y_(new range::Gaussian(N, bbox.west(), bbox.east())) { } diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index 401401208..41ca5a70b 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -190,14 +190,16 @@ void ORCA::check(const Configuration& config) { size_t ORCA::write(const PathName& p, const std::string& compression) { codec::RecordWriter record; + codec::ArrayShape shape{static_cast(dimensions_[0]), static_cast(dimensions_[1])}; + record.compression(compression); record.set("version", 0); record.set("dimensions", dimensions_); record.set("halo", halo_); record.set("pivot", pivot_); - record.set("longitude", codec::ArrayReference(longitudes_.data(), dimensions_)); - record.set("latitude", codec::ArrayReference(latitudes_.data(), dimensions_)); - record.set("flags", codec::ArrayReference(flags_.data(), dimensions_)); + record.set("longitude", codec::ArrayReference(longitudes_.data(), shape)); + record.set("latitude", codec::ArrayReference(latitudes_.data(), shape)); + record.set("flags", codec::ArrayReference(flags_.data(), shape)); return record.write(p); } diff --git a/src/eckit/geo/grid/unstructured/ORCA.h b/src/eckit/geo/grid/unstructured/ORCA.h index aff86a991..1e79d05da 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.h +++ b/src/eckit/geo/grid/unstructured/ORCA.h @@ -48,8 +48,7 @@ class ORCA final : public Unstructured { explicit ORCA(const Configuration&); // -- Destructor - - ~ORCA() override = default; + // None // -- Convertors // None @@ -88,11 +87,11 @@ class ORCA final : public Unstructured { const std::vector& latitudes() const override { return latitudes_; } // -- Class members - - static Configuration* config(const std::string& name); + // None // -- Class methods - // None + + static Configuration* config(const std::string& name); private: // -- Members diff --git a/src/eckit/geo/range/Gaussian.cc b/src/eckit/geo/range/Gaussian.cc index dc3d8fca0..b88196259 100644 --- a/src/eckit/geo/range/Gaussian.cc +++ b/src/eckit/geo/range/Gaussian.cc @@ -34,12 +34,17 @@ Gaussian::Gaussian(size_t N, double a, double b, double precision) : // pre-calculate on cropping auto [min, max] = std::minmax(a_, b_); if (!types::is_approximately_equal(min, -90., eps_) || !types::is_approximately_equal(max, 90., eps_)) { - auto [from, to] = util::monotonic_crop(values(), min, max, precision); - if (to != end()) { - erase(to); + auto& v = values(); + + auto [from, to] = util::monotonic_crop(v, min, max, precision); + auto f = v.begin() + from; + auto t = v.begin() + to; + + if (t != end()) { + erase(t); } - if (from != begin()) { - erase(begin(), from); + if (f != begin()) { + erase(begin(), f); } ASSERT(!empty()); } diff --git a/src/eckit/geo/range/GlobalRegular.h b/src/eckit/geo/range/GlobalRegular.h deleted file mode 100644 index 9043240f3..000000000 --- a/src/eckit/geo/range/GlobalRegular.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Range.h" - - -namespace eckit::geo::range { - - -class GlobalRegular final : public Range { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - GlobalRegular(size_t n, double a, double b, double precision = 0.); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - const std::vector& values() const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - const double a_; - const double b_; - const double precision_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/LocalRegular.cc b/src/eckit/geo/range/LocalRegular.cc deleted file mode 100644 index dc78b8c56..000000000 --- a/src/eckit/geo/range/LocalRegular.cc +++ /dev/null @@ -1,40 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/range/LocalRegular.h" - -#include "eckit/geo/util.h" - - -namespace eckit::geo::range { - - -LocalRegular::LocalRegular(size_t n, double a, double b, bool endpoint, double precision) : - Range(n), - a_(a), - b_(b), - endpoint_(endpoint), - precision_(precision) { -} - - -const std::vector& LocalRegular::values() const { - if (empty()) { - auto& v = const_cast&>(valuesVector()); - v = util::linspace(a_, b_, size(), endpoint_); - } - - return *this; -} - - -} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/GlobalRegular.cc b/src/eckit/geo/range/Regular.cc similarity index 57% rename from src/eckit/geo/range/GlobalRegular.cc rename to src/eckit/geo/range/Regular.cc index 7571bcaa2..d09018644 100644 --- a/src/eckit/geo/range/GlobalRegular.cc +++ b/src/eckit/geo/range/Regular.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/range/GlobalRegular.h" +#include "eckit/geo/range/Regular.h" #include "eckit/geo/util.h" @@ -18,22 +18,32 @@ namespace eckit::geo::range { -GlobalRegular::GlobalRegular(size_t n, double a, double b, double precision) : +Regular::Regular(size_t n, double a, double b, double precision) : Range(n), a_(a), b_(b), - precision_(precision) { + precision_(precision), + endpoint_(false) { } -const std::vector& GlobalRegular::values() const { +Regular::Regular(size_t n, double a, double b, bool endpoint, double precision) : + Range(n), + a_(a), + b_(b), + precision_(precision), + endpoint_(endpoint) { +} + + +const std::vector& Regular::values() const { if (empty()) { auto& v = const_cast&>(valuesVector()); v = util::linspace(0., 360., size(), false); - auto mm = util::monotonic_crop(v, a_, b_, 1e-3); - v.erase(mm.second, v.end()); - v.erase(v.begin(), mm.first); + auto [from, to] = util::monotonic_crop(v, a_, b_, 1e-3); + v.erase(v.begin() + to, v.end()); + v.erase(v.begin(), v.begin() + from); } return *this; diff --git a/src/eckit/geo/range/LocalRegular.h b/src/eckit/geo/range/Regular.h similarity index 85% rename from src/eckit/geo/range/LocalRegular.h rename to src/eckit/geo/range/Regular.h index 9b6e48087..f3cc7276c 100644 --- a/src/eckit/geo/range/LocalRegular.h +++ b/src/eckit/geo/range/Regular.h @@ -18,7 +18,7 @@ namespace eckit::geo::range { -class LocalRegular final : public Range { +class Regular final : public Range { public: // -- Types // None @@ -28,7 +28,8 @@ class LocalRegular final : public Range { // -- Constructors - LocalRegular(size_t n, double a, double b, bool endpoint, double precision = 0.); + explicit Regular(size_t n, double a, double b, double precision = 0.); + explicit Regular(size_t n, double a, double b, bool endpoint, double precision = 0.); // -- Destructor // None @@ -57,8 +58,8 @@ class LocalRegular final : public Range { const double a_; const double b_; - const bool endpoint_; const double precision_; + const bool endpoint_; // -- Methods // None diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index e9586d6c9..79b4bf61c 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -22,7 +23,8 @@ namespace eckit::geo { -using pl_type = std::vector; +using difference_type = std::make_signed_t; +using pl_type = std::vector; namespace util { @@ -56,8 +58,7 @@ std::vector gaussian_latitudes(size_t N, bool increasing); std::vector linspace(double start, double stop, size_t num, bool endpoint); -std::pair::const_iterator, std::vector::const_iterator> monotonic_crop( - const std::vector&, double min, double max, double eps); +std::pair monotonic_crop(const std::vector&, double min, double max, double eps); const pl_type& reduced_classical_pl(size_t N); diff --git a/src/eckit/geo/util/monotonic_crop.cc b/src/eckit/geo/util/monotonic_crop.cc index d636a5d14..16c906b82 100644 --- a/src/eckit/geo/util/monotonic_crop.cc +++ b/src/eckit/geo/util/monotonic_crop.cc @@ -11,6 +11,8 @@ #include +#include +#include #include #include @@ -21,21 +23,28 @@ namespace eckit::geo::util { -std::pair::const_iterator, std::vector::const_iterator> monotonic_crop( +using difference_type = std::make_signed_t; + + +std::pair monotonic_crop( const std::vector& values, double min, double max, double eps) { if (values.empty() || min > max) { return {}; } + auto b = values.begin(); + auto e = values.end(); // monotonically increasing const auto increasing = values.size() == 1 || values.front() < values.back(); if (increasing) { - ASSERT(std::is_sorted(values.begin(), values.end())); + ASSERT(std::is_sorted(b, e)); auto lt = [eps](double a, double b) { return a < b && (0. == eps || !types::is_approximately_equal(a, b, eps)); }; - return {std::lower_bound(values.begin(), values.end(), min, lt), - std::upper_bound(values.begin(), values.end(), max, lt)}; + + return { + std::distance(b, std::lower_bound(b, e, min, lt)), + std::distance(b, std::upper_bound(b, e, max, lt))}; } @@ -43,8 +52,10 @@ std::pair::const_iterator, std::vector::const_iterat ASSERT(std::is_sorted(values.rbegin(), values.rend())); auto gt = [eps](double a, double b) { return a > b && (0. == eps || !types::is_approximately_equal(a, b, eps)); }; - return {std::lower_bound(values.begin(), values.end(), max, gt), - std::upper_bound(values.begin(), values.end(), min, gt)}; + + return { + std::distance(b, std::lower_bound(b, e, max, gt)), + std::distance(b, std::upper_bound(b, e, min, gt))}; } diff --git a/tests/geo/test_range.cc b/tests/geo/test_range.cc index fbb65be33..630b7db56 100644 --- a/tests/geo/test_range.cc +++ b/tests/geo/test_range.cc @@ -14,8 +14,7 @@ #include #include "eckit/geo/range/Gaussian.h" -#include "eckit/geo/range/GlobalRegular.h" -#include "eckit/geo/range/LocalRegular.h" +#include "eckit/geo/range/Regular.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" From 422888e364d7cd0c72ef1485bf1ffc106a801e13 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 28 Sep 2023 10:52:01 +0100 Subject: [PATCH 327/737] clang-format 18, fixes to the configuration file --- .clang-format | 172 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 150 insertions(+), 22 deletions(-) diff --git a/.clang-format b/.clang-format index 053c7ef93..cf6d896d8 100644 --- a/.clang-format +++ b/.clang-format @@ -2,27 +2,66 @@ Language: Cpp AccessModifierOffset: -4 AlignAfterOpenBracket: Align -AlignConsecutiveAssignments: true -AlignConsecutiveDeclarations: false +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveMacros: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveShortCaseStatements: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCaseColons: false AlignEscapedNewlines: Left -AlignOperands: true -AlignTrailingComments: true +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: true +AllowBreakBeforeNoexceptSpecifier: Never +AllowShortBlocksOnASingleLine: Always AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: true AllowShortFunctionsOnASingleLine: Inline -AllowShortIfStatementsOnASingleLine: false +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true -AlwaysBreakTemplateDeclarations: true -BinPackArguments: true -BinPackParameters: true +AlwaysBreakTemplateDeclarations: Yes +AttributeMacros: + - __capability +BinPackArguments: false +BinPackParameters: false +BitFieldColonSpacing: Both BraceWrapping: + AfterCaseLabel: false AfterClass: false - AfterControlStatement: false + AfterControlStatement: Never AfterEnum: true + AfterExternBlock: false AfterFunction: false AfterNamespace: false AfterObjCDeclaration: false @@ -30,79 +69,168 @@ BraceWrapping: AfterUnion: false BeforeCatch: true BeforeElse: true + BeforeLambdaBody: false + BeforeWhile: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true +BreakAfterAttributes: Never +BreakAfterJavaFieldAnnotations: false +BreakArrays: true BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always BreakBeforeBraces: Custom -BreakBeforeInheritanceComma: false +BreakBeforeInlineASMColon: OnlyMultiline BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: AfterColon -BreakAfterJavaFieldAnnotations: false +BreakInheritanceList: BeforeColon BreakStringLiterals: true ColumnLimit: 120 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve IncludeCategories: - Regex: '^<.*\.h>' Priority: 1 + SortPriority: 0 + CaseSensitive: false - Regex: '^<.*' Priority: 2 + SortPriority: 0 + CaseSensitive: false - Regex: '.*' Priority: 3 + SortPriority: 0 + CaseSensitive: false IncludeIsMainRegex: '([-_](test|unittest))?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseBlocks: false IndentCaseLabels: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true IndentWidth: 4 IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: false +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: true +KeepEmptyLinesAtEOF: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 2 NamespaceIndentation: None +ObjCBinPackProtocolList: Auto ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: false +PackConstructorInitializers: NextLineOnly PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Leave +ReferenceAlignment: Pointer ReflowComments: true -SortIncludes: true -SortUsingDeclarations: true +RemoveBracesLLVM: false +RemoveParentheses: Leave +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeJsonColon: false SpaceBeforeParens: ControlStatements -SpaceInEmptyParentheses: false +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false SpacesBeforeTrailingComments: 2 -SpacesInAngles: false +SpacesInAngles: Never SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParens: Never +SpacesInParensOptions: + InCStyleCasts: false + InConditionalStatements: false + InEmptyParentheses: false + Other: false SpacesInSquareBrackets: false Standard: Auto +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION TabWidth: 4 UseTab: Never -BreakBeforeBinaryOperators: All -ColumnLimit: 0 +VerilogBreakBetweenInstancePorts: true +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE ... + From 4134105fe1eff321de3bdfdec8994bc29d46128c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 28 Sep 2023 11:10:57 +0100 Subject: [PATCH 328/737] clang-format --- src/eckit/geo/Configurator.h | 9 +- src/eckit/geo/Domain.cc | 6 +- src/eckit/geo/EllipsoidOfRevolution.cc | 7 +- src/eckit/geo/EllipsoidOfRevolution.h | 7 +- src/eckit/geo/GreatCircle.cc | 3 +- src/eckit/geo/Grid.h | 4 +- src/eckit/geo/GridConfig.cc | 26 +- src/eckit/geo/LibEcKitGeo.cc | 9 +- src/eckit/geo/Point3.cc | 6 +- src/eckit/geo/Point3.h | 3 +- src/eckit/geo/Range.cc | 3 +- src/eckit/geo/Range.h | 4 +- src/eckit/geo/Search.h | 8 +- src/eckit/geo/Sphere.cc | 18 +- src/eckit/geo/Sphere.h | 6 +- src/eckit/geo/SphereT.h | 9 +- src/eckit/geo/area/BoundingBox.cc | 12 +- src/eckit/geo/grid/Reduced.cc | 6 +- src/eckit/geo/grid/Regular.cc | 6 +- src/eckit/geo/grid/Unstructured.cc | 3 +- src/eckit/geo/grid/reduced/HEALPix.cc | 18 +- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 20 +- src/eckit/geo/grid/reduced/ReducedLatLon.cc | 3 +- src/eckit/geo/grid/regular/IrregularLatLon.cc | 3 +- src/eckit/geo/grid/regular/RegularGaussian.cc | 12 +- src/eckit/geo/grid/regular/RegularLatLon.cc | 6 +- src/eckit/geo/grid/unstructured/ORCA.cc | 3 +- src/eckit/geo/polygon/LonLatPolygon.cc | 12 +- src/eckit/geo/projection/LonLatToXYZ.cc | 15 +- src/eckit/geo/projection/Rotation.cc | 27 +- src/eckit/geo/range/Gaussian.cc | 6 +- src/eckit/geo/range/Regular.cc | 14 +- src/eckit/geo/util.h | 10 +- src/eckit/geo/util/arange.cc | 7 +- src/eckit/geo/util/gaussian_latitudes.cc | 7 +- src/eckit/geo/util/linspace.cc | 5 +- src/eckit/geo/util/monotonic_crop.cc | 18 +- src/eckit/geo/util/reduced_classical_pl.cc | 669 +++++++++--------- tests/geo/test_great_circle.cc | 22 +- tests/geo/test_grid.cc | 9 +- tests/geo/test_polygon.cc | 19 +- tests/geo/test_projection.cc | 22 +- tests/geo/test_range.cc | 5 +- 43 files changed, 548 insertions(+), 539 deletions(-) diff --git a/src/eckit/geo/Configurator.h b/src/eckit/geo/Configurator.h index dc526094b..3347f94e1 100644 --- a/src/eckit/geo/Configurator.h +++ b/src/eckit/geo/Configurator.h @@ -249,9 +249,7 @@ class ConcreteConfigurationGeneratorT0 final : public ConfigurationGeneratorT0 { // -- Destructor - ~ConcreteConfigurationGeneratorT0() override { - Configurator::instance().unregist(key_); - } + ~ConcreteConfigurationGeneratorT0() override { Configurator::instance().unregist(key_); } // -- Operators @@ -332,7 +330,10 @@ class ConcreteConfigurationGeneratorT2 final : public ConfigurationGeneratorT2::arg1_t p1, typename ConfigurationGeneratorT1::arg2_t p2) const override { return T::config(p1, p2); } + Configuration* config(typename ConfigurationGeneratorT1::arg1_t p1, + typename ConfigurationGeneratorT1::arg2_t p2) const override { + return T::config(p1, p2); + } private: // -- Members diff --git a/src/eckit/geo/Domain.cc b/src/eckit/geo/Domain.cc index 9cbf16653..bf4af3580 100644 --- a/src/eckit/geo/Domain.cc +++ b/src/eckit/geo/Domain.cc @@ -72,11 +72,13 @@ bool Domain::contains(const Domain& other) const { } // check for West/East range (if non-periodic), then other's corners - if (east_ - west_ < other.east_ - other.west_ || east_ < PointLonLat::normalise_angle_to_minimum(other.east_, west_)) { + if (east_ - west_ < other.east_ - other.west_ || + east_ < PointLonLat::normalise_angle_to_minimum(other.east_, west_)) { return false; } - return contains(other.north_, other.west_) && contains(other.north_, other.east_) && contains(other.south_, other.west_) && contains(other.south_, other.east_); + return contains(other.north_, other.west_) && contains(other.north_, other.east_) && + contains(other.south_, other.west_) && contains(other.south_, other.east_); } diff --git a/src/eckit/geo/EllipsoidOfRevolution.cc b/src/eckit/geo/EllipsoidOfRevolution.cc index 0da29eac5..807f24198 100644 --- a/src/eckit/geo/EllipsoidOfRevolution.cc +++ b/src/eckit/geo/EllipsoidOfRevolution.cc @@ -24,11 +24,8 @@ namespace eckit::geo { //---------------------------------------------------------------------------------------------------------------------- -Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, - double b, - const PointLonLat& P, - double height, - bool normalise_angle) { +Point3 EllipsoidOfRevolution::convertSphericalToCartesian( + double a, double b, const PointLonLat& P, double height, bool normalise_angle) { ASSERT(a > 0.); ASSERT(b > 0.); diff --git a/src/eckit/geo/EllipsoidOfRevolution.h b/src/eckit/geo/EllipsoidOfRevolution.h index 798bd40bd..e0290f4d3 100644 --- a/src/eckit/geo/EllipsoidOfRevolution.h +++ b/src/eckit/geo/EllipsoidOfRevolution.h @@ -24,11 +24,8 @@ class PointLonLat; struct EllipsoidOfRevolution { // Convert elliptic coordinates to Cartesian - static Point3 convertSphericalToCartesian(double a, - double b, - const PointLonLat&, - double height = 0., - bool normalise_angle = false); + static Point3 convertSphericalToCartesian( + double a, double b, const PointLonLat&, double height = 0., bool normalise_angle = false); }; //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geo/GreatCircle.cc b/src/eckit/geo/GreatCircle.cc index 4aa433f12..b99f291d6 100644 --- a/src/eckit/geo/GreatCircle.cc +++ b/src/eckit/geo/GreatCircle.cc @@ -67,7 +67,8 @@ std::vector GreatCircle::latitude(double lon) const { const double lambda2p = degrees_to_radians * (lon - B_.lon); const double lambda = degrees_to_radians * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, -180.); - double lat = std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); + double lat = + std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); return {radians_to_degrees * lat}; } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index bf289fc17..6aa77c013 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -49,7 +49,9 @@ class Grid { struct Iterator final : std::unique_ptr { explicit Iterator(geo::Iterator* it) : - unique_ptr(it) { ASSERT(unique_ptr::operator bool()); } + unique_ptr(it) { + ASSERT(unique_ptr::operator bool()); + } using diff_t = unique_ptr::element_type::diff_t; Iterator(const Iterator&) = delete; diff --git a/src/eckit/geo/GridConfig.cc b/src/eckit/geo/GridConfig.cc index a831a95de..b90790999 100644 --- a/src/eckit/geo/GridConfig.cc +++ b/src/eckit/geo/GridConfig.cc @@ -44,12 +44,14 @@ void set_config_value(MappedConfiguration& config, const std::string& key, const auto list_of = [](const ValueList& list, auto pred) { return std::all_of(list.begin(), list.end(), pred); }; - auto val = value.isList() && list_of(value, [](const Value& v) { return v.isDouble(); }) ? __from_value>(value) - : value.isList() && list_of(value, [](const Value& v) { return v.isNumber(); }) ? __from_value>(value) - : value.isList() ? __from_value>(value) - : value.isDouble() ? __from_value(value) - : value.isNumber() ? __from_value(value) - : __from_value(value); + auto val = value.isList() && list_of(value, [](const Value& v) { return v.isDouble(); }) + ? __from_value>(value) + : value.isList() && list_of(value, [](const Value& v) { return v.isNumber(); }) + ? __from_value>(value) + : value.isList() ? __from_value>(value) + : value.isDouble() ? __from_value(value) + : value.isNumber() ? __from_value(value) + : __from_value(value); std::visit([&](const auto& val) { config.set(key, val); }, val); } @@ -87,7 +89,9 @@ GridConfig::GridConfig(const PathName& path) { struct ConfigurationFromName final : GridConfigurationName::configurator_t { explicit ConfigurationFromName(MappedConfiguration* config) : config_(config) {} - Configuration* config(GridConfigurationName::configurator_t::arg1_t) const override { return new MappedConfiguration(*config_); } + Configuration* config(GridConfigurationName::configurator_t::arg1_t) const override { + return new MappedConfiguration(*config_); + } std::unique_ptr config_; }; @@ -100,7 +104,9 @@ GridConfig::GridConfig(const PathName& path) { if (key == "grid_uids") { for (ValueMap m : static_cast(kv.second)) { ASSERT(m.size() == 1); - GridConfigurationUID::instance().regist(m.begin()->first.as(), new ConfigurationFromUID(config_from_value_map(m.begin()->second))); + GridConfigurationUID::instance().regist( + m.begin()->first.as(), + new ConfigurationFromUID(config_from_value_map(m.begin()->second))); } continue; } @@ -108,7 +114,9 @@ GridConfig::GridConfig(const PathName& path) { if (key == "grid_names") { for (ValueMap m : static_cast(kv.second)) { ASSERT(m.size() == 1); - GridConfigurationName::instance().regist(m.begin()->first.as(), new ConfigurationFromName(config_from_value_map(m.begin()->second))); + GridConfigurationName::instance().regist( + m.begin()->first.as(), + new ConfigurationFromName(config_from_value_map(m.begin()->second))); } continue; } diff --git a/src/eckit/geo/LibEcKitGeo.cc b/src/eckit/geo/LibEcKitGeo.cc index e40364dcb..72bca2286 100644 --- a/src/eckit/geo/LibEcKitGeo.cc +++ b/src/eckit/geo/LibEcKitGeo.cc @@ -35,19 +35,22 @@ LibEcKitGeo& LibEcKitGeo::instance() { PathName LibEcKitGeo::configFileGrid() { - static const PathName path{LibResource("eckit-geo-grid;$ECKIT_GEO_GRID", "~eckit/etc/eckit/geo/grid.yaml")}; + static const PathName path{ + LibResource("eckit-geo-grid;$ECKIT_GEO_GRID", "~eckit/etc/eckit/geo/grid.yaml")}; return path; } bool LibEcKitGeo::caching() { - static const bool yes{LibResource("eckit-geo-caching;$ECKIT_GEO_CACHING", eckit_HAVE_GEO_CACHING != 0 ? true : false)}; + static const bool yes{LibResource("eckit-geo-caching;$ECKIT_GEO_CACHING", + eckit_HAVE_GEO_CACHING != 0 ? true : false)}; return yes; } std::string LibEcKitGeo::cacheDir() { - static std::string path = PathName{LibResource("eckit-geo-cache-path;$ECKIT_GEO_CACHE_PATH", eckit_GEO_CACHE_PATH)}; + static std::string path = PathName{ + LibResource("eckit-geo-cache-path;$ECKIT_GEO_CACHE_PATH", eckit_GEO_CACHE_PATH)}; return path; } diff --git a/src/eckit/geo/Point3.cc b/src/eckit/geo/Point3.cc index 9d3951b49..b48eada4c 100644 --- a/src/eckit/geo/Point3.cc +++ b/src/eckit/geo/Point3.cc @@ -20,11 +20,11 @@ namespace eckit::geo { bool points_equal(const Point3& a, const Point3& b) { auto eps = 1e-6; - return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps) && types::is_approximately_equal(a.Z, b.Z, eps); + return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps) && + types::is_approximately_equal(a.Z, b.Z, eps); } -bool operator<(const Point3& a, const Point3& b) { -} +bool operator<(const Point3& a, const Point3& b) {} //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/geo/Point3.h b/src/eckit/geo/Point3.h index 191b56b36..21bf5f375 100644 --- a/src/eckit/geo/Point3.h +++ b/src/eckit/geo/Point3.h @@ -79,7 +79,8 @@ class Point3 : public KPoint<3> { } static Point3 cross(const Point3& p1, const Point3& p2) { - return Point3(p1[YY] * p2[ZZ] - p1[ZZ] * p2[YY], p1[ZZ] * p2[XX] - p1[XX] * p2[ZZ], + return Point3(p1[YY] * p2[ZZ] - p1[ZZ] * p2[YY], + p1[ZZ] * p2[XX] - p1[XX] * p2[ZZ], p1[XX] * p2[YY] - p1[YY] * p2[XX]); } }; diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 10277273c..3912ce29a 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -20,8 +20,7 @@ namespace eckit::geo { Range::Range(const Configuration& config) : - Range(config.getUnsigned("n")) { -} + Range(config.getUnsigned("n")) {} Range::Range(size_t n) : diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 07e90b3fd..82c9a2882 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -78,9 +78,7 @@ class Range : protected std::vector { // -- Methods - virtual const std::vector& valuesVector() const { - return *this; - } + virtual const std::vector& valuesVector() const { return *this; } // -- Overridden methods // None diff --git a/src/eckit/geo/Search.h b/src/eckit/geo/Search.h index f506d73a2..e30434fd1 100644 --- a/src/eckit/geo/Search.h +++ b/src/eckit/geo/Search.h @@ -44,9 +44,7 @@ struct SearchLonLat : Search3 { using Search3::Search3; - void insert(const SearchLonLat::Value& value) { - Search3::insert({to_cartesian(value.point()), value.payload()}); - } + void insert(const SearchLonLat::Value& value) { Search3::insert({to_cartesian(value.point()), value.payload()}); } template void build(const Container& c) { @@ -78,9 +76,7 @@ struct SearchLonLat : Search3 { } private: - static Search3::Point to_cartesian(const Point& p) { - return UnitSphere::convertSphericalToCartesian(p); - } + static Search3::Point to_cartesian(const Point& p) { return UnitSphere::convertSphericalToCartesian(p); } }; diff --git a/src/eckit/geo/Sphere.cc b/src/eckit/geo/Sphere.cc index eb7d93425..1961933d5 100644 --- a/src/eckit/geo/Sphere.cc +++ b/src/eckit/geo/Sphere.cc @@ -79,8 +79,9 @@ double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { const double cos_lambda = cos(lambda); const double sin_lambda = sin(lambda); - const double angle = std::atan2(std::sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), - sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); + const double angle = std::atan2( + std::sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), + sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); if (is_approximately_equal(angle, 0.)) { return 0.; @@ -127,10 +128,8 @@ double Sphere::area(double radius, const PointLonLat& WestNorth, const PointLonL // Set longitude fraction double W = WestNorth.lon; double E = PointLonLat::normalise_angle_to_minimum(EastSouth.lon, W); - double longitude_range(is_approximately_equal(W, E) - && !is_approximately_equal(EastSouth.lon, WestNorth.lon) - ? 360. - : E - W); + double longitude_range( + is_approximately_equal(W, E) && !is_approximately_equal(EastSouth.lon, WestNorth.lon) ? 360. : E - W); ASSERT(longitude_range <= 360.); double longitude_fraction = longitude_range / 360.; @@ -146,9 +145,7 @@ double Sphere::area(double radius, const PointLonLat& WestNorth, const PointLonL return area(radius) * latitude_fraction * longitude_fraction; } -double Sphere::greatCircleLatitudeGivenLongitude(const PointLonLat& A, - const PointLonLat& B, - double Clon) { +double Sphere::greatCircleLatitudeGivenLongitude(const PointLonLat& A, const PointLonLat& B, double Clon) { GreatCircle gc(A, B); auto lat = gc.latitude(Clon); return lat.size() == 1 ? lat[0] : std::numeric_limits::signaling_NaN(); @@ -190,8 +187,7 @@ Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, const auto sin_phi = std::sin(phi); const auto cos_phi = std::sqrt(1. - sin_phi * sin_phi); const auto sin_lambda = std::abs(P.lon) < 180. ? std::sin(lambda) : 0.; - const auto cos_lambda = std::abs(P.lon) > 90. ? std::cos(lambda) - : std::sqrt(1. - sin_lambda * sin_lambda); + const auto cos_lambda = std::abs(P.lon) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); return {(radius + height) * cos_phi * cos_lambda, (radius + height) * cos_phi * sin_lambda, diff --git a/src/eckit/geo/Sphere.h b/src/eckit/geo/Sphere.h index cd6d75724..e144a205b 100644 --- a/src/eckit/geo/Sphere.h +++ b/src/eckit/geo/Sphere.h @@ -23,8 +23,7 @@ class PointLonLat; struct Sphere { /// Great-circle central angle between two points in radians - static double centralAngle(const PointLonLat&, - const PointLonLat&); + static double centralAngle(const PointLonLat&, const PointLonLat&); /// Great-circle central angle between two points (Cartesian coordinates) in radians static double centralAngle(double radius, const Point3&, const Point3&); @@ -45,7 +44,8 @@ struct Sphere { static double greatCircleLatitudeGivenLongitude(const PointLonLat&, const PointLonLat&, double lon); // Great-circle intermediate longitude(s) provided two circle points and intermediate latitude in degrees - static void greatCircleLongitudeGivenLatitude(const PointLonLat&, const PointLonLat&, double lat, double& lon1, double& lon2); + static void greatCircleLongitudeGivenLatitude( + const PointLonLat&, const PointLonLat&, double lat, double& lon1, double& lon2); // Convert spherical to Cartesian coordinates static Point3 convertSphericalToCartesian(double radius, diff --git a/src/eckit/geo/SphereT.h b/src/eckit/geo/SphereT.h index d638588dc..abb4f1cab 100644 --- a/src/eckit/geo/SphereT.h +++ b/src/eckit/geo/SphereT.h @@ -33,10 +33,7 @@ struct SphereT { inline static double radius() { return DATUM::radius(); } /// Great-circle central angle between two points in radians - inline static double centralAngle(const PointLonLat& A, - const PointLonLat& B) { - return Sphere::centralAngle(A, B); - } + inline static double centralAngle(const PointLonLat& A, const PointLonLat& B) { return Sphere::centralAngle(A, B); } /// Great-circle central angle between two points (Cartesian coordinates) in radians inline static double centralAngle(const Point3& A, const Point3& B) { @@ -65,8 +62,8 @@ struct SphereT { } // Great-circle intermediate longitude(s) provided two circle points and intermediate latitude in degrees - inline static void greatCircleLongitudeGivenLatitude(const PointLonLat& A, const PointLonLat& B, - double lat, double& lon1, double& lon2) { + inline static void greatCircleLongitudeGivenLatitude( + const PointLonLat& A, const PointLonLat& B, double lat, double& lon1, double& lon2) { return Sphere::greatCircleLongitudeGivenLatitude(A, B, lat, lon1, lon2); } diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 976e6db73..fc7780354 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -27,8 +27,10 @@ namespace eckit::geo::area { BoundingBox::BoundingBox(const Configuration& config) : - BoundingBox(config.getDouble("north", 90.), config.getDouble("west", 0.), config.getDouble("south", -90.), config.getDouble("east", 360.)) { -} + BoundingBox(config.getDouble("north", 90.), + config.getDouble("west", 0.), + config.getDouble("south", -90.), + config.getDouble("east", 360.)) {} BoundingBox::BoundingBox(double north, double west, double south, double east) : @@ -68,11 +70,13 @@ bool BoundingBox::contains(const BoundingBox& other) const { } // check for West/East range (if non-periodic), then other's corners - if (east_ - west_ < other.east_ - other.west_ || east_ < PointLonLat::normalise_angle_to_minimum(other.east_, west_)) { + if (east_ - west_ < other.east_ - other.west_ || + east_ < PointLonLat::normalise_angle_to_minimum(other.east_, west_)) { return false; } - return contains(other.north_, other.west_) && contains(other.north_, other.east_) && contains(other.south_, other.west_) && contains(other.south_, other.east_); + return contains(other.north_, other.west_) && contains(other.north_, other.east_) && + contains(other.south_, other.west_) && contains(other.south_, other.east_); } diff --git a/src/eckit/geo/grid/Reduced.cc b/src/eckit/geo/grid/Reduced.cc index a738fffa5..a5d6c97c3 100644 --- a/src/eckit/geo/grid/Reduced.cc +++ b/src/eckit/geo/grid/Reduced.cc @@ -24,13 +24,11 @@ size_t Reduced::size() const { Reduced::Reduced(const Configuration& config) : - Grid(config) { -} + Grid(config) {} Reduced::Reduced(const area::BoundingBox& bbox) : - Grid(bbox) { -} + Grid(bbox) {} const std::vector& Reduced::niacc() const { diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index 526bb6231..a011259e0 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -19,13 +19,11 @@ namespace eckit::geo::grid { Regular::Regular(const Configuration& config) : - Grid(config) { -} + Grid(config) {} Regular::Regular(const area::BoundingBox& bbox) : - Grid(bbox) { -} + Grid(bbox) {} } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc index de22d5745..240ceb54c 100644 --- a/src/eckit/geo/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -29,8 +29,7 @@ Grid::iterator Unstructured::cend() const { Unstructured::Unstructured(const Configuration& config) : - Grid(config) { -} + Grid(config) {} } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/reduced/HEALPix.cc b/src/eckit/geo/grid/reduced/HEALPix.cc index 32fc02347..252354539 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.cc +++ b/src/eckit/geo/grid/reduced/HEALPix.cc @@ -22,14 +22,14 @@ namespace eckit::geo::grid::reduced { static Ordering ordering_from_string(const std::string& str) { - return str == "ring" ? Ordering::healpix_ring : str == "nested" ? Ordering::healpix_nested - : throw AssertionFailed("HEALPix::Ordering", Here()); + return str == "ring" ? Ordering::healpix_ring + : str == "nested" ? Ordering::healpix_nested + : throw AssertionFailed("HEALPix::Ordering", Here()); } HEALPix::HEALPix(const Configuration& config) : - HEALPix(config.getUnsigned("Nside"), ordering_from_string(config.getString("orderingConvention", "ring"))) { -} + HEALPix(config.getUnsigned("Nside"), ordering_from_string(config.getString("orderingConvention", "ring"))) {} HEALPix::HEALPix(size_t Nside, Ordering ordering) : @@ -51,8 +51,7 @@ Grid::iterator HEALPix::cend() const { size_t HEALPix::ni(size_t j) const { ASSERT(j < nj()); - return j < N_ ? 4 * (j + 1) : j < 3 * N_ ? 4 * N_ - : ni(nj() - 1 - j); + return j < N_ ? 4 * (j + 1) : j < 3 * N_ ? 4 * N_ : ni(nj() - 1 - j); } @@ -102,7 +101,8 @@ const std::vector& HEALPix::latitudes() const { auto i = latitudes_.begin(); auto j = latitudes_.rbegin(); for (size_t ring = 1; ring < 2 * N_; ++ring, ++i, ++j) { - const auto f = ring < N_ ? 1. - static_cast(ring * ring) / (3 * static_cast(N_ * N_)) : 4. / 3. - 2 * static_cast(ring) / (3 * static_cast(N_)); + const auto f = ring < N_ ? 1. - static_cast(ring * ring) / (3 * static_cast(N_ * N_)) + : 4. / 3. - 2 * static_cast(ring) / (3 * static_cast(N_)); *i = 90. - util::radian_to_degree * std::acos(f); *j = -*i; @@ -121,7 +121,9 @@ std::vector HEALPix::longitudes(size_t j) const { const auto start = j < N_ || 3 * N_ - 1 < j || static_cast((j + N_) % 2) ? step / 2. : 0.; std::vector lons(Ni); - std::generate_n(lons.begin(), Ni, [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); + std::generate_n(lons.begin(), Ni, [start, step, n = 0ULL]() mutable { + return start + static_cast(n++) * step; + }); return lons; } diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 5c7230467..f4bc9d53a 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -24,16 +24,11 @@ namespace eckit::geo::grid::reduced { ReducedGaussian::ReducedGaussian(const Configuration& config) : - ReducedGaussian(config.getUnsigned("N"), config.getLongVector("pl"), - area::BoundingBox(config)) {} + ReducedGaussian(config.getUnsigned("N"), config.getLongVector("pl"), area::BoundingBox(config)) {} ReducedGaussian::ReducedGaussian(size_t N, const pl_type& pl, const area::BoundingBox& bbox) : - Reduced(bbox), - pl_(pl), - j_(0), - Nj_(N * 2), - y_(new range::Gaussian(N, bbox.north(), bbox.south())) { + Reduced(bbox), pl_(pl), j_(0), Nj_(N * 2), y_(new range::Gaussian(N, bbox.north(), bbox.south())) { ASSERT(y_); } @@ -67,8 +62,7 @@ const std::vector& ReducedGaussian::latitudes() const { std::vector ReducedGaussian::longitudes(size_t j) const { auto Ni = ni(j); if (!x_ || x_->size() != Ni) { - const_cast&>(x_).reset( - new range::Regular(Ni, bbox().west(), bbox().east())); + const_cast&>(x_).reset(new range::Regular(Ni, bbox().west(), bbox().east())); } return x_->values(); @@ -78,9 +72,7 @@ std::vector ReducedGaussian::longitudes(size_t j) const { struct ReducedGaussianClassical { static Configuration* config(const std::string& name) { auto N = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "reduced_gg"}, - {"N", N}, - {"pl", util::reduced_classical_pl(N)}}); + return new MappedConfiguration({{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_classical_pl(N)}}); } }; @@ -88,9 +80,7 @@ struct ReducedGaussianClassical { struct ReducedGaussianOctahedral { static Configuration* config(const std::string& name) { auto N = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "reduced_gg"}, - {"N", N}, - {"pl", util::reduced_octahedral_pl(N)}}); + return new MappedConfiguration({{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_octahedral_pl(N)}}); } }; diff --git a/src/eckit/geo/grid/reduced/ReducedLatLon.cc b/src/eckit/geo/grid/reduced/ReducedLatLon.cc index e09eb61c4..bc0411ec8 100644 --- a/src/eckit/geo/grid/reduced/ReducedLatLon.cc +++ b/src/eckit/geo/grid/reduced/ReducedLatLon.cc @@ -19,8 +19,7 @@ namespace eckit::geo::grid::reduced { ReducedLatLon::ReducedLatLon(const Configuration& config) : - Reduced(config) { -} + Reduced(config) {} Grid::iterator ReducedLatLon::cbegin() const { diff --git a/src/eckit/geo/grid/regular/IrregularLatLon.cc b/src/eckit/geo/grid/regular/IrregularLatLon.cc index e43d55e6f..011c74b54 100644 --- a/src/eckit/geo/grid/regular/IrregularLatLon.cc +++ b/src/eckit/geo/grid/regular/IrregularLatLon.cc @@ -19,8 +19,7 @@ namespace eckit::geo::grid::regular { IrregularLatLon::IrregularLatLon(const Configuration& config) : - Regular(config) { -} + Regular(config) {} Grid::iterator IrregularLatLon::cbegin() const { diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index ce1c89ce7..3480dc8f5 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -27,9 +27,7 @@ RegularGaussian::RegularGaussian(const Configuration& config) : Regular(config), ni_(config.getUnsigned("ni", config.getUnsigned("ni"))), x_(new range::Regular(ni_, config.getDouble("west", 0.), config.getDouble("east", 360.), true /*FIXME*/)), - y_(new range::Gaussian(config.getUnsigned("N"), - config.getDouble("north", 90.), - config.getDouble("south", -90.))) { + y_(new range::Gaussian(config.getUnsigned("N"), config.getDouble("north", 90.), config.getDouble("south", -90.))) { ASSERT(ni_ > 0); } @@ -38,8 +36,7 @@ RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : Regular(bbox), ni_(4 * N), x_(new range::Regular(ni_, bbox.west(), bbox.east(), true /*FIXME*/)), - y_(new range::Gaussian(N, bbox.west(), bbox.east())) { -} + y_(new range::Gaussian(N, bbox.west(), bbox.east())) {} Grid::iterator RegularGaussian::cbegin() const { @@ -54,10 +51,7 @@ Grid::iterator RegularGaussian::cend() const { Configuration* RegularGaussian::config(const std::string& name) { auto N = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "regular_gg"}, - {"N", N}, - {"Ni", 2 * N}, - {"Nj", 4 * N}}); + return new MappedConfiguration({{"type", "regular_gg"}, {"N", N}, {"Ni", 2 * N}, {"Nj", 4 * N}}); } diff --git a/src/eckit/geo/grid/regular/RegularLatLon.cc b/src/eckit/geo/grid/regular/RegularLatLon.cc index 5570c5da6..317d2f318 100644 --- a/src/eckit/geo/grid/regular/RegularLatLon.cc +++ b/src/eckit/geo/grid/regular/RegularLatLon.cc @@ -22,8 +22,7 @@ namespace eckit::geo::grid::regular { RegularLatLon::RegularLatLon(const Configuration& config) : - Regular(config) { -} + Regular(config) {} Grid::iterator RegularLatLon::cbegin() const { @@ -69,7 +68,8 @@ Configuration* RegularLatLon::config(const std::string& name) { auto d = Translator{}; std::vector increments{d(match[1]), d(match[4])}; - auto ni = 1; // detail::RegularIterator(Fraction(0), Fraction(360), Fraction(increments[0]), Fraction(0), Fraction(360)).n(); + auto ni = 1; // detail::RegularIterator(Fraction(0), Fraction(360), Fraction(increments[0]), Fraction(0), + // Fraction(360)).n(); auto nj = 1; // detail::RegularIterator(Fraction(-90), Fraction(90), Fraction(increments[1]), Fraction(0)).n(); return new MappedConfiguration({{"type", "regular_ll"}, diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index 41ca5a70b..b0cbafe92 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -98,7 +98,8 @@ ORCA::ORCA(const Configuration& config) : } PathName::rename(tmp, path); - Log::info() << "ORCA: download of " << Bytes(static_cast(length)) << " took " << timer.elapsed() << " s." << std::endl; + Log::info() << "ORCA: download of " << Bytes(static_cast(length)) << " took " << timer.elapsed() + << " s." << std::endl; } #endif diff --git a/src/eckit/geo/polygon/LonLatPolygon.cc b/src/eckit/geo/polygon/LonLatPolygon.cc index a39bad3ff..5ceb3c28b 100644 --- a/src/eckit/geo/polygon/LonLatPolygon.cc +++ b/src/eckit/geo/polygon/LonLatPolygon.cc @@ -38,14 +38,12 @@ inline double cross_product_analog(const Point2& A, const Point2& B, const Point } inline int on_direction(double a, double b, double c) { - return a <= b && b <= c ? 1 : c <= b && b <= a ? -1 - : 0; + return a <= b && b <= c ? 1 : c <= b && b <= a ? -1 : 0; }; inline int on_side(const Point2& P, const Point2& A, const Point2& B) { const auto p = cross_product_analog(P, A, B); - return is_approximately_equal(p, 0) ? 0 : p > 0 ? 1 - : -1; + return is_approximately_equal(p, 0) ? 0 : p > 0 ? 1 : -1; } } // namespace @@ -55,7 +53,8 @@ inline int on_side(const Point2& P, const Point2& A, const Point2& B) { LonLatPolygon::LonLatPolygon(const std::vector& points, bool includePoles) : container_type(points) { ASSERT(points.size() > 1); - ASSERT(is_approximately_equal(points.front()[LON], points.back()[LON]) && is_approximately_equal(points.front()[LAT], points.back()[LAT])); + ASSERT(is_approximately_equal(points.front()[LON], points.back()[LON]) && + is_approximately_equal(points.front()[LAT], points.back()[LAT])); if (points.size() > 2) { clear(); // assumes reserved size is kept @@ -143,7 +142,8 @@ bool LonLatPolygon::contains(const Point2& Plonlat, bool normalise_angle) const const auto& A = operator[](i - 1); const auto& B = operator[](i); - // check point-edge side and direction, testing if P is on|above|below (in latitude) of a A,B polygon edge, by: + // check point-edge side and direction, testing if P is on|above|below (in latitude) of a A,B polygon edge, + // by: // - intersecting "up" on forward crossing & P above edge, or // - intersecting "down" on backward crossing & P below edge const auto direction = on_direction(A[LAT], lat, B[LAT]); diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc index d7a4e7ec3..e0db54f83 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -34,12 +34,8 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { explicit LonLatToSphereXYZ(double R) : R_(R) {} - Point3 operator()(const PointLonLat& p) const override { - return S::convertSphericalToCartesian(R_, p, 0.); - } - PointLonLat operator()(const Point3& q) const override { - return S::convertCartesianToSpherical(R_, q); - } + Point3 operator()(const PointLonLat& p) const override { return S::convertSphericalToCartesian(R_, p, 0.); } + PointLonLat operator()(const Point3& q) const override { return S::convertCartesianToSpherical(R_, q); } }; struct LonLatToSpheroidXYZ final : Implementation { @@ -49,9 +45,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { explicit LonLatToSpheroidXYZ(double a, double b) : a_(a), b_(b) {} - Point3 operator()(const PointLonLat& p) const override { - return S::convertSphericalToCartesian(a_, b_, p, 0.); - } + Point3 operator()(const PointLonLat& p) const override { return S::convertSphericalToCartesian(a_, b_, p, 0.); } PointLonLat operator()(const Point3& q) const override { NOTIMP; } }; @@ -65,8 +59,7 @@ LonLatToXYZ::LonLatToXYZ(double R) : LonLatToXYZ::LonLatToXYZ(const Configuration& config) : - LonLatToXYZ(config.getDouble("a", config.getDouble("R", 1.)), - config.getDouble("b", config.getDouble("R", 1.))) {} + LonLatToXYZ(config.getDouble("a", config.getDouble("R", 1.)), config.getDouble("b", config.getDouble("R", 1.))) {} } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index cac28fba1..0b757957d 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -86,23 +86,34 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : // q = Rz Ry Ra p = [ cosφ sinφ ] [ cosϑ sinϑ ] [ cosα sinα ] p // [ -sinφ cosφ ] [ 1 ] [ -sinα cosα ] // [ 1 ] [ -sinϑ cosϑ ] [ 1 ] - fwd_ = std::make_unique(M{ca * cp * ct - sa * sp, sa * cp * ct + ca * sp, cp * st, // - -sa * cp - ca * ct * sp, ca * cp - sa * ct * sp, -sp * st, // - -ca * st, -sa * st, ct}); + fwd_ = std::make_unique(M{ca * cp * ct - sa * sp, + sa * cp * ct + ca * sp, + cp * st, // + -sa * cp - ca * ct * sp, + ca * cp - sa * ct * sp, + -sp * st, // + -ca * st, + -sa * st, + ct}); // Un-rotate (rotate by -φ, -ϑ, -α): // p = Ra Ry Rz q = [ cosα -sinα ] [ cosϑ -sinϑ ] [ cosφ -sinφ ] q // [ sinα cosα ] [ 1 ] [ sinφ cosφ ] // [ 1 ] [ sinϑ cosϑ ] [ 1 ] - inv_ = std::make_unique(M{ca * cp * ct - sa * sp, -sa * cp - ca * ct * sp, -ca * st, // - sa * cp * ct + ca * sp, ca * cp - sa * ct * sp, -sa * st, // - cp * st, -sp * st, ct}); + inv_ = std::make_unique(M{ca * cp * ct - sa * sp, + -sa * cp - ca * ct * sp, + -ca * st, // + sa * cp * ct + ca * sp, + ca * cp - sa * ct * sp, + -sa * st, // + cp * st, + -sp * st, + ct}); } Rotation::Rotation(const Configuration& config) : - Rotation(config.getDouble("south_pole_lon"), config.getDouble("south_pole_lat"), - config.getDouble("angle", 0)) {} + Rotation(config.getDouble("south_pole_lon"), config.getDouble("south_pole_lat"), config.getDouble("angle", 0)) {} } // namespace eckit::geo::projection diff --git a/src/eckit/geo/range/Gaussian.cc b/src/eckit/geo/range/Gaussian.cc index b88196259..66eb9832d 100644 --- a/src/eckit/geo/range/Gaussian.cc +++ b/src/eckit/geo/range/Gaussian.cc @@ -23,11 +23,7 @@ namespace eckit::geo::range { Gaussian::Gaussian(size_t N, double a, double b, double precision) : - Range(2 * N), - N_(N), - a_(a), - b_(b), - eps_(precision) { + Range(2 * N), N_(N), a_(a), b_(b), eps_(precision) { ASSERT(N > 0); ASSERT(eps_ >= 0.); diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc index d09018644..b2554db93 100644 --- a/src/eckit/geo/range/Regular.cc +++ b/src/eckit/geo/range/Regular.cc @@ -19,21 +19,11 @@ namespace eckit::geo::range { Regular::Regular(size_t n, double a, double b, double precision) : - Range(n), - a_(a), - b_(b), - precision_(precision), - endpoint_(false) { -} + Range(n), a_(a), b_(b), precision_(precision), endpoint_(false) {} Regular::Regular(size_t n, double a, double b, bool endpoint, double precision) : - Range(n), - a_(a), - b_(b), - precision_(precision), - endpoint_(endpoint) { -} + Range(n), a_(a), b_(b), precision_(precision), endpoint_(endpoint) {} const std::vector& Regular::values() const { diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index 79b4bf61c..224d518cf 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -39,8 +39,9 @@ pl_type pl_convert(const T& pl) { ASSERT(!pl.empty()); pl_type _pl(pl.size()); - std::transform(pl.begin(), pl.end(), _pl.begin(), - [](typename T::value_type p) { return static_cast(p); }); + std::transform(pl.begin(), pl.end(), _pl.begin(), [](typename T::value_type p) { + return static_cast(p); + }); return _pl; } @@ -58,7 +59,10 @@ std::vector gaussian_latitudes(size_t N, bool increasing); std::vector linspace(double start, double stop, size_t num, bool endpoint); -std::pair monotonic_crop(const std::vector&, double min, double max, double eps); +std::pair monotonic_crop(const std::vector&, + double min, + double max, + double eps); const pl_type& reduced_classical_pl(size_t N); diff --git a/src/eckit/geo/util/arange.cc b/src/eckit/geo/util/arange.cc index e7b0a0c9c..f83ee9201 100644 --- a/src/eckit/geo/util/arange.cc +++ b/src/eckit/geo/util/arange.cc @@ -19,7 +19,8 @@ namespace eckit::geo::util { std::vector arange(double start, double stop, double step) { - if (types::is_approximately_equal(step, 0.) || types::is_approximately_equal(start, stop) || (stop - start) * step < 0.) { + if (types::is_approximately_equal(step, 0.) || types::is_approximately_equal(start, stop) || + (stop - start) * step < 0.) { std::vector l(1, start); return l; } @@ -27,7 +28,9 @@ std::vector arange(double start, double stop, double step) { const auto num = static_cast((stop - start) / step) + 1; std::vector l(num); - std::generate_n(l.begin(), num, [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); + std::generate_n(l.begin(), num, [start, step, n = 0ULL]() mutable { + return start + static_cast(n++) * step; + }); return l; } diff --git a/src/eckit/geo/util/gaussian_latitudes.cc b/src/eckit/geo/util/gaussian_latitudes.cc index 4fd5a8ba6..baa8d51df 100644 --- a/src/eckit/geo/util/gaussian_latitudes.cc +++ b/src/eckit/geo/util/gaussian_latitudes.cc @@ -38,7 +38,8 @@ std::vector gaussian_latitudes(size_t N, bool increasing) { } for (size_t j = 2; j <= i - (i % 2); j += 2) { - zfn[i - j] = zfn[i - j + 2] * static_cast((j - 1) * (2 * i - j + 2)) / static_cast(j * (2 * i - j + 1)); + zfn[i - j] = zfn[i - j + 2] * static_cast((j - 1) * (2 * i - j + 2)) / + static_cast(j * (2 * i - j + 1)); } } @@ -80,8 +81,8 @@ std::vector gaussian_latitudes(size_t N, bool increasing) { } if (!converged) { - throw BadValue("Could not calculate latitude within accuracy/iterations: " - + std::to_string(eps) + "/" + std::to_string(Nmax)); + throw BadValue("Could not calculate latitude within accuracy/iterations: " + std::to_string(eps) + "/" + + std::to_string(Nmax)); } // Convert colatitude [rad] to latitude [degree], symmetry diff --git a/src/eckit/geo/util/linspace.cc b/src/eckit/geo/util/linspace.cc index 5f8948a67..16fdabe51 100644 --- a/src/eckit/geo/util/linspace.cc +++ b/src/eckit/geo/util/linspace.cc @@ -25,8 +25,9 @@ std::vector linspace(double start, double stop, size_t num, bool endpoin const auto step = num > 1 ? (stop - start) / static_cast(endpoint ? (num - 1) : num) : 0; std::vector l(num); - std::generate_n(l.begin(), num, - [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); + std::generate_n(l.begin(), num, [start, step, n = 0ULL]() mutable { + return start + static_cast(n++) * step; + }); return l; } diff --git a/src/eckit/geo/util/monotonic_crop.cc b/src/eckit/geo/util/monotonic_crop.cc index 16c906b82..d45995424 100644 --- a/src/eckit/geo/util/monotonic_crop.cc +++ b/src/eckit/geo/util/monotonic_crop.cc @@ -26,8 +26,10 @@ namespace eckit::geo::util { using difference_type = std::make_signed_t; -std::pair monotonic_crop( - const std::vector& values, double min, double max, double eps) { +std::pair monotonic_crop(const std::vector& values, + double min, + double max, + double eps) { if (values.empty() || min > max) { return {}; } @@ -40,11 +42,11 @@ std::pair monotonic_crop( if (increasing) { ASSERT(std::is_sorted(b, e)); - auto lt = [eps](double a, double b) { return a < b && (0. == eps || !types::is_approximately_equal(a, b, eps)); }; + auto lt = [eps](double a, double b) { + return a < b && (0. == eps || !types::is_approximately_equal(a, b, eps)); + }; - return { - std::distance(b, std::lower_bound(b, e, min, lt)), - std::distance(b, std::upper_bound(b, e, max, lt))}; + return {std::distance(b, std::lower_bound(b, e, min, lt)), std::distance(b, std::upper_bound(b, e, max, lt))}; } @@ -53,9 +55,7 @@ std::pair monotonic_crop( auto gt = [eps](double a, double b) { return a > b && (0. == eps || !types::is_approximately_equal(a, b, eps)); }; - return { - std::distance(b, std::lower_bound(b, e, max, gt)), - std::distance(b, std::upper_bound(b, e, min, gt))}; + return {std::distance(b, std::lower_bound(b, e, max, gt)), std::distance(b, std::upper_bound(b, e, min, gt))}; } diff --git a/src/eckit/geo/util/reduced_classical_pl.cc b/src/eckit/geo/util/reduced_classical_pl.cc index 46441eb54..952c5d97d 100644 --- a/src/eckit/geo/util/reduced_classical_pl.cc +++ b/src/eckit/geo/util/reduced_classical_pl.cc @@ -23,14 +23,31 @@ namespace eckit::geo::util { static const std::map __classical_pls{ {16, {20, 27, 32, 40, 45, 48, 60, 60, 64, 64, 64, 64, 64, 64, 64, 64}}, {24, {20, 25, 36, 40, 45, 48, 54, 60, 64, 72, 80, 80, 90, 90, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96}}, - {32, {20, 27, 36, 40, 45, 50, 60, 64, 72, 75, 80, 90, 90, 96, 100, 108, 108, 120, 120, 120, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}}, - {48, {20, 25, 36, 40, 45, 50, 60, 60, 72, 75, 80, 90, 96, 100, 108, 120, 120, 120, 128, 135, 144, 144, 160, 160, 160, 160, 160, 180, 180, 180, 180, 180, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192}}, - {64, {20, 25, 36, 40, 45, 54, 60, 64, 72, 75, 80, 90, 96, 100, 108, 120, 120, 125, 135, 135, 144, 150, 160, 160, 180, 180, 180, 180, 192, 192, 200, 200, 216, 216, 216, 216, 225, 225, 225, 240, 240, 240, 240, 243, 250, 250, 250, 250, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256}}, - {80, {18, 25, 36, 40, 45, 54, 60, 64, 72, 72, 80, 90, 96, 100, 108, 120, 120, 128, 135, 144, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 200, 216, 216, 216, 225, 225, 240, 240, 240, 256, 256, 256, 256, 288, 288, 288, 288, 288, 288, 288, 288, 288, 300, 300, 300, 300, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320}}, - {96, {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 96, 100, 108, 120, 120, 125, 135, 144, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 200, 216, 216, 225, 225, 240, 240, 240, 250, 250, 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 375, 375, 375, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384}}, - {128, {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 90, 100, 108, 120, 120, 125, 128, 144, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 240, 250, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, 400, 400, 400, 400, 405, 432, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 450, 480, 480, 480, 480, 480, 480, 480, 480, 480, 480, 486, 486, 486, 500, 500, 500, 500, 500, 500, 500, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512}}, + {32, {20, 27, 36, 40, 45, 50, 60, 64, 72, 75, 80, 90, 90, 96, 100, 108, + 108, 120, 120, 120, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128}}, + {48, {20, 25, 36, 40, 45, 50, 60, 60, 72, 75, 80, 90, 96, 100, 108, 120, + 120, 120, 128, 135, 144, 144, 160, 160, 160, 160, 160, 180, 180, 180, 180, 180, + 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192}}, + {64, {20, 25, 36, 40, 45, 54, 60, 64, 72, 75, 80, 90, 96, 100, 108, 120, 120, 125, 135, 135, 144, 150, + 160, 160, 180, 180, 180, 180, 192, 192, 200, 200, 216, 216, 216, 216, 225, 225, 225, 240, 240, 240, 240, 243, + 250, 250, 250, 250, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256}}, + {80, {18, 25, 36, 40, 45, 54, 60, 64, 72, 72, 80, 90, 96, 100, 108, 120, 120, 128, 135, 144, + 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 200, 216, 216, 216, 225, 225, 240, 240, 240, 256, + 256, 256, 256, 288, 288, 288, 288, 288, 288, 288, 288, 288, 300, 300, 300, 300, 320, 320, 320, 320, + 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320}}, + {96, {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 96, 100, 108, 120, 120, 125, 135, 144, + 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 200, 216, 216, 225, 225, 240, 240, 240, 250, 250, + 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, 320, 320, 324, 360, 360, 360, + 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 375, 375, 375, 384, 384, 384, 384, 384, + 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384}}, + {128, {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 90, 100, 108, 120, 120, 125, 128, 144, 144, 150, + 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 240, 250, 250, 256, 270, 270, 288, 288, + 288, 300, 300, 320, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, 400, + 400, 400, 400, 405, 432, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 450, 480, 480, 480, 480, 480, 480, + 480, 480, 480, 480, 486, 486, 486, 500, 500, 500, 500, 500, 500, 500, 512, 512, 512, 512, 512, 512, 512, 512, + 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512, 512}}, {160, - {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 90, 96, 108, 120, 120, 125, 128, 135, 144, 150, 160, + {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 80, 90, 90, 96, 108, 120, 120, 125, 128, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, 375, 375, 384, 384, 400, 400, 400, 405, 432, 432, 432, 432, 432, 450, 450, 450, 450, 480, 480, 480, 480, 480, 480, 480, 500, 500, 500, 500, 500, 512, 512, 540, 540, 540, @@ -38,7 +55,7 @@ static const std::map __classical_pls{ 600, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640, 640}}, {200, - {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, + {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, 375, 375, 384, 400, 400, 400, 400, 432, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 480, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, 540, 540, 576, 576, @@ -48,30 +65,30 @@ static const std::map __classical_pls{ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800, 800}}, {256, - {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, - 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 243, 250, - 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, - 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, - 486, 500, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, - 600, 600, 600, 640, 640, 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 675, 720, - 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, 750, 750, 750, 750, 768, 768, 768, 768, - 800, 800, 800, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, - 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, - 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 972, 972, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, + {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, + 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 243, 250, + 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, + 486, 500, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, + 600, 600, 600, 640, 640, 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 675, 720, + 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, 750, 750, 750, 750, 768, 768, 768, 768, + 800, 800, 800, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, + 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 972, 972, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 1024}}, {320, - {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, - 135, 144, 144, 150, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 240, 250, - 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, - 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, - 500, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, - 600, 640, 640, 640, 640, 640, 640, 640, 648, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, - 720, 720, 720, 720, 729, 750, 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, - 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, - 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 972, 972, 1000, + {18, 25, 36, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, + 135, 144, 144, 150, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 240, 250, + 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, + 600, 640, 640, 640, 640, 640, 640, 640, 648, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, + 720, 720, 720, 720, 729, 750, 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, + 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, + 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, @@ -81,15 +98,15 @@ static const std::map __classical_pls{ 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280}}, {400, - {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, - 128, 144, 144, 150, 160, 160, 180, 180, 192, 192, 200, 200, 216, 216, 225, 240, 240, 240, 250, - 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, - 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, - 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, - 640, 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, - 720, 729, 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, - 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, - 960, 960, 960, 960, 960, 960, 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 100, 108, 120, 120, 125, + 128, 144, 144, 150, 160, 160, 180, 180, 192, 192, 200, 200, 216, 216, 225, 240, 240, 240, 250, + 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, + 640, 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, + 720, 729, 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, + 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, + 960, 960, 960, 960, 960, 960, 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1215, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, @@ -104,15 +121,15 @@ static const std::map __classical_pls{ 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600}}, {512, - {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 100, 108, 120, 125, - 128, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, - 250, 256, 270, 270, 288, 288, 288, 300, 320, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, - 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, - 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 640, - 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, - 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, - 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, - 960, 960, 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 100, 108, 120, 125, + 128, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, + 250, 256, 270, 270, 288, 288, 288, 300, 320, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 640, + 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, @@ -132,15 +149,15 @@ static const std::map __classical_pls{ 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048}}, {576, - {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 100, 108, 120, 120, - 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, - 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, - 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, - 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, 640, - 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, - 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, - 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 100, 108, 120, 120, + 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, 243, + 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, 640, + 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, @@ -164,15 +181,15 @@ static const std::map __classical_pls{ 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304}}, {640, - {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 90, 96, 100, 108, 120, 120, - 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 243, - 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, - 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, - 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, 640, - 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, - 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, - 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 90, 96, 100, 108, 120, 120, + 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 216, 225, 240, 240, 243, + 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, 375, + 375, 384, 384, 400, 400, 400, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, 486, + 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, 640, + 640, 640, 640, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, + 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, @@ -199,15 +216,15 @@ static const std::map __classical_pls{ 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560}}, {800, - {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 80, 90, 90, 96, 100, 108, 120, 120, - 125, 128, 135, 144, 150, 160, 160, 180, 180, 192, 192, 200, 200, 216, 216, 225, 240, 240, 240, - 250, 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 375, - 375, 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 486, - 500, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 625, - 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, - 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, - 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 80, 90, 90, 96, 100, 108, 120, 120, + 125, 128, 135, 144, 150, 160, 160, 180, 180, 192, 192, 200, 200, 216, 216, 225, 240, 240, 240, + 250, 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, 375, + 375, 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 486, + 500, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 625, + 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, + 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, @@ -243,15 +260,15 @@ static const std::map __classical_pls{ 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200}}, {1024, - {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, - 125, 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, - 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, - 375, 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, - 486, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, - 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, - 729, 750, 750, 750, 750, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, - 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, + 125, 125, 135, 144, 150, 160, 160, 180, 180, 180, 192, 192, 200, 216, 216, 225, 225, 240, 240, + 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, 360, + 375, 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, 480, + 486, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, + 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 750, 750, 750, 750, 768, 768, 800, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, @@ -298,15 +315,15 @@ static const std::map __classical_pls{ 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096}}, {1280, - {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, - 120, 125, 135, 135, 144, 144, 160, 160, 180, 180, 180, 192, 200, 200, 216, 216, 225, 240, 240, - 240, 250, 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, - 375, 375, 375, 384, 400, 400, 400, 432, 432, 432, 432, 432, 450, 450, 480, 480, 480, 480, 480, - 486, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, - 625, 625, 625, 625, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, - 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, - 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 64, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, + 120, 125, 135, 135, 144, 144, 160, 160, 180, 180, 180, 192, 200, 200, 216, 216, 225, 240, 240, + 240, 250, 250, 256, 270, 288, 288, 288, 300, 300, 320, 320, 320, 324, 360, 360, 360, 360, 360, + 375, 375, 375, 384, 400, 400, 400, 432, 432, 432, 432, 432, 450, 450, 480, 480, 480, 480, 480, + 486, 500, 500, 512, 512, 540, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, 600, + 625, 625, 625, 625, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, @@ -367,15 +384,15 @@ static const std::map __classical_pls{ 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120}}, {1600, - {18, 25, 32, 40, 45, 50, 54, 60, 72, 72, 75, 80, 90, 90, 96, 100, 108, 120, 120, - 120, 125, 128, 135, 144, 144, 150, 160, 160, 162, 180, 180, 180, 192, 192, 216, 216, 225, 240, - 240, 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, - 360, 375, 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, - 480, 486, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, - 600, 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, - 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, - 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 54, 60, 72, 72, 75, 80, 90, 90, 96, 100, 108, 120, 120, + 120, 125, 128, 135, 144, 144, 150, 160, 160, 162, 180, 180, 180, 192, 192, 216, 216, 225, 240, + 240, 243, 250, 256, 270, 270, 288, 288, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, 360, + 360, 375, 375, 384, 384, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, 480, + 480, 486, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 600, 600, 600, + 600, 625, 625, 625, 625, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, + 729, 729, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, @@ -453,15 +470,15 @@ static const std::map __classical_pls{ 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400}}, {2000, - {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, - 120, 125, 135, 135, 144, 144, 150, 160, 160, 180, 180, 180, 180, 192, 192, 192, 200, 216, 216, - 216, 225, 240, 240, 243, 250, 256, 270, 270, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, - 360, 360, 375, 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, - 480, 486, 500, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, - 600, 625, 625, 625, 625, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, - 720, 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, - 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + {18, 25, 32, 40, 45, 50, 60, 60, 72, 72, 75, 81, 90, 96, 96, 108, 108, 120, 120, + 120, 125, 135, 135, 144, 144, 150, 160, 160, 180, 180, 180, 180, 192, 192, 192, 200, 216, 216, + 216, 225, 240, 240, 243, 250, 256, 270, 270, 288, 300, 300, 320, 320, 320, 360, 360, 360, 360, + 360, 360, 375, 375, 384, 400, 400, 400, 405, 432, 432, 432, 432, 450, 450, 450, 480, 480, 480, + 480, 486, 500, 500, 500, 512, 512, 540, 540, 540, 540, 576, 576, 576, 576, 576, 600, 600, 600, + 600, 625, 625, 625, 625, 640, 640, 640, 648, 675, 675, 675, 675, 720, 720, 720, 720, 720, 720, + 720, 729, 750, 750, 750, 750, 768, 768, 768, 800, 800, 800, 800, 800, 810, 864, 864, 864, 864, + 864, 864, 864, 864, 864, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 972, 972, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, @@ -560,113 +577,113 @@ static const std::map __classical_pls{ 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000}}, {4000, - {18, 24, 32, 40, 45, 48, 54, 60, 64, 72, 75, 80, 90, 90, 96, 100, - 108, 108, 120, 120, 125, 128, 135, 135, 144, 150, 150, 160, 160, 180, 180, 180, - 180, 192, 192, 192, 200, 216, 216, 216, 216, 225, 225, 240, 240, 240, 243, 250, - 256, 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, 320, - 324, 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, 400, - 400, 400, 405, 405, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 480, 480, - 480, 480, 480, 480, 486, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, 540, - 540, 540, 576, 576, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, 600, 600, - 625, 625, 625, 625, 625, 625, 640, 640, 640, 648, 648, 675, 675, 675, 675, 675, - 675, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, 750, - 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, 800, 810, 810, - 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, - 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, - 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, - 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1152, - 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1215, 1250, - 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, - 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, - 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, - 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, - 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, 1600, - 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1620, 1728, 1728, - 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, - 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, - 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, 1875, - 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, 1920, - 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, 2000, - 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, 2025, 2025, 2025, 2048, - 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, - 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, - 2187, 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, - 2250, 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, - 2304, 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, - 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2500, 2500, 2500, 2500, 2500, - 2500, 2500, 2500, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, 2700, 2700, 2700, - 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, 2880, 2880, 2880, 2880, 2880, - 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, - 2916, 2916, 2916, 2916, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, - 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3200, 3200, - 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3375, 3375, 3375, 3375, - 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3456, 3456, - 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, - 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3645, 3645, 3645, 3645, 3645, - 3645, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, - 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3888, 3888, 3888, - 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, - 4000, 4000, 4000, 4050, 4050, 4050, 4050, 4050, 4050, 4096, 4096, 4096, 4096, 4096, 4096, 4096, - 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, - 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4374, - 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, - 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, 4608, 4608, 4608, 4608, 4608, - 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, 4800, 4800, 4800, 4800, 4800, - 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, - 4800, 4800, 4800, 4800, 4800, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 5000, 5000, - 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, - 5000, 5000, 5000, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, - 5120, 5120, 5120, 5120, 5120, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5400, 5400, - 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, - 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5625, - 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, - 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, - 5625, 5625, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, - 5760, 5760, 5760, 5760, 5760, 5760, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, - 5832, 5832, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, - 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6075, 6075, 6075, 6075, - 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6144, 6144, 6144, 6144, 6144, 6144, 6144, - 6144, 6144, 6144, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, - 6250, 6250, 6250, 6250, 6250, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, - 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6480, 6480, 6480, 6480, - 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6561, 6561, 6561, 6561, 6561, 6561, 6561, - 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, - 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, - 6750, 6750, 6750, 6750, 6750, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, - 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, - 6912, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, - 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, - 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, - 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, - 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, - 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, - 7500, 7500, 7500, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, - 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, - 7680, 7680, 7680, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, - 7776, 7776, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, - 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, - 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8100, 8100, 8100, 8100, 8100, 8100, - 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8192, 8192, 8192, 8192, 8192, - 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8748, 8748, 8748, 8748, - 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, - 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, - 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, - 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9216, 9216, 9216, - 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, - 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, - 9216, 9216, 9216, 9216, 9216, 9216, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, - 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, - 9375, 9375, 9375, 9375, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, - 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, - 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, - 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, - 9720, 9720, 9720, 9720, 9720, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, + {18, 24, 32, 40, 45, 48, 54, 60, 64, 72, 75, 80, 90, 90, 96, 100, + 108, 108, 120, 120, 125, 128, 135, 135, 144, 150, 150, 160, 160, 180, 180, 180, + 180, 192, 192, 192, 200, 216, 216, 216, 216, 225, 225, 240, 240, 240, 243, 250, + 256, 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, 320, + 324, 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, 400, + 400, 400, 405, 405, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 480, 480, + 480, 480, 480, 480, 486, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, 540, + 540, 540, 576, 576, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, 600, 600, + 625, 625, 625, 625, 625, 625, 640, 640, 640, 648, 648, 675, 675, 675, 675, 675, + 675, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, 750, + 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, 800, 810, 810, + 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, 900, 900, + 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, 1024, + 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1125, + 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, 1152, 1152, + 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, 1215, 1250, + 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1280, 1296, 1296, + 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1440, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, + 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1620, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, + 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, 1875, + 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, 1920, + 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, 2025, 2025, 2025, 2048, + 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, + 2187, 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, + 2250, 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2500, 2500, 2500, 2500, 2500, + 2500, 2500, 2500, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, 2700, 2700, 2700, + 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2916, 2916, 2916, 2916, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, + 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3375, 3375, 3375, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3456, 3456, + 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3645, 3645, 3645, 3645, 3645, + 3645, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, + 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3888, 3888, 3888, + 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4050, 4050, 4050, 4050, 4050, 4050, 4096, 4096, 4096, 4096, 4096, 4096, 4096, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4374, + 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, 4608, 4608, 4608, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 4860, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, + 5760, 5760, 5760, 5760, 5760, 5760, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, + 5832, 5832, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, + 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6075, 6075, 6075, 6075, + 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6144, 6144, 6144, 6144, 6144, 6144, 6144, + 6144, 6144, 6144, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, + 6250, 6250, 6250, 6250, 6250, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6480, 6480, 6480, 6480, + 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6561, 6561, 6561, 6561, 6561, 6561, 6561, + 6561, 6561, 6561, 6561, 6561, 6561, 6561, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, + 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, + 6750, 6750, 6750, 6750, 6750, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, + 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, + 6912, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, 7776, + 7776, 7776, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8100, 8100, 8100, 8100, 8100, 8100, + 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8748, 8748, 8748, 8748, + 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9216, 9216, 9216, + 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, + 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, + 9216, 9216, 9216, 9216, 9216, 9216, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, + 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, + 9375, 9375, 9375, 9375, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, + 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, + 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, + 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, + 9720, 9720, 9720, 9720, 9720, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10125, 10125, 10125, @@ -811,116 +828,116 @@ static const std::map __classical_pls{ 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000, 16000}}, {8000, - {16, 24, 30, 36, 40, 45, 54, 60, 64, 72, 72, 75, 81, 90, 90, 96, - 100, 108, 120, 120, 120, 125, 128, 135, 144, 144, 150, 160, 160, 160, 180, 180, - 180, 180, 192, 192, 192, 200, 216, 216, 216, 216, 225, 225, 240, 240, 240, 243, - 250, 250, 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, - 320, 324, 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, - 400, 400, 400, 405, 405, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 480, - 480, 480, 480, 480, 480, 480, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, - 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, - 600, 625, 625, 625, 625, 625, 625, 640, 640, 640, 640, 648, 675, 675, 675, 675, - 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, - 750, 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, 800, 800, - 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, - 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 960, 960, 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, - 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, - 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, - 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, - 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1280, - 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, - 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, - 1440, 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, - 1500, 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, - 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1620, 1728, - 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, - 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, - 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, - 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, - 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, - 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, 2025, 2025, 2025, 2048, - 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, - 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, - 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, - 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, - 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, - 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2430, 2430, 2430, 2430, 2500, - 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2560, - 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, - 2592, 2592, 2592, 2592, 2592, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, - 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, - 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, - 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, - 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2916, 2916, 2916, 2916, 2916, 2916, - 2916, 2916, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, - 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, - 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, - 3125, 3125, 3125, 3125, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, - 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3375, - 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, - 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, - 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, - 3456, 3456, 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, - 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, - 3600, 3600, 3600, 3600, 3600, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, - 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, - 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3840, 3840, 3840, 3840, 3840, 3840, 3840, - 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3888, - 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, - 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, - 4000, 4000, 4000, 4000, 4000, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, - 4050, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4320, 4320, 4320, - 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, - 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, - 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, - 4320, 4320, 4320, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, - 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, - 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, - 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, - 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, - 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, - 4800, 4860, 4860, 4860, 4860, 4860, 4860, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, - 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, - 5120, 5120, 5120, 5120, 5120, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5400, 5400, 5400, 5400, - 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, - 5400, 5400, 5400, 5400, 5400, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, - 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, - 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, - 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 6000, 6000, 6000, 6000, 6000, 6000, 6000, - 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6075, 6075, - 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6250, - 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6400, 6400, 6400, - 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, - 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6561, 6561, 6561, 6561, 6561, - 6561, 6561, 6561, 6561, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, - 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6912, 6912, 6912, - 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, - 6912, 6912, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, - 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, - 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, - 7290, 7290, 7290, 7290, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, - 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, - 7500, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, - 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7776, 7776, 7776, 7776, 7776, 7776, - 7776, 7776, 7776, 7776, 7776, 7776, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, - 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, - 8000, 8000, 8000, 8000, 8000, 8000, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, - 8100, 8100, 8100, 8100, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, - 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, - 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, - 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, - 9000, 9000, 9000, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, - 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, - 9216, 9216, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, - 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9600, 9600, 9600, 9600, 9600, 9600, - 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, - 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9720, 9720, 9720, 9720, 9720, 9720, - 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 10000, 10000, 10000, 10000, + {16, 24, 30, 36, 40, 45, 54, 60, 64, 72, 72, 75, 81, 90, 90, 96, + 100, 108, 120, 120, 120, 125, 128, 135, 144, 144, 150, 160, 160, 160, 180, 180, + 180, 180, 192, 192, 192, 200, 216, 216, 216, 216, 225, 225, 240, 240, 240, 243, + 250, 250, 256, 270, 270, 270, 288, 288, 288, 288, 300, 300, 300, 320, 320, 320, + 320, 324, 360, 360, 360, 360, 360, 360, 360, 360, 375, 375, 375, 375, 384, 384, + 400, 400, 400, 405, 405, 432, 432, 432, 432, 432, 432, 450, 450, 450, 450, 480, + 480, 480, 480, 480, 480, 480, 486, 500, 500, 500, 512, 512, 512, 540, 540, 540, + 540, 540, 540, 540, 576, 576, 576, 576, 576, 576, 576, 576, 600, 600, 600, 600, + 600, 625, 625, 625, 625, 625, 625, 640, 640, 640, 640, 648, 675, 675, 675, 675, + 675, 675, 675, 720, 720, 720, 720, 720, 720, 720, 720, 720, 720, 729, 729, 750, + 750, 750, 750, 750, 768, 768, 768, 768, 800, 800, 800, 800, 800, 800, 800, 800, + 810, 810, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 864, 900, + 900, 900, 900, 900, 900, 900, 900, 960, 960, 960, 960, 960, 960, 960, 960, 960, + 960, 960, 960, 960, 960, 972, 972, 972, 1000, 1000, 1000, 1000, 1000, 1000, 1024, 1024, + 1024, 1024, 1024, 1024, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, 1080, + 1080, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1125, 1152, 1152, 1152, 1152, + 1152, 1152, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1200, 1215, 1215, 1215, + 1215, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1250, 1280, 1280, 1280, 1280, 1280, 1280, 1280, + 1296, 1296, 1296, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, 1350, + 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, 1440, + 1440, 1440, 1440, 1440, 1440, 1458, 1458, 1458, 1458, 1500, 1500, 1500, 1500, 1500, 1500, 1500, + 1500, 1500, 1500, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1536, 1600, 1600, 1600, 1600, + 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1600, 1620, 1620, 1620, 1620, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, + 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1728, 1800, 1800, 1800, 1800, 1800, 1800, 1800, + 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1800, 1875, 1875, 1875, 1875, 1875, 1875, + 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1875, 1920, 1920, 1920, 1920, + 1920, 1920, 1920, 1920, 1920, 1920, 1944, 1944, 1944, 1944, 1944, 1944, 2000, 2000, 2000, 2000, + 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2025, 2025, 2025, 2025, 2025, 2025, 2048, + 2048, 2048, 2048, 2048, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, + 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2160, 2187, + 2187, 2187, 2187, 2187, 2187, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, 2250, + 2250, 2250, 2250, 2250, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, 2304, + 2304, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, + 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2430, 2430, 2430, 2430, 2430, 2430, 2430, 2500, + 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2500, 2560, + 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2560, 2592, 2592, 2592, + 2592, 2592, 2592, 2592, 2592, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, + 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2700, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, + 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2880, 2916, 2916, 2916, 2916, 2916, 2916, + 2916, 2916, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, 3000, + 3000, 3000, 3000, 3000, 3000, 3000, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3072, + 3072, 3072, 3072, 3072, 3072, 3072, 3072, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, 3125, + 3125, 3125, 3125, 3125, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, 3200, + 3200, 3200, 3200, 3200, 3200, 3200, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3240, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, + 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, 3375, + 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, 3456, + 3456, 3456, 3456, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, 3600, + 3600, 3600, 3600, 3600, 3600, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, 3645, + 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, + 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3750, 3840, 3840, 3840, 3840, 3840, 3840, 3840, + 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3840, 3888, + 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 3888, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, 4000, + 4000, 4000, 4000, 4000, 4000, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, 4050, + 4050, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4096, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, 4320, + 4320, 4320, 4320, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, 4374, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, + 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4500, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, + 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4608, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, 4800, + 4800, 4860, 4860, 4860, 4860, 4860, 4860, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, + 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5000, 5120, 5120, 5120, 5120, 5120, 5120, 5120, 5120, + 5120, 5120, 5120, 5120, 5120, 5184, 5184, 5184, 5184, 5184, 5184, 5184, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, 5400, + 5400, 5400, 5400, 5400, 5400, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, 5625, + 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, 5760, + 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 5832, 6000, 6000, 6000, 6000, 6000, 6000, 6000, + 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6075, 6075, + 6075, 6075, 6075, 6075, 6075, 6075, 6075, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6144, 6250, + 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6250, 6400, 6400, 6400, + 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, 6400, + 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6480, 6561, 6561, 6561, 6561, 6561, + 6561, 6561, 6561, 6561, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, + 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6750, 6912, 6912, 6912, + 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, 6912, + 6912, 6912, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, + 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7200, 7290, 7290, 7290, 7290, 7290, 7290, 7290, 7290, + 7290, 7290, 7290, 7290, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, 7500, + 7500, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, + 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7680, 7776, 7776, 7776, 7776, 7776, 7776, + 7776, 7776, 7776, 7776, 7776, 7776, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, 8000, + 8000, 8000, 8000, 8000, 8000, 8000, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, 8100, + 8100, 8100, 8100, 8100, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, 8640, + 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, 8748, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, + 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, 9000, + 9000, 9000, 9000, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, + 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, 9216, + 9216, 9216, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, + 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9375, 9600, 9600, 9600, 9600, 9600, 9600, + 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, + 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9600, 9720, 9720, 9720, 9720, 9720, 9720, + 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 9720, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, 10125, diff --git a/tests/geo/test_great_circle.cc b/tests/geo/test_great_circle.cc index 66bbab069..575911cf5 100644 --- a/tests/geo/test_great_circle.cc +++ b/tests/geo/test_great_circle.cc @@ -27,8 +27,8 @@ CASE("test great circles intersections") { using types::is_approximately_equal; using types::is_approximately_greater_or_equal; - auto is_approximately_equal_longitude = [](double lon1, double lon2, - double epsilon = std::numeric_limits::epsilon()) -> bool { + auto is_approximately_equal_longitude = + [](double lon1, double lon2, double epsilon = std::numeric_limits::epsilon()) -> bool { while (lon2 < lon1) { lon2 += 360; } @@ -106,8 +106,8 @@ CASE("test great circles intersections") { auto lons = gc.longitude(mid.lat); EXPECT(lons.size() == 2); - EXPECT(is_approximately_equal_longitude(lons[0], mid.lon, 0.01) - || is_approximately_equal_longitude(lons[1], mid.lon, 0.01)); + EXPECT(is_approximately_equal_longitude(lons[0], mid.lon, 0.01) || + is_approximately_equal_longitude(lons[1], mid.lon, 0.01)); } SECTION("mal-formed great circle") { @@ -141,13 +141,17 @@ CASE("test great circles intersections") { auto lon_at_equator = gc.longitude(0); EXPECT(lon_at_equator.size() == 2); - EXPECT((is_approximately_equal_longitude(lon_gc + 90, lon_at_equator[0]) && is_approximately_equal_longitude(lon_gc - 90, lon_at_equator[1])) || (is_approximately_equal_longitude(lon_gc - 90, lon_at_equator[0]) && is_approximately_equal_longitude(lon_gc + 90, lon_at_equator[1]))); + EXPECT((is_approximately_equal_longitude(lon_gc + 90, lon_at_equator[0]) && + is_approximately_equal_longitude(lon_gc - 90, lon_at_equator[1])) || + (is_approximately_equal_longitude(lon_gc - 90, lon_at_equator[0]) && + is_approximately_equal_longitude(lon_gc + 90, lon_at_equator[1]))); auto lon_extrema1 = gc.longitude(lat_gc); EXPECT(lon_extrema1.size() == 1 && is_approximately_equal_longitude(lon_extrema1[0], lon_gc, 0.01)); auto lon_extrema2 = gc.longitude(-lat_gc); - EXPECT(lon_extrema2.size() == 1 && is_approximately_equal_longitude(lon_extrema2[0], lon_gc + 180, 0.01)); + EXPECT(lon_extrema2.size() == 1 && + is_approximately_equal_longitude(lon_extrema2[0], lon_gc + 180, 0.01)); } } } @@ -170,7 +174,8 @@ CASE("test great circles intersections") { } else { EXPECT(is_approximately_equal_longitude(lons[0] + 180, lons[1])); - EXPECT(is_approximately_equal_longitude(lons[0], lon) || is_approximately_equal_longitude(lons[1], lon)); + EXPECT(is_approximately_equal_longitude(lons[0], lon) || + is_approximately_equal_longitude(lons[1], lon)); } } @@ -182,7 +187,8 @@ CASE("test great circles intersections") { EXPECT(lons.size() == 2); EXPECT(is_approximately_equal_longitude(lons[0] + 180, lons[1])); - EXPECT(is_approximately_equal_longitude(lons[0], lon) || is_approximately_equal_longitude(lons[1], lon)); + EXPECT(is_approximately_equal_longitude(lons[0], lon) || + is_approximately_equal_longitude(lons[1], lon)); } } } diff --git a/tests/geo/test_grid.cc b/tests/geo/test_grid.cc index 961f1bcfa..f37e43a4f 100644 --- a/tests/geo/test_grid.cc +++ b/tests/geo/test_grid.cc @@ -40,17 +40,14 @@ CASE("GridFactory::build") { } - SECTION("Grid::build_from_uid") { - } + SECTION("Grid::build_from_uid") {} - SECTION("Grid::build_from_increments") { - } + SECTION("Grid::build_from_increments") {} SECTION("Grid::build") { - std::unique_ptr grid(geo::GridFactory::build(MappedConfiguration{ - {{"name", "O2"}}})); + std::unique_ptr grid(geo::GridFactory::build(MappedConfiguration{{{"name", "O2"}}})); // auto size = grid->size(); // EXPECT_EQUAL(size, 88); diff --git a/tests/geo/test_polygon.cc b/tests/geo/test_polygon.cc index f50e3654c..7f6e93abe 100644 --- a/tests/geo/test_polygon.cc +++ b/tests/geo/test_polygon.cc @@ -90,7 +90,8 @@ CASE("LonLatPolygon") { SECTION("Construction") { const std::vector points1{{0, 0}, {1, 1}, {2, 2}, {0, 0}}; - const std::vector points2{{0, 0}, {1, 0}, {2, 0}, {2, 1}, {2, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 0}}; + const std::vector + points2{{0, 0}, {1, 0}, {2, 0}, {2, 1}, {2, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 0}}; EXPECT_EQUAL(Polygon(points1).size(), 2); EXPECT_EQUAL(Polygon(points1.begin(), points1.end()).size(), 2); @@ -210,7 +211,8 @@ CASE("LonLatPolygon") { } // HEALPix-like equator wedge in longitude - Polygon poly({{0, 1}, {0, 90}, {360, 90}, {360, 1}, {361, 0}, {360, -1}, {360, -90}, {0, -90}, {0, -1}, {1, 0}, {0, 1}}); + Polygon poly( + {{0, 1}, {0, 90}, {360, 90}, {360, 1}, {361, 0}, {360, -1}, {360, -90}, {0, -90}, {0, -1}, {1, 0}, {0, 1}}); EXPECT(poly.contains({0, 0})); EXPECT(poly.contains({1, 0})); EXPECT(poly.contains({360, 0})); @@ -328,9 +330,7 @@ CASE("LonLatPolygon") { } SECTION("Partitioning (includePoles=false)") { - auto mid = [](double a, double b) { - return (a + b) / 2.; - }; + auto mid = [](double a, double b) { return (a + b) / 2.; }; constexpr double lon[] = {0, 90, 180, 270, 360}; constexpr double lat[] = {90, 0, -90}; @@ -347,7 +347,14 @@ CASE("LonLatPolygon") { std::vector points; - const std::vector list_lons{lon[0], mid(lon[0], lon[1]), lon[1], mid(lon[1], lon[2]), lon[2], mid(lon[2], lon[3]), lon[3], mid(lon[3], lon[4])}; + const std::vector list_lons{lon[0], + mid(lon[0], lon[1]), + lon[1], + mid(lon[1], lon[2]), + lon[2], + mid(lon[2], lon[3]), + lon[3], + mid(lon[3], lon[4])}; const std::vector list_lats{lat[0], mid(lat[0], lat[1]), lat[1], mid(lat[1], lat[2]), lat[2]}; for (double lon : list_lons) { diff --git a/tests/geo/test_projection.cc b/tests/geo/test_projection.cc index c9da06c1c..e4d69f5a9 100644 --- a/tests/geo/test_projection.cc +++ b/tests/geo/test_projection.cc @@ -51,8 +51,10 @@ int main(int argc, char* argv[]) { { Projection s1(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"R", 1.}}))); - Projection s2(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 1.}}))); - Projection s3(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 0.5}}))); + Projection s2( + ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 1.}}))); + Projection s3( + ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 0.5}}))); EXPECT(points_equal(p, s1->inv(s1->fwd(p)))); EXPECT(points_equal(p, s2->inv(s2->fwd(p)))); @@ -118,7 +120,9 @@ int main(int argc, char* argv[]) { for (auto a : delta) { for (auto b : delta) { for (auto c : delta) { - projection::Rotation rot(0. + static_cast(b), -90. + static_cast(a), static_cast(c)); + projection::Rotation rot(0. + static_cast(b), + -90. + static_cast(a), + static_cast(c)); EXPECT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); EXPECT(points_equal(p, rot.inv(rot.fwd(p)))); @@ -287,15 +291,14 @@ int main(int argc, char* argv[]) { {a, "EPSG:4326"}, {a, "EPSG:4979"}, {Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, - {Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, - "+proj=cart +R=6371229."}, - {Point3{3574399.5431832, 759762.07693392, 5218815.216709}, - "+proj=cart +ellps=sphere"}, + {Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, "+proj=cart +R=6371229."}, + {Point3{3574399.5431832, 759762.07693392, 5218815.216709}, "+proj=cart +ellps=sphere"}, {a, "+proj=latlon +ellps=sphere"}, }; for (const auto& test : tests) { - Projection projection(ProjectionFactory::instance().get("proj").create(MappedConfiguration{{{"source", "EPSG:4326"}, {"target", test.target}}})); + Projection projection(ProjectionFactory::instance().get("proj").create( + MappedConfiguration{{{"source", "EPSG:4326"}, {"target", test.target}}})); #if 0 std::cout << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) @@ -310,7 +313,8 @@ int main(int argc, char* argv[]) { EXPECT(points_equal(b, test.b)); EXPECT(points_equal(c, a)); - Projection reverse(ProjectionFactory::instance().get("proj").create(MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}}))); + Projection reverse(ProjectionFactory::instance().get("proj").create( + MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}}))); auto d = reverse->fwd(test.b); auto e = reverse->inv(d); diff --git a/tests/geo/test_range.cc b/tests/geo/test_range.cc index 630b7db56..39a7a64e3 100644 --- a/tests/geo/test_range.cc +++ b/tests/geo/test_range.cc @@ -27,10 +27,7 @@ int main(int argc, const char* argv[]) { { - std::vector ref{59.44440828916676, - 19.87571914744090, - -19.87571914744090, - -59.44440828916676}; + std::vector ref{59.44440828916676, 19.87571914744090, -19.87571914744090, -59.44440828916676}; auto global = Gaussian(2); EXPECT(global.size() == ref.size()); From 17ed40ea1f2e7ba806481807e4829ec09d6666e3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 28 Sep 2023 11:32:00 +0100 Subject: [PATCH 329/737] eckit::geo::grid::regular::RegularLatLon --- src/eckit/geo/grid/regular/RegularLatLon.cc | 32 +++++++++++++-------- src/eckit/geo/grid/regular/RegularLatLon.h | 19 ++++++++++-- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/src/eckit/geo/grid/regular/RegularLatLon.cc b/src/eckit/geo/grid/regular/RegularLatLon.cc index 317d2f318..97815ee1f 100644 --- a/src/eckit/geo/grid/regular/RegularLatLon.cc +++ b/src/eckit/geo/grid/regular/RegularLatLon.cc @@ -13,6 +13,7 @@ #include "eckit/geo/grid/regular/RegularLatLon.h" #include "eckit/config/MappedConfiguration.h" +#include "eckit/geo/Increments.h" #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/util/regex.h" #include "eckit/utils/Translator.h" @@ -22,29 +23,36 @@ namespace eckit::geo::grid::regular { RegularLatLon::RegularLatLon(const Configuration& config) : - Regular(config) {} + RegularLatLon({config.getDouble("west_east_increment"), config.getDouble("south_north_increment")}, + area::BoundingBox(config), + {config.getDouble("west", 0.), config.getDouble("south", -90.)}) {} -Grid::iterator RegularLatLon::cbegin() const { - return iterator{new geo::iterator::Regular(*this, 0)}; -} +RegularLatLon::RegularLatLon(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& reference) : + Regular(bbox) {} -Grid::iterator RegularLatLon::cend() const { - return iterator{new geo::iterator::Regular(*this, size())}; -} +RegularLatLon::RegularLatLon(size_t ni, size_t nj, const area::BoundingBox& bbox, const PointLonLat& reference) : + Regular(bbox), ni_(ni), nj_(nj) {} -size_t RegularLatLon::ni() const { - NOTIMP; -} +RegularLatLon::RegularLatLon(const Increments& inc, const PointLonLat& reference) : + RegularLatLon(inc, area::BoundingBox::make_global_prime(), reference) {} -size_t RegularLatLon::nj() const { - NOTIMP; +RegularLatLon::RegularLatLon(size_t ni, size_t nj, const PointLonLat& reference) : + RegularLatLon(ni, nj, area::BoundingBox::make_global_prime(), reference) {} + + +Grid::iterator RegularLatLon::cbegin() const { + return iterator{new geo::iterator::Regular(*this, 0)}; } +Grid::iterator RegularLatLon::cend() const { + return iterator{new geo::iterator::Regular(*this, size())}; +} + const std::vector& RegularLatLon::longitudes() const { NOTIMP; } diff --git a/src/eckit/geo/grid/regular/RegularLatLon.h b/src/eckit/geo/grid/regular/RegularLatLon.h index db3c3394a..1a63ac6f4 100644 --- a/src/eckit/geo/grid/regular/RegularLatLon.h +++ b/src/eckit/geo/grid/regular/RegularLatLon.h @@ -15,6 +15,11 @@ #include "eckit/geo/grid/Regular.h" +namespace eckit::geo { +class Increments; +} + + namespace eckit::geo::grid::regular { @@ -30,6 +35,12 @@ class RegularLatLon final : public Regular { explicit RegularLatLon(const Configuration&); + RegularLatLon(const Increments&, const area::BoundingBox&, const PointLonLat& reference = {0, 0}); + RegularLatLon(size_t ni, size_t nj, const area::BoundingBox&, const PointLonLat& reference = {0, 0}); + + explicit RegularLatLon(const Increments&, const PointLonLat& reference = {0, 0}); + RegularLatLon(size_t ni, size_t nj, const PointLonLat& reference = {0, 0}); + // -- Destructor // None @@ -47,8 +58,8 @@ class RegularLatLon final : public Regular { iterator cbegin() const override; iterator cend() const override; - size_t ni() const override; - size_t nj() const override; + size_t ni() const override { return ni_; } + size_t nj() const override { return nj_; } // -- Class members // None @@ -59,7 +70,9 @@ class RegularLatLon final : public Regular { private: // -- Members - // None + + size_t ni_; + size_t nj_; // -- Methods // None From 64629738a1f6f5f78324c3a71a427f03f3db9084 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 28 Sep 2023 11:57:06 +0100 Subject: [PATCH 330/737] eckit::geo::grid::regular::RegularLatLon --- src/eckit/geo/CMakeLists.txt | 12 +++---- .../{ReducedLatLon.cc => ReducedLL.cc} | 16 ++++----- .../reduced/{ReducedLatLon.h => ReducedLL.h} | 4 +-- .../{IrregularLatLon.cc => IrregularLL.cc} | 16 ++++----- .../{IrregularLatLon.h => IrregularLL.h} | 4 +-- .../{RegularLatLon.cc => RegularLL.cc} | 36 +++++++++---------- .../regular/{RegularLatLon.h => RegularLL.h} | 12 +++---- 7 files changed, 50 insertions(+), 50 deletions(-) rename src/eckit/geo/grid/reduced/{ReducedLatLon.cc => ReducedLL.cc} (64%) rename src/eckit/geo/grid/reduced/{ReducedLatLon.h => ReducedLL.h} (93%) rename src/eckit/geo/grid/regular/{IrregularLatLon.cc => IrregularLL.cc} (59%) rename src/eckit/geo/grid/regular/{IrregularLatLon.h => IrregularLL.h} (93%) rename src/eckit/geo/grid/regular/{RegularLatLon.cc => RegularLL.cc} (58%) rename src/eckit/geo/grid/regular/{RegularLatLon.h => RegularLL.h} (75%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index fc4624c7f..3fabe4f7a 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -60,14 +60,14 @@ list( APPEND eckit_geo_srcs grid/reduced/HEALPix.h grid/reduced/ReducedGaussian.cc grid/reduced/ReducedGaussian.h - grid/reduced/ReducedLatLon.cc - grid/reduced/ReducedLatLon.h - grid/regular/IrregularLatLon.cc - grid/regular/IrregularLatLon.h + grid/reduced/ReducedLL.cc + grid/reduced/ReducedLL.h + grid/regular/IrregularLL.cc + grid/regular/IrregularLL.h grid/regular/RegularGaussian.cc grid/regular/RegularGaussian.h - grid/regular/RegularLatLon.cc - grid/regular/RegularLatLon.h + grid/regular/RegularLL.cc + grid/regular/RegularLL.h grid/unstructured/ORCA.cc grid/unstructured/ORCA.h iterator/Reduced.cc diff --git a/src/eckit/geo/grid/reduced/ReducedLatLon.cc b/src/eckit/geo/grid/reduced/ReducedLL.cc similarity index 64% rename from src/eckit/geo/grid/reduced/ReducedLatLon.cc rename to src/eckit/geo/grid/reduced/ReducedLL.cc index bc0411ec8..c4a3ab463 100644 --- a/src/eckit/geo/grid/reduced/ReducedLatLon.cc +++ b/src/eckit/geo/grid/reduced/ReducedLL.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/reduced/ReducedLatLon.h" +#include "eckit/geo/grid/reduced/ReducedLL.h" #include "eckit/geo/iterator/Reduced.h" @@ -18,36 +18,36 @@ namespace eckit::geo::grid::reduced { -ReducedLatLon::ReducedLatLon(const Configuration& config) : +ReducedLL::ReducedLL(const Configuration& config) : Reduced(config) {} -Grid::iterator ReducedLatLon::cbegin() const { +Grid::iterator ReducedLL::cbegin() const { return iterator{new geo::iterator::Reduced(*this, 0)}; } -Grid::iterator ReducedLatLon::cend() const { +Grid::iterator ReducedLL::cend() const { return iterator{new geo::iterator::Reduced(*this, size())}; } -size_t ReducedLatLon::ni(size_t j) const { +size_t ReducedLL::ni(size_t j) const { NOTIMP; } -size_t ReducedLatLon::nj() const { +size_t ReducedLL::nj() const { NOTIMP; } -const std::vector& ReducedLatLon::latitudes() const { +const std::vector& ReducedLL::latitudes() const { NOTIMP; } -std::vector ReducedLatLon::longitudes(size_t j) const { +std::vector ReducedLL::longitudes(size_t j) const { NOTIMP; } diff --git a/src/eckit/geo/grid/reduced/ReducedLatLon.h b/src/eckit/geo/grid/reduced/ReducedLL.h similarity index 93% rename from src/eckit/geo/grid/reduced/ReducedLatLon.h rename to src/eckit/geo/grid/reduced/ReducedLL.h index 8fc6b306e..3d826bbe4 100644 --- a/src/eckit/geo/grid/reduced/ReducedLatLon.h +++ b/src/eckit/geo/grid/reduced/ReducedLL.h @@ -18,7 +18,7 @@ namespace eckit::geo::grid::reduced { -class ReducedLatLon : public Reduced { +class ReducedLL : public Reduced { public: // -- Types // None @@ -28,7 +28,7 @@ class ReducedLatLon : public Reduced { // -- Constructors - explicit ReducedLatLon(const Configuration&); + explicit ReducedLL(const Configuration&); // -- Destructor // None diff --git a/src/eckit/geo/grid/regular/IrregularLatLon.cc b/src/eckit/geo/grid/regular/IrregularLL.cc similarity index 59% rename from src/eckit/geo/grid/regular/IrregularLatLon.cc rename to src/eckit/geo/grid/regular/IrregularLL.cc index 011c74b54..89f83f60c 100644 --- a/src/eckit/geo/grid/regular/IrregularLatLon.cc +++ b/src/eckit/geo/grid/regular/IrregularLL.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/regular/IrregularLatLon.h" +#include "eckit/geo/grid/regular/IrregularLL.h" // #include <> @@ -18,36 +18,36 @@ namespace eckit::geo::grid::regular { -IrregularLatLon::IrregularLatLon(const Configuration& config) : +IrregularLL::IrregularLL(const Configuration& config) : Regular(config) {} -Grid::iterator IrregularLatLon::cbegin() const { +Grid::iterator IrregularLL::cbegin() const { NOTIMP; } -Grid::iterator IrregularLatLon::cend() const { +Grid::iterator IrregularLL::cend() const { NOTIMP; } -size_t IrregularLatLon::ni() const { +size_t IrregularLL::ni() const { NOTIMP; } -size_t IrregularLatLon::nj() const { +size_t IrregularLL::nj() const { NOTIMP; } -const std::vector& IrregularLatLon::longitudes() const { +const std::vector& IrregularLL::longitudes() const { NOTIMP; } -const std::vector& IrregularLatLon::latitudes() const { +const std::vector& IrregularLL::latitudes() const { NOTIMP; } diff --git a/src/eckit/geo/grid/regular/IrregularLatLon.h b/src/eckit/geo/grid/regular/IrregularLL.h similarity index 93% rename from src/eckit/geo/grid/regular/IrregularLatLon.h rename to src/eckit/geo/grid/regular/IrregularLL.h index 47db1c1f3..c8b8edd91 100644 --- a/src/eckit/geo/grid/regular/IrregularLatLon.h +++ b/src/eckit/geo/grid/regular/IrregularLL.h @@ -18,7 +18,7 @@ namespace eckit::geo::grid::regular { -class IrregularLatLon final : public Regular { +class IrregularLL final : public Regular { public: // -- Types // None @@ -28,7 +28,7 @@ class IrregularLatLon final : public Regular { // -- Constructors - explicit IrregularLatLon(const Configuration&); + explicit IrregularLL(const Configuration&); // -- Destructor // None diff --git a/src/eckit/geo/grid/regular/RegularLatLon.cc b/src/eckit/geo/grid/regular/RegularLL.cc similarity index 58% rename from src/eckit/geo/grid/regular/RegularLatLon.cc rename to src/eckit/geo/grid/regular/RegularLL.cc index 97815ee1f..54af68f3c 100644 --- a/src/eckit/geo/grid/regular/RegularLatLon.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/regular/RegularLatLon.h" +#include "eckit/geo/grid/regular/RegularLL.h" #include "eckit/config/MappedConfiguration.h" #include "eckit/geo/Increments.h" @@ -22,43 +22,43 @@ namespace eckit::geo::grid::regular { -RegularLatLon::RegularLatLon(const Configuration& config) : - RegularLatLon({config.getDouble("west_east_increment"), config.getDouble("south_north_increment")}, - area::BoundingBox(config), - {config.getDouble("west", 0.), config.getDouble("south", -90.)}) {} +RegularLL::RegularLL(const Configuration& config) : + RegularLL({config.getDouble("west_east_increment"), config.getDouble("south_north_increment")}, + area::BoundingBox(config), + {config.getDouble("west", 0.), config.getDouble("south", -90.)}) {} -RegularLatLon::RegularLatLon(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& reference) : +RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& reference) : Regular(bbox) {} -RegularLatLon::RegularLatLon(size_t ni, size_t nj, const area::BoundingBox& bbox, const PointLonLat& reference) : +RegularLL::RegularLL(size_t ni, size_t nj, const area::BoundingBox& bbox, const PointLonLat& reference) : Regular(bbox), ni_(ni), nj_(nj) {} -RegularLatLon::RegularLatLon(const Increments& inc, const PointLonLat& reference) : - RegularLatLon(inc, area::BoundingBox::make_global_prime(), reference) {} +RegularLL::RegularLL(const Increments& inc, const PointLonLat& reference) : + RegularLL(inc, area::BoundingBox::make_global_prime(), reference) {} -RegularLatLon::RegularLatLon(size_t ni, size_t nj, const PointLonLat& reference) : - RegularLatLon(ni, nj, area::BoundingBox::make_global_prime(), reference) {} +RegularLL::RegularLL(size_t ni, size_t nj, const PointLonLat& reference) : + RegularLL(ni, nj, area::BoundingBox::make_global_prime(), reference) {} -Grid::iterator RegularLatLon::cbegin() const { +Grid::iterator RegularLL::cbegin() const { return iterator{new geo::iterator::Regular(*this, 0)}; } -Grid::iterator RegularLatLon::cend() const { +Grid::iterator RegularLL::cend() const { return iterator{new geo::iterator::Regular(*this, size())}; } -const std::vector& RegularLatLon::longitudes() const { +const std::vector& RegularLL::longitudes() const { NOTIMP; } -const std::vector& RegularLatLon::latitudes() const { +const std::vector& RegularLL::latitudes() const { NOTIMP; } @@ -66,7 +66,7 @@ const std::vector& RegularLatLon::latitudes() const { #define POSITIVE_REAL "[+]?([0-9]*[.])?[0-9]+([eE][-+][0-9]+)?" -Configuration* RegularLatLon::config(const std::string& name) { +Configuration* RegularLL::config(const std::string& name) { static const std::string pattern("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); auto match = util::regex_match(pattern, name); @@ -88,8 +88,8 @@ Configuration* RegularLatLon::config(const std::string& name) { } -static const GridRegisterType __grid_type("regular_ll"); -static const GridRegisterName __grid_pattern(POSITIVE_REAL "/" POSITIVE_REAL); +static const GridRegisterType __grid_type("regular_ll"); +static const GridRegisterName __grid_pattern(POSITIVE_REAL "/" POSITIVE_REAL); } // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/grid/regular/RegularLatLon.h b/src/eckit/geo/grid/regular/RegularLL.h similarity index 75% rename from src/eckit/geo/grid/regular/RegularLatLon.h rename to src/eckit/geo/grid/regular/RegularLL.h index 1a63ac6f4..93ecb1e37 100644 --- a/src/eckit/geo/grid/regular/RegularLatLon.h +++ b/src/eckit/geo/grid/regular/RegularLL.h @@ -23,7 +23,7 @@ class Increments; namespace eckit::geo::grid::regular { -class RegularLatLon final : public Regular { +class RegularLL final : public Regular { public: // -- Types // None @@ -33,13 +33,13 @@ class RegularLatLon final : public Regular { // -- Constructors - explicit RegularLatLon(const Configuration&); + explicit RegularLL(const Configuration&); - RegularLatLon(const Increments&, const area::BoundingBox&, const PointLonLat& reference = {0, 0}); - RegularLatLon(size_t ni, size_t nj, const area::BoundingBox&, const PointLonLat& reference = {0, 0}); + RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& reference = {0, 0}); + RegularLL(size_t ni, size_t nj, const area::BoundingBox&, const PointLonLat& reference = {0, 0}); - explicit RegularLatLon(const Increments&, const PointLonLat& reference = {0, 0}); - RegularLatLon(size_t ni, size_t nj, const PointLonLat& reference = {0, 0}); + explicit RegularLL(const Increments&, const PointLonLat& reference = {0, 0}); + RegularLL(size_t ni, size_t nj, const PointLonLat& reference = {0, 0}); // -- Destructor // None From d341943599b35789a646a189ba339f91cf24be53 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 29 Sep 2023 11:50:46 +0100 Subject: [PATCH 331/737] eckit::config test_configuration --- tests/config/test_configuration.cc | 75 +++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/tests/config/test_configuration.cc b/tests/config/test_configuration.cc index d2ff38726..9b80b78d1 100644 --- a/tests/config/test_configuration.cc +++ b/tests/config/test_configuration.cc @@ -15,8 +15,8 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/config/YAMLConfiguration.h" #include "eckit/filesystem/PathName.h" -#include "eckit/log/Log.h" #include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" #include "eckit/types/Types.h" #include "eckit/utils/Hash.h" @@ -407,6 +407,72 @@ CASE("Hash a configuration") { //---------------------------------------------------------------------------------------------------------------------- +CASE("test_mapped_configuration") { + int one = 1; + MappedConfiguration a({ + {"double", static_cast(one)}, + {"float", static_cast(one)}, + {"int", static_cast(one)}, + {"long", static_cast(one)}, + {"size_t", static_cast(one)}, + }); + + // test scalar type conversion + for (std::string key : {"double", "float", "int", "long", "size_t"}) { + double value_as_double = 0; + float value_as_float = 0; + + EXPECT(a.get(key, value_as_double) && value_as_double == static_cast(one)); + EXPECT(a.get(key, value_as_float) && value_as_float == static_cast(one)); + + if (key == "int" || key == "long" || key == "size_t") { + int value_as_int = 0; + long value_as_long = 0; + size_t value_as_size_t = 0; + + EXPECT(a.get(key, value_as_int) && value_as_int == static_cast(one)); + EXPECT(a.get(key, value_as_long) && value_as_long == static_cast(one)); + EXPECT(a.get(key, value_as_size_t) && value_as_size_t == static_cast(one)); + } + + EXPECT_EQUAL(a.getString(key), std::to_string(1)); + } + + + MappedConfiguration b({ + {"true", true}, + {"false", false}, + {"zero", 0}, + {"one", 1}, + }); + + EXPECT(b.getBool("true")); + EXPECT(!b.getBool("false")); + + bool maybe = false; + EXPECT(!b.has("?")); + EXPECT(!b.getBool("?", false)); + EXPECT(b.getBool("?", true)); + + EXPECT(b.get("true", maybe = false) && maybe); + EXPECT(b.getBool("true", true)); + EXPECT(b.getBool("true", false)); + + EXPECT(b.get("false", maybe = true) && !maybe); + EXPECT(!b.getBool("false", true)); + EXPECT(!b.getBool("false", false)); + + EXPECT(!b.getBool("zero")); + EXPECT(!b.getBool("zero", maybe = true)); + EXPECT(b.get("zero", maybe = true) && !maybe); + + EXPECT(b.getBool("one")); + EXPECT(b.getBool("one", maybe = false)); + EXPECT(b.get("one", maybe = false) && maybe); +} + +//---------------------------------------------------------------------------------------------------------------------- + CASE("test_dynamic_configuration") { double one = 1.; int two = 2; @@ -417,10 +483,13 @@ CASE("test_dynamic_configuration") { a.set("foo", one); EXPECT(a.has("foo")); + EXPECT_THROWS_AS(a.getInt("foo"), eckit::ConfigurationNotFound); // cannot access as int + EXPECT(a.getString("foo") == "1"); a.set("bar", two); EXPECT_EQUAL(a.getInt("bar"), two); - EXPECT_THROWS_AS(a.getString("bar"), std::bad_variant_access); + EXPECT(::eckit::types::is_approximately_equal(a.getDouble("bar"), static_cast(two))); + EXPECT(a.getString("bar") == "2"); a.set("foo", three); EXPECT_EQUAL(a.getString("foo"), three); @@ -429,6 +498,8 @@ CASE("test_dynamic_configuration") { EXPECT(b.has("foo")); EXPECT_EQUAL(b.getString("foo"), three); + EXPECT_THROWS_AS(b.getInt("foo"), eckit::ConfigurationNotFound); // cannot access as int + EXPECT_THROWS_AS(b.getDouble("foo"), eckit::ConfigurationNotFound); // cannot access as real b.set("foo", two); EXPECT_EQUAL(b.getInt("foo"), two); From 6e27bb68985b494e443eca7d2113e55ab0ca3992 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 2 Oct 2023 09:01:21 +0100 Subject: [PATCH 332/737] eckit::config test_configuration --- tests/config/test_configuration.cc | 78 +++++++++++------------------- 1 file changed, 28 insertions(+), 50 deletions(-) diff --git a/tests/config/test_configuration.cc b/tests/config/test_configuration.cc index 9b80b78d1..27792635f 100644 --- a/tests/config/test_configuration.cc +++ b/tests/config/test_configuration.cc @@ -17,62 +17,40 @@ #include "eckit/filesystem/PathName.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" -#include "eckit/types/Types.h" #include "eckit/utils/Hash.h" -using namespace eckit; -using namespace eckit::testing; - namespace eckit::test { //---------------------------------------------------------------------------------------------------------------------- -template -std::vector make_vector(const T& t1, const T& t2) { - std::vector result; - result.push_back(t1); - result.push_back(t2); - return result; -} -template -std::vector make_vector(const T& t1, const T& t2, const T& t3) { - std::vector result; - result.push_back(t1); - result.push_back(t2); - result.push_back(t3); - return result; -} - -//---------------------------------------------------------------------------------------------------------------------- - CASE("test_configuration_interface") { - bool value_bool = bool(true); - int value_int = int(1); - long value_long = long(2); - long long value_long_long = 2ll; - size_t value_size_t = size_t(3); - float value_float = float(1.234567); - double value_double = double(1.2345678912345789123456789); - std::string value_string = std::string("string"); - std::vector value_arr_int = make_vector(1, 2, 3); - std::vector value_arr_long = make_vector(4l, 5l); - std::vector value_arr_long_long = make_vector(4ll, 5ll); - std::vector value_arr_size_t = make_vector(std::size_t{6}, std::size_t{7}); - std::vector value_arr_float = make_vector(1.234567f, 2.345678f); - std::vector value_arr_double = make_vector(1.234567, 2.345678); - std::vector value_arr_string = make_vector(std::string("hello"), std::string("world")); + bool value_bool = true; + int value_int = 1; + long value_long = 2; + long long value_long_long = 2; + size_t value_size_t = 3; + float value_float = 1.234567; + double value_double = 1.2345678912345789123456789; + std::string value_string = "string"; + std::vector value_arr_int = {1, 2, 3}; + std::vector value_arr_long = {4, 5}; + std::vector value_arr_long_long = {4, 5}; + std::vector value_arr_size_t = {6, 7}; + std::vector value_arr_float = {1.234567, 2.345678}; + std::vector value_arr_double = {1.234567, 2.345678}; + std::vector value_arr_string = {"hello", "world"}; std::int32_t value_int32 = value_int; std::int64_t value_int64 = value_long_long; - std::vector value_arr_int32{4, 5}; - std::vector value_arr_int64{4ll, 5ll}; - - bool result_bool; - int result_int; - long result_long; - long long result_long_long; - size_t result_size_t; - float result_float; - double result_double; + std::vector value_arr_int32 = {4, 5}; + std::vector value_arr_int64 = {4, 5}; + + bool result_bool = false; + int result_int = 0; + long result_long = 0; + long long result_long_long = 0; + size_t result_size_t = 0; + float result_float = 0; + double result_double = 0; std::string result_string; std::vector result_arr_int; std::vector result_arr_long; @@ -81,8 +59,8 @@ CASE("test_configuration_interface") { std::vector result_arr_float; std::vector result_arr_double; std::vector result_arr_string; - std::int32_t result_int32; - std::int64_t result_int64; + std::int32_t result_int32 = 0; + std::int64_t result_int64 = 0; std::vector result_arr_int32; std::vector result_arr_int64; @@ -521,5 +499,5 @@ CASE("test_dynamic_configuration") { } // namespace eckit::test int main(int argc, char** argv) { - return run_tests(argc, argv); + return eckit::testing::run_tests(argc, argv); } From a333fa8f709f9e7be3ecbc7bb8dd0b9d634da7ee Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 29 Sep 2023 11:50:54 +0100 Subject: [PATCH 333/737] eckit::config --- src/eckit/config/Configuration.cc | 14 +++++--------- src/eckit/config/Configuration.h | 9 +++++++++ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/eckit/config/Configuration.cc b/src/eckit/config/Configuration.cc index 4e47d3b03..732c2da9c 100644 --- a/src/eckit/config/Configuration.cc +++ b/src/eckit/config/Configuration.cc @@ -14,7 +14,6 @@ #include "eckit/config/Configuration.h" #include "eckit/config/LocalConfiguration.h" -#include "eckit/exception/Exceptions.h" #include "eckit/log/JSON.h" #include "eckit/utils/Tokenizer.h" #include "eckit/value/Value.h" @@ -23,14 +22,11 @@ namespace eckit { //---------------------------------------------------------------------------------------------------------------------- -class ConfigurationNotFound : public Exception { -public: - ConfigurationNotFound(const std::string& name) { - std::ostringstream s; - s << "ConfigurationNotFound: [" << name << "]"; - reason(s.str()); - } -}; +ConfigurationNotFound::ConfigurationNotFound(const std::string& name) { + std::ostringstream s; + s << "ConfigurationNotFound: [" << name << "]"; + reason(s.str()); +} //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/config/Configuration.h b/src/eckit/config/Configuration.h index 86d765aa4..03f9fbc50 100644 --- a/src/eckit/config/Configuration.h +++ b/src/eckit/config/Configuration.h @@ -18,13 +18,22 @@ #include #include + #include "eckit/config/Parametrisation.h" +#include "eckit/exception/Exceptions.h" namespace eckit { //---------------------------------------------------------------------------------------------------------------------- +class ConfigurationNotFound : public Exception { +public: + explicit ConfigurationNotFound(const std::string& name); +}; + +//---------------------------------------------------------------------------------------------------------------------- + class LocalConfiguration; class JSON; class Value; From 9f71c52c71494ae8cb4fbc2977485a9921c47ce2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 2 Oct 2023 17:36:10 +0100 Subject: [PATCH 334/737] eckit::config DynamicConfiguration --- src/eckit/config/DynamicConfiguration.cc | 175 +++-------------------- src/eckit/config/DynamicConfiguration.h | 96 ++++++------- 2 files changed, 65 insertions(+), 206 deletions(-) diff --git a/src/eckit/config/DynamicConfiguration.cc b/src/eckit/config/DynamicConfiguration.cc index 5bb84f640..e5281b23b 100644 --- a/src/eckit/config/DynamicConfiguration.cc +++ b/src/eckit/config/DynamicConfiguration.cc @@ -11,6 +11,7 @@ #include "eckit/config/DynamicConfiguration.h" #include "eckit/config/LocalConfiguration.h" +#include "eckit/exception/Exceptions.h" #include "eckit/value/Value.h" namespace eckit { @@ -32,83 +33,8 @@ DynamicConfiguration::DynamicConfiguration() : DynamicConfiguration(__empty_configuration) {} -DynamicConfiguration::DynamicConfiguration(const Configuration& passive) : - Configuration(__empty_root), passive_(passive) {} - - -void DynamicConfiguration::set(const std::string& name, const std::string& value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, bool value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, int value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, long value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, long long value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, std::size_t value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, float value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, double value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, const std::vector& value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, const std::vector& value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, const std::vector& value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, const std::vector& value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, const std::vector& value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, const std::vector& value) { - __set(*this, name, value); -} - - -void DynamicConfiguration::set(const std::string& name, const std::vector& value) { - __set(*this, name, value); -} +DynamicConfiguration::DynamicConfiguration(const Configuration& config) : + Configuration(__empty_root), config_(config) {} void DynamicConfiguration::hide(const std::string& name) { @@ -121,88 +47,33 @@ void DynamicConfiguration::unhide(const std::string& name) { } -bool DynamicConfiguration::has(const std::string& name) const { - return !hide_.contains(name) && (active_.has(name) || passive_.has(name)); -} - - -bool DynamicConfiguration::get(const std::string& name, std::string& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, bool& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, int& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, long& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, long long& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, std::size_t& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, float& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, double& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return __get(*this, name, value); -} - - -bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return __get(*this, name, value); +void DynamicConfiguration::push_back(Configuration* config) { + ASSERT(config != nullptr); + configs_.emplace_back(config); } -bool DynamicConfiguration::get(const std::string& name, std::vector& value) const { - return __get(*this, name, value); +void DynamicConfiguration::push_front(Configuration* config) { + ASSERT(config != nullptr); + configs_.emplace_front(config); } void DynamicConfiguration::print(std::ostream& out) const { - out << "DynamicConfiguration[active=" << active_ << ",passive=" << passive_ << "]"; + const auto* sep = ""; + out << "DynamicConfiguration[hide["; + for (const auto& name : hide_) { + out << sep << name; + sep = ","; + } + + sep = ""; + out << "],config=" << config_ << ",configs["; + for (const auto& config : configs_) { + out << sep << *config; + sep = ","; + } + out << "]]"; } diff --git a/src/eckit/config/DynamicConfiguration.h b/src/eckit/config/DynamicConfiguration.h index 124cbacd5..37dbb1b00 100644 --- a/src/eckit/config/DynamicConfiguration.h +++ b/src/eckit/config/DynamicConfiguration.h @@ -11,10 +11,12 @@ #ifndef eckit_DynamicConfiguration_H #define eckit_DynamicConfiguration_H +#include +#include +#include #include #include "eckit/config/Configuration.h" -#include "eckit/config/MappedConfiguration.h" namespace eckit { @@ -44,48 +46,36 @@ class DynamicConfiguration : public Configuration { // -- Methods - // (consistent with Configured) - void set(const std::string&, const std::string&); - void set(const std::string&, bool); - void set(const std::string&, int); - void set(const std::string&, long); - void set(const std::string&, long long); - void set(const std::string&, std::size_t); - void set(const std::string&, float); - void set(const std::string&, double); - - // (consistent with Configured) - void set(const std::string&, const std::vector&); - void set(const std::string&, const std::vector&); - void set(const std::string&, const std::vector&); - void set(const std::string&, const std::vector&); - void set(const std::string&, const std::vector&); - void set(const std::string&, const std::vector&); - void set(const std::string&, const std::vector&); - void hide(const std::string&); void unhide(const std::string&); + void push_back(Configuration*); + void push_front(Configuration*); // -- Overridden methods - bool has(const std::string&) const override; - - bool get(const std::string&, std::string&) const override; - bool get(const std::string&, bool&) const override; - bool get(const std::string&, int&) const override; - bool get(const std::string&, long&) const override; - bool get(const std::string&, long long&) const override; - bool get(const std::string&, std::size_t&) const override; - bool get(const std::string&, float&) const override; - bool get(const std::string&, double&) const override; - - bool get(const std::string&, std::vector&) const override; - bool get(const std::string&, std::vector&) const override; - bool get(const std::string&, std::vector&) const override; - bool get(const std::string&, std::vector&) const override; - bool get(const std::string&, std::vector&) const override; - bool get(const std::string&, std::vector&) const override; - bool get(const std::string&, std::vector&) const override; + bool has(const std::string& name) const override { + return !hide_.contains(name) && + (config_.has(name) || + std::any_of(configs_.begin(), configs_.end(), [&](const decltype(configs_)::value_type& c) { + return c->has(name); + })); + } + + bool get(const std::string& name, std::string& value) const override { return __get(name, value); } + bool get(const std::string& name, bool& value) const override { return __get(name, value); } + bool get(const std::string& name, int& value) const override { return __get(name, value); } + bool get(const std::string& name, long& value) const override { return __get(name, value); } + bool get(const std::string& name, long long& value) const override { return __get(name, value); } + bool get(const std::string& name, std::size_t& value) const override { return __get(name, value); } + bool get(const std::string& name, float& value) const override { return __get(name, value); } + bool get(const std::string& name, double& value) const override { return __get(name, value); } + bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } + bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } + bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } + bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } + bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } + bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } + bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } // -- Class members // None @@ -96,15 +86,23 @@ class DynamicConfiguration : public Configuration { private: // -- Members - const Configuration& passive_; - MappedConfiguration active_; - struct : std::unordered_set { - bool contains(const value_type& key) const { return find(key) != end(); } + bool contains(const value_type& name) const { return find(name) != end(); } } hide_; + const Configuration& config_; + std::deque> configs_; + // -- Methods - // None + + template + bool __get(const std::string& name, T& value) const { + return !hide_.contains(name) && + (config_.get(name, value) || + std::any_of(configs_.begin(), configs_.end(), [&](const decltype(configs_)::value_type& c) { + return c->get(name, value); + })); + } // -- Overridden methods @@ -117,17 +115,7 @@ class DynamicConfiguration : public Configuration { // None // -- Friends - - template - friend void __set(DynamicConfiguration& config, const std::string& name, T& value) { - config.active_.set(name, value); - config.hide_.erase(name); - } - - template - friend bool __get(const DynamicConfiguration& config, const std::string& name, T& value) { - return !config.hide_.contains(name) && (config.active_.get(name, value) || config.passive_.get(name, value)); - } + // None }; //---------------------------------------------------------------------------------------------------------------------- From 875fc465b2035f0ddb71c7634ded73f80b17541a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 29 Sep 2023 11:50:54 +0100 Subject: [PATCH 335/737] eckit::config MappedConfiguration --- src/eckit/config/MappedConfiguration.cc | 45 +++++++++++++++---------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/eckit/config/MappedConfiguration.cc b/src/eckit/config/MappedConfiguration.cc index 13140e0e8..7ea0d16a0 100644 --- a/src/eckit/config/MappedConfiguration.cc +++ b/src/eckit/config/MappedConfiguration.cc @@ -71,11 +71,15 @@ bool __get_s_integral(const MappedConfiguration::container_type& map, const std: template bool __get_s_real(const MappedConfiguration::container_type& map, const std::string& name, T& value) { + if (__get_s_integral(map, name, value)) { + return true; + } + if (auto it = map.find(name); it != map.cend()) { const auto& v = it->second; - return std::holds_alternative(v) ? __get_s(std::get(v), value) - : std::holds_alternative(v) ? __get_s(std::get(v), value) - : false; + return std::holds_alternative(v) ? __get_s(std::get(v), value) + : std::holds_alternative(v) ? __get_s(std::get(v), value) + : false; } return false; } @@ -85,11 +89,12 @@ template bool __get_v_integral(const MappedConfiguration::container_type& map, const std::string& name, T& value) { if (auto it = map.find(name); it != map.cend()) { const auto& v = it->second; - return std::holds_alternative>(v) ? __get_v(std::get>(v), value) - : std::holds_alternative>(v) ? __get_v(std::get>(v), value) - : std::holds_alternative>(v) ? __get_v(std::get>(v), value) - : std::holds_alternative>(v) ? __get_v(std::get>(v), value) - : false; + return std::holds_alternative>(v) ? __get_v(std::get>(v), value) + : std::holds_alternative>(v) ? __get_v(std::get>(v), value) + : std::holds_alternative>(v) ? __get_v(std::get>(v), value) + : std::holds_alternative>(v) + ? __get_v(std::get>(v), value) + : false; } return false; } @@ -97,11 +102,15 @@ bool __get_v_integral(const MappedConfiguration::container_type& map, const std: template bool __get_v_real(const MappedConfiguration::container_type& map, const std::string& name, T& value) { + if (__get_v_integral(map, name, value)) { + return true; + } + if (auto it = map.find(name); it != map.cend()) { const auto& v = it->second; - return std::holds_alternative>(v) ? __get_v(std::get>(v), value) - : std::holds_alternative>(v) ? __get_v(std::get>(v), value) - : false; + return std::holds_alternative>(v) ? __get_v(std::get>(v), value) + : std::holds_alternative>(v) ? __get_v(std::get>(v), value) + : false; } return false; } @@ -117,13 +126,11 @@ JSON& operator<<(JSON& out, const MappedConfiguration::value_type& value) { MappedConfiguration::MappedConfiguration(const MappedConfiguration::container_type& map) : - Configuration(__empty_root), - map_(map) {} + Configuration(__empty_root), map_(map) {} MappedConfiguration::MappedConfiguration(MappedConfiguration::container_type&& map) : - Configuration(__empty_root), - map_(map) {} + Configuration(__empty_root), map_(map) {} MappedConfiguration::MappedConfiguration(const MappedConfiguration& config) : @@ -228,8 +235,10 @@ bool MappedConfiguration::has(const std::string& name) const { bool MappedConfiguration::get(const std::string& name, std::string& value) const { if (auto it = map_.find(name); it != map_.cend()) { - value = std::holds_alternative(it->second) ? std::get(it->second) - : std::visit([](auto&& arg) -> std::string { return (std::ostringstream() << arg).str(); }, it->second); + value = + std::holds_alternative(it->second) + ? std::get(it->second) + : std::visit([](auto&& arg) -> std::string { return (std::ostringstream() << arg).str(); }, it->second); return true; } return false; @@ -239,7 +248,7 @@ bool MappedConfiguration::get(const std::string& name, std::string& value) const bool MappedConfiguration::get(const std::string& name, bool& value) const { if (auto it = map_.find(name); it != map_.cend()) { if (std::holds_alternative(it->second)) { - std::get(it->second); + value = std::get(it->second); return true; } From 75773ee8659f7cf87b0aa9160e20d9c9f305eaf7 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 4 Oct 2023 17:30:33 +0100 Subject: [PATCH 336/737] eckit::config MappedConfiguration disable automatic conversion of values to string --- src/eckit/config/MappedConfiguration.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/eckit/config/MappedConfiguration.cc b/src/eckit/config/MappedConfiguration.cc index 7ea0d16a0..6d99094dc 100644 --- a/src/eckit/config/MappedConfiguration.cc +++ b/src/eckit/config/MappedConfiguration.cc @@ -234,11 +234,8 @@ bool MappedConfiguration::has(const std::string& name) const { bool MappedConfiguration::get(const std::string& name, std::string& value) const { - if (auto it = map_.find(name); it != map_.cend()) { - value = - std::holds_alternative(it->second) - ? std::get(it->second) - : std::visit([](auto&& arg) -> std::string { return (std::ostringstream() << arg).str(); }, it->second); + if (auto it = map_.find(name); it != map_.cend() && std::holds_alternative(it->second)) { + value = std::get(it->second); return true; } return false; From 7ba45190ed95f1c0ae47421d2245ea5231174b11 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 4 Oct 2023 17:39:26 +0100 Subject: [PATCH 337/737] eckit::config MappedConfiguration --- src/eckit/config/MappedConfiguration.h | 38 +++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/eckit/config/MappedConfiguration.h b/src/eckit/config/MappedConfiguration.h index db861284c..4a6739467 100644 --- a/src/eckit/config/MappedConfiguration.h +++ b/src/eckit/config/MappedConfiguration.h @@ -24,25 +24,23 @@ class MappedConfiguration final : public Configuration { public: // -- Types - using value_type = std::variant< - std::string, - bool, - int, - long, - long long, - std::size_t, - float, - double, - std::vector, - std::vector, - std::vector, - std::vector, - std::vector, - std::vector, - std::vector>; - - using container_type = std::map; + using value_type = std::variant, + std::vector, + std::vector, + std::vector, + std::vector, + std::vector, + std::vector>; + + using container_type = std::map; // -- Exceptions // None @@ -68,6 +66,8 @@ class MappedConfiguration final : public Configuration { // -- Methods + bool empty() const { return map_.empty(); } + // (consistent with Configured) void set(const std::string&, const std::string&); void set(const std::string&, bool); From 940ca9abe922eda644817e3ddbf187623adb40b3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 4 Oct 2023 17:39:41 +0100 Subject: [PATCH 338/737] eckit::config MappedConfiguration --- src/eckit/config/MappedConfiguration.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/eckit/config/MappedConfiguration.h b/src/eckit/config/MappedConfiguration.h index 4a6739467..14341669b 100644 --- a/src/eckit/config/MappedConfiguration.h +++ b/src/eckit/config/MappedConfiguration.h @@ -67,6 +67,9 @@ class MappedConfiguration final : public Configuration { // -- Methods bool empty() const { return map_.empty(); } + void clear() { map_.clear(); } + + void set(const std::string& name, const char* value) { set(name, std::string{value}); } // (consistent with Configured) void set(const std::string&, const std::string&); From 98c0f9ed6be248086fa9f16e3da3298522181394 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 29 Sep 2023 11:51:26 +0100 Subject: [PATCH 339/737] eckit::geo::grid::regular::RegularLL --- src/eckit/geo/grid/regular/RegularLL.cc | 101 +++++++++++++++++++++--- src/eckit/geo/grid/regular/RegularLL.h | 1 + tests/geo/test_grid.cc | 12 ++- 3 files changed, 104 insertions(+), 10 deletions(-) diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index 54af68f3c..2ebebff53 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -13,35 +13,118 @@ #include "eckit/geo/grid/regular/RegularLL.h" #include "eckit/config/MappedConfiguration.h" +#include "eckit/exception/Exceptions.h" #include "eckit/geo/Increments.h" #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/util/regex.h" +#include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" namespace eckit::geo::grid::regular { +namespace { + + +struct DiscreteRange { + DiscreteRange(double _a, double _b, double _inc, double _ref) : + DiscreteRange(Fraction{_a}, Fraction{_b}, Fraction{_inc}, Fraction{_ref}) {} + + DiscreteRange(double _a, double _b, double _inc, double _ref, double period) : + DiscreteRange(Fraction{_a}, Fraction{_b}, Fraction{_inc}, Fraction{_ref}, Fraction{period}) {} + + DiscreteRange(const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref) : + inc(_inc) { + ASSERT(_a <= _b); + ASSERT(_inc >= 0); + + auto adjust = [](const Fraction& target, const Fraction& inc, bool up) -> Fraction { + ASSERT(inc > 0); + + auto r = target / inc; + auto n = r.integralPart(); + + if (!r.integer() && (r > 0) == up) { + n += (up ? 1 : -1); + } + + return n * inc; + }; + + if (inc == 0) { + b = a = _a; + n = 1; + } + else { + auto shift = (_ref / inc).decimalPart() * _inc; + a = shift + adjust(_a - shift, inc, true); + + if (_b == _a) { + b = a; + } + else { + auto c = shift + adjust(_b - shift, inc, false); + c = a + ((c - a) / inc).integralPart() * inc; + b = c < a ? a : c; + } + + n = static_cast(((b - a) / inc).integralPart() + 1); + } + + ASSERT(a <= b); + ASSERT(n >= 1); + } + + DiscreteRange( + const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref, const Fraction& period) : + DiscreteRange(_a, _b, _inc, _ref) { + ASSERT(period > 0); + + if ((n - 1) * inc >= period) { + n -= 1; + ASSERT(n * inc == period || (n - 1) * inc < period); + + b = a + (n - 1) * inc; + } + } + + Fraction a; + Fraction b; + Fraction inc; + size_t n; +}; + + +} // namespace + + RegularLL::RegularLL(const Configuration& config) : RegularLL({config.getDouble("west_east_increment"), config.getDouble("south_north_increment")}, area::BoundingBox(config), - {config.getDouble("west", 0.), config.getDouble("south", -90.)}) {} + {config.getDouble("west", 0), config.getDouble("south", 0)}) {} -RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& reference) : - Regular(bbox) {} +RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& ref) : + Regular(bbox), + ni_(DiscreteRange(bbox.west(), bbox.east(), inc.west_east, ref.lon, 360).n), + nj_(DiscreteRange(bbox.south(), bbox.north(), inc.south_north, ref.lat).n), + reference_(ref) { + ASSERT(ni_ > 0); + ASSERT(nj_ > 0); +} -RegularLL::RegularLL(size_t ni, size_t nj, const area::BoundingBox& bbox, const PointLonLat& reference) : - Regular(bbox), ni_(ni), nj_(nj) {} +RegularLL::RegularLL(size_t ni, size_t nj, const area::BoundingBox& bbox, const PointLonLat& ref) : + Regular(bbox), ni_(ni), nj_(nj), reference_(ref) {} -RegularLL::RegularLL(const Increments& inc, const PointLonLat& reference) : - RegularLL(inc, area::BoundingBox::make_global_prime(), reference) {} +RegularLL::RegularLL(const Increments& inc, const PointLonLat& ref) : + RegularLL(inc, area::BoundingBox::make_global_prime(), ref) {} -RegularLL::RegularLL(size_t ni, size_t nj, const PointLonLat& reference) : - RegularLL(ni, nj, area::BoundingBox::make_global_prime(), reference) {} +RegularLL::RegularLL(size_t ni, size_t nj, const PointLonLat& ref) : + RegularLL(ni, nj, area::BoundingBox::make_global_prime(), ref) {} Grid::iterator RegularLL::cbegin() const { diff --git a/src/eckit/geo/grid/regular/RegularLL.h b/src/eckit/geo/grid/regular/RegularLL.h index 93ecb1e37..32d3cadf5 100644 --- a/src/eckit/geo/grid/regular/RegularLL.h +++ b/src/eckit/geo/grid/regular/RegularLL.h @@ -73,6 +73,7 @@ class RegularLL final : public Regular { size_t ni_; size_t nj_; + PointLonLat reference_; // -- Methods // None diff --git a/tests/geo/test_grid.cc b/tests/geo/test_grid.cc index f37e43a4f..0ede51eab 100644 --- a/tests/geo/test_grid.cc +++ b/tests/geo/test_grid.cc @@ -43,7 +43,17 @@ CASE("GridFactory::build") { SECTION("Grid::build_from_uid") {} - SECTION("Grid::build_from_increments") {} + SECTION("Grid::build_from_increments") { + std::unique_ptr cfg(new MappedConfiguration({ + {"type", "regular_ll"}, + {"west_east_increment", 1}, + {"south_north_increment", 1}, + })); + std::unique_ptr grid(geo::GridFactory::build(*cfg)); + + auto size = grid->size(); + EXPECT_EQUAL(size, 360 * 181); + } SECTION("Grid::build") { From fc4831cfd6b8407cb116bade799b2ab7b1d3b795 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 29 Sep 2023 16:33:45 +0100 Subject: [PATCH 340/737] eckit::geo::Range tests --- tests/geo/test_range.cc | 54 +++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/tests/geo/test_range.cc b/tests/geo/test_range.cc index 39a7a64e3..bd0e0ec92 100644 --- a/tests/geo/test_range.cc +++ b/tests/geo/test_range.cc @@ -22,39 +22,45 @@ #define EXPECT_APPROX(a, b) EXPECT(::eckit::types::is_approximately_equal((a), (b), 1e-12)) -int main(int argc, const char* argv[]) { - using namespace eckit::geo::range; +namespace eckit::test { - { - std::vector ref{59.44440828916676, 19.87571914744090, -19.87571914744090, -59.44440828916676}; +CASE("range::Gaussian") { + using geo::range::Gaussian; - auto global = Gaussian(2); - EXPECT(global.size() == ref.size()); + std::vector ref{59.44440828916676, 19.87571914744090, -19.87571914744090, -59.44440828916676}; - size_t i = 0; - for (const auto& test : global.values()) { - EXPECT_APPROX(test, ref[i++]); - } + auto global = Gaussian(2); - auto cropped = Gaussian(2, 50., -50., 1e-3); - EXPECT(cropped.size() == ref.size() - 2); + EXPECT(global.size() == ref.size()); - i = 1; - for (const auto& test : cropped.values()) { - EXPECT_APPROX(test, ref[i++]); - } - - EXPECT(Gaussian(2, 59.444, -59.444, 1e-3).size() == 4); - EXPECT(Gaussian(2, 59.444, -59.444, 1e-6).size() == 2); - EXPECT(Gaussian(2, 59.444, -59.445, 1e-6).size() == 3); + size_t i = 0; + for (const auto& test : global.values()) { + EXPECT_APPROX(test, ref[i++]); + } - auto single = Gaussian(2, -59.444, -59.444, 1e-3); - EXPECT(single.size() == 1); + auto cropped = Gaussian(2, 50., -50., 1e-3); + EXPECT(cropped.size() == ref.size() - 2); - EXPECT_APPROX(single.values().front(), ref.back()); + i = 1; + for (const auto& test : cropped.values()) { + EXPECT_APPROX(test, ref[i++]); } + EXPECT(Gaussian(2, 59.444, -59.444, 1e-3).size() == 4); + EXPECT(Gaussian(2, 59.444, -59.444, 1e-6).size() == 2); + EXPECT(Gaussian(2, 59.444, -59.445, 1e-6).size() == 3); + + auto single = Gaussian(2, -59.444, -59.444, 1e-3); + EXPECT(single.size() == 1); + + EXPECT_APPROX(single.values().front(), ref.back()); +} + + +} // namespace eckit::test + - return 0; +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); } From 48dc030d90660aaa427cdf1cad1da08a87b5730d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 29 Sep 2023 16:33:52 +0100 Subject: [PATCH 341/737] eckit::geo::Range tests fixes --- src/eckit/geo/Range.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 82c9a2882..5f3493d7b 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -25,6 +25,10 @@ namespace eckit::geo { class Range : protected std::vector { +protected: + // -- Types + using P = vector; + public: // -- Types // None @@ -50,13 +54,10 @@ class Range : protected std::vector { Range& operator=(Range&&) = delete; // -- Methods - // None - - using vector::empty; - size_t size() const { return empty() ? n_ : vector::size(); } + size_t size() const { return empty() ? n_ : P::size(); } - virtual const std::vector& values() const = 0; + virtual const P& values() const = 0; // -- Overridden methods // None @@ -78,7 +79,7 @@ class Range : protected std::vector { // -- Methods - virtual const std::vector& valuesVector() const { return *this; } + virtual const P& valuesVector() const { return *this; } // -- Overridden methods // None From 9c1cbf57034f141b7b95840d86d5544764ad90f1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 29 Sep 2023 17:06:15 +0100 Subject: [PATCH 342/737] eckit::geo::projection::Rotation --- src/eckit/geo/projection/Rotation.cc | 6 ++---- src/eckit/geo/util.h | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 0b757957d..66b4bfc3b 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -56,8 +56,6 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : const M R_; }; - constexpr auto eps = 1e-12; - const auto alpha = util::degree_to_radian * angle; const auto theta = util::degree_to_radian * -(south_pole_lat + 90.); const auto phi = util::degree_to_radian * -south_pole_lon; @@ -66,9 +64,9 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : const auto ct = std::cos(theta); const auto cp = std::cos(phi); - if (types::is_approximately_equal(ct, 1., eps)) { + if (types::is_approximately_equal(ct, 1., util::eps)) { angle = PointLonLat::normalise_angle_to_minimum(angle - south_pole_lon, -180.); - rotated_ = !types::is_approximately_equal(angle, 0., eps); + rotated_ = !types::is_approximately_equal(angle, 0., util::eps); fwd_.reset(rotated_ ? static_cast(new RotationAngle(-angle)) : new NonRotated); inv_.reset(rotated_ ? static_cast(new RotationAngle(angle)) : new NonRotated); diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index 224d518cf..83756dc8b 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -33,6 +33,8 @@ namespace util { constexpr double degree_to_radian = M_PI / 180.; constexpr double radian_to_degree = M_1_PI * 180.; +constexpr double eps = 1e-12; + template pl_type pl_convert(const T& pl) { From d6705226306029dba2896fd2f2b2c3d168cfc3ef Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 29 Sep 2023 17:52:08 +0100 Subject: [PATCH 343/737] eckit::geo::grid::RegularGaussian --- src/eckit/geo/CMakeLists.txt | 2 + src/eckit/geo/grid/regular/RegularGaussian.cc | 24 +++--- src/eckit/geo/grid/regular/RegularGaussian.h | 3 +- src/eckit/geo/range/RegularLongitude.cc | 53 ++++++++++++ src/eckit/geo/range/RegularLongitude.h | 80 +++++++++++++++++++ tests/geo/test_grid.cc | 44 ++++++---- 6 files changed, 176 insertions(+), 30 deletions(-) create mode 100644 src/eckit/geo/range/RegularLongitude.cc create mode 100644 src/eckit/geo/range/RegularLongitude.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 3fabe4f7a..d32dde9ff 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -90,6 +90,8 @@ list( APPEND eckit_geo_srcs range/Gaussian.h range/Regular.cc range/Regular.h + range/RegularLongitude.cc + range/RegularLongitude.h util.cc util.h util/arange.cc diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index 3480dc8f5..e70a588ce 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -15,28 +15,28 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/range/Gaussian.h" -#include "eckit/geo/range/Regular.h" +#include "eckit/geo/range/RegularLongitude.h" #include "eckit/utils/Translator.h" namespace eckit::geo::grid::regular { -// Regular(size_t n, double a, double b, bool endpoint, double precision = 0.); RegularGaussian::RegularGaussian(const Configuration& config) : - Regular(config), - ni_(config.getUnsigned("ni", config.getUnsigned("ni"))), - x_(new range::Regular(ni_, config.getDouble("west", 0.), config.getDouble("east", 360.), true /*FIXME*/)), - y_(new range::Gaussian(config.getUnsigned("N"), config.getDouble("north", 90.), config.getDouble("south", -90.))) { - ASSERT(ni_ > 0); -} + RegularGaussian(config.getUnsigned("N"), config.getUnsigned("ni"), area::BoundingBox(config)) {} RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : + RegularGaussian(N, 4 * N, bbox) {} + + +RegularGaussian::RegularGaussian(size_t N, size_t ni, const area::BoundingBox& bbox) : Regular(bbox), - ni_(4 * N), - x_(new range::Regular(ni_, bbox.west(), bbox.east(), true /*FIXME*/)), - y_(new range::Gaussian(N, bbox.west(), bbox.east())) {} + x_(new range::RegularLongitude(ni, bbox.west(), bbox.east())), + y_(new range::Gaussian(N, bbox.north(), bbox.south())) { + ASSERT(x_->size() > 0); + ASSERT(y_->size() > 0); +} Grid::iterator RegularGaussian::cbegin() const { @@ -51,7 +51,7 @@ Grid::iterator RegularGaussian::cend() const { Configuration* RegularGaussian::config(const std::string& name) { auto N = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "regular_gg"}, {"N", N}, {"Ni", 2 * N}, {"Nj", 4 * N}}); + return new MappedConfiguration({{"type", "regular_gg"}, {"N", N}, {"ni", 4 * N}}); } diff --git a/src/eckit/geo/grid/regular/RegularGaussian.h b/src/eckit/geo/grid/regular/RegularGaussian.h index d62ace883..10105244d 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.h +++ b/src/eckit/geo/grid/regular/RegularGaussian.h @@ -31,6 +31,7 @@ class RegularGaussian final : public Regular { explicit RegularGaussian(const Configuration&); explicit RegularGaussian(size_t N, const area::BoundingBox& = area::BoundingBox::make_global_prime()); + RegularGaussian(size_t N, size_t ni, const area::BoundingBox& = area::BoundingBox::make_global_prime()); // -- Destructor // None @@ -62,8 +63,6 @@ class RegularGaussian final : public Regular { private: // -- Members - size_t ni_; - std::unique_ptr x_; std::unique_ptr y_; diff --git a/src/eckit/geo/range/RegularLongitude.cc b/src/eckit/geo/range/RegularLongitude.cc new file mode 100644 index 000000000..12e19e774 --- /dev/null +++ b/src/eckit/geo/range/RegularLongitude.cc @@ -0,0 +1,53 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/range/RegularLongitude.h" + +#include "eckit/geo/PointLonLat.h" +#include "eckit/geo/util.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::range { + + +RegularLongitude::RegularLongitude(size_t n, double a, double b, double precision) : + Range(n), a_(a), b_(b), precision_(precision) { + if (types::is_approximately_equal(a, b, util::eps)) { + endpoint_ = false; + } + else { + + b = PointLonLat::normalise_angle_to_minimum(b, a + util::eps); + auto inc = (b - a) / static_cast(n); + auto periodic = types::is_approximately_greater_or_equal(b - a + inc, 360.); + + endpoint_ = !periodic; + } +} + + +const std::vector& RegularLongitude::values() const { + if (empty()) { + auto& v = const_cast&>(valuesVector()); + v = util::linspace(0., 360., size(), false); + + auto [from, to] = util::monotonic_crop(v, a_, b_, 1e-3); + v.erase(v.begin() + to, v.end()); + v.erase(v.begin(), v.begin() + from); + } + + return *this; +} + + +} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/RegularLongitude.h b/src/eckit/geo/range/RegularLongitude.h new file mode 100644 index 000000000..a7147a0d6 --- /dev/null +++ b/src/eckit/geo/range/RegularLongitude.h @@ -0,0 +1,80 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Range.h" + + +namespace eckit::geo::range { + + +class RegularLongitude final : public Range { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit RegularLongitude(size_t n, double a, double b, double precision = 0.); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + const std::vector& values() const override; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + const double a_; + const double b_; + const double precision_; + bool endpoint_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::range diff --git a/tests/geo/test_grid.cc b/tests/geo/test_grid.cc index 0ede51eab..4fd422a0d 100644 --- a/tests/geo/test_grid.cc +++ b/tests/geo/test_grid.cc @@ -32,8 +32,9 @@ CASE("GridFactory::build") { SECTION("GridFactory::build_from_name") { for (const auto& test : {test_t{"O2", 88}, {"f2", 32}, {"h2", 48}}) { - std::unique_ptr cfg(new MappedConfiguration({{"name", test.name}})); - std::unique_ptr grid(geo::GridFactory::build(*cfg)); + std::unique_ptr grid(geo::GridFactory::build( + *std::unique_ptr(new MappedConfiguration({{"name", test.name}})))); + auto size = grid->size(); EXPECT_EQUAL(size, test.size); } @@ -44,23 +45,34 @@ CASE("GridFactory::build") { SECTION("Grid::build_from_increments") { - std::unique_ptr cfg(new MappedConfiguration({ - {"type", "regular_ll"}, - {"west_east_increment", 1}, - {"south_north_increment", 1}, - })); - std::unique_ptr grid(geo::GridFactory::build(*cfg)); - - auto size = grid->size(); - EXPECT_EQUAL(size, 360 * 181); - } + SECTION("global") { + std::unique_ptr global( + geo::GridFactory::build(*std::unique_ptr(new MappedConfiguration({ + {"type", "regular_ll"}, + {"west_east_increment", 1}, + {"south_north_increment", 1}, + })))); + + auto size = global->size(); + EXPECT_EQUAL(size, 360 * 181); + } - SECTION("Grid::build") { - std::unique_ptr grid(geo::GridFactory::build(MappedConfiguration{{{"name", "O2"}}})); + SECTION("non-global") { + std::unique_ptr grid( + geo::GridFactory::build(*std::unique_ptr(new MappedConfiguration({ + {"type", "regular_ll"}, + {"west_east_increment", 1}, + {"south_north_increment", 1}, + {"north", 10}, + {"west", 1}, + {"south", 1}, + {"east", 10}, + })))); - // auto size = grid->size(); - // EXPECT_EQUAL(size, 88); + auto size = grid->size(); + EXPECT_EQUAL(size, 100); + } } } From 69406a45ee4a66eb8661492ada29f431cd121bd3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 2 Oct 2023 17:36:10 +0100 Subject: [PATCH 344/737] eckit::geo --- src/eckit/geo/Grid.cc | 19 +++++-- tests/config/test_configuration.cc | 87 ++++++++++++++++++------------ 2 files changed, 68 insertions(+), 38 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 077dd4d00..01308fe61 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -15,7 +15,7 @@ #include #include -#include "eckit/config/Configuration.h" +#include "eckit/config/DynamicConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/GridConfig.h" #include "eckit/log/Log.h" @@ -109,13 +109,22 @@ const Grid* GridFactory::build_(const Configuration& config) const { GridConfig::instance(); if (std::string uid; config.get("uid", uid)) { - std::unique_ptr cfg(GridConfigurationUID::instance().get(uid).config()); - return build(*cfg); + auto* cfg = new DynamicConfiguration(config); + ASSERT(cfg != nullptr); + + cfg->push_back(GridConfigurationUID::instance().get(uid).config()); + + return build(*std::unique_ptr(cfg)); } if (std::string name; config.get("name", name)) { - std::unique_ptr cfg(GridConfigurationName::instance().match(name).config(name)); - return build(*cfg); + auto* cfg = new DynamicConfiguration(config); + ASSERT(cfg != nullptr); + + cfg->push_back(GridConfigurationName::instance().match(name).config(name)); + cfg->hide("name"); + + return build(*std::unique_ptr(cfg)); } if (std::string type; config.get("type", type)) { diff --git a/tests/config/test_configuration.cc b/tests/config/test_configuration.cc index 27792635f..47b62924b 100644 --- a/tests/config/test_configuration.cc +++ b/tests/config/test_configuration.cc @@ -386,7 +386,11 @@ CASE("Hash a configuration") { //---------------------------------------------------------------------------------------------------------------------- CASE("test_mapped_configuration") { - int one = 1; + int one = 1; + double two = 2.; + std::string three = "3"; + + MappedConfiguration a({ {"double", static_cast(one)}, {"float", static_cast(one)}, @@ -447,51 +451,68 @@ CASE("test_mapped_configuration") { EXPECT(b.getBool("one")); EXPECT(b.getBool("one", maybe = false)); EXPECT(b.get("one", maybe = false) && maybe); -} -//---------------------------------------------------------------------------------------------------------------------- -CASE("test_dynamic_configuration") { - double one = 1.; - int two = 2; - std::string three = "3"; + MappedConfiguration c; + EXPECT_NOT(c.has("foo")); - DynamicConfiguration a; - EXPECT_NOT(a.has("foo")); + c.set("foo", two); + EXPECT(c.has("foo")); + EXPECT_THROWS_AS(c.getInt("foo"), eckit::ConfigurationNotFound); // cannot access as int + EXPECT(::eckit::types::is_approximately_equal(c.getDouble("foo"), two)); + EXPECT(c.getString("foo") == "2"); - a.set("foo", one); - EXPECT(a.has("foo")); - EXPECT_THROWS_AS(a.getInt("foo"), eckit::ConfigurationNotFound); // cannot access as int - EXPECT(a.getString("foo") == "1"); + c.set("bar", one); + EXPECT_EQUAL(c.getInt("bar"), one); + EXPECT(::eckit::types::is_approximately_equal(c.getDouble("bar"), static_cast(one))); + EXPECT(c.getString("bar") == "1"); - a.set("bar", two); - EXPECT_EQUAL(a.getInt("bar"), two); - EXPECT(::eckit::types::is_approximately_equal(a.getDouble("bar"), static_cast(two))); - EXPECT(a.getString("bar") == "2"); + c.set("foo", three); + EXPECT_EQUAL(c.getString("foo"), three); - a.set("foo", three); - EXPECT_EQUAL(a.getString("foo"), three); - DynamicConfiguration b(a); + MappedConfiguration d(c); + + EXPECT(d.has("foo")); + EXPECT_EQUAL(d.getString("foo"), three); + EXPECT_THROWS_AS(d.getInt("foo"), eckit::ConfigurationNotFound); // cannot access as int + EXPECT_THROWS_AS(d.getDouble("foo"), eckit::ConfigurationNotFound); // cannot access as real + + d.set("foo", one); + EXPECT_EQUAL(d.getInt("foo"), one); - EXPECT(b.has("foo")); - EXPECT_EQUAL(b.getString("foo"), three); - EXPECT_THROWS_AS(b.getInt("foo"), eckit::ConfigurationNotFound); // cannot access as int - EXPECT_THROWS_AS(b.getDouble("foo"), eckit::ConfigurationNotFound); // cannot access as real - b.set("foo", two); - EXPECT_EQUAL(b.getInt("foo"), two); + MappedConfiguration e(c); + + ASSERT(e.has("foo")); + ASSERT(e.has("bar")); +} + +//---------------------------------------------------------------------------------------------------------------------- + +CASE("test_dynamic_configuration") { + int one = 1; + double two = 2.; + + MappedConfiguration a({{"foo", one}, {"bar", two}}); + ASSERT(a.has("foo")); + ASSERT(a.has("bar")); + + DynamicConfiguration b(a); + + ASSERT(b.has("foo")); + ASSERT(b.has("bar")); - DynamicConfiguration c(a); + b.hide("foo"); + EXPECT_NOT(b.has("foo")); - ASSERT(c.has("foo")); - ASSERT(c.has("bar")); + b.unhide("foo"); + ASSERT(b.has("foo")); - c.hide("bar"); - EXPECT_NOT(c.has("bar")); + EXPECT_EQUAL(a.getInt("foo"), one); - c.unhide("bar"); - EXPECT_EQUAL(a.getInt("bar"), two); + auto value = b.getInt("foo"); + EXPECT_EQUAL(value, one); } //---------------------------------------------------------------------------------------------------------------------- From dff384ecae74280c75e998eba32ad15e1f99492e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 3 Oct 2023 10:17:51 +0100 Subject: [PATCH 345/737] eckit::geo --- src/eckit/geo/Range.h | 2 +- src/eckit/geo/range/Gaussian.cc | 14 +++------ src/eckit/geo/range/Regular.cc | 11 ++++---- src/eckit/geo/range/Regular.h | 2 -- tests/geo/test_grid.cc | 9 ++++++ tests/geo/test_range.cc | 50 ++++++++++++++++++++++----------- 6 files changed, 52 insertions(+), 36 deletions(-) diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 5f3493d7b..1c4e60154 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -79,7 +79,7 @@ class Range : protected std::vector { // -- Methods - virtual const P& valuesVector() const { return *this; } + const P& valuesVector() const { return *this; } // -- Overridden methods // None diff --git a/src/eckit/geo/range/Gaussian.cc b/src/eckit/geo/range/Gaussian.cc index 66eb9832d..7e96fdc43 100644 --- a/src/eckit/geo/range/Gaussian.cc +++ b/src/eckit/geo/range/Gaussian.cc @@ -30,18 +30,12 @@ Gaussian::Gaussian(size_t N, double a, double b, double precision) : // pre-calculate on cropping auto [min, max] = std::minmax(a_, b_); if (!types::is_approximately_equal(min, -90., eps_) || !types::is_approximately_equal(max, 90., eps_)) { - auto& v = values(); + auto& v = const_cast&>(values()); auto [from, to] = util::monotonic_crop(v, min, max, precision); - auto f = v.begin() + from; - auto t = v.begin() + to; - - if (t != end()) { - erase(t); - } - if (f != begin()) { - erase(begin(), f); - } + v.erase(v.begin() + to, v.end()); + v.erase(v.begin(), v.begin() + from); + ASSERT(!empty()); } } diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc index b2554db93..18b926c92 100644 --- a/src/eckit/geo/range/Regular.cc +++ b/src/eckit/geo/range/Regular.cc @@ -12,6 +12,7 @@ #include "eckit/geo/range/Regular.h" +#include "eckit/exception/Exceptions.h" #include "eckit/geo/util.h" @@ -19,11 +20,7 @@ namespace eckit::geo::range { Regular::Regular(size_t n, double a, double b, double precision) : - Range(n), a_(a), b_(b), precision_(precision), endpoint_(false) {} - - -Regular::Regular(size_t n, double a, double b, bool endpoint, double precision) : - Range(n), a_(a), b_(b), precision_(precision), endpoint_(endpoint) {} + Range(n), a_(a), b_(b), precision_(precision) {} const std::vector& Regular::values() const { @@ -31,9 +28,11 @@ const std::vector& Regular::values() const { auto& v = const_cast&>(valuesVector()); v = util::linspace(0., 360., size(), false); - auto [from, to] = util::monotonic_crop(v, a_, b_, 1e-3); + auto [from, to] = util::monotonic_crop(v, a_, b_, precision_); v.erase(v.begin() + to, v.end()); v.erase(v.begin(), v.begin() + from); + + ASSERT(!empty()); } return *this; diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h index f3cc7276c..7c54d2436 100644 --- a/src/eckit/geo/range/Regular.h +++ b/src/eckit/geo/range/Regular.h @@ -29,7 +29,6 @@ class Regular final : public Range { // -- Constructors explicit Regular(size_t n, double a, double b, double precision = 0.); - explicit Regular(size_t n, double a, double b, bool endpoint, double precision = 0.); // -- Destructor // None @@ -59,7 +58,6 @@ class Regular final : public Range { const double a_; const double b_; const double precision_; - const bool endpoint_; // -- Methods // None diff --git a/tests/geo/test_grid.cc b/tests/geo/test_grid.cc index 4fd422a0d..712f18e2f 100644 --- a/tests/geo/test_grid.cc +++ b/tests/geo/test_grid.cc @@ -41,6 +41,15 @@ CASE("GridFactory::build") { } + SECTION("RegularGaussian") { + std::unique_ptr grid(geo::GridFactory::build( + *std::unique_ptr(new MappedConfiguration({{"name", "f2"}, {"south", 0}})))); + + auto nh = grid->size(); + EXPECT_EQUAL(nh, 32 / 2); + } + + SECTION("Grid::build_from_uid") {} diff --git a/tests/geo/test_range.cc b/tests/geo/test_range.cc index bd0e0ec92..3a4504ee1 100644 --- a/tests/geo/test_range.cc +++ b/tests/geo/test_range.cc @@ -19,7 +19,7 @@ #include "eckit/types/FloatCompare.h" -#define EXPECT_APPROX(a, b) EXPECT(::eckit::types::is_approximately_equal((a), (b), 1e-12)) +#define EXPECT_APPROX(a, b, eps) EXPECT(::eckit::types::is_approximately_equal((a), (b), (eps))) namespace eckit::test { @@ -30,31 +30,47 @@ CASE("range::Gaussian") { std::vector ref{59.44440828916676, 19.87571914744090, -19.87571914744090, -59.44440828916676}; - auto global = Gaussian(2); - EXPECT(global.size() == ref.size()); + SECTION("global") { + auto global = Gaussian(2); + EXPECT(global.size() == ref.size()); - size_t i = 0; - for (const auto& test : global.values()) { - EXPECT_APPROX(test, ref[i++]); + size_t i = 0; + for (const auto& test : global.values()) { + EXPECT_APPROX(test, ref[i++], 1e-12); + } } - auto cropped = Gaussian(2, 50., -50., 1e-3); - EXPECT(cropped.size() == ref.size() - 2); - i = 1; - for (const auto& test : cropped.values()) { - EXPECT_APPROX(test, ref[i++]); + SECTION("crop [50., -50.]") { + constexpr auto eps = 1e-3; + + auto cropped = Gaussian(2, 50., -50., eps); + EXPECT(cropped.size() == ref.size() - 2); + + EXPECT_APPROX(cropped.values()[0], ref[1], eps); + EXPECT_APPROX(cropped.values()[1], ref[2], eps); + + EXPECT(Gaussian(2, 59.444, -59.444, 1e-3).size() == 4); + EXPECT(Gaussian(2, 59.444, -59.444, 1e-6).size() == 2); + EXPECT(Gaussian(2, 59.444, -59.445, 1e-6).size() == 3); + + auto single = Gaussian(2, -59.444, -59.444, eps); + EXPECT(single.size() == 1); + + EXPECT_APPROX(single.values().front(), ref.back(), eps); } - EXPECT(Gaussian(2, 59.444, -59.444, 1e-3).size() == 4); - EXPECT(Gaussian(2, 59.444, -59.444, 1e-6).size() == 2); - EXPECT(Gaussian(2, 59.444, -59.445, 1e-6).size() == 3); - auto single = Gaussian(2, -59.444, -59.444, 1e-3); - EXPECT(single.size() == 1); + SECTION("crop [90., 0.]") { + constexpr auto eps = 1e-3; + + auto cropped = Gaussian(2, 90., 0., eps); + EXPECT(cropped.size() == ref.size() / 2); - EXPECT_APPROX(single.values().front(), ref.back()); + EXPECT_APPROX(cropped.values()[0], ref[0], eps); + EXPECT_APPROX(cropped.values()[1], ref[1], eps); + } } From ab8e97cd2fb91ccf52c36b04a446ea9464874cb6 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 3 Oct 2023 17:53:04 +0100 Subject: [PATCH 346/737] eckit::geo gridspec --- src/eckit/geo/Grid.cc | 31 +++++++++++++++++++++++++------ src/eckit/geo/Grid.h | 4 ++++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 01308fe61..5752bfd89 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -108,13 +108,30 @@ const Grid* GridFactory::build_(const Configuration& config) const { GridConfig::instance(); + std::unique_ptr cfg(configure_(config)); + + if (std::string type; cfg->get("type", type)) { + return GridFactoryType::instance().get(type).create(*cfg); + } + + list(Log::error() << "Grid: cannot build grid without 'type', choices are: "); + throw SeriousBug("Grid: cannot build grid without 'type'"); +} + + +Configuration* GridFactory::configure_(const Configuration& config) const { + AutoLock lock(mutex_); + + GridConfig::instance(); + if (std::string uid; config.get("uid", uid)) { auto* cfg = new DynamicConfiguration(config); ASSERT(cfg != nullptr); cfg->push_back(GridConfigurationUID::instance().get(uid).config()); + cfg->hide("uid"); - return build(*std::unique_ptr(cfg)); + return configure_(*cfg); } if (std::string name; config.get("name", name)) { @@ -124,15 +141,17 @@ const Grid* GridFactory::build_(const Configuration& config) const { cfg->push_back(GridConfigurationName::instance().match(name).config(name)); cfg->hide("name"); - return build(*std::unique_ptr(cfg)); + return configure_(*cfg); } - if (std::string type; config.get("type", type)) { - return GridFactoryType::instance().get(type).create(config); + // interpretation (gridspec) + // TODO + + if (config.has("type")) { + return new DynamicConfiguration(config); } - list(Log::error() << "Grid: cannot build grid, choices are: "); - throw SeriousBug("Grid: cannot build grid"); + throw SeriousBug("Grid: cannot interpret gridspec"); } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 6aa77c013..9cfd1bdbd 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -195,6 +195,8 @@ using GridRegisterName = ConcreteConfigurationGeneratorT1 struct GridFactory { // This is 'const' as Grid should always be immutable static const Grid* build(const Configuration& config) { return instance().build_(config); } + + static Configuration* configure(const Configuration& config) { return instance().configure_(config); } static void list(std::ostream& out) { return instance().list_(out); } private: @@ -202,6 +204,8 @@ struct GridFactory { // This is 'const' as Grid should always be immutable const Grid* build_(const Configuration&) const; + + Configuration* configure_(const Configuration&) const; void list_(std::ostream&) const; mutable Mutex mutex_; From 06b400d032bd17a050524cc7c38bca41141fc222 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 4 Oct 2023 17:29:55 +0100 Subject: [PATCH 347/737] eckit::geo::Increments --- src/eckit/geo/CMakeLists.txt | 2 ++ src/eckit/geo/Increments.cc | 43 ++++++++++++++++++++++++++++++++++++ src/eckit/geo/Increments.h | 28 +++++++++-------------- 3 files changed, 55 insertions(+), 18 deletions(-) create mode 100644 src/eckit/geo/Increments.cc diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index d32dde9ff..38641a90d 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -25,6 +25,8 @@ list( APPEND eckit_geo_srcs Grid.h GridConfig.cc GridConfig.h + Increments.cc + Increments.h Iterator.h KPoint.cc KPoint.h diff --git a/src/eckit/geo/Increments.cc b/src/eckit/geo/Increments.cc new file mode 100644 index 000000000..34f4c2033 --- /dev/null +++ b/src/eckit/geo/Increments.cc @@ -0,0 +1,43 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Increments.h" + +#include "eckit/config/Configuration.h" +#include "eckit/exception/Exceptions.h" + + +namespace eckit::geo { + + +Increments::Increments(double west_east, double south_north) : + P{west_east, south_north} { + ASSERT(operator[](0) > 0.); + ASSERT(operator[](1) > 0.); +} + + +Increments::Increments(const Configuration& config) : + Increments(VectorHelper(config)) {} + + +Increments::Increments(const VectorHelper& helper) : + Increments(helper[0], helper[1]) {} + + +Increments::VectorHelper::VectorHelper(const Configuration& config) : + vector(config.getDoubleVector("grid")) { + ASSERT(size() == 2); +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Increments.h b/src/eckit/geo/Increments.h index 39dc0edab..fd531b009 100644 --- a/src/eckit/geo/Increments.h +++ b/src/eckit/geo/Increments.h @@ -13,6 +13,7 @@ #pragma once #include +#include namespace eckit { @@ -29,6 +30,10 @@ class Increments : protected std::array { using P = std::array; + struct VectorHelper : std::vector { + explicit VectorHelper(const Configuration&); + }; + public: // -- Types // None @@ -38,10 +43,9 @@ class Increments : protected std::array { // -- Constructors - Increments(double west_east, double south_north) : - P{west_east, south_north} {}; + Increments(double west_east, double south_north); - Increments(const Configuration&); + explicit Increments(const Configuration& config); // -- Destructor // None @@ -70,23 +74,11 @@ class Increments : protected std::array { // -- Class methods // None -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None +private: + // -- Constructors - // -- Class methods - // None + explicit Increments(const VectorHelper&); -private: // -- Members // None From 60b5e2c747c2afc77b28a12c533b5d0fa4c35a93 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 4 Oct 2023 17:32:22 +0100 Subject: [PATCH 348/737] eckit::geo::Grid use "grid" instead of "name" and *"_increment" --- src/eckit/geo/grid/regular/RegularLL.cc | 11 +++-------- tests/geo/test_grid.cc | 4 ++-- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index 2ebebff53..d7660149c 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -100,9 +100,8 @@ struct DiscreteRange { RegularLL::RegularLL(const Configuration& config) : - RegularLL({config.getDouble("west_east_increment"), config.getDouble("south_north_increment")}, - area::BoundingBox(config), - {config.getDouble("west", 0), config.getDouble("south", 0)}) {} + RegularLL( + Increments{config}, area::BoundingBox{config}, {config.getDouble("west", 0), config.getDouble("south", 0)}) {} RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& ref) : @@ -163,11 +162,7 @@ Configuration* RegularLL::config(const std::string& name) { // Fraction(360)).n(); auto nj = 1; // detail::RegularIterator(Fraction(-90), Fraction(90), Fraction(increments[1]), Fraction(0)).n(); - return new MappedConfiguration({{"type", "regular_ll"}, - {"west_east_increment", increments[0]}, - {"south_north_increment", increments[1]}, - {"ni", ni}, - {"nj", nj}}); + return new MappedConfiguration({{"type", "regular_ll"}, {"grid", increments}, {"ni", ni}, {"nj", nj}}); } diff --git a/tests/geo/test_grid.cc b/tests/geo/test_grid.cc index 712f18e2f..e325efcbc 100644 --- a/tests/geo/test_grid.cc +++ b/tests/geo/test_grid.cc @@ -33,7 +33,7 @@ CASE("GridFactory::build") { SECTION("GridFactory::build_from_name") { for (const auto& test : {test_t{"O2", 88}, {"f2", 32}, {"h2", 48}}) { std::unique_ptr grid(geo::GridFactory::build( - *std::unique_ptr(new MappedConfiguration({{"name", test.name}})))); + *std::unique_ptr(new MappedConfiguration({{"grid", test.name}})))); auto size = grid->size(); EXPECT_EQUAL(size, test.size); @@ -43,7 +43,7 @@ CASE("GridFactory::build") { SECTION("RegularGaussian") { std::unique_ptr grid(geo::GridFactory::build( - *std::unique_ptr(new MappedConfiguration({{"name", "f2"}, {"south", 0}})))); + *std::unique_ptr(new MappedConfiguration({{"grid", "f2"}, {"south", 0}})))); auto nh = grid->size(); EXPECT_EQUAL(nh, 32 / 2); From c38a4e4dd319a83a9938fff82d8a59e28988042c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 4 Oct 2023 17:39:26 +0100 Subject: [PATCH 349/737] eckit::geo::GridFactory --- src/eckit/geo/Configurator.h | 24 ++++++++++++++------ src/eckit/geo/Grid.cc | 44 ++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 27 deletions(-) diff --git a/src/eckit/geo/Configurator.h b/src/eckit/geo/Configurator.h index 3347f94e1..62f704ab3 100644 --- a/src/eckit/geo/Configurator.h +++ b/src/eckit/geo/Configurator.h @@ -12,6 +12,7 @@ #pragma once +#include #include #include #include @@ -57,6 +58,8 @@ class Configurator { static Configurator& instance(); bool exists(const key_t&) const; + bool matches(const std::string&) const; + void regist(const key_t&, configurator_t*); void unregist(const key_t&); @@ -100,7 +103,13 @@ Configurator& Configurator::instance() { template bool Configurator::exists(const key_t& k) const { AutoLock lock(mutex_); - return (store_.find(k) != store_.end()); + return store_.find(k) != store_.end(); +} + +template +bool Configurator::matches(const std::string& k) const { + AutoLock lock(mutex_); + return std::any_of(store_.begin(), store_.end(), [&](const auto& p) { return Regex(p.first).match(k); }); } template @@ -116,19 +125,20 @@ void Configurator::regist(const key_t& k, configurator_t* c) { template void Configurator::unregist(const key_t& k) { AutoLock lock(mutex_); - if (!exists(k)) { - throw BadParameter("Configurator unknown: '" + k + "'", Here()); + if (auto it = store_.find(k); it != store_.end()) { + store_.erase(it); + return; } - store_.erase(k); + throw BadParameter("Configurator unknown: '" + k + "'", Here()); } template const typename Configurator::configurator_t& Configurator::get(const key_t& k) const { AutoLock lock(mutex_); - if (!exists(k)) { - throw BadParameter("Configurator unknown: '" + k + "'", Here()); + if (auto it = store_.find(k); it != store_.end()) { + return *(it->second); } - return *(store_.find(k)->second); + throw BadParameter("Configurator unknown: '" + k + "'", Here()); } template diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 5752bfd89..590adab18 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -16,6 +16,7 @@ #include #include "eckit/config/DynamicConfiguration.h" +#include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/GridConfig.h" #include "eckit/log/Log.h" @@ -106,8 +107,6 @@ GridFactory& GridFactory::instance() { const Grid* GridFactory::build_(const Configuration& config) const { AutoLock lock(mutex_); - GridConfig::instance(); - std::unique_ptr cfg(configure_(config)); if (std::string type; cfg->get("type", type)) { @@ -124,34 +123,39 @@ Configuration* GridFactory::configure_(const Configuration& config) const { GridConfig::instance(); - if (std::string uid; config.get("uid", uid)) { - auto* cfg = new DynamicConfiguration(config); - ASSERT(cfg != nullptr); + auto* cfg = new DynamicConfiguration(config); + ASSERT(cfg != nullptr); - cfg->push_back(GridConfigurationUID::instance().get(uid).config()); - cfg->hide("uid"); - return configure_(*cfg); - } + // hardcoded, interpreted options (contributing to gridspec) - if (std::string name; config.get("name", name)) { - auto* cfg = new DynamicConfiguration(config); - ASSERT(cfg != nullptr); + auto* map = new MappedConfiguration; + ASSERT(map != nullptr); - cfg->push_back(GridConfigurationName::instance().match(name).config(name)); - cfg->hide("name"); + if (size_t N = 0; cfg->get("N", N)) { + map->set("grid", "O" + std::to_string(N)); + } - return configure_(*cfg); + if (std::vector grid; cfg->get("grid", grid) && grid.size() == 2) { + map->set("type", "regular_ll"); } - // interpretation (gridspec) - // TODO + cfg->push_back(map); + - if (config.has("type")) { - return new DynamicConfiguration(config); + // configurable options + + if (std::string uid; cfg->get("uid", uid)) { + cfg->push_front(GridConfigurationUID::instance().get(uid).config()); + } + else if (std::string grid; cfg->get("grid", grid) && GridConfigurationName::instance().matches(grid)) { + cfg->push_front(GridConfigurationName::instance().match(grid).config(grid)); } - throw SeriousBug("Grid: cannot interpret gridspec"); + + // finalise + + return cfg; } From d5e00236f0b0133c184d0d5d26b34003875d3fbc Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 8 Oct 2023 08:22:15 +0100 Subject: [PATCH 350/737] eckit::geo Figure --- src/eckit/geo/CMakeLists.txt | 5 ++ src/eckit/geo/Figure.cc | 41 +++++++++++++ src/eckit/geo/Figure.h | 8 +++ src/eckit/geo/figure/OblateSpheroid.cc | 39 ++++++++++++ src/eckit/geo/figure/OblateSpheroid.h | 82 ++++++++++++++++++++++++++ src/eckit/geo/figure/Sphere.cc | 33 +++++++++++ src/eckit/geo/figure/Sphere.h | 81 +++++++++++++++++++++++++ 7 files changed, 289 insertions(+) create mode 100644 src/eckit/geo/Figure.cc create mode 100644 src/eckit/geo/figure/OblateSpheroid.cc create mode 100644 src/eckit/geo/figure/OblateSpheroid.h create mode 100644 src/eckit/geo/figure/Sphere.cc create mode 100644 src/eckit/geo/figure/Sphere.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 38641a90d..57d76ef2a 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -18,6 +18,7 @@ list( APPEND eckit_geo_srcs Earth.h EllipsoidOfRevolution.cc EllipsoidOfRevolution.h + Figure.cc Figure.h GreatCircle.cc GreatCircle.h @@ -52,6 +53,10 @@ list( APPEND eckit_geo_srcs UnitSphere.h area/BoundingBox.cc area/BoundingBox.h + figure/OblateSpheroid.cc + figure/OblateSpheroid.h + figure/Sphere.cc + figure/Sphere.h grid/Reduced.cc grid/Reduced.h grid/Regular.cc diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc new file mode 100644 index 000000000..497c0923b --- /dev/null +++ b/src/eckit/geo/Figure.cc @@ -0,0 +1,41 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Figure.h" + +#include "eckit/exception/Exceptions.h" + + +namespace eckit::geo { + + +double Figure::R() const { + throw NotImplemented("Figure::R", Here()); +} + + +double Figure::a() const { + throw NotImplemented("Figure::a", Here()); +} + + +double Figure::b() const { + throw NotImplemented("Figure::b", Here()); +} + + +double Figure::eccentricity() const { + return std::sqrt(1. - (b() * b()) / (a() * a())); +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index 705f194b2..44bd1aea2 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -42,6 +42,8 @@ class Figure { Figure(const Figure&) = default; Figure(Figure&&) = default; + explicit Figure(const Configuration&); + // -- Destructor virtual ~Figure() = default; @@ -58,6 +60,12 @@ class Figure { static std::string className() { return "figure"; } + virtual double R() const; + virtual double a() const; + virtual double b() const; + + double eccentricity() const; + // -- Overridden methods // None diff --git a/src/eckit/geo/figure/OblateSpheroid.cc b/src/eckit/geo/figure/OblateSpheroid.cc new file mode 100644 index 000000000..bfdd2cb41 --- /dev/null +++ b/src/eckit/geo/figure/OblateSpheroid.cc @@ -0,0 +1,39 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/figure/OblateSpheroid.h" + +#include "eckit/config/Configuration.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::figure { + + +OblateSpheroid::OblateSpheroid(double a, double b) : + a_(a), b_(b) { + ASSERT_MSG(types::is_strictly_greater(b_, 0.) && b_ <= a_, "OblateSpheroid requires 0 < b <= a"); +} + + +OblateSpheroid::OblateSpheroid(const Configuration& config) : + OblateSpheroid(config.getDouble("a"), config.getDouble("b")) {} + + +double OblateSpheroid::R() const { + ASSERT_MSG(types::is_approximately_equal(a_, b_), "OblateSpheroid::R requires a ~= b"); + return a_; +} + + +} // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/OblateSpheroid.h b/src/eckit/geo/figure/OblateSpheroid.h new file mode 100644 index 000000000..96a88aa37 --- /dev/null +++ b/src/eckit/geo/figure/OblateSpheroid.h @@ -0,0 +1,82 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Figure.h" + + +namespace eckit::geo::figure { + + +class OblateSpheroid final : public Figure { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + OblateSpheroid(double R, double b); + OblateSpheroid(const Configuration&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + double R() const override; + double a() const override { return a_; } + double b() const override { return b_; } + + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + const double a_; + const double b_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/Sphere.cc b/src/eckit/geo/figure/Sphere.cc new file mode 100644 index 000000000..9980ffa2a --- /dev/null +++ b/src/eckit/geo/figure/Sphere.cc @@ -0,0 +1,33 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/figure/Sphere.h" + +#include "eckit/config/Configuration.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::figure { + + +Sphere::Sphere(double R) : + R_(R) { + ASSERT_MSG(types::is_strictly_greater(R_, 0.), "Sphere requires R > 0"); +} + + +Sphere::Sphere(const Configuration& config) : + Sphere(config.getDouble("R")) {} + + +} // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/Sphere.h b/src/eckit/geo/figure/Sphere.h new file mode 100644 index 000000000..3be6dc40b --- /dev/null +++ b/src/eckit/geo/figure/Sphere.h @@ -0,0 +1,81 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Figure.h" + + +namespace eckit::geo::figure { + + +class Sphere final : public Figure { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + Sphere(double R); + Sphere(const Configuration&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + double R() const override { return R_; } + double a() const override { return R_; } + double b() const override { return R_; } + + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + const double R_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::figure From 2183f95aaeb5fb2af7d0c391f4a2353a5af01c9a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 8 Oct 2023 08:23:12 +0100 Subject: [PATCH 351/737] eckit::geo projection Mercator --- src/eckit/geo/CMakeLists.txt | 4 + src/eckit/geo/grid/regular/Mercator.cc | 59 ++++++++++++++ src/eckit/geo/grid/regular/Mercator.h | 89 +++++++++++++++++++++ src/eckit/geo/projection/Mercator.cc | 106 +++++++++++++++++++++++++ src/eckit/geo/projection/Mercator.h | 99 +++++++++++++++++++++++ 5 files changed, 357 insertions(+) create mode 100644 src/eckit/geo/grid/regular/Mercator.cc create mode 100644 src/eckit/geo/grid/regular/Mercator.h create mode 100644 src/eckit/geo/projection/Mercator.cc create mode 100644 src/eckit/geo/projection/Mercator.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 57d76ef2a..3fd2b2d15 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -71,6 +71,8 @@ list( APPEND eckit_geo_srcs grid/reduced/ReducedLL.h grid/regular/IrregularLL.cc grid/regular/IrregularLL.h + grid/regular/Mercator.cc + grid/regular/Mercator.h grid/regular/RegularGaussian.cc grid/regular/RegularGaussian.h grid/regular/RegularLL.cc @@ -89,6 +91,8 @@ list( APPEND eckit_geo_srcs polygon/Polygon.h projection/LonLatToXYZ.cc projection/LonLatToXYZ.h + projection/Mercator.cc + projection/Mercator.h projection/None.cc projection/None.h projection/Rotation.cc diff --git a/src/eckit/geo/grid/regular/Mercator.cc b/src/eckit/geo/grid/regular/Mercator.cc new file mode 100644 index 000000000..1f7f3be80 --- /dev/null +++ b/src/eckit/geo/grid/regular/Mercator.cc @@ -0,0 +1,59 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/regular/Mercator.h" + +#include "eckit/config/MappedConfiguration.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/iterator/Regular.h" +#include "eckit/geo/util/regex.h" +#include "eckit/types/Fraction.h" +#include "eckit/utils/Translator.h" + + +namespace eckit::geo::grid::regular { + + +static const GridRegisterType __grid_type("mercator"); + + +Mercator::Mercator(const Configuration& config) : + Mercator(config.getUnsigned("ni"), config.getUnsigned("nj"), Increments{config}, area::BoundingBox{config}) {} + + +Mercator::Mercator(size_t ni, size_t nj, const Increments& inc, const area::BoundingBox& bbox) : + Regular(bbox), inc_(inc), ni_(ni), nj_(nj) { + ASSERT(ni_ > 0); + ASSERT(nj_ > 0); +} + + +Grid::iterator Mercator::cbegin() const { + return iterator{new geo::iterator::Regular(*this, 0)}; +} + + +Grid::iterator Mercator::cend() const { + return iterator{new geo::iterator::Regular(*this, size())}; +} + +const std::vector& Mercator::longitudes() const { + NOTIMP; +} + + +const std::vector& Mercator::latitudes() const { + NOTIMP; +} + + +} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/grid/regular/Mercator.h b/src/eckit/geo/grid/regular/Mercator.h new file mode 100644 index 000000000..42ea855de --- /dev/null +++ b/src/eckit/geo/grid/regular/Mercator.h @@ -0,0 +1,89 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Regular.h" + +#include "eckit/geo/Increments.h" + + +namespace eckit::geo::grid::regular { + + +class Mercator final : public Regular { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit Mercator(const Configuration&); + + Mercator(size_t ni, size_t nj, const Increments&, const area::BoundingBox&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + iterator cbegin() const override; + iterator cend() const override; + + size_t ni() const override { return ni_; } + size_t nj() const override { return nj_; } + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + Increments inc_; + size_t ni_; + size_t nj_; + + // -- Methods + // None + + // -- Overridden methods + + const std::vector& longitudes() const override; + const std::vector& latitudes() const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/projection/Mercator.cc b/src/eckit/geo/projection/Mercator.cc new file mode 100644 index 000000000..8236b25d4 --- /dev/null +++ b/src/eckit/geo/projection/Mercator.cc @@ -0,0 +1,106 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/projection/Mercator.h" + +#include + +#include "eckit/config/MappedConfiguration.h" +#include "eckit/geo/util.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::projection { + + +static ProjectionBuilder __projection("mercator"); + + +Mercator::Mercator(double meridian, double parallel, Figure* figure, PointLonLat first) : + meridian_(PointLonLat::normalise_angle_to_minimum(meridian, -180.)), + parallel_(parallel), + figure_(figure), + first_(first), + eps_(1e-10), + max_iter_(15) { + // Map Projections: A Working Manual, John P. Snyder (1987) + // - Equation (7-9) to calculate phi iteratively + // - Equation (15-11) to calculate t + ASSERT(figure_); + + ASSERT_MSG(!types::is_approximately_equal(first.lat, 90.) && !types::is_approximately_equal(first.lat, -90.), + "Mercator: projection cannot be calculated at the poles"); + + e_ = figure_->eccentricity(); + lam0_ = util::degree_to_radian * meridian_; + + auto phi0 = util::degree_to_radian * parallel_; + auto lam1 = util::degree_to_radian * first.lon; + auto phi1 = util::degree_to_radian * first.lat; + + m_ = figure_->a() * std::cos(phi0) / (std::sqrt(1. - e_ * e_ * std::sin(phi0) * std::sin(phi0))); + ASSERT(!types::is_approximately_equal(m_, 0.)); + + w_ = 1. / m_; + x0_ = m_ * (lam0_ - lam1); + y0_ = m_ * std::log(std::tan(M_PI_4 - 0.5 * phi1) / + std::pow(((1. - e_ * std::sin(phi1)) / (1. + e_ * std::sin(phi1))), 0.5 * e_)); + + ASSERT(types::is_approximately_equal(phi1, calculate_phi(std::exp(y0_ * w_)), eps_)); +} + + +Mercator::Mercator(const Configuration& config) : + Mercator(config.getDouble("meridian"), + config.getDouble("parallel"), + FigureFactory::instance().get(config.getString("figure")).create(config), + PointLonLat{config.getDouble("lon0"), config.getDouble("lat0")}) {} + + +double Mercator::calculate_phi(double t) const { + auto phi = M_PI_2 - 2 * std::atan(t); + for (size_t i = 0; i <= max_iter_; i++) { + auto es = e_ * std::sin(phi); + auto dphi = M_PI_2 - 2 * std::atan(t * (std::pow(((1. - es * es) / (1. + es * es)), 0.5 * e_))) - phi; + + phi += dphi; + if (types::is_approximately_equal(dphi, 0., eps_)) { + return phi; + } + } + + throw SeriousBug("Mercator: phi calculation failed to converge"); +} + + +Point2 Mercator::fwd(const PointLonLat& p) const { + auto phi = util::degree_to_radian * p.lat; + auto lam = util::degree_to_radian * p.lon; + + return {x0_ + m_ * (lam - lam0_), + y0_ - m_ * std::log(std::tan(M_PI_4 - 0.5 * phi) / + std::pow(((1. - e_ * std::sin(phi)) / (1. + e_ * std::sin(phi))), 0.5 * e_))}; +} + + +PointLonLat Mercator::inv(const Point2& q) const { + return PointLonLat::make(util::radian_to_degree * (lam0_ + (q.X - x0_) * w_), + util::radian_to_degree * calculate_phi(std::exp(-(q.Y - y0_) * w_))); +} + + +Projection::Spec Mercator::spec() const { + return Spec{{{"lad", parallel_}, {"orientation", meridian_}}}; +} + + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/Mercator.h b/src/eckit/geo/projection/Mercator.h new file mode 100644 index 000000000..d2479ab09 --- /dev/null +++ b/src/eckit/geo/projection/Mercator.h @@ -0,0 +1,99 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "eckit/geo/Figure.h" +#include "eckit/geo/Projection.h" + + +namespace eckit::geo::projection { + + +/// Calculate coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle +class Mercator final : public Projection { +public: + // -- Exceptions + // None + + // -- Constructors + + Mercator(double meridian, double parallel, Figure*, PointLonLat first = {0, 0}); + + explicit Mercator(const Configuration&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + Point2 fwd(const PointLonLat& p) const; + PointLonLat inv(const Point2& q) const; + + // -- Overridden methods + + Spec spec() const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + const double meridian_; // angle [degree] between Eastward direction and the Equator, range [0, 90] + const double parallel_; // latitude [degree] of projection intersecting ellipsoid + + const std::unique_ptr
figure_; + PointLonLat first_; + + const double eps_; + const size_t max_iter_; + + double lam0_; + double x0_; + double y0_; + double e_; + double m_; + double w_; + + // -- Methods + + double calculate_phi(double t) const; + + // -- Overridden methods + + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::projection From 73009f5badd03ed106d92f1b1208b4c6588ebb52 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 4 Oct 2023 17:39:41 +0100 Subject: [PATCH 352/737] eckit::geo test_gridspec --- tests/geo/CMakeLists.txt | 1 + tests/geo/test_gridspec.cc | 136 +++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 tests/geo/test_gridspec.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 103d9779d..151f902e9 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -2,6 +2,7 @@ foreach( _test coordinate_helpers great_circle grid + gridspec iterator kdtree kpoint diff --git a/tests/geo/test_gridspec.cc b/tests/geo/test_gridspec.cc new file mode 100644 index 000000000..b062905ba --- /dev/null +++ b/tests/geo/test_gridspec.cc @@ -0,0 +1,136 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "eckit/config/MappedConfiguration.h" +#include "eckit/geo/Grid.h" +#include "eckit/log/Log.h" +#include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" + + +#define EXPECT_APPROX(a, b, eps) EXPECT(::eckit::types::is_approximately_equal((a), (b), (eps))) + +#define EXPECT_AREA(a, b, eps) \ + EXPECT((a).size() == 4 && (b).size() == 4 && EXPECT_APPROX((a)[0], (b)[0], (eps)) && \ + EXPECT_APPROX((a)[1], (b)[1], (eps)) && EXPECT_APPROX((a)[2], (b)[2], (eps)) && \ + EXPECT_APPROX((a)[3], (b)[3], (eps))) + + +namespace eckit::test { + + +using C = std::unique_ptr; +using G = std::unique_ptr; +using M = MappedConfiguration; +using v = std::vector; + + +static const MappedConfiguration BAD; + + +static std::pair cases[]{ + {M({{"N", 2}}), M({{"N", 2}, {"type", "reduced_gg"}})}, + {M({{"area", v{90, -180, -90, 180}}, {"grid", v{2, 2}}}), M({{"type", "regular_ll"}})}, + {M({{"area", v{90, -180, -90, 180}}}), BAD}, + {M({{"grid", "B48"}}), BAD}, + {M({{"grid", "F48"}}), M({{"type", "regular_gg"}})}, + {M({{"grid", "N48"}}), M({{"type", "reduced_gg"}})}, + {M({{"grid", "O48"}}), M({{"type", "reduced_gg"}})}, + {M({{"grid", 48}}), BAD}, + {M({{"grid", v{2, 2}}}), M({{"grid", v{2, 2}}, {"type", "regular_ll"}})}, + {M({{"type", "latlon"}, {"grid", v{2, 2}}}), BAD}, + {M({{"type", "reduced_gg"}, {"grid", "48"}}), BAD}, + {M({{"type", "reduced_gg"}, {"grid", "F048"}}), BAD}, + {M({{"type", "reduced_gg"}, {"grid", "N"}}), BAD}, + {M({{"type", "reduced_gg"}, {"grid", "N048"}}), BAD}, + {M({{"type", "reduced_gg"}, {"grid", "N48"}}), M({{"type", "reduced_gg"}})}, + {M({{"type", "reduced_gg"}, {"grid", "O048"}}), BAD}, + {M({{"type", "reduced_gg"}, {"grid", "O48"}}), M({{"type", "reduced_gg"}})}, + {M({{"type", "reduced_gg"}, {"grid", 48}}), BAD}, + {M({{"type", "reduced_gg"}}), BAD}, + {M({{"type", "reduced_latlon"}, {"grid", 2}}), BAD}, + {M({{"type", "reduced_ll"}, {"grid", 12}}), BAD}, + {M({{"type", "regular_gg"}, {"grid", "48"}}), BAD}, + {M({{"type", "regular_gg"}, {"grid", "F048"}}), BAD}, + {M({{"type", "regular_gg"}, {"grid", "F48"}}), M({{"type", "regular_gg"}})}, + {M({{"type", "regular_gg"}, {"grid", "N48"}}), BAD}, + {M({{"type", "regular_gg"}, {"grid", "O48"}}), BAD}, + {M({{"type", "regular_gg"}, {"grid", "a"}}), BAD}, + {M({{"type", "regular_gg"}, {"grid", 48}}), BAD}, + {M({{"type", "regular_ll"}, {"area", v{90, -180, -90, 180}}}), BAD}, + {M({{"type", "regular_ll"}, {"grid", "F48"}}), BAD}, + {M({{"type", "regular_ll"}, {"grid", "a"}}), BAD}, + {M({{"type", "regular_ll"}, {"grid", 48}}), BAD}, + {M({{"type", "regular_ll"}, {"grid", std::vector{"a", "b"}}}), BAD}, + {M({{"type", "regular_ll"}, {"grid", v{1, 2, 3}}}), BAD}, + {M({{"type", "regular_ll"}, {"grid", v{1, 2}}}), M({{"type", "regular_ll"}})}, + {M({{"type", "regular_ll"}, {"grid", v{1}}}), BAD}, + + {M({{"type", "mercator"}, + {"area", v{31.173058, 262.036499, 14.736453, 284.975281}}, + {"grid", v{45000.0, 45000.0}}, + {"lad", 14.0}, + {"nx", 56}, + {"ny", 44}, + {"orientation", 0.0}}), + M()}, +}; + + +CASE("gridspec") { + SECTION("user -> type") { + for (const auto& [user, gridspec] : cases) { + Log::info() << user << " -> " << gridspec << std::endl; + + C config(geo::GridFactory::configure(user)); + ASSERT(config); + + if (!config->has("type")) { + EXPECT(gridspec.empty()); + continue; + } + + if (gridspec.empty()) { + EXPECT_THROWS(G(geo::GridFactory::build(*config))); + } + else { + EXPECT_NO_THROW(G(geo::GridFactory::build(*config))); + } + } + } + + + SECTION("user -> grid -> gridspec") { + for (const auto& [user, gridspec] : cases) { + Log::info() << user << " -> " << gridspec << std::endl; + + if (gridspec.empty()) { + EXPECT_THROWS(G(geo::GridFactory::build(user))); + continue; + } + + // G grid(geo::GridFactory::build(*user)); + // EXPECT(grid); + } + } +} + + +} // namespace eckit::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From c8c599cfbedaa89490ce166f3a9b2baf1121bb50 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 8 Oct 2023 08:23:12 +0100 Subject: [PATCH 353/737] eckit::geo test_projspec --- src/eckit/geo/Projection.h | 9 +- src/eckit/geo/projection/LonLatToXYZ.cc | 12 +- src/eckit/geo/projection/LonLatToXYZ.h | 4 +- src/eckit/geo/projection/None.cc | 7 ++ src/eckit/geo/projection/None.h | 3 +- src/eckit/geo/projection/PROJ.cc | 7 +- src/eckit/geo/projection/PROJ.h | 2 + src/eckit/geo/projection/Rotation.cc | 19 ++- src/eckit/geo/projection/Rotation.h | 4 +- tests/geo/test_projection.cc | 158 +++++++++++++++--------- 10 files changed, 157 insertions(+), 68 deletions(-) diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index b5ca1fc66..daeb26948 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -21,7 +21,8 @@ namespace eckit { class Configuration; -} +class MappedConfiguration; +} // namespace eckit namespace eckit::geo { @@ -34,6 +35,8 @@ class Projection { using builder_t = BuilderT1; using ARG1 = const Configuration&; + using Spec = MappedConfiguration; + // -- Exceptions // None @@ -57,10 +60,12 @@ class Projection { // -- Methods + static std::string className() { return "projection"; } + virtual Point fwd(const Point&) const = 0; virtual Point inv(const Point&) const = 0; - static std::string className() { return "projection"; } + virtual Spec spec() const = 0; // -- Overridden methods // None diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc index e0db54f83..ac8c30497 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -12,7 +12,7 @@ #include "eckit/geo/projection/LonLatToXYZ.h" -#include "eckit/config/Configuration.h" +#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/EllipsoidOfRevolution.h" #include "eckit/geo/Sphere.h" #include "eckit/types/FloatCompare.h" @@ -25,8 +25,7 @@ static ProjectionBuilder __projection("ll_to_xyz"); LonLatToXYZ::LonLatToXYZ(double a, double b) { - ASSERT(0. < a); - ASSERT(0. < b); + ASSERT_MSG(types::is_strictly_greater(b, 0.) && b <= a, "LonLatToXYZ requires 0 < b <= a"); struct LonLatToSphereXYZ final : Implementation { using S = Sphere; @@ -36,6 +35,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { R_(R) {} Point3 operator()(const PointLonLat& p) const override { return S::convertSphericalToCartesian(R_, p, 0.); } PointLonLat operator()(const Point3& q) const override { return S::convertCartesianToSpherical(R_, q); } + Spec spec() const override { return Spec{{{"R", R_}}}; } }; struct LonLatToSpheroidXYZ final : Implementation { @@ -47,6 +47,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { a_(a), b_(b) {} Point3 operator()(const PointLonLat& p) const override { return S::convertSphericalToCartesian(a_, b_, p, 0.); } PointLonLat operator()(const Point3& q) const override { NOTIMP; } + Spec spec() const override { return Spec{{{"a", a_}, {"b", b_}}}; } }; impl_.reset(types::is_approximately_equal(a, b) ? static_cast(new LonLatToSphereXYZ(a)) @@ -62,4 +63,9 @@ LonLatToXYZ::LonLatToXYZ(const Configuration& config) : LonLatToXYZ(config.getDouble("a", config.getDouble("R", 1.)), config.getDouble("b", config.getDouble("R", 1.))) {} +Projection::Spec LonLatToXYZ::spec() const { + return impl_->spec(); +} + + } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LonLatToXYZ.h b/src/eckit/geo/projection/LonLatToXYZ.h index c47061fd0..9b2ea6998 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.h +++ b/src/eckit/geo/projection/LonLatToXYZ.h @@ -47,7 +47,8 @@ class LonLatToXYZ final : public Projection { PointLonLat inv(const Point3& q) const { return (*impl_)(q); } // -- Overridden methods - // None + + Spec spec() const override; // -- Class members // None @@ -69,6 +70,7 @@ class LonLatToXYZ final : public Projection { virtual Point3 operator()(const PointLonLat&) const = 0; virtual PointLonLat operator()(const Point3&) const = 0; + virtual Spec spec() const = 0; }; // -- Members diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index c3df3b4ad..88f168cba 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -12,6 +12,8 @@ #include "eckit/geo/projection/None.h" +#include "eckit/config/MappedConfiguration.h" + namespace eckit::geo::projection { @@ -25,4 +27,9 @@ static ProjectionBuilder __projection4("plate-carree"); None::None(const Configuration&) {} +Projection::Spec None::spec() const { + return Spec{}; +} + + } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index 1a9fc3ff5..3aa618f72 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -44,7 +44,8 @@ class None final : public Projection { // None // -- Overridden methods - // None + + Spec spec() const override; // -- Class members // None diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index f84130307..9b8e531b7 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -12,7 +12,7 @@ #include "eckit/geo/projection/PROJ.h" -#include "eckit/config/Configuration.h" +#include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" @@ -123,4 +123,9 @@ Point PROJ::inv(const Point& q) const { } +Projection::Spec PROJ::spec() const { + return Spec{{{"source", source_}, {"target", target_}}}; +} + + } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index fe87a74c2..cc38f535d 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -83,6 +83,8 @@ class PROJ final : public Projection { Point fwd(const Point&) const override; Point inv(const Point&) const override; + Spec spec() const override; + // -- Class members // None diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 66b4bfc3b..77bb02cde 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -15,7 +15,7 @@ #include #include -#include "eckit/config/Configuration.h" +#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/UnitSphere.h" #include "eckit/geo/util.h" #include "eckit/maths/Matrix3.h" @@ -38,22 +38,32 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : struct NonRotated final : Rotate { PointLonLat operator()(const PointLonLat& p) const override { return p; } + Spec spec() const override { return Spec{}; } }; struct RotationAngle final : Rotate { explicit RotationAngle(double angle) : angle_(angle) {} PointLonLat operator()(const PointLonLat& p) const override { return {p.lon + angle_, p.lat}; } + Spec spec() const override { return Spec{{{"angle", angle_}}}; } const double angle_; }; struct RotationMatrix final : Rotate { explicit RotationMatrix(M&& R) : - R_(R) {} + RotationMatrix(std::move(R), 0, 0, 0) {} + RotationMatrix(M&& R, double south_pole_lon, double south_pole_lat, double angle) : + R_(R), south_pole_lon_(south_pole_lon), south_pole_lat_(south_pole_lat), angle_(angle) {} PointLonLat operator()(const PointLonLat& p) const override { return UnitSphere::convertCartesianToSpherical(R_ * UnitSphere::convertSphericalToCartesian(p)); } + Spec spec() const override { + return Spec{{{"south_pole_lon", south_pole_lon_}, {"south_pole_lat", south_pole_lat_}, {"angle", angle_}}}; + } const M R_; + const double south_pole_lon_; + const double south_pole_lat_; + const double angle_; }; const auto alpha = util::degree_to_radian * angle; @@ -114,4 +124,9 @@ Rotation::Rotation(const Configuration& config) : Rotation(config.getDouble("south_pole_lon"), config.getDouble("south_pole_lat"), config.getDouble("angle", 0)) {} +Projection::Spec Rotation::spec() const { + return fwd_->spec(); +} + + } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index 2ad36a4da..947ef5c81 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -48,7 +48,8 @@ class Rotation final : public Projection { PointLonLat inv(const PointLonLat& q) const { return (*inv_)(q); } // -- Overridden methods - // None + + Spec spec() const override; // -- Class members // None @@ -69,6 +70,7 @@ class Rotation final : public Projection { void operator=(Rotate&&) = delete; virtual PointLonLat operator()(const PointLonLat&) const = 0; + virtual Spec spec() const = 0; }; // -- Members diff --git a/tests/geo/test_projection.cc b/tests/geo/test_projection.cc index e4d69f5a9..e39cb7327 100644 --- a/tests/geo/test_projection.cc +++ b/tests/geo/test_projection.cc @@ -15,12 +15,18 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/geo/Projection.h" +#include "eckit/geo/figure/Sphere.h" #include "eckit/geo/projection/LonLatToXYZ.h" +#include "eckit/geo/projection/Mercator.h" #include "eckit/geo/projection/Rotation.h" +#include "eckit/log/Log.h" #include "eckit/testing/Test.h" -int main(int argc, char* argv[]) { +namespace eckit::test { + + +CASE("projection") { using eckit::MappedConfiguration; using namespace eckit::geo; @@ -30,13 +36,15 @@ int main(int argc, char* argv[]) { Point p = PointLonLat{1, 1}; - { + + SECTION("projection type: none") { Projection projection(ProjectionFactory::instance().get("none").create(MappedConfiguration{})); EXPECT(points_equal(p, projection->inv(p))); EXPECT(points_equal(p, projection->fwd(p))); } - { + + SECTION("projection type: rotation") { MappedConfiguration param({ {"projection", "rotation"}, {"south_pole_lat", -91.}, @@ -49,7 +57,8 @@ int main(int argc, char* argv[]) { EXPECT(points_equal(p, projection->fwd(projection->inv(p)))); } - { + + SECTION("projection type: ll_to_xyz") { Projection s1(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"R", 1.}}))); Projection s2( ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 1.}}))); @@ -85,35 +94,31 @@ int main(int argc, char* argv[]) { } - { - + SECTION("projection type: ll_to_xyz") { const PointLonLat p(723., 1.); // <- FIXME - { - projection::LonLatToXYZ to_xyz(1.); + projection::LonLatToXYZ to_xyz_r(1.); - auto q = to_xyz.fwd(p); - auto r = to_xyz.inv(q); - std::cout << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; + auto q = to_xyz_r.fwd(p); + auto r = to_xyz_r.inv(q); + std::cout << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; - EXPECT(points_equal(p, r)); - } + EXPECT(points_equal(p, r)); + // oblate spheroid (supported) + projection::LonLatToXYZ to_xyz_ab(3., 2.); - { - projection::LonLatToXYZ to_xyz_ab(3., 2.); // oblate - projection::LonLatToXYZ to_xyz_ba(2., 3.); // problate - - for (const auto& lon : {0., 90., 180., 270.}) { - PointLonLat p{lon, 0.}; - std::cout << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) - << ", p_ba(x,y,z): " << to_xyz_ba.fwd(p) << std::endl; - } + for (const auto& lon : {0., 90., 180., 270.}) { + PointLonLat p{lon, 0.}; + std::cout << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) << std::endl; } + + // problate spheroid (not supported) + EXPECT_THROWS(projection::LonLatToXYZ(2., 3.)); } - { + SECTION("projection type: rotation") { const PointLonLat p(1, 1); int delta[] = {-360, -180, -1, 0, 1, 90, 91, 180}; @@ -133,7 +138,8 @@ int main(int argc, char* argv[]) { } - { +#if 0 + SECTION("projection type: rotation") { const int Ni = 12; const int Nj = 3; @@ -230,14 +236,17 @@ int main(int argc, char* argv[]) { PointLonLat a(static_cast(i) * 360. / static_cast(Ni), static_cast(j - Nj) * 90. / static_cast(Nj)); auto b = rot.fwd(a); + auto c = rot.inv(b); + EXPECT(points_equal(b, ref[k])); - EXPECT(points_equal(a, rot.inv(b))); + EXPECT(points_equal(a, c)); } } } +#endif - { + SECTION("projection type: rotation") { const projection::Rotation non_rotated(0., -90., 0.); const projection::Rotation rotation_angle(0., -90., -180.); const projection::Rotation rotation_matrix(4., -40., 180.); @@ -277,52 +286,87 @@ int main(int argc, char* argv[]) { } - if (ProjectionFactory::instance().exists("proj")) { - std::cout.precision(14); + SECTION("projection type: proj") { + if (ProjectionFactory::instance().exists("proj")) { + std::cout.precision(14); - PointLonLat a{12., 55.}; + PointLonLat a{12., 55.}; - struct { - const Point b; - const std::string target; - } tests[] = { - {Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, - {Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, - {a, "EPSG:4326"}, - {a, "EPSG:4979"}, - {Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, - {Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, "+proj=cart +R=6371229."}, - {Point3{3574399.5431832, 759762.07693392, 5218815.216709}, "+proj=cart +ellps=sphere"}, - {a, "+proj=latlon +ellps=sphere"}, - }; + struct { + const Point b; + const std::string target; + } tests[] = { + {Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, + {Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, + {a, "EPSG:4326"}, + {a, "EPSG:4979"}, + {Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, + {Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, "+proj=cart +R=6371229."}, + {Point3{3574399.5431832, 759762.07693392, 5218815.216709}, "+proj=cart +ellps=sphere"}, + {a, "+proj=latlon +ellps=sphere"}, + }; - for (const auto& test : tests) { - Projection projection(ProjectionFactory::instance().get("proj").create( - MappedConfiguration{{{"source", "EPSG:4326"}, {"target", test.target}}})); + for (const auto& test : tests) { + Projection projection(ProjectionFactory::instance().get("proj").create( + MappedConfiguration{{{"source", "EPSG:4326"}, {"target", test.target}}})); #if 0 std::cout << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) << std::endl; #endif - auto b = projection->fwd(a); - auto c = projection->inv(b); + auto b = projection->fwd(a); + auto c = projection->inv(b); - std::cout << "-> a:" << a << " -> fwd(a):" << b << " -> inv(fwd(a)):" << c << std::endl; + std::cout << "-> a:" << a << " -> fwd(a):" << b << " -> inv(fwd(a)):" << c << std::endl; - EXPECT(points_equal(b, test.b)); - EXPECT(points_equal(c, a)); + EXPECT(points_equal(b, test.b)); + EXPECT(points_equal(c, a)); - Projection reverse(ProjectionFactory::instance().get("proj").create( - MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}}))); + Projection reverse(ProjectionFactory::instance().get("proj").create( + MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}}))); - auto d = reverse->fwd(test.b); - auto e = reverse->inv(d); + auto d = reverse->fwd(test.b); + auto e = reverse->inv(d); - std::cout << "-> b:" << test.b << " -> fwd(b):" << d << " -> inv(fwd(b)):" << e << std::endl; + std::cout << "-> b:" << test.b << " -> fwd(b):" << d << " -> inv(fwd(b)):" << e << std::endl; - EXPECT(points_equal(d, a)); - EXPECT(points_equal(e, test.b)); + EXPECT(points_equal(d, a)); + EXPECT(points_equal(e, test.b)); + } } } + + + SECTION("projection type: mercator") { + PointLonLat first{262.036, 14.7365}; + + { + projection::Mercator projection(0., 14., new figure::Sphere(6371229.), first); + + auto p = projection.inv({0, 0}); + Log::info() << p << std::endl; + + auto q = projection.fwd(p); + Log::info() << q << std::endl; + } + + { + projection::Mercator projection(-180., 0., new figure::Sphere(1.), {0, 0}); + + auto q = projection.fwd({-75, 35}); + Log::info() << q << std::endl; + + auto p = projection.inv(q); + Log::info() << p << std::endl; + } + } +} + + +} // namespace eckit::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); } From ada53ab841ace5ca83054e0d477087bba93744c4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 18 Oct 2023 17:11:16 +0100 Subject: [PATCH 354/737] eckit::geo grid RegularLL --- src/eckit/geo/grid/regular/RegularLL.cc | 27 ++++++++++--------------- src/eckit/geo/grid/regular/RegularLL.h | 11 ++++++---- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index d7660149c..2e58ec568 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -100,30 +100,24 @@ struct DiscreteRange { RegularLL::RegularLL(const Configuration& config) : - RegularLL( - Increments{config}, area::BoundingBox{config}, {config.getDouble("west", 0), config.getDouble("south", 0)}) {} + RegularLL(Increments{config}, + area::BoundingBox{config}, + PointLonLat{config.getDouble("reference_lon", config.getDouble("west", 0)), + config.getDouble("reference_lat", config.getDouble("south", -90))}) {} -RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& ref) : +RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& reference) : Regular(bbox), - ni_(DiscreteRange(bbox.west(), bbox.east(), inc.west_east, ref.lon, 360).n), - nj_(DiscreteRange(bbox.south(), bbox.north(), inc.south_north, ref.lat).n), - reference_(ref) { + ni_(DiscreteRange(bbox.west(), bbox.east(), inc.west_east, reference.lon, 360).n), + nj_(DiscreteRange(bbox.south(), bbox.north(), inc.south_north, reference.lat).n), + reference_(reference) { ASSERT(ni_ > 0); ASSERT(nj_ > 0); } -RegularLL::RegularLL(size_t ni, size_t nj, const area::BoundingBox& bbox, const PointLonLat& ref) : - Regular(bbox), ni_(ni), nj_(nj), reference_(ref) {} - - -RegularLL::RegularLL(const Increments& inc, const PointLonLat& ref) : - RegularLL(inc, area::BoundingBox::make_global_prime(), ref) {} - - -RegularLL::RegularLL(size_t ni, size_t nj, const PointLonLat& ref) : - RegularLL(ni, nj, area::BoundingBox::make_global_prime(), ref) {} +RegularLL::RegularLL(size_t ni, size_t nj, const area::BoundingBox& bbox, const PointLonLat& reference) : + Regular(bbox), ni_(ni), nj_(nj), reference_(reference) {} Grid::iterator RegularLL::cbegin() const { @@ -135,6 +129,7 @@ Grid::iterator RegularLL::cend() const { return iterator{new geo::iterator::Regular(*this, size())}; } + const std::vector& RegularLL::longitudes() const { NOTIMP; } diff --git a/src/eckit/geo/grid/regular/RegularLL.h b/src/eckit/geo/grid/regular/RegularLL.h index 32d3cadf5..eb5414596 100644 --- a/src/eckit/geo/grid/regular/RegularLL.h +++ b/src/eckit/geo/grid/regular/RegularLL.h @@ -35,11 +35,14 @@ class RegularLL final : public Regular { explicit RegularLL(const Configuration&); - RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& reference = {0, 0}); - RegularLL(size_t ni, size_t nj, const area::BoundingBox&, const PointLonLat& reference = {0, 0}); + explicit RegularLL(const Increments& increments, const area::BoundingBox& bbox = {}) : + RegularLL(increments, bbox, {bbox.south(), bbox.west()}) {} - explicit RegularLL(const Increments&, const PointLonLat& reference = {0, 0}); - RegularLL(size_t ni, size_t nj, const PointLonLat& reference = {0, 0}); + explicit RegularLL(size_t ni, size_t nj, const area::BoundingBox& bbox = {}) : + RegularLL(ni, nj, bbox, {bbox.south(), bbox.west()}) {} + + RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& reference); + RegularLL(size_t ni, size_t nj, const area::BoundingBox&, const PointLonLat& reference); // -- Destructor // None From 5de474f06a2590421e75946771ecaa763935458b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 25 Jul 2023 16:06:48 +0100 Subject: [PATCH 355/737] eckit::geo HEALPix testing ring ordering --- healpix.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 healpix.py diff --git a/healpix.py b/healpix.py new file mode 100644 index 000000000..1a868eef6 --- /dev/null +++ b/healpix.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 + + +import numpy as np + + +class Healpix: + def __init__(self, Nside): + assert 0 < Nside + self._N = Nside + + pl = np.array([self.pl(i) for i in range(self.Nrow())], dtype=int) + self._pla = np.cumsum(pl) + + def Nside(self): + return self._N + + def Nrow(self): + return 4 * self._N - 1 + + def size(self): + return 12 * self._N * self._N + + def pl(self, i): + assert 0 <= i < self.Nrow(), f"i={i}" + if i >= self._N * 2: + return self.pl(self.Nrow() - 1 - i) + return self._N * min(4, i + 1) + + def row(self, count): + assert 0 <= count < self.size() + return np.searchsorted(self._pla, count, side="right") + + def latlon(self, count): + r = self.row(count) + dlat = 45.0 / self._N + dlon = 180.0 / self.pl(r) + + j = count - (self._pla[r - 1], 0)[r == 0] + lon = dlon * (2 * j + (0, 1)[r % 2]) + lat = 90.0 - dlat * (r + 1) + + return lat, lon + + +h = Healpix(4) + +for i in range(h.size()): + print(h.latlon(i)) From 7b8fa1ce5730c682e93cecce2dc3d18326468be4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 25 Jul 2023 16:43:35 +0100 Subject: [PATCH 356/737] eckit::geo HEALPix testing ring ordering --- healpix.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/healpix.py b/healpix.py index 1a868eef6..ba0b3c2e1 100644 --- a/healpix.py +++ b/healpix.py @@ -4,7 +4,7 @@ import numpy as np -class Healpix: +class HEALPix: def __init__(self, Nside): assert 0 < Nside self._N = Nside @@ -36,14 +36,14 @@ def latlon(self, count): dlat = 45.0 / self._N dlon = 180.0 / self.pl(r) - j = count - (self._pla[r - 1], 0)[r == 0] + j = count if r == 0 else count - self._pla[r - 1] lon = dlon * (2 * j + (0, 1)[r % 2]) lat = 90.0 - dlat * (r + 1) return lat, lon -h = Healpix(4) +h = HEALPix(4) for i in range(h.size()): print(h.latlon(i)) From becc00a4db84583fd0725e0cf9dab0d8d0cfdb16 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 3 Aug 2023 17:47:27 +0100 Subject: [PATCH 357/737] eckit::geo HEALPix testing ring ordering --- healpix.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/healpix.py b/healpix.py index ba0b3c2e1..65b180569 100644 --- a/healpix.py +++ b/healpix.py @@ -18,7 +18,7 @@ def Nside(self): def Nrow(self): return 4 * self._N - 1 - def size(self): + def __len__(self): return 12 * self._N * self._N def pl(self, i): @@ -27,23 +27,21 @@ def pl(self, i): return self.pl(self.Nrow() - 1 - i) return self._N * min(4, i + 1) - def row(self, count): - assert 0 <= count < self.size() - return np.searchsorted(self._pla, count, side="right") - def latlon(self, count): - r = self.row(count) + assert 0 <= count < len(self) + + i = np.searchsorted(self._pla, count, side="right") + j = count if i == 0 else count - self._pla[i - 1] dlat = 45.0 / self._N - dlon = 180.0 / self.pl(r) + dlon = 180.0 / self.pl(i) - j = count if r == 0 else count - self._pla[r - 1] - lon = dlon * (2 * j + (0, 1)[r % 2]) - lat = 90.0 - dlat * (r + 1) + lon = dlon * (2 * j + (0, 1)[i % 2]) + lat = 90.0 - dlat * (i + 1) return lat, lon h = HEALPix(4) -for i in range(h.size()): +for i in range(len(h)): print(h.latlon(i)) From 8bd90b29c315a7b5cd3ea6fbef313b6c420f2a73 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 3 Aug 2023 20:46:45 +0100 Subject: [PATCH 358/737] eckit::geo HEALPix testing nested ordering --- HEALPix.cc | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++ HEALPix.h | 19 ++++++ main.cc | 28 ++++++++ 3 files changed, 232 insertions(+) create mode 100644 HEALPix.cc create mode 100644 HEALPix.h create mode 100644 main.cc diff --git a/HEALPix.cc b/HEALPix.cc new file mode 100644 index 000000000..8ec8a3395 --- /dev/null +++ b/HEALPix.cc @@ -0,0 +1,185 @@ +#include "HEALPix.h" + +#include +#include +#include +#include +#include +#include + + +namespace { + + +struct CodecFijNest { + static constexpr uint64_t __masks[] = {0x00000000ffffffff, 0x0000ffff0000ffff, 0x00ff00ff00ff00ff, + 0x0f0f0f0f0f0f0f0f, 0x3333333333333333, 0x5555555555555555}; + + inline static int nest_encode_bits(int n) { + auto b = static_cast(n) & __masks[0]; + b = (b ^ (b << 16)) & __masks[1]; + b = (b ^ (b << 8)) & __masks[2]; + b = (b ^ (b << 4)) & __masks[3]; + b = (b ^ (b << 2)) & __masks[4]; + b = (b ^ (b << 1)) & __masks[5]; + return static_cast(b); + } + + inline static int nest_decode_bits(int n) { + auto b = static_cast(n) & __masks[5]; + b = (b ^ (b >> 1)) & __masks[4]; + b = (b ^ (b >> 2)) & __masks[3]; + b = (b ^ (b >> 4)) & __masks[2]; + b = (b ^ (b >> 8)) & __masks[1]; + b = (b ^ (b >> 16)) & __masks[0]; + return static_cast(b); + } + + static std::tuple nest_to_fij(int n, int k) { + assert(0 <= n); + auto f = n >> (2 * k); // f = n / (Nside * Nside) + n &= (1 << (2 * k)) - 1; // n = n % (Nside * Nside) + auto i = nest_decode_bits(n); + auto j = nest_decode_bits(n >> 1); + return {f, i, j}; + } + + static int fij_to_nest(int f, int i, int j, int k) { + return (f << (2 * k)) + nest_encode_bits(i) + (nest_encode_bits(j) << 1); + } +}; + + +inline int sqrt(int n) { + return static_cast(std::sqrt(static_cast(n) + 0.5)); +} + + +// for division result within [0; 3] +inline int div_03(int a, int b) { + int t = (a >= (b << 1)) ? 1 : 0; + a -= t * (b << 1); + return (t << 1) + (a >= b ? 1 : 0); +} + + +inline bool is_power_of_2(int n) { + return std::bitset(n).count() == 1; +} + + +inline int pll(int f) { + constexpr int __pll[] = {1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7}; + return __pll[f]; +} + + +} // unnamed namespace + + +HEALPix::HEALPix(int Nside) : + Nside_(Nside), + Npix_(size()), + Ncap_((Nside * (Nside - 1)) << 1), + k_(is_power_of_2(Nside_) ? static_cast(std::log2(Nside)) : -1) { + assert(0 <= k_); // (specific to nested ordering) + assert(0 < Nside_); +} + + +int HEALPix::ring_to_nest(int r) const { + auto to_nest = [&](int f, //!< base pixel index + int ring, //!< 1-based ring number + int Nring, //!< number of pixels in ring + int phi, //!< index in longitude + int shift //!< if ring's first pixel is not at phi=0 + ) -> int { + int r = ((2 + (f >> 2)) << k_) - ring - 1; + int p = 2 * phi - pll(f) * Nring - shift - 1; + if (p >= 2 * Nside_) { + p -= 8 * Nside_; + } + + int i = (r + p) >> 1; + int j = (r - p) >> 1; + + assert(f < 12 && i < Nside_ && j < Nside_); + return CodecFijNest::fij_to_nest(f, i, j, k_); + }; + + if (r < Ncap_) { + // North polar cap + int Nring = (1 + sqrt(2 * r + 1)) >> 1; + int phi = 1 + r - 2 * Nring * (Nring - 1); + int r = Nring; + int f = div_03(phi - 1, Nring); + + return to_nest(f, r, Nring, phi, 0); + } + + if (Npix_ - Ncap_ <= r) { + // South polar cap + int Nring = (1 + sqrt(2 * Npix_ - 2 * r - 1)) >> 1; + int phi = 1 + r + 2 * Nring * (Nring - 1) + 4 * Nring - Npix_; + int ring = 4 * Nside_ - Nring; // (from South pole) + int f = div_03(phi - 1, Nring) + 8; + + return to_nest(f, ring, Nring, phi, 0); + } + + // Equatorial belt + int ip = r - Ncap_; + int tmp = ip >> (k_ + 2); + + int Nring = Nside_; + int phi = ip - tmp * 4 * Nside_ + 1; + int ring = tmp + Nside_; + + int ifm = 1 + ((phi - 1 - ((1 + tmp) >> 1)) >> k_); + int ifp = 1 + ((phi - 1 - ((1 - tmp + 2 * Nside_) >> 1)) >> k_); + int f = (ifp == ifm) ? (ifp | 4) : ((ifp < ifm) ? ifp : (ifm + 8)); + + return to_nest(f, ring, Nring, phi, ring & 1); +} + + +int HEALPix::nest_to_ring(int n) const { + auto [f, i, j] = CodecFijNest::nest_to_fij(n, k_); + assert(f < 12 && i < Nside_ && j < Nside_); + + auto to_ring_local = [&](int f, int i, int j, + int Nring, //!< number of pixels in ring + int shift //!< if ring's first pixel is/is not at phi=0 + ) -> int { + Nring >>= 2; + int r = (pll(f) * Nring + i - j + 1 + shift) / 2 - 1; + assert(r < 4 * Nring); + + return r < 0 ? r + 4 * Nside_ : r; + }; + + const int ring = ((f >> 2) + 2) * Nside_ - i - j - 1; // 1-based ring number + if (ring < Nside_) { + // North polar cap + int Nring = 4 * ring; + int r0 = 2 * ring * (ring - 1); // index of first ring pixel (ring numbering) + + return r0 + to_ring_local(f, i, j, Nring, 0); + } + + if (ring < 3 * Nside_) { + // South polar cap + int Nring = 4 * Nside_; + int r0 = Ncap_ + (ring - Nside_) * Nring; // index of first ring pixel (ring numbering) + int shift = (ring - Nside_) & 1; + + return r0 + to_ring_local(f, i, j, Nring, shift); + } + + // Equatorial belt + int N = 4 * Nside_ - ring; + int Nring = 4 * N; + int r0 = Npix_ - 2 * N * (N + 1); // index of first ring pixel (ring numbering) + + return r0 + to_ring_local(f, i, j, Nring, 0); +} diff --git a/HEALPix.h b/HEALPix.h new file mode 100644 index 000000000..130d36d87 --- /dev/null +++ b/HEALPix.h @@ -0,0 +1,19 @@ +#pragma once + + +class HEALPix { +public: + explicit HEALPix(int Nside); + + int size() const { return 12 * Nside_ * Nside_; } + int nside() const { return Nside_; } + + int nest_to_ring(int) const; + int ring_to_nest(int) const; + +private: + const int Nside_; // up to 2^13 + const int Npix_; + const int Ncap_; + const int k_; +}; diff --git a/main.cc b/main.cc new file mode 100644 index 000000000..e763ff0e6 --- /dev/null +++ b/main.cc @@ -0,0 +1,28 @@ + +#include +#include +#include // for std::stoi + +#include "HEALPix.h" + + +int main(int argc, char* argv[]) { + for (int a = 1; a < argc; ++a) { + int nside = std::stoi(argv[a]); + + HEALPix h(nside); + + std::cout << "Nside=" << h.nside() << "\n" + << "r->n\t| n->r" << std::endl; + + for (int i = 0; i < h.size(); ++i) { + auto n = h.ring_to_nest(i); + auto r = h.nest_to_ring(i); + assert(i == h.ring_to_nest(r) && i == h.nest_to_ring(n)); + + std::cout << i << " -> " << n << "\t| " << i << " -> " << r << std::endl; + } + } + + return 0; +} From 7280e619ba38da28fec6a3677f23d08d3ba08420 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 23 Oct 2023 11:13:56 +0100 Subject: [PATCH 359/737] Cleanup for merge --- healpix.py | 47 ------------------- main.cc | 28 ----------- .../eckit/geo/grid/reduced/HEALPixRenumber.cc | 0 .../eckit/geo/grid/reduced/HEALPixRenumber.h | 0 4 files changed, 75 deletions(-) delete mode 100644 healpix.py delete mode 100644 main.cc rename HEALPix.cc => src/eckit/geo/grid/reduced/HEALPixRenumber.cc (100%) rename HEALPix.h => src/eckit/geo/grid/reduced/HEALPixRenumber.h (100%) diff --git a/healpix.py b/healpix.py deleted file mode 100644 index 65b180569..000000000 --- a/healpix.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python3 - - -import numpy as np - - -class HEALPix: - def __init__(self, Nside): - assert 0 < Nside - self._N = Nside - - pl = np.array([self.pl(i) for i in range(self.Nrow())], dtype=int) - self._pla = np.cumsum(pl) - - def Nside(self): - return self._N - - def Nrow(self): - return 4 * self._N - 1 - - def __len__(self): - return 12 * self._N * self._N - - def pl(self, i): - assert 0 <= i < self.Nrow(), f"i={i}" - if i >= self._N * 2: - return self.pl(self.Nrow() - 1 - i) - return self._N * min(4, i + 1) - - def latlon(self, count): - assert 0 <= count < len(self) - - i = np.searchsorted(self._pla, count, side="right") - j = count if i == 0 else count - self._pla[i - 1] - dlat = 45.0 / self._N - dlon = 180.0 / self.pl(i) - - lon = dlon * (2 * j + (0, 1)[i % 2]) - lat = 90.0 - dlat * (i + 1) - - return lat, lon - - -h = HEALPix(4) - -for i in range(len(h)): - print(h.latlon(i)) diff --git a/main.cc b/main.cc deleted file mode 100644 index e763ff0e6..000000000 --- a/main.cc +++ /dev/null @@ -1,28 +0,0 @@ - -#include -#include -#include // for std::stoi - -#include "HEALPix.h" - - -int main(int argc, char* argv[]) { - for (int a = 1; a < argc; ++a) { - int nside = std::stoi(argv[a]); - - HEALPix h(nside); - - std::cout << "Nside=" << h.nside() << "\n" - << "r->n\t| n->r" << std::endl; - - for (int i = 0; i < h.size(); ++i) { - auto n = h.ring_to_nest(i); - auto r = h.nest_to_ring(i); - assert(i == h.ring_to_nest(r) && i == h.nest_to_ring(n)); - - std::cout << i << " -> " << n << "\t| " << i << " -> " << r << std::endl; - } - } - - return 0; -} diff --git a/HEALPix.cc b/src/eckit/geo/grid/reduced/HEALPixRenumber.cc similarity index 100% rename from HEALPix.cc rename to src/eckit/geo/grid/reduced/HEALPixRenumber.cc diff --git a/HEALPix.h b/src/eckit/geo/grid/reduced/HEALPixRenumber.h similarity index 100% rename from HEALPix.h rename to src/eckit/geo/grid/reduced/HEALPixRenumber.h From 1d40c506e62c97294f38d1aa135c79f536522368 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 23 Oct 2023 18:00:44 +0100 Subject: [PATCH 360/737] eckit::geo::Grid::reorder --- src/eckit/geo/Grid.cc | 15 +- src/eckit/geo/Grid.h | 5 +- src/eckit/geo/grid/reduced/HEALPix.cc | 238 +++++++++++++++++- src/eckit/geo/grid/reduced/HEALPix.h | 4 + src/eckit/geo/grid/reduced/HEALPixRenumber.cc | 185 -------------- src/eckit/geo/grid/reduced/HEALPixRenumber.h | 19 -- tests/geo/CMakeLists.txt | 1 + tests/geo/test_grid_reorder.cc | 81 ++++++ 8 files changed, 340 insertions(+), 208 deletions(-) delete mode 100644 src/eckit/geo/grid/reduced/HEALPixRenumber.cc delete mode 100644 src/eckit/geo/grid/reduced/HEALPixRenumber.h create mode 100644 tests/geo/test_grid_reorder.cc diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 590adab18..4a087ef53 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -13,6 +13,7 @@ #include "eckit/geo/Grid.h" #include +#include #include #include "eckit/config/DynamicConfiguration.h" @@ -93,11 +94,23 @@ Ordering Grid::order() const { } -Renumber Grid::reorder(const PointLonLat&) const { +Renumber Grid::reorder(Ordering) const { throw NotImplemented("Grid::reorder"); } +Grid* Grid::grid_reorder(Ordering) const { + throw NotImplemented("Grid::grid_reorder"); +} + + +Renumber Grid::no_reorder(size_t size) { + Renumber ren(size); + std::iota(ren.begin(), ren.end(), 0); + return ren; +} + + GridFactory& GridFactory::instance() { static GridFactory obj; return obj; diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 9cfd1bdbd..36ac5a9dd 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -124,7 +124,8 @@ class Grid { virtual std::pair, std::vector> to_latlon() const; virtual Ordering order() const; - virtual Renumber reorder(const PointLonLat&) const; + virtual Renumber reorder(Ordering) const; + virtual Grid* grid_reorder(Ordering) const; // -- Overridden methods // None @@ -146,6 +147,8 @@ class Grid { area::BoundingBox bbox() const { return bbox_; } void bbox(const area::BoundingBox& bbox) { bbox_ = bbox; } + static Renumber no_reorder(size_t size); + // -- Overridden methods // None diff --git a/src/eckit/geo/grid/reduced/HEALPix.cc b/src/eckit/geo/grid/reduced/HEALPix.cc index 252354539..b93d5bfcd 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.cc +++ b/src/eckit/geo/grid/reduced/HEALPix.cc @@ -12,19 +12,218 @@ #include "eckit/geo/grid/reduced/HEALPix.h" +#include +#include +#include +#include +#include + #include "eckit/config/MappedConfiguration.h" #include "eckit/geo/iterator/Reduced.h" #include "eckit/geo/util.h" #include "eckit/utils/Translator.h" +namespace { + + +struct CodecFijNest { + static constexpr uint64_t __masks[] = {0x00000000ffffffff, + 0x0000ffff0000ffff, + 0x00ff00ff00ff00ff, + 0x0f0f0f0f0f0f0f0f, + 0x3333333333333333, + 0x5555555555555555}; + + inline static int nest_encode_bits(int n) { + auto b = static_cast(n) & __masks[0]; + b = (b ^ (b << 16)) & __masks[1]; + b = (b ^ (b << 8)) & __masks[2]; + b = (b ^ (b << 4)) & __masks[3]; + b = (b ^ (b << 2)) & __masks[4]; + b = (b ^ (b << 1)) & __masks[5]; + return static_cast(b); + } + + inline static int nest_decode_bits(int n) { + auto b = static_cast(n) & __masks[5]; + b = (b ^ (b >> 1)) & __masks[4]; + b = (b ^ (b >> 2)) & __masks[3]; + b = (b ^ (b >> 4)) & __masks[2]; + b = (b ^ (b >> 8)) & __masks[1]; + b = (b ^ (b >> 16)) & __masks[0]; + return static_cast(b); + } + + static std::tuple nest_to_fij(int n, int k) { + ASSERT(0 <= n); + auto f = n >> (2 * k); // f = n / (Nside * Nside) + n &= (1 << (2 * k)) - 1; // n = n % (Nside * Nside) + auto i = nest_decode_bits(n); + auto j = nest_decode_bits(n >> 1); + return {f, i, j}; + } + + static int fij_to_nest(int f, int i, int j, int k) { + return (f << (2 * k)) + nest_encode_bits(i) + (nest_encode_bits(j) << 1); + } +}; + + +inline int sqrt(int n) { + return static_cast(std::sqrt(static_cast(n) + 0.5)); +} + + +// for division result within [0; 3] +inline int div_03(int a, int b) { + int t = (a >= (b << 1)) ? 1 : 0; + a -= t * (b << 1); + return (t << 1) + (a >= b ? 1 : 0); +} + + +inline bool is_power_of_2(int n) { + return std::bitset(n).count() == 1; +} + + +inline int pll(int f) { + constexpr int __pll[] = {1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7}; + return __pll[f]; +} + + +class Reorder { +public: + explicit Reorder(int Nside) : + Nside_(Nside), + Npix_(size()), + Ncap_((Nside * (Nside - 1)) << 1), + k_(is_power_of_2(Nside_) ? static_cast(std::log2(Nside)) : -1) { + ASSERT(0 <= k_); // (specific to nested ordering) + ASSERT(0 < Nside_); + } + + int size() const { return 12 * Nside_ * Nside_; } + int nside() const { return Nside_; } + + int ring_to_nest(int r) const { + auto to_nest = [&](int f, //!< base pixel index + int ring, //!< 1-based ring number + int Nring, //!< number of pixels in ring + int phi, //!< index in longitude + int shift //!< if ring's first pixel is not at phi=0 + ) -> int { + int r = ((2 + (f >> 2)) << k_) - ring - 1; + int p = 2 * phi - pll(f) * Nring - shift - 1; + if (p >= 2 * Nside_) { + p -= 8 * Nside_; + } + + int i = (r + p) >> 1; + int j = (r - p) >> 1; + + ASSERT(f < 12 && i < Nside_ && j < Nside_); + return CodecFijNest::fij_to_nest(f, i, j, k_); + }; + + if (r < Ncap_) { + // North polar cap + int Nring = (1 + sqrt(2 * r + 1)) >> 1; + int phi = 1 + r - 2 * Nring * (Nring - 1); + int r = Nring; + int f = div_03(phi - 1, Nring); + + return to_nest(f, r, Nring, phi, 0); + } + + if (Npix_ - Ncap_ <= r) { + // South polar cap + int Nring = (1 + sqrt(2 * Npix_ - 2 * r - 1)) >> 1; + int phi = 1 + r + 2 * Nring * (Nring - 1) + 4 * Nring - Npix_; + int ring = 4 * Nside_ - Nring; // (from South pole) + int f = div_03(phi - 1, Nring) + 8; + + return to_nest(f, ring, Nring, phi, 0); + } + + // Equatorial belt + int ip = r - Ncap_; + int tmp = ip >> (k_ + 2); + + int Nring = Nside_; + int phi = ip - tmp * 4 * Nside_ + 1; + int ring = tmp + Nside_; + + int ifm = 1 + ((phi - 1 - ((1 + tmp) >> 1)) >> k_); + int ifp = 1 + ((phi - 1 - ((1 - tmp + 2 * Nside_) >> 1)) >> k_); + int f = (ifp == ifm) ? (ifp | 4) : ((ifp < ifm) ? ifp : (ifm + 8)); + + return to_nest(f, ring, Nring, phi, ring & 1); + } + + int nest_to_ring(int n) const { + auto [f, i, j] = CodecFijNest::nest_to_fij(n, k_); + ASSERT(f < 12 && i < Nside_ && j < Nside_); + + auto to_ring_local = [&](int f, + int i, + int j, + int Nring, //!< number of pixels in ring + int shift //!< if ring's first pixel is/is not at phi=0 + ) -> int { + Nring >>= 2; + int r = (pll(f) * Nring + i - j + 1 + shift) / 2 - 1; + ASSERT(r < 4 * Nring); + + return r < 0 ? r + 4 * Nside_ : r; + }; + + const int ring = ((f >> 2) + 2) * Nside_ - i - j - 1; // 1-based ring number + if (ring < Nside_) { + // North polar cap + int Nring = 4 * ring; + int r0 = 2 * ring * (ring - 1); // index of first ring pixel (ring numbering) + + return r0 + to_ring_local(f, i, j, Nring, 0); + } + + if (ring < 3 * Nside_) { + // South polar cap + int Nring = 4 * Nside_; + int r0 = Ncap_ + (ring - Nside_) * Nring; // index of first ring pixel (ring numbering) + int shift = (ring - Nside_) & 1; + + return r0 + to_ring_local(f, i, j, Nring, shift); + } + + // Equatorial belt + int N = 4 * Nside_ - ring; + int Nring = 4 * N; + int r0 = Npix_ - 2 * N * (N + 1); // index of first ring pixel (ring numbering) + + return r0 + to_ring_local(f, i, j, Nring, 0); + } + +private: + const int Nside_; // up to 2^13 + const int Npix_; + const int Ncap_; + const int k_; +}; + + +} // unnamed namespace + + namespace eckit::geo::grid::reduced { static Ordering ordering_from_string(const std::string& str) { return str == "ring" ? Ordering::healpix_ring : str == "nested" ? Ordering::healpix_nested - : throw AssertionFailed("HEALPix::Ordering", Here()); + : throw AssertionFailed("HEALPix: supported orderings: ring, nested", Here()); } @@ -35,7 +234,42 @@ HEALPix::HEALPix(const Configuration& config) : HEALPix::HEALPix(size_t Nside, Ordering ordering) : Reduced(area::BoundingBox::make_global_prime()), N_(Nside), ordering_(ordering) { ASSERT(N_ > 0); - ASSERT(ordering_ == Ordering::healpix_ring); + ASSERT_MSG(ordering == Ordering::healpix_ring || ordering == Ordering::healpix_nested, + "HEALPix: supported orderings: ring, nested"); + + if (ordering_ == Ordering::healpix_nested) { + ASSERT(is_power_of_2(Nside)); + } +} + + +Renumber HEALPix::reorder(Ordering ordering) const { + ASSERT_MSG(ordering == Ordering::healpix_ring || ordering == Ordering::healpix_nested, + "HEALPix: supported orderings: ring, nested"); + + if (ordering == ordering_) { + return Grid::no_reorder(size()); + } + + if (ordering == Ordering::healpix_ring) { + const Reorder reorder(static_cast(N_)); + Renumber ren(size()); + for (int i = 0, N = static_cast(size()); i < N; ++i) { + ren[i] = reorder.nest_to_ring(i); + } + return ren; + } + + if (ordering == Ordering::healpix_nested) { + const Reorder reorder(static_cast(N_)); + Renumber ren(size()); + for (int i = 0, N = static_cast(size()); i < N; ++i) { + ren[i] = reorder.ring_to_nest(i); + } + return ren; + } + + throw AssertionFailed("HEALPix: supported orderings: ring, nested", Here()); } diff --git a/src/eckit/geo/grid/reduced/HEALPix.h b/src/eckit/geo/grid/reduced/HEALPix.h index d3a2599fb..fd1d2c642 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.h +++ b/src/eckit/geo/grid/reduced/HEALPix.h @@ -51,6 +51,10 @@ class HEALPix final : public Reduced { size_t ni(size_t j) const override; size_t nj() const override; + Ordering order() const override { return ordering_; } + Renumber reorder(Ordering) const override; + Grid* grid_reorder(Ordering ordering) const override { return new HEALPix(N_, ordering); } + // -- Class members static Configuration* config(const std::string& name); diff --git a/src/eckit/geo/grid/reduced/HEALPixRenumber.cc b/src/eckit/geo/grid/reduced/HEALPixRenumber.cc deleted file mode 100644 index 8ec8a3395..000000000 --- a/src/eckit/geo/grid/reduced/HEALPixRenumber.cc +++ /dev/null @@ -1,185 +0,0 @@ -#include "HEALPix.h" - -#include -#include -#include -#include -#include -#include - - -namespace { - - -struct CodecFijNest { - static constexpr uint64_t __masks[] = {0x00000000ffffffff, 0x0000ffff0000ffff, 0x00ff00ff00ff00ff, - 0x0f0f0f0f0f0f0f0f, 0x3333333333333333, 0x5555555555555555}; - - inline static int nest_encode_bits(int n) { - auto b = static_cast(n) & __masks[0]; - b = (b ^ (b << 16)) & __masks[1]; - b = (b ^ (b << 8)) & __masks[2]; - b = (b ^ (b << 4)) & __masks[3]; - b = (b ^ (b << 2)) & __masks[4]; - b = (b ^ (b << 1)) & __masks[5]; - return static_cast(b); - } - - inline static int nest_decode_bits(int n) { - auto b = static_cast(n) & __masks[5]; - b = (b ^ (b >> 1)) & __masks[4]; - b = (b ^ (b >> 2)) & __masks[3]; - b = (b ^ (b >> 4)) & __masks[2]; - b = (b ^ (b >> 8)) & __masks[1]; - b = (b ^ (b >> 16)) & __masks[0]; - return static_cast(b); - } - - static std::tuple nest_to_fij(int n, int k) { - assert(0 <= n); - auto f = n >> (2 * k); // f = n / (Nside * Nside) - n &= (1 << (2 * k)) - 1; // n = n % (Nside * Nside) - auto i = nest_decode_bits(n); - auto j = nest_decode_bits(n >> 1); - return {f, i, j}; - } - - static int fij_to_nest(int f, int i, int j, int k) { - return (f << (2 * k)) + nest_encode_bits(i) + (nest_encode_bits(j) << 1); - } -}; - - -inline int sqrt(int n) { - return static_cast(std::sqrt(static_cast(n) + 0.5)); -} - - -// for division result within [0; 3] -inline int div_03(int a, int b) { - int t = (a >= (b << 1)) ? 1 : 0; - a -= t * (b << 1); - return (t << 1) + (a >= b ? 1 : 0); -} - - -inline bool is_power_of_2(int n) { - return std::bitset(n).count() == 1; -} - - -inline int pll(int f) { - constexpr int __pll[] = {1, 3, 5, 7, 0, 2, 4, 6, 1, 3, 5, 7}; - return __pll[f]; -} - - -} // unnamed namespace - - -HEALPix::HEALPix(int Nside) : - Nside_(Nside), - Npix_(size()), - Ncap_((Nside * (Nside - 1)) << 1), - k_(is_power_of_2(Nside_) ? static_cast(std::log2(Nside)) : -1) { - assert(0 <= k_); // (specific to nested ordering) - assert(0 < Nside_); -} - - -int HEALPix::ring_to_nest(int r) const { - auto to_nest = [&](int f, //!< base pixel index - int ring, //!< 1-based ring number - int Nring, //!< number of pixels in ring - int phi, //!< index in longitude - int shift //!< if ring's first pixel is not at phi=0 - ) -> int { - int r = ((2 + (f >> 2)) << k_) - ring - 1; - int p = 2 * phi - pll(f) * Nring - shift - 1; - if (p >= 2 * Nside_) { - p -= 8 * Nside_; - } - - int i = (r + p) >> 1; - int j = (r - p) >> 1; - - assert(f < 12 && i < Nside_ && j < Nside_); - return CodecFijNest::fij_to_nest(f, i, j, k_); - }; - - if (r < Ncap_) { - // North polar cap - int Nring = (1 + sqrt(2 * r + 1)) >> 1; - int phi = 1 + r - 2 * Nring * (Nring - 1); - int r = Nring; - int f = div_03(phi - 1, Nring); - - return to_nest(f, r, Nring, phi, 0); - } - - if (Npix_ - Ncap_ <= r) { - // South polar cap - int Nring = (1 + sqrt(2 * Npix_ - 2 * r - 1)) >> 1; - int phi = 1 + r + 2 * Nring * (Nring - 1) + 4 * Nring - Npix_; - int ring = 4 * Nside_ - Nring; // (from South pole) - int f = div_03(phi - 1, Nring) + 8; - - return to_nest(f, ring, Nring, phi, 0); - } - - // Equatorial belt - int ip = r - Ncap_; - int tmp = ip >> (k_ + 2); - - int Nring = Nside_; - int phi = ip - tmp * 4 * Nside_ + 1; - int ring = tmp + Nside_; - - int ifm = 1 + ((phi - 1 - ((1 + tmp) >> 1)) >> k_); - int ifp = 1 + ((phi - 1 - ((1 - tmp + 2 * Nside_) >> 1)) >> k_); - int f = (ifp == ifm) ? (ifp | 4) : ((ifp < ifm) ? ifp : (ifm + 8)); - - return to_nest(f, ring, Nring, phi, ring & 1); -} - - -int HEALPix::nest_to_ring(int n) const { - auto [f, i, j] = CodecFijNest::nest_to_fij(n, k_); - assert(f < 12 && i < Nside_ && j < Nside_); - - auto to_ring_local = [&](int f, int i, int j, - int Nring, //!< number of pixels in ring - int shift //!< if ring's first pixel is/is not at phi=0 - ) -> int { - Nring >>= 2; - int r = (pll(f) * Nring + i - j + 1 + shift) / 2 - 1; - assert(r < 4 * Nring); - - return r < 0 ? r + 4 * Nside_ : r; - }; - - const int ring = ((f >> 2) + 2) * Nside_ - i - j - 1; // 1-based ring number - if (ring < Nside_) { - // North polar cap - int Nring = 4 * ring; - int r0 = 2 * ring * (ring - 1); // index of first ring pixel (ring numbering) - - return r0 + to_ring_local(f, i, j, Nring, 0); - } - - if (ring < 3 * Nside_) { - // South polar cap - int Nring = 4 * Nside_; - int r0 = Ncap_ + (ring - Nside_) * Nring; // index of first ring pixel (ring numbering) - int shift = (ring - Nside_) & 1; - - return r0 + to_ring_local(f, i, j, Nring, shift); - } - - // Equatorial belt - int N = 4 * Nside_ - ring; - int Nring = 4 * N; - int r0 = Npix_ - 2 * N * (N + 1); // index of first ring pixel (ring numbering) - - return r0 + to_ring_local(f, i, j, Nring, 0); -} diff --git a/src/eckit/geo/grid/reduced/HEALPixRenumber.h b/src/eckit/geo/grid/reduced/HEALPixRenumber.h deleted file mode 100644 index 130d36d87..000000000 --- a/src/eckit/geo/grid/reduced/HEALPixRenumber.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - - -class HEALPix { -public: - explicit HEALPix(int Nside); - - int size() const { return 12 * Nside_ * Nside_; } - int nside() const { return Nside_; } - - int nest_to_ring(int) const; - int ring_to_nest(int) const; - -private: - const int Nside_; // up to 2^13 - const int Npix_; - const int Ncap_; - const int k_; -}; diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 151f902e9..ec3aa820c 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -2,6 +2,7 @@ foreach( _test coordinate_helpers great_circle grid + grid_reorder gridspec iterator kdtree diff --git a/tests/geo/test_grid_reorder.cc b/tests/geo/test_grid_reorder.cc new file mode 100644 index 000000000..3a3d7d9d2 --- /dev/null +++ b/tests/geo/test_grid_reorder.cc @@ -0,0 +1,81 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/config/MappedConfiguration.h" +#include "eckit/geo/Grid.h" +#include "eckit/testing/Test.h" + + +#define EXPECT_EQUAL_VECTOR(x, y) \ + { \ + EXPECT_EQUAL(x.size(), y.size()); \ + for (size_t i = 0; i < x.size(); ++i) { \ + EXPECT_EQUAL(x[i], y[i]); \ + } \ + } + + +namespace eckit::test { + + +CASE("HEALPix") { + SECTION("HEALPix::reorder") { + std::unique_ptr ring( + geo::GridFactory::build(*std::unique_ptr(new MappedConfiguration({{"grid", "H2"}})))); + + static const geo::Renumber expected_ren_ring_to_nested{ + 3, 7, 11, 15, 2, 1, 6, 5, 10, 9, 14, 13, 19, 0, 23, 4, 27, 8, 31, 12, 17, 22, 21, 26, + 25, 30, 29, 18, 16, 35, 20, 39, 24, 43, 28, 47, 34, 33, 38, 37, 42, 41, 46, 45, 32, 36, 40, 44, + }; + + const geo::Renumber expected_ren_nested_to_ring{ + 13, 5, 4, 0, 15, 7, 6, 1, 17, 9, 8, 2, 19, 11, 10, 3, 28, 20, 27, 12, 30, 22, 21, 14, + 32, 24, 23, 16, 34, 26, 25, 18, 44, 37, 36, 29, 45, 39, 38, 31, 46, 41, 40, 33, 47, 43, 42, 35, + }; + + const geo::Renumber expected_ren_none{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + }; + + auto order_ring = ring->order(); + EXPECT_EQUAL(order_ring, geo::Ordering::healpix_ring); + + auto ren_to_ring = ring->reorder(geo::Ordering::healpix_ring); + EXPECT_EQUAL_VECTOR(ren_to_ring, expected_ren_none); + + auto ren_to_nested = ring->reorder(geo::Ordering::healpix_nested); + EXPECT_EQUAL_VECTOR(ren_to_nested, expected_ren_ring_to_nested); + + + std::unique_ptr nested(ring->grid_reorder(geo::Ordering::healpix_nested)); + + auto order_nested = nested->order(); + EXPECT_EQUAL(order_nested, geo::Ordering::healpix_nested); + + ren_to_nested = nested->reorder(geo::Ordering::healpix_nested); + EXPECT_EQUAL_VECTOR(ren_to_nested, expected_ren_none); + + ren_to_ring = nested->reorder(geo::Ordering::healpix_ring); + EXPECT_EQUAL_VECTOR(ren_to_ring, expected_ren_nested_to_ring); + } +} + + +} // namespace eckit::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From 3ec265bd07d3493cc339493dec585dee9c52e248 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 23 Oct 2023 18:01:14 +0100 Subject: [PATCH 361/737] eckit::geo::grid::unstructured::UnstructuredFromGrid --- src/eckit/geo/CMakeLists.txt | 12 +- src/eckit/geo/grid/Unstructured.cc | 4 + src/eckit/geo/grid/Unstructured.h | 1 + .../grid/unstructured/UnstructuredFromGrid.cc | 88 +++++++++++++++ .../grid/unstructured/UnstructuredFromGrid.h | 104 ++++++++++++++++++ tests/geo/CMakeLists.txt | 1 + tests/geo/test_grid_to_points.cc | 55 +++++++++ 7 files changed, 259 insertions(+), 6 deletions(-) create mode 100644 src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc create mode 100644 src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h create mode 100644 tests/geo/test_grid_to_points.cc diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 3fd2b2d15..23f934617 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -1,11 +1,11 @@ -configure_file( eckit_geo_config.h.in eckit_geo_config.h @ONLY ) +configure_file(eckit_geo_config.h.in eckit_geo_config.h @ONLY) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_config.h DESTINATION ${INSTALL_INCLUDE_DIR}/eckit ) -list( APPEND eckit_geo_srcs +list(APPEND eckit_geo_srcs ${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_config.h Area.h Cache.cc @@ -79,6 +79,8 @@ list( APPEND eckit_geo_srcs grid/regular/RegularLL.h grid/unstructured/ORCA.cc grid/unstructured/ORCA.h + grid/unstructured/UnstructuredFromGrid.cc + grid/unstructured/UnstructuredFromGrid.h iterator/Reduced.cc iterator/Reduced.h iterator/Regular.cc @@ -130,12 +132,10 @@ endif() ecbuild_add_library( TARGET eckit_geo - TYPE SHARED - + TYPE SHARED INSTALL_HEADERS ALL HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geo PUBLIC_LIBS ${eckit_geo_libs} PUBLIC_INCLUDES ${eckit_geo_include_dirs} - - SOURCES ${eckit_geo_srcs} + SOURCES ${eckit_geo_srcs} ) diff --git a/src/eckit/geo/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc index 240ceb54c..61fa321a0 100644 --- a/src/eckit/geo/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -32,4 +32,8 @@ Unstructured::Unstructured(const Configuration& config) : Grid(config) {} +Unstructured::Unstructured(const area::BoundingBox& bbox) : + Grid(bbox) {} + + } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h index bc9ce7ef5..9b606b6e8 100644 --- a/src/eckit/geo/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -62,6 +62,7 @@ class Unstructured : public Grid { // -- Constructors explicit Unstructured(const Configuration&); + explicit Unstructured(const area::BoundingBox&); // -- Members // None diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc new file mode 100644 index 000000000..b1a423783 --- /dev/null +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc @@ -0,0 +1,88 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/unstructured/UnstructuredFromGrid.h" + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/iterator/Unstructured.h" + + +namespace eckit::geo::grid::unstructured { + + +namespace { + + +std::vector points_lat(const std::vector& points) { + std::vector l(points.size()); + std::transform(points.begin(), points.end(), l.begin(), [](const Point& p) { + return std::get(p).lat; + }); + return l; +} + + +std::vector points_lon(const std::vector& points) { + std::vector l(points.size()); + std::transform(points.begin(), points.end(), l.begin(), [](const Point& p) { + return std::get(p).lon; + }); + return l; +} + + +} // namespace + + +UnstructuredFromGrid::UnstructuredFromGrid(const std::vector& points) : + Unstructured(area::BoundingBox::make_global_prime()), + latitudes_(points_lat(points)), + longitudes_(points_lon(points)) { + ASSERT(size() > 0); +} + + +Grid::iterator UnstructuredFromGrid::cbegin() const { + return iterator{new geo::iterator::Unstructured(*this, 0)}; +} + + +Grid::iterator UnstructuredFromGrid::cend() const { + return iterator{new geo::iterator::Unstructured(*this, size())}; +} + + +const area::BoundingBox& UnstructuredFromGrid::boundingBox() const { + return Unstructured::boundingBox(); +} + + +std::vector UnstructuredFromGrid::to_points() const { + std::vector p; + for (size_t i = 0; i < size(); ++i) { + p[i] = PointLonLat{longitudes_[i], latitudes_[i]}; + } + return p; +} + + +Configuration* UnstructuredFromGrid::config(const std::string& name) { + return GridConfigurationUID::instance().get(name).config(); +} + + +Grid::uid_t UnstructuredFromGrid::uid() const { + NOTIMP; +} + + +} // namespace eckit::geo::grid::unstructured diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h new file mode 100644 index 000000000..638bff622 --- /dev/null +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h @@ -0,0 +1,104 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include +#include + +#include "eckit/geo/grid/Unstructured.h" + + +namespace eckit { +class PathName; +} + + +namespace eckit::geo::grid::unstructured { + + +class UnstructuredFromGrid final : public Unstructured { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit UnstructuredFromGrid(const std::vector&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + iterator cbegin() const override; + iterator cend() const override; + + const area::BoundingBox& boundingBox() const override; + + size_t size() const override { return latitudes_.size(); } + uid_t uid() const override; + + bool includesNorthPole() const override { return true; } + bool includesSouthPole() const override { return true; } + bool isPeriodicWestEast() const override { return true; } + + std::vector to_points() const override; + std::pair, std::vector> to_latlon() const override { return {latitudes_, longitudes_}; } + + const std::vector& longitudes() const override { return longitudes_; } + const std::vector& latitudes() const override { return latitudes_; } + + // -- Class members + // None + + // -- Class methods + + static Configuration* config(const std::string& name); + +private: + // -- Members + + mutable std::vector latitudes_; + mutable std::vector longitudes_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::grid::unstructured diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index ec3aa820c..fe377e769 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -3,6 +3,7 @@ foreach( _test great_circle grid grid_reorder + grid_to_points gridspec iterator kdtree diff --git a/tests/geo/test_grid_to_points.cc b/tests/geo/test_grid_to_points.cc new file mode 100644 index 000000000..915af6aa7 --- /dev/null +++ b/tests/geo/test_grid_to_points.cc @@ -0,0 +1,55 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "eckit/geo/grid/reduced/HEALPix.h" +#include "eckit/testing/Test.h" + + +namespace eckit::test { + + +CASE("HEALPix") { + SECTION("HEALPix::to_points") { + std::unique_ptr grid(new geo::grid::reduced::HEALPix(2, geo::Ordering::healpix_ring)); + + static const std::vector expected_points_ring{ + {45, 66.443536}, {135, 66.443536}, {225, 66.443536}, {315, 66.443536}, {22.5, 41.810315}, + {67.5, 41.810315}, {112.5, 41.810315}, {157.5, 41.810315}, {202.5, 41.810315}, {247.5, 41.810315}, + {292.5, 41.810315}, {337.5, 41.810315}, {0, 19.471221}, {45, 19.471221}, {90, 19.471221}, + {135, 19.471221}, {180, 19.471221}, {225, 19.471221}, {270, 19.471221}, {315, 19.471221}, + {22.5, 0}, {67.5, 0}, {112.5, 0}, {157.5, 0}, {202.5, 0}, + {247.5, 0}, {292.5, 0}, {337.5, 0}, {0, -19.471221}, {45, -19.471221}, + {90, -19.471221}, {135, -19.471221}, {180, -19.471221}, {225, -19.471221}, {270, -19.471221}, + {315, -19.471221}, {22.5, -41.810315}, {67.5, -41.810315}, {112.5, -41.810315}, {157.5, -41.810315}, + {202.5, -41.810315}, {247.5, -41.810315}, {292.5, -41.810315}, {337.5, -41.810315}, {45, -66.443536}, + {135, -66.443536}, {225, -66.443536}, {315, -66.443536}, + }; + + auto points = grid->to_points(); + EXPECT_EQUAL(points.size(), expected_points_ring.size()); + + for (int i = 0; i < points.size(); ++i) { + EXPECT(geo::points_equal(std::get(points[i]), expected_points_ring[i])); + } + } +} + + +} // namespace eckit::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From e152ed9bf23951680ef7e3755794d33e3a8a7ec3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 2 Nov 2023 08:32:44 +0000 Subject: [PATCH 362/737] eckit::geo eckit::codec disabled --- src/eckit/CMakeLists.txt | 1 - src/eckit/geo/CMakeLists.txt | 6 +++--- tests/CMakeLists.txt | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/eckit/CMakeLists.txt b/src/eckit/CMakeLists.txt index 9644df4f6..a61163cc5 100644 --- a/src/eckit/CMakeLists.txt +++ b/src/eckit/CMakeLists.txt @@ -984,7 +984,6 @@ add_subdirectory( option ) add_subdirectory( web ) if( HAVE_EXPERIMENTAL ) - add_subdirectory( codec ) add_subdirectory( geo ) endif() diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 23f934617..e2a79190a 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -77,8 +77,8 @@ list(APPEND eckit_geo_srcs grid/regular/RegularGaussian.h grid/regular/RegularLL.cc grid/regular/RegularLL.h - grid/unstructured/ORCA.cc - grid/unstructured/ORCA.h + # grid/unstructured/ORCA.cc # requires eckit::codec + # grid/unstructured/ORCA.h grid/unstructured/UnstructuredFromGrid.cc grid/unstructured/UnstructuredFromGrid.h iterator/Reduced.cc @@ -122,7 +122,7 @@ set(eckit_geo_include_dirs $ ) -set(eckit_geo_libs eckit_maths eckit_codec) +set(eckit_geo_libs eckit_maths) # eckit_codec if(HAVE_PROJ) list(APPEND eckit_geo_srcs projection/PROJ.cc projection/PROJ.h) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fbc86e82e..c9fe2b4ff 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -26,7 +26,6 @@ if( HAVE_ECKIT_SQL ) endif() if( HAVE_EXPERIMENTAL ) - add_subdirectory( codec ) add_subdirectory( geo ) add_subdirectory( experimental ) endif() From dd287a8d99b9e98a4c360319ad99bc523835285b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 2 Nov 2023 13:59:03 +0000 Subject: [PATCH 363/737] eckit::maths --- src/eckit/maths/Matrix3.h | 8 +++ tests/maths/CMakeLists.txt | 22 +++++--- tests/maths/test_matrix3.cc | 102 ++++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 tests/maths/test_matrix3.cc diff --git a/src/eckit/maths/Matrix3.h b/src/eckit/maths/Matrix3.h index f5bec5854..f48860297 100644 --- a/src/eckit/maths/Matrix3.h +++ b/src/eckit/maths/Matrix3.h @@ -87,6 +87,12 @@ class Matrix3 final : protected std::array { // -- Methods + using P::size; + using P::begin; + using P::end; + using P::cbegin; + using P::cend; + static Matrix3 identity() { return {1, 0, 0, 0, 1, 0, 0, 0, 1}; } Matrix3 inverse() const { @@ -98,6 +104,8 @@ class Matrix3 final : protected std::array { (YX * ZY - YY * ZX) / det, (XY * ZX - XX * ZY) / det, (XX * YY - XY * YX) / det}; } + T determinant() const { return XX*YY*ZZ-XZ*YY*ZX+XY*YZ*ZX+XZ*YX*ZY-XX*YZ*ZY-XY*YX*ZZ; } + // -- Overridden methods // None diff --git a/tests/maths/CMakeLists.txt b/tests/maths/CMakeLists.txt index 797a792dd..329dbe54b 100644 --- a/tests/maths/CMakeLists.txt +++ b/tests/maths/CMakeLists.txt @@ -1,9 +1,15 @@ -ecbuild_add_test( TARGET eckit_test_maths_eigen - SOURCES test_eigen.cc - CONDITION HAVE_EIGEN - LIBS eckit_maths eckit -) -ecbuild_add_test( TARGET eckit_test_maths_matrix - SOURCES test_matrix.cc - LIBS eckit_maths eckit +ecbuild_add_test( + TARGET eckit_test_maths_eigen + SOURCES test_eigen.cc + CONDITION HAVE_EIGEN + LIBS eckit_maths eckit ) + +foreach( _test matrix matrix3 ) + ecbuild_add_test( + TARGET eckit_test_maths_${_test} + SOURCES test_${_test}.cc + LIBS eckit_maths eckit + ) +endforeach() + diff --git a/tests/maths/test_matrix3.cc b/tests/maths/test_matrix3.cc new file mode 100644 index 000000000..51e988b33 --- /dev/null +++ b/tests/maths/test_matrix3.cc @@ -0,0 +1,102 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/maths/Matrix3.h" +#include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::test { + + +using Matrix = maths::Matrix3; + +constexpr double tolerance = 1.e-8; + + +//---------------------------------------------------------------------------------------------------------------------- + + +CASE("test determinant") { + Matrix M{1, + 2, + 3, // + 4, + 5, + 6, // + 7, + 8, + 1}; + + EXPECT(types::is_approximately_equal(M.determinant(), 24., tolerance)); +} + + +CASE("test inverse") { + auto is_approximately_equal = [](const Matrix& A, const Matrix& B) { + ASSERT(A.size() == B.size()); + return std::equal(A.begin(), A.end(), B.begin(), [](double a, double b) { + return types::is_approximately_equal(a, b, tolerance); + }); + }; + + Matrix M{1, + 2, + 3, // + 4, + 5, + 6, // + 7, + 8, + 1}; + + // Calculate inverse + auto W = M.inverse(); + EXPECT(is_approximately_equal(W, + {-43. / 24., + 22. / 24., + -3. / 24., // + 38. / 24., + -20. / 24., + 6. / 24., // + -3. / 24., + 6. / 24., + -3. / 24.})); + + // Calculate identity + auto I = Matrix::identity(); + EXPECT(is_approximately_equal(I, + {1, + 0, + 0, // + 0, + 1, + 0, // + 0, + 0, + 1})); + + EXPECT(is_approximately_equal(I, W * M)); + EXPECT(is_approximately_equal(I, M * W)); +} + + +//---------------------------------------------------------------------------------------------------------------------- + + +} // namespace eckit::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From bcd9441f71bca128ab7595809ec318a9b0c54835 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 2 Nov 2023 14:42:09 +0000 Subject: [PATCH 364/737] eckit::config --- tests/config/CMakeLists.txt | 21 ++++++++---- .../test_mapped_configuration.cc} | 33 ++++++++++++++----- 2 files changed, 39 insertions(+), 15 deletions(-) rename tests/{geo/test_param.cc => config/test_mapped_configuration.cc} (51%) diff --git a/tests/config/CMakeLists.txt b/tests/config/CMakeLists.txt index 2a810e523..588db74bc 100644 --- a/tests/config/CMakeLists.txt +++ b/tests/config/CMakeLists.txt @@ -1,8 +1,15 @@ -ecbuild_add_test( TARGET eckit_test_config_resource - SOURCES test_resource.cc - ARGS -integer 100 -listlong 88,99,11,22 - LIBS eckit ) +ecbuild_add_test( + TARGET eckit_test_config_resource + SOURCES test_resource.cc + ARGS -integer 100 -listlong 88,99,11,22 + LIBS eckit +) + +foreach( _test configuration mapped_configuration ) + ecbuild_add_test( + TARGET eckit_test_config_${_test} + SOURCES test_${_test}.cc + LIBS eckit + ) +endforeach() -ecbuild_add_test( TARGET eckit_test_config_configuration - SOURCES test_configuration.cc - LIBS eckit ) diff --git a/tests/geo/test_param.cc b/tests/config/test_mapped_configuration.cc similarity index 51% rename from tests/geo/test_param.cc rename to tests/config/test_mapped_configuration.cc index 01a092a14..218f97392 100644 --- a/tests/geo/test_param.cc +++ b/tests/config/test_mapped_configuration.cc @@ -17,24 +17,41 @@ #include "eckit/testing/Test.h" -int main(int argc, char* argv[]) { - std::unique_ptr param( - new eckit::MappedConfiguration({{"a", -123}, {"b", "B"}, {"c", 123UL}})); +//---------------------------------------------------------------------------------------------------------------------- + + +namespace eckit::test { + + +CASE("MappedConfiguration") { + std::unique_ptr param(new MappedConfiguration({{"a", -123}, {"b", "B"}, {"c", 123UL}})); int a = 0; EXPECT(param->get("a", a)); + EXPECT_EQUAL(a, -123); std::cout << "a: '" << a << "'" << std::endl; std::string b; EXPECT(param->get("b", b)); - std::cout << "b: '" << b << "'" << std::endl; + EXPECT_EQUAL(b, "B"); size_t c = 0; EXPECT(param->get("c", c)); - std::cout << "c: '" << c << "'" << std::endl; + EXPECT_EQUAL(c, 123UL); - int d = 321; - dynamic_cast(param.get())->set("b", d); + int d = 0; + dynamic_cast(param.get())->set("b", 321); EXPECT(param->get("b", d)); - std::cout << "d: '" << d << "'" << std::endl; + EXPECT_EQUAL(d, 321); +} + + +} // namespace eckit::test + + +//---------------------------------------------------------------------------------------------------------------------- + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); } From bcaaa9b0a551f938d2c332f92ac626a3bfcecc9a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 2 Nov 2023 14:42:52 +0000 Subject: [PATCH 365/737] eckit::geo organize tests --- tests/geo/CMakeLists.txt | 16 ++-- tests/geo/area_boundingbox.cc | 41 +++++++++++ .../geo/{test_polygon.cc => area_polygon.cc} | 8 +- ...inate_helpers.cc => coordinate_helpers.cc} | 3 + .../geo/{test_sphere.cc => figure_sphere.cc} | 64 ++++++++-------- ...ircle.cc => figure_sphere_great_circle.cc} | 6 +- tests/geo/{test_grid.cc => grid.cc} | 14 ++-- .../{test_grid_reorder.cc => grid_reorder.cc} | 27 ++++--- ...st_grid_to_points.cc => grid_to_points.cc} | 9 ++- tests/geo/{test_gridspec.cc => gridspec.cc} | 15 ++-- tests/geo/iterator.cc | 37 ++++++++++ tests/geo/{test_kdtree.cc => kdtree.cc} | 32 ++++---- tests/geo/{test_kpoint.cc => kpoint.cc} | 12 +-- tests/geo/{test_points.cc => point.cc} | 72 ++++++++++++++++-- .../geo/{test_projection.cc => projection.cc} | 24 +++--- tests/geo/{test_range.cc => range.cc} | 19 ++--- tests/geo/search.cc | 73 +++++++++++++++++++ tests/geo/test_iterator.cc | 32 -------- tests/geo/test_search.cc | 60 --------------- tests/geo/test_types.cc | 60 --------------- tests/geo/test_util.cc | 53 -------------- tests/geo/util.cc | 72 ++++++++++++++++++ 22 files changed, 424 insertions(+), 325 deletions(-) create mode 100644 tests/geo/area_boundingbox.cc rename tests/geo/{test_polygon.cc => area_polygon.cc} (99%) rename tests/geo/{test_coordinate_helpers.cc => coordinate_helpers.cc} (99%) rename tests/geo/{test_sphere.cc => figure_sphere.cc} (82%) rename tests/geo/{test_great_circle.cc => figure_sphere_great_circle.cc} (99%) rename tests/geo/{test_grid.cc => grid.cc} (82%) rename tests/geo/{test_grid_reorder.cc => grid_reorder.cc} (71%) rename tests/geo/{test_grid_to_points.cc => grid_to_points.cc} (87%) rename tests/geo/{test_gridspec.cc => gridspec.cc} (92%) create mode 100644 tests/geo/iterator.cc rename tests/geo/{test_kdtree.cc => kdtree.cc} (93%) rename tests/geo/{test_kpoint.cc => kpoint.cc} (94%) rename tests/geo/{test_points.cc => point.cc} (71%) rename tests/geo/{test_projection.cc => projection.cc} (92%) rename tests/geo/{test_range.cc => range.cc} (79%) create mode 100644 tests/geo/search.cc delete mode 100644 tests/geo/test_iterator.cc delete mode 100644 tests/geo/test_search.cc delete mode 100644 tests/geo/test_types.cc delete mode 100644 tests/geo/test_util.cc create mode 100644 tests/geo/util.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index fe377e769..84d9b1706 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -1,6 +1,9 @@ foreach( _test + area_boundingbox + area_polygon coordinate_helpers - great_circle + figure_sphere + figure_sphere_great_circle grid grid_reorder grid_to_points @@ -8,18 +11,15 @@ foreach( _test iterator kdtree kpoint - param - points - polygon + point projection range search - sphere - types util ) ecbuild_add_test( TARGET eckit_test_geo_${_test} - SOURCES test_${_test}.cc - LIBS eckit_geo ) + SOURCES ${_test}.cc + LIBS eckit_geo + ) endforeach() diff --git a/tests/geo/area_boundingbox.cc b/tests/geo/area_boundingbox.cc new file mode 100644 index 000000000..7a7a63564 --- /dev/null +++ b/tests/geo/area_boundingbox.cc @@ -0,0 +1,41 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/area/BoundingBox.h" +#include "eckit/testing/Test.h" + + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace eckit::test { + + +using namespace geo; + + +CASE("") { + auto a = area::BoundingBox{}; + auto b = area::BoundingBox{90, 0, -90, 360}; + EXPECT_EQUAL(a, b); +} + + +} // namespace eckit::test + + +//---------------------------------------------------------------------------------------------------------------------- + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/test_polygon.cc b/tests/geo/area_polygon.cc similarity index 99% rename from tests/geo/test_polygon.cc rename to tests/geo/area_polygon.cc index 7f6e93abe..4ddcfd6a8 100644 --- a/tests/geo/test_polygon.cc +++ b/tests/geo/area_polygon.cc @@ -3,11 +3,13 @@ * * 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 #include "eckit/geo/Point2.h" @@ -17,6 +19,10 @@ namespace eckit::test { + +using namespace geo; + + CASE("Polygon") { using geo::polygon::Polygon; @@ -269,7 +275,7 @@ CASE("LonLatPolygon") { // Test points at non-canonical coordinates // Default behavior throws - EXPECT_THROWS_AS(poly.contains({lonmid, 180. - latmid}), eckit::BadValue); + EXPECT_THROWS_AS(poly.contains({lonmid, 180. - latmid}), BadValue); EXPECT(poly.contains({lonmid + 360., latmid}, true)); EXPECT(poly.contains({lonmid, 180. - latmid}, true)); diff --git a/tests/geo/test_coordinate_helpers.cc b/tests/geo/coordinate_helpers.cc similarity index 99% rename from tests/geo/test_coordinate_helpers.cc rename to tests/geo/coordinate_helpers.cc index 2cf204f31..ad4ea4459 100644 --- a/tests/geo/test_coordinate_helpers.cc +++ b/tests/geo/coordinate_helpers.cc @@ -5,6 +5,7 @@ * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. */ + #include "eckit/geo/CoordinateHelpers.h" #include "eckit/geo/Point2.h" #include "eckit/testing/Test.h" @@ -12,8 +13,10 @@ namespace eckit::test { + using namespace geo; + // ----------------------------------------------------------------------------- CASE("normalise angles") { diff --git a/tests/geo/test_sphere.cc b/tests/geo/figure_sphere.cc similarity index 82% rename from tests/geo/test_sphere.cc rename to tests/geo/figure_sphere.cc index 3c9ef38c7..95476975a 100644 --- a/tests/geo/test_sphere.cc +++ b/tests/geo/figure_sphere.cc @@ -3,11 +3,13 @@ * * 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 #include @@ -19,17 +21,17 @@ namespace eckit::tests::geo { + +using namespace eckit::geo; + + // set sphere struct DatumTwoUnits { static double radius() { return 2.; } }; -using TwoUnitsSphere = eckit::geo::SphereT; - -using eckit::geo::Point3; -using eckit::geo::PointLonLat; +using TwoUnitsSphere = SphereT; -using eckit::geo::UnitSphere; const double R = UnitSphere::radius(); @@ -116,8 +118,8 @@ CASE("test unit sphere lon 45") { auto p = UnitSphere::convertSphericalToCartesian({45., 0.}); auto q = UnitSphere::convertSphericalToCartesian({-315., 0.}); - EXPECT(eckit::types::is_approximately_equal(p.X, L)); - EXPECT(eckit::types::is_approximately_equal(p.Y, L)); + EXPECT(types::is_approximately_equal(p.X, L)); + EXPECT(types::is_approximately_equal(p.Y, L)); EXPECT(p.Z == 0); EXPECT(Point3::equal(p, q)); @@ -127,8 +129,8 @@ CASE("test unit sphere lon 135") { auto p = UnitSphere::convertSphericalToCartesian({135., 0.}); auto q = UnitSphere::convertSphericalToCartesian({-225., 0.}); - EXPECT(eckit::types::is_approximately_equal(p.X, -L)); - EXPECT(eckit::types::is_approximately_equal(p.Y, L)); + EXPECT(types::is_approximately_equal(p.X, -L)); + EXPECT(types::is_approximately_equal(p.Y, L)); EXPECT(p.Z == 0); EXPECT(Point3::equal(p, q)); @@ -138,8 +140,8 @@ CASE("test unit sphere lon 225") { auto p = UnitSphere::convertSphericalToCartesian({225., 0.}); auto q = UnitSphere::convertSphericalToCartesian({-135., 0.}); - EXPECT(eckit::types::is_approximately_equal(p.X, -L)); - EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); + EXPECT(types::is_approximately_equal(p.X, -L)); + EXPECT(types::is_approximately_equal(p.Y, -L)); EXPECT(p.Z == 0); EXPECT(Point3::equal(p, q)); @@ -149,8 +151,8 @@ CASE("test unit sphere lon 315") { auto p = UnitSphere::convertSphericalToCartesian({315., 0.}); auto q = UnitSphere::convertSphericalToCartesian({-45., 0.}); - EXPECT(eckit::types::is_approximately_equal(p.X, L)); - EXPECT(eckit::types::is_approximately_equal(p.Y, -L)); + EXPECT(types::is_approximately_equal(p.X, L)); + EXPECT(types::is_approximately_equal(p.Y, -L)); EXPECT(p.Z == 0); EXPECT(Point3::equal(p, q)); @@ -161,44 +163,44 @@ CASE("test unit sphere lon 315") { CASE("test unit sphere lat 100") { // Default behavior throws - EXPECT_THROWS_AS(PointLonLat(0., 100.), eckit::BadValue); - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({0., 100.}), eckit::BadValue); + EXPECT_THROWS_AS(PointLonLat(0., 100.), BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({0., 100.}), BadValue); auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(0., 100.), 0.); auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(180., 80.), 0.); // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); - EXPECT(eckit::types::is_approximately_equal(p.Y, q.Y)); - EXPECT(eckit::types::is_approximately_equal(p.Z, q.Z)); + EXPECT(types::is_approximately_equal(p.X, q.X)); + EXPECT(types::is_approximately_equal(p.Y, q.Y)); + EXPECT(types::is_approximately_equal(p.Z, q.Z)); } CASE("test unit sphere lat 290") { // Default behavior throws - EXPECT_THROWS_AS(PointLonLat(15., 290.), eckit::BadValue); - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({15., 290.}), eckit::BadValue); + EXPECT_THROWS_AS(PointLonLat(15., 290.), BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({15., 290.}), BadValue); auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., 290.), 0.); auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., -70.), 0.); // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); - EXPECT(eckit::types::is_approximately_equal(p.Y, q.Y)); - EXPECT(eckit::types::is_approximately_equal(p.Z, q.Z)); + EXPECT(types::is_approximately_equal(p.X, q.X)); + EXPECT(types::is_approximately_equal(p.Y, q.Y)); + EXPECT(types::is_approximately_equal(p.Z, q.Z)); } CASE("test unit sphere lat -120") { // Default behavior throws - EXPECT_THROWS_AS(PointLonLat(45., -120.), eckit::BadValue); - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({45., -120.}), eckit::BadValue); + EXPECT_THROWS_AS(PointLonLat(45., -120.), BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({45., -120.}), BadValue); auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(45., -120.), 0.); auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(225., -60.), 0.); // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(eckit::types::is_approximately_equal(p.X, q.X)); - EXPECT(eckit::types::is_approximately_equal(p.Y, q.Y)); - EXPECT(eckit::types::is_approximately_equal(p.Z, q.Z)); + EXPECT(types::is_approximately_equal(p.X, q.X)); + EXPECT(types::is_approximately_equal(p.Y, q.Y)); + EXPECT(types::is_approximately_equal(p.Z, q.Z)); } // ----------------------------------------------------------------------------- @@ -218,9 +220,9 @@ CASE("test unit sphere distances") { const double d2 = UnitSphere::distance(P1, P2b); const double d3 = UnitSphere::distance(P1, P2c); - EXPECT(eckit::types::is_approximately_equal(d0, d1)); - EXPECT(eckit::types::is_approximately_equal(d0, d2)); - EXPECT(eckit::types::is_approximately_equal(d0, d3)); + EXPECT(types::is_approximately_equal(d0, d1)); + EXPECT(types::is_approximately_equal(d0, d2)); + EXPECT(types::is_approximately_equal(d0, d3)); } // ----------------------------------------------------------------------------- diff --git a/tests/geo/test_great_circle.cc b/tests/geo/figure_sphere_great_circle.cc similarity index 99% rename from tests/geo/test_great_circle.cc rename to tests/geo/figure_sphere_great_circle.cc index 575911cf5..309fc0d89 100644 --- a/tests/geo/test_great_circle.cc +++ b/tests/geo/figure_sphere_great_circle.cc @@ -3,11 +3,13 @@ * * 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 #include #include @@ -18,10 +20,12 @@ namespace eckit::test { + using namespace geo; + // ----------------------------------------------------------------------------- -// test great circles + CASE("test great circles intersections") { using types::is_approximately_equal; diff --git a/tests/geo/test_grid.cc b/tests/geo/grid.cc similarity index 82% rename from tests/geo/test_grid.cc rename to tests/geo/grid.cc index e325efcbc..08e002c47 100644 --- a/tests/geo/test_grid.cc +++ b/tests/geo/grid.cc @@ -20,10 +20,10 @@ namespace eckit::test { -CASE("GridFactory::build") { - using geo::Grid; +using namespace geo; +CASE("GridFactory::build") { struct test_t { std::string name; size_t size; @@ -32,8 +32,8 @@ CASE("GridFactory::build") { SECTION("GridFactory::build_from_name") { for (const auto& test : {test_t{"O2", 88}, {"f2", 32}, {"h2", 48}}) { - std::unique_ptr grid(geo::GridFactory::build( - *std::unique_ptr(new MappedConfiguration({{"grid", test.name}})))); + std::unique_ptr grid( + GridFactory::build(*std::unique_ptr(new MappedConfiguration({{"grid", test.name}})))); auto size = grid->size(); EXPECT_EQUAL(size, test.size); @@ -42,7 +42,7 @@ CASE("GridFactory::build") { SECTION("RegularGaussian") { - std::unique_ptr grid(geo::GridFactory::build( + std::unique_ptr grid(GridFactory::build( *std::unique_ptr(new MappedConfiguration({{"grid", "f2"}, {"south", 0}})))); auto nh = grid->size(); @@ -56,7 +56,7 @@ CASE("GridFactory::build") { SECTION("Grid::build_from_increments") { SECTION("global") { std::unique_ptr global( - geo::GridFactory::build(*std::unique_ptr(new MappedConfiguration({ + GridFactory::build(*std::unique_ptr(new MappedConfiguration({ {"type", "regular_ll"}, {"west_east_increment", 1}, {"south_north_increment", 1}, @@ -69,7 +69,7 @@ CASE("GridFactory::build") { SECTION("non-global") { std::unique_ptr grid( - geo::GridFactory::build(*std::unique_ptr(new MappedConfiguration({ + GridFactory::build(*std::unique_ptr(new MappedConfiguration({ {"type", "regular_ll"}, {"west_east_increment", 1}, {"south_north_increment", 1}, diff --git a/tests/geo/test_grid_reorder.cc b/tests/geo/grid_reorder.cc similarity index 71% rename from tests/geo/test_grid_reorder.cc rename to tests/geo/grid_reorder.cc index 3a3d7d9d2..572ca7b09 100644 --- a/tests/geo/test_grid_reorder.cc +++ b/tests/geo/grid_reorder.cc @@ -29,45 +29,48 @@ namespace eckit::test { +using namespace geo; + + CASE("HEALPix") { SECTION("HEALPix::reorder") { - std::unique_ptr ring( - geo::GridFactory::build(*std::unique_ptr(new MappedConfiguration({{"grid", "H2"}})))); + std::unique_ptr ring( + GridFactory::build(*std::unique_ptr(new MappedConfiguration({{"grid", "H2"}})))); - static const geo::Renumber expected_ren_ring_to_nested{ + static const Renumber expected_ren_ring_to_nested{ 3, 7, 11, 15, 2, 1, 6, 5, 10, 9, 14, 13, 19, 0, 23, 4, 27, 8, 31, 12, 17, 22, 21, 26, 25, 30, 29, 18, 16, 35, 20, 39, 24, 43, 28, 47, 34, 33, 38, 37, 42, 41, 46, 45, 32, 36, 40, 44, }; - const geo::Renumber expected_ren_nested_to_ring{ + const Renumber expected_ren_nested_to_ring{ 13, 5, 4, 0, 15, 7, 6, 1, 17, 9, 8, 2, 19, 11, 10, 3, 28, 20, 27, 12, 30, 22, 21, 14, 32, 24, 23, 16, 34, 26, 25, 18, 44, 37, 36, 29, 45, 39, 38, 31, 46, 41, 40, 33, 47, 43, 42, 35, }; - const geo::Renumber expected_ren_none{ + const Renumber expected_ren_none{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, }; auto order_ring = ring->order(); - EXPECT_EQUAL(order_ring, geo::Ordering::healpix_ring); + EXPECT_EQUAL(order_ring, Ordering::healpix_ring); - auto ren_to_ring = ring->reorder(geo::Ordering::healpix_ring); + auto ren_to_ring = ring->reorder(Ordering::healpix_ring); EXPECT_EQUAL_VECTOR(ren_to_ring, expected_ren_none); - auto ren_to_nested = ring->reorder(geo::Ordering::healpix_nested); + auto ren_to_nested = ring->reorder(Ordering::healpix_nested); EXPECT_EQUAL_VECTOR(ren_to_nested, expected_ren_ring_to_nested); - std::unique_ptr nested(ring->grid_reorder(geo::Ordering::healpix_nested)); + std::unique_ptr nested(ring->grid_reorder(Ordering::healpix_nested)); auto order_nested = nested->order(); - EXPECT_EQUAL(order_nested, geo::Ordering::healpix_nested); + EXPECT_EQUAL(order_nested, Ordering::healpix_nested); - ren_to_nested = nested->reorder(geo::Ordering::healpix_nested); + ren_to_nested = nested->reorder(Ordering::healpix_nested); EXPECT_EQUAL_VECTOR(ren_to_nested, expected_ren_none); - ren_to_ring = nested->reorder(geo::Ordering::healpix_ring); + ren_to_ring = nested->reorder(Ordering::healpix_ring); EXPECT_EQUAL_VECTOR(ren_to_ring, expected_ren_nested_to_ring); } } diff --git a/tests/geo/test_grid_to_points.cc b/tests/geo/grid_to_points.cc similarity index 87% rename from tests/geo/test_grid_to_points.cc rename to tests/geo/grid_to_points.cc index 915af6aa7..358c667d0 100644 --- a/tests/geo/test_grid_to_points.cc +++ b/tests/geo/grid_to_points.cc @@ -20,11 +20,14 @@ namespace eckit::test { +using namespace geo; + + CASE("HEALPix") { SECTION("HEALPix::to_points") { - std::unique_ptr grid(new geo::grid::reduced::HEALPix(2, geo::Ordering::healpix_ring)); + std::unique_ptr grid(new grid::reduced::HEALPix(2, Ordering::healpix_ring)); - static const std::vector expected_points_ring{ + static const std::vector expected_points_ring{ {45, 66.443536}, {135, 66.443536}, {225, 66.443536}, {315, 66.443536}, {22.5, 41.810315}, {67.5, 41.810315}, {112.5, 41.810315}, {157.5, 41.810315}, {202.5, 41.810315}, {247.5, 41.810315}, {292.5, 41.810315}, {337.5, 41.810315}, {0, 19.471221}, {45, 19.471221}, {90, 19.471221}, @@ -41,7 +44,7 @@ CASE("HEALPix") { EXPECT_EQUAL(points.size(), expected_points_ring.size()); for (int i = 0; i < points.size(); ++i) { - EXPECT(geo::points_equal(std::get(points[i]), expected_points_ring[i])); + EXPECT(points_equal(std::get(points[i]), expected_points_ring[i])); } } } diff --git a/tests/geo/test_gridspec.cc b/tests/geo/gridspec.cc similarity index 92% rename from tests/geo/test_gridspec.cc rename to tests/geo/gridspec.cc index b062905ba..192e39995 100644 --- a/tests/geo/test_gridspec.cc +++ b/tests/geo/gridspec.cc @@ -31,8 +31,11 @@ namespace eckit::test { +using namespace geo; + + using C = std::unique_ptr; -using G = std::unique_ptr; +using G = std::unique_ptr; using M = MappedConfiguration; using v = std::vector; @@ -94,7 +97,7 @@ CASE("gridspec") { for (const auto& [user, gridspec] : cases) { Log::info() << user << " -> " << gridspec << std::endl; - C config(geo::GridFactory::configure(user)); + C config(GridFactory::configure(user)); ASSERT(config); if (!config->has("type")) { @@ -103,10 +106,10 @@ CASE("gridspec") { } if (gridspec.empty()) { - EXPECT_THROWS(G(geo::GridFactory::build(*config))); + EXPECT_THROWS(G(GridFactory::build(*config))); } else { - EXPECT_NO_THROW(G(geo::GridFactory::build(*config))); + EXPECT_NO_THROW(G(GridFactory::build(*config))); } } } @@ -117,11 +120,11 @@ CASE("gridspec") { Log::info() << user << " -> " << gridspec << std::endl; if (gridspec.empty()) { - EXPECT_THROWS(G(geo::GridFactory::build(user))); + EXPECT_THROWS(G(GridFactory::build(user))); continue; } - // G grid(geo::GridFactory::build(*user)); + // G grid(GridFactory::build(*user)); // EXPECT(grid); } } diff --git a/tests/geo/iterator.cc b/tests/geo/iterator.cc new file mode 100644 index 000000000..67ddd73fa --- /dev/null +++ b/tests/geo/iterator.cc @@ -0,0 +1,37 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Iterator.h" +#include "eckit/testing/Test.h" + + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace eckit::test { + + +using namespace eckit::geo; + + +CASE("") {} + + +} // namespace eckit::test + + +//---------------------------------------------------------------------------------------------------------------------- + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/test_kdtree.cc b/tests/geo/kdtree.cc similarity index 93% rename from tests/geo/test_kdtree.cc rename to tests/geo/kdtree.cc index ef5212779..a06e1d53b 100644 --- a/tests/geo/test_kdtree.cc +++ b/tests/geo/kdtree.cc @@ -3,11 +3,13 @@ * * 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 #include "eckit/container/KDTree.h" @@ -15,13 +17,13 @@ #include "eckit/os/Semaphore.h" #include "eckit/testing/Test.h" -using namespace std; -using namespace eckit; -using namespace eckit::testing; -using namespace eckit::geo; namespace eckit::test { + +using namespace geo; + + //---------------------------------------------------------------------------------------------------------------------- struct TestTreeTrait { @@ -36,12 +38,12 @@ struct TestTreeTrait { template class PointInBoxInteriorFinder { public: - typedef eckit::KDTreeX KDTree; - typedef typename KDTree::Point Point; + using KDTree = KDTreeX; + using Point = KDTree::Point; private: - typedef typename KDTree::Alloc Alloc; - typedef typename KDTree::Node Node; + using Alloc = KDTree::Alloc; + using Node = KDTree::Node; public: /// \brief Returns true if any point in \p tree lies in the interior of the specified @@ -112,9 +114,9 @@ class PointInBoxInteriorFinder { /// \brief Returns true if any point in \p tree is in the interior of the axis-aligned box /// with bottom-left and top-right corners at \p lbound and \p ubound. template -bool isAnyPointInBoxInterior(const eckit::KDTreeX& tree, - const typename eckit::KDTreeX::Point& lbound, - const typename eckit::KDTreeX::Point& ubound) { +bool isAnyPointInBoxInterior(const KDTreeX& tree, + const typename KDTreeX::Point& lbound, + const typename KDTreeX::Point& ubound) { return PointInBoxInteriorFinder::isAnyPointInBoxInterior(tree, lbound, ubound); } @@ -325,7 +327,7 @@ CASE("test_kdtree_mapped") { return true; }; - eckit::PathName path("test_kdtree_mapped.kdtree"); + PathName path("test_kdtree_mapped.kdtree"); // Write file with kdtree { @@ -344,10 +346,10 @@ CASE("test_kdtree_mapped") { Tree kd(path, 0, 0); // Cannot insert point as the tree is readonly - EXPECT_THROWS_AS(kd.insert(points.front()), eckit::AssertionFailed); + EXPECT_THROWS_AS(kd.insert(points.front()), AssertionFailed); // Cannot build with points as the tree is readonly - EXPECT_THROWS_AS(kd.build(points), eckit::AssertionFailed); + EXPECT_THROWS_AS(kd.build(points), AssertionFailed); EXPECT_EQUAL(kd.size(), points.size()); EXPECT(passTest(kd)); @@ -370,5 +372,5 @@ CASE("test_kdtree_iterate_empty") { } // namespace eckit::test int main(int argc, char** argv) { - return run_tests(argc, argv); + return eckit::testing::run_tests(argc, argv); } diff --git a/tests/geo/test_kpoint.cc b/tests/geo/kpoint.cc similarity index 94% rename from tests/geo/test_kpoint.cc rename to tests/geo/kpoint.cc index 8075c03cd..99d0438c9 100644 --- a/tests/geo/test_kpoint.cc +++ b/tests/geo/kpoint.cc @@ -3,21 +3,23 @@ * * 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 "eckit/geo/Point3.h" #include "eckit/testing/Test.h" -using namespace std; -using namespace eckit; -using namespace eckit::testing; -using namespace eckit::geo; namespace eckit::test { + +using namespace geo; + + CASE("KPoint Inits to Zero") { Point3 p; @@ -111,5 +113,5 @@ CASE("KPoint distance2 comparison") { //---------------------------------------------------------------------------------------------------------------------- int main(int argc, char** argv) { - return run_tests(argc, argv); + return eckit::testing::run_tests(argc, argv); } diff --git a/tests/geo/test_points.cc b/tests/geo/point.cc similarity index 71% rename from tests/geo/test_points.cc rename to tests/geo/point.cc index e501676be..a3b2ddd82 100644 --- a/tests/geo/test_points.cc +++ b/tests/geo/point.cc @@ -3,22 +3,66 @@ * * 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 "eckit/geo/Point2.h" -#include "eckit/geo/Point3.h" + +#include "eckit/geo/Point.h" +#include "eckit/maths/Matrix3.h" #include "eckit/testing/Test.h" -using namespace std; -using namespace eckit; -using namespace eckit::testing; -using namespace eckit::geo; + +//---------------------------------------------------------------------------------------------------------------------- + namespace eckit::test { + +using namespace geo; + + +CASE("PointLonLat normalisation") { + PointLonLat p(1, 90.); + EXPECT_EQUAL(p.lon, 1.); + EXPECT_EQUAL(p.lat, 90.); + + auto p2 = PointLonLat::make(p.lon, p.lat); + EXPECT_EQUAL(p2.lon, 0.); + EXPECT(points_equal(p, p2)); + + auto p3 = PointLonLat(50., 90.); + EXPECT(points_equal(p, p3)); + + PointLonLat q(1., -90.); + EXPECT_EQUAL(q.lon, 1.); + EXPECT_EQUAL(q.lat, -90.); + + auto q2 = q.antipode(); + EXPECT_EQUAL(q2.lon, 0.); + EXPECT(points_equal(q2, p)); + + auto q3 = q2.antipode(); + EXPECT(points_equal(q3, q)); +} + + +CASE("PointLonLat comparison") { + auto r(PointLonLat::make(-10., -91.)); + EXPECT(points_equal(r, r.antipode().antipode())); + + Point a1 = PointLonLat{300, -30}; + Point a2 = PointLonLat{-59.99999999999996, -30.000000000000018}; + EXPECT(points_equal(a1, a2)); + + Point b1 = PointLonLat{-178., -46.7}; + Point b2 = PointLonLat{-178.00000000000003, -46.7}; + EXPECT(points_equal(b1, b2)); +} + + CASE("Inits to Zero") { Point2 q; @@ -26,6 +70,7 @@ CASE("Inits to Zero") { EXPECT(q[YY] == 0.); } + CASE("Inits to Array/Point") { Point2 q = {4.0, 5.0}; @@ -46,6 +91,7 @@ CASE("Inits to Array/Point") { EXPECT(s[ZZ] == 3.0); } + CASE("Point2 addition") { Point2 p1 = {1.0, 2.0}; Point2 p2 = {2.0, 4.0}; @@ -56,6 +102,7 @@ CASE("Point2 addition") { EXPECT(r[YY] == 6.0); } + CASE("Point2 subtraction") { Point2 p1 = {2.0, 5.0}; Point2 p2 = {1.0, 2.0}; @@ -66,6 +113,7 @@ CASE("Point2 subtraction") { EXPECT(r[YY] == 3.0); } + CASE("Point2 scaling") { Point2 p1 = {1.0, 2.0}; Point2 p2(p1); @@ -83,6 +131,7 @@ CASE("Point2 scaling") { EXPECT(p5 == oo); } + CASE("Point2 equality") { Point2 p1 = {1.0, 2.0}; Point2 p2 = {1.0, 2.0}; @@ -90,6 +139,7 @@ CASE("Point2 equality") { EXPECT(p1 == p2); } + CASE("Point2 inequality") { Point2 p1 = {1.0, 3.0}; Point2 p2 = {1.0, 4.0}; @@ -97,13 +147,15 @@ CASE("Point2 inequality") { EXPECT(p1 != p2); } + CASE("Point2 comparison") { Point2 p1 = {2.0, 1.0}; Point2 p2 = {1.0, 2.0}; - EXPECT(p2 < p1); + // EXPECT(p2 < p1); } + CASE("Point distance comparison") { Point2 p1 = {2.0, 1.0}; Point2 p2 = {1.0, 2.0}; @@ -115,6 +167,7 @@ CASE("Point distance comparison") { EXPECT(types::is_approximately_equal(p1.distance(p3), 5.0)); } + CASE("Point distance2 comparison") { Point2 p1 = {2.0, 1.0}; Point2 p2 = {1.0, 2.0}; @@ -147,10 +200,13 @@ CASE("Point3 cross") { EXPECT(types::is_approximately_equal(p7[ZZ], p8[ZZ])); } + } // namespace eckit::test + //---------------------------------------------------------------------------------------------------------------------- + int main(int argc, char** argv) { - return run_tests(argc, argv); + return eckit::testing::run_tests(argc, argv); } diff --git a/tests/geo/test_projection.cc b/tests/geo/projection.cc similarity index 92% rename from tests/geo/test_projection.cc rename to tests/geo/projection.cc index e39cb7327..7fffdfcbb 100644 --- a/tests/geo/test_projection.cc +++ b/tests/geo/projection.cc @@ -26,19 +26,17 @@ namespace eckit::test { -CASE("projection") { - using eckit::MappedConfiguration; +using namespace geo; - using namespace eckit::geo; - using Projection = std::unique_ptr; - using eckit::geo::ProjectionFactory; +CASE("projection") { + using P = std::unique_ptr; Point p = PointLonLat{1, 1}; SECTION("projection type: none") { - Projection projection(ProjectionFactory::instance().get("none").create(MappedConfiguration{})); + P projection(ProjectionFactory::instance().get("none").create(MappedConfiguration{})); EXPECT(points_equal(p, projection->inv(p))); EXPECT(points_equal(p, projection->fwd(p))); } @@ -51,7 +49,7 @@ CASE("projection") { {"south_pole_lon", -361.}, }); - Projection projection(ProjectionFactory::instance().get(param.getString("projection")).create(param)); + P projection(ProjectionFactory::instance().get(param.getString("projection")).create(param)); EXPECT(points_equal(p, projection->inv(projection->fwd(p)))); EXPECT(points_equal(p, projection->fwd(projection->inv(p)))); @@ -59,11 +57,9 @@ CASE("projection") { SECTION("projection type: ll_to_xyz") { - Projection s1(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"R", 1.}}))); - Projection s2( - ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 1.}}))); - Projection s3( - ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 0.5}}))); + P s1(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"R", 1.}}))); + P s2(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 1.}}))); + P s3(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 0.5}}))); EXPECT(points_equal(p, s1->inv(s1->fwd(p)))); EXPECT(points_equal(p, s2->inv(s2->fwd(p)))); @@ -307,7 +303,7 @@ CASE("projection") { }; for (const auto& test : tests) { - Projection projection(ProjectionFactory::instance().get("proj").create( + P projection(ProjectionFactory::instance().get("proj").create( MappedConfiguration{{{"source", "EPSG:4326"}, {"target", test.target}}})); #if 0 @@ -323,7 +319,7 @@ CASE("projection") { EXPECT(points_equal(b, test.b)); EXPECT(points_equal(c, a)); - Projection reverse(ProjectionFactory::instance().get("proj").create( + P reverse(ProjectionFactory::instance().get("proj").create( MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}}))); auto d = reverse->fwd(test.b); diff --git a/tests/geo/test_range.cc b/tests/geo/range.cc similarity index 79% rename from tests/geo/test_range.cc rename to tests/geo/range.cc index 3a4504ee1..972412c16 100644 --- a/tests/geo/test_range.cc +++ b/tests/geo/range.cc @@ -25,14 +25,15 @@ namespace eckit::test { -CASE("range::Gaussian") { - using geo::range::Gaussian; +using namespace geo; + +CASE("range::Gaussian") { std::vector ref{59.44440828916676, 19.87571914744090, -19.87571914744090, -59.44440828916676}; SECTION("global") { - auto global = Gaussian(2); + auto global = range::Gaussian(2); EXPECT(global.size() == ref.size()); size_t i = 0; @@ -45,17 +46,17 @@ CASE("range::Gaussian") { SECTION("crop [50., -50.]") { constexpr auto eps = 1e-3; - auto cropped = Gaussian(2, 50., -50., eps); + auto cropped = range::Gaussian(2, 50., -50., eps); EXPECT(cropped.size() == ref.size() - 2); EXPECT_APPROX(cropped.values()[0], ref[1], eps); EXPECT_APPROX(cropped.values()[1], ref[2], eps); - EXPECT(Gaussian(2, 59.444, -59.444, 1e-3).size() == 4); - EXPECT(Gaussian(2, 59.444, -59.444, 1e-6).size() == 2); - EXPECT(Gaussian(2, 59.444, -59.445, 1e-6).size() == 3); + EXPECT(range::Gaussian(2, 59.444, -59.444, 1e-3).size() == 4); + EXPECT(range::Gaussian(2, 59.444, -59.444, 1e-6).size() == 2); + EXPECT(range::Gaussian(2, 59.444, -59.445, 1e-6).size() == 3); - auto single = Gaussian(2, -59.444, -59.444, eps); + auto single = range::Gaussian(2, -59.444, -59.444, eps); EXPECT(single.size() == 1); EXPECT_APPROX(single.values().front(), ref.back(), eps); @@ -65,7 +66,7 @@ CASE("range::Gaussian") { SECTION("crop [90., 0.]") { constexpr auto eps = 1e-3; - auto cropped = Gaussian(2, 90., 0., eps); + auto cropped = range::Gaussian(2, 90., 0., eps); EXPECT(cropped.size() == ref.size() / 2); EXPECT_APPROX(cropped.values()[0], ref[0], eps); diff --git a/tests/geo/search.cc b/tests/geo/search.cc new file mode 100644 index 000000000..8e7d993ab --- /dev/null +++ b/tests/geo/search.cc @@ -0,0 +1,73 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "eckit/geo/Search.h" +#include "eckit/testing/Test.h" + + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace eckit::test { + + +using namespace geo; + + +CASE("") { + std::vector points{ + {{0, 0, 0}, 0}, + }; + + Search3 search; + search.build(points); + + std::cout << search.nearestNeighbour({0.1, 0, 0}) << std::endl; + std::cout << search.nearestNeighbour({0.9, 0, 0}) << std::endl; + + search.insert({{1, 0, 0}, 1}); + + std::cout << search.nearestNeighbour({0.1, 0, 0}) << std::endl; + std::cout << search.nearestNeighbour({0.9, 0, 0}) << std::endl; +} + + +CASE("") { + std::vector points{ + {{0, 0}, 0}, + }; + + Search2 search; + search.build(points); + + std::cout << search.nearestNeighbour({0.1, 0}) << std::endl; + std::cout << search.nearestNeighbour({0.9, 0}) << std::endl; + + search.insert({{1, 0}, 1}); + + std::cout << search.nearestNeighbour({0.1, 0}) << std::endl; + std::cout << search.nearestNeighbour({0.9, 0}) << std::endl; +} + + +} // namespace eckit::test + + +//---------------------------------------------------------------------------------------------------------------------- + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/test_iterator.cc b/tests/geo/test_iterator.cc deleted file mode 100644 index 31c80c183..000000000 --- a/tests/geo/test_iterator.cc +++ /dev/null @@ -1,32 +0,0 @@ -/* - * (C) Copyright 1996- 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 - -#include "eckit/exception/Exceptions.h" -// #include "eckit/geo/Scanner.h" -// #include "eckit/geo/iterator/IteratorAggregator.h" -// #include "eckit/geo/iterator/IteratorComposer.h" - - -int main(int argc, const char* argv[]) { - // eckit::geo::iterator::IteratorComposer i(nullptr); - - // struct ScannerTest : public eckit::grid::Scanner { - // bool operator++() override { NOTIMP; } - // size_t size() const override { NOTIMP; } - // }; - - // eckit::grid::iterator::IteratorAggregator j; - - return 0; -} diff --git a/tests/geo/test_search.cc b/tests/geo/test_search.cc deleted file mode 100644 index afab1f0e4..000000000 --- a/tests/geo/test_search.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* - * (C) Copyright 1996- 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 -#include - -#include "eckit/geo/Search.h" - - -int main(int argc, const char* argv[]) { - using namespace eckit::geo; - - - { - std::vector points{ - {{0, 0, 0}, 0}, - }; - - Search3 search; - search.build(points); - - std::cout << search.nearestNeighbour({0.1, 0, 0}) << std::endl; - std::cout << search.nearestNeighbour({0.9, 0, 0}) << std::endl; - - search.insert({{1, 0, 0}, 1}); - - std::cout << search.nearestNeighbour({0.1, 0, 0}) << std::endl; - std::cout << search.nearestNeighbour({0.9, 0, 0}) << std::endl; - } - - - { - std::vector points{ - {{0, 0}, 0}, - }; - - Search2 search; - search.build(points); - - std::cout << search.nearestNeighbour({0.1, 0}) << std::endl; - std::cout << search.nearestNeighbour({0.9, 0}) << std::endl; - - search.insert({{1, 0}, 1}); - - std::cout << search.nearestNeighbour({0.1, 0}) << std::endl; - std::cout << search.nearestNeighbour({0.9, 0}) << std::endl; - } - - - return 0; -} diff --git a/tests/geo/test_types.cc b/tests/geo/test_types.cc deleted file mode 100644 index f0d88a86d..000000000 --- a/tests/geo/test_types.cc +++ /dev/null @@ -1,60 +0,0 @@ -/* - * (C) Copyright 1996- 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 - -#include "eckit/geo/Point.h" -#include "eckit/maths/Matrix3.h" -#include "eckit/testing/Test.h" - - -int main(int argc, char* argv[]) { - using namespace eckit::geo; - - PointLonLat p(1, 90.); - - std::cout << "p: " << p << std::endl; - std::cout << "p: " << PointLonLat::make(p.lon, p.lat) << std::endl; - std::cout << "p: " << points_equal(p, PointLonLat(50., 90.)) << std::endl; - - PointLonLat q(1., -90.); - std::cout << "q: " << q << std::endl; - std::cout << "~q: " << q.antipode() << std::endl; - std::cout << "~~q: " << q.antipode().antipode() << std::endl; - - auto r(PointLonLat::make(-10., -91.)); - EXPECT(points_equal(r, r.antipode().antipode())); - - Point a1 = PointLonLat{300, -30}; - Point a2 = PointLonLat{-59.99999999999996, -30.000000000000018}; - EXPECT(points_equal(a1, a2)); - - Point b1 = PointLonLat{-178., -46.7}; - Point b2 = PointLonLat{-178.00000000000003, -46.7}; - EXPECT(points_equal(b1, b2)); - - { - using Matrix3 = eckit::maths::Matrix3; - Matrix3 M{1, - 2, - 3, // - 4, - 5, - 6, // - 7, - 8, - 1}; - const auto W = M.inverse(); - std::cout << "M M^-1=" << (M * W) << std::endl; - std::cout << "M^-1 M=" << (W * M) << std::endl; - } -} diff --git a/tests/geo/test_util.cc b/tests/geo/test_util.cc deleted file mode 100644 index 11513d6ba..000000000 --- a/tests/geo/test_util.cc +++ /dev/null @@ -1,53 +0,0 @@ -/* - * (C) Copyright 1996- 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 -#include - -#include "eckit/geo/util.h" - - -template -std::ostream& operator<<(std::ostream& out, const std::vector& v) { - const auto* sep = ""; - for (const auto& value : v) { - out << sep << value; - sep = ", "; - } - return out; -} - - -int main(int argc, char* argv[]) { - using namespace eckit::geo::util; - -#if 0 - std::cout << linspace(1, 2, 2, true) << std::endl; - std::cout << arange(1, 2, 0.5) << std::endl; - std::cout << gaussian_latitudes(64, false) << std::endl; - std::cout << normalise_longitude_to_maximum(0., 360.) << std::endl; - std::cout << normalise_longitude_to_minimum(0., -360.) << std::endl; -#elif 1 - std::cout << reduced_classical_pl(16) << std::endl; - std::cout << reduced_classical_pl(16) << std::endl; - std::cout << reduced_octahedral_pl(16) << std::endl; - std::cout << reduced_octahedral_pl(16) << std::endl; -#elif 0 - std::vector values1{1., 2., 3., 4., 5., 6.}; - std::vector values2{6., 5., 4., 3., 2., 1.}; - - std::cout << monotonic_crop({1.}, 1., 1., 0.) << std::endl; - std::cout << monotonic_crop({1., 1., 1.}, 1., 2., 0.) << std::endl; - std::cout << monotonic_crop(values1, 2., 3., 0.) << std::endl; - std::cout << monotonic_crop(values2, 2., 3., 0.) << std::endl; -#endif -} diff --git a/tests/geo/util.cc b/tests/geo/util.cc new file mode 100644 index 000000000..8b739447a --- /dev/null +++ b/tests/geo/util.cc @@ -0,0 +1,72 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "eckit/geo/util.h" +#include "eckit/testing/Test.h" + + +template +std::ostream& operator<<(std::ostream& out, const std::vector& v) { + const auto* sep = ""; + for (const auto& value : v) { + out << sep << value; + sep = ", "; + } + return out; +} + + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace eckit::test { + + +using namespace geo; + + +CASE("") { +#if 0 + std::cout << util::linspace(1, 2, 2, true) << std::endl; + std::cout << util::arange(1, 2, 0.5) << std::endl; + std::cout << util::gaussian_latitudes(64, false) << std::endl; + std::cout << util::normalise_longitude_to_maximum(0., 360.) << std::endl; + std::cout << util::normalise_longitude_to_minimum(0., -360.) << std::endl; +#elif 1 + std::cout << util::reduced_classical_pl(16) << std::endl; + std::cout << util::reduced_classical_pl(16) << std::endl; + std::cout << util::reduced_octahedral_pl(16) << std::endl; + std::cout << util::reduced_octahedral_pl(16) << std::endl; +#elif 0 + std::vector values1{1., 2., 3., 4., 5., 6.}; + std::vector values2{6., 5., 4., 3., 2., 1.}; + + std::cout << util::monotonic_crop({1.}, 1., 1., 0.) << std::endl; + std::cout << util::monotonic_crop({1., 1., 1.}, 1., 2., 0.) << std::endl; + std::cout << util::monotonic_crop(values1, 2., 3., 0.) << std::endl; + std::cout << util::monotonic_crop(values2, 2., 3., 0.) << std::endl; +#endif +} + + +} // namespace eckit::test + + +//---------------------------------------------------------------------------------------------------------------------- + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From 17c7ff9d28e217a37250dfad5a46e883726da136 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 2 Nov 2023 15:37:02 +0000 Subject: [PATCH 366/737] eckit::geo area::BoundingBox --- src/eckit/geo/area/BoundingBox.cc | 80 ++++++++++--------- src/eckit/geo/area/BoundingBox.h | 62 +++++++------- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 4 +- src/eckit/geo/grid/regular/RegularGaussian.cc | 4 +- tests/geo/area_boundingbox.cc | 55 ++++++++++++- 5 files changed, 127 insertions(+), 78 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index fc7780354..e9b8d4fd1 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -17,7 +17,7 @@ #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Point.h" +#include "eckit/geo/PointLonLat.h" #include "eckit/geo/Sphere.h" #include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -26,63 +26,67 @@ namespace eckit::geo::area { +static BoundingBox make_from_config(const Configuration& config) { + auto area = config.getDoubleVector("area", + {config.getDouble("north", 90.), + config.getDouble("west", 0.), + config.getDouble("south", -90.), + config.getDouble("east", 360.)}); + + ASSERT_MSG(area.size() == 4, "BoundingBox: expected list of size 4"); + return {area[0], area[1], area[2], area[3]}; +} + + BoundingBox::BoundingBox(const Configuration& config) : - BoundingBox(config.getDouble("north", 90.), - config.getDouble("west", 0.), - config.getDouble("south", -90.), - config.getDouble("east", 360.)) {} + BoundingBox(make_from_config(config)) {} -BoundingBox::BoundingBox(double north, double west, double south, double east) : - north_(north), west_(west), south_(south), east_(east) { - if (west_ != east_) { +BoundingBox::BoundingBox(double n, double w, double s, double e) : + array{n, w, s, e} { + if (west != east) { auto e = PointLonLat::normalise_angle_to_minimum(east, west); - east_ = e == west_ ? (e + 360.) : e; + east = e == west ? (e + 360.) : e; } - ASSERT_MSG(west_ <= east_ && east_ <= west_ + 360., "BoundingBox: longitude range"); - ASSERT_MSG(-90. <= south_ && south_ <= north_ && north_ <= 90., "BoundingBox: latitude range"); + ASSERT_MSG(west <= east && east <= west + 360., "BoundingBox: longitude range"); + ASSERT_MSG(-90. <= south && south <= north && north <= 90., "BoundingBox: latitude range"); } -BoundingBox::BoundingBox() : - BoundingBox(90., 0., -90., 360.) {} - - bool BoundingBox::operator==(const BoundingBox& other) const { - return north_ == other.north_ && south_ == other.south_ && west_ == other.west_ && east_ == other.east_; + return north == other.north && south == other.south && west == other.west && east == other.east; } bool BoundingBox::isPeriodicWestEast() const { - return west_ != east_ && west_ == PointLonLat::normalise_angle_to_minimum(east_, west_); + return west != east && west == PointLonLat::normalise_angle_to_minimum(east, west); } bool BoundingBox::contains(double lat, double lon) const { - return lat <= north_ && lat >= south_ && PointLonLat::normalise_angle_to_minimum(lon, west_) <= east_; + return lat <= north && lat >= south && PointLonLat::normalise_angle_to_minimum(lon, west) <= east; } bool BoundingBox::contains(const BoundingBox& other) const { if (other.empty()) { - return contains(other.south_, other.west_); + return contains(other.south, other.west); } // check for West/East range (if non-periodic), then other's corners - if (east_ - west_ < other.east_ - other.west_ || - east_ < PointLonLat::normalise_angle_to_minimum(other.east_, west_)) { + if (east - west < other.east - other.west || east < PointLonLat::normalise_angle_to_minimum(other.east, west)) { return false; } - return contains(other.north_, other.west_) && contains(other.north_, other.east_) && - contains(other.south_, other.west_) && contains(other.south_, other.east_); + return contains(other.north, other.west) && contains(other.north, other.east) && + contains(other.south, other.west) && contains(other.south, other.east); } bool BoundingBox::intersects(BoundingBox& other) const { - auto n = std::min(north_, other.north_); - auto s = std::max(south_, other.south_); + auto n = std::min(north, other.north); + auto s = std::max(south, other.south); bool intersectsSN = s <= n; if (!intersectsSN) { @@ -90,24 +94,24 @@ bool BoundingBox::intersects(BoundingBox& other) const { } if (isPeriodicWestEast() && other.isPeriodicWestEast()) { - other = {n, other.west_, s, other.east_}; + other = {n, other.west, s, other.east}; return intersectsSN; } - auto w = std::min(west_, other.west_); + auto w = std::min(west, other.west); auto e = w; auto intersect = [](const BoundingBox& a, const BoundingBox& b, double& w, double& e) { bool p = a.isPeriodicWestEast(); if (p || b.isPeriodicWestEast()) { - w = (p ? b : a).west_; - e = (p ? b : a).east_; + w = (p ? b : a).west; + e = (p ? b : a).east; return true; } - auto ref = PointLonLat::normalise_angle_to_minimum(b.west_, a.west_); - auto w_ = std::max(a.west_, ref); - auto e_ = std::min(a.east_, PointLonLat::normalise_angle_to_minimum(b.east_, ref)); + auto ref = PointLonLat::normalise_angle_to_minimum(b.west, a.west); + auto w_ = std::max(a.west, ref); + auto e_ = std::min(a.east, PointLonLat::normalise_angle_to_minimum(b.east, ref)); if (w_ <= e_) { w = w_; @@ -118,8 +122,8 @@ bool BoundingBox::intersects(BoundingBox& other) const { return false; }; - bool intersectsWE = west_ <= other.west_ ? intersect(*this, other, w, e) || intersect(other, *this, w, e) - : intersect(other, *this, w, e) || intersect(*this, other, w, e); + bool intersectsWE = west <= other.west ? intersect(*this, other, w, e) || intersect(other, *this, w, e) + : intersect(other, *this, w, e) || intersect(*this, other, w, e); ASSERT_MSG(w <= e, "BoundingBox::intersects: longitude range"); other = {n, w, s, e}; @@ -129,16 +133,16 @@ bool BoundingBox::intersects(BoundingBox& other) const { bool BoundingBox::empty() const { - return types::is_approximately_equal(north_, south_) || types::is_approximately_equal(west_, east_); + return types::is_approximately_equal(north, south) || types::is_approximately_equal(west, east); } double BoundingBox::area(double radius) const { - double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); + double lonf = isPeriodicWestEast() ? 1. : ((east - west) / 360.); ASSERT(0. <= lonf && lonf <= 1.); - const auto sn = std::sin(north_ * util::degree_to_radian); - const auto ss = std::sin(south_ * util::degree_to_radian); + const auto sn = std::sin(north * util::degree_to_radian); + const auto ss = std::sin(south * util::degree_to_radian); double latf = 0.5 * (sn - ss); ASSERT(0. <= latf && latf <= 1.); diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 3964b749e..b9dd28982 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include "eckit/geo/Area.h" @@ -35,10 +36,17 @@ class BoundingBox : public Area, protected std::array { explicit BoundingBox(const Configuration&); BoundingBox(double north, double west, double south, double east); - BoundingBox(); + BoundingBox() : + BoundingBox(90., 0., -90., 360.) {} + + BoundingBox(const BoundingBox& other) : + array(other) {} + + BoundingBox(BoundingBox&&) = default; // -- Destructor - // None + + ~BoundingBox() override = default; // -- Convertors // None @@ -48,14 +56,19 @@ class BoundingBox : public Area, protected std::array { bool operator==(const BoundingBox&) const; bool operator!=(const BoundingBox& other) const { return !operator==(other); } - // -- Methods + BoundingBox& operator=(const BoundingBox& other) { + array::operator=(other); + return *this; + } + + BoundingBox& operator=(BoundingBox&& other) { + array::operator=(other); + return *this; + } - std::array deconstruct() const { return {north_, west_, south_, east_}; } + // -- Methods - double north() const { return north_; } - double west() const { return west_; } - double south() const { return south_; } - double east() const { return east_; } + std::array deconstruct() const { return {north, west, south, east}; } bool isPeriodicWestEast() const; @@ -80,32 +93,12 @@ class BoundingBox : public Area, protected std::array { // -- Class methods // None -protected: // -- Members - // None - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None - -private: - // -- Members - - double north_; - double west_; - double south_; - double east_; + double& north = operator[](0); + double& west = operator[](1); + double& south = operator[](2); + double& east = operator[](3); // -- Methods // None @@ -120,7 +113,10 @@ class BoundingBox : public Area, protected std::array { // None // -- Friends - // None + + friend std::ostream& operator<<(std::ostream& os, const BoundingBox& bbox) { + return os << "[" << bbox.north << "," << bbox.west << "," << bbox.south << "," << bbox.east << "]"; + } }; diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index f4bc9d53a..d208f5983 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -28,7 +28,7 @@ ReducedGaussian::ReducedGaussian(const Configuration& config) : ReducedGaussian::ReducedGaussian(size_t N, const pl_type& pl, const area::BoundingBox& bbox) : - Reduced(bbox), pl_(pl), j_(0), Nj_(N * 2), y_(new range::Gaussian(N, bbox.north(), bbox.south())) { + Reduced(bbox), pl_(pl), j_(0), Nj_(N * 2), y_(new range::Gaussian(N, bbox.north, bbox.south)) { ASSERT(y_); } @@ -62,7 +62,7 @@ const std::vector& ReducedGaussian::latitudes() const { std::vector ReducedGaussian::longitudes(size_t j) const { auto Ni = ni(j); if (!x_ || x_->size() != Ni) { - const_cast&>(x_).reset(new range::Regular(Ni, bbox().west(), bbox().east())); + const_cast&>(x_).reset(new range::Regular(Ni, bbox().west, bbox().east)); } return x_->values(); diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index e70a588ce..d6cbcb000 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -32,8 +32,8 @@ RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : RegularGaussian::RegularGaussian(size_t N, size_t ni, const area::BoundingBox& bbox) : Regular(bbox), - x_(new range::RegularLongitude(ni, bbox.west(), bbox.east())), - y_(new range::Gaussian(N, bbox.north(), bbox.south())) { + x_(new range::RegularLongitude(ni, bbox.west, bbox.east)), + y_(new range::Gaussian(N, bbox.north, bbox.south)) { ASSERT(x_->size() > 0); ASSERT(y_->size() > 0); } diff --git a/tests/geo/area_boundingbox.cc b/tests/geo/area_boundingbox.cc index 7a7a63564..59409ca9d 100644 --- a/tests/geo/area_boundingbox.cc +++ b/tests/geo/area_boundingbox.cc @@ -23,13 +23,62 @@ namespace eckit::test { using namespace geo; -CASE("") { - auto a = area::BoundingBox{}; - auto b = area::BoundingBox{90, 0, -90, 360}; +CASE("global") { + area::BoundingBox a; + area::BoundingBox b(90, 0, -90, 360); EXPECT_EQUAL(a, b); } +CASE("latitude (checks)") { + EXPECT_THROWS(area::BoundingBox(-90, 0, 90, 360)); // fails South<=North + EXPECT_NO_THROW(area::BoundingBox(90, 0, 90, 360)); + EXPECT_NO_THROW(area::BoundingBox(-90, 0, -90, 360)); +} + + +CASE("longitude (normalisation)") { + for (auto west : {-900, -720, -540, -360, -180, 0, 180, 360, 540, 720, 900}) { + area::BoundingBox a(90, west, 90, west); + EXPECT_EQUAL(a.west, west); + + area::BoundingBox b(90, west, 90, west - 1); + EXPECT_EQUAL(b.east, west + 360 - 1); + } +} + + +CASE("assignment") { + area::BoundingBox a(10, 1, -10, 100); + + area::BoundingBox b(20, 2, -20, 200); + EXPECT_NOT_EQUAL(a.north, b.north); + EXPECT_NOT_EQUAL(a, b); + + b = a; + EXPECT_EQUAL(a.north, b.north); + EXPECT_EQUAL(a, b); + + b.north = 30; + EXPECT_EQUAL(b.north, 30); + EXPECT_EQUAL(a.north, 10); + + area::BoundingBox c(a); + EXPECT_EQUAL(a.north, c.north); + EXPECT_EQUAL(a, c); + + c.north = 40; + EXPECT_EQUAL(c.north, 40); + EXPECT_EQUAL(a.north, 10); + + auto d(std::move(a)); + EXPECT_EQUAL(d.north, 10); + + d.north = 50; + EXPECT_EQUAL(d.north, 50); +} + + } // namespace eckit::test From 0e252ee22ad3c1f2e507af0f3b2ee87c75e86072 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 2 Nov 2023 16:33:39 +0000 Subject: [PATCH 367/737] eckit::geo Increments --- src/eckit/geo/Increments.cc | 26 ++++++------ src/eckit/geo/Increments.h | 53 ++++++++++++++----------- tests/geo/CMakeLists.txt | 1 + tests/geo/increments.cc | 79 +++++++++++++++++++++++++++++++++++++ 4 files changed, 125 insertions(+), 34 deletions(-) create mode 100644 tests/geo/increments.cc diff --git a/src/eckit/geo/Increments.cc b/src/eckit/geo/Increments.cc index 34f4c2033..b64e776da 100644 --- a/src/eckit/geo/Increments.cc +++ b/src/eckit/geo/Increments.cc @@ -14,29 +14,33 @@ #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo { -Increments::Increments(double west_east, double south_north) : - P{west_east, south_north} { - ASSERT(operator[](0) > 0.); - ASSERT(operator[](1) > 0.); +static Increments make_from_config(const Configuration& config) { + auto grid = config.getDoubleVector("grid"); + + ASSERT_MSG(grid.size() == 2, "Increments: expected list of size 2"); + return {grid[0], grid[1]}; } -Increments::Increments(const Configuration& config) : - Increments(VectorHelper(config)) {} +Increments::Increments(double west_east, double south_north) : + array{west_east, south_north} { + ASSERT(!types::is_equal(operator[](0), 0.)); + ASSERT(!types::is_equal(operator[](1), 0.)); +} -Increments::Increments(const VectorHelper& helper) : - Increments(helper[0], helper[1]) {} +Increments::Increments(const Configuration& config) : + Increments(make_from_config(config)) {} -Increments::VectorHelper::VectorHelper(const Configuration& config) : - vector(config.getDoubleVector("grid")) { - ASSERT(size() == 2); +bool Increments::operator==(const Increments& other) const { + return west_east == other.west_east && south_north == other.south_north; } diff --git a/src/eckit/geo/Increments.h b/src/eckit/geo/Increments.h index fd531b009..37fe6345f 100644 --- a/src/eckit/geo/Increments.h +++ b/src/eckit/geo/Increments.h @@ -13,7 +13,7 @@ #pragma once #include -#include +#include namespace eckit { @@ -25,41 +25,49 @@ namespace eckit::geo { class Increments : protected std::array { -private: - // -- Types - - using P = std::array; - - struct VectorHelper : std::vector { - explicit VectorHelper(const Configuration&); - }; - public: - // -- Types - // None - // -- Exceptions // None // -- Constructors + explicit Increments(const Configuration&); + Increments(double west_east, double south_north); + Increments() : + Increments(0, 0) {} + + Increments(const Increments& other) : + array(other) {} - explicit Increments(const Configuration& config); + Increments(Increments&&) = default; // -- Destructor - // None + + ~Increments() = default; // -- Convertors // None // -- Operators - // None + + bool operator==(const Increments& other) const; + bool operator!=(const Increments& other) const { return !operator==(other); } + + Increments& operator=(const Increments& other) { + array::operator=(other); + return *this; + } + + Increments& operator=(Increments&& other) { + array::operator=(other); + return *this; + } // Members - double& west_east = P::operator[](0); - double& south_north = P::operator[](1); + double& west_east = array::operator[](0); + double& south_north = array::operator[](1); // -- Methods @@ -75,10 +83,6 @@ class Increments : protected std::array { // None private: - // -- Constructors - - explicit Increments(const VectorHelper&); - // -- Members // None @@ -95,7 +99,10 @@ class Increments : protected std::array { // None // -- Friends - // None + + friend std::ostream& operator<<(std::ostream& os, const Increments& inc) { + return os << "[" << inc.west_east << "," << inc.south_north << "]"; + } }; diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 84d9b1706..fc5774980 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -8,6 +8,7 @@ foreach( _test grid_reorder grid_to_points gridspec + increments iterator kdtree kpoint diff --git a/tests/geo/increments.cc b/tests/geo/increments.cc new file mode 100644 index 000000000..23f681aa9 --- /dev/null +++ b/tests/geo/increments.cc @@ -0,0 +1,79 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Increments.h" +#include "eckit/testing/Test.h" + + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace eckit::test { + + +using namespace geo; + + +CASE("checks") { + EXPECT_NO_THROW(Increments(1, 2)); + EXPECT_NO_THROW(Increments(1, -2)); + EXPECT_NO_THROW(Increments(-1, 2)); + EXPECT_NO_THROW(Increments(-1, -2)); + + EXPECT_THROWS(Increments(-1, 0)); + EXPECT_THROWS(Increments(0, -2)); + EXPECT_THROWS(Increments(0, 0)); + EXPECT_THROWS(Increments(0, 2)); + EXPECT_THROWS(Increments(1, 0)); +} + + +CASE("assignment") { + Increments a(10, 1); + + Increments b(20, 2); + EXPECT_NOT_EQUAL(a.west_east, b.west_east); + EXPECT_NOT_EQUAL(a, b); + + b = a; + EXPECT_EQUAL(a.west_east, b.west_east); + EXPECT_EQUAL(a, b); + + b.west_east = 30; + EXPECT_EQUAL(b.west_east, 30); + EXPECT_EQUAL(a.west_east, 10); + + Increments c(a); + EXPECT_EQUAL(a.west_east, c.west_east); + EXPECT_EQUAL(a, c); + + c.west_east = 40; + EXPECT_EQUAL(c.west_east, 40); + EXPECT_EQUAL(a.west_east, 10); + + auto d(std::move(a)); + EXPECT_EQUAL(d.west_east, 10); + + d.west_east = 50; + EXPECT_EQUAL(d.west_east, 50); +} + + +} // namespace eckit::test + + +//---------------------------------------------------------------------------------------------------------------------- + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From fa89c1e6c22797f50b7a3d294ca6c096996e5ae7 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 2 Nov 2023 16:47:11 +0000 Subject: [PATCH 368/737] eckit::geo RegularLL --- src/eckit/geo/grid/regular/RegularLL.cc | 70 ++++++++++++++++--------- src/eckit/geo/grid/regular/RegularLL.h | 44 ++++++++++------ 2 files changed, 75 insertions(+), 39 deletions(-) diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index 2e58ec568..9a8795053 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -16,6 +16,8 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Increments.h" #include "eckit/geo/iterator/Regular.h" +#include "eckit/geo/range/Regular.h" +#include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/util/regex.h" #include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" @@ -55,23 +57,23 @@ struct DiscreteRange { if (inc == 0) { b = a = _a; n = 1; + return; } - else { - auto shift = (_ref / inc).decimalPart() * _inc; - a = shift + adjust(_a - shift, inc, true); - if (_b == _a) { - b = a; - } - else { - auto c = shift + adjust(_b - shift, inc, false); - c = a + ((c - a) / inc).integralPart() * inc; - b = c < a ? a : c; - } + auto shift = (_ref / inc).decimalPart() * _inc; + a = shift + adjust(_a - shift, inc, true); - n = static_cast(((b - a) / inc).integralPart() + 1); + if (_b == _a) { + b = a; + } + else { + auto c = shift + adjust(_b - shift, inc, false); + c = a + ((c - a) / inc).integralPart() * inc; + b = c < a ? a : c; } + n = static_cast(((b - a) / inc).integralPart() + 1); + ASSERT(a <= b); ASSERT(n >= 1); } @@ -99,6 +101,21 @@ struct DiscreteRange { } // namespace +RegularLL::Internal::Internal(const Increments& _inc, const area::BoundingBox& _bbox, const PointLonLat& _ref) : + inc(_inc), bbox(_bbox), first(_ref) { + + const DiscreteRange lon(bbox.west, bbox.east, inc.west_east, _ref.lon, 360); + const DiscreteRange lat(bbox.south, bbox.north, inc.south_north, _ref.lat); + + ni = lon.n; + nj = lat.n; + ASSERT(ni > 0); + ASSERT(nj > 0); + + bbox = {lat.b, lon.a, lat.a, lon.b}; +} + + RegularLL::RegularLL(const Configuration& config) : RegularLL(Increments{config}, area::BoundingBox{config}, @@ -106,18 +123,23 @@ RegularLL::RegularLL(const Configuration& config) : config.getDouble("reference_lat", config.getDouble("south", -90))}) {} -RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& reference) : - Regular(bbox), - ni_(DiscreteRange(bbox.west(), bbox.east(), inc.west_east, reference.lon, 360).n), - nj_(DiscreteRange(bbox.south(), bbox.north(), inc.south_north, reference.lat).n), - reference_(reference) { - ASSERT(ni_ > 0); - ASSERT(nj_ > 0); -} +RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : + RegularLL(inc, bbox, {bbox.south, bbox.west}) {} + +RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& ref) : + RegularLL(Internal{inc, bbox, ref}) {} -RegularLL::RegularLL(size_t ni, size_t nj, const area::BoundingBox& bbox, const PointLonLat& reference) : - Regular(bbox), ni_(ni), nj_(nj), reference_(reference) {} + +RegularLL::RegularLL(Internal&& internal) : + Regular(internal.bbox), + internal_(internal), + range_longitude_(new range::RegularLongitude(internal_.ni, internal_.bbox.east, internal_.bbox.west)), + range_latitude_(new range::Regular(internal_.nj, internal_.bbox.north, internal_.bbox.south)) { + ASSERT(size() > 0); + ASSERT(ni() == range_longitude_->size()); + ASSERT(nj() == range_latitude_->size()); +} Grid::iterator RegularLL::cbegin() const { @@ -131,12 +153,12 @@ Grid::iterator RegularLL::cend() const { const std::vector& RegularLL::longitudes() const { - NOTIMP; + return range_longitude_->values(); } const std::vector& RegularLL::latitudes() const { - NOTIMP; + return range_latitude_->values(); } diff --git a/src/eckit/geo/grid/regular/RegularLL.h b/src/eckit/geo/grid/regular/RegularLL.h index eb5414596..e2eae4f6a 100644 --- a/src/eckit/geo/grid/regular/RegularLL.h +++ b/src/eckit/geo/grid/regular/RegularLL.h @@ -12,18 +12,39 @@ #pragma once +#include + #include "eckit/geo/grid/Regular.h" namespace eckit::geo { class Increments; -} +class Range; +} // namespace eckit::geo namespace eckit::geo::grid::regular { class RegularLL final : public Regular { +private: + // -- Types + + struct Internal { + Internal(const Increments& _inc, const area::BoundingBox& _bbox, const PointLonLat& _ref); + + Increments inc; + area::BoundingBox bbox; + PointLonLat first; + + size_t ni = 0; + size_t nj = 0; + }; + + // -- Constructors + + explicit RegularLL(Internal&&); + public: // -- Types // None @@ -34,15 +55,8 @@ class RegularLL final : public Regular { // -- Constructors explicit RegularLL(const Configuration&); - - explicit RegularLL(const Increments& increments, const area::BoundingBox& bbox = {}) : - RegularLL(increments, bbox, {bbox.south(), bbox.west()}) {} - - explicit RegularLL(size_t ni, size_t nj, const area::BoundingBox& bbox = {}) : - RegularLL(ni, nj, bbox, {bbox.south(), bbox.west()}) {} - - RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& reference); - RegularLL(size_t ni, size_t nj, const area::BoundingBox&, const PointLonLat& reference); + explicit RegularLL(const Increments&, const area::BoundingBox& = {}); + RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); // -- Destructor // None @@ -61,8 +75,8 @@ class RegularLL final : public Regular { iterator cbegin() const override; iterator cend() const override; - size_t ni() const override { return ni_; } - size_t nj() const override { return nj_; } + size_t ni() const override { return internal_.ni; } + size_t nj() const override { return internal_.nj; } // -- Class members // None @@ -74,9 +88,9 @@ class RegularLL final : public Regular { private: // -- Members - size_t ni_; - size_t nj_; - PointLonLat reference_; + const Internal internal_; + const std::unique_ptr range_longitude_; + const std::unique_ptr range_latitude_; // -- Methods // None From d0a67609cf1ee94483faefa447fcb2a6d47b883f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 2 Nov 2023 17:01:31 +0000 Subject: [PATCH 369/737] eckit::geo RegularLL --- tests/geo/CMakeLists.txt | 1 + tests/geo/grid_regular_ll.cc | 46 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 tests/geo/grid_regular_ll.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index fc5774980..7d6e63585 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -5,6 +5,7 @@ foreach( _test figure_sphere figure_sphere_great_circle grid + grid_regular_ll grid_reorder grid_to_points gridspec diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc new file mode 100644 index 000000000..65e9bab2a --- /dev/null +++ b/tests/geo/grid_regular_ll.cc @@ -0,0 +1,46 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/config/MappedConfiguration.h" +#include "eckit/geo/grid/regular/RegularLL.h" +#include "eckit/testing/Test.h" + + +namespace eckit::test { + + +using namespace eckit::geo; + + +CASE("") { + std::unique_ptr global( + new grid::regular::RegularLL(MappedConfiguration{{{"grid", std::vector{1, 1}}}})); + + size_t global_size = global->size(); + EXPECT_EQUAL(global_size, 360 * 181); + + std::unique_ptr local(new grid::regular::RegularLL( + MappedConfiguration{{{"grid", std::vector{2, 1}}, {"area", std::vector{10, 1, 1, 10}}}})); + + size_t local_size = local->size(); + EXPECT_EQUAL(local_size, 5 * 10); +} + + +} // namespace eckit::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From ea9c4e4cc31d8359c24837fd2924f1ab1b24ac78 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 14 Nov 2023 09:07:06 +0000 Subject: [PATCH 370/737] eckit::DynamicConfiguration, MappedConfiguration cleanup --- src/eckit/config/DynamicConfiguration.cc | 5 +- src/eckit/config/DynamicConfiguration.h | 9 +-- src/eckit/config/MappedConfiguration.cc | 18 +++--- src/eckit/config/MappedConfiguration.h | 76 +++++++++++------------- 4 files changed, 47 insertions(+), 61 deletions(-) diff --git a/src/eckit/config/DynamicConfiguration.cc b/src/eckit/config/DynamicConfiguration.cc index e5281b23b..6fe575f43 100644 --- a/src/eckit/config/DynamicConfiguration.cc +++ b/src/eckit/config/DynamicConfiguration.cc @@ -14,9 +14,8 @@ #include "eckit/exception/Exceptions.h" #include "eckit/value/Value.h" -namespace eckit { -//---------------------------------------------------------------------------------------------------------------------- +namespace eckit { namespace { @@ -77,6 +76,4 @@ void DynamicConfiguration::print(std::ostream& out) const { } -//---------------------------------------------------------------------------------------------------------------------- - } // namespace eckit diff --git a/src/eckit/config/DynamicConfiguration.h b/src/eckit/config/DynamicConfiguration.h index 37dbb1b00..b538e5131 100644 --- a/src/eckit/config/DynamicConfiguration.h +++ b/src/eckit/config/DynamicConfiguration.h @@ -8,8 +8,8 @@ * does it submit to any jurisdiction. */ -#ifndef eckit_DynamicConfiguration_H -#define eckit_DynamicConfiguration_H + +#pragma once #include #include @@ -18,9 +18,9 @@ #include "eckit/config/Configuration.h" + namespace eckit { -//---------------------------------------------------------------------------------------------------------------------- class DynamicConfiguration : public Configuration { public: @@ -118,8 +118,5 @@ class DynamicConfiguration : public Configuration { // None }; -//---------------------------------------------------------------------------------------------------------------------- } // namespace eckit - -#endif diff --git a/src/eckit/config/MappedConfiguration.cc b/src/eckit/config/MappedConfiguration.cc index 6d99094dc..891ccb232 100644 --- a/src/eckit/config/MappedConfiguration.cc +++ b/src/eckit/config/MappedConfiguration.cc @@ -8,14 +8,14 @@ * does it submit to any jurisdiction. */ + #include "eckit/config/MappedConfiguration.h" #include "eckit/log/JSON.h" #include "eckit/value/Value.h" -namespace eckit { -//---------------------------------------------------------------------------------------------------------------------- +namespace eckit { namespace { @@ -328,6 +328,12 @@ bool MappedConfiguration::get(const std::string& name, std::vector& } +void MappedConfiguration::print(std::ostream& out) const { + JSON j(out); + json(j); +} + + void MappedConfiguration::json(JSON& j) const { j.startObject(); for (const auto& nv : map_) { @@ -338,12 +344,4 @@ void MappedConfiguration::json(JSON& j) const { } -void MappedConfiguration::print(std::ostream& out) const { - JSON j(out); - json(j); -} - - -//---------------------------------------------------------------------------------------------------------------------- - } // namespace eckit diff --git a/src/eckit/config/MappedConfiguration.h b/src/eckit/config/MappedConfiguration.h index 14341669b..03f196388 100644 --- a/src/eckit/config/MappedConfiguration.h +++ b/src/eckit/config/MappedConfiguration.h @@ -8,17 +8,17 @@ * does it submit to any jurisdiction. */ -#ifndef eckit_MappedConfiguration_H -#define eckit_MappedConfiguration_H + +#pragma once #include #include #include "eckit/config/Configuration.h" + namespace eckit { -//---------------------------------------------------------------------------------------------------------------------- class MappedConfiguration final : public Configuration { public: @@ -72,44 +72,41 @@ class MappedConfiguration final : public Configuration { void set(const std::string& name, const char* value) { set(name, std::string{value}); } // (consistent with Configured) - void set(const std::string&, const std::string&); - void set(const std::string&, bool); - void set(const std::string&, int); - void set(const std::string&, long); - void set(const std::string&, long long); - void set(const std::string&, std::size_t); - void set(const std::string&, float); - void set(const std::string&, double); - - // (consistent with Configured) - void set(const std::string&, const std::vector&); - void set(const std::string&, const std::vector&); - void set(const std::string&, const std::vector&); - void set(const std::string&, const std::vector&); - void set(const std::string&, const std::vector&); - void set(const std::string&, const std::vector&); - void set(const std::string&, const std::vector&); + void set(const std::string& name, const std::string& value); + void set(const std::string& name, bool value); + void set(const std::string& name, int value); + void set(const std::string& name, long value); + void set(const std::string& name, long long value); + void set(const std::string& name, std::size_t value); + void set(const std::string& name, float value); + void set(const std::string& name, double value); + void set(const std::string& name, const std::vector& value); + void set(const std::string& name, const std::vector& value); + void set(const std::string& name, const std::vector& value); + void set(const std::string& name, const std::vector& value); + void set(const std::string& name, const std::vector& value); + void set(const std::string& name, const std::vector& value); + void set(const std::string& name, const std::vector& value); // -- Overridden methods - bool has(const std::string&) const override; - - bool get(const std::string&, std::string&) const override; - bool get(const std::string&, bool&) const override; - bool get(const std::string&, int&) const override; - bool get(const std::string&, long&) const override; - bool get(const std::string&, long long&) const override; - bool get(const std::string&, std::size_t&) const override; - bool get(const std::string&, float&) const override; - bool get(const std::string&, double&) const override; - - bool get(const std::string&, std::vector&) const override; - bool get(const std::string&, std::vector&) const override; - bool get(const std::string&, std::vector&) const override; - bool get(const std::string&, std::vector&) const override; - bool get(const std::string&, std::vector&) const override; - bool get(const std::string&, std::vector&) const override; - bool get(const std::string&, std::vector&) const override; + bool has(const std::string& name) const override; + + bool get(const std::string& name, std::string& value) const override; + bool get(const std::string& name, bool& value) const override; + bool get(const std::string& name, int& value) const override; + bool get(const std::string& name, long& value) const override; + bool get(const std::string& name, long long& value) const override; + bool get(const std::string& name, std::size_t& value) const override; + bool get(const std::string& name, float& value) const override; + bool get(const std::string& name, double& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; // -- Class members // None @@ -140,8 +137,5 @@ class MappedConfiguration final : public Configuration { // None }; -//---------------------------------------------------------------------------------------------------------------------- } // namespace eckit - -#endif From 09e434368cad380f2f19ffc38f8b6cbc33c5358a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 14 Nov 2023 09:15:09 +0000 Subject: [PATCH 371/737] eckit::DynamicConfiguration improved priorities --- src/eckit/config/DynamicConfiguration.cc | 15 +++++++++++---- src/eckit/config/DynamicConfiguration.h | 18 ++++++++++++------ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/eckit/config/DynamicConfiguration.cc b/src/eckit/config/DynamicConfiguration.cc index 6fe575f43..ebfb97554 100644 --- a/src/eckit/config/DynamicConfiguration.cc +++ b/src/eckit/config/DynamicConfiguration.cc @@ -48,13 +48,13 @@ void DynamicConfiguration::unhide(const std::string& name) { void DynamicConfiguration::push_back(Configuration* config) { ASSERT(config != nullptr); - configs_.emplace_back(config); + after_.emplace_back(config); } void DynamicConfiguration::push_front(Configuration* config) { ASSERT(config != nullptr); - configs_.emplace_front(config); + before_.emplace_back(config); } @@ -67,8 +67,15 @@ void DynamicConfiguration::print(std::ostream& out) const { } sep = ""; - out << "],config=" << config_ << ",configs["; - for (const auto& config : configs_) { + out << "],config=" << config_ << ",before["; + for (const auto& config : before_) { + out << sep << *config; + sep = ","; + } + + sep = ""; + out << ",after["; + for (const auto& config : after_) { out << sep << *config; sep = ","; } diff --git a/src/eckit/config/DynamicConfiguration.h b/src/eckit/config/DynamicConfiguration.h index b538e5131..23bc81282 100644 --- a/src/eckit/config/DynamicConfiguration.h +++ b/src/eckit/config/DynamicConfiguration.h @@ -12,7 +12,6 @@ #pragma once #include -#include #include #include @@ -55,8 +54,11 @@ class DynamicConfiguration : public Configuration { bool has(const std::string& name) const override { return !hide_.contains(name) && - (config_.has(name) || - std::any_of(configs_.begin(), configs_.end(), [&](const decltype(configs_)::value_type& c) { + (std::any_of(before_.begin(), + before_.end(), + [&](const decltype(before_)::value_type& c) { return c->has(name); }) || + config_.has(name) || + std::any_of(after_.begin(), after_.end(), [&](const decltype(after_)::value_type& c) { return c->has(name); })); } @@ -91,15 +93,19 @@ class DynamicConfiguration : public Configuration { } hide_; const Configuration& config_; - std::deque> configs_; + std::vector> before_; + std::vector> after_; // -- Methods template bool __get(const std::string& name, T& value) const { return !hide_.contains(name) && - (config_.get(name, value) || - std::any_of(configs_.begin(), configs_.end(), [&](const decltype(configs_)::value_type& c) { + (std::any_of(before_.begin(), + before_.end(), + [&](const decltype(before_)::value_type& c) { return c->get(name, value); }) || + config_.get(name, value) || + std::any_of(after_.begin(), after_.end(), [&](const decltype(after_)::value_type& c) { return c->get(name, value); })); } From 7f0f6d65994eec922e7dfc93de870b231be4cae3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 16 Nov 2023 16:44:43 +0000 Subject: [PATCH 372/737] eckit::geo::area::BoundingBox default settings --- src/eckit/geo/area/BoundingBox.cc | 27 +++++++++++++++++++-------- src/eckit/geo/area/BoundingBox.h | 3 +-- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index e9b8d4fd1..37318a2fa 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -14,6 +14,7 @@ #include #include +#include #include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" @@ -26,15 +27,21 @@ namespace eckit::geo::area { +static constexpr std::array DEFAULT{90, 0, -90, 360}; + + static BoundingBox make_from_config(const Configuration& config) { - auto area = config.getDoubleVector("area", - {config.getDouble("north", 90.), - config.getDouble("west", 0.), - config.getDouble("south", -90.), - config.getDouble("east", 360.)}); - - ASSERT_MSG(area.size() == 4, "BoundingBox: expected list of size 4"); - return {area[0], area[1], area[2], area[3]}; + if (std::vector area{DEFAULT[0], DEFAULT[1], DEFAULT[2], DEFAULT[3]}; config.get("area", area)) { + ASSERT_MSG(area.size() == 4, "BoundingBox: 'area' expected list of size 4"); + return {area[0], area[1], area[2], area[3]}; + } + + if (auto area(DEFAULT); config.get("north", area[0]) && config.get("west", area[1]) && + config.get("south", area[2]) && config.get("east", area[3])) { + return {area[0], area[1], area[2], area[3]}; + } + + throw UserError("BoundingBox: expecting 'area'=N/W/S/E or ('north', 'west', 'south', 'east')"); } @@ -54,6 +61,10 @@ BoundingBox::BoundingBox(double n, double w, double s, double e) : } +BoundingBox::BoundingBox() : + BoundingBox(DEFAULT[0], DEFAULT[1], DEFAULT[2], DEFAULT[3]) {} + + bool BoundingBox::operator==(const BoundingBox& other) const { return north == other.north && south == other.south && west == other.west && east == other.east; } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index b9dd28982..346a345f2 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -36,8 +36,7 @@ class BoundingBox : public Area, protected std::array { explicit BoundingBox(const Configuration&); BoundingBox(double north, double west, double south, double east); - BoundingBox() : - BoundingBox(90., 0., -90., 360.) {} + BoundingBox(); BoundingBox(const BoundingBox& other) : array(other) {} From f867cc310c2363cbf3f790f027623044ab8321f0 Mon Sep 17 00:00:00 2001 From: odlomax Date: Fri, 17 Nov 2023 16:29:04 +0000 Subject: [PATCH 373/737] Implemented forward interpolation. TODO: adjoint and more tests. --- src/atlas/util/UnitSphere.h | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/atlas/util/UnitSphere.h b/src/atlas/util/UnitSphere.h index c1458468f..1f38e455d 100644 --- a/src/atlas/util/UnitSphere.h +++ b/src/atlas/util/UnitSphere.h @@ -10,6 +10,12 @@ #pragma once +#include +#include + +#include "atlas/util/Constants.h" +#include "atlas/util/Point.h" + #include "eckit/geometry/UnitSphere.h" //------------------------------------------------------------------------------------------------------ @@ -21,6 +27,42 @@ namespace util { using eckit::geometry::UnitSphere; +/// @brief Calculate great-cricle course between points +/// +/// @details Calculates the direction (clockwise from north) of a great-circle +/// arc between lonLat1 and lonLat2. Returns the direction of the arc +/// at lonLat1 (first) and lonLat2 (second). Angle is normalised to the +/// range of atan2 (usually (-180, 180]). All input and output values +/// are in units of degrees. +/// @ref https://en.wikipedia.org/wiki/Great-circle_navigation +/// +inline std::pair greatCircleCourse(const Point2& lonLat1, + const Point2& lonLat2) { + + const auto lambda1 = lonLat1[0] * Constants::degreesToRadians(); + const auto lambda2 = lonLat2[0] * Constants::degreesToRadians(); + const auto phi1 = lonLat1[1] * Constants::degreesToRadians(); + const auto phi2 = lonLat2[1] * Constants::degreesToRadians(); + + const auto sinLambda12 = std::sin(lambda2 - lambda1); + const auto cosLambda12 = std::cos(lambda2 - lambda1); + const auto sinPhi1 = std::sin(phi1); + const auto sinPhi2 = std::sin(phi2); + const auto cosPhi1 = std::cos(phi1); + const auto cosPhi2 = std::cos(phi2); + + const auto alpha1 = + std::atan2(cosPhi2 * sinLambda12, + cosPhi1 * sinPhi2 - sinPhi1 * cosPhi2 * cosLambda12); + + const auto alpha2 = + std::atan2(cosPhi1 * sinLambda12, + -cosPhi2 * sinPhi1 + sinPhi2 * cosPhi1 * cosLambda12); + + return std::make_pair(alpha1 * Constants::radiansToDegrees(), + alpha2 * Constants::radiansToDegrees()); +}; + //------------------------------------------------------------------------------------------------------ } // namespace util From 10e8efba51b576f88e7a9fa8d1f5857cacb862f6 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 20 Nov 2023 09:41:52 +0000 Subject: [PATCH 374/737] eckit::geo ORCA --- src/eckit/geo/CMakeLists.txt | 4 ++-- src/eckit/geo/Range.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index e2a79190a..3397528db 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -77,8 +77,8 @@ list(APPEND eckit_geo_srcs grid/regular/RegularGaussian.h grid/regular/RegularLL.cc grid/regular/RegularLL.h - # grid/unstructured/ORCA.cc # requires eckit::codec - # grid/unstructured/ORCA.h + grid/unstructured/ORCA.cc + grid/unstructured/ORCA.h grid/unstructured/UnstructuredFromGrid.cc grid/unstructured/UnstructuredFromGrid.h iterator/Reduced.cc diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 1c4e60154..6346d6391 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -12,7 +12,6 @@ #pragma once -#include #include From 5f4b635975194d7f17a565e9eb8d9e33de61b36c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 21 Nov 2023 10:39:30 +0000 Subject: [PATCH 375/737] eckit::geo --- src/eckit/geo/CMakeLists.txt | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 3397528db..2e43ced48 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -77,8 +77,6 @@ list(APPEND eckit_geo_srcs grid/regular/RegularGaussian.h grid/regular/RegularLL.cc grid/regular/RegularLL.h - grid/unstructured/ORCA.cc - grid/unstructured/ORCA.h grid/unstructured/UnstructuredFromGrid.cc grid/unstructured/UnstructuredFromGrid.h iterator/Reduced.cc @@ -122,20 +120,23 @@ set(eckit_geo_include_dirs $ ) -set(eckit_geo_libs eckit_maths) # eckit_codec - -if(HAVE_PROJ) - list(APPEND eckit_geo_srcs projection/PROJ.cc projection/PROJ.h) - list(APPEND eckit_geo_libs PROJ::proj) - list(APPEND eckit_geo_include_dirs ${PROJ_INCLUDE_DIRS}) -endif() - ecbuild_add_library( TARGET eckit_geo TYPE SHARED INSTALL_HEADERS ALL HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geo - PUBLIC_LIBS ${eckit_geo_libs} + PUBLIC_LIBS eckit_maths PUBLIC_INCLUDES ${eckit_geo_include_dirs} SOURCES ${eckit_geo_srcs} ) + +if(HAVE_PROJ) + target_sources(eckit_geo PRIVATE projection/PROJ.cc projection/PROJ.h) + target_link_libraries(eckit_geo PUBLIC PROJ::proj) +endif() + +if(HAVE_CODEC) + target_sources(eckit_geo PRIVATE grid/unstructured/ORCA.cc grid/unstructured/ORCA.h) + target_link_libraries(eckit_geo PUBLIC eckit_codec) +endif() + From dcb34c1df3b1224545950284124e82d1304c1214 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 21 Nov 2023 15:09:15 +0000 Subject: [PATCH 376/737] eckit::geo --- src/eckit/geo/CMakeLists.txt | 2 +- src/eckit/geo/grid/unstructured/ORCA.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 2e43ced48..cf52e2db5 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -121,7 +121,7 @@ set(eckit_geo_include_dirs ) ecbuild_add_library( - TARGET eckit_geo + TARGET eckit_geo TYPE SHARED INSTALL_HEADERS ALL HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geo diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index b0cbafe92..90298b2b5 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -13,6 +13,7 @@ #include "eckit/geo/grid/unstructured/ORCA.h" #include "eckit/codec/codec.h" +#include "eckit/eckit_config.h" #include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "eckit/geo/LibEcKitGeo.h" @@ -25,7 +26,7 @@ #include "eckit/utils/ByteSwap.h" #include "eckit/utils/MD5.h" -#ifdef eckit_HAVE_CURL +#if eckit_HAVE_CURL #include "eckit/io/URLHandle.h" #endif From 46071c310d3883c0b8251a5084a52d7f72d68abe Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 21 Nov 2023 15:46:58 +0000 Subject: [PATCH 377/737] eckit::geo --- tests/geo/kdtree.cc | 306 +++++++++++++++++--------------------------- 1 file changed, 116 insertions(+), 190 deletions(-) diff --git a/tests/geo/kdtree.cc b/tests/geo/kdtree.cc index a06e1d53b..709dbb869 100644 --- a/tests/geo/kdtree.cc +++ b/tests/geo/kdtree.cc @@ -10,25 +10,21 @@ */ -#include +#include #include "eckit/container/KDTree.h" #include "eckit/geo/Point2.h" -#include "eckit/os/Semaphore.h" #include "eckit/testing/Test.h" namespace eckit::test { -using namespace geo; - - //---------------------------------------------------------------------------------------------------------------------- struct TestTreeTrait { - typedef Point2 Point; - typedef double Payload; + using Point = geo::Point2; + using Payload = double; }; //---------------------------------------------------------------------------------------------------------------------- @@ -36,16 +32,12 @@ struct TestTreeTrait { /// \brief Class used to test whether any point in a kd-tree lies in the interior of an /// axis-aligned box. template -class PointInBoxInteriorFinder { -public: +struct PointInBoxInteriorFinder { using KDTree = KDTreeX; - using Point = KDTree::Point; - -private: - using Alloc = KDTree::Alloc; - using Node = KDTree::Node; + using Point = typename KDTree::Point; + using Alloc = typename KDTree::Alloc; + using Node = typename KDTree::Node; -public: /// \brief Returns true if any point in \p tree lies in the interior of the specified /// axis-aligned box. /// @@ -59,8 +51,10 @@ class PointInBoxInteriorFinder { if (!tree.root_) { return false; } - Alloc& alloc = tree.alloc_; - Node* root = alloc.convert(tree.root_, static_cast(nullptr)); + + auto& alloc = tree.alloc_; + auto* root = alloc.convert(tree.root_, static_cast(nullptr)); + ASSERT(root != nullptr); return isAnyPointInBoxInterior(root, alloc, lbound, ubound); } @@ -70,7 +64,11 @@ class PointInBoxInteriorFinder { /// interior of the axis-aligned box with bottom-left and top-right corners at /// \p lbound and \p ubound. static bool isAnyPointInBoxInterior(const Node* node, Alloc& alloc, const Point& lbound, const Point& ubound) { - const Point& point = node->value().point(); + if (node == nullptr) { + return false; + } + + const auto& point = node->value().point(); if (isPointInBoxInterior(point, lbound, ubound)) { return true; @@ -78,23 +76,8 @@ class PointInBoxInteriorFinder { const size_t axis = node->axis(); - if (lbound.x(axis) < point.x(axis)) { - if (Node* left = node->left(alloc)) { - if (isAnyPointInBoxInterior(left, alloc, lbound, ubound)) { - return true; - } - } - } - - if (ubound.x(axis) > point.x(axis)) { - if (Node* right = node->right(alloc)) { - if (isAnyPointInBoxInterior(right, alloc, lbound, ubound)) { - return true; - } - } - } - - return false; + return (lbound.x(axis) < point.x(axis) && isAnyPointInBoxInterior(node->left(alloc), alloc, lbound, ubound)) || + (ubound.x(axis) > point.x(axis) && isAnyPointInBoxInterior(node->right(alloc), alloc, lbound, ubound)); } /// \brief Returns true if \p point is in the interior of the axis-aligned box @@ -122,177 +105,120 @@ bool isAnyPointInBoxInterior(const KDTreeX& tree, //---------------------------------------------------------------------------------------------------------------------- -CASE("test_eckit_container_kdtree_constructor") { - typedef KDTreeMemory Tree; +#define EXPECT_POINT_EQUAL(a, b) \ + for (size_t i = 0; i < Point::dimensions(); ++i) { \ + EXPECT(a.x(i) == b.x(i)); \ + } - Tree kd; + +CASE("test_eckit_container_kdtree_constructor") { + using Tree = KDTreeMemory; using Point = Tree::PointType; + // build k-d tree (offline) + Tree kd; std::vector points; - - // test it for single closest point - - for (unsigned int i = 0; i < 10; i++) { - for (unsigned int j = 0; j < 10; j++) { - Point p = Point(double(i), double(j)); - Tree::Value v(p, 99.9); - points.push_back(v); + for (size_t i = 0; i < 10; ++i) { + for (size_t j = 0; j < 10; ++j) { + points.emplace_back(Point{static_cast(i), static_cast(j)}, 99.9); } } - kd.build(points.begin(), points.end()); - // pick some point from the vector - Point refPoint = points[points.size() / 2].point(); - - // perturb it a little - Point delta(0.1, 0.1); - Point testPoint = Point::add(refPoint, delta); - Log::info() << "testPoint perturb " << testPoint.x(0) << ", " << testPoint.x(1) << std::endl; - - Point nr = kd.nearestNeighbour(testPoint).point(); + // size + EXPECT_EQUAL(kd.size(), points.size()); - // we should find the same point - for (unsigned int i = 0; i < Point::dimensions(); i++) { - EXPECT(nr.x(i) == refPoint.x(i)); - } + // pick a point + auto ref = points[points.size() / 2].point(); - // test exact match to a point + SECTION("test single closest point") { + // a point similar to an existing one + EXPECT_POINT_EQUAL(ref, kd.nearestNeighbour(Point::add(ref, Point{0.1, 0.1})).point()); - nr = kd.nearestNeighbour(refPoint).point(); - for (unsigned int i = 0; i < Point::dimensions(); i++) { - EXPECT(nr.x(i) == refPoint.x(i)); - } + // exact match to a point + EXPECT_POINT_EQUAL(ref, kd.nearestNeighbour(ref).point()); - // test "off the scale" - i.e. not within a group of points - delta = Point(1000.0, 0.0); - // add it to the last point - testPoint = Point::add(points.back().point(), delta); - nr = kd.nearestNeighbour(testPoint).point(); + // off the scale, i.e. not within a group of points (+) + EXPECT_POINT_EQUAL(points.back().point(), + kd.nearestNeighbour(Point::add(points.back().point(), Point{1000., 0.})).point()); - for (unsigned int i = 0; i < Point::dimensions(); i++) { - EXPECT(nr.x(i) == points.back().point().x(i)); + // off the scale, i.e. not within a group of points (-) + EXPECT_POINT_EQUAL(points.front().point(), + kd.nearestNeighbour(Point::add(points.front().point(), Point{-1000., 0.})).point()); } - // and negatively - // - delta = Point(-1000.0, 0.0); - // add it to the point() point - testPoint = Point::add(points.front().point(), delta); - nr = kd.nearestNeighbour(testPoint).point(); + SECTION("test N nearest") { + // move this point so it lies between four equally, make sure we differ by 0.5 along each axis + auto test = Point::add(ref, Point{0.5, 0.5}); - for (unsigned int i = 0; i < Point::dimensions(); i++) { - EXPECT(nr.x(i) == points.front().point().x(i)); - } - - // test N nearest - refPoint = points[points.size() / 2].point(); - // move this point so it lies between four equally - delta = Point(0.5, 0.5); - testPoint = Point::add(refPoint, delta); - - Tree::NodeList nn = kd.kNearestNeighbours(testPoint, 4); - for (Tree::NodeList::iterator it = nn.begin(); it != nn.end(); ++it) { - Point diff = Point::sub(it->point(), testPoint); - // make sure we differ by 0.5 along each axis - for (unsigned int i = 0; i < Point::dimensions(); ++i) { - Log::info() << "distance along point " << Point::distance(Point(0.0, 0.0), diff, i) << std::endl; - EXPECT(Point::distance(Point(0.0, 0.0), diff, i) == 0.5); + for (auto& near : kd.kNearestNeighbours(test, 4)) { + auto diff = Point::sub(near.point(), test); + for (size_t i = 0; i < Point::dimensions(); ++i) { + EXPECT(Point::distance(Point{0., 0.}, diff, i) == 0.5); + } } } - // Test a custom visitor. The purpose of doing that in this test is to ensure that the public - // interface of KDTree is sufficient to write a custom class traversing the tree. - delta = Point(0.25, 0.25); - Point lbound = Point::sub(refPoint, delta); - Point ubound = Point::add(refPoint, delta); - EXPECT(isAnyPointInBoxInterior(kd, lbound, ubound)); - - delta = Point(0.5, 0.5); - lbound = Point::add(lbound, delta); - ubound = Point::add(ubound, delta); - EXPECT_NOT(isAnyPointInBoxInterior(kd, lbound, ubound)); - - // Test size() - EXPECT_EQUAL(kd.size(), points.size()); + SECTION("test a custom visitor") { + // Test a custom visitor. The purpose of doing that in this test is to ensure that the public + // interface of KDTree is sufficient to write a custom class traversing the tree. + auto a = Point{0.25, 0.25}; + auto lbound = Point::sub(ref, a); + auto ubound = Point::add(ref, a); + EXPECT(isAnyPointInBoxInterior(kd, lbound, ubound)); + + auto b = Point{0.5, 0.5}; + lbound = Point::add(lbound, b); + ubound = Point::add(ubound, b); + EXPECT_NOT(isAnyPointInBoxInterior(kd, lbound, ubound)); + } } CASE("test_eckit_container_kdtree_insert") { - typedef KDTreeMemory Tree; + using Tree = KDTreeMemory; + using Point = Tree::PointType; + // build k-d tree (online) Tree kd; - typedef Tree::PointType Point; - std::vector points; - - // test it for single closest point - - for (unsigned int i = 0; i < 10; i++) { - for (unsigned int j = 0; j < 10; j++) { - Point p = Point(double(i), double(j)); - Tree::Value v(p, 99.9); - points.push_back(v); - kd.insert(v); + for (size_t i = 0; i < 10; ++i) { + for (size_t j = 0; j < 10; ++j) { + points.emplace_back(Point{static_cast(i), static_cast(j)}, 99.9); + kd.insert(points.back()); } } + // size + EXPECT_EQUAL(kd.size(), points.size()); - // pick some point from the vector - Point refPoint = points[points.size() / 2].point(); - - // perturb it a little - Point delta(0.1, 0.1); - Point testPoint = Point::add(refPoint, delta); - Log::info() << "testPoint perturb " << testPoint.x(0) << ", " << testPoint.x(1) << std::endl; - - Point nr = kd.nearestNeighbour(testPoint).point(); - - // we should find the same point - for (unsigned int i = 0; i < Point::dimensions(); i++) { - EXPECT(nr.x(i) == refPoint.x(i)); - } + // pick a point + auto ref = points[points.size() / 2].point(); - // test exact match to a point + SECTION("test single closest point") { + // a point similar to an existing one + EXPECT_POINT_EQUAL(ref, kd.nearestNeighbour(Point::add(ref, Point{0.1, 0.1})).point()); - nr = kd.nearestNeighbour(refPoint).point(); - for (unsigned int i = 0; i < Point::dimensions(); i++) { - EXPECT(nr.x(i) == refPoint.x(i)); - } + // exact match to a point + EXPECT_POINT_EQUAL(ref, kd.nearestNeighbour(ref).point()); - // test "off the scale" - i.e. not within a group of points - delta = Point(1000.0, 0.0); - // add it to the last point - testPoint = Point::add(points.back().point(), delta); - nr = kd.nearestNeighbour(testPoint).point(); + // off the scale, i.e. not within a group of points (+) + EXPECT_POINT_EQUAL(points.back().point(), + kd.nearestNeighbour(Point::add(points.back().point(), Point{1000., 0.})).point()); - for (unsigned int i = 0; i < Point::dimensions(); i++) { - EXPECT(nr.x(i) == points.back().point().x(i)); + // off the scale, i.e. not within a group of points (-) + EXPECT_POINT_EQUAL(points.front().point(), + kd.nearestNeighbour(Point::add(points.front().point(), Point{-1000., 0.})).point()); } - // and negatively - // - delta = Point(-1000.0, 0.0); - // add it to the point() point - testPoint = Point::add(points.front().point(), delta); - nr = kd.nearestNeighbour(testPoint).point(); + SECTION("test N nearest") { + // move this point so it lies between four equally, make sure we differ by 0.5 along each axis + auto test = Point::add(ref, Point{0.5, 0.5}); - for (unsigned int i = 0; i < Point::dimensions(); i++) { - EXPECT(nr.x(i) == points.front().point().x(i)); - } - - // test N nearest - refPoint = points[points.size() / 2].point(); - // move this point so it lies between four equally - delta = Point(0.5, 0.5); - testPoint = Point::add(refPoint, delta); - - Tree::NodeList nn = kd.kNearestNeighbours(testPoint, 4); - for (Tree::NodeList::iterator it = nn.begin(); it != nn.end(); ++it) { - Point diff = Point::sub(it->point(), testPoint); - // make sure we differ by 0.5 along each axis - for (unsigned int i = 0; i < Point::dimensions(); ++i) { - Log::info() << "distance along point " << Point::distance(Point(0.0, 0.0), diff, i) << std::endl; - EXPECT(Point::distance(Point(0.0, 0.0), diff, i) == 0.5); + for (auto& near : kd.kNearestNeighbours(test, 4)) { + auto diff = Point::sub(near.point(), test); + for (size_t i = 0; i < Point::dimensions(); ++i) { + EXPECT(Point::distance(Point{0., 0.}, diff, i) == 0.5); + } } } } @@ -300,27 +226,23 @@ CASE("test_eckit_container_kdtree_insert") { CASE("test_kdtree_mapped") { using Tree = KDTreeMapped; using Point = Tree::PointType; + std::vector points; - for (unsigned int i = 0; i < 10; i++) { - for (unsigned int j = 0; j < 10; j++) { - Point p = Point(double(i), double(j)); - Tree::Value v(p, 99.9); - points.push_back(v); + for (size_t i = 0; i < 10; ++i) { + for (size_t j = 0; j < 10; ++j) { + points.emplace_back(Point{static_cast(i), static_cast(j)}, 99.9); } } - auto passTest = [&](Tree& kd) -> bool { - // pick some point from the vector - Point refPoint = points[points.size() / 2].point(); - // perturb it a little - Point delta(0.1, 0.1); - Point testPoint = Point::add(refPoint, delta); - - Point nr = kd.nearestNeighbour(testPoint).point(); + // pick a point + auto ref = points[points.size() / 2].point(); + auto passTest = [&](Tree& kd, const Point& p) -> bool { + // perturb it a little // we should find the same point - for (unsigned int i = 0; i < Point::dimensions(); i++) { - if (nr.x(i) != refPoint.x(i)) { + auto nr = kd.nearestNeighbour(Point::add(p, Point{0.1, 0.1})).point(); + for (size_t i = 0; i < Point::dimensions(); ++i) { + if (nr.x(i) != p.x(i)) { return false; } } @@ -329,19 +251,22 @@ CASE("test_kdtree_mapped") { PathName path("test_kdtree_mapped.kdtree"); - // Write file with kdtree + // Write file with k-d tree { if (path.exists()) { path.unlink(); } + Tree kd(path, points.size(), 0); EXPECT_EQUAL(kd.size(), 0); + kd.build(points); + EXPECT_EQUAL(kd.size(), points.size()); - EXPECT(passTest(kd)); + EXPECT(passTest(kd, ref)); } - // Load file with kdtree + // Load file with k-d tree { Tree kd(path, 0, 0); @@ -352,19 +277,20 @@ CASE("test_kdtree_mapped") { EXPECT_THROWS_AS(kd.build(points), AssertionFailed); EXPECT_EQUAL(kd.size(), points.size()); - EXPECT(passTest(kd)); + EXPECT(passTest(kd, ref)); } } CASE("test_kdtree_iterate_empty") { using Tree = KDTreeMemory; + size_t count = 0; Tree kd; - size_t count{0}; for (auto& item : kd) { count++; } EXPECT_EQUAL(count, 0); + EXPECT_EQUAL(kd.size(), 0); } //---------------------------------------------------------------------------------------------------------------------- From 856abb3f437757dada47bde95182415e2d31771a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 Nov 2023 16:45:47 +0000 Subject: [PATCH 378/737] eckit::geo Grid --- src/eckit/geo/Grid.cc | 5 ----- src/eckit/geo/Grid.h | 1 - 2 files changed, 6 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 4a087ef53..c32db4312 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -41,11 +41,6 @@ const area::BoundingBox& Grid::boundingBox() const { } -void Grid::boundingBox(const area::BoundingBox& bbox) { - bbox_ = bbox; -} - - size_t Grid::size() const { throw NotImplemented("Grid::size", Here()); } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 36ac5a9dd..135912a5b 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -111,7 +111,6 @@ class Grid { virtual iterator cend() const = 0; virtual const area::BoundingBox& boundingBox() const; - void boundingBox(const area::BoundingBox&); virtual size_t size() const; virtual uid_t uid() const; From 8e7d66d843c0993cf974a760c81c8c22e662279b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 Nov 2023 16:45:55 +0000 Subject: [PATCH 379/737] eckit::geo Grid --- src/eckit/geo/grid/regular/RegularLL.cc | 23 ++++++++++++++++++----- src/eckit/geo/grid/regular/RegularLL.h | 2 +- tests/geo/grid_regular_ll.cc | 6 ++++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index 9a8795053..1045f9476 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -37,7 +37,7 @@ struct DiscreteRange { DiscreteRange(Fraction{_a}, Fraction{_b}, Fraction{_inc}, Fraction{_ref}, Fraction{period}) {} DiscreteRange(const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref) : - inc(_inc) { + inc(_inc), periodic(false) { ASSERT(_a <= _b); ASSERT(_inc >= 0); @@ -89,15 +89,31 @@ struct DiscreteRange { b = a + (n - 1) * inc; } + + if (n * inc == period) { + periodic = true; + b = a + n * inc; + } } Fraction a; Fraction b; Fraction inc; size_t n; + bool periodic; }; +PointLonLat make_reference_from_config(const Configuration& config) { + if (double lon = 0, lat = 0; config.get("reference_lon", lon) && config.get("reference_lat", lat)) { + return {lon, lat}; + } + + area::BoundingBox area(config); + return {area.west, area.south}; +} + + } // namespace @@ -117,10 +133,7 @@ RegularLL::Internal::Internal(const Increments& _inc, const area::BoundingBox& _ RegularLL::RegularLL(const Configuration& config) : - RegularLL(Increments{config}, - area::BoundingBox{config}, - PointLonLat{config.getDouble("reference_lon", config.getDouble("west", 0)), - config.getDouble("reference_lat", config.getDouble("south", -90))}) {} + RegularLL(Increments{config}, area::BoundingBox{config}, make_reference_from_config(config)) {} RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : diff --git a/src/eckit/geo/grid/regular/RegularLL.h b/src/eckit/geo/grid/regular/RegularLL.h index e2eae4f6a..c13545563 100644 --- a/src/eckit/geo/grid/regular/RegularLL.h +++ b/src/eckit/geo/grid/regular/RegularLL.h @@ -31,7 +31,7 @@ class RegularLL final : public Regular { // -- Types struct Internal { - Internal(const Increments& _inc, const area::BoundingBox& _bbox, const PointLonLat& _ref); + Internal(const Increments&, const area::BoundingBox&, const PointLonLat& _ref); Increments inc; area::BoundingBox bbox; diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index 65e9bab2a..201f8e07f 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -35,6 +35,12 @@ CASE("") { size_t local_size = local->size(); EXPECT_EQUAL(local_size, 5 * 10); + + std::unique_ptr almost_global(new grid::regular::RegularLL(MappedConfiguration{ + {{"grid", std::vector{1, 1}}, {"area", std::vector{89.5, 0., -89.5, 359.1}}}})); + + size_t almost_global_size = almost_global->size(); + EXPECT_EQUAL(almost_global_size, 360 * 180); } From bd5601327420dbd119527c1a2177ed4ee4eb2a67 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 Nov 2023 16:44:36 +0000 Subject: [PATCH 380/737] eckit::geo triangulation --- CMakeLists.txt | 11 +++-- src/tools/CMakeLists.txt | 6 +++ src/tools/eckit-grid-triangulation.cc | 60 +++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 src/tools/eckit-grid-triangulation.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 1787b6137..1412ce4f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,22 +143,25 @@ ecbuild_add_option( FEATURE AEC ecbuild_add_option( FEATURE XXHASH DESCRIPTION "xxHash support for hashing" ) -### Codec options +### eckit::codec ecbuild_add_option( FEATURE ECKIT_CODEC DEFAULT OFF - DESCRIPTION "Encoding/Decoding library ported from atlas_io" ) + DESCRIPTION "eckit::codec encoding/decoding library" ) set( eckit_CODEC_STATIC_ASSERT ON CACHE BOOL "eckit::codec static assertions" ) -### eckit::geo options +### eckit::geo ecbuild_add_option( FEATURE GEO_CACHING CONDITION HAVE_EXPERIMENTAL DEFAULT OFF DESCRIPTION "eckit::geo default caching behaviour" ) -set( eckit_GEO_CACHE_PATH "/tmp/cache" ) +if( HAVE_EXPERIMENTAL ) + set( eckit_GEO_CACHE_PATH "/tmp/cache" ) + find_package( Qhull COMPONENTS C CXX ) +endif() ### LAPACK diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 87b5b09bd..ed83b4dc5 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -28,6 +28,12 @@ ecbuild_add_executable( TARGET eckit_grid_list SOURCES eckit-grid-list.cc LIBS eckit_geo eckit_option ) +ecbuild_add_executable( TARGET eckit_grid_triangulation + OUTPUT_NAME eckit-grid-triangulation + CONDITION HAVE_BUILD_TOOLS AND HAVE_EXPERIMENTAL AND Qhull_FOUND + SOURCES eckit-grid-triangulation.cc + LIBS eckit_geo eckit_option Qhull::Qhull ) + ### NOT TO INSTALL ecbuild_add_executable( TARGET dhcopy diff --git a/src/tools/eckit-grid-triangulation.cc b/src/tools/eckit-grid-triangulation.cc new file mode 100644 index 000000000..dbf9ddc60 --- /dev/null +++ b/src/tools/eckit-grid-triangulation.cc @@ -0,0 +1,60 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/config/MappedConfiguration.h" +#include "eckit/geo/Grid.h" +#include "eckit/log/Log.h" +#include "eckit/option/CmdArgs.h" +#include "eckit/option/EckitTool.h" +#include "eckit/option/SimpleOption.h" +#include "eckit/exception/Exceptions.h" + + +namespace eckit::tools { + + +struct EckitGridTriangulation final : EckitTool { + EckitGridTriangulation(int argc, char** argv) : + EckitTool(argc, argv) { + options_.push_back(new option::SimpleOption("grid", "grid name")); + } + + void execute(const option::CmdArgs&) override; + + void usage(const std::string& tool) const override { + Log::info() << "\n" + "Usage: " + << tool << "--grid=O32" << std::endl; + } +}; + + +void EckitGridTriangulation::execute(const option::CmdArgs& args) { + std::unique_ptr grid( + geo::GridFactory::build(MappedConfiguration{{{"grid", args.getString("grid")}}})); + + Log::info() << grid << std::endl; + + auto [lon, lat] = grid->to_latlon(); + ASSERT(lon.size() == lat.size()); + + // TODO +} + + +} // namespace eckit::tools + + +int main(int argc, char** argv) { + eckit::tools::EckitGridTriangulation app(argc, argv); + return app.start(); +} From b1497cdc3c9f36c864ddcb0e7e7391fa5b0a8082 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 Nov 2023 17:20:16 +0000 Subject: [PATCH 381/737] eckit::geo triangulation --- src/tools/eckit-grid-triangulation.cc | 75 ++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 6 deletions(-) diff --git a/src/tools/eckit-grid-triangulation.cc b/src/tools/eckit-grid-triangulation.cc index dbf9ddc60..b6cc6f98a 100644 --- a/src/tools/eckit-grid-triangulation.cc +++ b/src/tools/eckit-grid-triangulation.cc @@ -8,20 +8,82 @@ * does it submit to any jurisdiction. */ + +#include #include +#include +#include +#include #include "eckit/config/MappedConfiguration.h" +#include "eckit/exception/Exceptions.h" #include "eckit/geo/Grid.h" +#include "eckit/geo/projection/LonLatToXYZ.h" #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" #include "eckit/option/EckitTool.h" #include "eckit/option/SimpleOption.h" -#include "eckit/exception/Exceptions.h" + +#include "libqhullcpp/Qhull.h" +#include "libqhullcpp/QhullFacet.h" +#include "libqhullcpp/QhullFacetList.h" +#include "libqhullcpp/QhullPoints.h" +#include "libqhullcpp/QhullVertexSet.h" namespace eckit::tools { +struct Triangulation { + using triangle_type = std::array; + + size_t n_triangles() const { + ASSERT(qhull_); + return static_cast(qhull_->facetCount()); + } + + std::vector triangles() const { + ASSERT(qhull_); + + std::vector tri; + tri.reserve(qhull_->facetCount()); + + for (const auto& facet : qhull_->facetList()) { + auto vertices = facet.vertices(); + ASSERT(vertices.size() == 3); + + tri.emplace_back(triangle_type{vertices[0].id(), vertices[1].id(), vertices[2].id()}); + } + + return tri; + } + +protected: + std::unique_ptr qhull_; +}; + + +struct Triangulation3D : Triangulation { + Triangulation3D(const std::vector& lon, const std::vector& lat) { + ASSERT(lon.size() == lat.size()); + + auto N = static_cast(lon.size()); + std::vector coord(N * 3); + + geo::projection::LonLatToXYZ lonlat2xyz(1.); + for (size_t i = 0; i < N; ++i) { + auto p = lonlat2xyz.fwd({lon[i], lat[i]}); + + coord[i * 3 + 0] = p.X; + coord[i * 3 + 1] = p.Y; + coord[i * 3 + 2] = p.Z; + } + + qhull_ = std::make_unique("", 3, N, coord.data(), "Qt"); + } +}; + + struct EckitGridTriangulation final : EckitTool { EckitGridTriangulation(int argc, char** argv) : EckitTool(argc, argv) { @@ -42,13 +104,14 @@ void EckitGridTriangulation::execute(const option::CmdArgs& args) { std::unique_ptr grid( geo::GridFactory::build(MappedConfiguration{{{"grid", args.getString("grid")}}})); - Log::info() << grid << std::endl; - - auto [lon, lat] = grid->to_latlon(); + auto [lat, lon] = grid->to_latlon(); ASSERT(lon.size() == lat.size()); - // TODO -} + std::unique_ptr tri(new Triangulation3D(lon, lat)); + for (const auto& t : tri->triangles()) { + Log::info() << t[0] << ' ' << t[1] << ' ' << t[2] << std::endl; + } +}; } // namespace eckit::tools From d84307886bd8e8ef2c9ea873e1b8fe7e59e7fd23 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 Nov 2023 23:27:42 +0000 Subject: [PATCH 382/737] eckit::geo Grid --- src/eckit/geo/Increments.h | 4 +++- src/eckit/geo/area/BoundingBox.cc | 6 +++++- src/eckit/geo/area/BoundingBox.h | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/eckit/geo/Increments.h b/src/eckit/geo/Increments.h index 37fe6345f..ed229ea1b 100644 --- a/src/eckit/geo/Increments.h +++ b/src/eckit/geo/Increments.h @@ -34,13 +34,15 @@ class Increments : protected std::array { explicit Increments(const Configuration&); Increments(double west_east, double south_north); + Increments() : Increments(0, 0) {} Increments(const Increments& other) : array(other) {} - Increments(Increments&&) = default; + Increments(Increments&& other) : + array(other) {} // -- Destructor diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 37318a2fa..dc93cd13f 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -41,7 +41,11 @@ static BoundingBox make_from_config(const Configuration& config) { return {area[0], area[1], area[2], area[3]}; } - throw UserError("BoundingBox: expecting 'area'=N/W/S/E or ('north', 'west', 'south', 'east')"); + if (!config.has("north") && !config.has("west") && !config.has("south") && !config.has("east")) { + return {}; + } + + throw UserError("BoundingBox: expecting 'area'=north/west/south/east or ('north', 'west', 'south', 'east')"); } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 346a345f2..0f7b1f7d5 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -36,12 +36,14 @@ class BoundingBox : public Area, protected std::array { explicit BoundingBox(const Configuration&); BoundingBox(double north, double west, double south, double east); + BoundingBox(); BoundingBox(const BoundingBox& other) : array(other) {} - BoundingBox(BoundingBox&&) = default; + BoundingBox(BoundingBox&& other) : + array(other) {} // -- Destructor From dd5bab2c3d1192952e6605b136c0182dd4323b50 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 25 Nov 2023 01:04:21 +0000 Subject: [PATCH 383/737] eckit::geo Grid --- src/eckit/geo/grid/Reduced.cc | 41 +++++++++++++++++++++++++++++++++++ src/eckit/geo/grid/Reduced.h | 2 ++ 2 files changed, 43 insertions(+) diff --git a/src/eckit/geo/grid/Reduced.cc b/src/eckit/geo/grid/Reduced.cc index a5d6c97c3..74bb6b4e0 100644 --- a/src/eckit/geo/grid/Reduced.cc +++ b/src/eckit/geo/grid/Reduced.cc @@ -23,6 +23,47 @@ size_t Reduced::size() const { } +std::vector Reduced::to_points() const { + std::vector points; + points.reserve(size()); + + const auto& lats = latitudes(); + ASSERT(lats.size() == nj()); + + for (size_t j = 0; j < nj(); ++j) { + const auto lons = longitudes(j); + ASSERT(lons.size() == ni(j)); + + const auto lat = lats.at(j); + for (auto lon : lons) { + points.emplace_back(PointLonLat{lon, lat}); + } + } + + return points; +} + + +std::pair, std::vector > Reduced::to_latlon() const { + std::vector lat; + std::vector lon; + lat.reserve(size()); + lon.reserve(size()); + + const auto& lats = latitudes(); + ASSERT(lats.size() == nj()); + + for (size_t j = 0; j < nj(); ++j) { + const auto lons = longitudes(j); + + lat.insert(lat.end(), lons.size(), lats.at(j)); + lon.insert(lon.end(), lons.begin(), lons.end()); + } + + return {lat, lon}; +} + + Reduced::Reduced(const Configuration& config) : Grid(config) {} diff --git a/src/eckit/geo/grid/Reduced.h b/src/eckit/geo/grid/Reduced.h index 5a7f6eb19..759cfeed5 100644 --- a/src/eckit/geo/grid/Reduced.h +++ b/src/eckit/geo/grid/Reduced.h @@ -50,6 +50,8 @@ class Reduced : public Grid { // -- Overridden methods size_t size() const override; + std::vector to_points() const override; + std::pair, std::vector> to_latlon() const override; // -- Class members // None From 62ff24693f0a4a54d24d5c0f04cb33350c657a1b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 5 Dec 2023 11:54:55 +0000 Subject: [PATCH 384/737] eckit::geo triangulation --- src/eckit/geo/CMakeLists.txt | 7 ++ src/eckit/geo/Triangulation.cc | 0 src/eckit/geo/Triangulation.h | 70 +++++++++++++++ src/eckit/geo/triangulation/Triangulation3.cc | 57 ++++++++++++ src/eckit/geo/triangulation/Triangulation3.h | 31 +++++++ src/tools/eckit-grid-triangulation.cc | 89 ++++++------------- 6 files changed, 191 insertions(+), 63 deletions(-) create mode 100644 src/eckit/geo/Triangulation.cc create mode 100644 src/eckit/geo/Triangulation.h create mode 100644 src/eckit/geo/triangulation/Triangulation3.cc create mode 100644 src/eckit/geo/triangulation/Triangulation3.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index cf52e2db5..cbf2de0a4 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -50,6 +50,8 @@ list(APPEND eckit_geo_srcs Sphere.cc Sphere.h SphereT.h + Triangulation.cc + Triangulation.h UnitSphere.h area/BoundingBox.cc area/BoundingBox.h @@ -140,3 +142,8 @@ if(HAVE_CODEC) target_link_libraries(eckit_geo PUBLIC eckit_codec) endif() +if(Qhull_FOUND) + target_sources(eckit_geo PRIVATE triangulation/Triangulation3.cc triangulation/Triangulation3.h) + target_link_libraries(eckit_geo PUBLIC Qhull::Qhull) +endif() + diff --git a/src/eckit/geo/Triangulation.cc b/src/eckit/geo/Triangulation.cc new file mode 100644 index 000000000..e69de29bb diff --git a/src/eckit/geo/Triangulation.h b/src/eckit/geo/Triangulation.h new file mode 100644 index 000000000..610cc5aad --- /dev/null +++ b/src/eckit/geo/Triangulation.h @@ -0,0 +1,70 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "eckit/memory/Builder.h" +#include "eckit/memory/Factory.h" + + +namespace eckit { +class Configuration; +} // namespace eckit + + +namespace eckit::geo { + + +using Triangle = std::array; + + +class Triangulation : protected std::vector { +public: + // -- Types + + using builder_t = BuilderT1; + using ARG1 = const Configuration&; + + // -- Destructor + + virtual ~Triangulation() = default; + + // -- Operators + + using vector::operator[]; + + // -- Methods + + static std::string className() { return "Triangulation"; } + + using vector::at; + using vector::size; + + using vector::begin; + using vector::cbegin; + using vector::cend; + using vector::end; + +protected: + // -- Constructors + + Triangulation() /*noexcept */ = default; +}; + + +using TriangulationFactory = Factory; + +template +using TriangulationBuilder = ConcreteBuilderT1; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/triangulation/Triangulation3.cc b/src/eckit/geo/triangulation/Triangulation3.cc new file mode 100644 index 000000000..0f82b7e2c --- /dev/null +++ b/src/eckit/geo/triangulation/Triangulation3.cc @@ -0,0 +1,57 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/triangulation/Triangulation3.h" + +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/Grid.h" +#include "eckit/geo/projection/LonLatToXYZ.h" + +#include "libqhullcpp/Qhull.h" +#include "libqhullcpp/QhullFacetList.h" +#include "libqhullcpp/QhullVertexSet.h" + + +namespace eckit::geo::triangulation { + + +Triangulation3::Triangulation3(const Grid& grid) { + auto [lat, lon] = grid.to_latlon(); + ASSERT(lat.size() == lon.size()); + + auto N = static_cast(lon.size()); + std::vector coord(N * 3); + + geo::projection::LonLatToXYZ lonlat2xyz(1.); + for (size_t i = 0; i < N; ++i) { + auto p = lonlat2xyz.fwd({lon[i], lat[i]}); + + coord[i * 3 + 0] = p.X; + coord[i * 3 + 1] = p.Y; + coord[i * 3 + 2] = p.Z; + } + + auto qh = std::make_unique("", 3, N, coord.data(), "Qt"); + + reserve(qh->facetCount()); + for (const auto& facet : qh->facetList()) { + auto vertices = facet.vertices(); + ASSERT(vertices.size() == 3); + emplace_back(Triangle{static_cast(vertices[0].id()), + static_cast(vertices[1].id()), + static_cast(vertices[2].id())}); + } +} + + +} // namespace eckit::geo::triangulation diff --git a/src/eckit/geo/triangulation/Triangulation3.h b/src/eckit/geo/triangulation/Triangulation3.h new file mode 100644 index 000000000..71a2a8191 --- /dev/null +++ b/src/eckit/geo/triangulation/Triangulation3.h @@ -0,0 +1,31 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Triangulation.h" + + +namespace eckit::geo { +class Grid; +} // namespace eckit::geo + + +namespace eckit::geo::triangulation { + + +class Triangulation3 : public Triangulation { +public: + explicit Triangulation3(const Grid&); +}; + + +} // namespace eckit::geo::triangulation diff --git a/src/tools/eckit-grid-triangulation.cc b/src/tools/eckit-grid-triangulation.cc index b6cc6f98a..143d4e1d3 100644 --- a/src/tools/eckit-grid-triangulation.cc +++ b/src/tools/eckit-grid-triangulation.cc @@ -9,81 +9,23 @@ */ -#include #include #include -#include -#include #include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/Grid.h" #include "eckit/geo/projection/LonLatToXYZ.h" +#include "eckit/geo/triangulation/Triangulation3.h" #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" #include "eckit/option/EckitTool.h" #include "eckit/option/SimpleOption.h" -#include "libqhullcpp/Qhull.h" -#include "libqhullcpp/QhullFacet.h" -#include "libqhullcpp/QhullFacetList.h" -#include "libqhullcpp/QhullPoints.h" -#include "libqhullcpp/QhullVertexSet.h" - namespace eckit::tools { -struct Triangulation { - using triangle_type = std::array; - - size_t n_triangles() const { - ASSERT(qhull_); - return static_cast(qhull_->facetCount()); - } - - std::vector triangles() const { - ASSERT(qhull_); - - std::vector tri; - tri.reserve(qhull_->facetCount()); - - for (const auto& facet : qhull_->facetList()) { - auto vertices = facet.vertices(); - ASSERT(vertices.size() == 3); - - tri.emplace_back(triangle_type{vertices[0].id(), vertices[1].id(), vertices[2].id()}); - } - - return tri; - } - -protected: - std::unique_ptr qhull_; -}; - - -struct Triangulation3D : Triangulation { - Triangulation3D(const std::vector& lon, const std::vector& lat) { - ASSERT(lon.size() == lat.size()); - - auto N = static_cast(lon.size()); - std::vector coord(N * 3); - - geo::projection::LonLatToXYZ lonlat2xyz(1.); - for (size_t i = 0; i < N; ++i) { - auto p = lonlat2xyz.fwd({lon[i], lat[i]}); - - coord[i * 3 + 0] = p.X; - coord[i * 3 + 1] = p.Y; - coord[i * 3 + 2] = p.Z; - } - - qhull_ = std::make_unique("", 3, N, coord.data(), "Qt"); - } -}; - - struct EckitGridTriangulation final : EckitTool { EckitGridTriangulation(int argc, char** argv) : EckitTool(argc, argv) { @@ -104,13 +46,34 @@ void EckitGridTriangulation::execute(const option::CmdArgs& args) { std::unique_ptr grid( geo::GridFactory::build(MappedConfiguration{{{"grid", args.getString("grid")}}})); + auto& out = std::cout; + + geo::triangulation::Triangulation3 tri(*grid); + auto [lat, lon] = grid->to_latlon(); - ASSERT(lon.size() == lat.size()); - std::unique_ptr tri(new Triangulation3D(lon, lat)); - for (const auto& t : tri->triangles()) { - Log::info() << t[0] << ' ' << t[1] << ' ' << t[2] << std::endl; + auto N = grid->size(); + ASSERT(N == lat.size()); + ASSERT(N == lon.size()); + + out << "$MeshFormat\n" + "4.1 0 8\n" + "$EndMeshFormat\n"; + + out << "$Nodes\n" << N << '\n'; + geo::projection::LonLatToXYZ lonlat2xyz(1.); + for (size_t i = 0; i < N; ++i) { + auto p = lonlat2xyz.fwd(geo::PointLonLat{lon[i], lat[i]}); + out << (i + 1) << ' ' << p.X << ' ' << p.Y << ' ' << p.Z << '\n'; + } + out << "$EndNodes\n"; + + out << "$Elements\n" << tri.size() << '\n'; + size_t i = 0; + for (const auto& t : tri) { + out << (i + 1) << " 2 4 1 1 1 0 " << t[0] << ' ' << t[1] << ' ' << t[2] << '\n'; } + out << "$EndElements\n"; }; From 74b3e22e5abc037e641b4c572d2d1af5a19cb935 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 7 Dec 2023 16:01:26 +0000 Subject: [PATCH 385/737] eckit::geo triangulation --- src/eckit/geo/triangulation/Triangulation3.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/eckit/geo/triangulation/Triangulation3.cc b/src/eckit/geo/triangulation/Triangulation3.cc index 0f82b7e2c..4b78c1492 100644 --- a/src/eckit/geo/triangulation/Triangulation3.cc +++ b/src/eckit/geo/triangulation/Triangulation3.cc @@ -47,9 +47,10 @@ Triangulation3::Triangulation3(const Grid& grid) { for (const auto& facet : qh->facetList()) { auto vertices = facet.vertices(); ASSERT(vertices.size() == 3); - emplace_back(Triangle{static_cast(vertices[0].id()), - static_cast(vertices[1].id()), - static_cast(vertices[2].id())}); + + emplace_back(Triangle{static_cast(vertices[0].id()), + static_cast(vertices[1].id()), + static_cast(vertices[2].id())}); } } From a4f7c209bba813a049c3c287830a7147e10e4c1f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 7 Dec 2023 16:01:50 +0000 Subject: [PATCH 386/737] eckit::geo cmake refactor (not experimental anymore) --- CMakeLists.txt | 23 +- src/eckit/CMakeLists.txt | 1280 +++++++++++++-------------- src/eckit/geo/CMakeLists.txt | 35 +- src/eckit/geo/eckit_geo_config.h.in | 16 +- src/eckit/maths/CMakeLists.txt | 2 +- src/tools/CMakeLists.txt | 20 +- tests/CMakeLists.txt | 8 +- 7 files changed, 700 insertions(+), 684 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1412ce4f7..2c881c14c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,16 +153,29 @@ set( eckit_CODEC_STATIC_ASSERT ON CACHE BOOL "eckit::codec static assertions" ) ### eckit::geo +ecbuild_add_option( FEATURE ECKIT_GEO + DEFAULT OFF + DESCRIPTION "eckit::geo geometry library" ) + ecbuild_add_option( FEATURE GEO_CACHING - CONDITION HAVE_EXPERIMENTAL DEFAULT OFF - DESCRIPTION "eckit::geo default caching behaviour" ) + CONDITION HAVE_ECKIT_GEO + DESCRIPTION "eckit::geo geometry library default caching behaviour" ) -if( HAVE_EXPERIMENTAL ) - set( eckit_GEO_CACHE_PATH "/tmp/cache" ) - find_package( Qhull COMPONENTS C CXX ) +ecbuild_add_option( FEATURE GEO_CONVEX_HULL + DEFAULT ON + CONDITION HAVE_ECKIT_GEO + DESCRIPTION "eckit::geo geometry library convex hull/Delaunay triangulation" + REQUIRED_PACKAGES "Qhull COMPONENTS C CXX" ) + +if( eckit_HAVE_GEO_CONVEX_HULL ) + if(NOT Qhull_FOUND OR NOT TARGET Qhull::Qhull) + message(FATAL_ERROR "eckit::geo ENABLE_GEO_CONVEX_HULL requires Qhull C/C++ libraries") + endif() endif() +set( eckit_GEO_CACHE_PATH "/tmp/cache" ) + ### LAPACK if( eckit_HAVE_MKL ) diff --git a/src/eckit/CMakeLists.txt b/src/eckit/CMakeLists.txt index 957f4b55c..77e3bc8e7 100644 --- a/src/eckit/CMakeLists.txt +++ b/src/eckit/CMakeLists.txt @@ -82,246 +82,243 @@ configure_file( eckit_version.cc.in eckit_version.cc ) list( APPEND eckit_srcs eckit.h deprecated.h ${CMAKE_CURRENT_BINARY_DIR}/eckit_version.cc ) list( APPEND eckit_container_srcs - -container/BSPTree.h -container/BTree.cc -container/BTree.h -container/BloomFilter.cc -container/BloomFilter.h -container/Cache.h -container/CacheLRU.cc -container/CacheLRU.h -container/CacheManager.cc -container/CacheManager.h -container/ClassExtent.h -container/DenseMap.h -container/DenseSet.h -container/KDMapped.cc -container/KDMapped.h -container/KDMemory.h -container/KDTree.h -container/MappedArray.cc -container/MappedArray.h -container/Queue.h -container/Recycler.h -container/SharedMemArray.cc -container/SharedMemArray.h -container/StatCollector.h -container/Trie.cc -container/Trie.h -container/bsptree/BSPHyperPlane.h -container/bsptree/BSPNode.cc -container/bsptree/BSPNode.h -container/kdtree/KDNode.cc -container/kdtree/KDNode.cc -container/kdtree/KDNode.h -container/sptree/SPIterator.h -container/sptree/SPMetadata.h -container/sptree/SPNode.h -container/sptree/SPNodeInfo.h -container/sptree/SPNodeQueue.h -container/sptree/SPTree.h -container/sptree/SPValue.h + container/BSPTree.h + container/BTree.cc + container/BTree.h + container/BloomFilter.cc + container/BloomFilter.h + container/Cache.h + container/CacheLRU.cc + container/CacheLRU.h + container/CacheManager.cc + container/CacheManager.h + container/ClassExtent.h + container/DenseMap.h + container/DenseSet.h + container/KDMapped.cc + container/KDMapped.h + container/KDMemory.h + container/KDTree.h + container/MappedArray.cc + container/MappedArray.h + container/Queue.h + container/Recycler.h + container/SharedMemArray.cc + container/SharedMemArray.h + container/StatCollector.h + container/Trie.cc + container/Trie.h + container/bsptree/BSPHyperPlane.h + container/bsptree/BSPNode.cc + container/bsptree/BSPNode.h + container/kdtree/KDNode.cc + container/kdtree/KDNode.h + container/sptree/SPIterator.h + container/sptree/SPMetadata.h + container/sptree/SPNode.h + container/sptree/SPNodeInfo.h + container/sptree/SPNodeQueue.h + container/sptree/SPTree.h + container/sptree/SPValue.h ) list( APPEND eckit_io_srcs -io/AsyncHandle.cc -io/AsyncHandle.h -io/AIOHandle.cc -io/AIOHandle.h -io/AutoCloser.h -io/Base64.cc -io/Base64.h -io/BitIO.cc -io/BitIO.h -io/Buffer.cc -io/Buffer.h -io/BufferCache.cc -io/BufferCache.h -io/BufferList.cc -io/BufferList.h -io/BufferedHandle.cc -io/BufferedHandle.h -io/PeekHandle.cc -io/PeekHandle.h -io/SeekableHandle.cc -io/SeekableHandle.h -io/CircularBuffer.cc -io/CircularBuffer.h -io/CommandStream.cc -io/CommandStream.h -io/Compress.cc -io/Compress.h -io/DataHandle.cc -io/DataHandle.h -io/DblBuffer.cc -io/DblBuffer.h -io/EmptyHandle.cc -io/EmptyHandle.h -io/FDataSync.cc -io/FDataSync.h -io/FTPHandle.cc -io/FTPHandle.h -io/FileBase.cc -io/FileBase.h -io/FileDescHandle.cc -io/FileDescHandle.h -io/FileHandle.cc -io/FileHandle.h -io/FOpenDataHandle.cc -io/MMappedFileHandle.cc -io/MMappedFileHandle.h -io/FileLock.cc -io/FileLock.h -io/FileLocker.cc -io/FileLocker.h -io/FilePool.cc -io/FilePool.h -io/FileHandle.cc -io/FileHandle.h -io/HandleBuf.cc -io/HandleBuf.h -io/HandleHolder.cc -io/HandleHolder.h -io/Length.cc -io/Length.h -io/MemoryHandle.cc -io/MemoryHandle.h -io/MoverTransfer.cc -io/MoverTransfer.h -io/MoverTransferSelection.cc -io/MoverTransferSelection.h -io/MultiHandle.cc -io/MultiHandle.h -io/Offset.cc -io/Offset.h -io/PartFileHandle.cc -io/PartFileHandle.h -io/PartHandle.cc -io/PartHandle.h -io/PipeHandle.cc -io/PipeHandle.h -io/Pipeline.cc -io/Pipeline.h -io/PooledFile.cc -io/PooledFile.h -io/PooledHandle.cc -io/PooledHandle.h -io/PooledFileDescriptor.cc -io/PooledFileDescriptor.h -io/RawFileHandle.cc -io/RawFileHandle.h -io/ResizableBuffer.h -io/Select.cc -io/Select.h -io/SharedBuffer.cc -io/SharedBuffer.h -io/SharedHandle.cc -io/SharedHandle.h -io/SockBuf.cc -io/SockBuf.h -io/StatsHandle.cc -io/StatsHandle.h -io/StdFile.cc -io/StdFile.h -io/StdPipe.cc -io/StdPipe.h -io/StdioBuf.cc -io/StdioBuf.h -io/TCPHandle.cc -io/TCPHandle.h -io/MultiSocketHandle.cc -io/MultiSocketHandle.h -io/TCPSocketHandle.cc -io/TCPSocketHandle.h -io/TeeHandle.cc -io/TeeHandle.h -io/TransferWatcher.cc -io/TransferWatcher.h -io/cluster/ClusterDisks.cc -io/cluster/ClusterDisks.h -io/cluster/ClusterNode.cc -io/cluster/ClusterNode.h -io/cluster/ClusterNodes.cc -io/cluster/ClusterNodes.h -io/cluster/NodeInfo.cc -io/cluster/NodeInfo.h + io/AIOHandle.cc + io/AIOHandle.h + io/AsyncHandle.cc + io/AsyncHandle.h + io/AutoCloser.h + io/Base64.cc + io/Base64.h + io/BitIO.cc + io/BitIO.h + io/Buffer.cc + io/Buffer.h + io/BufferCache.cc + io/BufferCache.h + io/BufferList.cc + io/BufferList.h + io/BufferedHandle.cc + io/BufferedHandle.h + io/CircularBuffer.cc + io/CircularBuffer.h + io/CommandStream.cc + io/CommandStream.h + io/Compress.cc + io/Compress.h + io/DataHandle.cc + io/DataHandle.h + io/DblBuffer.cc + io/DblBuffer.h + io/EmptyHandle.cc + io/EmptyHandle.h + io/FDataSync.cc + io/FDataSync.h + io/FOpenDataHandle.cc + io/FTPHandle.cc + io/FTPHandle.h + io/FileBase.cc + io/FileBase.h + io/FileDescHandle.cc + io/FileDescHandle.h + io/FileHandle.cc + io/FileHandle.h + io/FileLock.cc + io/FileLock.h + io/FileLocker.cc + io/FileLocker.h + io/FilePool.cc + io/FilePool.h + io/HandleBuf.cc + io/HandleBuf.h + io/HandleHolder.cc + io/HandleHolder.h + io/Length.cc + io/Length.h + io/MMappedFileHandle.cc + io/MMappedFileHandle.h + io/MemoryHandle.cc + io/MemoryHandle.h + io/MoverTransfer.cc + io/MoverTransfer.h + io/MoverTransferSelection.cc + io/MoverTransferSelection.h + io/MultiHandle.cc + io/MultiHandle.h + io/MultiSocketHandle.cc + io/MultiSocketHandle.h + io/Offset.cc + io/Offset.h + io/PartFileHandle.cc + io/PartFileHandle.h + io/PartHandle.cc + io/PartHandle.h + io/PeekHandle.cc + io/PeekHandle.h + io/PipeHandle.cc + io/PipeHandle.h + io/Pipeline.cc + io/Pipeline.h + io/PooledFile.cc + io/PooledFile.h + io/PooledFileDescriptor.cc + io/PooledFileDescriptor.h + io/PooledHandle.cc + io/PooledHandle.h + io/RawFileHandle.cc + io/RawFileHandle.h + io/ResizableBuffer.h + io/SeekableHandle.cc + io/SeekableHandle.h + io/Select.cc + io/Select.h + io/SharedBuffer.cc + io/SharedBuffer.h + io/SharedHandle.cc + io/SharedHandle.h + io/SockBuf.cc + io/SockBuf.h + io/StatsHandle.cc + io/StatsHandle.h + io/StdFile.cc + io/StdFile.h + io/StdPipe.cc + io/StdPipe.h + io/StdioBuf.cc + io/StdioBuf.h + io/TCPHandle.cc + io/TCPHandle.h + io/TCPSocketHandle.cc + io/TCPSocketHandle.h + io/TeeHandle.cc + io/TeeHandle.h + io/TransferWatcher.cc + io/TransferWatcher.h + io/cluster/ClusterDisks.cc + io/cluster/ClusterDisks.h + io/cluster/ClusterNode.cc + io/cluster/ClusterNode.h + io/cluster/ClusterNodes.cc + io/cluster/ClusterNodes.h + io/cluster/NodeInfo.cc + io/cluster/NodeInfo.h ) if(HAVE_CURL) -list(APPEND eckit_io_srcs -io/EasyCURL.cc -io/EasyCURL.h -io/URLHandle.cc -io/URLHandle.h) + list(APPEND eckit_io_srcs + io/EasyCURL.cc + io/EasyCURL.h + io/URLHandle.cc + io/URLHandle.h + ) endif() list(APPEND eckit_message_srcs -message/Decoder.cc -message/Decoder.h -message/Message.cc -message/Message.h -message/MessageContent.cc -message/MessageContent.h -message/Reader.cc -message/Reader.h -message/Splitter.cc -message/Splitter.h + message/Decoder.cc + message/Decoder.h + message/Message.cc + message/Message.h + message/MessageContent.cc + message/MessageContent.h + message/Reader.cc + message/Reader.h + message/Splitter.cc + message/Splitter.h ) if(HAVE_RADOS) -list( APPEND eckit_io_srcs -io/rados/RadosHandle.cc -io/rados/RadosHandle.h -io/rados/RadosCluster.h -io/rados/RadosCluster.cc -io/rados/RadosReadHandle.cc -io/rados/RadosReadHandle.h -io/rados/RadosWriteHandle.cc -io/rados/RadosWriteHandle.h -io/rados/RadosObject.h -io/rados/RadosObject.cc -io/rados/RadosAttributes.h -io/rados/RadosAttributes.cc -) + list( APPEND eckit_io_srcs + io/rados/RadosHandle.cc + io/rados/RadosHandle.h + io/rados/RadosCluster.h + io/rados/RadosCluster.cc + io/rados/RadosReadHandle.cc + io/rados/RadosReadHandle.h + io/rados/RadosWriteHandle.cc + io/rados/RadosWriteHandle.h + io/rados/RadosObject.h + io/rados/RadosObject.cc + io/rados/RadosAttributes.h + io/rados/RadosAttributes.cc + ) endif() list( APPEND eckit_filesystem_srcs -filesystem/BasePathName.cc -filesystem/BasePathName.h -filesystem/BasePathNameT.cc -filesystem/BasePathNameT.h -filesystem/FileMode.cc -filesystem/FileMode.h -filesystem/FileSpace.cc -filesystem/FileSpace.h -filesystem/FileSpaceStrategies.cc -filesystem/FileSpaceStrategies.h -filesystem/FileSystem.cc -filesystem/FileSystem.h -filesystem/FileSystemSize.h -filesystem/LocalPathName.cc -filesystem/LocalPathName.h -filesystem/PathExpander.cc -filesystem/PathExpander.h -filesystem/PathName.cc -filesystem/PathName.h -filesystem/PathNameFactory.cc -filesystem/PathNameFactory.h -filesystem/TempFile.cc -filesystem/TempFile.h -filesystem/TmpDir.cc -filesystem/TmpDir.h -filesystem/StdDir.cc -filesystem/StdDir.h -filesystem/TmpFile.cc -filesystem/TmpFile.h -filesystem/URI.cc -filesystem/URI.h -filesystem/URIManager.cc -filesystem/URIManager.h -filesystem/LocalFileManager.cc -filesystem/LocalFileManager.h + filesystem/BasePathName.cc + filesystem/BasePathName.h + filesystem/BasePathNameT.cc + filesystem/BasePathNameT.h + filesystem/FileMode.cc + filesystem/FileMode.h + filesystem/FileSpace.cc + filesystem/FileSpace.h + filesystem/FileSpaceStrategies.cc + filesystem/FileSpaceStrategies.h + filesystem/FileSystem.cc + filesystem/FileSystem.h + filesystem/FileSystemSize.h + filesystem/LocalPathName.cc + filesystem/LocalPathName.h + filesystem/PathExpander.cc + filesystem/PathExpander.h + filesystem/PathName.cc + filesystem/PathName.h + filesystem/PathNameFactory.cc + filesystem/PathNameFactory.h + filesystem/TempFile.cc + filesystem/TempFile.h + filesystem/TmpDir.cc + filesystem/TmpDir.h + filesystem/StdDir.cc + filesystem/StdDir.h + filesystem/TmpFile.cc + filesystem/TmpFile.h + filesystem/URI.cc + filesystem/URI.h + filesystem/URIManager.cc + filesystem/URIManager.h + filesystem/LocalFileManager.cc + filesystem/LocalFileManager.h ) list( APPEND eckit_thread_srcs @@ -343,415 +340,408 @@ list( APPEND eckit_thread_srcs ) list( APPEND eckit_config_srcs -config/Configurable.cc -config/Configurable.h -config/Configuration.cc -config/Configuration.h -config/Configured.cc -config/Configured.h -config/EtcTable.cc -config/EtcTable.h -config/JSONConfiguration.h -config/LibEcKit.cc -config/LibEcKit.h -config/LocalConfiguration.cc -config/LocalConfiguration.h -config/Parametrisation.cc -config/Parametrisation.h -config/Resource.h -config/ResourceBase.cc -config/ResourceBase.h -config/ResourceMgr.cc -config/ResourceMgr.h -config/YAMLConfiguration.cc -config/YAMLConfiguration.h + config/Configurable.cc + config/Configurable.h + config/Configuration.cc + config/Configuration.h + config/Configured.cc + config/Configured.h + config/DynamicConfiguration.cc + config/DynamicConfiguration.h + config/EtcTable.cc + config/EtcTable.h + config/JSONConfiguration.h + config/LibEcKit.cc + config/LibEcKit.h + config/LocalConfiguration.cc + config/LocalConfiguration.h + config/MappedConfiguration.cc + config/MappedConfiguration.h + config/Parametrisation.cc + config/Parametrisation.h + config/Resource.h + config/ResourceBase.cc + config/ResourceBase.h + config/ResourceMgr.cc + config/ResourceMgr.h + config/YAMLConfiguration.cc + config/YAMLConfiguration.h ) -if( HAVE_EXPERIMENTAL ) - list( APPEND eckit_config_srcs - config/DynamicConfiguration.cc - config/DynamicConfiguration.h - config/MappedConfiguration.cc - config/MappedConfiguration.h - ) -endif() - list( APPEND eckit_runtime_srcs -runtime/Application.cc -runtime/Application.h -runtime/Dispatcher.h -runtime/Library.cc -runtime/Library.h -runtime/Main.cc -runtime/Main.h -runtime/Metrics.cc -runtime/Metrics.h -runtime/Monitor.cc -runtime/Monitor.h -runtime/Monitorable.cc -runtime/Monitorable.h -runtime/Pipe.h -runtime/PipeApplication.cc -runtime/PipeApplication.h -runtime/PipeHandler.cc -runtime/PipeHandler.h -runtime/ProcessControler.cc -runtime/ProcessControler.h -runtime/ProducerConsumer.h -runtime/Telemetry.cc -runtime/Telemetry.h -runtime/SessionID.cc -runtime/SessionID.h -runtime/Task.cc -runtime/Task.h -runtime/TaskID.h -runtime/TaskInfo.cc -runtime/TaskInfo.h -runtime/Tool.cc -runtime/Tool.h + runtime/Application.cc + runtime/Application.h + runtime/Dispatcher.h + runtime/Library.cc + runtime/Library.h + runtime/Main.cc + runtime/Main.h + runtime/Metrics.cc + runtime/Metrics.h + runtime/Monitor.cc + runtime/Monitor.h + runtime/Monitorable.cc + runtime/Monitorable.h + runtime/Pipe.h + runtime/PipeApplication.cc + runtime/PipeApplication.h + runtime/PipeHandler.cc + runtime/PipeHandler.h + runtime/ProcessControler.cc + runtime/ProcessControler.h + runtime/ProducerConsumer.h + runtime/Telemetry.cc + runtime/Telemetry.h + runtime/SessionID.cc + runtime/SessionID.h + runtime/Task.cc + runtime/Task.h + runtime/TaskID.h + runtime/TaskInfo.cc + runtime/TaskInfo.h + runtime/Tool.cc + runtime/Tool.h ) list( APPEND eckit_log_srcs -log/BigNum.cc -log/BigNum.h -log/Bytes.cc -log/Bytes.h -log/CallbackTarget.cc -log/CallbackTarget.h -log/Channel.cc -log/Channel.h -log/ChannelBuffer.cc -log/ChannelBuffer.h -log/CodeLocation.cc -log/CodeLocation.h -log/Colour.cc -log/Colour.h -log/ColouringTarget.cc -log/ColouringTarget.h -log/ETA.cc -log/ETA.h -log/FileTarget.cc -log/FileTarget.h -log/IndentTarget.cc -log/IndentTarget.h -log/JSON.cc -log/JSON.h -log/LineBasedTarget.cc -log/LineBasedTarget.h -log/Log.cc -log/Log.h -log/LogTarget.cc -log/LogTarget.h -log/MessageTarget.cc -log/MessageTarget.h -log/MonitorTarget.cc -log/MonitorTarget.h -log/Number.cc -log/Number.h -log/OStreamTarget.cc -log/OStreamTarget.h -log/Plural.h -log/PrefixTarget.cc -log/PrefixTarget.h -log/Progress.cc -log/Progress.h -log/ProgressTimer.cc -log/ProgressTimer.h -log/ResourceUsage.cc -log/ResourceUsage.h -log/RotationTarget.cc -log/RotationTarget.h -log/SavedStatus.cc -log/SavedStatus.h -log/Seconds.cc -log/Seconds.h -log/Statistics.cc -log/Statistics.h -log/StatusTarget.cc -log/StatusTarget.h -log/SysLog.cc -log/SysLog.h -log/TeeTarget.cc -log/TeeTarget.h -log/TimeStamp.cc -log/TimeStamp.h -log/TimeStampTarget.cc -log/TimeStampTarget.h -log/Timer.cc -log/Timer.h -log/TraceTimer.h -log/UserChannel.cc -log/UserChannel.h -log/WrapperTarget.cc -log/WrapperTarget.h + log/BigNum.cc + log/BigNum.h + log/Bytes.cc + log/Bytes.h + log/CallbackTarget.cc + log/CallbackTarget.h + log/Channel.cc + log/Channel.h + log/ChannelBuffer.cc + log/ChannelBuffer.h + log/CodeLocation.cc + log/CodeLocation.h + log/Colour.cc + log/Colour.h + log/ColouringTarget.cc + log/ColouringTarget.h + log/ETA.cc + log/ETA.h + log/FileTarget.cc + log/FileTarget.h + log/IndentTarget.cc + log/IndentTarget.h + log/JSON.cc + log/JSON.h + log/LineBasedTarget.cc + log/LineBasedTarget.h + log/Log.cc + log/Log.h + log/LogTarget.cc + log/LogTarget.h + log/MessageTarget.cc + log/MessageTarget.h + log/MonitorTarget.cc + log/MonitorTarget.h + log/Number.cc + log/Number.h + log/OStreamTarget.cc + log/OStreamTarget.h + log/Plural.h + log/PrefixTarget.cc + log/PrefixTarget.h + log/Progress.cc + log/Progress.h + log/ProgressTimer.cc + log/ProgressTimer.h + log/ResourceUsage.cc + log/ResourceUsage.h + log/RotationTarget.cc + log/RotationTarget.h + log/SavedStatus.cc + log/SavedStatus.h + log/Seconds.cc + log/Seconds.h + log/Statistics.cc + log/Statistics.h + log/StatusTarget.cc + log/StatusTarget.h + log/SysLog.cc + log/SysLog.h + log/TeeTarget.cc + log/TeeTarget.h + log/TimeStamp.cc + log/TimeStamp.h + log/TimeStampTarget.cc + log/TimeStampTarget.h + log/Timer.cc + log/Timer.h + log/TraceTimer.h + log/UserChannel.cc + log/UserChannel.h + log/WrapperTarget.cc + log/WrapperTarget.h ) list( APPEND eckit_exception_srcs -exception/Exceptions.cc -exception/Exceptions.h + exception/Exceptions.cc + exception/Exceptions.h ) list( APPEND eckit_types_srcs -types/ClimateDate.cc -types/ClimateDate.h -types/Coord.cc -types/Coord.h -types/Date.cc -types/Date.h -types/DateTime.cc -types/DateTime.h -types/DayOfYear.cc -types/DayOfYear.h -types/Double.cc -types/Double.h -types/FixedString.h -types/FloatCompare.cc -types/FloatCompare.h -types/Fraction.cc -types/Fraction.h -types/Grid.cc -types/Grid.h -types/Hour.cc -types/Hour.h -types/Month.cc -types/Month.h -types/Time.cc -types/Time.h -types/TimeInterval.cc -types/TimeInterval.h -types/Types.cc -types/Types.h -types/UUID.cc -types/UUID.h -types/SemanticVersion.cc -types/SemanticVersion.h -types/VerifyingDate.cc -types/VerifyingDate.h + types/ClimateDate.cc + types/ClimateDate.h + types/Coord.cc + types/Coord.h + types/Date.cc + types/Date.h + types/DateTime.cc + types/DateTime.h + types/DayOfYear.cc + types/DayOfYear.h + types/Double.cc + types/Double.h + types/FixedString.h + types/FloatCompare.cc + types/FloatCompare.h + types/Fraction.cc + types/Fraction.h + types/Grid.cc + types/Grid.h + types/Hour.cc + types/Hour.h + types/Month.cc + types/Month.h + types/SemanticVersion.cc + types/SemanticVersion.h + types/Time.cc + types/Time.h + types/TimeInterval.cc + types/TimeInterval.h + types/Types.cc + types/Types.h + types/UUID.cc + types/UUID.h + types/VerifyingDate.cc + types/VerifyingDate.h ) list( APPEND eckit_parser_srcs -parser/CSVParser.cc -parser/CSVParser.h -parser/JSON.h -parser/JSONParser.cc -parser/JSONParser.h -parser/ObjectParser.cc -parser/ObjectParser.h -parser/StreamParser.cc -parser/StreamParser.h -parser/YAMLParser.cc -parser/YAMLParser.h + parser/CSVParser.cc + parser/CSVParser.h + parser/JSON.h + parser/JSONParser.cc + parser/JSONParser.h + parser/ObjectParser.cc + parser/ObjectParser.h + parser/StreamParser.cc + parser/StreamParser.h + parser/YAMLParser.cc + parser/YAMLParser.h ) list( APPEND eckit_value_srcs -value/BoolContent.cc -value/BoolContent.h -value/CompositeParams.cc -value/CompositeParams.h -value/Content.cc -value/Content.h -value/DateContent.cc -value/DateContent.h -value/DateTimeContent.cc -value/DateTimeContent.h -value/DispatchParams.h -value/DoubleContent.cc -value/DoubleContent.h -value/Expression.h -value/ListContent.cc -value/ListContent.h -value/MapContent.cc -value/MapContent.h -value/NilContent.cc -value/NilContent.h -value/NumberContent.cc -value/NumberContent.h -value/OrderedMapContent.cc -value/OrderedMapContent.h -value/Params.cc -value/Params.h -value/Properties.cc -value/Properties.h -value/ScopeParams.cc -value/ScopeParams.h -value/StringContent.cc -value/StringContent.h -value/TimeContent.cc -value/TimeContent.h -value/Value.cc -value/Value.h + value/BoolContent.cc + value/BoolContent.h + value/CompositeParams.cc + value/CompositeParams.h + value/Content.cc + value/Content.h + value/DateContent.cc + value/DateContent.h + value/DateTimeContent.cc + value/DateTimeContent.h + value/DispatchParams.h + value/DoubleContent.cc + value/DoubleContent.h + value/Expression.h + value/ListContent.cc + value/ListContent.h + value/MapContent.cc + value/MapContent.h + value/NilContent.cc + value/NilContent.h + value/NumberContent.cc + value/NumberContent.h + value/OrderedMapContent.cc + value/OrderedMapContent.h + value/Params.cc + value/Params.h + value/Properties.cc + value/Properties.h + value/ScopeParams.cc + value/ScopeParams.h + value/StringContent.cc + value/StringContent.h + value/TimeContent.cc + value/TimeContent.h + value/Value.cc + value/Value.h ) list( APPEND eckit_os_srcs -os/AutoAlarm.cc -os/AutoAlarm.h -os/AutoUmask.h -os/BackTrace.cc -os/BackTrace.h -os/Password.cc -os/Password.h -os/SemLocker.cc -os/SemLocker.h -os/Semaphore.cc -os/Semaphore.h -os/SharedInt.cc -os/SharedInt.h -os/SignalHandler.cc -os/SignalHandler.h -os/Stat.h -os/System.cc -os/System.h + os/AutoAlarm.cc + os/AutoAlarm.h + os/AutoUmask.h + os/BackTrace.cc + os/BackTrace.h + os/Password.cc + os/Password.h + os/SemLocker.cc + os/SemLocker.h + os/Semaphore.cc + os/Semaphore.h + os/SharedInt.cc + os/SharedInt.h + os/SignalHandler.cc + os/SignalHandler.h + os/Stat.h + os/System.cc + os/System.h ) list( APPEND eckit_net_srcs -net/Connector.cc -net/Connector.h -net/Endpoint.cc -net/Endpoint.h -net/HttpHeader.cc -net/HttpHeader.h -net/IPAddress.cc -net/IPAddress.h -net/NetMask.cc -net/NetMask.h -net/NetService.cc -net/NetService.h -net/NetUser.cc -net/NetUser.h -net/Port.cc -net/Port.h -net/ProxiedTCPClient.cc -net/ProxiedTCPClient.h -net/ProxiedTCPServer.cc -net/ProxiedTCPServer.h -net/SocketOptions.cc -net/SocketOptions.h -net/TCPClient.cc -net/TCPClient.h -net/TCPServer.cc -net/TCPServer.h -net/TCPSocket.cc -net/TCPSocket.h -net/MultiSocket.cc -net/MultiSocket.h -net/TCPStream.cc -net/TCPStream.h -net/Telnet.cc -net/Telnet.h -net/TelnetUser.cc -net/TelnetUser.h -net/Telnetable.cc -net/Telnetable.h -net/UDPClient.cc -net/UDPClient.h -net/UDPServer.cc -net/UDPServer.h + net/Connector.cc + net/Connector.h + net/Endpoint.cc + net/Endpoint.h + net/HttpHeader.cc + net/HttpHeader.h + net/IPAddress.cc + net/IPAddress.h + net/MultiSocket.cc + net/MultiSocket.h + net/NetMask.cc + net/NetMask.h + net/NetService.cc + net/NetService.h + net/NetUser.cc + net/NetUser.h + net/Port.cc + net/Port.h + net/ProxiedTCPClient.cc + net/ProxiedTCPClient.h + net/ProxiedTCPServer.cc + net/ProxiedTCPServer.h + net/SocketOptions.cc + net/SocketOptions.h + net/TCPClient.cc + net/TCPClient.h + net/TCPServer.cc + net/TCPServer.h + net/TCPSocket.cc + net/TCPSocket.h + net/TCPStream.cc + net/TCPStream.h + net/Telnet.cc + net/Telnet.h + net/TelnetUser.cc + net/TelnetUser.h + net/Telnetable.cc + net/Telnetable.h + net/UDPClient.cc + net/UDPClient.h + net/UDPServer.cc + net/UDPServer.h ) list( APPEND eckit_serialisation_srcs -serialisation/BadTag.cc -serialisation/BadTag.h -serialisation/FileStream.cc -serialisation/FileStream.h -serialisation/FstreamStream.h -serialisation/HandleStream.h -serialisation/IfstreamStream.h -serialisation/MemoryStream.cc -serialisation/MemoryStream.h -serialisation/PipeStream.cc -serialisation/PipeStream.h -serialisation/Reanimator.cc -serialisation/Reanimator.h -serialisation/ReanimatorBase.cc -serialisation/ResizableMemoryStream.cc -serialisation/ResizableMemoryStream.h -serialisation/Stream.cc -serialisation/Stream.h -serialisation/Streamable.cc -serialisation/Streamable.h + serialisation/BadTag.cc + serialisation/BadTag.h + serialisation/FileStream.cc + serialisation/FileStream.h + serialisation/FstreamStream.h + serialisation/HandleStream.h + serialisation/IfstreamStream.h + serialisation/MemoryStream.cc + serialisation/MemoryStream.h + serialisation/PipeStream.cc + serialisation/PipeStream.h + serialisation/Reanimator.cc + serialisation/Reanimator.h + serialisation/ReanimatorBase.cc + serialisation/ResizableMemoryStream.cc + serialisation/ResizableMemoryStream.h + serialisation/Stream.cc + serialisation/Stream.h + serialisation/Streamable.cc + serialisation/Streamable.h ) - - list( APPEND eckit_persist_srcs -persist/Bless.h -persist/DumpLoad.cc -persist/DumpLoad.h -persist/Exporter.cc -persist/Exporter.h -persist/Isa.cc -persist/Isa.h + persist/Bless.h + persist/DumpLoad.cc + persist/DumpLoad.h + persist/Exporter.cc + persist/Exporter.h + persist/Isa.cc + persist/Isa.h ) list( APPEND eckit_utils_srcs - utils/ByteSwap.h - utils/Compressor.cc - utils/Compressor.h - utils/Hash.cc - utils/Hash.h - utils/HyperCube.cc - utils/HyperCube.h - utils/MD5.cc - utils/MD5.h - utils/EnumBitmask.h - utils/Optional.h - utils/RLE.cc - utils/RLE.h - utils/Regex.cc - utils/Regex.h - utils/RendezvousHash.cc - utils/RendezvousHash.h - utils/StringTools.cc - utils/StringTools.h - utils/Tokenizer.cc - utils/Tokenizer.h - utils/Clock.h - utils/Translator.cc - utils/Translator.h + utils/ByteSwap.h + utils/Clock.h + utils/Compressor.cc + utils/Compressor.h + utils/EnumBitmask.h + utils/Hash.cc + utils/Hash.h + utils/HyperCube.cc + utils/HyperCube.h + utils/MD5.cc + utils/MD5.h + utils/Optional.h + utils/RLE.cc + utils/RLE.h + utils/Regex.cc + utils/Regex.h + utils/RendezvousHash.cc + utils/RendezvousHash.h + utils/StringTools.cc + utils/StringTools.h + utils/Tokenizer.cc + utils/Tokenizer.h + utils/Translator.cc + utils/Translator.h ) if(eckit_HAVE_BZIP2) list( APPEND eckit_utils_srcs - utils/BZip2Compressor.cc - utils/BZip2Compressor.h + utils/BZip2Compressor.cc + utils/BZip2Compressor.h ) endif() if(eckit_HAVE_SNAPPY) - list( APPEND eckit_utils_srcs - utils/SnappyCompressor.cc - utils/SnappyCompressor.h - ) + list( APPEND eckit_utils_srcs + utils/SnappyCompressor.cc + utils/SnappyCompressor.h + ) endif() if(eckit_HAVE_LZ4) - list( APPEND eckit_utils_srcs - utils/LZ4Compressor.cc - utils/LZ4Compressor.h - ) + list( APPEND eckit_utils_srcs + utils/LZ4Compressor.cc + utils/LZ4Compressor.h + ) endif() if(eckit_HAVE_AEC) - list( APPEND eckit_utils_srcs - utils/AECCompressor.cc - utils/AECCompressor.h - ) + list( APPEND eckit_utils_srcs + utils/AECCompressor.cc + utils/AECCompressor.h + ) endif() if(eckit_HAVE_SSL) list( APPEND eckit_utils_srcs - utils/MD4.cc - utils/MD4.h - utils/SHA1.cc - utils/SHA1.h + utils/MD4.cc + utils/MD4.h + utils/SHA1.cc + utils/SHA1.h ) endif() if(eckit_HAVE_RSYNC) - list( APPEND eckit_utils_srcs - utils/Rsync.cc - utils/Rsync.h - ) + list( APPEND eckit_utils_srcs + utils/Rsync.cc + utils/Rsync.h + ) endif() if(eckit_HAVE_XXHASH) @@ -769,49 +759,49 @@ endif() list( APPEND eckit_memory_srcs -memory/Builder.h -memory/Counted.cc -memory/Counted.h -memory/Factory.h -memory/MMap.cc -memory/MMap.h -memory/MapAllocator.cc -memory/MapAllocator.h -memory/MemoryBuffer.cc -memory/MemoryBuffer.h -memory/NonCopyable.cc -memory/NonCopyable.h -memory/OnlyMovable.h -memory/Owned.h -memory/Padded.h -memory/ScopedPtr.h -memory/SharedPtr.cc -memory/SharedPtr.h -memory/Shmget.cc -memory/Shmget.h -memory/Zero.h + memory/Builder.h + memory/Counted.cc + memory/Counted.h + memory/Factory.h + memory/MMap.cc + memory/MMap.h + memory/MapAllocator.cc + memory/MapAllocator.h + memory/MemoryBuffer.cc + memory/MemoryBuffer.h + memory/NonCopyable.cc + memory/NonCopyable.h + memory/OnlyMovable.h + memory/Owned.h + memory/Padded.h + memory/ScopedPtr.h + memory/SharedPtr.cc + memory/SharedPtr.h + memory/Shmget.cc + memory/Shmget.h + memory/Zero.h ) list( APPEND eckit_compat_srcs -compat/Inited.h -compat/StrStream.h + compat/Inited.h + compat/StrStream.h ) list( APPEND eckit_maths_srcs -maths/Functions.cc -maths/Functions.h + maths/Functions.cc + maths/Functions.h ) list( APPEND eckit_system_srcs - system/Plugin.cc - system/Plugin.h system/Library.cc system/Library.h system/LibraryManager.cc system/LibraryManager.h system/MemoryInfo.cc system/MemoryInfo.h + system/Plugin.cc + system/Plugin.h system/ResourceUsage.cc system/ResourceUsage.h system/SystemInfo.cc @@ -835,10 +825,10 @@ if(HAVE_JEMALLOC) endif() list( APPEND eckit_bases_srcs -bases/Loader.cc -bases/Loader.h -bases/Watcher.cc -bases/Watcher.h + bases/Loader.cc + bases/Loader.h + bases/Watcher.cc + bases/Watcher.h ) list( APPEND eckit_transaction_srcs @@ -880,40 +870,40 @@ list( APPEND eckit_dirs ) foreach( dir ${eckit_dirs} ) - list( APPEND eckit_srcs ${eckit_${dir}_srcs} ) + list( APPEND eckit_srcs ${eckit_${dir}_srcs} ) endforeach() list( APPEND eckit_templates - container/CacheLRU.cc - container/kdtree/KDNode.cc - container/sptree/SPNode.cc - filesystem/BasePathNameT.cc - io/FileBase.cc - runtime/PipeHandler.cc - serialisation/Reanimator.cc - transaction/TxnLog.cc - types/Types.cc - utils/RLE.cc - container/BTree.cc - container/BloomFilter.cc - container/MappedArray.cc - container/SharedMemArray.cc - container/Trie.cc - container/bsptree/BSPNode.cc + container/BTree.cc + container/BloomFilter.cc + container/CacheLRU.cc + container/MappedArray.cc + container/SharedMemArray.cc + container/Trie.cc + container/bsptree/BSPNode.cc + container/kdtree/KDNode.cc + container/sptree/SPNode.cc + filesystem/BasePathNameT.cc + io/FileBase.cc + runtime/PipeHandler.cc + serialisation/Reanimator.cc + transaction/TxnLog.cc + types/Types.cc + utils/RLE.cc ) list( APPEND eckit_persistent - io/Length.h - io/Offset.h - types/ClimateDate.h - types/Date.h - types/DateTime.h - types/DayOfYear.h - types/Double.h - types/Grid.h - types/Month.h - types/Time.h - types/VerifyingDate.h + io/Length.h + io/Offset.h + types/ClimateDate.h + types/Date.h + types/DateTime.h + types/DayOfYear.h + types/Double.h + types/Grid.h + types/Month.h + types/Time.h + types/VerifyingDate.h ) ### eckit library @@ -925,13 +915,13 @@ ecbuild_add_library( HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit SOURCES - ${eckit_srcs} + ${eckit_srcs} TEMPLATES - ${eckit_templates} + ${eckit_templates} PERSISTENT - ${eckit_persistent} + ${eckit_persistent} PUBLIC_INCLUDES $ @@ -969,11 +959,11 @@ ecbuild_add_library( ### sub-directories -if( HAVE_ECKIT_CMD ) +if( eckit_HAVE_ECKIT_CMD ) add_subdirectory( cmd ) endif() -if( HAVE_ECKIT_SQL ) +if( eckit_HAVE_ECKIT_SQL ) add_subdirectory( sql ) endif() @@ -985,11 +975,11 @@ add_subdirectory( mpi ) add_subdirectory( option ) add_subdirectory( web ) -if( HAVE_ECKIT_CODEC ) +if( eckit_HAVE_ECKIT_CODEC ) add_subdirectory( codec ) endif() -if( HAVE_EXPERIMENTAL ) +if( eckit_HAVE_ECKIT_GEO ) add_subdirectory( geo ) endif() diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index cbf2de0a4..ea2a8a3b5 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -122,28 +122,29 @@ set(eckit_geo_include_dirs $ ) +set(eckit_geo_libs eckit_maths) + +if(eckit_HAVE_PROJ) + list(APPEND eckit_geo_srcs projection/PROJ.cc projection/PROJ.h) + list(APPEND eckit_geo_libs PROJ::proj) +endif() + +if(eckit_HAVE_ECKIT_CODEC) + list(APPEND eckit_geo_srcs grid/unstructured/ORCA.cc grid/unstructured/ORCA.h) + list(APPEND eckit_geo_libs eckit_codec) +endif() + +if(eckit_HAVE_GEO_CONVEX_HULL) + list(APPEND eckit_geo_srcs triangulation/Triangulation3.cc triangulation/Triangulation3.h) + list(APPEND eckit_geo_libs Qhull::Qhull) +endif() + ecbuild_add_library( TARGET eckit_geo TYPE SHARED INSTALL_HEADERS ALL HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/geo - PUBLIC_LIBS eckit_maths + PUBLIC_LIBS ${eckit_geo_libs} PUBLIC_INCLUDES ${eckit_geo_include_dirs} SOURCES ${eckit_geo_srcs} ) - -if(HAVE_PROJ) - target_sources(eckit_geo PRIVATE projection/PROJ.cc projection/PROJ.h) - target_link_libraries(eckit_geo PUBLIC PROJ::proj) -endif() - -if(HAVE_CODEC) - target_sources(eckit_geo PRIVATE grid/unstructured/ORCA.cc grid/unstructured/ORCA.h) - target_link_libraries(eckit_geo PUBLIC eckit_codec) -endif() - -if(Qhull_FOUND) - target_sources(eckit_geo PRIVATE triangulation/Triangulation3.cc triangulation/Triangulation3.h) - target_link_libraries(eckit_geo PUBLIC Qhull::Qhull) -endif() - diff --git a/src/eckit/geo/eckit_geo_config.h.in b/src/eckit/geo/eckit_geo_config.h.in index 42ad9b678..707e321f5 100644 --- a/src/eckit/geo/eckit_geo_config.h.in +++ b/src/eckit/geo/eckit_geo_config.h.in @@ -1,5 +1,19 @@ +/* + * (C) Copyright 1996- 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. + */ + + #pragma once -#cmakedefine01 eckit_HAVE_GEO_CACHING +#cmakedefine01 eckit_HAVE_ECKIT_CODEC +#cmakedefine01 eckit_HAVE_GEO_CACHING +#cmakedefine01 eckit_HAVE_GEO_CONVEX_HULL #cmakedefine eckit_GEO_CACHE_PATH "@eckit_GEO_CACHE_PATH@" diff --git a/src/eckit/maths/CMakeLists.txt b/src/eckit/maths/CMakeLists.txt index b5ab82098..399cdd27d 100644 --- a/src/eckit/maths/CMakeLists.txt +++ b/src/eckit/maths/CMakeLists.txt @@ -7,7 +7,7 @@ list( APPEND eckit_maths_lib_srcs MatrixLapack.h ) -if( HAVE_EXPERIMENTAL ) +if( eckit_HAVE_ECKIT_GEO ) # for eckit::geo list( APPEND eckit_maths_lib_srcs Matrix3.h diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index ed83b4dc5..82bc22803 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -1,36 +1,38 @@ ecbuild_add_executable( TARGET eckit_version OUTPUT_NAME eckit-version - CONDITION HAVE_BUILD_TOOLS SOURCES eckit-version.cc LIBS eckit_option eckit ) +if( NOT eckit_HAVE_BUILD_TOOLS ) + return() +endif() + ecbuild_add_executable( TARGET eckit_info OUTPUT_NAME eckit-info - CONDITION HAVE_BUILD_TOOLS SOURCES eckit-info.cc LIBS eckit_option eckit ) ecbuild_add_executable( TARGET eckit_codec_list OUTPUT_NAME eckit-codec-list - CONDITION HAVE_BUILD_TOOLS AND ECKIT_CODEC + CONDITION ECKIT_CODEC SOURCES eckit-codec-list.cc LIBS eckit_codec eckit_option ) ecbuild_add_executable( TARGET eckit_grid OUTPUT_NAME eckit-grid - CONDITION HAVE_BUILD_TOOLS AND HAVE_EXPERIMENTAL + CONDITION eckit_HAVE_ECKIT_GEO SOURCES eckit-grid.cc LIBS eckit_geo eckit_option ) ecbuild_add_executable( TARGET eckit_grid_list OUTPUT_NAME eckit-grid-list - CONDITION HAVE_BUILD_TOOLS AND HAVE_EXPERIMENTAL + CONDITION eckit_HAVE_ECKIT_GEO SOURCES eckit-grid-list.cc LIBS eckit_geo eckit_option ) ecbuild_add_executable( TARGET eckit_grid_triangulation OUTPUT_NAME eckit-grid-triangulation - CONDITION HAVE_BUILD_TOOLS AND HAVE_EXPERIMENTAL AND Qhull_FOUND + CONDITION eckit_HAVE_ECKIT_GEO AND eckit_HAVE_GEO_CONVEX_HULL SOURCES eckit-grid-triangulation.cc LIBS eckit_geo eckit_option Qhull::Qhull ) @@ -38,35 +40,31 @@ ecbuild_add_executable( TARGET eckit_grid_triangulation ecbuild_add_executable( TARGET dhcopy OUTPUT_NAME eckit-dhcopy - CONDITION HAVE_BUILD_TOOLS NOINSTALL SOURCES dhcopy.cc LIBS eckit_option eckit ) ecbuild_add_executable( TARGET syslog_server OUTPUT_NAME eckit-syslog-server - CONDITION HAVE_BUILD_TOOLS NOINSTALL SOURCES syslog-server.cc LIBS eckit ) ecbuild_add_executable( TARGET syslog_client OUTPUT_NAME eckit-syslog-client - CONDITION HAVE_BUILD_TOOLS NOINSTALL SOURCES syslog-client.cc LIBS eckit ) ecbuild_add_executable( TARGET eckit_rsync OUTPUT_NAME eckit-rsync - CONDITION HAVE_BUILD_TOOLS AND eckit_HAVE_RSYNC + CONDITION eckit_HAVE_RSYNC NOINSTALL SOURCES rsync.cc LIBS eckit_option eckit ) ecbuild_add_executable( TARGET eckit_hash OUTPUT_NAME eckit-hash - CONDITION HAVE_BUILD_TOOLS NOINSTALL SOURCES eckit-hash.cc LIBS eckit_option eckit ) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b737aef77..30d3bc5a6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -21,18 +21,18 @@ add_subdirectory( types ) add_subdirectory( utils ) add_subdirectory( value ) -if( HAVE_ECKIT_SQL ) +if( eckit_HAVE_ECKIT_SQL ) add_subdirectory( sql ) endif() -if( HAVE_ECKIT_CODEC ) +if( eckit_HAVE_ECKIT_CODEC ) add_subdirectory( codec ) endif() -if( HAVE_EXPERIMENTAL ) +if( eckit_HAVE_ECKIT_GEO ) add_subdirectory( geo ) endif() -if( HAVE_EXPERIMENTAL ) +if( eckit_HAVE_EXPERIMENTAL ) add_subdirectory( experimental ) endif() From 47c20305bd436a8371e510111fc237ab1bf7afa5 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 7 Dec 2023 16:03:12 +0000 Subject: [PATCH 387/737] eckit::geo cmake refactor (not experimental anymore) --- CMakeLists.txt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c881c14c..d6257bc49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -168,10 +168,8 @@ ecbuild_add_option( FEATURE GEO_CONVEX_HULL DESCRIPTION "eckit::geo geometry library convex hull/Delaunay triangulation" REQUIRED_PACKAGES "Qhull COMPONENTS C CXX" ) -if( eckit_HAVE_GEO_CONVEX_HULL ) - if(NOT Qhull_FOUND OR NOT TARGET Qhull::Qhull) - message(FATAL_ERROR "eckit::geo ENABLE_GEO_CONVEX_HULL requires Qhull C/C++ libraries") - endif() +if( eckit_HAVE_GEO_CONVEX_HULL AND NOT TARGET Qhull::Qhull ) + message(FATAL_ERROR "eckit::geo ENABLE_GEO_CONVEX_HULL requires Qhull C/C++ libraries") endif() set( eckit_GEO_CACHE_PATH "/tmp/cache" ) From 7dee4a26836a52eb523fe8d53ae5776f91890fab Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 7 Dec 2023 16:49:53 +0000 Subject: [PATCH 388/737] eckit::geo triangulation/convex hull --- src/eckit/geo/CMakeLists.txt | 11 +++- src/eckit/geo/ConvexHull.cc | 0 src/eckit/geo/ConvexHull.h | 68 +++++++++++++++++++++++++ src/eckit/geo/convexhull/ConvexHullN.cc | 32 ++++++++++++ src/eckit/geo/convexhull/ConvexHullN.h | 40 +++++++++++++++ src/eckit/geo/convexhull/Qhull.cc | 40 +++++++++++++++ src/eckit/geo/convexhull/Qhull.h | 42 +++++++++++++++ 7 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 src/eckit/geo/ConvexHull.cc create mode 100644 src/eckit/geo/ConvexHull.h create mode 100644 src/eckit/geo/convexhull/ConvexHullN.cc create mode 100644 src/eckit/geo/convexhull/ConvexHullN.h create mode 100644 src/eckit/geo/convexhull/Qhull.cc create mode 100644 src/eckit/geo/convexhull/Qhull.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index ea2a8a3b5..f9c32c046 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -11,6 +11,8 @@ list(APPEND eckit_geo_srcs Cache.cc Cache.h Configurator.h + ConvexHull.cc + ConvexHull.h CoordinateHelpers.cc CoordinateHelpers.h Domain.cc @@ -135,7 +137,14 @@ if(eckit_HAVE_ECKIT_CODEC) endif() if(eckit_HAVE_GEO_CONVEX_HULL) - list(APPEND eckit_geo_srcs triangulation/Triangulation3.cc triangulation/Triangulation3.h) + list(APPEND eckit_geo_srcs + convexhull/ConvexHullN.cc + convexhull/ConvexHullN.h + convexhull/Qhull.cc + convexhull/Qhull.h + triangulation/Triangulation3.cc + triangulation/Triangulation3.h + ) list(APPEND eckit_geo_libs Qhull::Qhull) endif() diff --git a/src/eckit/geo/ConvexHull.cc b/src/eckit/geo/ConvexHull.cc new file mode 100644 index 000000000..e69de29bb diff --git a/src/eckit/geo/ConvexHull.h b/src/eckit/geo/ConvexHull.h new file mode 100644 index 000000000..25edbc9b9 --- /dev/null +++ b/src/eckit/geo/ConvexHull.h @@ -0,0 +1,68 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "eckit/memory/Builder.h" +#include "eckit/memory/Factory.h" + + +namespace eckit { +class Configuration; +} // namespace eckit + + +namespace eckit::geo { + + +using Triangle = std::array; + + +class ConvexHull { +public: + // -- Types + + using builder_t = BuilderT1; + using ARG1 = const Configuration&; + + // -- Constructors + + ConvexHull(const ConvexHull&) = delete; + ConvexHull(ConvexHull&&) = delete; + + // -- Operators + + void operator=(const ConvexHull&) = delete; + void operator=(ConvexHull&&) = delete; + + // -- Destructor + + virtual ~ConvexHull() = default; + + // -- Methods + + static std::string className() { return "ConvexHull"; } + +protected: + // -- Constructors + + ConvexHull() /*noexcept */ = default; +}; + + +using ConvexHullFactory = Factory; + +template +using ConvexHullBuilder = ConcreteBuilderT1; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/convexhull/ConvexHullN.cc b/src/eckit/geo/convexhull/ConvexHullN.cc new file mode 100644 index 000000000..5c78f055a --- /dev/null +++ b/src/eckit/geo/convexhull/ConvexHullN.cc @@ -0,0 +1,32 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/convexhull/ConvexHullN.h" + +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/Grid.h" +#include "eckit/geo/projection/LonLatToXYZ.h" + +#include "libqhullcpp/Qhull.h" +#include "libqhullcpp/QhullFacetList.h" +#include "libqhullcpp/QhullVertexSet.h" + + +namespace eckit::geo::convexhull { + + +ConvexHullN::ConvexHullN(size_t N, const std::vector& coord) : + Qhull(N, coord, "Qt") {} + + +} // namespace eckit::geo::convexhull diff --git a/src/eckit/geo/convexhull/ConvexHullN.h b/src/eckit/geo/convexhull/ConvexHullN.h new file mode 100644 index 000000000..17d18b63a --- /dev/null +++ b/src/eckit/geo/convexhull/ConvexHullN.h @@ -0,0 +1,40 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/convexhull/Qhull.h" + +#include +#include + + +namespace eckit::geo { +class Grid; +} // namespace eckit::geo + + +namespace eckit::geo::convexhull { + + +class ConvexHullN : public Qhull { +public: + template + explicit ConvexHullN(const std::vector>&); + + explicit ConvexHullN(const std::vector>&); + +private: + explicit ConvexHullN(size_t N, const std::vector&); +}; + + +} // namespace eckit::geo::convexhull diff --git a/src/eckit/geo/convexhull/Qhull.cc b/src/eckit/geo/convexhull/Qhull.cc new file mode 100644 index 000000000..635ceba03 --- /dev/null +++ b/src/eckit/geo/convexhull/Qhull.cc @@ -0,0 +1,40 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/convexhull/Qhull.h" + +#include "eckit/exception/Exceptions.h" + +#include "libqhullcpp/Qhull.h" +#include "libqhullcpp/QhullFacetList.h" +#include "libqhullcpp/QhullVertexSet.h" + + +namespace eckit::geo::convexhull { + + +Qhull::Qhull(size_t N, const std::vector& coord, const std::string& command) { + ASSERT(coord.size() % N == 0); + auto pointDimension = static_cast(N); + auto pointCount = static_cast(coord.size() % N); + + qh_ = std::make_unique("", pointDimension, pointCount, coord.data(), command.c_str()); + ASSERT(qh_); +} + + +const orgQhull::Qhull& Qhull::qh() { + ASSERT(qh_); + return *qh_; +} + + +} // namespace eckit::geo::convexhull diff --git a/src/eckit/geo/convexhull/Qhull.h b/src/eckit/geo/convexhull/Qhull.h new file mode 100644 index 000000000..f684bfba5 --- /dev/null +++ b/src/eckit/geo/convexhull/Qhull.h @@ -0,0 +1,42 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/ConvexHull.h" + +#include +#include +#include + + +namespace orgQhull { +class Qhull; +} // namespace orgQhull + + +namespace eckit::geo::convexhull { + + +class Qhull : public ConvexHull { +protected: + Qhull(size_t N, const std::vector&, const std::string& command); + + using qh_type = orgQhull::Qhull; + + const qh_type& qh(); + +private: + std::unique_ptr qh_; +}; + + +} // namespace eckit::geo::convexhull From 510114b2e77670b23dd00381c2b59ad7191297b1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 7 Dec 2023 16:50:17 +0000 Subject: [PATCH 389/737] eckit::geo triangulation/convex hull --- src/eckit/geo/convexhull/ConvexHullN.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eckit/geo/convexhull/ConvexHullN.cc b/src/eckit/geo/convexhull/ConvexHullN.cc index 5c78f055a..ed3d99741 100644 --- a/src/eckit/geo/convexhull/ConvexHullN.cc +++ b/src/eckit/geo/convexhull/ConvexHullN.cc @@ -26,7 +26,7 @@ namespace eckit::geo::convexhull { ConvexHullN::ConvexHullN(size_t N, const std::vector& coord) : - Qhull(N, coord, "Qt") {} + Qhull(N, coord, "QJ") {} } // namespace eckit::geo::convexhull From a229da11acea10d462b34cc014e9fc34ed164f5e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 7 Dec 2023 23:41:39 +0000 Subject: [PATCH 390/737] eckit::geo triangulation --- src/eckit/geo/ConvexHull.h | 11 +++- src/eckit/geo/Triangulation.h | 16 ++++- src/eckit/geo/convexhull/Qhull.cc | 60 +++++++++++++++++-- src/eckit/geo/convexhull/Qhull.h | 21 ++++--- src/eckit/geo/triangulation/Triangulation3.cc | 23 ++----- 5 files changed, 95 insertions(+), 36 deletions(-) diff --git a/src/eckit/geo/ConvexHull.h b/src/eckit/geo/ConvexHull.h index 25edbc9b9..5a3dbe220 100644 --- a/src/eckit/geo/ConvexHull.h +++ b/src/eckit/geo/ConvexHull.h @@ -9,6 +9,8 @@ */ +#pragma once + #include #include @@ -24,13 +26,12 @@ class Configuration; namespace eckit::geo { -using Triangle = std::array; - - class ConvexHull { public: // -- Types + using Triangle = std::array; + using builder_t = BuilderT1; using ARG1 = const Configuration&; @@ -52,6 +53,10 @@ class ConvexHull { static std::string className() { return "ConvexHull"; } + virtual std::vector> list_vertices() const = 0; + virtual std::vector> list_facets() const = 0; + virtual std::vector list_triangles() const = 0; + protected: // -- Constructors diff --git a/src/eckit/geo/Triangulation.h b/src/eckit/geo/Triangulation.h index 610cc5aad..1a9515e6d 100644 --- a/src/eckit/geo/Triangulation.h +++ b/src/eckit/geo/Triangulation.h @@ -12,6 +12,7 @@ #include #include +#include "eckit/geo/ConvexHull.h" #include "eckit/memory/Builder.h" #include "eckit/memory/Factory.h" @@ -24,7 +25,7 @@ class Configuration; namespace eckit::geo { -using Triangle = std::array; +using Triangle = ConvexHull::Triangle; class Triangulation : protected std::vector { @@ -34,6 +35,13 @@ class Triangulation : protected std::vector { using builder_t = BuilderT1; using ARG1 = const Configuration&; + // -- Constructors + + using vector::vector; + + Triangulation(const Triangulation&) = default; + Triangulation(Triangulation&&) = default; + // -- Destructor virtual ~Triangulation() = default; @@ -42,6 +50,9 @@ class Triangulation : protected std::vector { using vector::operator[]; + Triangulation& operator=(const Triangulation&) = default; + Triangulation& operator=(Triangulation&&) = default; + // -- Methods static std::string className() { return "Triangulation"; } @@ -57,7 +68,8 @@ class Triangulation : protected std::vector { protected: // -- Constructors - Triangulation() /*noexcept */ = default; + explicit Triangulation(const std::vector& tri) : + vector(tri) {} }; diff --git a/src/eckit/geo/convexhull/Qhull.cc b/src/eckit/geo/convexhull/Qhull.cc index 635ceba03..d382b30b3 100644 --- a/src/eckit/geo/convexhull/Qhull.cc +++ b/src/eckit/geo/convexhull/Qhull.cc @@ -13,7 +13,6 @@ #include "eckit/exception/Exceptions.h" -#include "libqhullcpp/Qhull.h" #include "libqhullcpp/QhullFacetList.h" #include "libqhullcpp/QhullVertexSet.h" @@ -22,18 +21,69 @@ namespace eckit::geo::convexhull { Qhull::Qhull(size_t N, const std::vector& coord, const std::string& command) { + ASSERT(N > 0); ASSERT(coord.size() % N == 0); + auto pointDimension = static_cast(N); auto pointCount = static_cast(coord.size() % N); - qh_ = std::make_unique("", pointDimension, pointCount, coord.data(), command.c_str()); + qh_ = std::make_unique("", pointDimension, pointCount, coord.data(), command.c_str()); ASSERT(qh_); } -const orgQhull::Qhull& Qhull::qh() { - ASSERT(qh_); - return *qh_; +std::vector> Qhull::list_vertices() const { + std::vector> vertices; + vertices.reserve(qh_->vertexCount()); + + auto N = qh_->dimension(); + for (const auto& vertex : qh_->vertexList()) { + const auto point = vertex.point(); + ASSERT(point.dimension() == N); + + const auto* coord = point.coordinates(); + vertices.emplace_back(coord, coord + N); + } + + return vertices; +} + + +std::vector> Qhull::list_facets() const { + std::vector> facets; + facets.reserve(qh_->facetCount()); + + for (const auto& facet : qh_->facetList()) { + const auto vertices = facet.vertices(); + + std::vector f; + f.reserve(vertices.size()); + + for (const auto& vertex : vertices) { + f.push_back(static_cast(vertex.id())); + } + + facets.emplace_back(f); + } + + return facets; +} + + +std::vector Qhull::list_triangles() const { + std::vector tri; + tri.reserve(qh_->facetCount()); + + for (const auto& facet : qh_->facetList()) { + const auto vertices = facet.vertices(); + ASSERT(vertices.size() == 3); + + tri.emplace_back(Triangle{static_cast(vertices[0].id()), + static_cast(vertices[1].id()), + static_cast(vertices[2].id())}); + } + + return tri; } diff --git a/src/eckit/geo/convexhull/Qhull.h b/src/eckit/geo/convexhull/Qhull.h index f684bfba5..5ea4dcde8 100644 --- a/src/eckit/geo/convexhull/Qhull.h +++ b/src/eckit/geo/convexhull/Qhull.h @@ -17,25 +17,28 @@ #include #include - -namespace orgQhull { -class Qhull; -} // namespace orgQhull +#include "libqhullcpp/Qhull.h" namespace eckit::geo::convexhull { class Qhull : public ConvexHull { -protected: - Qhull(size_t N, const std::vector&, const std::string& command); +public: + // -- Types + + Qhull(size_t N, const std::vector& coord, const std::string& command); - using qh_type = orgQhull::Qhull; + // -- Overridden methods - const qh_type& qh(); + std::vector> list_vertices() const override; + std::vector> list_facets() const override; + std::vector list_triangles() const override; private: - std::unique_ptr qh_; + // -- Members + + std::unique_ptr qh_; }; diff --git a/src/eckit/geo/triangulation/Triangulation3.cc b/src/eckit/geo/triangulation/Triangulation3.cc index 4b78c1492..4e002aaf4 100644 --- a/src/eckit/geo/triangulation/Triangulation3.cc +++ b/src/eckit/geo/triangulation/Triangulation3.cc @@ -11,21 +11,16 @@ #include "eckit/geo/triangulation/Triangulation3.h" -#include - #include "eckit/exception/Exceptions.h" #include "eckit/geo/Grid.h" +#include "eckit/geo/convexhull/Qhull.h" #include "eckit/geo/projection/LonLatToXYZ.h" -#include "libqhullcpp/Qhull.h" -#include "libqhullcpp/QhullFacetList.h" -#include "libqhullcpp/QhullVertexSet.h" - namespace eckit::geo::triangulation { -Triangulation3::Triangulation3(const Grid& grid) { +std::vector grid_to_coord(const Grid& grid) { auto [lat, lon] = grid.to_latlon(); ASSERT(lat.size() == lon.size()); @@ -41,18 +36,12 @@ Triangulation3::Triangulation3(const Grid& grid) { coord[i * 3 + 2] = p.Z; } - auto qh = std::make_unique("", 3, N, coord.data(), "Qt"); + return coord; +} - reserve(qh->facetCount()); - for (const auto& facet : qh->facetList()) { - auto vertices = facet.vertices(); - ASSERT(vertices.size() == 3); - emplace_back(Triangle{static_cast(vertices[0].id()), - static_cast(vertices[1].id()), - static_cast(vertices[2].id())}); - } -} +Triangulation3::Triangulation3(const Grid& grid) : + Triangulation(convexhull::Qhull(3, grid_to_coord(grid), "Qt").list_triangles()) {} } // namespace eckit::geo::triangulation From 0db3c73431e308ccee3e9c4adcb2e6e1c5aacfa0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 8 Dec 2023 14:19:09 +0000 Subject: [PATCH 391/737] eckit::geo triangulation/convex hull --- src/eckit/geo/CMakeLists.txt | 4 +-- src/eckit/geo/convexhull/ConvexHullN.cc | 29 ++++++++++++------- src/eckit/geo/convexhull/ConvexHullN.h | 16 +++++----- src/eckit/geo/triangulation/Triangulation3.cc | 4 +-- src/eckit/geo/{convexhull => util}/Qhull.cc | 9 +++--- src/eckit/geo/{convexhull => util}/Qhull.h | 4 +-- 6 files changed, 36 insertions(+), 30 deletions(-) rename src/eckit/geo/{convexhull => util}/Qhull.cc (93%) rename src/eckit/geo/{convexhull => util}/Qhull.h (92%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index f9c32c046..816d89309 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -140,10 +140,10 @@ if(eckit_HAVE_GEO_CONVEX_HULL) list(APPEND eckit_geo_srcs convexhull/ConvexHullN.cc convexhull/ConvexHullN.h - convexhull/Qhull.cc - convexhull/Qhull.h triangulation/Triangulation3.cc triangulation/Triangulation3.h + util/Qhull.cc + util/Qhull.h ) list(APPEND eckit_geo_libs Qhull::Qhull) endif() diff --git a/src/eckit/geo/convexhull/ConvexHullN.cc b/src/eckit/geo/convexhull/ConvexHullN.cc index ed3d99741..824e7de35 100644 --- a/src/eckit/geo/convexhull/ConvexHullN.cc +++ b/src/eckit/geo/convexhull/ConvexHullN.cc @@ -11,22 +11,31 @@ #include "eckit/geo/convexhull/ConvexHullN.h" -#include - #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Grid.h" -#include "eckit/geo/projection/LonLatToXYZ.h" - -#include "libqhullcpp/Qhull.h" -#include "libqhullcpp/QhullFacetList.h" -#include "libqhullcpp/QhullVertexSet.h" +#include "eckit/geo/util/Qhull.h" namespace eckit::geo::convexhull { -ConvexHullN::ConvexHullN(size_t N, const std::vector& coord) : - Qhull(N, coord, "QJ") {} +std::vector> ConvexHullN::list_vertices() const { + NOTIMP; +} + + +std::vector> ConvexHullN::list_facets() const { + NOTIMP; +} + + +std::vector ConvexHullN::list_triangles() const { + NOTIMP; +} + + +ConvexHullN::ConvexHullN(size_t N, const std::vector& coord) { + // util::Qhull q(N, coord, "QJ"); +} } // namespace eckit::geo::convexhull diff --git a/src/eckit/geo/convexhull/ConvexHullN.h b/src/eckit/geo/convexhull/ConvexHullN.h index 17d18b63a..a1f778d35 100644 --- a/src/eckit/geo/convexhull/ConvexHullN.h +++ b/src/eckit/geo/convexhull/ConvexHullN.h @@ -11,27 +11,25 @@ #pragma once -#include "eckit/geo/convexhull/Qhull.h" +#include "eckit/geo/ConvexHull.h" -#include -#include - - -namespace eckit::geo { -class Grid; -} // namespace eckit::geo +// #include namespace eckit::geo::convexhull { -class ConvexHullN : public Qhull { +class ConvexHullN : public ConvexHull { public: template explicit ConvexHullN(const std::vector>&); explicit ConvexHullN(const std::vector>&); + std::vector> list_vertices() const override; + std::vector> list_facets() const override; + std::vector list_triangles() const override; + private: explicit ConvexHullN(size_t N, const std::vector&); }; diff --git a/src/eckit/geo/triangulation/Triangulation3.cc b/src/eckit/geo/triangulation/Triangulation3.cc index 4e002aaf4..a837c09b4 100644 --- a/src/eckit/geo/triangulation/Triangulation3.cc +++ b/src/eckit/geo/triangulation/Triangulation3.cc @@ -13,8 +13,8 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Grid.h" -#include "eckit/geo/convexhull/Qhull.h" #include "eckit/geo/projection/LonLatToXYZ.h" +#include "eckit/geo/util/Qhull.h" namespace eckit::geo::triangulation { @@ -41,7 +41,7 @@ std::vector grid_to_coord(const Grid& grid) { Triangulation3::Triangulation3(const Grid& grid) : - Triangulation(convexhull::Qhull(3, grid_to_coord(grid), "Qt").list_triangles()) {} + Triangulation(util::Qhull(3, grid_to_coord(grid), "Qt").list_triangles()) {} } // namespace eckit::geo::triangulation diff --git a/src/eckit/geo/convexhull/Qhull.cc b/src/eckit/geo/util/Qhull.cc similarity index 93% rename from src/eckit/geo/convexhull/Qhull.cc rename to src/eckit/geo/util/Qhull.cc index d382b30b3..008ca8a29 100644 --- a/src/eckit/geo/convexhull/Qhull.cc +++ b/src/eckit/geo/util/Qhull.cc @@ -9,7 +9,7 @@ */ -#include "eckit/geo/convexhull/Qhull.h" +#include "eckit/geo/util/Qhull.h" #include "eckit/exception/Exceptions.h" @@ -17,12 +17,11 @@ #include "libqhullcpp/QhullVertexSet.h" -namespace eckit::geo::convexhull { +namespace eckit::geo::util { Qhull::Qhull(size_t N, const std::vector& coord, const std::string& command) { - ASSERT(N > 0); - ASSERT(coord.size() % N == 0); + ASSERT(0 < N && coord.size() % N == 0); auto pointDimension = static_cast(N); auto pointCount = static_cast(coord.size() % N); @@ -87,4 +86,4 @@ std::vector Qhull::list_triangles() const { } -} // namespace eckit::geo::convexhull +} // namespace eckit::geo::util diff --git a/src/eckit/geo/convexhull/Qhull.h b/src/eckit/geo/util/Qhull.h similarity index 92% rename from src/eckit/geo/convexhull/Qhull.h rename to src/eckit/geo/util/Qhull.h index 5ea4dcde8..bfab0c20b 100644 --- a/src/eckit/geo/convexhull/Qhull.h +++ b/src/eckit/geo/util/Qhull.h @@ -20,7 +20,7 @@ #include "libqhullcpp/Qhull.h" -namespace eckit::geo::convexhull { +namespace eckit::geo::util { class Qhull : public ConvexHull { @@ -42,4 +42,4 @@ class Qhull : public ConvexHull { }; -} // namespace eckit::geo::convexhull +} // namespace eckit::geo::util From c4e1692d453f56a3342e56839a6baf3078c96c31 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 8 Dec 2023 15:10:12 +0000 Subject: [PATCH 392/737] eckit::geo triangulation/convex hull --- src/eckit/geo/CMakeLists.txt | 1 - src/eckit/geo/ConvexHull.h | 6 +-- src/eckit/geo/Grid.h | 1 - src/eckit/geo/convexhull/ConvexHullN.cc | 41 ---------------- src/eckit/geo/convexhull/ConvexHullN.h | 62 +++++++++++++++++++++---- src/eckit/geo/util/Qhull.cc | 15 ++---- src/eckit/geo/util/Qhull.h | 8 +++- 7 files changed, 68 insertions(+), 66 deletions(-) delete mode 100644 src/eckit/geo/convexhull/ConvexHullN.cc diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 816d89309..27213a23e 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -138,7 +138,6 @@ endif() if(eckit_HAVE_GEO_CONVEX_HULL) list(APPEND eckit_geo_srcs - convexhull/ConvexHullN.cc convexhull/ConvexHullN.h triangulation/Triangulation3.cc triangulation/Triangulation3.h diff --git a/src/eckit/geo/ConvexHull.h b/src/eckit/geo/ConvexHull.h index 5a3dbe220..9c4ad2d37 100644 --- a/src/eckit/geo/ConvexHull.h +++ b/src/eckit/geo/ConvexHull.h @@ -53,9 +53,9 @@ class ConvexHull { static std::string className() { return "ConvexHull"; } - virtual std::vector> list_vertices() const = 0; - virtual std::vector> list_facets() const = 0; - virtual std::vector list_triangles() const = 0; + virtual std::vector list_vertices() const = 0; + virtual std::vector> list_facets() const = 0; + virtual std::vector list_triangles() const = 0; protected: // -- Constructors diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 135912a5b..5ca238416 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -97,7 +97,6 @@ class Grid { // None // -- Operators - // None Grid& operator=(const Grid&) = delete; Grid& operator=(Grid&&) = delete; diff --git a/src/eckit/geo/convexhull/ConvexHullN.cc b/src/eckit/geo/convexhull/ConvexHullN.cc deleted file mode 100644 index 824e7de35..000000000 --- a/src/eckit/geo/convexhull/ConvexHullN.cc +++ /dev/null @@ -1,41 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/convexhull/ConvexHullN.h" - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/util/Qhull.h" - - -namespace eckit::geo::convexhull { - - -std::vector> ConvexHullN::list_vertices() const { - NOTIMP; -} - - -std::vector> ConvexHullN::list_facets() const { - NOTIMP; -} - - -std::vector ConvexHullN::list_triangles() const { - NOTIMP; -} - - -ConvexHullN::ConvexHullN(size_t N, const std::vector& coord) { - // util::Qhull q(N, coord, "QJ"); -} - - -} // namespace eckit::geo::convexhull diff --git a/src/eckit/geo/convexhull/ConvexHullN.h b/src/eckit/geo/convexhull/ConvexHullN.h index a1f778d35..4681fdf18 100644 --- a/src/eckit/geo/convexhull/ConvexHullN.h +++ b/src/eckit/geo/convexhull/ConvexHullN.h @@ -13,25 +13,71 @@ #include "eckit/geo/ConvexHull.h" -// #include +#include + +#include "eckit/geo/util/Qhull.h" namespace eckit::geo::convexhull { +template class ConvexHullN : public ConvexHull { public: - template - explicit ConvexHullN(const std::vector>&); + // -- Types + + using coord_t = util::Qhull::coord_t; + + // -- Constructors + + explicit ConvexHullN(const coord_t& coord) : + qhull_(N, coord, "QJ") {} + + explicit ConvexHullN(const std::vector>& coord_v) : + ConvexHullN(convert_vector_v(coord_v)) {} + + explicit ConvexHullN(const std::vector>& coord_a) : + ConvexHullN(convert_vector_a(coord_a)) {} + + // -- Methods - explicit ConvexHullN(const std::vector>&); + std::vector list_vertices() const override { return qhull_.list_vertices(); } - std::vector> list_vertices() const override; - std::vector> list_facets() const override; - std::vector list_triangles() const override; + std::vector> list_facets() const override { return qhull_.list_facets(); } + + std::vector list_triangles() const override { return qhull_.list_triangles(); } private: - explicit ConvexHullN(size_t N, const std::vector&); + // -- Methods + + static coord_t convert_vector_v(const std::vector>& coord_v) { + coord_t coord; + coord.reserve(N * coord_v.size()); + + for (const auto& v : coord_v) { + ASSERT(N == v.size()); + for (int i = 0; i < N; ++i) { + coord.emplace_back(v[i]); + } + } + + return coord; + } + + static coord_t convert_vector_a(const std::vector>& coord_a) { + coord_t coord; + coord.reserve(N * coord_a.size()); + for (const auto& a : coord_a) { + for (int i = 0; i < N; ++i) { + coord.emplace_back(a[i]); + } + } + return coord; + } + + // -- Members + + util::Qhull qhull_; }; diff --git a/src/eckit/geo/util/Qhull.cc b/src/eckit/geo/util/Qhull.cc index 008ca8a29..64d2dc2a4 100644 --- a/src/eckit/geo/util/Qhull.cc +++ b/src/eckit/geo/util/Qhull.cc @@ -20,28 +20,23 @@ namespace eckit::geo::util { -Qhull::Qhull(size_t N, const std::vector& coord, const std::string& command) { +Qhull::Qhull(size_t N, const coord_t& coord, const std::string& command) { ASSERT(0 < N && coord.size() % N == 0); auto pointDimension = static_cast(N); - auto pointCount = static_cast(coord.size() % N); + auto pointCount = static_cast(coord.size() / N); qh_ = std::make_unique("", pointDimension, pointCount, coord.data(), command.c_str()); ASSERT(qh_); } -std::vector> Qhull::list_vertices() const { - std::vector> vertices; +std::vector Qhull::list_vertices() const { + std::vector vertices; vertices.reserve(qh_->vertexCount()); - auto N = qh_->dimension(); for (const auto& vertex : qh_->vertexList()) { - const auto point = vertex.point(); - ASSERT(point.dimension() == N); - - const auto* coord = point.coordinates(); - vertices.emplace_back(coord, coord + N); + vertices.emplace_back(vertex.point().id()); } return vertices; diff --git a/src/eckit/geo/util/Qhull.h b/src/eckit/geo/util/Qhull.h index bfab0c20b..80a80fbd9 100644 --- a/src/eckit/geo/util/Qhull.h +++ b/src/eckit/geo/util/Qhull.h @@ -27,11 +27,15 @@ class Qhull : public ConvexHull { public: // -- Types - Qhull(size_t N, const std::vector& coord, const std::string& command); + using coord_t = std::vector; + + // -- Constructors + + Qhull(size_t N, const coord_t& coord, const std::string& command); // -- Overridden methods - std::vector> list_vertices() const override; + std::vector list_vertices() const override; std::vector> list_facets() const override; std::vector list_triangles() const override; From ef869b018f54da07f8654f67361f6566428a6113 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 8 Dec 2023 15:10:29 +0000 Subject: [PATCH 393/737] eckit::geo triangulation/convex hull test --- tests/geo/CMakeLists.txt | 1 + tests/geo/convex_hull_n.cc | 66 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 tests/geo/convex_hull_n.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 7d6e63585..54e20c9b7 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -1,6 +1,7 @@ foreach( _test area_boundingbox area_polygon + convex_hull_n coordinate_helpers figure_sphere figure_sphere_great_circle diff --git a/tests/geo/convex_hull_n.cc b/tests/geo/convex_hull_n.cc new file mode 100644 index 000000000..f4c4c39bd --- /dev/null +++ b/tests/geo/convex_hull_n.cc @@ -0,0 +1,66 @@ +/* + * (C) Copyright 1996- 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 +#include +#include + +#include "eckit/geo/convexhull/ConvexHullN.h" +#include "eckit/testing/Test.h" + + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace eckit::test { + + +using namespace geo; + +using Point2 = std::array; + + +CASE("PointLonLat normalisation") { + std::vector points{{ + {1, 2}, // part of convex hull + {3, 1}, //... + {4, 4}, + {6, 5}, + {7, 2}, //... + {2, 5}, //... + {5, 7}, + {8, 3}, //... + {6, 9}, //... + {9, 6}, //... + }}; + + std::vector vertices_reference{0, 1, 4, 5, 7, 8, 9}; + + convexhull::ConvexHullN ch(points); + auto vertices = ch.list_vertices(); + + EXPECT(vertices.size() == vertices_reference.size()); + for (const auto& vertex : vertices_reference) { + EXPECT(std::find(vertices.begin(), vertices.end(), vertex) != vertices.end()); + } +} + + +} // namespace eckit::test + + +//---------------------------------------------------------------------------------------------------------------------- + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From c3e8f40f3c3265637fda2419d441555190c23823 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 8 Dec 2023 17:02:32 +0000 Subject: [PATCH 394/737] eckit::geo triangulation/convex hull test --- tests/geo/convex_hull_n.cc | 49 ++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/tests/geo/convex_hull_n.cc b/tests/geo/convex_hull_n.cc index f4c4c39bd..56202c368 100644 --- a/tests/geo/convex_hull_n.cc +++ b/tests/geo/convex_hull_n.cc @@ -24,13 +24,10 @@ namespace eckit::test { -using namespace geo; +CASE("ConvexHullN, N=2") { + using Point2 = std::array; -using Point2 = std::array; - - -CASE("PointLonLat normalisation") { - std::vector points{{ + geo::convexhull::ConvexHullN ch(std::vector{ {1, 2}, // part of convex hull {3, 1}, //... {4, 4}, @@ -41,16 +38,42 @@ CASE("PointLonLat normalisation") { {8, 3}, //... {6, 9}, //... {9, 6}, //... - }}; + }); + - std::vector vertices_reference{0, 1, 4, 5, 7, 8, 9}; + SECTION("vertices") { + const auto vertices = ch.list_vertices(); + EXPECT(vertices.size() == 7); + + for (size_t vertex : {0, 1, 4, 5, 7, 8, 9}) { + EXPECT(std::find(vertices.begin(), vertices.end(), vertex) != vertices.end()); + } + + for (size_t vertex : {2, 3, 6}) { + EXPECT(std::find(vertices.begin(), vertices.end(), vertex) == vertices.end()); + } + } - convexhull::ConvexHullN ch(points); - auto vertices = ch.list_vertices(); - EXPECT(vertices.size() == vertices_reference.size()); - for (const auto& vertex : vertices_reference) { - EXPECT(std::find(vertices.begin(), vertices.end(), vertex) != vertices.end()); + SECTION("facets") { + const auto facets = ch.list_facets(); + EXPECT(facets.size() == 7); + + for (const auto& fr : std::vector>{ + {3, 2}, + {5, 1}, + {5, 3}, + {6, 1}, + {6, 4}, + {7, 2}, + {7, 4}, + }) { + ASSERT(fr.size() == 2); + EXPECT(std::count_if(facets.begin(), facets.end(), [&fr](const auto& facet) { + ASSERT(facet.size() == 2); + return (fr[0] == facet[0] && fr[1] == facet[1]) || (fr[0] == facet[1] && fr[1] == facet[0]); + }) == 1); + } } } From 635d4d069e568031ed8e9dc00e0e3450a29ac1f0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 8 Dec 2023 17:29:49 +0000 Subject: [PATCH 395/737] eckit::geo triangulation/convex hull test --- src/eckit/geo/util/Qhull.cc | 8 +-- tests/geo/convex_hull_n.cc | 98 ++++++++++++++++++++++++++++++------- 2 files changed, 85 insertions(+), 21 deletions(-) diff --git a/src/eckit/geo/util/Qhull.cc b/src/eckit/geo/util/Qhull.cc index 64d2dc2a4..b9d88b0d2 100644 --- a/src/eckit/geo/util/Qhull.cc +++ b/src/eckit/geo/util/Qhull.cc @@ -54,7 +54,7 @@ std::vector> Qhull::list_facets() const { f.reserve(vertices.size()); for (const auto& vertex : vertices) { - f.push_back(static_cast(vertex.id())); + f.push_back(static_cast(vertex.point().id())); } facets.emplace_back(f); @@ -72,9 +72,9 @@ std::vector Qhull::list_triangles() const { const auto vertices = facet.vertices(); ASSERT(vertices.size() == 3); - tri.emplace_back(Triangle{static_cast(vertices[0].id()), - static_cast(vertices[1].id()), - static_cast(vertices[2].id())}); + tri.emplace_back(Triangle{static_cast(vertices[0].point().id()), + static_cast(vertices[1].point().id()), + static_cast(vertices[2].point().id())}); } return tri; diff --git a/tests/geo/convex_hull_n.cc b/tests/geo/convex_hull_n.cc index 56202c368..5c73bc108 100644 --- a/tests/geo/convex_hull_n.cc +++ b/tests/geo/convex_hull_n.cc @@ -27,17 +27,18 @@ namespace eckit::test { CASE("ConvexHullN, N=2") { using Point2 = std::array; + // Polygon (vertices 0, 1, 4, 5, 7, 8, 9) containing point indices 2, 3, 6 geo::convexhull::ConvexHullN ch(std::vector{ - {1, 2}, // part of convex hull - {3, 1}, //... + {1, 2}, + {3, 1}, {4, 4}, {6, 5}, - {7, 2}, //... - {2, 5}, //... + {7, 2}, + {2, 5}, {5, 7}, - {8, 3}, //... - {6, 9}, //... - {9, 6}, //... + {8, 3}, + {6, 9}, + {9, 6}, }); @@ -59,21 +60,84 @@ CASE("ConvexHullN, N=2") { const auto facets = ch.list_facets(); EXPECT(facets.size() == 7); - for (const auto& fr : std::vector>{ - {3, 2}, - {5, 1}, - {5, 3}, - {6, 1}, - {6, 4}, - {7, 2}, - {7, 4}, - }) { - ASSERT(fr.size() == 2); + for (const auto& fr : {std::vector{8, 9}, {5, 0}, {5, 8}, {1, 0}, {1, 4}, {7, 9}, {7, 4}}) { EXPECT(std::count_if(facets.begin(), facets.end(), [&fr](const auto& facet) { ASSERT(facet.size() == 2); return (fr[0] == facet[0] && fr[1] == facet[1]) || (fr[0] == facet[1] && fr[1] == facet[0]); }) == 1); } + + for (size_t vertex : {2, 3, 6}) { + for (const auto& facet : facets) { + EXPECT(std::find(facet.begin(), facet.end(), vertex) == facet.end()); + } + } + } +} + + +CASE("ConvexHullN, N=3") { + using Point3 = std::array; + + // Tetrahedron (vertices 0, 1, 2, 3) containing point index 4 + geo::convexhull::ConvexHullN ch(std::vector{ + {0, 0, 1}, + {1, 0, -1}, + {-1, 1, -1}, + {-1, -1, -1}, + {0, 0, 0}, + }); + + + SECTION("vertices") { + const auto vertices = ch.list_vertices(); + EXPECT(vertices.size() == 4); + + for (size_t vertex = 0; vertex < 4; ++vertex) { + EXPECT(std::find(vertices.begin(), vertices.end(), vertex) != vertices.end()); + } + + EXPECT(std::find(vertices.begin(), vertices.end(), 4) == vertices.end()); + } + + + SECTION("facets") { + const auto facets = ch.list_facets(); + EXPECT(facets.size() == 4); + + for (const auto& fr : { + std::vector{0, 1, 2}, + {0, 1, 3}, + {0, 2, 3}, + {1, 2, 3}, + }) { + EXPECT(std::count_if(facets.begin(), facets.end(), [&fr](const auto& facet) { + ASSERT(facet.size() == 3); + return std::count(fr.begin(), fr.end(), facet[0]) == 1 && + std::count(fr.begin(), fr.end(), facet[1]) == 1 && + std::count(fr.begin(), fr.end(), facet[2]) == 1; + }) == 1); + } + } + + + SECTION("triangles") { + const auto triangles = ch.list_triangles(); + EXPECT(triangles.size() == 4); + + for (const auto& tr : { + std::vector{0, 1, 2}, + {0, 1, 3}, + {0, 2, 3}, + {1, 2, 3}, + }) { + EXPECT(std::count_if(triangles.begin(), triangles.end(), [&tr](const auto& tri) { + ASSERT(tri.size() == 3); + return std::count(tr.begin(), tr.end(), tri[0]) == 1 && + std::count(tr.begin(), tr.end(), tri[1]) == 1 && + std::count(tr.begin(), tr.end(), tri[2]) == 1; + }) == 1); + } } } From f0eb7c9589e9fed5e6ce7dc492fb87efc057ad44 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 8 Dec 2023 18:22:31 +0000 Subject: [PATCH 396/737] eckit::geo triangulation/convex hull test --- src/eckit/geo/CMakeLists.txt | 1 + src/eckit/geo/ConvexHull.h | 2 +- src/eckit/geo/convexhull/ConvexHullN.cc | 29 ++++++++++++ src/eckit/geo/convexhull/ConvexHullN.h | 3 -- tests/geo/convex_hull_n.cc | 61 +++++++++++++++++-------- 5 files changed, 73 insertions(+), 23 deletions(-) create mode 100644 src/eckit/geo/convexhull/ConvexHullN.cc diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 27213a23e..816d89309 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -138,6 +138,7 @@ endif() if(eckit_HAVE_GEO_CONVEX_HULL) list(APPEND eckit_geo_srcs + convexhull/ConvexHullN.cc convexhull/ConvexHullN.h triangulation/Triangulation3.cc triangulation/Triangulation3.h diff --git a/src/eckit/geo/ConvexHull.h b/src/eckit/geo/ConvexHull.h index 9c4ad2d37..a11b9a773 100644 --- a/src/eckit/geo/ConvexHull.h +++ b/src/eckit/geo/ConvexHull.h @@ -33,7 +33,7 @@ class ConvexHull { using Triangle = std::array; using builder_t = BuilderT1; - using ARG1 = const Configuration&; + using ARG1 = const std::vector>&; // TODO use std::vector // -- Constructors diff --git a/src/eckit/geo/convexhull/ConvexHullN.cc b/src/eckit/geo/convexhull/ConvexHullN.cc new file mode 100644 index 000000000..e5d96c34d --- /dev/null +++ b/src/eckit/geo/convexhull/ConvexHullN.cc @@ -0,0 +1,29 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/convexhull/ConvexHullN.h" + + +namespace eckit::geo::convexhull { + + +static ConvexHullBuilder> __convexhulln2("convex-hull-n-2"); +static ConvexHullBuilder> __convexhulln3("convex-hull-n-3"); +static ConvexHullBuilder> __convexhulln4("convex-hull-n-4"); +static ConvexHullBuilder> __convexhulln5("convex-hull-n-5"); +static ConvexHullBuilder> __convexhulln6("convex-hull-n-6"); +static ConvexHullBuilder> __convexhulln7("convex-hull-n-7"); +static ConvexHullBuilder> __convexhulln8("convex-hull-n-8"); +static ConvexHullBuilder> __convexhulln9("convex-hull-n-9"); +// ... + + +} // namespace eckit::geo::convexhull diff --git a/src/eckit/geo/convexhull/ConvexHullN.h b/src/eckit/geo/convexhull/ConvexHullN.h index 4681fdf18..ea4f55b7a 100644 --- a/src/eckit/geo/convexhull/ConvexHullN.h +++ b/src/eckit/geo/convexhull/ConvexHullN.h @@ -12,9 +12,6 @@ #pragma once #include "eckit/geo/ConvexHull.h" - -#include - #include "eckit/geo/util/Qhull.h" diff --git a/tests/geo/convex_hull_n.cc b/tests/geo/convex_hull_n.cc index 5c73bc108..fc28bfbd7 100644 --- a/tests/geo/convex_hull_n.cc +++ b/tests/geo/convex_hull_n.cc @@ -12,6 +12,8 @@ #include #include +#include +#include #include #include "eckit/geo/convexhull/ConvexHullN.h" @@ -73,6 +75,38 @@ CASE("ConvexHullN, N=2") { } } } + + + SECTION("factory") { + // same as above + std::unique_ptr ch2(geo::ConvexHullFactory::instance() + .get("convex-hull-n-2") + .create(std::vector>{ + {1, 2}, + {3, 1}, + {4, 4}, + {6, 5}, + {7, 2}, + {2, 5}, + {5, 7}, + {8, 3}, + {6, 9}, + {9, 6}, + })); + + auto vertex_set = [](const std::vector& list) { return std::set{list.cbegin(), list.cend()}; }; + EXPECT(vertex_set(ch.list_vertices()) == vertex_set(ch2->list_vertices())); + + // wrong dimensions + EXPECT_THROWS_AS(geo::ConvexHullFactory::instance() + .get("convex-hull-n-3") + .create(std::vector>{ + {1, 2}, + {3, 1}, + {4, 4}, + }), + AssertionFailed); + } } @@ -101,10 +135,13 @@ CASE("ConvexHullN, N=3") { } - SECTION("facets") { + SECTION("facets/triangles") { const auto facets = ch.list_facets(); EXPECT(facets.size() == 4); + const auto triangles = ch.list_triangles(); + EXPECT(triangles.size() == 4); + for (const auto& fr : { std::vector{0, 1, 2}, {0, 1, 3}, @@ -117,25 +154,11 @@ CASE("ConvexHullN, N=3") { std::count(fr.begin(), fr.end(), facet[1]) == 1 && std::count(fr.begin(), fr.end(), facet[2]) == 1; }) == 1); - } - } - - SECTION("triangles") { - const auto triangles = ch.list_triangles(); - EXPECT(triangles.size() == 4); - - for (const auto& tr : { - std::vector{0, 1, 2}, - {0, 1, 3}, - {0, 2, 3}, - {1, 2, 3}, - }) { - EXPECT(std::count_if(triangles.begin(), triangles.end(), [&tr](const auto& tri) { - ASSERT(tri.size() == 3); - return std::count(tr.begin(), tr.end(), tri[0]) == 1 && - std::count(tr.begin(), tr.end(), tri[1]) == 1 && - std::count(tr.begin(), tr.end(), tri[2]) == 1; + EXPECT(std::count_if(triangles.begin(), triangles.end(), [&fr](const auto& tri) { + return std::count(fr.begin(), fr.end(), tri[0]) == 1 && + std::count(fr.begin(), fr.end(), tri[1]) == 1 && + std::count(fr.begin(), fr.end(), tri[2]) == 1; }) == 1); } } From 47283a93af1af79f809460f2d8dd8ba66834e648 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 12 Dec 2023 14:31:46 +0000 Subject: [PATCH 397/737] eckit::geo triangulation/convex hull --- src/eckit/geo/CMakeLists.txt | 2 -- src/eckit/geo/ConvexHull.cc | 0 src/eckit/geo/Triangulation.cc | 0 3 files changed, 2 deletions(-) delete mode 100644 src/eckit/geo/ConvexHull.cc delete mode 100644 src/eckit/geo/Triangulation.cc diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 816d89309..1ffffd5a2 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -11,7 +11,6 @@ list(APPEND eckit_geo_srcs Cache.cc Cache.h Configurator.h - ConvexHull.cc ConvexHull.h CoordinateHelpers.cc CoordinateHelpers.h @@ -52,7 +51,6 @@ list(APPEND eckit_geo_srcs Sphere.cc Sphere.h SphereT.h - Triangulation.cc Triangulation.h UnitSphere.h area/BoundingBox.cc diff --git a/src/eckit/geo/ConvexHull.cc b/src/eckit/geo/ConvexHull.cc deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/eckit/geo/Triangulation.cc b/src/eckit/geo/Triangulation.cc deleted file mode 100644 index e69de29bb..000000000 From 43edbaacd5fd62e1942a93cbb4e349c73e74b9da Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 12 Dec 2023 17:24:03 +0000 Subject: [PATCH 398/737] eckit::geo::GreatCircle::course --- src/atlas/util/UnitSphere.h | 69 ------------------------------------ src/eckit/geo/GreatCircle.cc | 52 +++++++++++++++++---------- src/eckit/geo/GreatCircle.h | 24 +++++++++---- 3 files changed, 51 insertions(+), 94 deletions(-) delete mode 100644 src/atlas/util/UnitSphere.h diff --git a/src/atlas/util/UnitSphere.h b/src/atlas/util/UnitSphere.h deleted file mode 100644 index 1f38e455d..000000000 --- a/src/atlas/util/UnitSphere.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * (C) Copyright 2013 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. - */ - -#pragma once - -#include -#include - -#include "atlas/util/Constants.h" -#include "atlas/util/Point.h" - -#include "eckit/geometry/UnitSphere.h" - -//------------------------------------------------------------------------------------------------------ - -namespace atlas { -namespace util { - -//------------------------------------------------------------------------------------------------------ - -using eckit::geometry::UnitSphere; - -/// @brief Calculate great-cricle course between points -/// -/// @details Calculates the direction (clockwise from north) of a great-circle -/// arc between lonLat1 and lonLat2. Returns the direction of the arc -/// at lonLat1 (first) and lonLat2 (second). Angle is normalised to the -/// range of atan2 (usually (-180, 180]). All input and output values -/// are in units of degrees. -/// @ref https://en.wikipedia.org/wiki/Great-circle_navigation -/// -inline std::pair greatCircleCourse(const Point2& lonLat1, - const Point2& lonLat2) { - - const auto lambda1 = lonLat1[0] * Constants::degreesToRadians(); - const auto lambda2 = lonLat2[0] * Constants::degreesToRadians(); - const auto phi1 = lonLat1[1] * Constants::degreesToRadians(); - const auto phi2 = lonLat2[1] * Constants::degreesToRadians(); - - const auto sinLambda12 = std::sin(lambda2 - lambda1); - const auto cosLambda12 = std::cos(lambda2 - lambda1); - const auto sinPhi1 = std::sin(phi1); - const auto sinPhi2 = std::sin(phi2); - const auto cosPhi1 = std::cos(phi1); - const auto cosPhi2 = std::cos(phi2); - - const auto alpha1 = - std::atan2(cosPhi2 * sinLambda12, - cosPhi1 * sinPhi2 - sinPhi1 * cosPhi2 * cosLambda12); - - const auto alpha2 = - std::atan2(cosPhi1 * sinLambda12, - -cosPhi2 * sinPhi1 + sinPhi2 * cosPhi1 * cosLambda12); - - return std::make_pair(alpha1 * Constants::radiansToDegrees(), - alpha2 * Constants::radiansToDegrees()); -}; - -//------------------------------------------------------------------------------------------------------ - -} // namespace util -} // namespace atlas diff --git a/src/eckit/geo/GreatCircle.cc b/src/eckit/geo/GreatCircle.cc index b99f291d6..92eca2eba 100644 --- a/src/eckit/geo/GreatCircle.cc +++ b/src/eckit/geo/GreatCircle.cc @@ -15,6 +15,7 @@ #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" //---------------------------------------------------------------------------------------------------------------------- @@ -25,10 +26,6 @@ namespace eckit::geo { using types::is_approximately_equal; -static const double radians_to_degrees = 180. * M_1_PI; - -static const double degrees_to_radians = M_PI / 180.; - static bool pole(const double lat) { return is_approximately_equal(std::abs(lat), 90.); } @@ -61,15 +58,15 @@ std::vector GreatCircle::latitude(double lon) const { return {}; } - const double lat1 = degrees_to_radians * A_.lat; - const double lat2 = degrees_to_radians * B_.lat; - const double lambda1p = degrees_to_radians * (lon - A_.lon); - const double lambda2p = degrees_to_radians * (lon - B_.lon); - const double lambda = degrees_to_radians * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, -180.); + const double lat1 = util::degree_to_radian * A_.lat; + const double lat2 = util::degree_to_radian * B_.lat; + const double lambda1p = util::degree_to_radian * (lon - A_.lon); + const double lambda2p = util::degree_to_radian * (lon - B_.lon); + const double lambda = util::degree_to_radian * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, -180.); double lat = std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); - return {radians_to_degrees * lat}; + return {util::radian_to_degree * lat}; } std::vector GreatCircle::longitude(double lat) const { @@ -82,11 +79,11 @@ std::vector GreatCircle::longitude(double lat) const { return {lon, lon + 180.}; } - const double lon12 = degrees_to_radians * PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); - const double lon1 = degrees_to_radians * A_.lon; - const double lat1 = degrees_to_radians * A_.lat; - const double lat2 = degrees_to_radians * B_.lat; - const double lat3 = degrees_to_radians * lat; + const double lon12 = util::degree_to_radian * PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); + const double lon1 = util::degree_to_radian * A_.lon; + const double lat1 = util::degree_to_radian * A_.lat; + const double lat2 = util::degree_to_radian * B_.lat; + const double lat3 = util::degree_to_radian * lat; const double X = std::sin(lat1) * std::cos(lat2) * std::sin(lon12); const double Y = std::sin(lat1) * std::cos(lat2) * std::cos(lon12) - std::cos(lat1) * std::sin(lat2); @@ -99,16 +96,16 @@ std::vector GreatCircle::longitude(double lat) const { const double C = std::cos(lat1) * std::cos(lat2) * std::tan(lat3) * std::sin(lon12) / std::sqrt(X * X + Y * Y); if (is_approximately_equal(C, -1.)) { - return {radians_to_degrees * (lon0 + M_PI)}; + return {util::radian_to_degree * (lon0 + M_PI)}; } if (is_approximately_equal(C, 1.)) { - return {radians_to_degrees * lon0}; + return {util::radian_to_degree * lon0}; } if (-1 < C && C < 1) { const double dlon = std::acos(C); - return {radians_to_degrees * (lon0 - dlon + 2 * M_PI), radians_to_degrees * (lon0 + dlon)}; + return {util::radian_to_degree * (lon0 - dlon + 2 * M_PI), util::radian_to_degree * (lon0 + dlon)}; } return {}; @@ -118,6 +115,25 @@ bool GreatCircle::crossesPoles() const { return crossesPoles_; } +std::pair GreatCircle::calculate_course(const PointLonLat& lonLat1, const PointLonLat& lonLat2) { + const auto lambda1 = lonLat1.lon * util::degree_to_radian; + const auto lambda2 = lonLat2.lon * util::degree_to_radian; + const auto phi1 = lonLat1.lat * util::degree_to_radian; + const auto phi2 = lonLat2.lat * util::degree_to_radian; + + const auto sinLambda12 = std::sin(lambda2 - lambda1); + const auto cosLambda12 = std::cos(lambda2 - lambda1); + const auto sinPhi1 = std::sin(phi1); + const auto sinPhi2 = std::sin(phi2); + const auto cosPhi1 = std::cos(phi1); + const auto cosPhi2 = std::cos(phi2); + + const auto alpha1 = std::atan2(cosPhi2 * sinLambda12, cosPhi1 * sinPhi2 - sinPhi1 * cosPhi2 * cosLambda12); + const auto alpha2 = std::atan2(cosPhi1 * sinLambda12, -cosPhi2 * sinPhi1 + sinPhi2 * cosPhi1 * cosLambda12); + + return std::make_pair(alpha1 * util::radian_to_degree, alpha2 * util::radian_to_degree); +} + //---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geo diff --git a/src/eckit/geo/GreatCircle.h b/src/eckit/geo/GreatCircle.h index 55b8e627f..5a7a24ad9 100644 --- a/src/eckit/geo/GreatCircle.h +++ b/src/eckit/geo/GreatCircle.h @@ -8,18 +8,17 @@ * does it submit to any jurisdiction. */ -#ifndef GreatCircle_H -#define GreatCircle_H +#pragma once + +#include #include #include "eckit/geo/PointLonLat.h" -//------------------------------------------------------------------------------------------------------ namespace eckit::geo { -//------------------------------------------------------------------------------------------------------ class GreatCircle { public: @@ -32,8 +31,22 @@ class GreatCircle { /// Great circle longitude given latitude, see http://www.edwilliams.org/avform.htm#Par std::vector longitude(double lat) const; + // Calculate great circle course between two points + std::pair course(const PointLonLat& A, const PointLonLat& B) { return calculate_course(A_, B_); } + bool crossesPoles() const; + /** + * @brief Calculate great circle course between two points + * + * @details Calculates the direction (clockwise from North) of a great circle arc between two points. Returns the + * direction (angle) of the arc at each, normalised to the range of atan2 (usually (-180, 180]). All input and + * output values are in units of degrees. + * + * @ref https://en.wikipedia.org/wiki/Great-circle_navigation + */ + static std::pair calculate_course(const PointLonLat&, const PointLonLat&); + private: const PointLonLat A_; const PointLonLat B_; @@ -41,8 +54,5 @@ class GreatCircle { bool crossesPoles_; }; -//------------------------------------------------------------------------------------------------------ } // namespace eckit::geo - -#endif From 4241a20793701a287af3b9975dc2eacfa2e6a545 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 12 Dec 2023 17:49:35 +0000 Subject: [PATCH 399/737] eckit::geo::GreatCircle::course --- src/eckit/geo/GreatCircle.cc | 29 ++++++++----------- tests/geo/CMakeLists.txt | 2 +- ...sphere_great_circle.cc => great_circle.cc} | 24 ++++++++++++++- 3 files changed, 36 insertions(+), 19 deletions(-) rename tests/geo/{figure_sphere_great_circle.cc => great_circle.cc} (91%) diff --git a/src/eckit/geo/GreatCircle.cc b/src/eckit/geo/GreatCircle.cc index 92eca2eba..3057d5010 100644 --- a/src/eckit/geo/GreatCircle.cc +++ b/src/eckit/geo/GreatCircle.cc @@ -115,23 +115,18 @@ bool GreatCircle::crossesPoles() const { return crossesPoles_; } -std::pair GreatCircle::calculate_course(const PointLonLat& lonLat1, const PointLonLat& lonLat2) { - const auto lambda1 = lonLat1.lon * util::degree_to_radian; - const auto lambda2 = lonLat2.lon * util::degree_to_radian; - const auto phi1 = lonLat1.lat * util::degree_to_radian; - const auto phi2 = lonLat2.lat * util::degree_to_radian; - - const auto sinLambda12 = std::sin(lambda2 - lambda1); - const auto cosLambda12 = std::cos(lambda2 - lambda1); - const auto sinPhi1 = std::sin(phi1); - const auto sinPhi2 = std::sin(phi2); - const auto cosPhi1 = std::cos(phi1); - const auto cosPhi2 = std::cos(phi2); - - const auto alpha1 = std::atan2(cosPhi2 * sinLambda12, cosPhi1 * sinPhi2 - sinPhi1 * cosPhi2 * cosLambda12); - const auto alpha2 = std::atan2(cosPhi1 * sinLambda12, -cosPhi2 * sinPhi1 + sinPhi2 * cosPhi1 * cosLambda12); - - return std::make_pair(alpha1 * util::radian_to_degree, alpha2 * util::radian_to_degree); +std::pair GreatCircle::calculate_course(const PointLonLat& A, const PointLonLat& B) { + const auto sdl = std::sin(util::degree_to_radian * (B.lon - A.lon)); + const auto cdl = std::cos(util::degree_to_radian * (B.lon - A.lon)); + const auto spA = std::sin(util::degree_to_radian * A.lat); + const auto cpA = std::cos(util::degree_to_radian * A.lat); + const auto spB = std::sin(util::degree_to_radian * B.lat); + const auto cpB = std::cos(util::degree_to_radian * B.lat); + + const auto alpha1 = util::radian_to_degree * std::atan2(cpB * sdl, cpA * spB - spA * cpB * cdl); + const auto alpha2 = util::radian_to_degree * std::atan2(cpA * sdl, -cpB * spA + spB * cpA * cdl); + + return {alpha1, alpha2}; } //---------------------------------------------------------------------------------------------------------------------- diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 54e20c9b7..89b904aba 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -4,7 +4,7 @@ foreach( _test convex_hull_n coordinate_helpers figure_sphere - figure_sphere_great_circle + great_circle grid grid_regular_ll grid_reorder diff --git a/tests/geo/figure_sphere_great_circle.cc b/tests/geo/great_circle.cc similarity index 91% rename from tests/geo/figure_sphere_great_circle.cc rename to tests/geo/great_circle.cc index 309fc0d89..9f0c50c3e 100644 --- a/tests/geo/figure_sphere_great_circle.cc +++ b/tests/geo/great_circle.cc @@ -1,5 +1,6 @@ /* * (C) Copyright 1996- ECMWF. + * (C) Crown Copyright 2023 Met Office. * * 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. @@ -18,6 +19,9 @@ #include "eckit/geo/PointLonLat.h" #include "eckit/testing/Test.h" +#define EXPECT_APPROX(a, b, eps) EXPECT(::eckit::types::is_approximately_equal((a), (b), (eps))) + + namespace eckit::test { @@ -27,7 +31,7 @@ using namespace geo; // ----------------------------------------------------------------------------- -CASE("test great circles intersections") { +CASE("great circle intersections") { using types::is_approximately_equal; using types::is_approximately_greater_or_equal; @@ -241,6 +245,24 @@ CASE("test great circles intersections") { // ----------------------------------------------------------------------------- +CASE("great circle course") { + SECTION("Valparaíso-Shanghai") { + const auto [course1, course2] = GreatCircle::calculate_course({-71.6, -33.}, {121.8, 31.4}); + + EXPECT_APPROX(-94.41, course1, 0.01); + EXPECT_APPROX(-78.42, course2, 0.01); + } + + SECTION("polar") { + const auto [course3, course4] = GreatCircle::calculate_course({0., 89.}, {180., 89.}); + + EXPECT_APPROX(0., course3, 1.e-14); + EXPECT_APPROX(180., std::abs(course4), 1.e-14); + } +} + +// ----------------------------------------------------------------------------- + } // namespace eckit::test int main(int argc, char** argv) { From dc1e981021920afeb9b7d54d6bf63861e7a63562 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 20 Dec 2023 08:45:44 +0000 Subject: [PATCH 400/737] eckit::geo qhull --- CMakeLists.txt | 17 ++++++++++++----- src/tools/CMakeLists.txt | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d6257bc49..75f236007 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,13 +163,20 @@ ecbuild_add_option( FEATURE GEO_CACHING DESCRIPTION "eckit::geo geometry library default caching behaviour" ) ecbuild_add_option( FEATURE GEO_CONVEX_HULL - DEFAULT ON + DEFAULT OFF CONDITION HAVE_ECKIT_GEO - DESCRIPTION "eckit::geo geometry library convex hull/Delaunay triangulation" - REQUIRED_PACKAGES "Qhull COMPONENTS C CXX" ) + DESCRIPTION "eckit::geo geometry library convex hull/Delaunay triangulation" ) + # REQUIRED_PACKAGES "Qhull COMPONENTS C CXX" + +if( eckit_HAVE_GEO_CONVEX_HULL ) + find_package( Qhull REQUIRED CONFIG ) + + if( NOT TARGET Qhull::qhullcpp OR NOT TARGET Qhull::qhullstatic_r ) + message( FATAL_ERROR "eckit::geo ENABLE_GEO_CONVEX_HULL requires Qhull C/C++ libraries" ) + endif() -if( eckit_HAVE_GEO_CONVEX_HULL AND NOT TARGET Qhull::Qhull ) - message(FATAL_ERROR "eckit::geo ENABLE_GEO_CONVEX_HULL requires Qhull C/C++ libraries") + add_library(Qhull::Qhull INTERFACE IMPORTED) + target_link_libraries(Qhull::Qhull INTERFACE Qhull::qhullcpp Qhull::qhullstatic_r ) endif() set( eckit_GEO_CACHE_PATH "/tmp/cache" ) diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 82bc22803..f11087fa2 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -34,7 +34,7 @@ ecbuild_add_executable( TARGET eckit_grid_triangulation OUTPUT_NAME eckit-grid-triangulation CONDITION eckit_HAVE_ECKIT_GEO AND eckit_HAVE_GEO_CONVEX_HULL SOURCES eckit-grid-triangulation.cc - LIBS eckit_geo eckit_option Qhull::Qhull ) + LIBS eckit_geo eckit_option ) ### NOT TO INSTALL From bf4142b843f4bcc79a9f5429afb97f60894853df Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 20 Dec 2023 08:46:29 +0000 Subject: [PATCH 401/737] eckit::geo qhull --- src/eckit/geo/util/Qhull.cc | 29 +++++++++++++++++++++-------- src/eckit/geo/util/Qhull.h | 14 +++++++++++--- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/eckit/geo/util/Qhull.cc b/src/eckit/geo/util/Qhull.cc index b9d88b0d2..aa406cdb5 100644 --- a/src/eckit/geo/util/Qhull.cc +++ b/src/eckit/geo/util/Qhull.cc @@ -11,7 +11,10 @@ #include "eckit/geo/util/Qhull.h" +#include + #include "eckit/exception/Exceptions.h" +#include "eckit/log/Log.h" #include "libqhullcpp/QhullFacetList.h" #include "libqhullcpp/QhullVertexSet.h" @@ -26,16 +29,26 @@ Qhull::Qhull(size_t N, const coord_t& coord, const std::string& command) { auto pointDimension = static_cast(N); auto pointCount = static_cast(coord.size() / N); - qh_ = std::make_unique("", pointDimension, pointCount, coord.data(), command.c_str()); - ASSERT(qh_); + std::ostringstream err; + qh_.setErrorStream(&err); + qh_.setOutputStream(&Log::info()); + qh_.enableOutputStream(); + + try { + qh_.runQhull("", pointDimension, pointCount, coord.data(), command.c_str()); + ASSERT(qh_.qhullStatus() == 0); + } + catch (const orgQhull::QhullError& e) { + throw Exception(err.str(), e.errorCode(), command); + } } std::vector Qhull::list_vertices() const { std::vector vertices; - vertices.reserve(qh_->vertexCount()); + vertices.reserve(qh_.vertexCount()); - for (const auto& vertex : qh_->vertexList()) { + for (const auto& vertex : qh_.vertexList()) { vertices.emplace_back(vertex.point().id()); } @@ -45,9 +58,9 @@ std::vector Qhull::list_vertices() const { std::vector> Qhull::list_facets() const { std::vector> facets; - facets.reserve(qh_->facetCount()); + facets.reserve(qh_.facetCount()); - for (const auto& facet : qh_->facetList()) { + for (const auto& facet : qh_.facetList()) { const auto vertices = facet.vertices(); std::vector f; @@ -66,9 +79,9 @@ std::vector> Qhull::list_facets() const { std::vector Qhull::list_triangles() const { std::vector tri; - tri.reserve(qh_->facetCount()); + tri.reserve(qh_.facetCount()); - for (const auto& facet : qh_->facetList()) { + for (const auto& facet : qh_.facetList()) { const auto vertices = facet.vertices(); ASSERT(vertices.size() == 3); diff --git a/src/eckit/geo/util/Qhull.h b/src/eckit/geo/util/Qhull.h index 80a80fbd9..ee2c2f850 100644 --- a/src/eckit/geo/util/Qhull.h +++ b/src/eckit/geo/util/Qhull.h @@ -11,12 +11,13 @@ #pragma once -#include "eckit/geo/ConvexHull.h" -#include #include #include +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/ConvexHull.h" + #include "libqhullcpp/Qhull.h" @@ -29,6 +30,13 @@ class Qhull : public ConvexHull { using coord_t = std::vector; + struct Exception : eckit::Exception { + Exception(const std::string& what, int _errorCode, const std::string& _command) : + eckit::Exception(what), errorCode(_errorCode), command(_command) {} + const int errorCode; + const std::string& command; + }; + // -- Constructors Qhull(size_t N, const coord_t& coord, const std::string& command); @@ -42,7 +50,7 @@ class Qhull : public ConvexHull { private: // -- Members - std::unique_ptr qh_; + orgQhull::Qhull qh_; }; From c984945823d809c6dbe5ae530cb8c4fffcc394c3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 20 Dec 2023 08:47:41 +0000 Subject: [PATCH 402/737] eckit::geo qhull --- tests/geo/CMakeLists.txt | 7 ++++++ tests/geo/qhull.cc | 47 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/geo/qhull.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 89b904aba..31a82b484 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -26,3 +26,10 @@ foreach( _test ) endforeach() +ecbuild_add_test( + TARGET eckit_test_geo_qhull + SOURCES qhull.cc + LIBS eckit_geo + CONDITION eckit_HAVE_GEO_CONVEX_HULL +) + diff --git a/tests/geo/qhull.cc b/tests/geo/qhull.cc new file mode 100644 index 000000000..1841e1e86 --- /dev/null +++ b/tests/geo/qhull.cc @@ -0,0 +1,47 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/util/Qhull.h" +#include "eckit/testing/Test.h" + + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace eckit::test { + + +CASE("QHull error codes") { + using geo::util::Qhull; + + + SECTION("QH6214 qhull input error: not enough points(1) to construct initial simplex (need 3)") { + try { + Qhull(2, {1, 1}, "Qt"); + EXPECT(false); + } + catch (const Qhull::QhullException& e) { + EXPECT(e.errorCode == 6214); + } + } +} + + +} // namespace eckit::test + + +//---------------------------------------------------------------------------------------------------------------------- + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From c62d4830eed87f4dfedb3f86776b86a7e6bf9df5 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 20 Dec 2023 12:09:52 +0000 Subject: [PATCH 403/737] eckit::geo qhull --- tests/geo/qhull.cc | 58 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/tests/geo/qhull.cc b/tests/geo/qhull.cc index 1841e1e86..125f06ad1 100644 --- a/tests/geo/qhull.cc +++ b/tests/geo/qhull.cc @@ -11,6 +11,7 @@ #include "eckit/geo/util/Qhull.h" +#include "eckit/exception/Exceptions.h" #include "eckit/testing/Test.h" @@ -20,19 +21,72 @@ namespace eckit::test { -CASE("QHull error codes") { +CASE("QHull assertions") { using geo::util::Qhull; + SECTION("Assertion failed: 0 < N && coord.size() % N == 0 in Qhull") { + for (size_t N : {2, 3, 4}) { + Qhull::coord_t coord((N + 1) * N + 1, 1.); + ASSERT(coord.size() % N != 0); + EXPECT_THROWS_AS(Qhull(N, coord, "Qt"), AssertionFailed); + } + } + + + SECTION("QH6050 qhull error: dimension 1 must be > 1") { + try { + Qhull(1, {1, 1}, "Qt"); + EXPECT(false); + } + catch (const Qhull::Exception& e) { + EXPECT(e.errorCode == 6050); + } + } + + + SECTION("QH6154 Qhull precision error: Initial simplex is flat (facet 1 is coplanar with the interior point)") { + try { + Qhull(2, {1, 1, 2, 2, 3, 3, 4, 4}, "Qt"); + EXPECT(false); + } + catch (const Qhull::Exception& e) { + EXPECT(e.errorCode == 6154); + } + } + + SECTION("QH6214 qhull input error: not enough points(1) to construct initial simplex (need 3)") { try { Qhull(2, {1, 1}, "Qt"); EXPECT(false); } - catch (const Qhull::QhullException& e) { + catch (const Qhull::Exception& e) { EXPECT(e.errorCode == 6214); } } + + + SECTION("QH6412 qhull input error (qh_initqhull_globals): expecting between 1 and 2147483631 points") { + try { + Qhull(2, {}, "Qt"); + EXPECT(false); + } + catch (const Qhull::Exception& e) { + EXPECT(e.errorCode == 6412); + } + } + + + SECTION("QH6421 qhull internal error (qh_maxsimplex): qh.MAXwidth required for qh_maxsimplex") { + try { + Qhull(2, {1, 1, 1, 1, 1, 1}, "Qt"); + EXPECT(false); + } + catch (const Qhull::Exception& e) { + EXPECT(e.errorCode == 6421); + } + } } From f9aff43da27afd8906d3ced18455d3ba0b1b73f9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 20 Dec 2023 12:28:19 +0000 Subject: [PATCH 404/737] eckit::geo qhull --- src/eckit/geo/util/Qhull.cc | 2 +- tests/geo/qhull.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/eckit/geo/util/Qhull.cc b/src/eckit/geo/util/Qhull.cc index aa406cdb5..bed852dfb 100644 --- a/src/eckit/geo/util/Qhull.cc +++ b/src/eckit/geo/util/Qhull.cc @@ -67,7 +67,7 @@ std::vector> Qhull::list_facets() const { f.reserve(vertices.size()); for (const auto& vertex : vertices) { - f.push_back(static_cast(vertex.point().id())); + f.emplace_back(vertex.point().id()); } facets.emplace_back(f); diff --git a/tests/geo/qhull.cc b/tests/geo/qhull.cc index 125f06ad1..7b2fd5ed5 100644 --- a/tests/geo/qhull.cc +++ b/tests/geo/qhull.cc @@ -21,7 +21,7 @@ namespace eckit::test { -CASE("QHull assertions") { +CASE("QHull exceptions") { using geo::util::Qhull; From 5549b4a57a7d5a01103d307c04b86072ed234849 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 20 Dec 2023 13:22:49 +0000 Subject: [PATCH 405/737] eckit::geo qhull --- tests/geo/qhull.cc | 81 ++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 54 deletions(-) diff --git a/tests/geo/qhull.cc b/tests/geo/qhull.cc index 7b2fd5ed5..08497a2c8 100644 --- a/tests/geo/qhull.cc +++ b/tests/geo/qhull.cc @@ -21,70 +21,43 @@ namespace eckit::test { -CASE("QHull exceptions") { +CASE("Qhull errors/exceptions") { using geo::util::Qhull; - SECTION("Assertion failed: 0 < N && coord.size() % N == 0 in Qhull") { + SECTION("input errors") { for (size_t N : {2, 3, 4}) { Qhull::coord_t coord((N + 1) * N + 1, 1.); ASSERT(coord.size() % N != 0); - EXPECT_THROWS_AS(Qhull(N, coord, "Qt"), AssertionFailed); + EXPECT_THROWS_AS(Qhull(N, coord, "Qt"), AssertionFailed); // 0 < N && coord.size() % N == 0 } } - SECTION("QH6050 qhull error: dimension 1 must be > 1") { - try { - Qhull(1, {1, 1}, "Qt"); - EXPECT(false); - } - catch (const Qhull::Exception& e) { - EXPECT(e.errorCode == 6050); - } - } - - - SECTION("QH6154 Qhull precision error: Initial simplex is flat (facet 1 is coplanar with the interior point)") { - try { - Qhull(2, {1, 1, 2, 2, 3, 3, 4, 4}, "Qt"); - EXPECT(false); - } - catch (const Qhull::Exception& e) { - EXPECT(e.errorCode == 6154); - } - } - - - SECTION("QH6214 qhull input error: not enough points(1) to construct initial simplex (need 3)") { - try { - Qhull(2, {1, 1}, "Qt"); - EXPECT(false); - } - catch (const Qhull::Exception& e) { - EXPECT(e.errorCode == 6214); - } - } - - - SECTION("QH6412 qhull input error (qh_initqhull_globals): expecting between 1 and 2147483631 points") { - try { - Qhull(2, {}, "Qt"); - EXPECT(false); - } - catch (const Qhull::Exception& e) { - EXPECT(e.errorCode == 6412); - } - } - - - SECTION("QH6421 qhull internal error (qh_maxsimplex): qh.MAXwidth required for qh_maxsimplex") { - try { - Qhull(2, {1, 1, 1, 1, 1, 1}, "Qt"); - EXPECT(false); - } - catch (const Qhull::Exception& e) { - EXPECT(e.errorCode == 6421); + SECTION("qhull errors") { + struct { + const int errorCode; + const std::string what; + const std::string command; + const size_t N; + const Qhull::coord_t coord; + } static const tests[] = { + {6050, "QH6050 qhull error: dimension 1 must be > 1", "Qt", 1, {1, 1}}, + {6154, "QH6154 Qhull precision error: Initial simplex is flat", "Qt", 2, {1, 1, 2, 2, 3, 3}}, + {6214, "QH6214 qhull input error: not enough points", "Qt", 2, {1, 1}}, + {6412, "QH6412 qhull input error (qh_initqhull_globals)", "Qt", 2, {}}, + {6421, "QH6421 qhull internal error (qh_maxsimplex)", "Qt", 2, {1, 1, 1, 1, 1, 1}}, + }; + + for (const auto& test : tests) { + try { + Qhull(test.N, test.coord, test.command); + EXPECT(false); + } + catch (const Qhull::Exception& e) { + EXPECT_EQUAL(test.errorCode, e.errorCode); + EXPECT_EQUAL(test.what, std::string(e.what(), test.what.length())); + } } } } From 33549bb605dfbada960637f3118df4aa80f42249 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 20 Dec 2023 16:20:42 +0000 Subject: [PATCH 406/737] eckit::geo qhull --- tests/geo/CMakeLists.txt | 57 +++++++------- .../geo/{convex_hull_n.cc => convex_hull.cc} | 44 +++++++++++ tests/geo/qhull.cc | 74 ------------------- 3 files changed, 71 insertions(+), 104 deletions(-) rename tests/geo/{convex_hull_n.cc => convex_hull.cc} (79%) delete mode 100644 tests/geo/qhull.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 31a82b484..f6e096c48 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -1,35 +1,32 @@ -foreach( _test - area_boundingbox - area_polygon - convex_hull_n - coordinate_helpers - figure_sphere - great_circle - grid - grid_regular_ll - grid_reorder - grid_to_points - gridspec - increments - iterator - kdtree - kpoint - point - projection - range - search - util ) +set( _tests + area_boundingbox + area_polygon + coordinate_helpers + figure_sphere + great_circle + grid + grid_regular_ll + grid_reorder + grid_to_points + gridspec + increments + iterator + kdtree + kpoint + point + projection + range + search + util ) + +if( eckit_HAVE_GEO_CONVEX_HULL ) + list( APPEND _tests convex_hull ) +endif() + +foreach( _test ${_tests} ) ecbuild_add_test( TARGET eckit_test_geo_${_test} SOURCES ${_test}.cc - LIBS eckit_geo - ) + LIBS eckit_geo ) endforeach() -ecbuild_add_test( - TARGET eckit_test_geo_qhull - SOURCES qhull.cc - LIBS eckit_geo - CONDITION eckit_HAVE_GEO_CONVEX_HULL -) - diff --git a/tests/geo/convex_hull_n.cc b/tests/geo/convex_hull.cc similarity index 79% rename from tests/geo/convex_hull_n.cc rename to tests/geo/convex_hull.cc index fc28bfbd7..327c479af 100644 --- a/tests/geo/convex_hull_n.cc +++ b/tests/geo/convex_hull.cc @@ -16,7 +16,9 @@ #include #include +#include "eckit/exception/Exceptions.h" #include "eckit/geo/convexhull/ConvexHullN.h" +#include "eckit/geo/util/Qhull.h" #include "eckit/testing/Test.h" @@ -26,6 +28,48 @@ namespace eckit::test { +CASE("Qhull errors/exceptions") { + using geo::util::Qhull; + + + SECTION("input") { + for (size_t N : {2, 3, 4}) { + Qhull::coord_t coord((N + 1) * N + 1, 1.); + ASSERT(coord.size() % N != 0); + EXPECT_THROWS_AS(Qhull(N, coord, "Qt"), AssertionFailed); // 0 < N && coord.size() % N == 0 + } + } + + + SECTION("qhull") { + struct { + const int errorCode; + const std::string what; + const std::string command; + const size_t N; + const Qhull::coord_t coord; + } static const tests[] = { + {6050, "QH6050 qhull error: dimension 1 must be > 1", "Qt", 1, {1, 1}}, + {6154, "QH6154 Qhull precision error: Initial simplex is flat", "Qt", 2, {1, 1, 2, 2, 3, 3}}, + {6214, "QH6214 qhull input error: not enough points", "Qt", 2, {1, 1}}, + {6412, "QH6412 qhull input error (qh_initqhull_globals)", "Qt", 2, {}}, + {6421, "QH6421 qhull internal error (qh_maxsimplex)", "Qt", 2, {1, 1, 1, 1, 1, 1}}, + }; + + for (const auto& test : tests) { + try { + Qhull(test.N, test.coord, test.command); + EXPECT(false); + } + catch (const Qhull::Exception& e) { + EXPECT_EQUAL(test.errorCode, e.errorCode); + EXPECT_EQUAL(test.what, std::string(e.what(), test.what.length())); + } + } + } +} + + CASE("ConvexHullN, N=2") { using Point2 = std::array; diff --git a/tests/geo/qhull.cc b/tests/geo/qhull.cc deleted file mode 100644 index 08497a2c8..000000000 --- a/tests/geo/qhull.cc +++ /dev/null @@ -1,74 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/util/Qhull.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/testing/Test.h" - - -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { - - -CASE("Qhull errors/exceptions") { - using geo::util::Qhull; - - - SECTION("input errors") { - for (size_t N : {2, 3, 4}) { - Qhull::coord_t coord((N + 1) * N + 1, 1.); - ASSERT(coord.size() % N != 0); - EXPECT_THROWS_AS(Qhull(N, coord, "Qt"), AssertionFailed); // 0 < N && coord.size() % N == 0 - } - } - - - SECTION("qhull errors") { - struct { - const int errorCode; - const std::string what; - const std::string command; - const size_t N; - const Qhull::coord_t coord; - } static const tests[] = { - {6050, "QH6050 qhull error: dimension 1 must be > 1", "Qt", 1, {1, 1}}, - {6154, "QH6154 Qhull precision error: Initial simplex is flat", "Qt", 2, {1, 1, 2, 2, 3, 3}}, - {6214, "QH6214 qhull input error: not enough points", "Qt", 2, {1, 1}}, - {6412, "QH6412 qhull input error (qh_initqhull_globals)", "Qt", 2, {}}, - {6421, "QH6421 qhull internal error (qh_maxsimplex)", "Qt", 2, {1, 1, 1, 1, 1, 1}}, - }; - - for (const auto& test : tests) { - try { - Qhull(test.N, test.coord, test.command); - EXPECT(false); - } - catch (const Qhull::Exception& e) { - EXPECT_EQUAL(test.errorCode, e.errorCode); - EXPECT_EQUAL(test.what, std::string(e.what(), test.what.length())); - } - } - } -} - - -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- - - -int main(int argc, char** argv) { - return eckit::testing::run_tests(argc, argv); -} From 26658dffdf81f8797648af2ceb7ada39f06cc098 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 21 Dec 2023 10:15:02 +0000 Subject: [PATCH 407/737] eckit::geo qhull --- tests/geo/convex_hull.cc | 52 ++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/tests/geo/convex_hull.cc b/tests/geo/convex_hull.cc index 327c479af..f9d562424 100644 --- a/tests/geo/convex_hull.cc +++ b/tests/geo/convex_hull.cc @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -73,13 +74,13 @@ CASE("Qhull errors/exceptions") { CASE("ConvexHullN, N=2") { using Point2 = std::array; - // Polygon (vertices 0, 1, 4, 5, 7, 8, 9) containing point indices 2, 3, 6 + // Build convex hull geo::convexhull::ConvexHullN ch(std::vector{ {1, 2}, {3, 1}, {4, 4}, {6, 5}, - {7, 2}, + {7, 0}, {2, 5}, {5, 7}, {8, 3}, @@ -87,36 +88,29 @@ CASE("ConvexHullN, N=2") { {9, 6}, }); + // Inner points to convex hull + const std::set inner{2, 3, 6, 7 /*on edge*/}; - SECTION("vertices") { + SECTION("vertices and facets") { const auto vertices = ch.list_vertices(); - EXPECT(vertices.size() == 7); - - for (size_t vertex : {0, 1, 4, 5, 7, 8, 9}) { - EXPECT(std::find(vertices.begin(), vertices.end(), vertex) != vertices.end()); - } - - for (size_t vertex : {2, 3, 6}) { - EXPECT(std::find(vertices.begin(), vertices.end(), vertex) == vertices.end()); - } - } + EXPECT(vertices.size() == 6); - - SECTION("facets") { const auto facets = ch.list_facets(); - EXPECT(facets.size() == 7); - - for (const auto& fr : {std::vector{8, 9}, {5, 0}, {5, 8}, {1, 0}, {1, 4}, {7, 9}, {7, 4}}) { - EXPECT(std::count_if(facets.begin(), facets.end(), [&fr](const auto& facet) { - ASSERT(facet.size() == 2); - return (fr[0] == facet[0] && fr[1] == facet[1]) || (fr[0] == facet[1] && fr[1] == facet[0]); - }) == 1); - } - - for (size_t vertex : {2, 3, 6}) { - for (const auto& facet : facets) { - EXPECT(std::find(facet.begin(), facet.end(), vertex) == facet.end()); - } + EXPECT(facets.size() == 6); + + for (size_t vertex = 0; vertex < 10; ++vertex) { + auto inside = inner.find(vertex) != inner.end(); + auto count_in_vertices = std::count(vertices.begin(), vertices.end(), vertex); + auto count_in_facets = std::accumulate(facets.begin(), + facets.end(), + static_cast(0), + [vertex](auto c, const auto& facet) { + auto f = std::count(facet.begin(), facet.end(), vertex); + EXPECT(f <= 1); + return c + f; + }); + EXPECT_EQUAL(count_in_vertices, (inside ? 0 : 1)); + EXPECT_EQUAL(count_in_facets, (inside ? 0 : 2)); } } @@ -130,7 +124,7 @@ CASE("ConvexHullN, N=2") { {3, 1}, {4, 4}, {6, 5}, - {7, 2}, + {7, 0}, {2, 5}, {5, 7}, {8, 3}, From 01c0dd56fc3336b41791b3dca7d72b7f8df443f7 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 21 Dec 2023 11:56:38 +0000 Subject: [PATCH 408/737] eckit::geo::Grid --- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 1 + src/eckit/geo/grid/reduced/ReducedGaussian.h | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index d208f5983..134877e95 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -18,6 +18,7 @@ #include "eckit/geo/range/Gaussian.h" #include "eckit/geo/range/Regular.h" #include "eckit/utils/Translator.h" +#include "eckit/geo/Range.h" namespace eckit::geo::grid::reduced { diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.h b/src/eckit/geo/grid/reduced/ReducedGaussian.h index eda111c14..fbad9736a 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.h @@ -14,11 +14,15 @@ #include -#include "eckit/geo/Range.h" #include "eckit/geo/grid/Reduced.h" #include "eckit/geo/util.h" +namespace eckit::geo { +class Range;} + + + namespace eckit::geo::grid::reduced { From 4fedd98af6277b427f1b74c658641abde7319d61 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 21 Dec 2023 11:56:38 +0000 Subject: [PATCH 409/737] eckit::geo::Grid --- src/eckit/geo/Grid.h | 1 - tests/geo/grid.cc | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 5ca238416..4e85e5e57 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -13,7 +13,6 @@ #pragma once #include -#include #include #include #include diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index 08e002c47..400c54f71 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -50,7 +50,9 @@ CASE("GridFactory::build") { } - SECTION("Grid::build_from_uid") {} + SECTION("Grid::build_from_uid") { + // TODO + } SECTION("Grid::build_from_increments") { From 913f68d134fa46111a95fa27f923fb1c57d3ef0a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Jan 2024 06:30:10 +0000 Subject: [PATCH 410/737] eckit::geo qhull --- CMakeLists.txt | 17 -- src/eckit/geo/CMakeLists.txt | 13 -- src/eckit/geo/Triangulation.h | 82 ------- src/eckit/geo/convexhull/ConvexHullN.cc | 29 --- src/eckit/geo/convexhull/ConvexHullN.h | 81 ------- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 2 +- src/eckit/geo/grid/reduced/ReducedGaussian.h | 4 +- src/eckit/geo/triangulation/Triangulation3.cc | 47 ---- src/eckit/geo/triangulation/Triangulation3.h | 31 --- src/eckit/geo/util/Qhull.cc | 97 -------- src/eckit/geo/util/Qhull.h | 57 ----- src/tools/CMakeLists.txt | 6 - src/tools/eckit-grid-triangulation.cc | 86 ------- tests/geo/CMakeLists.txt | 4 - tests/geo/convex_hull.cc | 214 ------------------ 15 files changed, 3 insertions(+), 767 deletions(-) delete mode 100644 src/eckit/geo/Triangulation.h delete mode 100644 src/eckit/geo/convexhull/ConvexHullN.cc delete mode 100644 src/eckit/geo/convexhull/ConvexHullN.h delete mode 100644 src/eckit/geo/triangulation/Triangulation3.cc delete mode 100644 src/eckit/geo/triangulation/Triangulation3.h delete mode 100644 src/eckit/geo/util/Qhull.cc delete mode 100644 src/eckit/geo/util/Qhull.h delete mode 100644 src/tools/eckit-grid-triangulation.cc delete mode 100644 tests/geo/convex_hull.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 75f236007..07ca1e37c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,23 +162,6 @@ ecbuild_add_option( FEATURE GEO_CACHING CONDITION HAVE_ECKIT_GEO DESCRIPTION "eckit::geo geometry library default caching behaviour" ) -ecbuild_add_option( FEATURE GEO_CONVEX_HULL - DEFAULT OFF - CONDITION HAVE_ECKIT_GEO - DESCRIPTION "eckit::geo geometry library convex hull/Delaunay triangulation" ) - # REQUIRED_PACKAGES "Qhull COMPONENTS C CXX" - -if( eckit_HAVE_GEO_CONVEX_HULL ) - find_package( Qhull REQUIRED CONFIG ) - - if( NOT TARGET Qhull::qhullcpp OR NOT TARGET Qhull::qhullstatic_r ) - message( FATAL_ERROR "eckit::geo ENABLE_GEO_CONVEX_HULL requires Qhull C/C++ libraries" ) - endif() - - add_library(Qhull::Qhull INTERFACE IMPORTED) - target_link_libraries(Qhull::Qhull INTERFACE Qhull::qhullcpp Qhull::qhullstatic_r ) -endif() - set( eckit_GEO_CACHE_PATH "/tmp/cache" ) ### LAPACK diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 1ffffd5a2..ae468d73c 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -51,7 +51,6 @@ list(APPEND eckit_geo_srcs Sphere.cc Sphere.h SphereT.h - Triangulation.h UnitSphere.h area/BoundingBox.cc area/BoundingBox.h @@ -134,18 +133,6 @@ if(eckit_HAVE_ECKIT_CODEC) list(APPEND eckit_geo_libs eckit_codec) endif() -if(eckit_HAVE_GEO_CONVEX_HULL) - list(APPEND eckit_geo_srcs - convexhull/ConvexHullN.cc - convexhull/ConvexHullN.h - triangulation/Triangulation3.cc - triangulation/Triangulation3.h - util/Qhull.cc - util/Qhull.h - ) - list(APPEND eckit_geo_libs Qhull::Qhull) -endif() - ecbuild_add_library( TARGET eckit_geo TYPE SHARED diff --git a/src/eckit/geo/Triangulation.h b/src/eckit/geo/Triangulation.h deleted file mode 100644 index 1a9515e6d..000000000 --- a/src/eckit/geo/Triangulation.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * (C) Copyright 1996- 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 -#include - -#include "eckit/geo/ConvexHull.h" -#include "eckit/memory/Builder.h" -#include "eckit/memory/Factory.h" - - -namespace eckit { -class Configuration; -} // namespace eckit - - -namespace eckit::geo { - - -using Triangle = ConvexHull::Triangle; - - -class Triangulation : protected std::vector { -public: - // -- Types - - using builder_t = BuilderT1; - using ARG1 = const Configuration&; - - // -- Constructors - - using vector::vector; - - Triangulation(const Triangulation&) = default; - Triangulation(Triangulation&&) = default; - - // -- Destructor - - virtual ~Triangulation() = default; - - // -- Operators - - using vector::operator[]; - - Triangulation& operator=(const Triangulation&) = default; - Triangulation& operator=(Triangulation&&) = default; - - // -- Methods - - static std::string className() { return "Triangulation"; } - - using vector::at; - using vector::size; - - using vector::begin; - using vector::cbegin; - using vector::cend; - using vector::end; - -protected: - // -- Constructors - - explicit Triangulation(const std::vector& tri) : - vector(tri) {} -}; - - -using TriangulationFactory = Factory; - -template -using TriangulationBuilder = ConcreteBuilderT1; - - -} // namespace eckit::geo diff --git a/src/eckit/geo/convexhull/ConvexHullN.cc b/src/eckit/geo/convexhull/ConvexHullN.cc deleted file mode 100644 index e5d96c34d..000000000 --- a/src/eckit/geo/convexhull/ConvexHullN.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/convexhull/ConvexHullN.h" - - -namespace eckit::geo::convexhull { - - -static ConvexHullBuilder> __convexhulln2("convex-hull-n-2"); -static ConvexHullBuilder> __convexhulln3("convex-hull-n-3"); -static ConvexHullBuilder> __convexhulln4("convex-hull-n-4"); -static ConvexHullBuilder> __convexhulln5("convex-hull-n-5"); -static ConvexHullBuilder> __convexhulln6("convex-hull-n-6"); -static ConvexHullBuilder> __convexhulln7("convex-hull-n-7"); -static ConvexHullBuilder> __convexhulln8("convex-hull-n-8"); -static ConvexHullBuilder> __convexhulln9("convex-hull-n-9"); -// ... - - -} // namespace eckit::geo::convexhull diff --git a/src/eckit/geo/convexhull/ConvexHullN.h b/src/eckit/geo/convexhull/ConvexHullN.h deleted file mode 100644 index ea4f55b7a..000000000 --- a/src/eckit/geo/convexhull/ConvexHullN.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/ConvexHull.h" -#include "eckit/geo/util/Qhull.h" - - -namespace eckit::geo::convexhull { - - -template -class ConvexHullN : public ConvexHull { -public: - // -- Types - - using coord_t = util::Qhull::coord_t; - - // -- Constructors - - explicit ConvexHullN(const coord_t& coord) : - qhull_(N, coord, "QJ") {} - - explicit ConvexHullN(const std::vector>& coord_v) : - ConvexHullN(convert_vector_v(coord_v)) {} - - explicit ConvexHullN(const std::vector>& coord_a) : - ConvexHullN(convert_vector_a(coord_a)) {} - - // -- Methods - - std::vector list_vertices() const override { return qhull_.list_vertices(); } - - std::vector> list_facets() const override { return qhull_.list_facets(); } - - std::vector list_triangles() const override { return qhull_.list_triangles(); } - -private: - // -- Methods - - static coord_t convert_vector_v(const std::vector>& coord_v) { - coord_t coord; - coord.reserve(N * coord_v.size()); - - for (const auto& v : coord_v) { - ASSERT(N == v.size()); - for (int i = 0; i < N; ++i) { - coord.emplace_back(v[i]); - } - } - - return coord; - } - - static coord_t convert_vector_a(const std::vector>& coord_a) { - coord_t coord; - coord.reserve(N * coord_a.size()); - for (const auto& a : coord_a) { - for (int i = 0; i < N; ++i) { - coord.emplace_back(a[i]); - } - } - return coord; - } - - // -- Members - - util::Qhull qhull_; -}; - - -} // namespace eckit::geo::convexhull diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 134877e95..6e54d3d68 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -14,11 +14,11 @@ #include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Range.h" #include "eckit/geo/iterator/Reduced.h" #include "eckit/geo/range/Gaussian.h" #include "eckit/geo/range/Regular.h" #include "eckit/utils/Translator.h" -#include "eckit/geo/Range.h" namespace eckit::geo::grid::reduced { diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.h b/src/eckit/geo/grid/reduced/ReducedGaussian.h index fbad9736a..492eef657 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.h @@ -19,8 +19,8 @@ namespace eckit::geo { -class Range;} - +class Range; +} namespace eckit::geo::grid::reduced { diff --git a/src/eckit/geo/triangulation/Triangulation3.cc b/src/eckit/geo/triangulation/Triangulation3.cc deleted file mode 100644 index a837c09b4..000000000 --- a/src/eckit/geo/triangulation/Triangulation3.cc +++ /dev/null @@ -1,47 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/triangulation/Triangulation3.h" - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/Grid.h" -#include "eckit/geo/projection/LonLatToXYZ.h" -#include "eckit/geo/util/Qhull.h" - - -namespace eckit::geo::triangulation { - - -std::vector grid_to_coord(const Grid& grid) { - auto [lat, lon] = grid.to_latlon(); - ASSERT(lat.size() == lon.size()); - - auto N = static_cast(lon.size()); - std::vector coord(N * 3); - - geo::projection::LonLatToXYZ lonlat2xyz(1.); - for (size_t i = 0; i < N; ++i) { - auto p = lonlat2xyz.fwd({lon[i], lat[i]}); - - coord[i * 3 + 0] = p.X; - coord[i * 3 + 1] = p.Y; - coord[i * 3 + 2] = p.Z; - } - - return coord; -} - - -Triangulation3::Triangulation3(const Grid& grid) : - Triangulation(util::Qhull(3, grid_to_coord(grid), "Qt").list_triangles()) {} - - -} // namespace eckit::geo::triangulation diff --git a/src/eckit/geo/triangulation/Triangulation3.h b/src/eckit/geo/triangulation/Triangulation3.h deleted file mode 100644 index 71a2a8191..000000000 --- a/src/eckit/geo/triangulation/Triangulation3.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Triangulation.h" - - -namespace eckit::geo { -class Grid; -} // namespace eckit::geo - - -namespace eckit::geo::triangulation { - - -class Triangulation3 : public Triangulation { -public: - explicit Triangulation3(const Grid&); -}; - - -} // namespace eckit::geo::triangulation diff --git a/src/eckit/geo/util/Qhull.cc b/src/eckit/geo/util/Qhull.cc deleted file mode 100644 index bed852dfb..000000000 --- a/src/eckit/geo/util/Qhull.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/util/Qhull.h" - -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/log/Log.h" - -#include "libqhullcpp/QhullFacetList.h" -#include "libqhullcpp/QhullVertexSet.h" - - -namespace eckit::geo::util { - - -Qhull::Qhull(size_t N, const coord_t& coord, const std::string& command) { - ASSERT(0 < N && coord.size() % N == 0); - - auto pointDimension = static_cast(N); - auto pointCount = static_cast(coord.size() / N); - - std::ostringstream err; - qh_.setErrorStream(&err); - qh_.setOutputStream(&Log::info()); - qh_.enableOutputStream(); - - try { - qh_.runQhull("", pointDimension, pointCount, coord.data(), command.c_str()); - ASSERT(qh_.qhullStatus() == 0); - } - catch (const orgQhull::QhullError& e) { - throw Exception(err.str(), e.errorCode(), command); - } -} - - -std::vector Qhull::list_vertices() const { - std::vector vertices; - vertices.reserve(qh_.vertexCount()); - - for (const auto& vertex : qh_.vertexList()) { - vertices.emplace_back(vertex.point().id()); - } - - return vertices; -} - - -std::vector> Qhull::list_facets() const { - std::vector> facets; - facets.reserve(qh_.facetCount()); - - for (const auto& facet : qh_.facetList()) { - const auto vertices = facet.vertices(); - - std::vector f; - f.reserve(vertices.size()); - - for (const auto& vertex : vertices) { - f.emplace_back(vertex.point().id()); - } - - facets.emplace_back(f); - } - - return facets; -} - - -std::vector Qhull::list_triangles() const { - std::vector tri; - tri.reserve(qh_.facetCount()); - - for (const auto& facet : qh_.facetList()) { - const auto vertices = facet.vertices(); - ASSERT(vertices.size() == 3); - - tri.emplace_back(Triangle{static_cast(vertices[0].point().id()), - static_cast(vertices[1].point().id()), - static_cast(vertices[2].point().id())}); - } - - return tri; -} - - -} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/Qhull.h b/src/eckit/geo/util/Qhull.h deleted file mode 100644 index ee2c2f850..000000000 --- a/src/eckit/geo/util/Qhull.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - - -#include -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/ConvexHull.h" - -#include "libqhullcpp/Qhull.h" - - -namespace eckit::geo::util { - - -class Qhull : public ConvexHull { -public: - // -- Types - - using coord_t = std::vector; - - struct Exception : eckit::Exception { - Exception(const std::string& what, int _errorCode, const std::string& _command) : - eckit::Exception(what), errorCode(_errorCode), command(_command) {} - const int errorCode; - const std::string& command; - }; - - // -- Constructors - - Qhull(size_t N, const coord_t& coord, const std::string& command); - - // -- Overridden methods - - std::vector list_vertices() const override; - std::vector> list_facets() const override; - std::vector list_triangles() const override; - -private: - // -- Members - - orgQhull::Qhull qh_; -}; - - -} // namespace eckit::geo::util diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index f11087fa2..27c2bef4e 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -30,12 +30,6 @@ ecbuild_add_executable( TARGET eckit_grid_list SOURCES eckit-grid-list.cc LIBS eckit_geo eckit_option ) -ecbuild_add_executable( TARGET eckit_grid_triangulation - OUTPUT_NAME eckit-grid-triangulation - CONDITION eckit_HAVE_ECKIT_GEO AND eckit_HAVE_GEO_CONVEX_HULL - SOURCES eckit-grid-triangulation.cc - LIBS eckit_geo eckit_option ) - ### NOT TO INSTALL ecbuild_add_executable( TARGET dhcopy diff --git a/src/tools/eckit-grid-triangulation.cc b/src/tools/eckit-grid-triangulation.cc deleted file mode 100644 index 143d4e1d3..000000000 --- a/src/tools/eckit-grid-triangulation.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - * (C) Copyright 1996- 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 -#include - -#include "eckit/config/MappedConfiguration.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/Grid.h" -#include "eckit/geo/projection/LonLatToXYZ.h" -#include "eckit/geo/triangulation/Triangulation3.h" -#include "eckit/log/Log.h" -#include "eckit/option/CmdArgs.h" -#include "eckit/option/EckitTool.h" -#include "eckit/option/SimpleOption.h" - - -namespace eckit::tools { - - -struct EckitGridTriangulation final : EckitTool { - EckitGridTriangulation(int argc, char** argv) : - EckitTool(argc, argv) { - options_.push_back(new option::SimpleOption("grid", "grid name")); - } - - void execute(const option::CmdArgs&) override; - - void usage(const std::string& tool) const override { - Log::info() << "\n" - "Usage: " - << tool << "--grid=O32" << std::endl; - } -}; - - -void EckitGridTriangulation::execute(const option::CmdArgs& args) { - std::unique_ptr grid( - geo::GridFactory::build(MappedConfiguration{{{"grid", args.getString("grid")}}})); - - auto& out = std::cout; - - geo::triangulation::Triangulation3 tri(*grid); - - auto [lat, lon] = grid->to_latlon(); - - auto N = grid->size(); - ASSERT(N == lat.size()); - ASSERT(N == lon.size()); - - out << "$MeshFormat\n" - "4.1 0 8\n" - "$EndMeshFormat\n"; - - out << "$Nodes\n" << N << '\n'; - geo::projection::LonLatToXYZ lonlat2xyz(1.); - for (size_t i = 0; i < N; ++i) { - auto p = lonlat2xyz.fwd(geo::PointLonLat{lon[i], lat[i]}); - out << (i + 1) << ' ' << p.X << ' ' << p.Y << ' ' << p.Z << '\n'; - } - out << "$EndNodes\n"; - - out << "$Elements\n" << tri.size() << '\n'; - size_t i = 0; - for (const auto& t : tri) { - out << (i + 1) << " 2 4 1 1 1 0 " << t[0] << ' ' << t[1] << ' ' << t[2] << '\n'; - } - out << "$EndElements\n"; -}; - - -} // namespace eckit::tools - - -int main(int argc, char** argv) { - eckit::tools::EckitGridTriangulation app(argc, argv); - return app.start(); -} diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index f6e096c48..492c639fe 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -19,10 +19,6 @@ set( _tests search util ) -if( eckit_HAVE_GEO_CONVEX_HULL ) - list( APPEND _tests convex_hull ) -endif() - foreach( _test ${_tests} ) ecbuild_add_test( TARGET eckit_test_geo_${_test} diff --git a/tests/geo/convex_hull.cc b/tests/geo/convex_hull.cc deleted file mode 100644 index f9d562424..000000000 --- a/tests/geo/convex_hull.cc +++ /dev/null @@ -1,214 +0,0 @@ -/* - * (C) Copyright 1996- 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 -#include -#include -#include -#include -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/convexhull/ConvexHullN.h" -#include "eckit/geo/util/Qhull.h" -#include "eckit/testing/Test.h" - - -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { - - -CASE("Qhull errors/exceptions") { - using geo::util::Qhull; - - - SECTION("input") { - for (size_t N : {2, 3, 4}) { - Qhull::coord_t coord((N + 1) * N + 1, 1.); - ASSERT(coord.size() % N != 0); - EXPECT_THROWS_AS(Qhull(N, coord, "Qt"), AssertionFailed); // 0 < N && coord.size() % N == 0 - } - } - - - SECTION("qhull") { - struct { - const int errorCode; - const std::string what; - const std::string command; - const size_t N; - const Qhull::coord_t coord; - } static const tests[] = { - {6050, "QH6050 qhull error: dimension 1 must be > 1", "Qt", 1, {1, 1}}, - {6154, "QH6154 Qhull precision error: Initial simplex is flat", "Qt", 2, {1, 1, 2, 2, 3, 3}}, - {6214, "QH6214 qhull input error: not enough points", "Qt", 2, {1, 1}}, - {6412, "QH6412 qhull input error (qh_initqhull_globals)", "Qt", 2, {}}, - {6421, "QH6421 qhull internal error (qh_maxsimplex)", "Qt", 2, {1, 1, 1, 1, 1, 1}}, - }; - - for (const auto& test : tests) { - try { - Qhull(test.N, test.coord, test.command); - EXPECT(false); - } - catch (const Qhull::Exception& e) { - EXPECT_EQUAL(test.errorCode, e.errorCode); - EXPECT_EQUAL(test.what, std::string(e.what(), test.what.length())); - } - } - } -} - - -CASE("ConvexHullN, N=2") { - using Point2 = std::array; - - // Build convex hull - geo::convexhull::ConvexHullN ch(std::vector{ - {1, 2}, - {3, 1}, - {4, 4}, - {6, 5}, - {7, 0}, - {2, 5}, - {5, 7}, - {8, 3}, - {6, 9}, - {9, 6}, - }); - - // Inner points to convex hull - const std::set inner{2, 3, 6, 7 /*on edge*/}; - - SECTION("vertices and facets") { - const auto vertices = ch.list_vertices(); - EXPECT(vertices.size() == 6); - - const auto facets = ch.list_facets(); - EXPECT(facets.size() == 6); - - for (size_t vertex = 0; vertex < 10; ++vertex) { - auto inside = inner.find(vertex) != inner.end(); - auto count_in_vertices = std::count(vertices.begin(), vertices.end(), vertex); - auto count_in_facets = std::accumulate(facets.begin(), - facets.end(), - static_cast(0), - [vertex](auto c, const auto& facet) { - auto f = std::count(facet.begin(), facet.end(), vertex); - EXPECT(f <= 1); - return c + f; - }); - EXPECT_EQUAL(count_in_vertices, (inside ? 0 : 1)); - EXPECT_EQUAL(count_in_facets, (inside ? 0 : 2)); - } - } - - - SECTION("factory") { - // same as above - std::unique_ptr ch2(geo::ConvexHullFactory::instance() - .get("convex-hull-n-2") - .create(std::vector>{ - {1, 2}, - {3, 1}, - {4, 4}, - {6, 5}, - {7, 0}, - {2, 5}, - {5, 7}, - {8, 3}, - {6, 9}, - {9, 6}, - })); - - auto vertex_set = [](const std::vector& list) { return std::set{list.cbegin(), list.cend()}; }; - EXPECT(vertex_set(ch.list_vertices()) == vertex_set(ch2->list_vertices())); - - // wrong dimensions - EXPECT_THROWS_AS(geo::ConvexHullFactory::instance() - .get("convex-hull-n-3") - .create(std::vector>{ - {1, 2}, - {3, 1}, - {4, 4}, - }), - AssertionFailed); - } -} - - -CASE("ConvexHullN, N=3") { - using Point3 = std::array; - - // Tetrahedron (vertices 0, 1, 2, 3) containing point index 4 - geo::convexhull::ConvexHullN ch(std::vector{ - {0, 0, 1}, - {1, 0, -1}, - {-1, 1, -1}, - {-1, -1, -1}, - {0, 0, 0}, - }); - - - SECTION("vertices") { - const auto vertices = ch.list_vertices(); - EXPECT(vertices.size() == 4); - - for (size_t vertex = 0; vertex < 4; ++vertex) { - EXPECT(std::find(vertices.begin(), vertices.end(), vertex) != vertices.end()); - } - - EXPECT(std::find(vertices.begin(), vertices.end(), 4) == vertices.end()); - } - - - SECTION("facets/triangles") { - const auto facets = ch.list_facets(); - EXPECT(facets.size() == 4); - - const auto triangles = ch.list_triangles(); - EXPECT(triangles.size() == 4); - - for (const auto& fr : { - std::vector{0, 1, 2}, - {0, 1, 3}, - {0, 2, 3}, - {1, 2, 3}, - }) { - EXPECT(std::count_if(facets.begin(), facets.end(), [&fr](const auto& facet) { - ASSERT(facet.size() == 3); - return std::count(fr.begin(), fr.end(), facet[0]) == 1 && - std::count(fr.begin(), fr.end(), facet[1]) == 1 && - std::count(fr.begin(), fr.end(), facet[2]) == 1; - }) == 1); - - EXPECT(std::count_if(triangles.begin(), triangles.end(), [&fr](const auto& tri) { - return std::count(fr.begin(), fr.end(), tri[0]) == 1 && - std::count(fr.begin(), fr.end(), tri[1]) == 1 && - std::count(fr.begin(), fr.end(), tri[2]) == 1; - }) == 1); - } - } -} - - -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- - - -int main(int argc, char** argv) { - return eckit::testing::run_tests(argc, argv); -} From 71e8ac4fd6facb0776f764575da5e7cb484122a7 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 11 Jan 2024 17:36:13 +0000 Subject: [PATCH 411/737] eckit::geo::spec --- src/eckit/CMakeLists.txt | 4 ---- src/eckit/geo/CMakeLists.txt | 4 ++++ src/eckit/geo/Grid.cc | 8 +++---- src/eckit/geo/GridConfig.cc | 24 +++++++++---------- src/eckit/geo/Projection.h | 4 +++- src/eckit/geo/grid/reduced/HEALPix.cc | 4 ++-- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 7 +++--- src/eckit/geo/grid/regular/Mercator.cc | 2 +- src/eckit/geo/grid/regular/RegularGaussian.cc | 4 ++-- src/eckit/geo/grid/regular/RegularLL.cc | 4 ++-- src/eckit/geo/projection/LonLatToXYZ.cc | 2 +- src/eckit/geo/projection/Mercator.cc | 2 +- src/eckit/geo/projection/None.cc | 2 +- src/eckit/geo/projection/PROJ.cc | 2 +- src/eckit/geo/projection/Rotation.cc | 2 +- .../spec}/DynamicConfiguration.cc | 6 ++--- .../spec}/DynamicConfiguration.h | 4 ++-- .../spec}/MappedConfiguration.cc | 6 ++--- .../spec}/MappedConfiguration.h | 7 +++--- src/tools/eckit-grid.cc | 4 ++-- tests/config/CMakeLists.txt | 3 ++- tests/config/test_configuration.cc | 18 +++++++------- tests/config/test_mapped_configuration.cc | 6 ++--- tests/geo/grid.cc | 12 +++++----- tests/geo/grid_regular_ll.cc | 10 ++++---- tests/geo/grid_reorder.cc | 4 ++-- tests/geo/gridspec.cc | 6 ++--- tests/geo/projection.cc | 16 ++++++------- 28 files changed, 91 insertions(+), 86 deletions(-) rename src/eckit/{config => geo/spec}/DynamicConfiguration.cc (94%) rename src/eckit/{config => geo/spec}/DynamicConfiguration.h (98%) rename src/eckit/{config => geo/spec}/MappedConfiguration.cc (98%) rename src/eckit/{config => geo/spec}/MappedConfiguration.h (97%) diff --git a/src/eckit/CMakeLists.txt b/src/eckit/CMakeLists.txt index 77e3bc8e7..8ef1c1d37 100644 --- a/src/eckit/CMakeLists.txt +++ b/src/eckit/CMakeLists.txt @@ -346,8 +346,6 @@ list( APPEND eckit_config_srcs config/Configuration.h config/Configured.cc config/Configured.h - config/DynamicConfiguration.cc - config/DynamicConfiguration.h config/EtcTable.cc config/EtcTable.h config/JSONConfiguration.h @@ -355,8 +353,6 @@ list( APPEND eckit_config_srcs config/LibEcKit.h config/LocalConfiguration.cc config/LocalConfiguration.h - config/MappedConfiguration.cc - config/MappedConfiguration.h config/Parametrisation.cc config/Parametrisation.h config/Resource.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index ae468d73c..e689d3b4c 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -104,6 +104,10 @@ list(APPEND eckit_geo_srcs range/Regular.h range/RegularLongitude.cc range/RegularLongitude.h + spec/DynamicConfiguration.cc + spec/DynamicConfiguration.h + spec/MappedConfiguration.cc + spec/MappedConfiguration.h util.cc util.h util/arange.cc diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index c32db4312..be94a0bf2 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -16,10 +16,10 @@ #include #include -#include "eckit/config/DynamicConfiguration.h" -#include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/GridConfig.h" +#include "eckit/geo/spec/DynamicConfiguration.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -131,13 +131,13 @@ Configuration* GridFactory::configure_(const Configuration& config) const { GridConfig::instance(); - auto* cfg = new DynamicConfiguration(config); + auto* cfg = new spec::DynamicConfiguration(config); ASSERT(cfg != nullptr); // hardcoded, interpreted options (contributing to gridspec) - auto* map = new MappedConfiguration; + auto* map = new spec::MappedConfiguration; ASSERT(map != nullptr); if (size_t N = 0; cfg->get("N", N)) { diff --git a/src/eckit/geo/GridConfig.cc b/src/eckit/geo/GridConfig.cc index b90790999..3adca680e 100644 --- a/src/eckit/geo/GridConfig.cc +++ b/src/eckit/geo/GridConfig.cc @@ -15,11 +15,11 @@ #include #include -#include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "eckit/geo/Grid.h" #include "eckit/geo/LibEcKitGeo.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/geo/util.h" #include "eckit/parser/YAMLParser.h" #include "eckit/value/Value.h" @@ -32,14 +32,14 @@ namespace { template -MappedConfiguration::value_type __from_value(const Value& value) { +spec::MappedConfiguration::value_type __from_value(const Value& value) { T to; fromValue(to, value); return {to}; } -void set_config_value(MappedConfiguration& config, const std::string& key, const Value& value) { +void set_config_value(spec::MappedConfiguration& config, const std::string& key, const Value& value) { using number_type = pl_type::value_type; auto list_of = [](const ValueList& list, auto pred) { return std::all_of(list.begin(), list.end(), pred); }; @@ -57,8 +57,8 @@ void set_config_value(MappedConfiguration& config, const std::string& key, const } -MappedConfiguration* config_from_value_map(const ValueMap& map) { - auto* config = new MappedConfiguration; +spec::MappedConfiguration* config_from_value_map(const ValueMap& map) { + auto* config = new spec::MappedConfiguration; for (const auto& kv : map) { set_config_value(*config, kv.first, kv.second); } @@ -76,23 +76,23 @@ const GridConfig& GridConfig::instance() { GridConfig::GridConfig(const PathName& path) { - auto* config = new MappedConfiguration; + auto* config = new spec::MappedConfiguration; config_.reset(config); struct ConfigurationFromUID final : GridConfigurationUID::configurator_t { - explicit ConfigurationFromUID(MappedConfiguration* config) : + explicit ConfigurationFromUID(spec::MappedConfiguration* config) : config_(config) {} - Configuration* config() const override { return new MappedConfiguration(*config_); } - std::unique_ptr config_; + Configuration* config() const override { return new spec::MappedConfiguration(*config_); } + std::unique_ptr config_; }; struct ConfigurationFromName final : GridConfigurationName::configurator_t { - explicit ConfigurationFromName(MappedConfiguration* config) : + explicit ConfigurationFromName(spec::MappedConfiguration* config) : config_(config) {} Configuration* config(GridConfigurationName::configurator_t::arg1_t) const override { - return new MappedConfiguration(*config_); + return new spec::MappedConfiguration(*config_); } - std::unique_ptr config_; + std::unique_ptr config_; }; if (path.exists()) { diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index daeb26948..121abdfdc 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -21,7 +21,9 @@ namespace eckit { class Configuration; +namespace geo::spec { class MappedConfiguration; +} } // namespace eckit @@ -35,7 +37,7 @@ class Projection { using builder_t = BuilderT1; using ARG1 = const Configuration&; - using Spec = MappedConfiguration; + using Spec = spec::MappedConfiguration; // -- Exceptions // None diff --git a/src/eckit/geo/grid/reduced/HEALPix.cc b/src/eckit/geo/grid/reduced/HEALPix.cc index b93d5bfcd..8a721f668 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.cc +++ b/src/eckit/geo/grid/reduced/HEALPix.cc @@ -18,8 +18,8 @@ #include #include -#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/iterator/Reduced.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/geo/util.h" #include "eckit/utils/Translator.h" @@ -296,7 +296,7 @@ size_t HEALPix::nj() const { Configuration* HEALPix::config(const std::string& name) { auto Nside = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "HEALPix"}, {"Nside", Nside}, {"orderingConvention", "ring"}}); + return new spec::MappedConfiguration({{"type", "HEALPix"}, {"Nside", Nside}, {"orderingConvention", "ring"}}); } diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 6e54d3d68..f1c1b2863 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -12,12 +12,12 @@ #include "eckit/geo/grid/reduced/ReducedGaussian.h" -#include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/Range.h" #include "eckit/geo/iterator/Reduced.h" #include "eckit/geo/range/Gaussian.h" #include "eckit/geo/range/Regular.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/utils/Translator.h" @@ -73,7 +73,7 @@ std::vector ReducedGaussian::longitudes(size_t j) const { struct ReducedGaussianClassical { static Configuration* config(const std::string& name) { auto N = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_classical_pl(N)}}); + return new spec::MappedConfiguration({{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_classical_pl(N)}}); } }; @@ -81,7 +81,8 @@ struct ReducedGaussianClassical { struct ReducedGaussianOctahedral { static Configuration* config(const std::string& name) { auto N = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_octahedral_pl(N)}}); + return new spec::MappedConfiguration( + {{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_octahedral_pl(N)}}); } }; diff --git a/src/eckit/geo/grid/regular/Mercator.cc b/src/eckit/geo/grid/regular/Mercator.cc index 1f7f3be80..04119b02a 100644 --- a/src/eckit/geo/grid/regular/Mercator.cc +++ b/src/eckit/geo/grid/regular/Mercator.cc @@ -12,9 +12,9 @@ #include "eckit/geo/grid/regular/Mercator.h" -#include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/iterator/Regular.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/geo/util/regex.h" #include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index d6cbcb000..bad26b975 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -12,10 +12,10 @@ #include "eckit/geo/grid/regular/RegularGaussian.h" -#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/range/Gaussian.h" #include "eckit/geo/range/RegularLongitude.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/utils/Translator.h" @@ -51,7 +51,7 @@ Grid::iterator RegularGaussian::cend() const { Configuration* RegularGaussian::config(const std::string& name) { auto N = Translator{}(name.substr(1)); - return new MappedConfiguration({{"type", "regular_gg"}, {"N", N}, {"ni", 4 * N}}); + return new spec::MappedConfiguration({{"type", "regular_gg"}, {"N", N}, {"ni", 4 * N}}); } diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index 1045f9476..92d4d2548 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -12,12 +12,12 @@ #include "eckit/geo/grid/regular/RegularLL.h" -#include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/Increments.h" #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/range/Regular.h" #include "eckit/geo/range/RegularLongitude.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/geo/util/regex.h" #include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" @@ -192,7 +192,7 @@ Configuration* RegularLL::config(const std::string& name) { // Fraction(360)).n(); auto nj = 1; // detail::RegularIterator(Fraction(-90), Fraction(90), Fraction(increments[1]), Fraction(0)).n(); - return new MappedConfiguration({{"type", "regular_ll"}, {"grid", increments}, {"ni", ni}, {"nj", nj}}); + return new spec::MappedConfiguration({{"type", "regular_ll"}, {"grid", increments}, {"ni", ni}, {"nj", nj}}); } diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc index ac8c30497..38a2732f7 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -12,9 +12,9 @@ #include "eckit/geo/projection/LonLatToXYZ.h" -#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/EllipsoidOfRevolution.h" #include "eckit/geo/Sphere.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/types/FloatCompare.h" diff --git a/src/eckit/geo/projection/Mercator.cc b/src/eckit/geo/projection/Mercator.cc index 8236b25d4..02216a42d 100644 --- a/src/eckit/geo/projection/Mercator.cc +++ b/src/eckit/geo/projection/Mercator.cc @@ -14,7 +14,7 @@ #include -#include "eckit/config/MappedConfiguration.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index 88f168cba..9273350ba 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -12,7 +12,7 @@ #include "eckit/geo/projection/None.h" -#include "eckit/config/MappedConfiguration.h" +#include "eckit/geo/spec/MappedConfiguration.h" namespace eckit::geo::projection { diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 9b8e531b7..76d607503 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -12,8 +12,8 @@ #include "eckit/geo/projection/PROJ.h" -#include "eckit/config/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geo/spec/MappedConfiguration.h" namespace eckit::geo::projection { diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 77bb02cde..6988e606e 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -15,8 +15,8 @@ #include #include -#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/UnitSphere.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/geo/util.h" #include "eckit/maths/Matrix3.h" #include "eckit/types/FloatCompare.h" diff --git a/src/eckit/config/DynamicConfiguration.cc b/src/eckit/geo/spec/DynamicConfiguration.cc similarity index 94% rename from src/eckit/config/DynamicConfiguration.cc rename to src/eckit/geo/spec/DynamicConfiguration.cc index ebfb97554..1be676cd0 100644 --- a/src/eckit/config/DynamicConfiguration.cc +++ b/src/eckit/geo/spec/DynamicConfiguration.cc @@ -8,14 +8,14 @@ * does it submit to any jurisdiction. */ -#include "eckit/config/DynamicConfiguration.h" +#include "eckit/geo/spec/DynamicConfiguration.h" #include "eckit/config/LocalConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/value/Value.h" -namespace eckit { +namespace eckit::geo::spec { namespace { @@ -83,4 +83,4 @@ void DynamicConfiguration::print(std::ostream& out) const { } -} // namespace eckit +} // namespace eckit::geo::spec diff --git a/src/eckit/config/DynamicConfiguration.h b/src/eckit/geo/spec/DynamicConfiguration.h similarity index 98% rename from src/eckit/config/DynamicConfiguration.h rename to src/eckit/geo/spec/DynamicConfiguration.h index 23bc81282..ea9f6dccd 100644 --- a/src/eckit/config/DynamicConfiguration.h +++ b/src/eckit/geo/spec/DynamicConfiguration.h @@ -18,7 +18,7 @@ #include "eckit/config/Configuration.h" -namespace eckit { +namespace eckit::geo::spec { class DynamicConfiguration : public Configuration { @@ -125,4 +125,4 @@ class DynamicConfiguration : public Configuration { }; -} // namespace eckit +} // namespace eckit::geo::spec diff --git a/src/eckit/config/MappedConfiguration.cc b/src/eckit/geo/spec/MappedConfiguration.cc similarity index 98% rename from src/eckit/config/MappedConfiguration.cc rename to src/eckit/geo/spec/MappedConfiguration.cc index 891ccb232..4574e01ec 100644 --- a/src/eckit/config/MappedConfiguration.cc +++ b/src/eckit/geo/spec/MappedConfiguration.cc @@ -9,13 +9,13 @@ */ -#include "eckit/config/MappedConfiguration.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/log/JSON.h" #include "eckit/value/Value.h" -namespace eckit { +namespace eckit::geo::spec { namespace { @@ -344,4 +344,4 @@ void MappedConfiguration::json(JSON& j) const { } -} // namespace eckit +} // namespace eckit::geo::spec diff --git a/src/eckit/config/MappedConfiguration.h b/src/eckit/geo/spec/MappedConfiguration.h similarity index 97% rename from src/eckit/config/MappedConfiguration.h rename to src/eckit/geo/spec/MappedConfiguration.h index 03f196388..3d1eb6138 100644 --- a/src/eckit/config/MappedConfiguration.h +++ b/src/eckit/geo/spec/MappedConfiguration.h @@ -17,7 +17,7 @@ #include "eckit/config/Configuration.h" -namespace eckit { +namespace eckit::geo::spec { class MappedConfiguration final : public Configuration { @@ -54,7 +54,8 @@ class MappedConfiguration final : public Configuration { MappedConfiguration(MappedConfiguration&&); // -- Destructor - // None + + ~MappedConfiguration() final = default; // -- Convertors // None @@ -138,4 +139,4 @@ class MappedConfiguration final : public Configuration { }; -} // namespace eckit +} // namespace eckit::geo::spec diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index 2c330bd0f..146dc6798 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -11,7 +11,7 @@ #include #include -#include "eckit/config/MappedConfiguration.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/Grid.h" #include "eckit/geo/Point.h" @@ -52,7 +52,7 @@ class EckitGrid final : public EckitTool { out.precision(args.getInt("precision", 16)); for (const auto& arg : args) { - std::unique_ptr cfg(new MappedConfiguration({{uid ? "uid" : "name", std::string(arg)}})); + std::unique_ptr cfg(new geo::spec::MappedConfiguration({{uid ? "uid" : "name", std::string(arg)}})); std::unique_ptr grid(geo::GridFactory::build(*cfg)); out << "size: " << grid->size() << std::endl; diff --git a/tests/config/CMakeLists.txt b/tests/config/CMakeLists.txt index 588db74bc..9430e1714 100644 --- a/tests/config/CMakeLists.txt +++ b/tests/config/CMakeLists.txt @@ -9,7 +9,8 @@ foreach( _test configuration mapped_configuration ) ecbuild_add_test( TARGET eckit_test_config_${_test} SOURCES test_${_test}.cc - LIBS eckit + LIBS eckit eckit_geo + CONDITION HAVE_ECKIT_GEO ) endforeach() diff --git a/tests/config/test_configuration.cc b/tests/config/test_configuration.cc index 47b62924b..255c48c37 100644 --- a/tests/config/test_configuration.cc +++ b/tests/config/test_configuration.cc @@ -10,9 +10,9 @@ #include -#include "eckit/config/DynamicConfiguration.h" +#include "eckit/geo/spec/DynamicConfiguration.h" #include "eckit/config/LocalConfiguration.h" -#include "eckit/config/MappedConfiguration.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/config/YAMLConfiguration.h" #include "eckit/filesystem/PathName.h" #include "eckit/testing/Test.h" @@ -391,7 +391,7 @@ CASE("test_mapped_configuration") { std::string three = "3"; - MappedConfiguration a({ + geo::spec::MappedConfiguration a({ {"double", static_cast(one)}, {"float", static_cast(one)}, {"int", static_cast(one)}, @@ -421,7 +421,7 @@ CASE("test_mapped_configuration") { } - MappedConfiguration b({ + geo::spec::MappedConfiguration b({ {"true", true}, {"false", false}, {"zero", 0}, @@ -453,7 +453,7 @@ CASE("test_mapped_configuration") { EXPECT(b.get("one", maybe = false) && maybe); - MappedConfiguration c; + geo::spec::MappedConfiguration c; EXPECT_NOT(c.has("foo")); c.set("foo", two); @@ -471,7 +471,7 @@ CASE("test_mapped_configuration") { EXPECT_EQUAL(c.getString("foo"), three); - MappedConfiguration d(c); + geo::spec::MappedConfiguration d(c); EXPECT(d.has("foo")); EXPECT_EQUAL(d.getString("foo"), three); @@ -482,7 +482,7 @@ CASE("test_mapped_configuration") { EXPECT_EQUAL(d.getInt("foo"), one); - MappedConfiguration e(c); + geo::spec::MappedConfiguration e(c); ASSERT(e.has("foo")); ASSERT(e.has("bar")); @@ -494,11 +494,11 @@ CASE("test_dynamic_configuration") { int one = 1; double two = 2.; - MappedConfiguration a({{"foo", one}, {"bar", two}}); + geo::spec::MappedConfiguration a({{"foo", one}, {"bar", two}}); ASSERT(a.has("foo")); ASSERT(a.has("bar")); - DynamicConfiguration b(a); + geo::spec::DynamicConfiguration b(a); ASSERT(b.has("foo")); ASSERT(b.has("bar")); diff --git a/tests/config/test_mapped_configuration.cc b/tests/config/test_mapped_configuration.cc index 218f97392..9738572bc 100644 --- a/tests/config/test_mapped_configuration.cc +++ b/tests/config/test_mapped_configuration.cc @@ -13,7 +13,7 @@ #include #include -#include "eckit/config/MappedConfiguration.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/testing/Test.h" @@ -24,7 +24,7 @@ namespace eckit::test { CASE("MappedConfiguration") { - std::unique_ptr param(new MappedConfiguration({{"a", -123}, {"b", "B"}, {"c", 123UL}})); + std::unique_ptr param(new geo::spec::MappedConfiguration({{"a", -123}, {"b", "B"}, {"c", 123UL}})); int a = 0; EXPECT(param->get("a", a)); @@ -40,7 +40,7 @@ CASE("MappedConfiguration") { EXPECT_EQUAL(c, 123UL); int d = 0; - dynamic_cast(param.get())->set("b", 321); + dynamic_cast(param.get())->set("b", 321); EXPECT(param->get("b", d)); EXPECT_EQUAL(d, 321); } diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index 400c54f71..68f1c8605 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -12,8 +12,8 @@ #include -#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/Grid.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/testing/Test.h" @@ -32,8 +32,8 @@ CASE("GridFactory::build") { SECTION("GridFactory::build_from_name") { for (const auto& test : {test_t{"O2", 88}, {"f2", 32}, {"h2", 48}}) { - std::unique_ptr grid( - GridFactory::build(*std::unique_ptr(new MappedConfiguration({{"grid", test.name}})))); + std::unique_ptr grid(GridFactory::build( + *std::unique_ptr(new spec::MappedConfiguration({{"grid", test.name}})))); auto size = grid->size(); EXPECT_EQUAL(size, test.size); @@ -43,7 +43,7 @@ CASE("GridFactory::build") { SECTION("RegularGaussian") { std::unique_ptr grid(GridFactory::build( - *std::unique_ptr(new MappedConfiguration({{"grid", "f2"}, {"south", 0}})))); + *std::unique_ptr(new spec::MappedConfiguration({{"grid", "f2"}, {"south", 0}})))); auto nh = grid->size(); EXPECT_EQUAL(nh, 32 / 2); @@ -58,7 +58,7 @@ CASE("GridFactory::build") { SECTION("Grid::build_from_increments") { SECTION("global") { std::unique_ptr global( - GridFactory::build(*std::unique_ptr(new MappedConfiguration({ + GridFactory::build(*std::unique_ptr(new spec::MappedConfiguration({ {"type", "regular_ll"}, {"west_east_increment", 1}, {"south_north_increment", 1}, @@ -71,7 +71,7 @@ CASE("GridFactory::build") { SECTION("non-global") { std::unique_ptr grid( - GridFactory::build(*std::unique_ptr(new MappedConfiguration({ + GridFactory::build(*std::unique_ptr(new spec::MappedConfiguration({ {"type", "regular_ll"}, {"west_east_increment", 1}, {"south_north_increment", 1}, diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index 201f8e07f..6a32ec790 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -12,31 +12,31 @@ #include -#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/grid/regular/RegularLL.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/testing/Test.h" namespace eckit::test { -using namespace eckit::geo; +using namespace geo; CASE("") { std::unique_ptr global( - new grid::regular::RegularLL(MappedConfiguration{{{"grid", std::vector{1, 1}}}})); + new grid::regular::RegularLL(spec::MappedConfiguration{{{"grid", std::vector{1, 1}}}})); size_t global_size = global->size(); EXPECT_EQUAL(global_size, 360 * 181); std::unique_ptr local(new grid::regular::RegularLL( - MappedConfiguration{{{"grid", std::vector{2, 1}}, {"area", std::vector{10, 1, 1, 10}}}})); + spec::MappedConfiguration{{{"grid", std::vector{2, 1}}, {"area", std::vector{10, 1, 1, 10}}}})); size_t local_size = local->size(); EXPECT_EQUAL(local_size, 5 * 10); - std::unique_ptr almost_global(new grid::regular::RegularLL(MappedConfiguration{ + std::unique_ptr almost_global(new grid::regular::RegularLL(spec::MappedConfiguration{ {{"grid", std::vector{1, 1}}, {"area", std::vector{89.5, 0., -89.5, 359.1}}}})); size_t almost_global_size = almost_global->size(); diff --git a/tests/geo/grid_reorder.cc b/tests/geo/grid_reorder.cc index 572ca7b09..bca207adc 100644 --- a/tests/geo/grid_reorder.cc +++ b/tests/geo/grid_reorder.cc @@ -12,8 +12,8 @@ #include -#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/Grid.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/testing/Test.h" @@ -35,7 +35,7 @@ using namespace geo; CASE("HEALPix") { SECTION("HEALPix::reorder") { std::unique_ptr ring( - GridFactory::build(*std::unique_ptr(new MappedConfiguration({{"grid", "H2"}})))); + GridFactory::build(*std::unique_ptr(new spec::MappedConfiguration({{"grid", "H2"}})))); static const Renumber expected_ren_ring_to_nested{ 3, 7, 11, 15, 2, 1, 6, 5, 10, 9, 14, 13, 19, 0, 23, 4, 27, 8, 31, 12, 17, 22, 21, 26, diff --git a/tests/geo/gridspec.cc b/tests/geo/gridspec.cc index 192e39995..00f70d7dd 100644 --- a/tests/geo/gridspec.cc +++ b/tests/geo/gridspec.cc @@ -13,8 +13,8 @@ #include #include -#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/Grid.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/log/Log.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" @@ -36,11 +36,11 @@ using namespace geo; using C = std::unique_ptr; using G = std::unique_ptr; -using M = MappedConfiguration; +using M = spec::MappedConfiguration; using v = std::vector; -static const MappedConfiguration BAD; +static const spec::MappedConfiguration BAD; static std::pair cases[]{ diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index 7fffdfcbb..692ac2e91 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -13,12 +13,12 @@ #include #include -#include "eckit/config/MappedConfiguration.h" #include "eckit/geo/Projection.h" #include "eckit/geo/figure/Sphere.h" #include "eckit/geo/projection/LonLatToXYZ.h" #include "eckit/geo/projection/Mercator.h" #include "eckit/geo/projection/Rotation.h" +#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/log/Log.h" #include "eckit/testing/Test.h" @@ -36,14 +36,14 @@ CASE("projection") { SECTION("projection type: none") { - P projection(ProjectionFactory::instance().get("none").create(MappedConfiguration{})); + P projection(ProjectionFactory::instance().get("none").create(spec::MappedConfiguration{})); EXPECT(points_equal(p, projection->inv(p))); EXPECT(points_equal(p, projection->fwd(p))); } SECTION("projection type: rotation") { - MappedConfiguration param({ + spec::MappedConfiguration param({ {"projection", "rotation"}, {"south_pole_lat", -91.}, {"south_pole_lon", -361.}, @@ -57,9 +57,9 @@ CASE("projection") { SECTION("projection type: ll_to_xyz") { - P s1(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"R", 1.}}))); - P s2(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 1.}}))); - P s3(ProjectionFactory::instance().get("ll_to_xyz").create(MappedConfiguration({{"a", 1.}, {"b", 0.5}}))); + P s1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::MappedConfiguration({{"R", 1.}}))); + P s2(ProjectionFactory::instance().get("ll_to_xyz").create(spec::MappedConfiguration({{"a", 1.}, {"b", 1.}}))); + P s3(ProjectionFactory::instance().get("ll_to_xyz").create(spec::MappedConfiguration({{"a", 1.}, {"b", 0.5}}))); EXPECT(points_equal(p, s1->inv(s1->fwd(p)))); EXPECT(points_equal(p, s2->inv(s2->fwd(p)))); @@ -304,7 +304,7 @@ CASE("projection") { for (const auto& test : tests) { P projection(ProjectionFactory::instance().get("proj").create( - MappedConfiguration{{{"source", "EPSG:4326"}, {"target", test.target}}})); + spec::MappedConfiguration{{{"source", "EPSG:4326"}, {"target", test.target}}})); #if 0 std::cout << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) @@ -320,7 +320,7 @@ CASE("projection") { EXPECT(points_equal(c, a)); P reverse(ProjectionFactory::instance().get("proj").create( - MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}}))); + spec::MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}}))); auto d = reverse->fwd(test.b); auto e = reverse->inv(d); From 80b67945ac467e6577f2a160b0c475e287c305b9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 12 Jan 2024 16:52:48 +0000 Subject: [PATCH 412/737] eckit::geo::Spec --- src/eckit/config/Configuration.cc | 14 +- src/eckit/config/Configuration.h | 11 +- src/eckit/geo/Area.h | 6 +- src/eckit/geo/CMakeLists.txt | 13 +- src/eckit/geo/ConvexHull.h | 73 ------- src/eckit/geo/Figure.h | 8 +- src/eckit/geo/Grid.cc | 28 +-- src/eckit/geo/Grid.h | 29 +-- src/eckit/geo/GridConfig.cc | 40 ++-- src/eckit/geo/GridConfig.h | 8 +- src/eckit/geo/Increments.cc | 11 +- src/eckit/geo/Increments.h | 6 +- src/eckit/geo/Projection.h | 16 +- src/eckit/geo/Range.cc | 6 +- src/eckit/geo/Range.h | 6 +- src/eckit/geo/Spec.cc | 118 +++++++++++ src/eckit/geo/Spec.h | 72 +++++++ src/eckit/geo/area/BoundingBox.cc | 16 +- src/eckit/geo/area/BoundingBox.h | 2 +- src/eckit/geo/figure/OblateSpheroid.cc | 6 +- src/eckit/geo/figure/OblateSpheroid.h | 2 +- src/eckit/geo/figure/Sphere.cc | 6 +- src/eckit/geo/figure/Sphere.h | 2 +- src/eckit/geo/grid/Reduced.cc | 4 +- src/eckit/geo/grid/Reduced.h | 2 +- src/eckit/geo/grid/Regular.cc | 4 +- src/eckit/geo/grid/Regular.h | 2 +- src/eckit/geo/grid/Unstructured.cc | 4 +- src/eckit/geo/grid/Unstructured.h | 2 +- src/eckit/geo/grid/reduced/HEALPix.cc | 10 +- src/eckit/geo/grid/reduced/HEALPix.h | 4 +- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 15 +- src/eckit/geo/grid/reduced/ReducedGaussian.h | 2 +- src/eckit/geo/grid/reduced/ReducedLL.cc | 4 +- src/eckit/geo/grid/reduced/ReducedLL.h | 2 +- src/eckit/geo/grid/regular/IrregularLL.cc | 4 +- src/eckit/geo/grid/regular/IrregularLL.h | 2 +- src/eckit/geo/grid/regular/Mercator.cc | 6 +- src/eckit/geo/grid/regular/Mercator.h | 2 +- src/eckit/geo/grid/regular/RegularGaussian.cc | 10 +- src/eckit/geo/grid/regular/RegularGaussian.h | 4 +- src/eckit/geo/grid/regular/RegularLL.cc | 16 +- src/eckit/geo/grid/regular/RegularLL.h | 4 +- src/eckit/geo/grid/unstructured/ORCA.cc | 31 +-- src/eckit/geo/grid/unstructured/ORCA.h | 6 +- .../grid/unstructured/UnstructuredFromGrid.cc | 4 +- .../grid/unstructured/UnstructuredFromGrid.h | 2 +- src/eckit/geo/projection/LonLatToXYZ.cc | 12 +- src/eckit/geo/projection/LonLatToXYZ.h | 6 +- src/eckit/geo/projection/Mercator.cc | 16 +- src/eckit/geo/projection/Mercator.h | 4 +- src/eckit/geo/projection/None.cc | 8 +- src/eckit/geo/projection/None.h | 4 +- src/eckit/geo/projection/PROJ.cc | 14 +- src/eckit/geo/projection/PROJ.h | 4 +- src/eckit/geo/projection/Rotation.cc | 27 +-- src/eckit/geo/projection/Rotation.h | 24 +-- .../{MappedConfiguration.cc => Custom.cc} | 113 +++++----- .../spec/{MappedConfiguration.h => Custom.h} | 26 ++- src/eckit/geo/spec/DynamicConfiguration.cc | 86 -------- .../geo/{Configurator.h => spec/Generator.h} | 136 ++++++------ src/eckit/geo/spec/Layered.cc | 84 ++++++++ .../{DynamicConfiguration.h => Layered.h} | 25 +-- src/tools/eckit-grid.cc | 10 +- tests/config/CMakeLists.txt | 13 +- tests/config/test_configuration.cc | 134 ------------ tests/config/test_mapped_configuration.cc | 57 ----- tests/geo/CMakeLists.txt | 43 ++-- tests/geo/grid.cc | 40 ++-- tests/geo/grid_regular_ll.cc | 11 +- tests/geo/grid_reorder.cc | 4 +- tests/geo/gridspec.cc | 104 +++++----- tests/geo/projection.cc | 18 +- tests/geo/spec.cc | 194 ++++++++++++++++++ 74 files changed, 977 insertions(+), 885 deletions(-) delete mode 100644 src/eckit/geo/ConvexHull.h create mode 100644 src/eckit/geo/Spec.cc create mode 100644 src/eckit/geo/Spec.h rename src/eckit/geo/spec/{MappedConfiguration.cc => Custom.cc} (57%) rename src/eckit/geo/spec/{MappedConfiguration.h => Custom.h} (88%) delete mode 100644 src/eckit/geo/spec/DynamicConfiguration.cc rename src/eckit/geo/{Configurator.h => spec/Generator.h} (55%) create mode 100644 src/eckit/geo/spec/Layered.cc rename src/eckit/geo/spec/{DynamicConfiguration.h => Layered.h} (87%) delete mode 100644 tests/config/test_mapped_configuration.cc create mode 100644 tests/geo/spec.cc diff --git a/src/eckit/config/Configuration.cc b/src/eckit/config/Configuration.cc index 732c2da9c..4e47d3b03 100644 --- a/src/eckit/config/Configuration.cc +++ b/src/eckit/config/Configuration.cc @@ -14,6 +14,7 @@ #include "eckit/config/Configuration.h" #include "eckit/config/LocalConfiguration.h" +#include "eckit/exception/Exceptions.h" #include "eckit/log/JSON.h" #include "eckit/utils/Tokenizer.h" #include "eckit/value/Value.h" @@ -22,11 +23,14 @@ namespace eckit { //---------------------------------------------------------------------------------------------------------------------- -ConfigurationNotFound::ConfigurationNotFound(const std::string& name) { - std::ostringstream s; - s << "ConfigurationNotFound: [" << name << "]"; - reason(s.str()); -} +class ConfigurationNotFound : public Exception { +public: + ConfigurationNotFound(const std::string& name) { + std::ostringstream s; + s << "ConfigurationNotFound: [" << name << "]"; + reason(s.str()); + } +}; //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/config/Configuration.h b/src/eckit/config/Configuration.h index 03f9fbc50..8f08f7802 100644 --- a/src/eckit/config/Configuration.h +++ b/src/eckit/config/Configuration.h @@ -18,22 +18,13 @@ #include #include - #include "eckit/config/Parametrisation.h" -#include "eckit/exception/Exceptions.h" namespace eckit { //---------------------------------------------------------------------------------------------------------------------- -class ConfigurationNotFound : public Exception { -public: - explicit ConfigurationNotFound(const std::string& name); -}; - -//---------------------------------------------------------------------------------------------------------------------- - class LocalConfiguration; class JSON; class Value; @@ -158,7 +149,7 @@ class Configuration : public Parametrisation { char separator_; private: // methods - virtual void json(JSON& s) const; + void json(JSON& s) const; friend JSON& operator<<(JSON& s, const Configuration& v) { v.json(s); return s; diff --git a/src/eckit/geo/Area.h b/src/eckit/geo/Area.h index 595ab9d27..fa45d11fb 100644 --- a/src/eckit/geo/Area.h +++ b/src/eckit/geo/Area.h @@ -18,8 +18,8 @@ #include "eckit/memory/Factory.h" -namespace eckit { -class Configuration; +namespace eckit::geo { +class Spec; } @@ -31,7 +31,7 @@ class Area { // -- Types using builder_t = BuilderT1; - using ARG1 = const Configuration&; + using ARG1 = const Spec&; // -- Exceptions // None diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index e689d3b4c..45abec437 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -10,8 +10,6 @@ list(APPEND eckit_geo_srcs Area.h Cache.cc Cache.h - Configurator.h - ConvexHull.h CoordinateHelpers.cc CoordinateHelpers.h Domain.cc @@ -48,6 +46,8 @@ list(APPEND eckit_geo_srcs Range.h Renumber.h Search.h + Spec.cc + Spec.h Sphere.cc Sphere.h SphereT.h @@ -104,10 +104,11 @@ list(APPEND eckit_geo_srcs range/Regular.h range/RegularLongitude.cc range/RegularLongitude.h - spec/DynamicConfiguration.cc - spec/DynamicConfiguration.h - spec/MappedConfiguration.cc - spec/MappedConfiguration.h + spec/Generator.h + spec/Custom.cc + spec/Custom.h + spec/Layered.cc + spec/Layered.h util.cc util.h util/arange.cc diff --git a/src/eckit/geo/ConvexHull.h b/src/eckit/geo/ConvexHull.h deleted file mode 100644 index a11b9a773..000000000 --- a/src/eckit/geo/ConvexHull.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include - -#include "eckit/memory/Builder.h" -#include "eckit/memory/Factory.h" - - -namespace eckit { -class Configuration; -} // namespace eckit - - -namespace eckit::geo { - - -class ConvexHull { -public: - // -- Types - - using Triangle = std::array; - - using builder_t = BuilderT1; - using ARG1 = const std::vector>&; // TODO use std::vector - - // -- Constructors - - ConvexHull(const ConvexHull&) = delete; - ConvexHull(ConvexHull&&) = delete; - - // -- Operators - - void operator=(const ConvexHull&) = delete; - void operator=(ConvexHull&&) = delete; - - // -- Destructor - - virtual ~ConvexHull() = default; - - // -- Methods - - static std::string className() { return "ConvexHull"; } - - virtual std::vector list_vertices() const = 0; - virtual std::vector> list_facets() const = 0; - virtual std::vector list_triangles() const = 0; - -protected: - // -- Constructors - - ConvexHull() /*noexcept */ = default; -}; - - -using ConvexHullFactory = Factory; - -template -using ConvexHullBuilder = ConcreteBuilderT1; - - -} // namespace eckit::geo diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index 44bd1aea2..d4852fcd9 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -18,8 +18,8 @@ #include "eckit/memory/Factory.h" -namespace eckit { -class Configuration; +namespace eckit::geo { +class Spec; } @@ -31,7 +31,7 @@ class Figure { // -- Types using builder_t = BuilderT1
; - using ARG1 = const Configuration&; + using ARG1 = const Spec&; // -- Exceptions // None @@ -42,7 +42,7 @@ class Figure { Figure(const Figure&) = default; Figure(Figure&&) = default; - explicit Figure(const Configuration&); + explicit Figure(const Spec&); // -- Destructor diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index be94a0bf2..0001fd609 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -18,8 +18,8 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/GridConfig.h" -#include "eckit/geo/spec/DynamicConfiguration.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/geo/spec/Layered.h" #include "eckit/log/Log.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -28,8 +28,8 @@ namespace eckit::geo { -Grid::Grid(const Configuration& config) : - bbox_(config) {} +Grid::Grid(const Spec& spec) : + bbox_(spec) {} Grid::Grid(const area::BoundingBox& bbox) : @@ -112,10 +112,10 @@ GridFactory& GridFactory::instance() { } -const Grid* GridFactory::build_(const Configuration& config) const { +const Grid* GridFactory::build_(const Spec& spec) const { AutoLock lock(mutex_); - std::unique_ptr cfg(configure_(config)); + std::unique_ptr cfg(generate_spec_(spec)); if (std::string type; cfg->get("type", type)) { return GridFactoryType::instance().get(type).create(*cfg); @@ -126,18 +126,18 @@ const Grid* GridFactory::build_(const Configuration& config) const { } -Configuration* GridFactory::configure_(const Configuration& config) const { +Spec* GridFactory::generate_spec_(const Spec& spec) const { AutoLock lock(mutex_); GridConfig::instance(); - auto* cfg = new spec::DynamicConfiguration(config); + auto* cfg = new spec::Layered(spec); ASSERT(cfg != nullptr); // hardcoded, interpreted options (contributing to gridspec) - auto* map = new spec::MappedConfiguration; + auto* map = new spec::Custom; ASSERT(map != nullptr); if (size_t N = 0; cfg->get("N", N)) { @@ -154,10 +154,10 @@ Configuration* GridFactory::configure_(const Configuration& config) const { // configurable options if (std::string uid; cfg->get("uid", uid)) { - cfg->push_front(GridConfigurationUID::instance().get(uid).config()); + cfg->push_front(SpecByUID::instance().get(uid).config()); } - else if (std::string grid; cfg->get("grid", grid) && GridConfigurationName::instance().matches(grid)) { - cfg->push_front(GridConfigurationName::instance().match(grid).config(grid)); + else if (std::string grid; cfg->get("grid", grid) && SpecByName::instance().matches(grid)) { + cfg->push_front(SpecByName::instance().match(grid).config(grid)); } @@ -172,8 +172,8 @@ void GridFactory::list_(std::ostream& out) const { GridConfig::instance(); - out << GridConfigurationUID::instance() << std::endl; - out << GridConfigurationName::instance() << std::endl; + out << SpecByUID::instance() << std::endl; + out << SpecByName::instance() << std::endl; out << GridFactoryType::instance() << std::endl; } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 4e85e5e57..01500fb89 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -19,19 +19,19 @@ #include #include "eckit/geo/Area.h" -#include "eckit/geo/Configurator.h" #include "eckit/geo/Increments.h" #include "eckit/geo/Iterator.h" #include "eckit/geo/Ordering.h" #include "eckit/geo/Point.h" #include "eckit/geo/Renumber.h" #include "eckit/geo/area/BoundingBox.h" +#include "eckit/geo/spec/Generator.h" #include "eckit/memory/Builder.h" #include "eckit/memory/Factory.h" -namespace eckit { -class Configuration; +namespace eckit::geo { +class Spec; } @@ -44,13 +44,14 @@ class Grid { using uid_t = std::string; using builder_t = BuilderT1; - using ARG1 = const Configuration&; + using ARG1 = const Spec&; struct Iterator final : std::unique_ptr { explicit Iterator(geo::Iterator* it) : unique_ptr(it) { ASSERT(unique_ptr::operator bool()); } + using diff_t = unique_ptr::element_type::diff_t; Iterator(const Iterator&) = delete; @@ -83,7 +84,7 @@ class Grid { // -- Constructors - explicit Grid(const Configuration&); + explicit Grid(const Spec&); Grid(const Grid&) = delete; Grid(Grid&&) = delete; @@ -177,35 +178,35 @@ class Grid { }; -using GridFactoryType = Factory; -using GridConfigurationName = Configurator>; -using GridConfigurationUID = Configurator; +using GridFactoryType = Factory; +using SpecByName = spec::GeneratorT>; +using SpecByUID = spec::GeneratorT; template using GridRegisterType = ConcreteBuilderT1; template -using GridRegisterUID = ConcreteConfigurationGeneratorT0; +using GridRegisterUID = spec::ConcreteSpecGeneratorT0; template -using GridRegisterName = ConcreteConfigurationGeneratorT1; +using GridRegisterName = spec::ConcreteSpecGeneratorT1; struct GridFactory { // This is 'const' as Grid should always be immutable - static const Grid* build(const Configuration& config) { return instance().build_(config); } + static const Grid* build(const Spec& spec) { return instance().build_(spec); } - static Configuration* configure(const Configuration& config) { return instance().configure_(config); } + static Spec* spec(const Spec& spec) { return instance().generate_spec_(spec); } static void list(std::ostream& out) { return instance().list_(out); } private: static GridFactory& instance(); // This is 'const' as Grid should always be immutable - const Grid* build_(const Configuration&) const; + const Grid* build_(const Spec&) const; - Configuration* configure_(const Configuration&) const; + Spec* generate_spec_(const Spec&) const; void list_(std::ostream&) const; mutable Mutex mutex_; diff --git a/src/eckit/geo/GridConfig.cc b/src/eckit/geo/GridConfig.cc index 3adca680e..684ebc6fa 100644 --- a/src/eckit/geo/GridConfig.cc +++ b/src/eckit/geo/GridConfig.cc @@ -19,7 +19,7 @@ #include "eckit/filesystem/PathName.h" #include "eckit/geo/Grid.h" #include "eckit/geo/LibEcKitGeo.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/parser/YAMLParser.h" #include "eckit/value/Value.h" @@ -32,14 +32,14 @@ namespace { template -spec::MappedConfiguration::value_type __from_value(const Value& value) { +spec::Custom::value_type __from_value(const Value& value) { T to; fromValue(to, value); return {to}; } -void set_config_value(spec::MappedConfiguration& config, const std::string& key, const Value& value) { +void set_config_value(spec::Custom& config, const std::string& key, const Value& value) { using number_type = pl_type::value_type; auto list_of = [](const ValueList& list, auto pred) { return std::all_of(list.begin(), list.end(), pred); }; @@ -57,8 +57,8 @@ void set_config_value(spec::MappedConfiguration& config, const std::string& key, } -spec::MappedConfiguration* config_from_value_map(const ValueMap& map) { - auto* config = new spec::MappedConfiguration; +spec::Custom* config_from_value_map(const ValueMap& map) { + auto* config = new spec::Custom; for (const auto& kv : map) { set_config_value(*config, kv.first, kv.second); } @@ -76,23 +76,21 @@ const GridConfig& GridConfig::instance() { GridConfig::GridConfig(const PathName& path) { - auto* config = new spec::MappedConfiguration; + auto* config = new spec::Custom; config_.reset(config); - struct ConfigurationFromUID final : GridConfigurationUID::configurator_t { - explicit ConfigurationFromUID(spec::MappedConfiguration* config) : + struct SpecUID final : SpecByUID::configurator_t { + explicit SpecUID(spec::Custom* config) : config_(config) {} - Configuration* config() const override { return new spec::MappedConfiguration(*config_); } - std::unique_ptr config_; + Spec* config() const override { return new spec::Custom(*config_); } + std::unique_ptr config_; }; - struct ConfigurationFromName final : GridConfigurationName::configurator_t { - explicit ConfigurationFromName(spec::MappedConfiguration* config) : + struct SpecName final : SpecByName::configurator_t { + explicit SpecName(spec::Custom* config) : config_(config) {} - Configuration* config(GridConfigurationName::configurator_t::arg1_t) const override { - return new spec::MappedConfiguration(*config_); - } - std::unique_ptr config_; + Spec* config(SpecByName::configurator_t::arg1_t) const override { return new spec::Custom(*config_); } + std::unique_ptr config_; }; if (path.exists()) { @@ -104,9 +102,8 @@ GridConfig::GridConfig(const PathName& path) { if (key == "grid_uids") { for (ValueMap m : static_cast(kv.second)) { ASSERT(m.size() == 1); - GridConfigurationUID::instance().regist( - m.begin()->first.as(), - new ConfigurationFromUID(config_from_value_map(m.begin()->second))); + SpecByUID::instance().regist(m.begin()->first.as(), + new SpecUID(config_from_value_map(m.begin()->second))); } continue; } @@ -114,9 +111,8 @@ GridConfig::GridConfig(const PathName& path) { if (key == "grid_names") { for (ValueMap m : static_cast(kv.second)) { ASSERT(m.size() == 1); - GridConfigurationName::instance().regist( - m.begin()->first.as(), - new ConfigurationFromName(config_from_value_map(m.begin()->second))); + SpecByName::instance().regist(m.begin()->first.as(), + new SpecName(config_from_value_map(m.begin()->second))); } continue; } diff --git a/src/eckit/geo/GridConfig.h b/src/eckit/geo/GridConfig.h index e17808663..148fcd512 100644 --- a/src/eckit/geo/GridConfig.h +++ b/src/eckit/geo/GridConfig.h @@ -16,7 +16,9 @@ namespace eckit { -class Configuration; +namespace geo { +class Spec; +} class PathName; } // namespace eckit @@ -48,7 +50,7 @@ class GridConfig final { static const GridConfig& instance(); - const Configuration& config() const { return *config_; } + const Spec& config() const { return *config_; } // -- Overridden methods // None @@ -66,7 +68,7 @@ class GridConfig final { // -- Members - std::unique_ptr config_; + std::unique_ptr config_; // -- Methods // None diff --git a/src/eckit/geo/Increments.cc b/src/eckit/geo/Increments.cc index b64e776da..a8989aa55 100644 --- a/src/eckit/geo/Increments.cc +++ b/src/eckit/geo/Increments.cc @@ -12,16 +12,17 @@ #include "eckit/geo/Increments.h" -#include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Spec.h" #include "eckit/types/FloatCompare.h" namespace eckit::geo { -static Increments make_from_config(const Configuration& config) { - auto grid = config.getDoubleVector("grid"); +static Increments make_from_spec(const Spec& spec) { + std::vector grid; + spec.get("grid", grid); ASSERT_MSG(grid.size() == 2, "Increments: expected list of size 2"); return {grid[0], grid[1]}; @@ -35,8 +36,8 @@ Increments::Increments(double west_east, double south_north) : } -Increments::Increments(const Configuration& config) : - Increments(make_from_config(config)) {} +Increments::Increments(const Spec& spec) : + Increments(make_from_spec(spec)) {} bool Increments::operator==(const Increments& other) const { diff --git a/src/eckit/geo/Increments.h b/src/eckit/geo/Increments.h index ed229ea1b..66439a11e 100644 --- a/src/eckit/geo/Increments.h +++ b/src/eckit/geo/Increments.h @@ -16,8 +16,8 @@ #include -namespace eckit { -class Configuration; +namespace eckit::geo { +class Spec; } @@ -31,7 +31,7 @@ class Increments : protected std::array { // -- Constructors - explicit Increments(const Configuration&); + explicit Increments(const Spec&); Increments(double west_east, double south_north); diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 121abdfdc..816c470c5 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -19,12 +19,12 @@ #include "eckit/memory/Factory.h" -namespace eckit { -class Configuration; -namespace geo::spec { -class MappedConfiguration; +namespace eckit::geo { +class Spec; +namespace spec { +class Custom; } -} // namespace eckit +} // namespace eckit::geo namespace eckit::geo { @@ -35,9 +35,7 @@ class Projection { // -- Types using builder_t = BuilderT1; - using ARG1 = const Configuration&; - - using Spec = spec::MappedConfiguration; + using ARG1 = const Spec&; // -- Exceptions // None @@ -67,7 +65,7 @@ class Projection { virtual Point fwd(const Point&) const = 0; virtual Point inv(const Point&) const = 0; - virtual Spec spec() const = 0; + virtual Spec* spec() const = 0; // -- Overridden methods // None diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 3912ce29a..e5b03e328 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -12,15 +12,15 @@ #include "eckit/geo/Range.h" -#include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Spec.h" namespace eckit::geo { -Range::Range(const Configuration& config) : - Range(config.getUnsigned("n")) {} +Range::Range(const Spec& spec) : + Range(spec.get_unsigned("n", 0)) {} Range::Range(size_t n) : diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 6346d6391..bcb0bdb95 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -15,8 +15,8 @@ #include -namespace eckit { -class Configuration; +namespace eckit::geo { +class Spec; } @@ -70,7 +70,7 @@ class Range : protected std::vector { protected: // -- Constructors - explicit Range(const Configuration&); + explicit Range(const Spec&); explicit Range(size_t n); // -- Members diff --git a/src/eckit/geo/Spec.cc b/src/eckit/geo/Spec.cc new file mode 100644 index 000000000..72f906a60 --- /dev/null +++ b/src/eckit/geo/Spec.cc @@ -0,0 +1,118 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Spec.h" + +#include "eckit/log/JSON.h" + + +namespace eckit::geo { + + +template +static T _get(const Spec& spec, const std::string& name, const T& _default) { + T value{_default}; + spec.get(name, value); + return value; +} + + +SpecNotFound::SpecNotFound(const std::string& name) { + std::ostringstream s; + s << "SpecNotFound: [" << name << "]"; + reason(s.str()); +} + + +bool Spec::get_bool(const std::string& name) const { + ASSERT(has(name)); + return _get(*this, name, false); +} + + +int Spec::get_int(const std::string& name) const { + ASSERT(has(name)); + return _get(*this, name, 0); +} + + +long Spec::get_long(const std::string& name) const { + ASSERT(has(name)); + return _get(*this, name, 0); +} + + +std::size_t Spec::get_unsigned(const std::string& name) const { + ASSERT(has(name)); + return _get(*this, name, 0); +} + + +double Spec::get_double(const std::string& name) const { + ASSERT(has(name)); + return _get(*this, name, 0); +} + + +std::string Spec::get_string(const std::string& name) const { + ASSERT(has(name)); + return _get(*this, name, {}); +} + + +std::vector Spec::get_long_vector(const std::string& name) const { + ASSERT(has(name)); + return _get>(*this, name, {}); +} + + +bool Spec::get_bool(const std::string& name, const bool& _default) const { + return _get(*this, name, _default); +} + + +int Spec::get_int(const std::string& name, const int& _default) const { + return _get(*this, name, _default); +} + + +long Spec::get_long(const std::string& name, const long& _default) const { + return _get(*this, name, _default); +} + + +std::size_t Spec::get_unsigned(const std::string& name, const std::size_t& _default) const { + return _get(*this, name, _default); +} + + +double Spec::get_double(const std::string& name, const double& _default) const { + return _get(*this, name, _default); +} + + +std::string Spec::get_string(const std::string& name, const std::string& _default) const { + return _get(*this, name, _default); +} + + +std::vector Spec::get_long_vector(const std::string& name, const std::vector& _default) const { + return _get(*this, name, _default); +} + + +void Spec::print(std::ostream& out) const { + JSON j(out); + json(j); +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Spec.h b/src/eckit/geo/Spec.h new file mode 100644 index 000000000..9cb7849f8 --- /dev/null +++ b/src/eckit/geo/Spec.h @@ -0,0 +1,72 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include + +#include "eckit/config/Parametrisation.h" +#include "eckit/exception/Exceptions.h" + + +namespace eckit { +class JSON; +} + + +namespace eckit::geo { + + +class SpecNotFound : public Exception { +public: + explicit SpecNotFound(const std::string& name); +}; + + +class Spec : public Parametrisation { +public: + Spec() = default; + ~Spec() override = default; + + Spec(const Spec&) = delete; + Spec(Spec&&) = delete; + + Spec& operator=(const Spec&) = delete; + Spec& operator=(Spec&&) = delete; + + bool get_bool(const std::string& name) const; + int get_int(const std::string& name) const; + long get_long(const std::string& name) const; + std::size_t get_unsigned(const std::string& name) const; + double get_double(const std::string& name) const; + std::string get_string(const std::string& name) const; + std::vector get_long_vector(const std::string& name) const; + + bool get_bool(const std::string& name, const bool&) const; + int get_int(const std::string& name, const int&) const; + long get_long(const std::string& name, const long&) const; + std::size_t get_unsigned(const std::string& name, const std::size_t&) const; + double get_double(const std::string& name, const double&) const; + std::string get_string(const std::string& name, const std::string&) const; + std::vector get_long_vector(const std::string& name, const std::vector&) const; + +private: + virtual void print(std::ostream&) const; + virtual void json(JSON&) const = 0; + + friend std::ostream& operator<<(std::ostream& out, const Spec& spec) { + spec.print(out); + return out; + } +}; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index dc93cd13f..ae3419945 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -16,9 +16,9 @@ #include #include -#include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/PointLonLat.h" +#include "eckit/geo/Spec.h" #include "eckit/geo/Sphere.h" #include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -30,18 +30,18 @@ namespace eckit::geo::area { static constexpr std::array DEFAULT{90, 0, -90, 360}; -static BoundingBox make_from_config(const Configuration& config) { - if (std::vector area{DEFAULT[0], DEFAULT[1], DEFAULT[2], DEFAULT[3]}; config.get("area", area)) { +static BoundingBox make_from_spec(const Spec& spec) { + if (std::vector area{DEFAULT[0], DEFAULT[1], DEFAULT[2], DEFAULT[3]}; spec.get("area", area)) { ASSERT_MSG(area.size() == 4, "BoundingBox: 'area' expected list of size 4"); return {area[0], area[1], area[2], area[3]}; } - if (auto area(DEFAULT); config.get("north", area[0]) && config.get("west", area[1]) && - config.get("south", area[2]) && config.get("east", area[3])) { + if (auto area(DEFAULT); spec.get("north", area[0]) && spec.get("west", area[1]) && spec.get("south", area[2]) && + spec.get("east", area[3])) { return {area[0], area[1], area[2], area[3]}; } - if (!config.has("north") && !config.has("west") && !config.has("south") && !config.has("east")) { + if (!spec.has("north") && !spec.has("west") && !spec.has("south") && !spec.has("east")) { return {}; } @@ -49,8 +49,8 @@ static BoundingBox make_from_config(const Configuration& config) { } -BoundingBox::BoundingBox(const Configuration& config) : - BoundingBox(make_from_config(config)) {} +BoundingBox::BoundingBox(const Spec& spec) : + BoundingBox(make_from_spec(spec)) {} BoundingBox::BoundingBox(double n, double w, double s, double e) : diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 0f7b1f7d5..6caa5283e 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -33,7 +33,7 @@ class BoundingBox : public Area, protected std::array { // -- Constructors - explicit BoundingBox(const Configuration&); + explicit BoundingBox(const Spec&); BoundingBox(double north, double west, double south, double east); diff --git a/src/eckit/geo/figure/OblateSpheroid.cc b/src/eckit/geo/figure/OblateSpheroid.cc index bfdd2cb41..d2618ddf8 100644 --- a/src/eckit/geo/figure/OblateSpheroid.cc +++ b/src/eckit/geo/figure/OblateSpheroid.cc @@ -12,8 +12,8 @@ #include "eckit/geo/figure/OblateSpheroid.h" -#include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Spec.h" #include "eckit/types/FloatCompare.h" @@ -26,8 +26,8 @@ OblateSpheroid::OblateSpheroid(double a, double b) : } -OblateSpheroid::OblateSpheroid(const Configuration& config) : - OblateSpheroid(config.getDouble("a"), config.getDouble("b")) {} +OblateSpheroid::OblateSpheroid(const Spec& spec) : + OblateSpheroid(spec.get_double("a"), spec.get_double("b")) {} double OblateSpheroid::R() const { diff --git a/src/eckit/geo/figure/OblateSpheroid.h b/src/eckit/geo/figure/OblateSpheroid.h index 96a88aa37..d9f66626b 100644 --- a/src/eckit/geo/figure/OblateSpheroid.h +++ b/src/eckit/geo/figure/OblateSpheroid.h @@ -29,7 +29,7 @@ class OblateSpheroid final : public Figure { // -- Constructors OblateSpheroid(double R, double b); - OblateSpheroid(const Configuration&); + OblateSpheroid(const Spec&); // -- Destructor // None diff --git a/src/eckit/geo/figure/Sphere.cc b/src/eckit/geo/figure/Sphere.cc index 9980ffa2a..0e980287e 100644 --- a/src/eckit/geo/figure/Sphere.cc +++ b/src/eckit/geo/figure/Sphere.cc @@ -12,8 +12,8 @@ #include "eckit/geo/figure/Sphere.h" -#include "eckit/config/Configuration.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Spec.h" #include "eckit/types/FloatCompare.h" @@ -26,8 +26,8 @@ Sphere::Sphere(double R) : } -Sphere::Sphere(const Configuration& config) : - Sphere(config.getDouble("R")) {} +Sphere::Sphere(const Spec& spec) : + Sphere(spec.get_double("R")) {} } // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/Sphere.h b/src/eckit/geo/figure/Sphere.h index 3be6dc40b..9093f3d8d 100644 --- a/src/eckit/geo/figure/Sphere.h +++ b/src/eckit/geo/figure/Sphere.h @@ -29,7 +29,7 @@ class Sphere final : public Figure { // -- Constructors Sphere(double R); - Sphere(const Configuration&); + Sphere(const Spec&); // -- Destructor // None diff --git a/src/eckit/geo/grid/Reduced.cc b/src/eckit/geo/grid/Reduced.cc index 74bb6b4e0..686c841a2 100644 --- a/src/eckit/geo/grid/Reduced.cc +++ b/src/eckit/geo/grid/Reduced.cc @@ -64,8 +64,8 @@ std::pair, std::vector > Reduced::to_latlon() const } -Reduced::Reduced(const Configuration& config) : - Grid(config) {} +Reduced::Reduced(const Spec& spec) : + Grid(spec) {} Reduced::Reduced(const area::BoundingBox& bbox) : diff --git a/src/eckit/geo/grid/Reduced.h b/src/eckit/geo/grid/Reduced.h index 759cfeed5..d153e8d4b 100644 --- a/src/eckit/geo/grid/Reduced.h +++ b/src/eckit/geo/grid/Reduced.h @@ -62,7 +62,7 @@ class Reduced : public Grid { protected: // -- Constructors - explicit Reduced(const Configuration&); + explicit Reduced(const Spec&); explicit Reduced(const area::BoundingBox&); // -- Members diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index a011259e0..070b3962d 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -18,8 +18,8 @@ namespace eckit::geo::grid { -Regular::Regular(const Configuration& config) : - Grid(config) {} +Regular::Regular(const Spec& spec) : + Grid(spec) {} Regular::Regular(const area::BoundingBox& bbox) : diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index 9607c43ac..f12a7fb1a 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -62,7 +62,7 @@ class Regular : public Grid { protected: // -- Constructors - explicit Regular(const Configuration&); + explicit Regular(const Spec&); explicit Regular(const area::BoundingBox&); // -- Members diff --git a/src/eckit/geo/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc index 61fa321a0..d25d15328 100644 --- a/src/eckit/geo/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -28,8 +28,8 @@ Grid::iterator Unstructured::cend() const { } -Unstructured::Unstructured(const Configuration& config) : - Grid(config) {} +Unstructured::Unstructured(const Spec& spec) : + Grid(spec) {} Unstructured::Unstructured(const area::BoundingBox& bbox) : diff --git a/src/eckit/geo/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h index 9b606b6e8..73ca1c6f7 100644 --- a/src/eckit/geo/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -61,7 +61,7 @@ class Unstructured : public Grid { protected: // -- Constructors - explicit Unstructured(const Configuration&); + explicit Unstructured(const Spec&); explicit Unstructured(const area::BoundingBox&); // -- Members diff --git a/src/eckit/geo/grid/reduced/HEALPix.cc b/src/eckit/geo/grid/reduced/HEALPix.cc index 8a721f668..dcb7a1536 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.cc +++ b/src/eckit/geo/grid/reduced/HEALPix.cc @@ -19,7 +19,7 @@ #include #include "eckit/geo/iterator/Reduced.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/utils/Translator.h" @@ -227,8 +227,8 @@ static Ordering ordering_from_string(const std::string& str) { } -HEALPix::HEALPix(const Configuration& config) : - HEALPix(config.getUnsigned("Nside"), ordering_from_string(config.getString("orderingConvention", "ring"))) {} +HEALPix::HEALPix(const Spec& spec) : + HEALPix(spec.get_unsigned("Nside"), ordering_from_string(spec.get_string("orderingConvention", "ring"))) {} HEALPix::HEALPix(size_t Nside, Ordering ordering) : @@ -294,9 +294,9 @@ size_t HEALPix::nj() const { } -Configuration* HEALPix::config(const std::string& name) { +Spec* HEALPix::config(const std::string& name) { auto Nside = Translator{}(name.substr(1)); - return new spec::MappedConfiguration({{"type", "HEALPix"}, {"Nside", Nside}, {"orderingConvention", "ring"}}); + return new spec::Custom({{"type", "HEALPix"}, {"Nside", Nside}, {"orderingConvention", "ring"}}); } diff --git a/src/eckit/geo/grid/reduced/HEALPix.h b/src/eckit/geo/grid/reduced/HEALPix.h index fd1d2c642..cb43f5897 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.h +++ b/src/eckit/geo/grid/reduced/HEALPix.h @@ -28,7 +28,7 @@ class HEALPix final : public Reduced { // -- Constructors - explicit HEALPix(const Configuration&); + explicit HEALPix(const Spec&); explicit HEALPix(size_t Nside, Ordering = Ordering::healpix_ring); // -- Destructor @@ -57,7 +57,7 @@ class HEALPix final : public Reduced { // -- Class members - static Configuration* config(const std::string& name); + static Spec* config(const std::string& name); // -- Class methods // None diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index f1c1b2863..b7cc487a1 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -17,15 +17,15 @@ #include "eckit/geo/iterator/Reduced.h" #include "eckit/geo/range/Gaussian.h" #include "eckit/geo/range/Regular.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/utils/Translator.h" namespace eckit::geo::grid::reduced { -ReducedGaussian::ReducedGaussian(const Configuration& config) : - ReducedGaussian(config.getUnsigned("N"), config.getLongVector("pl"), area::BoundingBox(config)) {} +ReducedGaussian::ReducedGaussian(const Spec& spec) : + ReducedGaussian(spec.get_unsigned("N"), spec.get_long_vector("pl"), area::BoundingBox(spec)) {} ReducedGaussian::ReducedGaussian(size_t N, const pl_type& pl, const area::BoundingBox& bbox) : @@ -71,18 +71,17 @@ std::vector ReducedGaussian::longitudes(size_t j) const { struct ReducedGaussianClassical { - static Configuration* config(const std::string& name) { + static Spec* config(const std::string& name) { auto N = Translator{}(name.substr(1)); - return new spec::MappedConfiguration({{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_classical_pl(N)}}); + return new spec::Custom({{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_classical_pl(N)}}); } }; struct ReducedGaussianOctahedral { - static Configuration* config(const std::string& name) { + static Spec* config(const std::string& name) { auto N = Translator{}(name.substr(1)); - return new spec::MappedConfiguration( - {{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_octahedral_pl(N)}}); + return new spec::Custom({{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_octahedral_pl(N)}}); } }; diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.h b/src/eckit/geo/grid/reduced/ReducedGaussian.h index 492eef657..5ae7dbc37 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.h @@ -36,7 +36,7 @@ class ReducedGaussian : public Reduced { // -- Constructors - explicit ReducedGaussian(const Configuration&); + explicit ReducedGaussian(const Spec&); ReducedGaussian(size_t N, const pl_type& pl, const area::BoundingBox& = area::BoundingBox::make_global_prime()); // -- Destructor diff --git a/src/eckit/geo/grid/reduced/ReducedLL.cc b/src/eckit/geo/grid/reduced/ReducedLL.cc index c4a3ab463..b525a081a 100644 --- a/src/eckit/geo/grid/reduced/ReducedLL.cc +++ b/src/eckit/geo/grid/reduced/ReducedLL.cc @@ -18,8 +18,8 @@ namespace eckit::geo::grid::reduced { -ReducedLL::ReducedLL(const Configuration& config) : - Reduced(config) {} +ReducedLL::ReducedLL(const Spec& spec) : + Reduced(spec) {} Grid::iterator ReducedLL::cbegin() const { diff --git a/src/eckit/geo/grid/reduced/ReducedLL.h b/src/eckit/geo/grid/reduced/ReducedLL.h index 3d826bbe4..e890bf215 100644 --- a/src/eckit/geo/grid/reduced/ReducedLL.h +++ b/src/eckit/geo/grid/reduced/ReducedLL.h @@ -28,7 +28,7 @@ class ReducedLL : public Reduced { // -- Constructors - explicit ReducedLL(const Configuration&); + explicit ReducedLL(const Spec&); // -- Destructor // None diff --git a/src/eckit/geo/grid/regular/IrregularLL.cc b/src/eckit/geo/grid/regular/IrregularLL.cc index 89f83f60c..3ee5d9d39 100644 --- a/src/eckit/geo/grid/regular/IrregularLL.cc +++ b/src/eckit/geo/grid/regular/IrregularLL.cc @@ -18,8 +18,8 @@ namespace eckit::geo::grid::regular { -IrregularLL::IrregularLL(const Configuration& config) : - Regular(config) {} +IrregularLL::IrregularLL(const Spec& spec) : + Regular(spec) {} Grid::iterator IrregularLL::cbegin() const { diff --git a/src/eckit/geo/grid/regular/IrregularLL.h b/src/eckit/geo/grid/regular/IrregularLL.h index c8b8edd91..828ccd63b 100644 --- a/src/eckit/geo/grid/regular/IrregularLL.h +++ b/src/eckit/geo/grid/regular/IrregularLL.h @@ -28,7 +28,7 @@ class IrregularLL final : public Regular { // -- Constructors - explicit IrregularLL(const Configuration&); + explicit IrregularLL(const Spec&); // -- Destructor // None diff --git a/src/eckit/geo/grid/regular/Mercator.cc b/src/eckit/geo/grid/regular/Mercator.cc index 04119b02a..26707493a 100644 --- a/src/eckit/geo/grid/regular/Mercator.cc +++ b/src/eckit/geo/grid/regular/Mercator.cc @@ -14,7 +14,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/iterator/Regular.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/geo/util/regex.h" #include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" @@ -26,8 +26,8 @@ namespace eckit::geo::grid::regular { static const GridRegisterType __grid_type("mercator"); -Mercator::Mercator(const Configuration& config) : - Mercator(config.getUnsigned("ni"), config.getUnsigned("nj"), Increments{config}, area::BoundingBox{config}) {} +Mercator::Mercator(const Spec& spec) : + Mercator(spec.get_unsigned("ni"), spec.get_unsigned("nj"), Increments{spec}, area::BoundingBox{spec}) {} Mercator::Mercator(size_t ni, size_t nj, const Increments& inc, const area::BoundingBox& bbox) : diff --git a/src/eckit/geo/grid/regular/Mercator.h b/src/eckit/geo/grid/regular/Mercator.h index 42ea855de..06c79a1c8 100644 --- a/src/eckit/geo/grid/regular/Mercator.h +++ b/src/eckit/geo/grid/regular/Mercator.h @@ -30,7 +30,7 @@ class Mercator final : public Regular { // -- Constructors - explicit Mercator(const Configuration&); + explicit Mercator(const Spec&); Mercator(size_t ni, size_t nj, const Increments&, const area::BoundingBox&); diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index bad26b975..3006968e1 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -15,15 +15,15 @@ #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/range/Gaussian.h" #include "eckit/geo/range/RegularLongitude.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/utils/Translator.h" namespace eckit::geo::grid::regular { -RegularGaussian::RegularGaussian(const Configuration& config) : - RegularGaussian(config.getUnsigned("N"), config.getUnsigned("ni"), area::BoundingBox(config)) {} +RegularGaussian::RegularGaussian(const Spec& spec) : + RegularGaussian(spec.get_unsigned("N"), spec.get_unsigned("ni"), area::BoundingBox(spec)) {} RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : @@ -49,9 +49,9 @@ Grid::iterator RegularGaussian::cend() const { } -Configuration* RegularGaussian::config(const std::string& name) { +Spec* RegularGaussian::config(const std::string& name) { auto N = Translator{}(name.substr(1)); - return new spec::MappedConfiguration({{"type", "regular_gg"}, {"N", N}, {"ni", 4 * N}}); + return new spec::Custom({{"type", "regular_gg"}, {"N", N}, {"ni", 4 * N}}); } diff --git a/src/eckit/geo/grid/regular/RegularGaussian.h b/src/eckit/geo/grid/regular/RegularGaussian.h index 10105244d..292c2c9e4 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.h +++ b/src/eckit/geo/grid/regular/RegularGaussian.h @@ -29,7 +29,7 @@ class RegularGaussian final : public Regular { // -- Constructors - explicit RegularGaussian(const Configuration&); + explicit RegularGaussian(const Spec&); explicit RegularGaussian(size_t N, const area::BoundingBox& = area::BoundingBox::make_global_prime()); RegularGaussian(size_t N, size_t ni, const area::BoundingBox& = area::BoundingBox::make_global_prime()); @@ -58,7 +58,7 @@ class RegularGaussian final : public Regular { // -- Class methods - static Configuration* config(const std::string& name); + static Spec* config(const std::string& name); private: // -- Members diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index 92d4d2548..c7354fdfa 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -17,7 +17,7 @@ #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/range/Regular.h" #include "eckit/geo/range/RegularLongitude.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/geo/util/regex.h" #include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" @@ -104,12 +104,12 @@ struct DiscreteRange { }; -PointLonLat make_reference_from_config(const Configuration& config) { - if (double lon = 0, lat = 0; config.get("reference_lon", lon) && config.get("reference_lat", lat)) { +PointLonLat make_reference_from_spec(const Spec& spec) { + if (double lon = 0, lat = 0; spec.get("reference_lon", lon) && spec.get("reference_lat", lat)) { return {lon, lat}; } - area::BoundingBox area(config); + area::BoundingBox area(spec); return {area.west, area.south}; } @@ -132,8 +132,8 @@ RegularLL::Internal::Internal(const Increments& _inc, const area::BoundingBox& _ } -RegularLL::RegularLL(const Configuration& config) : - RegularLL(Increments{config}, area::BoundingBox{config}, make_reference_from_config(config)) {} +RegularLL::RegularLL(const Spec& spec) : + RegularLL(Increments{spec}, area::BoundingBox{spec}, make_reference_from_spec(spec)) {} RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : @@ -178,7 +178,7 @@ const std::vector& RegularLL::latitudes() const { #define POSITIVE_REAL "[+]?([0-9]*[.])?[0-9]+([eE][-+][0-9]+)?" -Configuration* RegularLL::config(const std::string& name) { +Spec* RegularLL::config(const std::string& name) { static const std::string pattern("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); auto match = util::regex_match(pattern, name); @@ -192,7 +192,7 @@ Configuration* RegularLL::config(const std::string& name) { // Fraction(360)).n(); auto nj = 1; // detail::RegularIterator(Fraction(-90), Fraction(90), Fraction(increments[1]), Fraction(0)).n(); - return new spec::MappedConfiguration({{"type", "regular_ll"}, {"grid", increments}, {"ni", ni}, {"nj", nj}}); + return new spec::Custom({{"type", "regular_ll"}, {"grid", increments}, {"ni", ni}, {"nj", nj}}); } diff --git a/src/eckit/geo/grid/regular/RegularLL.h b/src/eckit/geo/grid/regular/RegularLL.h index c13545563..22c1a3d30 100644 --- a/src/eckit/geo/grid/regular/RegularLL.h +++ b/src/eckit/geo/grid/regular/RegularLL.h @@ -54,7 +54,7 @@ class RegularLL final : public Regular { // -- Constructors - explicit RegularLL(const Configuration&); + explicit RegularLL(const Spec&); explicit RegularLL(const Increments&, const area::BoundingBox& = {}); RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); @@ -83,7 +83,7 @@ class RegularLL final : public Regular { // -- Class methods - static Configuration* config(const std::string& name); + static Spec* config(const std::string& name); private: // -- Members diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index 90298b2b5..5a4589682 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -17,6 +17,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "eckit/geo/LibEcKitGeo.h" +#include "eckit/geo/Spec.h" #include "eckit/geo/area/BoundingBox.h" #include "eckit/geo/iterator/Unstructured.h" #include "eckit/io/Length.h" @@ -60,15 +61,15 @@ std::string arrangement_to_string(ORCA::Arrangement a) { } // namespace -ORCA::ORCA(const Configuration& config) : - Unstructured(config), - name_(config.getString("orca_name")), - uid_(config.getString("orca_uid")), - arrangement_(arrangement_from_string(config.getString("orca_arrangement"))), +ORCA::ORCA(const Spec& spec) : + Unstructured(spec), + name_(spec.get_string("orca_name")), + uid_(spec.get_string("orca_uid")), + arrangement_(arrangement_from_string(spec.get_string("orca_arrangement"))), dimensions_{-1, -1}, halo_{-1, -1, -1, -1}, pivot_{-1, -1} { - PathName path = config.getString("path", LibEcKitGeo::cacheDir() + "/eckit/geo/orca/" + uid_ + ".atlas"); + PathName path = spec.get_string("path", LibEcKitGeo::cacheDir() + "/eckit/geo/orca/" + uid_ + ".atlas"); #if eckit_HAVE_CURL // for eckit::URLHandle if (!path.exists() && LibEcKitGeo::caching()) { @@ -77,7 +78,7 @@ ORCA::ORCA(const Configuration& config) : ASSERT(dir.exists()); auto tmp = path + ".download"; - auto url = config.getString("url_prefix", "") + config.getString("url"); + auto url = spec.get_string("url_prefix", "") + spec.get_string("url"); Timer timer; Log::info() << "ORCA: downloading '" << url << "' to '" << path << "'..." << std::endl; @@ -108,7 +109,7 @@ ORCA::ORCA(const Configuration& config) : // read and check against metadata (if present) read(path); - check(config); + check(spec); } @@ -159,23 +160,23 @@ void ORCA::read(const PathName& p) { } -void ORCA::check(const Configuration& config) { +void ORCA::check(const Spec& spec) { ASSERT(uid_.length() == 32); - if (config.getBool("orca_uid_check", false)) { + if (spec.get_bool("orca_uid_check", false)) { ASSERT(uid_ == uid()); } - if (std::vector d; config.get("dimensions", d)) { + if (std::vector d; spec.get("dimensions", d)) { ASSERT(d.size() == 2); ASSERT(d[0] == dimensions_[0] && d[1] == dimensions_[1]); } - if (std::vector h; config.get("halo", h)) { + if (std::vector h; spec.get("halo", h)) { ASSERT(h.size() == 4); ASSERT(h[0] == halo_[0] && h[1] == halo_[1] && h[2] == halo_[2] && h[3] == halo_[3]); } - if (std::vector p; config.get("pivot", p)) { + if (std::vector p; spec.get("pivot", p)) { ASSERT(p.size() == 2); ASSERT(types::is_approximately_equal(p[0], pivot_[0])); ASSERT(types::is_approximately_equal(p[1], pivot_[1])); @@ -228,8 +229,8 @@ std::pair, std::vector> ORCA::to_latlon() const { } -Configuration* ORCA::config(const std::string& name) { - return GridConfigurationUID::instance().get(name).config(); +Spec* ORCA::config(const std::string& name) { + return SpecByUID::instance().get(name).config(); } diff --git a/src/eckit/geo/grid/unstructured/ORCA.h b/src/eckit/geo/grid/unstructured/ORCA.h index 1e79d05da..11bdc244a 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.h +++ b/src/eckit/geo/grid/unstructured/ORCA.h @@ -45,7 +45,7 @@ class ORCA final : public Unstructured { // -- Constructors - explicit ORCA(const Configuration&); + explicit ORCA(const Spec&); // -- Destructor // None @@ -61,7 +61,7 @@ class ORCA final : public Unstructured { uid_t calculate_uid() const; void read(const PathName&); - void check(const Configuration&); + void check(const Spec&); size_t write(const PathName&, const std::string& compression = "none"); size_t ni() const { return static_cast(dimensions_[0]); } @@ -91,7 +91,7 @@ class ORCA final : public Unstructured { // -- Class methods - static Configuration* config(const std::string& name); + static Spec* config(const std::string& name); private: // -- Members diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc index b1a423783..aa7d9439e 100644 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc @@ -75,8 +75,8 @@ std::vector UnstructuredFromGrid::to_points() const { } -Configuration* UnstructuredFromGrid::config(const std::string& name) { - return GridConfigurationUID::instance().get(name).config(); +Spec* UnstructuredFromGrid::config(const std::string& name) { + return SpecByUID::instance().get(name).config(); } diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h index 638bff622..1562a6a06 100644 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h @@ -76,7 +76,7 @@ class UnstructuredFromGrid final : public Unstructured { // -- Class methods - static Configuration* config(const std::string& name); + static Spec* config(const std::string& name); private: // -- Members diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc index 38a2732f7..320c8a3a0 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -14,7 +14,7 @@ #include "eckit/geo/EllipsoidOfRevolution.h" #include "eckit/geo/Sphere.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/types/FloatCompare.h" @@ -35,7 +35,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { R_(R) {} Point3 operator()(const PointLonLat& p) const override { return S::convertSphericalToCartesian(R_, p, 0.); } PointLonLat operator()(const Point3& q) const override { return S::convertCartesianToSpherical(R_, q); } - Spec spec() const override { return Spec{{{"R", R_}}}; } + Spec* spec() const override { return new spec::Custom{{{"R", R_}}}; } }; struct LonLatToSpheroidXYZ final : Implementation { @@ -47,7 +47,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { a_(a), b_(b) {} Point3 operator()(const PointLonLat& p) const override { return S::convertSphericalToCartesian(a_, b_, p, 0.); } PointLonLat operator()(const Point3& q) const override { NOTIMP; } - Spec spec() const override { return Spec{{{"a", a_}, {"b", b_}}}; } + Spec* spec() const override { return new spec::Custom{{{"a", a_}, {"b", b_}}}; } }; impl_.reset(types::is_approximately_equal(a, b) ? static_cast(new LonLatToSphereXYZ(a)) @@ -59,11 +59,11 @@ LonLatToXYZ::LonLatToXYZ(double R) : LonLatToXYZ(R, R) {} -LonLatToXYZ::LonLatToXYZ(const Configuration& config) : - LonLatToXYZ(config.getDouble("a", config.getDouble("R", 1.)), config.getDouble("b", config.getDouble("R", 1.))) {} +LonLatToXYZ::LonLatToXYZ(const Spec& spec) : + LonLatToXYZ(spec.get_double("a", spec.get_double("R", 1.)), spec.get_double("b", spec.get_double("R", 1.))) {} -Projection::Spec LonLatToXYZ::spec() const { +Spec* LonLatToXYZ::spec() const { return impl_->spec(); } diff --git a/src/eckit/geo/projection/LonLatToXYZ.h b/src/eckit/geo/projection/LonLatToXYZ.h index 9b2ea6998..bb979acd6 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.h +++ b/src/eckit/geo/projection/LonLatToXYZ.h @@ -30,7 +30,7 @@ class LonLatToXYZ final : public Projection { LonLatToXYZ(double a, double b); explicit LonLatToXYZ(double R); - explicit LonLatToXYZ(const Configuration&); + explicit LonLatToXYZ(const Spec&); // -- Destructor // None @@ -48,7 +48,7 @@ class LonLatToXYZ final : public Projection { // -- Overridden methods - Spec spec() const override; + Spec* spec() const override; // -- Class members // None @@ -70,7 +70,7 @@ class LonLatToXYZ final : public Projection { virtual Point3 operator()(const PointLonLat&) const = 0; virtual PointLonLat operator()(const Point3&) const = 0; - virtual Spec spec() const = 0; + virtual Spec* spec() const = 0; }; // -- Members diff --git a/src/eckit/geo/projection/Mercator.cc b/src/eckit/geo/projection/Mercator.cc index 02216a42d..676ac1842 100644 --- a/src/eckit/geo/projection/Mercator.cc +++ b/src/eckit/geo/projection/Mercator.cc @@ -14,7 +14,7 @@ #include -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -59,11 +59,11 @@ Mercator::Mercator(double meridian, double parallel, Figure* figure, PointLonLat } -Mercator::Mercator(const Configuration& config) : - Mercator(config.getDouble("meridian"), - config.getDouble("parallel"), - FigureFactory::instance().get(config.getString("figure")).create(config), - PointLonLat{config.getDouble("lon0"), config.getDouble("lat0")}) {} +Mercator::Mercator(const Spec& spec) : + Mercator(spec.get_double("meridian"), + spec.get_double("parallel"), + FigureFactory::instance().get(spec.get_string("figure")).create(spec), + PointLonLat{spec.get_double("lon0"), spec.get_double("lat0")}) {} double Mercator::calculate_phi(double t) const { @@ -98,8 +98,8 @@ PointLonLat Mercator::inv(const Point2& q) const { } -Projection::Spec Mercator::spec() const { - return Spec{{{"lad", parallel_}, {"orientation", meridian_}}}; +Spec* Mercator::spec() const { + return new spec::Custom{{{"lad", parallel_}, {"orientation", meridian_}}}; } diff --git a/src/eckit/geo/projection/Mercator.h b/src/eckit/geo/projection/Mercator.h index d2479ab09..7f9bb2e9e 100644 --- a/src/eckit/geo/projection/Mercator.h +++ b/src/eckit/geo/projection/Mercator.h @@ -31,7 +31,7 @@ class Mercator final : public Projection { Mercator(double meridian, double parallel, Figure*, PointLonLat first = {0, 0}); - explicit Mercator(const Configuration&); + explicit Mercator(const Spec&); // -- Destructor // None @@ -49,7 +49,7 @@ class Mercator final : public Projection { // -- Overridden methods - Spec spec() const override; + Spec* spec() const override; // -- Class members // None diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index 9273350ba..47893d451 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -12,7 +12,7 @@ #include "eckit/geo/projection/None.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" namespace eckit::geo::projection { @@ -24,11 +24,11 @@ static ProjectionBuilder __projection3("equirectangular"); static ProjectionBuilder __projection4("plate-carree"); -None::None(const Configuration&) {} +None::None(const Spec&) {} -Projection::Spec None::spec() const { - return Spec{}; +Spec* None::spec() const { + return new spec::Custom{}; } diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index 3aa618f72..e0c61b1a1 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -29,7 +29,7 @@ class None final : public Projection { // -- Constructors None() = default; - explicit None(const Configuration&); + explicit None(const Spec&); // -- Destructor // None @@ -45,7 +45,7 @@ class None final : public Projection { // -- Overridden methods - Spec spec() const override; + Spec* spec() const override; // -- Class members // None diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 76d607503..8b0c3bfe2 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -13,7 +13,7 @@ #include "eckit/geo/projection/PROJ.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" namespace eckit::geo::projection { @@ -90,10 +90,10 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini } -PROJ::PROJ(const Configuration& config) : - PROJ(config.getString("source", "EPSG:4326"), // default to WGS 84 - config.getString("target", "EPSG:4326"), // ... - config.getDouble("lon_minimum", 0)) {} +PROJ::PROJ(const Spec& spec) : + PROJ(spec.get_string("source", "EPSG:4326"), // default to WGS 84 + spec.get_string("target", "EPSG:4326"), // ... + spec.get_double("lon_minimum", 0)) {} std::string PROJ::ellipsoid(const std::string& string) { @@ -123,8 +123,8 @@ Point PROJ::inv(const Point& q) const { } -Projection::Spec PROJ::spec() const { - return Spec{{{"source", source_}, {"target", target_}}}; +Spec* PROJ::spec() const { + return new spec::Custom{{{"source", source_}, {"target", target_}}}; } diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index cc38f535d..1970793af 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -60,7 +60,7 @@ class PROJ final : public Projection { // -- Constructors PROJ(const std::string& source, const std::string& target, double lon_minimum = 0.); - explicit PROJ(const Configuration&); + explicit PROJ(const Spec&); // -- Destructor // None @@ -83,7 +83,7 @@ class PROJ final : public Projection { Point fwd(const Point&) const override; Point inv(const Point&) const override; - Spec spec() const override; + Spec* spec() const override; // -- Class members // None diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 6988e606e..a75782bae 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -16,7 +16,7 @@ #include #include "eckit/geo/UnitSphere.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/maths/Matrix3.h" #include "eckit/types/FloatCompare.h" @@ -36,20 +36,20 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : rotated_(true) { using M = maths::Matrix3; - struct NonRotated final : Rotate { + struct NonRotated final : Implementation { PointLonLat operator()(const PointLonLat& p) const override { return p; } - Spec spec() const override { return Spec{}; } + Spec* spec() const override { return new spec::Custom{}; } }; - struct RotationAngle final : Rotate { + struct RotationAngle final : Implementation { explicit RotationAngle(double angle) : angle_(angle) {} PointLonLat operator()(const PointLonLat& p) const override { return {p.lon + angle_, p.lat}; } - Spec spec() const override { return Spec{{{"angle", angle_}}}; } + Spec* spec() const override { return new spec::Custom{{{"angle", angle_}}}; } const double angle_; }; - struct RotationMatrix final : Rotate { + struct RotationMatrix final : Implementation { explicit RotationMatrix(M&& R) : RotationMatrix(std::move(R), 0, 0, 0) {} RotationMatrix(M&& R, double south_pole_lon, double south_pole_lat, double angle) : @@ -57,8 +57,9 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : PointLonLat operator()(const PointLonLat& p) const override { return UnitSphere::convertCartesianToSpherical(R_ * UnitSphere::convertSphericalToCartesian(p)); } - Spec spec() const override { - return Spec{{{"south_pole_lon", south_pole_lon_}, {"south_pole_lat", south_pole_lat_}, {"angle", angle_}}}; + Spec* spec() const override { + return new spec::Custom{ + {{"south_pole_lon", south_pole_lon_}, {"south_pole_lat", south_pole_lat_}, {"angle", angle_}}}; } const M R_; const double south_pole_lon_; @@ -78,8 +79,8 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : angle = PointLonLat::normalise_angle_to_minimum(angle - south_pole_lon, -180.); rotated_ = !types::is_approximately_equal(angle, 0., util::eps); - fwd_.reset(rotated_ ? static_cast(new RotationAngle(-angle)) : new NonRotated); - inv_.reset(rotated_ ? static_cast(new RotationAngle(angle)) : new NonRotated); + fwd_.reset(rotated_ ? static_cast(new RotationAngle(-angle)) : new NonRotated); + inv_.reset(rotated_ ? static_cast(new RotationAngle(angle)) : new NonRotated); return; } @@ -120,11 +121,11 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : } -Rotation::Rotation(const Configuration& config) : - Rotation(config.getDouble("south_pole_lon"), config.getDouble("south_pole_lat"), config.getDouble("angle", 0)) {} +Rotation::Rotation(const Spec& spec) : + Rotation(spec.get_double("south_pole_lon"), spec.get_double("south_pole_lat"), spec.get_double("angle", 0)) {} -Projection::Spec Rotation::spec() const { +Spec* Rotation::spec() const { return fwd_->spec(); } diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index 947ef5c81..f67f100e6 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -30,7 +30,7 @@ class Rotation final : public Projection { Rotation(); Rotation(double south_pole_lon, double south_pole_lat, double angle); - explicit Rotation(const Configuration&); + explicit Rotation(const Spec&); // -- Destructor // None @@ -49,7 +49,7 @@ class Rotation final : public Projection { // -- Overridden methods - Spec spec() const override; + Spec* spec() const override; // -- Class members // None @@ -60,23 +60,23 @@ class Rotation final : public Projection { private: // -- Types - struct Rotate { - Rotate() = default; - virtual ~Rotate() = default; + struct Implementation { + Implementation() = default; + virtual ~Implementation() = default; - Rotate(const Rotate&) = delete; - Rotate(Rotate&&) = delete; - void operator=(const Rotate&) = delete; - void operator=(Rotate&&) = delete; + Implementation(const Implementation&) = delete; + Implementation(Implementation&&) = delete; + void operator=(const Implementation&) = delete; + void operator=(Implementation&&) = delete; virtual PointLonLat operator()(const PointLonLat&) const = 0; - virtual Spec spec() const = 0; + virtual Spec* spec() const = 0; }; // -- Members - std::unique_ptr fwd_; - std::unique_ptr inv_; + std::unique_ptr fwd_; + std::unique_ptr inv_; bool rotated_; // -- Methods diff --git a/src/eckit/geo/spec/MappedConfiguration.cc b/src/eckit/geo/spec/Custom.cc similarity index 57% rename from src/eckit/geo/spec/MappedConfiguration.cc rename to src/eckit/geo/spec/Custom.cc index 4574e01ec..3b11beed5 100644 --- a/src/eckit/geo/spec/MappedConfiguration.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -9,10 +9,9 @@ */ -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/log/JSON.h" -#include "eckit/value/Value.h" namespace eckit::geo::spec { @@ -21,9 +20,6 @@ namespace eckit::geo::spec { namespace { -const eckit::Value __empty_root; - - template bool __get_s(const From& from, To& to) { to = static_cast(from); @@ -56,7 +52,7 @@ bool __get_v(const std::vector& from, std::vector& to) { template -bool __get_s_integral(const MappedConfiguration::container_type& map, const std::string& name, T& value) { +bool __get_s_integral(const Custom::container_type& map, const std::string& name, T& value) { if (auto it = map.find(name); it != map.cend()) { const auto& v = it->second; return std::holds_alternative(v) ? __get_s(std::get(v), value) @@ -70,7 +66,7 @@ bool __get_s_integral(const MappedConfiguration::container_type& map, const std: template -bool __get_s_real(const MappedConfiguration::container_type& map, const std::string& name, T& value) { +bool __get_s_real(const Custom::container_type& map, const std::string& name, T& value) { if (__get_s_integral(map, name, value)) { return true; } @@ -86,7 +82,7 @@ bool __get_s_real(const MappedConfiguration::container_type& map, const std::str template -bool __get_v_integral(const MappedConfiguration::container_type& map, const std::string& name, T& value) { +bool __get_v_integral(const Custom::container_type& map, const std::string& name, T& value) { if (auto it = map.find(name); it != map.cend()) { const auto& v = it->second; return std::holds_alternative>(v) ? __get_v(std::get>(v), value) @@ -101,7 +97,7 @@ bool __get_v_integral(const MappedConfiguration::container_type& map, const std: template -bool __get_v_real(const MappedConfiguration::container_type& map, const std::string& name, T& value) { +bool __get_v_real(const Custom::container_type& map, const std::string& name, T& value) { if (__get_v_integral(map, name, value)) { return true; } @@ -116,7 +112,7 @@ bool __get_v_real(const MappedConfiguration::container_type& map, const std::str } -JSON& operator<<(JSON& out, const MappedConfiguration::value_type& value) { +JSON& operator<<(JSON& out, const Custom::value_type& value) { std::visit([&](const auto& arg) { out << arg; }, value); return out; } @@ -125,115 +121,115 @@ JSON& operator<<(JSON& out, const MappedConfiguration::value_type& value) { } // namespace -MappedConfiguration::MappedConfiguration(const MappedConfiguration::container_type& map) : - Configuration(__empty_root), map_(map) {} +Custom::Custom(const Custom::container_type& map) : + map_(map) {} -MappedConfiguration::MappedConfiguration(MappedConfiguration::container_type&& map) : - Configuration(__empty_root), map_(map) {} +Custom::Custom(Custom::container_type&& map) : + map_(map) {} -MappedConfiguration::MappedConfiguration(const MappedConfiguration& config) : - MappedConfiguration(config.map_) {} +Custom::Custom(const Custom& custom) : + Custom(custom.map_) {} -MappedConfiguration::MappedConfiguration(MappedConfiguration&& config) : - MappedConfiguration(config.map_) {} +Custom::Custom(Custom&& custom) : + Custom(custom.map_) {} -MappedConfiguration& MappedConfiguration::operator=(MappedConfiguration&& config) { - map_.swap(config.map_); +Custom& Custom::operator=(Custom&& custom) { + map_.swap(custom.map_); return *this; } -MappedConfiguration& MappedConfiguration::operator=(const MappedConfiguration& config) { - map_ = config.map_; +Custom& Custom::operator=(const Custom& custom) { + map_ = custom.map_; return *this; } -void MappedConfiguration::set(const std::string& name, const std::string& value) { +void Custom::set(const std::string& name, const std::string& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, bool value) { +void Custom::set(const std::string& name, bool value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, int value) { +void Custom::set(const std::string& name, int value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, long value) { +void Custom::set(const std::string& name, long value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, long long value) { +void Custom::set(const std::string& name, long long value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, std::size_t value) { +void Custom::set(const std::string& name, std::size_t value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, float value) { +void Custom::set(const std::string& name, float value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, double value) { +void Custom::set(const std::string& name, double value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, const std::vector& value) { +void Custom::set(const std::string& name, const std::vector& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, const std::vector& value) { +void Custom::set(const std::string& name, const std::vector& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, const std::vector& value) { +void Custom::set(const std::string& name, const std::vector& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, const std::vector& value) { +void Custom::set(const std::string& name, const std::vector& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, const std::vector& value) { +void Custom::set(const std::string& name, const std::vector& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, const std::vector& value) { +void Custom::set(const std::string& name, const std::vector& value) { map_[name] = value; } -void MappedConfiguration::set(const std::string& name, const std::vector& value) { +void Custom::set(const std::string& name, const std::vector& value) { map_[name] = value; } -bool MappedConfiguration::has(const std::string& name) const { +bool Custom::has(const std::string& name) const { return map_.find(name) != map_.cend(); } -bool MappedConfiguration::get(const std::string& name, std::string& value) const { +bool Custom::get(const std::string& name, std::string& value) const { if (auto it = map_.find(name); it != map_.cend() && std::holds_alternative(it->second)) { value = std::get(it->second); return true; @@ -242,7 +238,7 @@ bool MappedConfiguration::get(const std::string& name, std::string& value) const } -bool MappedConfiguration::get(const std::string& name, bool& value) const { +bool Custom::get(const std::string& name, bool& value) const { if (auto it = map_.find(name); it != map_.cend()) { if (std::holds_alternative(it->second)) { value = std::get(it->second); @@ -258,67 +254,67 @@ bool MappedConfiguration::get(const std::string& name, bool& value) const { } -bool MappedConfiguration::get(const std::string& name, int& value) const { +bool Custom::get(const std::string& name, int& value) const { return __get_s_integral(map_, name, value); } -bool MappedConfiguration::get(const std::string& name, long& value) const { +bool Custom::get(const std::string& name, long& value) const { return __get_s_integral(map_, name, value); } -bool MappedConfiguration::get(const std::string& name, long long& value) const { +bool Custom::get(const std::string& name, long long& value) const { return __get_s_integral(map_, name, value); } -bool MappedConfiguration::get(const std::string& name, std::size_t& value) const { +bool Custom::get(const std::string& name, std::size_t& value) const { return __get_s_integral(map_, name, value); } -bool MappedConfiguration::get(const std::string& name, float& value) const { +bool Custom::get(const std::string& name, float& value) const { return __get_s_real(map_, name, value); } -bool MappedConfiguration::get(const std::string& name, double& value) const { +bool Custom::get(const std::string& name, double& value) const { return __get_s_real(map_, name, value); } -bool MappedConfiguration::get(const std::string& name, std::vector& value) const { +bool Custom::get(const std::string& name, std::vector& value) const { return __get_v_integral(map_, name, value); } -bool MappedConfiguration::get(const std::string& name, std::vector& value) const { +bool Custom::get(const std::string& name, std::vector& value) const { return __get_v_integral(map_, name, value); } -bool MappedConfiguration::get(const std::string& name, std::vector& value) const { +bool Custom::get(const std::string& name, std::vector& value) const { return __get_v_integral(map_, name, value); } -bool MappedConfiguration::get(const std::string& name, std::vector& value) const { +bool Custom::get(const std::string& name, std::vector& value) const { return __get_v_integral(map_, name, value); } -bool MappedConfiguration::get(const std::string& name, std::vector& value) const { +bool Custom::get(const std::string& name, std::vector& value) const { return __get_v_real(map_, name, value); } -bool MappedConfiguration::get(const std::string& name, std::vector& value) const { +bool Custom::get(const std::string& name, std::vector& value) const { return __get_v_real(map_, name, value); } -bool MappedConfiguration::get(const std::string& name, std::vector& value) const { +bool Custom::get(const std::string& name, std::vector& value) const { auto it = map_.find(name); if (it != map_.cend() && std::holds_alternative>(it->second)) { value = std::get>(it->second); @@ -328,17 +324,10 @@ bool MappedConfiguration::get(const std::string& name, std::vector& } -void MappedConfiguration::print(std::ostream& out) const { - JSON j(out); - json(j); -} - - -void MappedConfiguration::json(JSON& j) const { +void Custom::json(JSON& j) const { j.startObject(); for (const auto& nv : map_) { - j << nv.first; - j << nv.second; + j << nv.first << nv.second; } j.endObject(); } diff --git a/src/eckit/geo/spec/MappedConfiguration.h b/src/eckit/geo/spec/Custom.h similarity index 88% rename from src/eckit/geo/spec/MappedConfiguration.h rename to src/eckit/geo/spec/Custom.h index 3d1eb6138..0305cb96c 100644 --- a/src/eckit/geo/spec/MappedConfiguration.h +++ b/src/eckit/geo/spec/Custom.h @@ -14,13 +14,18 @@ #include #include -#include "eckit/config/Configuration.h" +#include "eckit/geo/Spec.h" + + +namespace eckit { +class JSON; +} namespace eckit::geo::spec { -class MappedConfiguration final : public Configuration { +class Custom final : public Spec { public: // -- Types @@ -47,23 +52,23 @@ class MappedConfiguration final : public Configuration { // -- Constructors - explicit MappedConfiguration(const container_type& = {}); - explicit MappedConfiguration(container_type&&); + explicit Custom(const container_type& = {}); + explicit Custom(container_type&&); - MappedConfiguration(const MappedConfiguration&); - MappedConfiguration(MappedConfiguration&&); + Custom(const Custom&); + Custom(Custom&&); // -- Destructor - ~MappedConfiguration() final = default; + ~Custom() final = default; // -- Convertors // None // -- Operators - MappedConfiguration& operator=(const MappedConfiguration&); - MappedConfiguration& operator=(MappedConfiguration&&); + Custom& operator=(const Custom&); + Custom& operator=(Custom&&); // -- Methods @@ -125,8 +130,7 @@ class MappedConfiguration final : public Configuration { // -- Overridden methods - void print(std::ostream&) const override; - void json(JSON&) const override; + void json(JSON&) const final; // -- Class members // None diff --git a/src/eckit/geo/spec/DynamicConfiguration.cc b/src/eckit/geo/spec/DynamicConfiguration.cc deleted file mode 100644 index 1be676cd0..000000000 --- a/src/eckit/geo/spec/DynamicConfiguration.cc +++ /dev/null @@ -1,86 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/spec/DynamicConfiguration.h" - -#include "eckit/config/LocalConfiguration.h" -#include "eckit/exception/Exceptions.h" -#include "eckit/value/Value.h" - - -namespace eckit::geo::spec { - - -namespace { - - -const LocalConfiguration __empty_configuration; -const eckit::Value __empty_root; - - -} // namespace - - -DynamicConfiguration::DynamicConfiguration() : - DynamicConfiguration(__empty_configuration) {} - - -DynamicConfiguration::DynamicConfiguration(const Configuration& config) : - Configuration(__empty_root), config_(config) {} - - -void DynamicConfiguration::hide(const std::string& name) { - hide_.insert(name); -} - - -void DynamicConfiguration::unhide(const std::string& name) { - hide_.erase(name); -} - - -void DynamicConfiguration::push_back(Configuration* config) { - ASSERT(config != nullptr); - after_.emplace_back(config); -} - - -void DynamicConfiguration::push_front(Configuration* config) { - ASSERT(config != nullptr); - before_.emplace_back(config); -} - - -void DynamicConfiguration::print(std::ostream& out) const { - const auto* sep = ""; - out << "DynamicConfiguration[hide["; - for (const auto& name : hide_) { - out << sep << name; - sep = ","; - } - - sep = ""; - out << "],config=" << config_ << ",before["; - for (const auto& config : before_) { - out << sep << *config; - sep = ","; - } - - sep = ""; - out << ",after["; - for (const auto& config : after_) { - out << sep << *config; - sep = ","; - } - out << "]]"; -} - - -} // namespace eckit::geo::spec diff --git a/src/eckit/geo/Configurator.h b/src/eckit/geo/spec/Generator.h similarity index 55% rename from src/eckit/geo/Configurator.h rename to src/eckit/geo/spec/Generator.h index 62f704ab3..6df47dd32 100644 --- a/src/eckit/geo/Configurator.h +++ b/src/eckit/geo/spec/Generator.h @@ -17,7 +17,6 @@ #include #include #include -#include #include "eckit/exception/Exceptions.h" #include "eckit/thread/AutoLock.h" @@ -25,17 +24,17 @@ #include "eckit/utils/Regex.h" -namespace eckit { -class Configuration; +namespace eckit::geo { +class Spec; } -namespace eckit::geo { +namespace eckit::geo::spec { //------------------------------------------------------------------------------------------------------ template -class Configurator { +class GeneratorT { public: // -- Types @@ -45,17 +44,17 @@ class Configurator { // -- Constructors - Configurator(const Configurator&) = delete; - Configurator(Configurator&&) = delete; + GeneratorT(const GeneratorT&) = delete; + GeneratorT(GeneratorT&&) = delete; // -- Operators - void operator=(const Configurator&) = delete; - void operator=(Configurator&&) = delete; + void operator=(const GeneratorT&) = delete; + void operator=(GeneratorT&&) = delete; // -- Methods - static Configurator& instance(); + static GeneratorT& instance(); bool exists(const key_t&) const; bool matches(const std::string&) const; @@ -69,11 +68,11 @@ class Configurator { private: // -- Constructors - Configurator() = default; + GeneratorT() = default; // -- Destructor - ~Configurator() = default; + ~GeneratorT() = default; // -- Members @@ -86,7 +85,7 @@ class Configurator { // -- Friends - friend std::ostream& operator<<(std::ostream& os, const Configurator& o) { + friend std::ostream& operator<<(std::ostream& os, const GeneratorT& o) { o.print(os); return os; } @@ -95,25 +94,25 @@ class Configurator { //------------------------------------------------------------------------------------------------------ template -Configurator& Configurator::instance() { - static Configurator obj; +GeneratorT& GeneratorT::instance() { + static GeneratorT obj; return obj; } template -bool Configurator::exists(const key_t& k) const { +bool GeneratorT::exists(const key_t& k) const { AutoLock lock(mutex_); return store_.find(k) != store_.end(); } template -bool Configurator::matches(const std::string& k) const { +bool GeneratorT::matches(const std::string& k) const { AutoLock lock(mutex_); return std::any_of(store_.begin(), store_.end(), [&](const auto& p) { return Regex(p.first).match(k); }); } template -void Configurator::regist(const key_t& k, configurator_t* c) { +void GeneratorT::regist(const key_t& k, configurator_t* c) { AutoLock lock(mutex_); if (exists(k)) { throw BadParameter("Configurator has already a builder for " + k, Here()); @@ -123,7 +122,7 @@ void Configurator::regist(const key_t& k, configurator_t* c) { } template -void Configurator::unregist(const key_t& k) { +void GeneratorT::unregist(const key_t& k) { AutoLock lock(mutex_); if (auto it = store_.find(k); it != store_.end()) { store_.erase(it); @@ -133,7 +132,7 @@ void Configurator::unregist(const key_t& k) { } template -const typename Configurator::configurator_t& Configurator::get(const key_t& k) const { +const typename GeneratorT::configurator_t& GeneratorT::get(const key_t& k) const { AutoLock lock(mutex_); if (auto it = store_.find(k); it != store_.end()) { return *(it->second); @@ -142,7 +141,7 @@ const typename Configurator::configurator_t& Configurator::get(const key_t } template -const typename Configurator::configurator_t& Configurator::match(const std::string& k) const { +const typename GeneratorT::configurator_t& GeneratorT::match(const std::string& k) const { AutoLock lock(mutex_); auto end = store_.cend(); @@ -164,7 +163,7 @@ const typename Configurator::configurator_t& Configurator::match(const std } template -void Configurator::print(std::ostream& os) const { +void GeneratorT::print(std::ostream& os) const { AutoLock lock(mutex_); os << "Configurator" << std::endl; @@ -180,7 +179,7 @@ void Configurator::print(std::ostream& os) const { //------------------------------------------------------------------------------------------------------ -class ConfigurationGenerator { +class SpecGenerator { public: // -- Types @@ -190,33 +189,33 @@ class ConfigurationGenerator { // -- Constructors - ConfigurationGenerator() = default; - ConfigurationGenerator(const ConfigurationGenerator&) = delete; - ConfigurationGenerator(ConfigurationGenerator&&) = delete; + SpecGenerator() = default; + SpecGenerator(const SpecGenerator&) = delete; + SpecGenerator(SpecGenerator&&) = delete; // -- Destructor - virtual ~ConfigurationGenerator() = default; + virtual ~SpecGenerator() = default; // -- Operators - void operator=(const ConfigurationGenerator&) = delete; - void operator=(ConfigurationGenerator&&) = delete; + void operator=(const SpecGenerator&) = delete; + void operator=(SpecGenerator&&) = delete; }; //------------------------------------------------------------------------------------------------------ -class ConfigurationGeneratorT0 : public ConfigurationGenerator { +class SpecGeneratorT0 : public SpecGenerator { public: // -- Methods - virtual Configuration* config() const = 0; + virtual Spec* config() const = 0; }; //------------------------------------------------------------------------------------------------------ template -class ConfigurationGeneratorT1 : public ConfigurationGenerator { +class SpecGeneratorT1 : public SpecGenerator { public: // -- Types @@ -224,13 +223,13 @@ class ConfigurationGeneratorT1 : public ConfigurationGenerator { // -- Methods - virtual Configuration* config(arg1_t) const = 0; + virtual Spec* config(arg1_t) const = 0; }; //------------------------------------------------------------------------------------------------------ template -class ConfigurationGeneratorT2 : public ConfigurationGenerator { +class SpecGeneratorT2 : public SpecGenerator { public: // -- Types @@ -239,118 +238,113 @@ class ConfigurationGeneratorT2 : public ConfigurationGenerator { // -- Methods - virtual Configuration* config(arg1_t, arg2_t) const = 0; + virtual Spec* config(arg1_t, arg2_t) const = 0; }; //------------------------------------------------------------------------------------------------------ template -class ConcreteConfigurationGeneratorT0 final : public ConfigurationGeneratorT0 { +class ConcreteSpecGeneratorT0 final : public SpecGeneratorT0 { public: // -- Constructors - explicit ConcreteConfigurationGeneratorT0(const ConfigurationGeneratorT0::key_t& k) : + explicit ConcreteSpecGeneratorT0(const SpecGeneratorT0::key_t& k) : key_(k) { - Configurator::instance().regist(key_, this); + GeneratorT::instance().regist(key_, this); } - ConcreteConfigurationGeneratorT0(const ConcreteConfigurationGeneratorT0&) = delete; - ConcreteConfigurationGeneratorT0(ConcreteConfigurationGeneratorT0&&) = delete; + ConcreteSpecGeneratorT0(const ConcreteSpecGeneratorT0&) = delete; + ConcreteSpecGeneratorT0(ConcreteSpecGeneratorT0&&) = delete; // -- Destructor - ~ConcreteConfigurationGeneratorT0() override { Configurator::instance().unregist(key_); } + ~ConcreteSpecGeneratorT0() override { GeneratorT::instance().unregist(key_); } // -- Operators - void operator=(const ConcreteConfigurationGeneratorT0&) = delete; - void operator=(ConcreteConfigurationGeneratorT0&&) = delete; + void operator=(const ConcreteSpecGeneratorT0&) = delete; + void operator=(ConcreteSpecGeneratorT0&&) = delete; // -- Overridden methods - Configuration* config() const override { return T::config(); } + Spec* config() const override { return T::config(); } private: // -- Members - ConfigurationGeneratorT0::key_t key_; + SpecGeneratorT0::key_t key_; }; //------------------------------------------------------------------------------------------------------ template -class ConcreteConfigurationGeneratorT1 final : public ConfigurationGeneratorT1 { +class ConcreteSpecGeneratorT1 final : public SpecGeneratorT1 { public: // -- Constructors - explicit ConcreteConfigurationGeneratorT1(const typename ConfigurationGeneratorT1::key_t& k) : + explicit ConcreteSpecGeneratorT1(const typename SpecGeneratorT1::key_t& k) : key_(k) { - Configurator>::instance().regist(key_, this); + GeneratorT>::instance().regist(key_, this); } - ConcreteConfigurationGeneratorT1(const ConcreteConfigurationGeneratorT1&) = delete; - ConcreteConfigurationGeneratorT1(ConcreteConfigurationGeneratorT1&&) = delete; + ConcreteSpecGeneratorT1(const ConcreteSpecGeneratorT1&) = delete; + ConcreteSpecGeneratorT1(ConcreteSpecGeneratorT1&&) = delete; // -- Destructor - ~ConcreteConfigurationGeneratorT1() override { - Configurator>::instance().unregist(key_); - } + ~ConcreteSpecGeneratorT1() override { GeneratorT>::instance().unregist(key_); } // -- Operators - void operator=(const ConcreteConfigurationGeneratorT1&) = delete; - void operator=(ConcreteConfigurationGeneratorT1&&) = delete; + void operator=(const ConcreteSpecGeneratorT1&) = delete; + void operator=(ConcreteSpecGeneratorT1&&) = delete; // -- Overridden methods - Configuration* config(typename ConfigurationGeneratorT1::arg1_t p1) const override { return T::config(p1); } + Spec* config(typename SpecGeneratorT1::arg1_t p1) const override { return T::config(p1); } private: // -- Members - typename ConfigurationGeneratorT1::key_t key_; + typename SpecGeneratorT1::key_t key_; }; //------------------------------------------------------------------------------------------------------ template -class ConcreteConfigurationGeneratorT2 final : public ConfigurationGeneratorT2 { +class ConcreteSpecGeneratorT2 final : public SpecGeneratorT2 { public: // -- Constructors - explicit ConcreteConfigurationGeneratorT2(const typename ConfigurationGeneratorT2::key_t& k) : + explicit ConcreteSpecGeneratorT2(const typename SpecGeneratorT2::key_t& k) : key_(k) { - Configurator>::instance().regist(key_, this); + GeneratorT>::instance().regist(key_, this); } - ConcreteConfigurationGeneratorT2(const ConcreteConfigurationGeneratorT2&) = delete; - ConcreteConfigurationGeneratorT2(ConcreteConfigurationGeneratorT2&&) = delete; + ConcreteSpecGeneratorT2(const ConcreteSpecGeneratorT2&) = delete; + ConcreteSpecGeneratorT2(ConcreteSpecGeneratorT2&&) = delete; // -- Destructor - ~ConcreteConfigurationGeneratorT2() override { - Configurator>::instance().unregist(key_); - } + ~ConcreteSpecGeneratorT2() override { GeneratorT>::instance().unregist(key_); } // -- Operators - void operator=(const ConcreteConfigurationGeneratorT2&) = delete; - void operator=(ConcreteConfigurationGeneratorT2&&) = delete; + void operator=(const ConcreteSpecGeneratorT2&) = delete; + void operator=(ConcreteSpecGeneratorT2&&) = delete; // -- Overridden methods - Configuration* config(typename ConfigurationGeneratorT1::arg1_t p1, - typename ConfigurationGeneratorT1::arg2_t p2) const override { + Spec* config(typename SpecGeneratorT1::arg1_t p1, typename SpecGeneratorT1::arg2_t p2) const override { return T::config(p1, p2); } private: // -- Members - typename ConfigurationGeneratorT2::key_t key_; + typename SpecGeneratorT2::key_t key_; }; //------------------------------------------------------------------------------------------------------ -} // namespace eckit::geo +} // namespace eckit::geo::spec diff --git a/src/eckit/geo/spec/Layered.cc b/src/eckit/geo/spec/Layered.cc new file mode 100644 index 000000000..682240500 --- /dev/null +++ b/src/eckit/geo/spec/Layered.cc @@ -0,0 +1,84 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/spec/Layered.h" + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/value/Value.h" + + +namespace eckit::geo::spec { + + +static const Custom __empty_spec; + + +Layered::Layered() : + Layered(__empty_spec) {} + + +Layered::Layered(const Spec& spec) : + spec_(spec) {} + + +void Layered::hide(const std::string& name) { + hide_.insert(name); +} + + +void Layered::unhide(const std::string& name) { + hide_.erase(name); +} + + +void Layered::push_back(Spec* spec) { + ASSERT(spec != nullptr); + after_.emplace_back(spec); +} + + +void Layered::push_front(Spec* spec) { + ASSERT(spec != nullptr); + before_.emplace_back(spec); +} + + +void Layered::print(std::ostream& out) const { + const auto* sep = ""; + out << "Layered[hide["; + for (const auto& name : hide_) { + out << sep << name; + sep = ","; + } + + sep = ""; + out << "],spec=" << spec_ << ",before["; + for (const auto& spec : before_) { + out << sep << *spec; + sep = ","; + } + + sep = ""; + out << ",after["; + for (const auto& spec : after_) { + out << sep << *spec; + sep = ","; + } + out << "]]"; +} + + +void Layered::json(JSON&) const { + NOTIMP; +} + + +} // namespace eckit::geo::spec diff --git a/src/eckit/geo/spec/DynamicConfiguration.h b/src/eckit/geo/spec/Layered.h similarity index 87% rename from src/eckit/geo/spec/DynamicConfiguration.h rename to src/eckit/geo/spec/Layered.h index ea9f6dccd..e8806ed9e 100644 --- a/src/eckit/geo/spec/DynamicConfiguration.h +++ b/src/eckit/geo/spec/Layered.h @@ -15,13 +15,13 @@ #include #include -#include "eckit/config/Configuration.h" +#include "eckit/geo/Spec.h" namespace eckit::geo::spec { -class DynamicConfiguration : public Configuration { +class Layered final : public Spec { public: // -- Types // None @@ -31,8 +31,8 @@ class DynamicConfiguration : public Configuration { // -- Constructors - DynamicConfiguration(); - explicit DynamicConfiguration(const Configuration&); + Layered(); + explicit Layered(const Spec&); // -- Destructor // None @@ -47,8 +47,8 @@ class DynamicConfiguration : public Configuration { void hide(const std::string&); void unhide(const std::string&); - void push_back(Configuration*); - void push_front(Configuration*); + void push_back(Spec*); + void push_front(Spec*); // -- Overridden methods @@ -57,7 +57,7 @@ class DynamicConfiguration : public Configuration { (std::any_of(before_.begin(), before_.end(), [&](const decltype(before_)::value_type& c) { return c->has(name); }) || - config_.has(name) || + spec_.has(name) || std::any_of(after_.begin(), after_.end(), [&](const decltype(after_)::value_type& c) { return c->has(name); })); @@ -92,9 +92,9 @@ class DynamicConfiguration : public Configuration { bool contains(const value_type& name) const { return find(name) != end(); } } hide_; - const Configuration& config_; - std::vector> before_; - std::vector> after_; + const Spec& spec_; + std::vector> before_; + std::vector> after_; // -- Methods @@ -104,7 +104,7 @@ class DynamicConfiguration : public Configuration { (std::any_of(before_.begin(), before_.end(), [&](const decltype(before_)::value_type& c) { return c->get(name, value); }) || - config_.get(name, value) || + spec_.get(name, value) || std::any_of(after_.begin(), after_.end(), [&](const decltype(after_)::value_type& c) { return c->get(name, value); })); @@ -112,7 +112,8 @@ class DynamicConfiguration : public Configuration { // -- Overridden methods - void print(std::ostream&) const override; + void print(std::ostream&) const final; + void json(JSON&) const final; // -- Class members // None diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index 146dc6798..5324201a1 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -11,12 +11,12 @@ #include #include -#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/Grid.h" #include "eckit/geo/Point.h" #include "eckit/geo/Search.h" #include "eckit/geo/grid/Unstructured.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" #include "eckit/option/EckitTool.h" @@ -52,8 +52,8 @@ class EckitGrid final : public EckitTool { out.precision(args.getInt("precision", 16)); for (const auto& arg : args) { - std::unique_ptr cfg(new geo::spec::MappedConfiguration({{uid ? "uid" : "name", std::string(arg)}})); - std::unique_ptr grid(geo::GridFactory::build(*cfg)); + std::unique_ptr spec(new geo::spec::Custom({{uid ? "uid" : "name", std::string(arg)}})); + std::unique_ptr grid(geo::GridFactory::build(*spec)); out << "size: " << grid->size() << std::endl; @@ -89,9 +89,7 @@ class EckitGrid final : public EckitTool { << tool << "[options] ..." << std::endl; } - int minimumPositionalArguments() const override { - return 0; - } + int minimumPositionalArguments() const override { return 0; } }; } // namespace eckit diff --git a/tests/config/CMakeLists.txt b/tests/config/CMakeLists.txt index 9430e1714..2b69b342d 100644 --- a/tests/config/CMakeLists.txt +++ b/tests/config/CMakeLists.txt @@ -5,12 +5,9 @@ ecbuild_add_test( LIBS eckit ) -foreach( _test configuration mapped_configuration ) - ecbuild_add_test( - TARGET eckit_test_config_${_test} - SOURCES test_${_test}.cc - LIBS eckit eckit_geo - CONDITION HAVE_ECKIT_GEO - ) -endforeach() +ecbuild_add_test( + TARGET eckit_test_config_configuration + SOURCES test_configuration.cc + LIBS eckit +) diff --git a/tests/config/test_configuration.cc b/tests/config/test_configuration.cc index 255c48c37..d7dc3c38c 100644 --- a/tests/config/test_configuration.cc +++ b/tests/config/test_configuration.cc @@ -10,9 +10,7 @@ #include -#include "eckit/geo/spec/DynamicConfiguration.h" #include "eckit/config/LocalConfiguration.h" -#include "eckit/geo/spec/MappedConfiguration.h" #include "eckit/config/YAMLConfiguration.h" #include "eckit/filesystem/PathName.h" #include "eckit/testing/Test.h" @@ -385,138 +383,6 @@ CASE("Hash a configuration") { //---------------------------------------------------------------------------------------------------------------------- -CASE("test_mapped_configuration") { - int one = 1; - double two = 2.; - std::string three = "3"; - - - geo::spec::MappedConfiguration a({ - {"double", static_cast(one)}, - {"float", static_cast(one)}, - {"int", static_cast(one)}, - {"long", static_cast(one)}, - {"size_t", static_cast(one)}, - }); - - // test scalar type conversion - for (std::string key : {"double", "float", "int", "long", "size_t"}) { - double value_as_double = 0; - float value_as_float = 0; - - EXPECT(a.get(key, value_as_double) && value_as_double == static_cast(one)); - EXPECT(a.get(key, value_as_float) && value_as_float == static_cast(one)); - - if (key == "int" || key == "long" || key == "size_t") { - int value_as_int = 0; - long value_as_long = 0; - size_t value_as_size_t = 0; - - EXPECT(a.get(key, value_as_int) && value_as_int == static_cast(one)); - EXPECT(a.get(key, value_as_long) && value_as_long == static_cast(one)); - EXPECT(a.get(key, value_as_size_t) && value_as_size_t == static_cast(one)); - } - - EXPECT_EQUAL(a.getString(key), std::to_string(1)); - } - - - geo::spec::MappedConfiguration b({ - {"true", true}, - {"false", false}, - {"zero", 0}, - {"one", 1}, - }); - - EXPECT(b.getBool("true")); - EXPECT(!b.getBool("false")); - - bool maybe = false; - EXPECT(!b.has("?")); - EXPECT(!b.getBool("?", false)); - EXPECT(b.getBool("?", true)); - - EXPECT(b.get("true", maybe = false) && maybe); - EXPECT(b.getBool("true", true)); - EXPECT(b.getBool("true", false)); - - EXPECT(b.get("false", maybe = true) && !maybe); - EXPECT(!b.getBool("false", true)); - EXPECT(!b.getBool("false", false)); - - EXPECT(!b.getBool("zero")); - EXPECT(!b.getBool("zero", maybe = true)); - EXPECT(b.get("zero", maybe = true) && !maybe); - - EXPECT(b.getBool("one")); - EXPECT(b.getBool("one", maybe = false)); - EXPECT(b.get("one", maybe = false) && maybe); - - - geo::spec::MappedConfiguration c; - EXPECT_NOT(c.has("foo")); - - c.set("foo", two); - EXPECT(c.has("foo")); - EXPECT_THROWS_AS(c.getInt("foo"), eckit::ConfigurationNotFound); // cannot access as int - EXPECT(::eckit::types::is_approximately_equal(c.getDouble("foo"), two)); - EXPECT(c.getString("foo") == "2"); - - c.set("bar", one); - EXPECT_EQUAL(c.getInt("bar"), one); - EXPECT(::eckit::types::is_approximately_equal(c.getDouble("bar"), static_cast(one))); - EXPECT(c.getString("bar") == "1"); - - c.set("foo", three); - EXPECT_EQUAL(c.getString("foo"), three); - - - geo::spec::MappedConfiguration d(c); - - EXPECT(d.has("foo")); - EXPECT_EQUAL(d.getString("foo"), three); - EXPECT_THROWS_AS(d.getInt("foo"), eckit::ConfigurationNotFound); // cannot access as int - EXPECT_THROWS_AS(d.getDouble("foo"), eckit::ConfigurationNotFound); // cannot access as real - - d.set("foo", one); - EXPECT_EQUAL(d.getInt("foo"), one); - - - geo::spec::MappedConfiguration e(c); - - ASSERT(e.has("foo")); - ASSERT(e.has("bar")); -} - -//---------------------------------------------------------------------------------------------------------------------- - -CASE("test_dynamic_configuration") { - int one = 1; - double two = 2.; - - geo::spec::MappedConfiguration a({{"foo", one}, {"bar", two}}); - ASSERT(a.has("foo")); - ASSERT(a.has("bar")); - - geo::spec::DynamicConfiguration b(a); - - ASSERT(b.has("foo")); - ASSERT(b.has("bar")); - - b.hide("foo"); - EXPECT_NOT(b.has("foo")); - - b.unhide("foo"); - ASSERT(b.has("foo")); - - EXPECT_EQUAL(a.getInt("foo"), one); - - auto value = b.getInt("foo"); - EXPECT_EQUAL(value, one); -} - -//---------------------------------------------------------------------------------------------------------------------- - } // namespace eckit::test int main(int argc, char** argv) { diff --git a/tests/config/test_mapped_configuration.cc b/tests/config/test_mapped_configuration.cc deleted file mode 100644 index 9738572bc..000000000 --- a/tests/config/test_mapped_configuration.cc +++ /dev/null @@ -1,57 +0,0 @@ -/* - * (C) Copyright 1996- 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 -#include - -#include "eckit/geo/spec/MappedConfiguration.h" -#include "eckit/testing/Test.h" - - -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { - - -CASE("MappedConfiguration") { - std::unique_ptr param(new geo::spec::MappedConfiguration({{"a", -123}, {"b", "B"}, {"c", 123UL}})); - - int a = 0; - EXPECT(param->get("a", a)); - EXPECT_EQUAL(a, -123); - std::cout << "a: '" << a << "'" << std::endl; - - std::string b; - EXPECT(param->get("b", b)); - EXPECT_EQUAL(b, "B"); - - size_t c = 0; - EXPECT(param->get("c", c)); - EXPECT_EQUAL(c, 123UL); - - int d = 0; - dynamic_cast(param.get())->set("b", 321); - EXPECT(param->get("b", d)); - EXPECT_EQUAL(d, 321); -} - - -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- - - -int main(int argc, char** argv) { - return eckit::testing::run_tests(argc, argv); -} diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 492c639fe..47f8ee008 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -1,25 +1,24 @@ -set( _tests - area_boundingbox - area_polygon - coordinate_helpers - figure_sphere - great_circle - grid - grid_regular_ll - grid_reorder - grid_to_points - gridspec - increments - iterator - kdtree - kpoint - point - projection - range - search - util ) - -foreach( _test ${_tests} ) +foreach(_test + area_boundingbox + area_polygon + coordinate_helpers + figure_sphere + great_circle + grid + grid_regular_ll + grid_reorder + grid_to_points + gridspec + increments + iterator + kdtree + kpoint + point + projection + range + search + spec + util ) ecbuild_add_test( TARGET eckit_test_geo_${_test} SOURCES ${_test}.cc diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index 68f1c8605..9ab75bc83 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -13,7 +13,7 @@ #include #include "eckit/geo/Grid.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" @@ -32,8 +32,8 @@ CASE("GridFactory::build") { SECTION("GridFactory::build_from_name") { for (const auto& test : {test_t{"O2", 88}, {"f2", 32}, {"h2", 48}}) { - std::unique_ptr grid(GridFactory::build( - *std::unique_ptr(new spec::MappedConfiguration({{"grid", test.name}})))); + std::unique_ptr grid( + GridFactory::build(*std::unique_ptr(new spec::Custom({{"grid", test.name}})))); auto size = grid->size(); EXPECT_EQUAL(size, test.size); @@ -42,8 +42,8 @@ CASE("GridFactory::build") { SECTION("RegularGaussian") { - std::unique_ptr grid(GridFactory::build( - *std::unique_ptr(new spec::MappedConfiguration({{"grid", "f2"}, {"south", 0}})))); + std::unique_ptr grid( + GridFactory::build(*std::unique_ptr(new spec::Custom({{"grid", "f2"}, {"south", 0}})))); auto nh = grid->size(); EXPECT_EQUAL(nh, 32 / 2); @@ -57,12 +57,11 @@ CASE("GridFactory::build") { SECTION("Grid::build_from_increments") { SECTION("global") { - std::unique_ptr global( - GridFactory::build(*std::unique_ptr(new spec::MappedConfiguration({ - {"type", "regular_ll"}, - {"west_east_increment", 1}, - {"south_north_increment", 1}, - })))); + std::unique_ptr global(GridFactory::build(*std::unique_ptr(new spec::Custom({ + {"type", "regular_ll"}, + {"west_east_increment", 1}, + {"south_north_increment", 1}, + })))); auto size = global->size(); EXPECT_EQUAL(size, 360 * 181); @@ -70,16 +69,15 @@ CASE("GridFactory::build") { SECTION("non-global") { - std::unique_ptr grid( - GridFactory::build(*std::unique_ptr(new spec::MappedConfiguration({ - {"type", "regular_ll"}, - {"west_east_increment", 1}, - {"south_north_increment", 1}, - {"north", 10}, - {"west", 1}, - {"south", 1}, - {"east", 10}, - })))); + std::unique_ptr grid(GridFactory::build(*std::unique_ptr(new spec::Custom({ + {"type", "regular_ll"}, + {"west_east_increment", 1}, + {"south_north_increment", 1}, + {"north", 10}, + {"west", 1}, + {"south", 1}, + {"east", 10}, + })))); auto size = grid->size(); EXPECT_EQUAL(size, 100); diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index 6a32ec790..addaed4b1 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -13,7 +13,7 @@ #include #include "eckit/geo/grid/regular/RegularLL.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" @@ -24,20 +24,19 @@ using namespace geo; CASE("") { - std::unique_ptr global( - new grid::regular::RegularLL(spec::MappedConfiguration{{{"grid", std::vector{1, 1}}}})); + std::unique_ptr global(new grid::regular::RegularLL(spec::Custom{{{"grid", std::vector{1, 1}}}})); size_t global_size = global->size(); EXPECT_EQUAL(global_size, 360 * 181); std::unique_ptr local(new grid::regular::RegularLL( - spec::MappedConfiguration{{{"grid", std::vector{2, 1}}, {"area", std::vector{10, 1, 1, 10}}}})); + spec::Custom{{{"grid", std::vector{2, 1}}, {"area", std::vector{10, 1, 1, 10}}}})); size_t local_size = local->size(); EXPECT_EQUAL(local_size, 5 * 10); - std::unique_ptr almost_global(new grid::regular::RegularLL(spec::MappedConfiguration{ - {{"grid", std::vector{1, 1}}, {"area", std::vector{89.5, 0., -89.5, 359.1}}}})); + std::unique_ptr almost_global(new grid::regular::RegularLL( + spec::Custom{{{"grid", std::vector{1, 1}}, {"area", std::vector{89.5, 0., -89.5, 359.1}}}})); size_t almost_global_size = almost_global->size(); EXPECT_EQUAL(almost_global_size, 360 * 180); diff --git a/tests/geo/grid_reorder.cc b/tests/geo/grid_reorder.cc index bca207adc..17e37ed62 100644 --- a/tests/geo/grid_reorder.cc +++ b/tests/geo/grid_reorder.cc @@ -13,7 +13,7 @@ #include #include "eckit/geo/Grid.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" @@ -35,7 +35,7 @@ using namespace geo; CASE("HEALPix") { SECTION("HEALPix::reorder") { std::unique_ptr ring( - GridFactory::build(*std::unique_ptr(new spec::MappedConfiguration({{"grid", "H2"}})))); + GridFactory::build(*std::unique_ptr(new spec::Custom({{"grid", "H2"}})))); static const Renumber expected_ren_ring_to_nested{ 3, 7, 11, 15, 2, 1, 6, 5, 10, 9, 14, 13, 19, 0, 23, 4, 27, 8, 31, 12, 17, 22, 21, 26, diff --git a/tests/geo/gridspec.cc b/tests/geo/gridspec.cc index 00f70d7dd..e430e6a01 100644 --- a/tests/geo/gridspec.cc +++ b/tests/geo/gridspec.cc @@ -1,5 +1,5 @@ /* - * (C) Copyright 1996- ECMWF. + * (S) Copyright 1996- 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. @@ -14,7 +14,7 @@ #include #include "eckit/geo/Grid.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/log/Log.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" @@ -34,61 +34,61 @@ namespace eckit::test { using namespace geo; -using C = std::unique_ptr; +using S = std::unique_ptr; using G = std::unique_ptr; -using M = spec::MappedConfiguration; +using C = spec::Custom; using v = std::vector; -static const spec::MappedConfiguration BAD; - - -static std::pair cases[]{ - {M({{"N", 2}}), M({{"N", 2}, {"type", "reduced_gg"}})}, - {M({{"area", v{90, -180, -90, 180}}, {"grid", v{2, 2}}}), M({{"type", "regular_ll"}})}, - {M({{"area", v{90, -180, -90, 180}}}), BAD}, - {M({{"grid", "B48"}}), BAD}, - {M({{"grid", "F48"}}), M({{"type", "regular_gg"}})}, - {M({{"grid", "N48"}}), M({{"type", "reduced_gg"}})}, - {M({{"grid", "O48"}}), M({{"type", "reduced_gg"}})}, - {M({{"grid", 48}}), BAD}, - {M({{"grid", v{2, 2}}}), M({{"grid", v{2, 2}}, {"type", "regular_ll"}})}, - {M({{"type", "latlon"}, {"grid", v{2, 2}}}), BAD}, - {M({{"type", "reduced_gg"}, {"grid", "48"}}), BAD}, - {M({{"type", "reduced_gg"}, {"grid", "F048"}}), BAD}, - {M({{"type", "reduced_gg"}, {"grid", "N"}}), BAD}, - {M({{"type", "reduced_gg"}, {"grid", "N048"}}), BAD}, - {M({{"type", "reduced_gg"}, {"grid", "N48"}}), M({{"type", "reduced_gg"}})}, - {M({{"type", "reduced_gg"}, {"grid", "O048"}}), BAD}, - {M({{"type", "reduced_gg"}, {"grid", "O48"}}), M({{"type", "reduced_gg"}})}, - {M({{"type", "reduced_gg"}, {"grid", 48}}), BAD}, - {M({{"type", "reduced_gg"}}), BAD}, - {M({{"type", "reduced_latlon"}, {"grid", 2}}), BAD}, - {M({{"type", "reduced_ll"}, {"grid", 12}}), BAD}, - {M({{"type", "regular_gg"}, {"grid", "48"}}), BAD}, - {M({{"type", "regular_gg"}, {"grid", "F048"}}), BAD}, - {M({{"type", "regular_gg"}, {"grid", "F48"}}), M({{"type", "regular_gg"}})}, - {M({{"type", "regular_gg"}, {"grid", "N48"}}), BAD}, - {M({{"type", "regular_gg"}, {"grid", "O48"}}), BAD}, - {M({{"type", "regular_gg"}, {"grid", "a"}}), BAD}, - {M({{"type", "regular_gg"}, {"grid", 48}}), BAD}, - {M({{"type", "regular_ll"}, {"area", v{90, -180, -90, 180}}}), BAD}, - {M({{"type", "regular_ll"}, {"grid", "F48"}}), BAD}, - {M({{"type", "regular_ll"}, {"grid", "a"}}), BAD}, - {M({{"type", "regular_ll"}, {"grid", 48}}), BAD}, - {M({{"type", "regular_ll"}, {"grid", std::vector{"a", "b"}}}), BAD}, - {M({{"type", "regular_ll"}, {"grid", v{1, 2, 3}}}), BAD}, - {M({{"type", "regular_ll"}, {"grid", v{1, 2}}}), M({{"type", "regular_ll"}})}, - {M({{"type", "regular_ll"}, {"grid", v{1}}}), BAD}, - - {M({{"type", "mercator"}, +static const spec::Custom BAD; + + +static std::pair cases[]{ + {C({{"N", 2}}), C({{"N", 2}, {"type", "reduced_gg"}})}, + {C({{"area", v{90, -180, -90, 180}}, {"grid", v{2, 2}}}), C({{"type", "regular_ll"}})}, + {C({{"area", v{90, -180, -90, 180}}}), BAD}, + {C({{"grid", "B48"}}), BAD}, + {C({{"grid", "F48"}}), C({{"type", "regular_gg"}})}, + {C({{"grid", "N48"}}), C({{"type", "reduced_gg"}})}, + {C({{"grid", "O48"}}), C({{"type", "reduced_gg"}})}, + {C({{"grid", 48}}), BAD}, + {C({{"grid", v{2, 2}}}), C({{"grid", v{2, 2}}, {"type", "regular_ll"}})}, + {C({{"type", "latlon"}, {"grid", v{2, 2}}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "48"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "F048"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "N"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "N048"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "N48"}}), C({{"type", "reduced_gg"}})}, + {C({{"type", "reduced_gg"}, {"grid", "O048"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "O48"}}), C({{"type", "reduced_gg"}})}, + {C({{"type", "reduced_gg"}, {"grid", 48}}), BAD}, + {C({{"type", "reduced_gg"}}), BAD}, + {C({{"type", "reduced_latlon"}, {"grid", 2}}), BAD}, + {C({{"type", "reduced_ll"}, {"grid", 12}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "48"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "F048"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "F48"}}), C({{"type", "regular_gg"}})}, + {C({{"type", "regular_gg"}, {"grid", "N48"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "O48"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "a"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", 48}}), BAD}, + {C({{"type", "regular_ll"}, {"area", v{90, -180, -90, 180}}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", "F48"}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", "a"}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", 48}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", std::vector{"a", "b"}}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", v{1, 2, 3}}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", v{1, 2}}}), C({{"type", "regular_ll"}})}, + {C({{"type", "regular_ll"}, {"grid", v{1}}}), BAD}, + + {C({{"type", "mercator"}, {"area", v{31.173058, 262.036499, 14.736453, 284.975281}}, {"grid", v{45000.0, 45000.0}}, {"lad", 14.0}, {"nx", 56}, {"ny", 44}, {"orientation", 0.0}}), - M()}, + C()}, }; @@ -97,19 +97,19 @@ CASE("gridspec") { for (const auto& [user, gridspec] : cases) { Log::info() << user << " -> " << gridspec << std::endl; - C config(GridFactory::configure(user)); - ASSERT(config); + S spec(GridFactory::spec(user)); + ASSERT(spec); - if (!config->has("type")) { + if (!spec->has("type")) { EXPECT(gridspec.empty()); continue; } if (gridspec.empty()) { - EXPECT_THROWS(G(GridFactory::build(*config))); + EXPECT_THROWS(GridFactory::build(*spec)); } else { - EXPECT_NO_THROW(G(GridFactory::build(*config))); + EXPECT_NO_THROW(GridFactory::build(*spec)); } } } diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index 692ac2e91..e8a5137fd 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -18,7 +18,7 @@ #include "eckit/geo/projection/LonLatToXYZ.h" #include "eckit/geo/projection/Mercator.h" #include "eckit/geo/projection/Rotation.h" -#include "eckit/geo/spec/MappedConfiguration.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/log/Log.h" #include "eckit/testing/Test.h" @@ -36,20 +36,20 @@ CASE("projection") { SECTION("projection type: none") { - P projection(ProjectionFactory::instance().get("none").create(spec::MappedConfiguration{})); + P projection(ProjectionFactory::instance().get("none").create(spec::Custom{})); EXPECT(points_equal(p, projection->inv(p))); EXPECT(points_equal(p, projection->fwd(p))); } SECTION("projection type: rotation") { - spec::MappedConfiguration param({ + spec::Custom spec({ {"projection", "rotation"}, {"south_pole_lat", -91.}, {"south_pole_lon", -361.}, }); - P projection(ProjectionFactory::instance().get(param.getString("projection")).create(param)); + P projection(ProjectionFactory::instance().get(spec.get_string("projection")).create(spec)); EXPECT(points_equal(p, projection->inv(projection->fwd(p)))); EXPECT(points_equal(p, projection->fwd(projection->inv(p)))); @@ -57,9 +57,9 @@ CASE("projection") { SECTION("projection type: ll_to_xyz") { - P s1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::MappedConfiguration({{"R", 1.}}))); - P s2(ProjectionFactory::instance().get("ll_to_xyz").create(spec::MappedConfiguration({{"a", 1.}, {"b", 1.}}))); - P s3(ProjectionFactory::instance().get("ll_to_xyz").create(spec::MappedConfiguration({{"a", 1.}, {"b", 0.5}}))); + P s1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"R", 1.}}))); + P s2(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 1.}}))); + P s3(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 0.5}}))); EXPECT(points_equal(p, s1->inv(s1->fwd(p)))); EXPECT(points_equal(p, s2->inv(s2->fwd(p)))); @@ -304,7 +304,7 @@ CASE("projection") { for (const auto& test : tests) { P projection(ProjectionFactory::instance().get("proj").create( - spec::MappedConfiguration{{{"source", "EPSG:4326"}, {"target", test.target}}})); + spec::Custom{{{"source", "EPSG:4326"}, {"target", test.target}}})); #if 0 std::cout << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) @@ -320,7 +320,7 @@ CASE("projection") { EXPECT(points_equal(c, a)); P reverse(ProjectionFactory::instance().get("proj").create( - spec::MappedConfiguration({{"source", test.target}, {"target", "EPSG:4326"}}))); + spec::Custom({{"source", test.target}, {"target", "EPSG:4326"}}))); auto d = reverse->fwd(test.b); auto e = reverse->inv(d); diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc new file mode 100644 index 000000000..d1748efaf --- /dev/null +++ b/tests/geo/spec.cc @@ -0,0 +1,194 @@ +/* + * (C) Copyright 1996- 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 +#include + +#include "eckit/geo/spec/Custom.h" +#include "eckit/geo/spec/Layered.h" +#include "eckit/testing/Test.h" + + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace eckit::test { + + +using namespace geo; + + +CASE("Custom") { + SECTION("access") { + std::unique_ptr spec(new spec::Custom({{"a", -123}, {"b", "B"}, {"c", 123UL}})); + + int a = 0; + EXPECT(spec->get("a", a)); + EXPECT_EQUAL(a, -123); + std::cout << "a: '" << a << "'" << std::endl; + + std::string b; + EXPECT(spec->get("b", b)); + EXPECT_EQUAL(b, "B"); + + size_t c = 0; + EXPECT(spec->get("c", c)); + EXPECT_EQUAL(c, 123UL); + + int d = 0; + dynamic_cast(spec.get())->set("b", 321); + EXPECT(spec->get("b", d)); + EXPECT_EQUAL(d, 321); + } + + SECTION("conversion") { + int one = 1; + double two = 2.; + std::string three = "3"; + + + spec::Custom a({ + {"double", static_cast(one)}, + {"float", static_cast(one)}, + {"int", static_cast(one)}, + {"long", static_cast(one)}, + {"size_t", static_cast(one)}, + }); + + // test scalar type conversion + for (std::string key : {"double", "float", "int", "long", "size_t"}) { + double value_as_double = 0; + float value_as_float = 0; + + EXPECT(a.get(key, value_as_double) && value_as_double == static_cast(one)); + EXPECT(a.get(key, value_as_float) && value_as_float == static_cast(one)); + + if (key == "int" || key == "long" || key == "size_t") { + int value_as_int = 0; + long value_as_long = 0; + size_t value_as_size_t = 0; + + EXPECT(a.get(key, value_as_int) && value_as_int == static_cast(one)); + EXPECT(a.get(key, value_as_long) && value_as_long == static_cast(one)); + EXPECT(a.get(key, value_as_size_t) && value_as_size_t == static_cast(one)); + } + + EXPECT_EQUAL(a.get_string(key), std::to_string(1)); + } + + + spec::Custom b({ + {"true", true}, + {"false", false}, + {"zero", 0}, + {"one", 1}, + }); + + EXPECT(b.get_bool("true")); + EXPECT(!b.get_bool("false")); + + bool maybe = false; + EXPECT(!b.has("?")); + EXPECT(!b.get_bool("?", false)); + EXPECT(b.get_bool("?", true)); + + EXPECT(b.get("true", maybe = false) && maybe); + EXPECT(b.get_bool("true", true)); + EXPECT(b.get_bool("true", false)); + + EXPECT(b.get("false", maybe = true) && !maybe); + EXPECT(!b.get_bool("false", true)); + EXPECT(!b.get_bool("false", false)); + + EXPECT(!b.get_bool("zero")); + EXPECT(!b.get_bool("zero", maybe = true)); + EXPECT(b.get("zero", maybe = true) && !maybe); + + EXPECT(b.get_bool("one")); + EXPECT(b.get_bool("one", maybe = false)); + EXPECT(b.get("one", maybe = false) && maybe); + + + spec::Custom c; + EXPECT_NOT(c.has("foo")); + + c.set("foo", two); + EXPECT(c.has("foo")); + EXPECT_THROWS_AS(c.get_int("foo"), SpecNotFound); // cannot access as int + EXPECT(::eckit::types::is_approximately_equal(c.get_double("foo"), two)); + EXPECT(c.get_string("foo") == "2"); + + c.set("bar", one); + EXPECT_EQUAL(c.get_int("bar"), one); + EXPECT(::eckit::types::is_approximately_equal(c.get_double("bar"), static_cast(one))); + EXPECT(c.get_string("bar") == "1"); + + c.set("foo", three); + EXPECT_EQUAL(c.get_string("foo"), three); + + + spec::Custom d(c); + + EXPECT(d.has("foo")); + EXPECT_EQUAL(d.get_string("foo"), three); + EXPECT_THROWS_AS(d.get_int("foo"), SpecNotFound); // cannot access as int + EXPECT_THROWS_AS(d.get_double("foo"), SpecNotFound); // cannot access as real + + d.set("foo", one); + EXPECT_EQUAL(d.get_int("foo"), one); + + + spec::Custom e(c); + + ASSERT(e.has("foo")); + ASSERT(e.has("bar")); + } +} + + +//---------------------------------------------------------------------------------------------------------------------- + +CASE("Layered") { + int one = 1; + double two = 2.; + + spec::Custom a({{"foo", one}, {"bar", two}}); + ASSERT(a.has("foo")); + ASSERT(a.has("bar")); + + spec::Layered b(a); + + ASSERT(b.has("foo")); + ASSERT(b.has("bar")); + + b.hide("foo"); + EXPECT_NOT(b.has("foo")); + + b.unhide("foo"); + ASSERT(b.has("foo")); + + EXPECT_EQUAL(a.get_int("foo"), one); + + auto value = b.get_int("foo"); + EXPECT_EQUAL(value, one); +} + + +} // namespace eckit::test + + +//---------------------------------------------------------------------------------------------------------------------- + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From 02452817eab899924612be9b66808acbddc1a852 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 12 Jan 2024 16:58:43 +0000 Subject: [PATCH 413/737] eckit::geo::etc::Grid --- src/eckit/geo/CMakeLists.txt | 6 +++--- src/eckit/geo/Grid.cc | 4 ++-- src/eckit/geo/{GridConfig.cc => etc/Grid.cc} | 12 ++++++------ src/eckit/geo/{GridConfig.h => etc/Grid.h} | 10 +++++----- 4 files changed, 16 insertions(+), 16 deletions(-) rename src/eckit/geo/{GridConfig.cc => etc/Grid.cc} (93%) rename src/eckit/geo/{GridConfig.h => etc/Grid.h} (88%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 45abec437..3a422c687 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -23,8 +23,6 @@ list(APPEND eckit_geo_srcs GreatCircle.h Grid.cc Grid.h - GridConfig.cc - GridConfig.h Increments.cc Increments.h Iterator.h @@ -54,6 +52,8 @@ list(APPEND eckit_geo_srcs UnitSphere.h area/BoundingBox.cc area/BoundingBox.h + etc/Grid.cc + etc/Grid.h figure/OblateSpheroid.cc figure/OblateSpheroid.h figure/Sphere.cc @@ -104,9 +104,9 @@ list(APPEND eckit_geo_srcs range/Regular.h range/RegularLongitude.cc range/RegularLongitude.h - spec/Generator.h spec/Custom.cc spec/Custom.h + spec/Generator.h spec/Layered.cc spec/Layered.h util.cc diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 0001fd609..9f83137b8 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -17,7 +17,7 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/GridConfig.h" +#include "eckit/geo/etc/Grid.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/spec/Layered.h" #include "eckit/log/Log.h" @@ -129,7 +129,7 @@ const Grid* GridFactory::build_(const Spec& spec) const { Spec* GridFactory::generate_spec_(const Spec& spec) const { AutoLock lock(mutex_); - GridConfig::instance(); + etc::Grid::instance(); auto* cfg = new spec::Layered(spec); ASSERT(cfg != nullptr); diff --git a/src/eckit/geo/GridConfig.cc b/src/eckit/geo/etc/Grid.cc similarity index 93% rename from src/eckit/geo/GridConfig.cc rename to src/eckit/geo/etc/Grid.cc index 684ebc6fa..4525fc127 100644 --- a/src/eckit/geo/GridConfig.cc +++ b/src/eckit/geo/etc/Grid.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/GridConfig.h" +#include "eckit/geo/etc/Grid.h" #include #include @@ -25,7 +25,7 @@ #include "eckit/value/Value.h" -namespace eckit::geo { +namespace eckit::geo::etc { namespace { @@ -69,13 +69,13 @@ spec::Custom* config_from_value_map(const ValueMap& map) { } // namespace -const GridConfig& GridConfig::instance() { - static const GridConfig __instance(LibEcKitGeo::configFileGrid()); +const Grid& Grid::instance() { + static const Grid __instance(LibEcKitGeo::configFileGrid()); return __instance; } -GridConfig::GridConfig(const PathName& path) { +Grid::Grid(const PathName& path) { auto* config = new spec::Custom; config_.reset(config); @@ -123,4 +123,4 @@ GridConfig::GridConfig(const PathName& path) { } -} // namespace eckit::geo +} // namespace eckit::geo::etc diff --git a/src/eckit/geo/GridConfig.h b/src/eckit/geo/etc/Grid.h similarity index 88% rename from src/eckit/geo/GridConfig.h rename to src/eckit/geo/etc/Grid.h index 148fcd512..74f63e2fb 100644 --- a/src/eckit/geo/GridConfig.h +++ b/src/eckit/geo/etc/Grid.h @@ -23,10 +23,10 @@ class PathName; } // namespace eckit -namespace eckit::geo { +namespace eckit::geo::etc { -class GridConfig final { +class Grid final { public: // -- Types // None @@ -48,7 +48,7 @@ class GridConfig final { // -- Methods - static const GridConfig& instance(); + static const Grid& instance(); const Spec& config() const { return *config_; } @@ -64,7 +64,7 @@ class GridConfig final { private: // -- Constructors - explicit GridConfig(const PathName&); + explicit Grid(const PathName&); // -- Members @@ -87,4 +87,4 @@ class GridConfig final { }; -} // namespace eckit::geo +} // namespace eckit::geo::etc From db2f73dadb6d0bde008cac1e394f6621d2c131cc Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 13 Jan 2024 00:29:03 +0000 Subject: [PATCH 414/737] eckit::geo::etc::Grid --- src/eckit/geo/Grid.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 9f83137b8..9022009ec 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -170,7 +170,7 @@ Spec* GridFactory::generate_spec_(const Spec& spec) const { void GridFactory::list_(std::ostream& out) const { AutoLock lock(mutex_); - GridConfig::instance(); + etc::Grid::instance(); out << SpecByUID::instance() << std::endl; out << SpecByName::instance() << std::endl; From 45b1eb111b81e7be8667c399c64495739f1de924 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 13 Jan 2024 00:29:14 +0000 Subject: [PATCH 415/737] eckit::geo::util::Mutex --- src/eckit/geo/CMakeLists.txt | 1 + src/eckit/geo/util/Mutex.h | 58 ++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 src/eckit/geo/util/Mutex.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 3a422c687..7df2d7701 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -111,6 +111,7 @@ list(APPEND eckit_geo_srcs spec/Layered.h util.cc util.h + util/Mutex.h util/arange.cc util/gaussian_latitudes.cc util/linspace.cc diff --git a/src/eckit/geo/util/Mutex.h b/src/eckit/geo/util/Mutex.h new file mode 100644 index 000000000..87ed8f477 --- /dev/null +++ b/src/eckit/geo/util/Mutex.h @@ -0,0 +1,58 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#define ECKIT_GEO_ECKIT_THREADS + +#if defined(ECKIT_GEO_ECKIT_THREADS) +#include "eckit/thread/AutoLock.h" +#include "eckit/thread/Mutex.h" +#else +#include +#endif + + +namespace eckit::geo::util { + + +#if defined(ECKIT_GEO_ECKIT_THREADS) + + +using recursive_mutex = eckit::Mutex; + +template +using lock_guard = typename eckit::AutoLock; + +struct once_flag { + pthread_once_t once_ = PTHREAD_ONCE_INIT; +}; + +template +inline void call_once(once_flag& flag, Callable&& fun) { + pthread_once(&(flag.once_), fun); +} + + +#else + + +using std::call_once; +using std::lock_guard; +using std::once_flag; +using std::recursive_mutex; + + +#endif + + +} // namespace eckit::geo::util From aa97121bc711d409c34cc8e9bc6605b456a0657f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 13 Jan 2024 01:46:51 +0000 Subject: [PATCH 416/737] eckit::geo::etc::Grid --- src/eckit/geo/Grid.cc | 4 +-- src/eckit/geo/LibEcKitGeo.cc | 2 +- src/eckit/geo/LibEcKitGeo.h | 2 +- src/eckit/geo/etc/Grid.cc | 36 +++++++++---------- src/eckit/geo/etc/Grid.h | 4 +-- src/eckit/geo/grid/reduced/HEALPix.cc | 2 +- src/eckit/geo/grid/reduced/HEALPix.h | 2 +- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 4 +-- src/eckit/geo/grid/regular/RegularGaussian.cc | 2 +- src/eckit/geo/grid/regular/RegularGaussian.h | 2 +- src/eckit/geo/grid/regular/RegularLL.cc | 2 +- src/eckit/geo/grid/regular/RegularLL.h | 2 +- src/eckit/geo/grid/unstructured/ORCA.cc | 4 +-- src/eckit/geo/grid/unstructured/ORCA.h | 2 +- .../grid/unstructured/UnstructuredFromGrid.cc | 4 +-- .../grid/unstructured/UnstructuredFromGrid.h | 2 +- src/eckit/geo/spec/Generator.h | 32 ++++++++--------- 17 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 9022009ec..c38c31c6c 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -154,10 +154,10 @@ Spec* GridFactory::generate_spec_(const Spec& spec) const { // configurable options if (std::string uid; cfg->get("uid", uid)) { - cfg->push_front(SpecByUID::instance().get(uid).config()); + cfg->push_front(SpecByUID::instance().get(uid).spec()); } else if (std::string grid; cfg->get("grid", grid) && SpecByName::instance().matches(grid)) { - cfg->push_front(SpecByName::instance().match(grid).config(grid)); + cfg->push_front(SpecByName::instance().match(grid).spec(grid)); } diff --git a/src/eckit/geo/LibEcKitGeo.cc b/src/eckit/geo/LibEcKitGeo.cc index 72bca2286..0c2f06038 100644 --- a/src/eckit/geo/LibEcKitGeo.cc +++ b/src/eckit/geo/LibEcKitGeo.cc @@ -34,7 +34,7 @@ LibEcKitGeo& LibEcKitGeo::instance() { } -PathName LibEcKitGeo::configFileGrid() { +PathName LibEcKitGeo::etcGrid() { static const PathName path{ LibResource("eckit-geo-grid;$ECKIT_GEO_GRID", "~eckit/etc/eckit/geo/grid.yaml")}; return path; diff --git a/src/eckit/geo/LibEcKitGeo.h b/src/eckit/geo/LibEcKitGeo.h index aaf3ed7c3..c1ad1b9d9 100644 --- a/src/eckit/geo/LibEcKitGeo.h +++ b/src/eckit/geo/LibEcKitGeo.h @@ -47,7 +47,7 @@ class LibEcKitGeo final : public system::Library { static LibEcKitGeo& instance(); - static eckit::PathName configFileGrid(); + static eckit::PathName etcGrid(); static bool caching(); static std::string cacheDir(); diff --git a/src/eckit/geo/etc/Grid.cc b/src/eckit/geo/etc/Grid.cc index 4525fc127..f9c88b482 100644 --- a/src/eckit/geo/etc/Grid.cc +++ b/src/eckit/geo/etc/Grid.cc @@ -39,7 +39,7 @@ spec::Custom::value_type __from_value(const Value& value) { } -void set_config_value(spec::Custom& config, const std::string& key, const Value& value) { +void set_custom_value(spec::Custom& custom, const std::string& key, const Value& value) { using number_type = pl_type::value_type; auto list_of = [](const ValueList& list, auto pred) { return std::all_of(list.begin(), list.end(), pred); }; @@ -53,14 +53,14 @@ void set_config_value(spec::Custom& config, const std::string& key, const Value& : value.isNumber() ? __from_value(value) : __from_value(value); - std::visit([&](const auto& val) { config.set(key, val); }, val); + std::visit([&](const auto& val) { custom.set(key, val); }, val); } spec::Custom* config_from_value_map(const ValueMap& map) { auto* config = new spec::Custom; for (const auto& kv : map) { - set_config_value(*config, kv.first, kv.second); + set_custom_value(*config, kv.first, kv.second); } return config; } @@ -70,27 +70,27 @@ spec::Custom* config_from_value_map(const ValueMap& map) { const Grid& Grid::instance() { - static const Grid __instance(LibEcKitGeo::configFileGrid()); + static const Grid __instance(LibEcKitGeo::etcGrid()); return __instance; } Grid::Grid(const PathName& path) { - auto* config = new spec::Custom; - config_.reset(config); - - struct SpecUID final : SpecByUID::configurator_t { - explicit SpecUID(spec::Custom* config) : - config_(config) {} - Spec* config() const override { return new spec::Custom(*config_); } - std::unique_ptr config_; + auto* custom = new spec::Custom; + spec_.reset(custom); + + struct SpecUID final : SpecByUID::generator_t { + explicit SpecUID(spec::Custom* spec) : + spec_(spec) {} + Spec* spec() const override { return new spec::Custom(*spec_); } + std::unique_ptr spec_; }; - struct SpecName final : SpecByName::configurator_t { - explicit SpecName(spec::Custom* config) : - config_(config) {} - Spec* config(SpecByName::configurator_t::arg1_t) const override { return new spec::Custom(*config_); } - std::unique_ptr config_; + struct SpecName final : SpecByName::generator_t { + explicit SpecName(spec::Custom* spec) : + spec_(spec) {} + Spec* spec(SpecByName::generator_t::arg1_t) const override { return new spec::Custom(*spec_); } + std::unique_ptr spec_; }; if (path.exists()) { @@ -117,7 +117,7 @@ Grid::Grid(const PathName& path) { continue; } - set_config_value(*config, key, kv.second); + set_custom_value(*custom, key, kv.second); } } } diff --git a/src/eckit/geo/etc/Grid.h b/src/eckit/geo/etc/Grid.h index 74f63e2fb..a85aebd15 100644 --- a/src/eckit/geo/etc/Grid.h +++ b/src/eckit/geo/etc/Grid.h @@ -50,7 +50,7 @@ class Grid final { static const Grid& instance(); - const Spec& config() const { return *config_; } + const Spec& spec() const { return *spec_; } // -- Overridden methods // None @@ -68,7 +68,7 @@ class Grid final { // -- Members - std::unique_ptr config_; + std::unique_ptr spec_; // -- Methods // None diff --git a/src/eckit/geo/grid/reduced/HEALPix.cc b/src/eckit/geo/grid/reduced/HEALPix.cc index dcb7a1536..e2a4ebf48 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.cc +++ b/src/eckit/geo/grid/reduced/HEALPix.cc @@ -294,7 +294,7 @@ size_t HEALPix::nj() const { } -Spec* HEALPix::config(const std::string& name) { +Spec* HEALPix::spec(const std::string& name) { auto Nside = Translator{}(name.substr(1)); return new spec::Custom({{"type", "HEALPix"}, {"Nside", Nside}, {"orderingConvention", "ring"}}); } diff --git a/src/eckit/geo/grid/reduced/HEALPix.h b/src/eckit/geo/grid/reduced/HEALPix.h index cb43f5897..007e24ce5 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.h +++ b/src/eckit/geo/grid/reduced/HEALPix.h @@ -57,7 +57,7 @@ class HEALPix final : public Reduced { // -- Class members - static Spec* config(const std::string& name); + static Spec* spec(const std::string& name); // -- Class methods // None diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index b7cc487a1..e7c50daf2 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -71,7 +71,7 @@ std::vector ReducedGaussian::longitudes(size_t j) const { struct ReducedGaussianClassical { - static Spec* config(const std::string& name) { + static Spec* spec(const std::string& name) { auto N = Translator{}(name.substr(1)); return new spec::Custom({{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_classical_pl(N)}}); } @@ -79,7 +79,7 @@ struct ReducedGaussianClassical { struct ReducedGaussianOctahedral { - static Spec* config(const std::string& name) { + static Spec* spec(const std::string& name) { auto N = Translator{}(name.substr(1)); return new spec::Custom({{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_octahedral_pl(N)}}); } diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index 3006968e1..c573326f1 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -49,7 +49,7 @@ Grid::iterator RegularGaussian::cend() const { } -Spec* RegularGaussian::config(const std::string& name) { +Spec* RegularGaussian::spec(const std::string& name) { auto N = Translator{}(name.substr(1)); return new spec::Custom({{"type", "regular_gg"}, {"N", N}, {"ni", 4 * N}}); } diff --git a/src/eckit/geo/grid/regular/RegularGaussian.h b/src/eckit/geo/grid/regular/RegularGaussian.h index 292c2c9e4..cb8afdf63 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.h +++ b/src/eckit/geo/grid/regular/RegularGaussian.h @@ -58,7 +58,7 @@ class RegularGaussian final : public Regular { // -- Class methods - static Spec* config(const std::string& name); + static Spec* spec(const std::string& name); private: // -- Members diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index c7354fdfa..89de6bfe3 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -178,7 +178,7 @@ const std::vector& RegularLL::latitudes() const { #define POSITIVE_REAL "[+]?([0-9]*[.])?[0-9]+([eE][-+][0-9]+)?" -Spec* RegularLL::config(const std::string& name) { +Spec* RegularLL::spec(const std::string& name) { static const std::string pattern("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); auto match = util::regex_match(pattern, name); diff --git a/src/eckit/geo/grid/regular/RegularLL.h b/src/eckit/geo/grid/regular/RegularLL.h index 22c1a3d30..a26794900 100644 --- a/src/eckit/geo/grid/regular/RegularLL.h +++ b/src/eckit/geo/grid/regular/RegularLL.h @@ -83,7 +83,7 @@ class RegularLL final : public Regular { // -- Class methods - static Spec* config(const std::string& name); + static Spec* spec(const std::string& name); private: // -- Members diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index 5a4589682..a5ff799a2 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -229,8 +229,8 @@ std::pair, std::vector> ORCA::to_latlon() const { } -Spec* ORCA::config(const std::string& name) { - return SpecByUID::instance().get(name).config(); +Spec* ORCA::spec(const std::string& name) { + return SpecByUID::instance().get(name).spec(); } diff --git a/src/eckit/geo/grid/unstructured/ORCA.h b/src/eckit/geo/grid/unstructured/ORCA.h index 11bdc244a..e924d0fa1 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.h +++ b/src/eckit/geo/grid/unstructured/ORCA.h @@ -91,7 +91,7 @@ class ORCA final : public Unstructured { // -- Class methods - static Spec* config(const std::string& name); + static Spec* spec(const std::string& name); private: // -- Members diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc index aa7d9439e..c0d4721ff 100644 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc @@ -75,8 +75,8 @@ std::vector UnstructuredFromGrid::to_points() const { } -Spec* UnstructuredFromGrid::config(const std::string& name) { - return SpecByUID::instance().get(name).config(); +Spec* UnstructuredFromGrid::spec(const std::string& name) { + return SpecByUID::instance().get(name).spec(); } diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h index 1562a6a06..4604bfbbe 100644 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h @@ -76,7 +76,7 @@ class UnstructuredFromGrid final : public Unstructured { // -- Class methods - static Spec* config(const std::string& name); + static Spec* spec(const std::string& name); private: // -- Members diff --git a/src/eckit/geo/spec/Generator.h b/src/eckit/geo/spec/Generator.h index 6df47dd32..ad0fa8edb 100644 --- a/src/eckit/geo/spec/Generator.h +++ b/src/eckit/geo/spec/Generator.h @@ -38,9 +38,9 @@ class GeneratorT { public: // -- Types - using configurator_t = C; - using key_t = std::string; - using storage_t = std::map; + using generator_t = C; + using key_t = std::string; + using storage_t = std::map; // -- Constructors @@ -59,11 +59,11 @@ class GeneratorT { bool exists(const key_t&) const; bool matches(const std::string&) const; - void regist(const key_t&, configurator_t*); + void regist(const key_t&, generator_t*); void unregist(const key_t&); - const configurator_t& get(const key_t&) const; - const configurator_t& match(const std::string&) const; + const generator_t& get(const key_t&) const; + const generator_t& match(const std::string&) const; private: // -- Constructors @@ -112,7 +112,7 @@ bool GeneratorT::matches(const std::string& k) const { } template -void GeneratorT::regist(const key_t& k, configurator_t* c) { +void GeneratorT::regist(const key_t& k, generator_t* c) { AutoLock lock(mutex_); if (exists(k)) { throw BadParameter("Configurator has already a builder for " + k, Here()); @@ -132,7 +132,7 @@ void GeneratorT::unregist(const key_t& k) { } template -const typename GeneratorT::configurator_t& GeneratorT::get(const key_t& k) const { +const typename GeneratorT::generator_t& GeneratorT::get(const key_t& k) const { AutoLock lock(mutex_); if (auto it = store_.find(k); it != store_.end()) { return *(it->second); @@ -141,7 +141,7 @@ const typename GeneratorT::configurator_t& GeneratorT::get(const key_t& k) } template -const typename GeneratorT::configurator_t& GeneratorT::match(const std::string& k) const { +const typename GeneratorT::generator_t& GeneratorT::match(const std::string& k) const { AutoLock lock(mutex_); auto end = store_.cend(); @@ -209,7 +209,7 @@ class SpecGeneratorT0 : public SpecGenerator { public: // -- Methods - virtual Spec* config() const = 0; + virtual Spec* spec() const = 0; }; //------------------------------------------------------------------------------------------------------ @@ -223,7 +223,7 @@ class SpecGeneratorT1 : public SpecGenerator { // -- Methods - virtual Spec* config(arg1_t) const = 0; + virtual Spec* spec(arg1_t) const = 0; }; //------------------------------------------------------------------------------------------------------ @@ -238,7 +238,7 @@ class SpecGeneratorT2 : public SpecGenerator { // -- Methods - virtual Spec* config(arg1_t, arg2_t) const = 0; + virtual Spec* spec(arg1_t, arg2_t) const = 0; }; //------------------------------------------------------------------------------------------------------ @@ -267,7 +267,7 @@ class ConcreteSpecGeneratorT0 final : public SpecGeneratorT0 { // -- Overridden methods - Spec* config() const override { return T::config(); } + Spec* spec() const override { return T::spec(); } private: // -- Members @@ -301,7 +301,7 @@ class ConcreteSpecGeneratorT1 final : public SpecGeneratorT1 { // -- Overridden methods - Spec* config(typename SpecGeneratorT1::arg1_t p1) const override { return T::config(p1); } + Spec* spec(typename SpecGeneratorT1::arg1_t p1) const override { return T::spec(p1); } private: // -- Members @@ -335,8 +335,8 @@ class ConcreteSpecGeneratorT2 final : public SpecGeneratorT2 { // -- Overridden methods - Spec* config(typename SpecGeneratorT1::arg1_t p1, typename SpecGeneratorT1::arg2_t p2) const override { - return T::config(p1, p2); + Spec* spec(typename SpecGeneratorT1::arg1_t p1, typename SpecGeneratorT1::arg2_t p2) const override { + return T::spec(p1, p2); } private: From b72119f0a3f70535854b6407a6db5aa2c6d4e0d5 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 15 Jan 2024 14:47:01 +0000 Subject: [PATCH 417/737] eckit::geo::etc::Grid --- src/eckit/geo/etc/Grid.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/etc/Grid.cc b/src/eckit/geo/etc/Grid.cc index f9c88b482..28329818d 100644 --- a/src/eckit/geo/etc/Grid.cc +++ b/src/eckit/geo/etc/Grid.cc @@ -79,15 +79,15 @@ Grid::Grid(const PathName& path) { auto* custom = new spec::Custom; spec_.reset(custom); - struct SpecUID final : SpecByUID::generator_t { - explicit SpecUID(spec::Custom* spec) : + struct SpecByUIDGenerator final : SpecByUID::generator_t { + explicit SpecByUIDGenerator(spec::Custom* spec) : spec_(spec) {} Spec* spec() const override { return new spec::Custom(*spec_); } std::unique_ptr spec_; }; - struct SpecName final : SpecByName::generator_t { - explicit SpecName(spec::Custom* spec) : + struct SpecByNameGenerator final : SpecByName::generator_t { + explicit SpecByNameGenerator(spec::Custom* spec) : spec_(spec) {} Spec* spec(SpecByName::generator_t::arg1_t) const override { return new spec::Custom(*spec_); } std::unique_ptr spec_; @@ -103,7 +103,7 @@ Grid::Grid(const PathName& path) { for (ValueMap m : static_cast(kv.second)) { ASSERT(m.size() == 1); SpecByUID::instance().regist(m.begin()->first.as(), - new SpecUID(config_from_value_map(m.begin()->second))); + new SpecByUIDGenerator(config_from_value_map(m.begin()->second))); } continue; } @@ -112,7 +112,7 @@ Grid::Grid(const PathName& path) { for (ValueMap m : static_cast(kv.second)) { ASSERT(m.size() == 1); SpecByName::instance().regist(m.begin()->first.as(), - new SpecName(config_from_value_map(m.begin()->second))); + new SpecByNameGenerator(config_from_value_map(m.begin()->second))); } continue; } From 3ed889f4effef945284b10acd192e85bfe9dd496 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 15 Jan 2024 15:04:27 +0000 Subject: [PATCH 418/737] eckit::geo::Projection --- src/eckit/geo/projection/None.cc | 3 --- src/eckit/geo/projection/None.h | 13 ++++++++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index 47893d451..7739cc0dd 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -24,9 +24,6 @@ static ProjectionBuilder __projection3("equirectangular"); static ProjectionBuilder __projection4("plate-carree"); -None::None(const Spec&) {} - - Spec* None::spec() const { return new spec::Custom{}; } diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index e0c61b1a1..9049acefd 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -29,7 +29,7 @@ class None final : public Projection { // -- Constructors None() = default; - explicit None(const Spec&); + explicit None(const Spec&) {} // -- Destructor // None @@ -62,8 +62,15 @@ class None final : public Projection { // -- Overridden methods - Point fwd(const Point& p) const override { return p; } - Point inv(const Point& q) const override { return q; } + Point fwd(const Point& p) const override { + const auto& q = std::get(p); + return Point2{q.lon, q.lat}; + } + + Point inv(const Point& q) const override { + const auto& p = std::get(q); + return PointLonLat{p.X, p.Y}; + } // -- Class members // None From 1dace2e1999eba831111905e47856a4160ae2b6f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 15 Jan 2024 16:30:00 +0000 Subject: [PATCH 419/737] eckit::geo::util::mutex.h --- src/eckit/geo/CMakeLists.txt | 2 +- src/eckit/geo/Grid.cc | 19 +++++++++++------- src/eckit/geo/Grid.h | 2 -- src/eckit/geo/grid/unstructured/ORCA.cc | 11 +++++++++++ src/eckit/geo/spec/Generator.h | 26 ++++++++++++++++--------- src/eckit/geo/util/{Mutex.h => mutex.h} | 0 6 files changed, 41 insertions(+), 19 deletions(-) rename src/eckit/geo/util/{Mutex.h => mutex.h} (100%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 7df2d7701..85231402e 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -111,11 +111,11 @@ list(APPEND eckit_geo_srcs spec/Layered.h util.cc util.h - util/Mutex.h util/arange.cc util/gaussian_latitudes.cc util/linspace.cc util/monotonic_crop.cc + util/mutex.h util/reduced_classical_pl.cc util/reduced_octahedral_pl.cc util/regex.cc diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index c38c31c6c..70cbf84ee 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -20,14 +20,21 @@ #include "eckit/geo/etc/Grid.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/spec/Layered.h" +#include "eckit/geo/util/mutex.h" #include "eckit/log/Log.h" -#include "eckit/thread/AutoLock.h" -#include "eckit/thread/Mutex.h" namespace eckit::geo { +static util::recursive_mutex MUTEX; + + +class lock_type { + util::lock_guard lock_guard_{MUTEX}; +}; + + Grid::Grid(const Spec& spec) : bbox_(spec) {} @@ -113,7 +120,7 @@ GridFactory& GridFactory::instance() { const Grid* GridFactory::build_(const Spec& spec) const { - AutoLock lock(mutex_); + lock_type lock; std::unique_ptr cfg(generate_spec_(spec)); @@ -127,8 +134,7 @@ const Grid* GridFactory::build_(const Spec& spec) const { Spec* GridFactory::generate_spec_(const Spec& spec) const { - AutoLock lock(mutex_); - + lock_type lock; etc::Grid::instance(); auto* cfg = new spec::Layered(spec); @@ -168,8 +174,7 @@ Spec* GridFactory::generate_spec_(const Spec& spec) const { void GridFactory::list_(std::ostream& out) const { - AutoLock lock(mutex_); - + lock_type lock; etc::Grid::instance(); out << SpecByUID::instance() << std::endl; diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 01500fb89..8b0cf5415 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -208,8 +208,6 @@ struct GridFactory { Spec* generate_spec_(const Spec&) const; void list_(std::ostream&) const; - - mutable Mutex mutex_; }; diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index a5ff799a2..4f2250047 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -20,6 +20,7 @@ #include "eckit/geo/Spec.h" #include "eckit/geo/area/BoundingBox.h" #include "eckit/geo/iterator/Unstructured.h" +#include "eckit/geo/util/mutex.h" #include "eckit/io/Length.h" #include "eckit/log/Bytes.h" #include "eckit/log/Timer.h" @@ -58,6 +59,13 @@ std::string arrangement_to_string(ORCA::Arrangement a) { } +static util::recursive_mutex MUTEX; + + +class lock_type { + util::lock_guard lock_guard_{MUTEX}; +}; + } // namespace @@ -69,6 +77,9 @@ ORCA::ORCA(const Spec& spec) : dimensions_{-1, -1}, halo_{-1, -1, -1, -1}, pivot_{-1, -1} { + // control concurrent download/access + lock_type lock; + PathName path = spec.get_string("path", LibEcKitGeo::cacheDir() + "/eckit/geo/orca/" + uid_ + ".atlas"); #if eckit_HAVE_CURL // for eckit::URLHandle diff --git a/src/eckit/geo/spec/Generator.h b/src/eckit/geo/spec/Generator.h index ad0fa8edb..fabd5219d 100644 --- a/src/eckit/geo/spec/Generator.h +++ b/src/eckit/geo/spec/Generator.h @@ -14,13 +14,13 @@ #include #include +#include #include #include #include #include "eckit/exception/Exceptions.h" -#include "eckit/thread/AutoLock.h" -#include "eckit/thread/Mutex.h" +#include "eckit/geo/util/mutex.h" #include "eckit/utils/Regex.h" @@ -93,6 +93,14 @@ class GeneratorT { //------------------------------------------------------------------------------------------------------ +static util::recursive_mutex MUTEX; + +class lock_type { + util::lock_guard lock_guard_{MUTEX}; +}; + +//------------------------------------------------------------------------------------------------------ + template GeneratorT& GeneratorT::instance() { static GeneratorT obj; @@ -101,19 +109,19 @@ GeneratorT& GeneratorT::instance() { template bool GeneratorT::exists(const key_t& k) const { - AutoLock lock(mutex_); + lock_type lock; return store_.find(k) != store_.end(); } template bool GeneratorT::matches(const std::string& k) const { - AutoLock lock(mutex_); + lock_type lock; return std::any_of(store_.begin(), store_.end(), [&](const auto& p) { return Regex(p.first).match(k); }); } template void GeneratorT::regist(const key_t& k, generator_t* c) { - AutoLock lock(mutex_); + lock_type lock; if (exists(k)) { throw BadParameter("Configurator has already a builder for " + k, Here()); } @@ -123,7 +131,7 @@ void GeneratorT::regist(const key_t& k, generator_t* c) { template void GeneratorT::unregist(const key_t& k) { - AutoLock lock(mutex_); + lock_type lock; if (auto it = store_.find(k); it != store_.end()) { store_.erase(it); return; @@ -133,7 +141,7 @@ void GeneratorT::unregist(const key_t& k) { template const typename GeneratorT::generator_t& GeneratorT::get(const key_t& k) const { - AutoLock lock(mutex_); + lock_type lock; if (auto it = store_.find(k); it != store_.end()) { return *(it->second); } @@ -142,7 +150,7 @@ const typename GeneratorT::generator_t& GeneratorT::get(const key_t& k) co template const typename GeneratorT::generator_t& GeneratorT::match(const std::string& k) const { - AutoLock lock(mutex_); + lock_type lock; auto end = store_.cend(); auto i = end; @@ -164,7 +172,7 @@ const typename GeneratorT::generator_t& GeneratorT::match(const std::strin template void GeneratorT::print(std::ostream& os) const { - AutoLock lock(mutex_); + lock_type lock; os << "Configurator" << std::endl; int key_width = 0; diff --git a/src/eckit/geo/util/Mutex.h b/src/eckit/geo/util/mutex.h similarity index 100% rename from src/eckit/geo/util/Mutex.h rename to src/eckit/geo/util/mutex.h From a9cb083ecc59b48759a16aa9fa5dcbae46f1d3f1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 Jan 2024 09:09:26 +0000 Subject: [PATCH 420/737] eckit::geo::util::Cache --- src/eckit/geo/CMakeLists.txt | 4 +- src/eckit/geo/Cache.cc | 47 ------------ src/eckit/geo/Cache.h | 55 -------------- src/eckit/geo/util/Cache.cc | 45 +++++++++++ src/eckit/geo/util/Cache.h | 83 +++++++++++++++++++++ src/eckit/geo/util/reduced_classical_pl.cc | 10 +-- src/eckit/geo/util/reduced_octahedral_pl.cc | 12 ++- 7 files changed, 140 insertions(+), 116 deletions(-) delete mode 100644 src/eckit/geo/Cache.cc delete mode 100644 src/eckit/geo/Cache.h create mode 100644 src/eckit/geo/util/Cache.cc create mode 100644 src/eckit/geo/util/Cache.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 85231402e..a3143824a 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -8,8 +8,6 @@ install( list(APPEND eckit_geo_srcs ${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_config.h Area.h - Cache.cc - Cache.h CoordinateHelpers.cc CoordinateHelpers.h Domain.cc @@ -111,6 +109,8 @@ list(APPEND eckit_geo_srcs spec/Layered.h util.cc util.h + util/Cache.cc + util/Cache.h util/arange.cc util/gaussian_latitudes.cc util/linspace.cc diff --git a/src/eckit/geo/Cache.cc b/src/eckit/geo/Cache.cc deleted file mode 100644 index c04830fd4..000000000 --- a/src/eckit/geo/Cache.cc +++ /dev/null @@ -1,47 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/Cache.h" - - -#include -#include -#include - - -namespace eckit::geo::cache { - - -static std::map> __cache; - - -class ClassA { -public: - void functionA() const {} -}; - - -class ClassB { -public: - void functionB() const {} -}; - - -void test() { - __cache.insert({"a", std::make_unique>(ClassA())}); - __cache.insert({"b", std::make_unique>(ClassB())}); - - __cache["b"]->call(); -} - - -} // namespace eckit::geo::cache diff --git a/src/eckit/geo/Cache.h b/src/eckit/geo/Cache.h deleted file mode 100644 index 22481469b..000000000 --- a/src/eckit/geo/Cache.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (C) Copyright 1996- 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 -#include - - -namespace eckit::geo::cache { - - -class Cache { -public: - virtual ~Cache() = default; - virtual void call() = 0; -}; - - -class ClassA; -class ClassB; - - -template -class CacheableT : public Cache { - T obj; - -public: - CacheableT(T&& o) : - obj(std::move(o)) {} - - void call() override { - if constexpr (std::is_same::value) { - obj.functionA(); - return; - } - - if constexpr (std::is_same::value) { - obj.functionB(); - return; - } - - return; - } -}; - - -} // namespace eckit::geo::cache diff --git a/src/eckit/geo/util/Cache.cc b/src/eckit/geo/util/Cache.cc new file mode 100644 index 000000000..11f6bcbcd --- /dev/null +++ b/src/eckit/geo/util/Cache.cc @@ -0,0 +1,45 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/util/Cache.h" + +#include + + +namespace eckit::geo::util { + + +static recursive_mutex MUTEX; +static std::vector CACHES; + + +Cache::bytes_t Cache::total_footprint() { + lock_guard lock(MUTEX); + return std::accumulate(CACHES.begin(), CACHES.end(), static_cast(0), [](bytes_t sum, const auto* cache) { + return sum + cache->footprint(); + }); +} + + +void Cache::total_purge() { + lock_guard lock(MUTEX); + std::for_each(CACHES.begin(), CACHES.end(), [](auto* cache) { cache->purge(); }); +} + + +Cache::Cache() { + lock_guard lock(MUTEX); + CACHES.emplace_back(this); +} + + +} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/Cache.h b/src/eckit/geo/util/Cache.h new file mode 100644 index 000000000..2f377a495 --- /dev/null +++ b/src/eckit/geo/util/Cache.h @@ -0,0 +1,83 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/util/mutex.h" + + +namespace eckit::geo::util { + + +class Cache { +public: + using bytes_t = decltype(sizeof(int)); + + static bytes_t total_footprint(); + static void total_purge(); + +protected: + Cache(); + +private: + virtual bytes_t footprint() const = 0; + virtual void purge() = 0; +}; + + +template +class CacheT final : private Cache { +public: + using key_type = Key; + using value_type = Value; + + CacheT() : + mutex_(new recursive_mutex) { + ASSERT(mutex_ != nullptr); + } + + bool contains(const key_type& key) const { + lock_guard lock(*mutex_); + return container_.find(key) != container_.end(); + } + + const value_type& operator[](const key_type& key) const { + lock_guard lock(*mutex_); + return container_[key]; + } + + value_type& operator[](const key_type& key) { + lock_guard lock(*mutex_); + return container_[key]; + } + + bytes_t footprint() const final { + lock_guard lock(*mutex_); + return std::accumulate(container_.begin(), container_.end(), 0, [](bytes_t sum, const auto& kv) { + return sum + kv.second.size() * sizeof(typename value_type::value_type); + }); + } + + void purge() final { container_.clear(); } + +private: + mutable std::map container_; + + recursive_mutex* mutex_; +}; + + +} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/reduced_classical_pl.cc b/src/eckit/geo/util/reduced_classical_pl.cc index 952c5d97d..307f10cf1 100644 --- a/src/eckit/geo/util/reduced_classical_pl.cc +++ b/src/eckit/geo/util/reduced_classical_pl.cc @@ -15,6 +15,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/util.h" +#include "eckit/geo/util/Cache.h" namespace eckit::geo::util { @@ -1334,9 +1335,9 @@ static const std::map __classical_pls{ const pl_type& reduced_classical_pl(size_t N) { ASSERT(N > 0); - static std::map __cache; - if (auto pl = __cache.find(N); pl != __cache.end()) { - return pl->second; + static CacheT cache; + if (cache.contains(N)) { + return cache[N]; } auto pl_half = __classical_pls.find(N); @@ -1353,8 +1354,7 @@ const pl_type& reduced_classical_pl(size_t N) { pl[i] = pl[j] = *p++; } - __cache[N] = std::move(pl); - return __cache[N]; + return (cache[N] = std::move(pl)); } diff --git a/src/eckit/geo/util/reduced_octahedral_pl.cc b/src/eckit/geo/util/reduced_octahedral_pl.cc index a6223dd22..a3bdb1dd7 100644 --- a/src/eckit/geo/util/reduced_octahedral_pl.cc +++ b/src/eckit/geo/util/reduced_octahedral_pl.cc @@ -10,10 +10,9 @@ */ -#include - #include "eckit/exception/Exceptions.h" #include "eckit/geo/util.h" +#include "eckit/geo/util/Cache.h" namespace eckit::geo::util { @@ -22,9 +21,9 @@ namespace eckit::geo::util { const pl_type& reduced_octahedral_pl(size_t N) { ASSERT(N > 0); - static std::map __cache; - if (auto pl = __cache.find(N); pl != __cache.end()) { - return pl->second; + static CacheT cache; + if (cache.contains(N)) { + return cache[N]; } pl_type pl(N * 2); @@ -35,8 +34,7 @@ const pl_type& reduced_octahedral_pl(size_t N) { p += 4; } - __cache[N] = std::move(pl); - return __cache[N]; + return (cache[N] = std::move(pl)); } From 4b6b58c98fcf78a4419c260a38f501152615e5f4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 Jan 2024 10:27:16 +0000 Subject: [PATCH 421/737] eckit::geo::util::Cache --- tests/geo/CMakeLists.txt | 1 + tests/geo/cache.cc | 67 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 tests/geo/cache.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 47f8ee008..fdb0c747b 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -1,6 +1,7 @@ foreach(_test area_boundingbox area_polygon + cache coordinate_helpers figure_sphere great_circle diff --git a/tests/geo/cache.cc b/tests/geo/cache.cc new file mode 100644 index 000000000..fc11a6bcc --- /dev/null +++ b/tests/geo/cache.cc @@ -0,0 +1,67 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/util.h" +#include "eckit/geo/util/Cache.h" +#include "eckit/testing/Test.h" + + +namespace eckit::test { + + +using namespace geo::util; + + +CASE("Cache") { + using func_t = const geo::pl_type& (*)(size_t); + + struct test_t { + size_t N; + Cache::bytes_t footprint; + Cache::bytes_t footprint_acc; + } tests[] = { + {16, 256, 256}, + {24, 384, 640}, + {24, 384, 640}, // (repeated for a cache hit) + {32, 512, 1152}, + {16, 256, 1152}, // (repeated for another cache hit) + {48, 768, 1920}, + {64, 1024, 2944}, + }; + + + SECTION("reduced_classical_pl, reduced_octahedral_pl") { + for (func_t cacheable : {&reduced_classical_pl, &reduced_octahedral_pl}) { + for (const auto& test : tests) { + Cache::total_purge(); + (*cacheable)(test.N); + EXPECT_EQUAL(Cache::total_footprint(), test.footprint); + } + + Cache::total_purge(); + for (const auto& test : tests) { + (*cacheable)(test.N); + EXPECT_EQUAL(Cache::total_footprint(), test.footprint_acc); + } + } + + Cache::total_purge(); + } +} + + +} // namespace eckit::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From e781d2b327b2a5693f6d18c89008624966cad6b8 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 Jan 2024 10:30:40 +0000 Subject: [PATCH 422/737] eckit::geo::util::Cache --- tests/geo/cache.cc | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/tests/geo/cache.cc b/tests/geo/cache.cc index fc11a6bcc..92d87c968 100644 --- a/tests/geo/cache.cc +++ b/tests/geo/cache.cc @@ -10,8 +10,8 @@ */ -#include "eckit/geo/util.h" #include "eckit/geo/util/Cache.h" +#include "eckit/geo/util.h" #include "eckit/testing/Test.h" @@ -22,12 +22,10 @@ using namespace geo::util; CASE("Cache") { - using func_t = const geo::pl_type& (*)(size_t); - struct test_t { size_t N; - Cache::bytes_t footprint; - Cache::bytes_t footprint_acc; + Cache::bytes_t pl_footprint; + Cache::bytes_t pl_footprint_acc; } tests[] = { {16, 256, 256}, {24, 384, 640}, @@ -39,22 +37,41 @@ CASE("Cache") { }; + SECTION("separate caches") { + Cache::total_purge(); + EXPECT_EQUAL(0, Cache::total_footprint()); + + // add an entry to a cache + reduced_classical_pl(16); + auto foot = Cache::total_footprint(); + EXPECT(0 < foot); + + // add another distinct entry to a cache of same type + reduced_octahedral_pl(16); + EXPECT(foot < Cache::total_footprint()); + + Cache::total_purge(); + EXPECT_EQUAL(0, Cache::total_footprint()); + } + + SECTION("reduced_classical_pl, reduced_octahedral_pl") { - for (func_t cacheable : {&reduced_classical_pl, &reduced_octahedral_pl}) { + for (const geo::pl_type& (*cacheable)(size_t) : {&reduced_classical_pl, &reduced_octahedral_pl}) { for (const auto& test : tests) { Cache::total_purge(); (*cacheable)(test.N); - EXPECT_EQUAL(Cache::total_footprint(), test.footprint); + EXPECT_EQUAL(Cache::total_footprint(), test.pl_footprint); } Cache::total_purge(); for (const auto& test : tests) { (*cacheable)(test.N); - EXPECT_EQUAL(Cache::total_footprint(), test.footprint_acc); + EXPECT_EQUAL(Cache::total_footprint(), test.pl_footprint_acc); } } Cache::total_purge(); + EXPECT_EQUAL(0, Cache::total_footprint()); } } From c7654b4230835a57aa88aa3401bc8bb66520ce91 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 Jan 2024 15:13:20 +0000 Subject: [PATCH 423/737] eckit::geo::range::Regular --- src/eckit/geo/CMakeLists.txt | 2 - src/eckit/geo/grid/regular/RegularGaussian.cc | 4 +- src/eckit/geo/grid/regular/RegularLL.cc | 3 +- src/eckit/geo/range/Regular.cc | 16 +++- src/eckit/geo/range/Regular.h | 1 + src/eckit/geo/range/RegularLongitude.cc | 53 ------------ src/eckit/geo/range/RegularLongitude.h | 80 ------------------- 7 files changed, 19 insertions(+), 140 deletions(-) delete mode 100644 src/eckit/geo/range/RegularLongitude.cc delete mode 100644 src/eckit/geo/range/RegularLongitude.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index a3143824a..4a774bd08 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -100,8 +100,6 @@ list(APPEND eckit_geo_srcs range/Gaussian.h range/Regular.cc range/Regular.h - range/RegularLongitude.cc - range/RegularLongitude.h spec/Custom.cc spec/Custom.h spec/Generator.h diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index c573326f1..1d86ed4a0 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -14,7 +14,7 @@ #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/range/Gaussian.h" -#include "eckit/geo/range/RegularLongitude.h" +#include "eckit/geo/range/Regular.h" #include "eckit/geo/spec/Custom.h" #include "eckit/utils/Translator.h" @@ -32,7 +32,7 @@ RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : RegularGaussian::RegularGaussian(size_t N, size_t ni, const area::BoundingBox& bbox) : Regular(bbox), - x_(new range::RegularLongitude(ni, bbox.west, bbox.east)), + x_(new range::Regular(ni, bbox.west, bbox.east)), y_(new range::Gaussian(N, bbox.north, bbox.south)) { ASSERT(x_->size() > 0); ASSERT(y_->size() > 0); diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index 89de6bfe3..87aa2bde3 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -16,7 +16,6 @@ #include "eckit/geo/Increments.h" #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/range/Regular.h" -#include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util/regex.h" #include "eckit/types/Fraction.h" @@ -147,7 +146,7 @@ RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const RegularLL::RegularLL(Internal&& internal) : Regular(internal.bbox), internal_(internal), - range_longitude_(new range::RegularLongitude(internal_.ni, internal_.bbox.east, internal_.bbox.west)), + range_longitude_(new range::Regular(internal_.ni, internal_.bbox.east, internal_.bbox.west)), range_latitude_(new range::Regular(internal_.nj, internal_.bbox.north, internal_.bbox.south)) { ASSERT(size() > 0); ASSERT(ni() == range_longitude_->size()); diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc index 18b926c92..7873dc8ce 100644 --- a/src/eckit/geo/range/Regular.cc +++ b/src/eckit/geo/range/Regular.cc @@ -13,14 +13,28 @@ #include "eckit/geo/range/Regular.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geo/PointLonLat.h" #include "eckit/geo/util.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo::range { Regular::Regular(size_t n, double a, double b, double precision) : - Range(n), a_(a), b_(b), precision_(precision) {} + Range(n), a_(a), b_(b), precision_(precision) { + if (types::is_approximately_equal(a, b, util::eps)) { + endpoint_ = false; + } + else { + + b = PointLonLat::normalise_angle_to_minimum(b, a + util::eps); + auto inc = (b - a) / static_cast(n); + auto periodic = types::is_approximately_greater_or_equal(b - a + inc, 360.); + + endpoint_ = !periodic; + } +} const std::vector& Regular::values() const { diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h index 7c54d2436..ccbab5d77 100644 --- a/src/eckit/geo/range/Regular.h +++ b/src/eckit/geo/range/Regular.h @@ -58,6 +58,7 @@ class Regular final : public Range { const double a_; const double b_; const double precision_; + bool endpoint_; // -- Methods // None diff --git a/src/eckit/geo/range/RegularLongitude.cc b/src/eckit/geo/range/RegularLongitude.cc deleted file mode 100644 index 12e19e774..000000000 --- a/src/eckit/geo/range/RegularLongitude.cc +++ /dev/null @@ -1,53 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/range/RegularLongitude.h" - -#include "eckit/geo/PointLonLat.h" -#include "eckit/geo/util.h" -#include "eckit/types/FloatCompare.h" - - -namespace eckit::geo::range { - - -RegularLongitude::RegularLongitude(size_t n, double a, double b, double precision) : - Range(n), a_(a), b_(b), precision_(precision) { - if (types::is_approximately_equal(a, b, util::eps)) { - endpoint_ = false; - } - else { - - b = PointLonLat::normalise_angle_to_minimum(b, a + util::eps); - auto inc = (b - a) / static_cast(n); - auto periodic = types::is_approximately_greater_or_equal(b - a + inc, 360.); - - endpoint_ = !periodic; - } -} - - -const std::vector& RegularLongitude::values() const { - if (empty()) { - auto& v = const_cast&>(valuesVector()); - v = util::linspace(0., 360., size(), false); - - auto [from, to] = util::monotonic_crop(v, a_, b_, 1e-3); - v.erase(v.begin() + to, v.end()); - v.erase(v.begin(), v.begin() + from); - } - - return *this; -} - - -} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/RegularLongitude.h b/src/eckit/geo/range/RegularLongitude.h deleted file mode 100644 index a7147a0d6..000000000 --- a/src/eckit/geo/range/RegularLongitude.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Range.h" - - -namespace eckit::geo::range { - - -class RegularLongitude final : public Range { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit RegularLongitude(size_t n, double a, double b, double precision = 0.); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - const std::vector& values() const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - const double a_; - const double b_; - const double precision_; - bool endpoint_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::range From a0bbebb12457c88912dce73f0c6a2293656cb393 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 Jan 2024 15:56:35 +0000 Subject: [PATCH 424/737] eckit::geo::range::Gaussian --- src/eckit/geo/Range.cc | 5 ----- src/eckit/geo/Range.h | 19 ++++--------------- src/eckit/geo/range/Gaussian.cc | 13 ++++--------- src/eckit/geo/range/Gaussian.h | 1 + src/eckit/geo/range/Regular.cc | 11 +++++------ src/eckit/geo/range/Regular.h | 1 + 6 files changed, 15 insertions(+), 35 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index e5b03e328..66381d9d5 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -13,16 +13,11 @@ #include "eckit/geo/Range.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Spec.h" namespace eckit::geo { -Range::Range(const Spec& spec) : - Range(spec.get_unsigned("n", 0)) {} - - Range::Range(size_t n) : n_(n) { ASSERT(n > 0); diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index bcb0bdb95..da88071f9 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -16,18 +16,9 @@ namespace eckit::geo { -class Spec; -} -namespace eckit::geo { - - -class Range : protected std::vector { -protected: - // -- Types - using P = vector; - +class Range { public: // -- Types // None @@ -54,9 +45,9 @@ class Range : protected std::vector { // -- Methods - size_t size() const { return empty() ? n_ : P::size(); } + size_t size() const { return n_; } - virtual const P& values() const = 0; + virtual const std::vector& values() const = 0; // -- Overridden methods // None @@ -70,15 +61,13 @@ class Range : protected std::vector { protected: // -- Constructors - explicit Range(const Spec&); explicit Range(size_t n); // -- Members // None // -- Methods - - const P& valuesVector() const { return *this; } + // None // -- Overridden methods // None diff --git a/src/eckit/geo/range/Gaussian.cc b/src/eckit/geo/range/Gaussian.cc index 7e96fdc43..0e43dfcfd 100644 --- a/src/eckit/geo/range/Gaussian.cc +++ b/src/eckit/geo/range/Gaussian.cc @@ -30,25 +30,20 @@ Gaussian::Gaussian(size_t N, double a, double b, double precision) : // pre-calculate on cropping auto [min, max] = std::minmax(a_, b_); if (!types::is_approximately_equal(min, -90., eps_) || !types::is_approximately_equal(max, 90., eps_)) { - auto& v = const_cast&>(values()); + values_ = util::gaussian_latitudes(N_, a_ < b_); + auto& v = values_; auto [from, to] = util::monotonic_crop(v, min, max, precision); v.erase(v.begin() + to, v.end()); v.erase(v.begin(), v.begin() + from); - ASSERT(!empty()); + ASSERT(!v.empty()); } } const std::vector& Gaussian::values() const { - if (empty()) { - const_cast&>(valuesVector()) = util::gaussian_latitudes(N_, a_ < b_); - ASSERT(!empty()); - ASSERT(size() == 2 * N_); - } - - return *this; + return values_.empty() ? util::gaussian_latitudes(N_, a_ < b_) : values_; } diff --git a/src/eckit/geo/range/Gaussian.h b/src/eckit/geo/range/Gaussian.h index 8a4fd6001..96a430c87 100644 --- a/src/eckit/geo/range/Gaussian.h +++ b/src/eckit/geo/range/Gaussian.h @@ -63,6 +63,7 @@ class Gaussian final : public Range { const double a_; const double b_; const double eps_; + std::vector values_; // -- Methods // None diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc index 7873dc8ce..6c1eb800d 100644 --- a/src/eckit/geo/range/Regular.cc +++ b/src/eckit/geo/range/Regular.cc @@ -27,7 +27,6 @@ Regular::Regular(size_t n, double a, double b, double precision) : endpoint_ = false; } else { - b = PointLonLat::normalise_angle_to_minimum(b, a + util::eps); auto inc = (b - a) / static_cast(n); auto periodic = types::is_approximately_greater_or_equal(b - a + inc, 360.); @@ -38,18 +37,18 @@ Regular::Regular(size_t n, double a, double b, double precision) : const std::vector& Regular::values() const { - if (empty()) { - auto& v = const_cast&>(valuesVector()); - v = util::linspace(0., 360., size(), false); + if (values_.empty()) { + auto& v = const_cast&>(values_); + v = util::linspace(0., 360., Range::size(), false); auto [from, to] = util::monotonic_crop(v, a_, b_, precision_); v.erase(v.begin() + to, v.end()); v.erase(v.begin(), v.begin() + from); - ASSERT(!empty()); + ASSERT(!v.empty()); } - return *this; + return values_; } diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h index ccbab5d77..cc80ed2b5 100644 --- a/src/eckit/geo/range/Regular.h +++ b/src/eckit/geo/range/Regular.h @@ -59,6 +59,7 @@ class Regular final : public Range { const double b_; const double precision_; bool endpoint_; + std::vector values_; // -- Methods // None From 3ea6b40384f8ce4393796563180cf686e1bc64ba Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 Jan 2024 15:56:52 +0000 Subject: [PATCH 425/737] eckit::geo::range::Gaussian --- src/eckit/geo/util.h | 2 +- src/eckit/geo/util/gaussian_latitudes.cc | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index 83756dc8b..5dde9acc4 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -55,7 +55,7 @@ pl_type pl_convert(const pl_type&); std::vector arange(double start, double stop, double step); -std::vector gaussian_latitudes(size_t N, bool increasing); +const std::vector& gaussian_latitudes(size_t N, bool increasing); std::vector linspace(double start, double stop, size_t num, bool endpoint); diff --git a/src/eckit/geo/util/gaussian_latitudes.cc b/src/eckit/geo/util/gaussian_latitudes.cc index baa8d51df..e46ebb7e2 100644 --- a/src/eckit/geo/util/gaussian_latitudes.cc +++ b/src/eckit/geo/util/gaussian_latitudes.cc @@ -13,15 +13,27 @@ #include #include #include +#include #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/util/Cache.h" namespace eckit::geo::util { -std::vector gaussian_latitudes(size_t N, bool increasing) { +const std::vector& gaussian_latitudes(size_t N, bool increasing) { + ASSERT(N > 0); + + using cache_t = CacheT, std::vector>; + const cache_t::key_type key{N, increasing}; + + static cache_t cache; + if (cache.contains(key)) { + return cache[key]; + } + std::vector lats(2 * N); @@ -92,7 +104,7 @@ std::vector gaussian_latitudes(size_t N, bool increasing) { } - return lats; + return (cache[key] = std::move(lats)); } From bd84dd97077fe5b92bf4694329ee25da56e89229 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 Jan 2024 15:57:03 +0000 Subject: [PATCH 426/737] eckit::geo::range::Gaussian --- tests/geo/cache.cc | 62 +++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/tests/geo/cache.cc b/tests/geo/cache.cc index 92d87c968..f4b57129c 100644 --- a/tests/geo/cache.cc +++ b/tests/geo/cache.cc @@ -21,40 +21,48 @@ namespace eckit::test { using namespace geo::util; -CASE("Cache") { +CASE("eckit::geo::util") { struct test_t { size_t N; + bool increasing; Cache::bytes_t pl_footprint; Cache::bytes_t pl_footprint_acc; + Cache::bytes_t gl_footprint; + Cache::bytes_t gl_footprint_acc; } tests[] = { - {16, 256, 256}, - {24, 384, 640}, - {24, 384, 640}, // (repeated for a cache hit) - {32, 512, 1152}, - {16, 256, 1152}, // (repeated for another cache hit) - {48, 768, 1920}, - {64, 1024, 2944}, + {16, false, 256, 256, 256, 256}, + {24, false, 384, 640, 384, 640}, + {24, false, 384, 640, 384, 640}, // (repeated for a cache hit) + {32, false, 512, 1152, 512, 1152}, + {16, false, 256, 1152, 256, 1152}, // (repeated for another cache hit) + {48, false, 768, 1920, 768, 1920}, + {16, true, 256, 1920, 256, 2176}, // (repeated except for 'increasing') + {24, true, 384, 1920, 384, 2560}, // ... + {24, true, 384, 1920, 384, 2560}, + {32, true, 512, 1920, 512, 3072}, + {16, true, 256, 1920, 256, 3072}, + {48, true, 768, 1920, 768, 3840}, }; - SECTION("separate caches") { - Cache::total_purge(); - EXPECT_EQUAL(0, Cache::total_footprint()); + Cache::total_purge(); + EXPECT_EQUAL(0, Cache::total_footprint()); + - // add an entry to a cache + SECTION("separate caches") { reduced_classical_pl(16); auto foot = Cache::total_footprint(); EXPECT(0 < foot); - // add another distinct entry to a cache of same type reduced_octahedral_pl(16); EXPECT(foot < Cache::total_footprint()); - - Cache::total_purge(); - EXPECT_EQUAL(0, Cache::total_footprint()); } + Cache::total_purge(); + EXPECT_EQUAL(0, Cache::total_footprint()); + + SECTION("reduced_classical_pl, reduced_octahedral_pl") { for (const geo::pl_type& (*cacheable)(size_t) : {&reduced_classical_pl, &reduced_octahedral_pl}) { for (const auto& test : tests) { @@ -69,10 +77,30 @@ CASE("Cache") { EXPECT_EQUAL(Cache::total_footprint(), test.pl_footprint_acc); } } + } + + + Cache::total_purge(); + EXPECT_EQUAL(0, Cache::total_footprint()); + + + SECTION("gaussian_latitudes") { + for (const auto& test : tests) { + Cache::total_purge(); + gaussian_latitudes(test.N, test.increasing); + EXPECT_EQUAL(Cache::total_footprint(), test.gl_footprint); + } Cache::total_purge(); - EXPECT_EQUAL(0, Cache::total_footprint()); + for (const auto& test : tests) { + gaussian_latitudes(test.N, test.increasing); + EXPECT_EQUAL(Cache::total_footprint(), test.gl_footprint_acc); + } } + + + Cache::total_purge(); + EXPECT_EQUAL(0, Cache::total_footprint()); } From 7ed858c84778d4a41bd91ac344500ea40a3f40e2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 Jan 2024 16:20:21 +0000 Subject: [PATCH 427/737] eckit::geo::Range --- src/eckit/geo/Domain.cc | 4 +-- src/eckit/geo/GreatCircle.cc | 46 +++++++++++++-------------- src/eckit/geo/Range.cc | 5 +-- src/eckit/geo/Range.h | 6 +++- src/eckit/geo/area/BoundingBox.cc | 4 +-- src/eckit/geo/grid/reduced/HEALPix.cc | 2 +- src/eckit/geo/projection/Mercator.cc | 16 +++++----- src/eckit/geo/projection/Rotation.cc | 10 +++--- src/eckit/geo/range/Gaussian.cc | 9 +++--- src/eckit/geo/range/Gaussian.h | 7 ++-- src/eckit/geo/range/Regular.cc | 10 +++--- src/eckit/geo/range/Regular.h | 3 +- src/eckit/geo/util.h | 7 ++-- 13 files changed, 65 insertions(+), 64 deletions(-) diff --git a/src/eckit/geo/Domain.cc b/src/eckit/geo/Domain.cc index bf4af3580..bb04ed914 100644 --- a/src/eckit/geo/Domain.cc +++ b/src/eckit/geo/Domain.cc @@ -91,8 +91,8 @@ double Domain::area(double radius) const { double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); ASSERT(0. <= lonf && lonf <= 1.); - const auto sn = std::sin(north_ * util::degree_to_radian); - const auto ss = std::sin(south_ * util::degree_to_radian); + const auto sn = std::sin(north_ * util::DEGREE_TO_RADIAN); + const auto ss = std::sin(south_ * util::DEGREE_TO_RADIAN); double latf = 0.5 * (sn - ss); ASSERT(0. <= latf && latf <= 1.); diff --git a/src/eckit/geo/GreatCircle.cc b/src/eckit/geo/GreatCircle.cc index 3057d5010..bb615fec0 100644 --- a/src/eckit/geo/GreatCircle.cc +++ b/src/eckit/geo/GreatCircle.cc @@ -58,15 +58,15 @@ std::vector GreatCircle::latitude(double lon) const { return {}; } - const double lat1 = util::degree_to_radian * A_.lat; - const double lat2 = util::degree_to_radian * B_.lat; - const double lambda1p = util::degree_to_radian * (lon - A_.lon); - const double lambda2p = util::degree_to_radian * (lon - B_.lon); - const double lambda = util::degree_to_radian * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, -180.); + const double lat1 = util::DEGREE_TO_RADIAN * A_.lat; + const double lat2 = util::DEGREE_TO_RADIAN * B_.lat; + const double lambda1p = util::DEGREE_TO_RADIAN * (lon - A_.lon); + const double lambda2p = util::DEGREE_TO_RADIAN * (lon - B_.lon); + const double lambda = util::DEGREE_TO_RADIAN * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, -180.); double lat = std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); - return {util::radian_to_degree * lat}; + return {util::RADIAN_TO_DEGREE * lat}; } std::vector GreatCircle::longitude(double lat) const { @@ -79,11 +79,11 @@ std::vector GreatCircle::longitude(double lat) const { return {lon, lon + 180.}; } - const double lon12 = util::degree_to_radian * PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); - const double lon1 = util::degree_to_radian * A_.lon; - const double lat1 = util::degree_to_radian * A_.lat; - const double lat2 = util::degree_to_radian * B_.lat; - const double lat3 = util::degree_to_radian * lat; + const double lon12 = util::DEGREE_TO_RADIAN * PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); + const double lon1 = util::DEGREE_TO_RADIAN * A_.lon; + const double lat1 = util::DEGREE_TO_RADIAN * A_.lat; + const double lat2 = util::DEGREE_TO_RADIAN * B_.lat; + const double lat3 = util::DEGREE_TO_RADIAN * lat; const double X = std::sin(lat1) * std::cos(lat2) * std::sin(lon12); const double Y = std::sin(lat1) * std::cos(lat2) * std::cos(lon12) - std::cos(lat1) * std::sin(lat2); @@ -96,16 +96,16 @@ std::vector GreatCircle::longitude(double lat) const { const double C = std::cos(lat1) * std::cos(lat2) * std::tan(lat3) * std::sin(lon12) / std::sqrt(X * X + Y * Y); if (is_approximately_equal(C, -1.)) { - return {util::radian_to_degree * (lon0 + M_PI)}; + return {util::RADIAN_TO_DEGREE * (lon0 + M_PI)}; } if (is_approximately_equal(C, 1.)) { - return {util::radian_to_degree * lon0}; + return {util::RADIAN_TO_DEGREE * lon0}; } if (-1 < C && C < 1) { const double dlon = std::acos(C); - return {util::radian_to_degree * (lon0 - dlon + 2 * M_PI), util::radian_to_degree * (lon0 + dlon)}; + return {util::RADIAN_TO_DEGREE * (lon0 - dlon + 2 * M_PI), util::RADIAN_TO_DEGREE * (lon0 + dlon)}; } return {}; @@ -116,15 +116,15 @@ bool GreatCircle::crossesPoles() const { } std::pair GreatCircle::calculate_course(const PointLonLat& A, const PointLonLat& B) { - const auto sdl = std::sin(util::degree_to_radian * (B.lon - A.lon)); - const auto cdl = std::cos(util::degree_to_radian * (B.lon - A.lon)); - const auto spA = std::sin(util::degree_to_radian * A.lat); - const auto cpA = std::cos(util::degree_to_radian * A.lat); - const auto spB = std::sin(util::degree_to_radian * B.lat); - const auto cpB = std::cos(util::degree_to_radian * B.lat); - - const auto alpha1 = util::radian_to_degree * std::atan2(cpB * sdl, cpA * spB - spA * cpB * cdl); - const auto alpha2 = util::radian_to_degree * std::atan2(cpA * sdl, -cpB * spA + spB * cpA * cdl); + const auto sdl = std::sin(util::DEGREE_TO_RADIAN * (B.lon - A.lon)); + const auto cdl = std::cos(util::DEGREE_TO_RADIAN * (B.lon - A.lon)); + const auto spA = std::sin(util::DEGREE_TO_RADIAN * A.lat); + const auto cpA = std::cos(util::DEGREE_TO_RADIAN * A.lat); + const auto spB = std::sin(util::DEGREE_TO_RADIAN * B.lat); + const auto cpB = std::cos(util::DEGREE_TO_RADIAN * B.lat); + + const auto alpha1 = util::RADIAN_TO_DEGREE * std::atan2(cpB * sdl, cpA * spB - spA * cpB * cdl); + const auto alpha2 = util::RADIAN_TO_DEGREE * std::atan2(cpA * sdl, -cpB * spA + spB * cpA * cdl); return {alpha1, alpha2}; } diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 66381d9d5..a485774ff 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -18,9 +18,10 @@ namespace eckit::geo { -Range::Range(size_t n) : - n_(n) { +Range::Range(size_t n, double eps) : + n_(n), eps_(eps) { ASSERT(n > 0); + ASSERT(eps_ >= 0); } diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index da88071f9..52ba49364 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -14,6 +14,8 @@ #include +#include "eckit/geo/util.h" + namespace eckit::geo { @@ -46,6 +48,7 @@ class Range { // -- Methods size_t size() const { return n_; } + double eps() const { return eps_; } virtual const std::vector& values() const = 0; @@ -61,7 +64,7 @@ class Range { protected: // -- Constructors - explicit Range(size_t n); + explicit Range(size_t n, double eps = util::EPS); // -- Members // None @@ -82,6 +85,7 @@ class Range { // -- Members const size_t n_; + const double eps_; // -- Methods // None diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index ae3419945..a21d7016b 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -156,8 +156,8 @@ double BoundingBox::area(double radius) const { double lonf = isPeriodicWestEast() ? 1. : ((east - west) / 360.); ASSERT(0. <= lonf && lonf <= 1.); - const auto sn = std::sin(north * util::degree_to_radian); - const auto ss = std::sin(south * util::degree_to_radian); + const auto sn = std::sin(north * util::DEGREE_TO_RADIAN); + const auto ss = std::sin(south * util::DEGREE_TO_RADIAN); double latf = 0.5 * (sn - ss); ASSERT(0. <= latf && latf <= 1.); diff --git a/src/eckit/geo/grid/reduced/HEALPix.cc b/src/eckit/geo/grid/reduced/HEALPix.cc index e2a4ebf48..fefcab6f0 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.cc +++ b/src/eckit/geo/grid/reduced/HEALPix.cc @@ -338,7 +338,7 @@ const std::vector& HEALPix::latitudes() const { const auto f = ring < N_ ? 1. - static_cast(ring * ring) / (3 * static_cast(N_ * N_)) : 4. / 3. - 2 * static_cast(ring) / (3 * static_cast(N_)); - *i = 90. - util::radian_to_degree * std::acos(f); + *i = 90. - util::RADIAN_TO_DEGREE * std::acos(f); *j = -*i; } *i = 0.; diff --git a/src/eckit/geo/projection/Mercator.cc b/src/eckit/geo/projection/Mercator.cc index 676ac1842..3ccca7f06 100644 --- a/src/eckit/geo/projection/Mercator.cc +++ b/src/eckit/geo/projection/Mercator.cc @@ -41,11 +41,11 @@ Mercator::Mercator(double meridian, double parallel, Figure* figure, PointLonLat "Mercator: projection cannot be calculated at the poles"); e_ = figure_->eccentricity(); - lam0_ = util::degree_to_radian * meridian_; + lam0_ = util::DEGREE_TO_RADIAN * meridian_; - auto phi0 = util::degree_to_radian * parallel_; - auto lam1 = util::degree_to_radian * first.lon; - auto phi1 = util::degree_to_radian * first.lat; + auto phi0 = util::DEGREE_TO_RADIAN * parallel_; + auto lam1 = util::DEGREE_TO_RADIAN * first.lon; + auto phi1 = util::DEGREE_TO_RADIAN * first.lat; m_ = figure_->a() * std::cos(phi0) / (std::sqrt(1. - e_ * e_ * std::sin(phi0) * std::sin(phi0))); ASSERT(!types::is_approximately_equal(m_, 0.)); @@ -83,8 +83,8 @@ double Mercator::calculate_phi(double t) const { Point2 Mercator::fwd(const PointLonLat& p) const { - auto phi = util::degree_to_radian * p.lat; - auto lam = util::degree_to_radian * p.lon; + auto phi = util::DEGREE_TO_RADIAN * p.lat; + auto lam = util::DEGREE_TO_RADIAN * p.lon; return {x0_ + m_ * (lam - lam0_), y0_ - m_ * std::log(std::tan(M_PI_4 - 0.5 * phi) / @@ -93,8 +93,8 @@ Point2 Mercator::fwd(const PointLonLat& p) const { PointLonLat Mercator::inv(const Point2& q) const { - return PointLonLat::make(util::radian_to_degree * (lam0_ + (q.X - x0_) * w_), - util::radian_to_degree * calculate_phi(std::exp(-(q.Y - y0_) * w_))); + return PointLonLat::make(util::RADIAN_TO_DEGREE * (lam0_ + (q.X - x0_) * w_), + util::RADIAN_TO_DEGREE * calculate_phi(std::exp(-(q.Y - y0_) * w_))); } diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index a75782bae..bd2c6c6b3 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -67,17 +67,17 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : const double angle_; }; - const auto alpha = util::degree_to_radian * angle; - const auto theta = util::degree_to_radian * -(south_pole_lat + 90.); - const auto phi = util::degree_to_radian * -south_pole_lon; + const auto alpha = util::DEGREE_TO_RADIAN * angle; + const auto theta = util::DEGREE_TO_RADIAN * -(south_pole_lat + 90.); + const auto phi = util::DEGREE_TO_RADIAN * -south_pole_lon; const auto ca = std::cos(alpha); const auto ct = std::cos(theta); const auto cp = std::cos(phi); - if (types::is_approximately_equal(ct, 1., util::eps)) { + if (types::is_approximately_equal(ct, 1., util::EPS)) { angle = PointLonLat::normalise_angle_to_minimum(angle - south_pole_lon, -180.); - rotated_ = !types::is_approximately_equal(angle, 0., util::eps); + rotated_ = !types::is_approximately_equal(angle, 0., util::EPS); fwd_.reset(rotated_ ? static_cast(new RotationAngle(-angle)) : new NonRotated); inv_.reset(rotated_ ? static_cast(new RotationAngle(angle)) : new NonRotated); diff --git a/src/eckit/geo/range/Gaussian.cc b/src/eckit/geo/range/Gaussian.cc index 0e43dfcfd..a46d85449 100644 --- a/src/eckit/geo/range/Gaussian.cc +++ b/src/eckit/geo/range/Gaussian.cc @@ -22,18 +22,17 @@ namespace eckit::geo::range { -Gaussian::Gaussian(size_t N, double a, double b, double precision) : - Range(2 * N), N_(N), a_(a), b_(b), eps_(precision) { +Gaussian::Gaussian(size_t N, double a, double b, double _eps) : + Range(2 * N, _eps), N_(N), a_(a), b_(b) { ASSERT(N > 0); - ASSERT(eps_ >= 0.); // pre-calculate on cropping auto [min, max] = std::minmax(a_, b_); - if (!types::is_approximately_equal(min, -90., eps_) || !types::is_approximately_equal(max, 90., eps_)) { + if (!types::is_approximately_equal(min, -90., eps()) || !types::is_approximately_equal(max, 90., eps())) { values_ = util::gaussian_latitudes(N_, a_ < b_); auto& v = values_; - auto [from, to] = util::monotonic_crop(v, min, max, precision); + auto [from, to] = util::monotonic_crop(v, min, max, eps()); v.erase(v.begin() + to, v.end()); v.erase(v.begin(), v.begin() + from); diff --git a/src/eckit/geo/range/Gaussian.h b/src/eckit/geo/range/Gaussian.h index 96a430c87..8f0394c1b 100644 --- a/src/eckit/geo/range/Gaussian.h +++ b/src/eckit/geo/range/Gaussian.h @@ -28,10 +28,10 @@ class Gaussian final : public Range { // -- Constructors - explicit Gaussian(size_t N, double precision = 0.) : - Gaussian(N, 90., -90., precision) {} + explicit Gaussian(size_t N, double eps = 0.) : + Gaussian(N, 90., -90., eps) {} - Gaussian(size_t N, double a, double b, double precision = 0.); + Gaussian(size_t N, double crop_a, double crop_b, double eps = 0.); // -- Destructor // None @@ -62,7 +62,6 @@ class Gaussian final : public Range { const size_t N_; const double a_; const double b_; - const double eps_; std::vector values_; // -- Methods diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc index 6c1eb800d..ce7c0265b 100644 --- a/src/eckit/geo/range/Regular.cc +++ b/src/eckit/geo/range/Regular.cc @@ -21,13 +21,13 @@ namespace eckit::geo::range { -Regular::Regular(size_t n, double a, double b, double precision) : - Range(n), a_(a), b_(b), precision_(precision) { - if (types::is_approximately_equal(a, b, util::eps)) { +Regular::Regular(size_t n, double a, double b, double _eps) : + Range(n, _eps), a_(a), b_(b) { + if (types::is_approximately_equal(a, b, eps())) { endpoint_ = false; } else { - b = PointLonLat::normalise_angle_to_minimum(b, a + util::eps); + b = PointLonLat::normalise_angle_to_minimum(b, a + eps()); auto inc = (b - a) / static_cast(n); auto periodic = types::is_approximately_greater_or_equal(b - a + inc, 360.); @@ -41,7 +41,7 @@ const std::vector& Regular::values() const { auto& v = const_cast&>(values_); v = util::linspace(0., 360., Range::size(), false); - auto [from, to] = util::monotonic_crop(v, a_, b_, precision_); + auto [from, to] = util::monotonic_crop(v, a_, b_, eps()); v.erase(v.begin() + to, v.end()); v.erase(v.begin(), v.begin() + from); diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h index cc80ed2b5..83c7ea3c5 100644 --- a/src/eckit/geo/range/Regular.h +++ b/src/eckit/geo/range/Regular.h @@ -28,7 +28,7 @@ class Regular final : public Range { // -- Constructors - explicit Regular(size_t n, double a, double b, double precision = 0.); + explicit Regular(size_t n, double a, double b, double eps = 0.); // -- Destructor // None @@ -57,7 +57,6 @@ class Regular final : public Range { const double a_; const double b_; - const double precision_; bool endpoint_; std::vector values_; diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index 5dde9acc4..11ee38371 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -30,10 +30,9 @@ using pl_type = std::vector; namespace util { -constexpr double degree_to_radian = M_PI / 180.; -constexpr double radian_to_degree = M_1_PI * 180.; - -constexpr double eps = 1e-12; +constexpr double DEGREE_TO_RADIAN = M_PI / 180.; +constexpr double RADIAN_TO_DEGREE = M_1_PI * 180.; +constexpr double EPS = 1e-12; template From 9c45eda6e3a33408559effd4eda484cc305cde3c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 Jan 2024 16:56:20 +0000 Subject: [PATCH 428/737] eckit::geo --- src/eckit/geo/Point3.h | 6 +++--- src/eckit/geo/figure/OblateSpheroid.h | 4 ++-- src/eckit/geo/figure/Sphere.h | 4 ++-- src/eckit/geo/grid/Reduced.h | 3 +-- src/eckit/geo/grid/Regular.h | 3 +-- src/eckit/geo/grid/Unstructured.h | 3 +-- src/eckit/geo/grid/unstructured/ORCA.cc | 2 +- tests/geo/kdtree.cc | 4 ++-- 8 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/eckit/geo/Point3.h b/src/eckit/geo/Point3.h index 21bf5f375..d80887a95 100644 --- a/src/eckit/geo/Point3.h +++ b/src/eckit/geo/Point3.h @@ -79,9 +79,9 @@ class Point3 : public KPoint<3> { } static Point3 cross(const Point3& p1, const Point3& p2) { - return Point3(p1[YY] * p2[ZZ] - p1[ZZ] * p2[YY], - p1[ZZ] * p2[XX] - p1[XX] * p2[ZZ], - p1[XX] * p2[YY] - p1[YY] * p2[XX]); + return {p1[YY] * p2[ZZ] - p1[ZZ] * p2[YY], + p1[ZZ] * p2[XX] - p1[XX] * p2[ZZ], + p1[XX] * p2[YY] - p1[YY] * p2[XX]}; } }; diff --git a/src/eckit/geo/figure/OblateSpheroid.h b/src/eckit/geo/figure/OblateSpheroid.h index d9f66626b..67be8f4fc 100644 --- a/src/eckit/geo/figure/OblateSpheroid.h +++ b/src/eckit/geo/figure/OblateSpheroid.h @@ -28,8 +28,8 @@ class OblateSpheroid final : public Figure { // -- Constructors - OblateSpheroid(double R, double b); - OblateSpheroid(const Spec&); + OblateSpheroid(double a, double b); + explicit OblateSpheroid(const Spec&); // -- Destructor // None diff --git a/src/eckit/geo/figure/Sphere.h b/src/eckit/geo/figure/Sphere.h index 9093f3d8d..fee30bfb6 100644 --- a/src/eckit/geo/figure/Sphere.h +++ b/src/eckit/geo/figure/Sphere.h @@ -28,8 +28,8 @@ class Sphere final : public Figure { // -- Constructors - Sphere(double R); - Sphere(const Spec&); + explicit Sphere(double R); + explicit Sphere(const Spec&); // -- Destructor // None diff --git a/src/eckit/geo/grid/Reduced.h b/src/eckit/geo/grid/Reduced.h index d153e8d4b..fbc507a39 100644 --- a/src/eckit/geo/grid/Reduced.h +++ b/src/eckit/geo/grid/Reduced.h @@ -35,8 +35,7 @@ class Reduced : public Grid { // None // -- Destructor - - ~Reduced() override = default; + // None // -- Convertors // None diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index f12a7fb1a..f4a527f2c 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -35,8 +35,7 @@ class Regular : public Grid { // None // -- Destructor - - ~Regular() override = default; + // None // -- Convertors // None diff --git a/src/eckit/geo/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h index 73ca1c6f7..7326cf4e7 100644 --- a/src/eckit/geo/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -35,8 +35,7 @@ class Unstructured : public Grid { // None // -- Destructor - - ~Unstructured() override = default; + // None // -- Convertors // None diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index 4f2250047..34277da83 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -59,7 +59,7 @@ std::string arrangement_to_string(ORCA::Arrangement a) { } -static util::recursive_mutex MUTEX; +util::recursive_mutex MUTEX; class lock_type { diff --git a/tests/geo/kdtree.cc b/tests/geo/kdtree.cc index 709dbb869..6e3098450 100644 --- a/tests/geo/kdtree.cc +++ b/tests/geo/kdtree.cc @@ -258,7 +258,7 @@ CASE("test_kdtree_mapped") { } Tree kd(path, points.size(), 0); - EXPECT_EQUAL(kd.size(), 0); + EXPECT(kd.empty()); kd.build(points); @@ -290,7 +290,7 @@ CASE("test_kdtree_iterate_empty") { count++; } EXPECT_EQUAL(count, 0); - EXPECT_EQUAL(kd.size(), 0); + EXPECT(kd.empty()); } //---------------------------------------------------------------------------------------------------------------------- From e35316445304493dfea56da0cb96ea62d3d269c9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 Jan 2024 23:45:54 +0000 Subject: [PATCH 429/737] eckit::geo::util::Cache --- src/eckit/geo/util/Cache.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/util/Cache.h b/src/eckit/geo/util/Cache.h index 2f377a495..d62681596 100644 --- a/src/eckit/geo/util/Cache.h +++ b/src/eckit/geo/util/Cache.h @@ -40,6 +40,19 @@ class Cache { template class CacheT final : private Cache { +private: + template + using footprint_t = decltype(std::declval().footprint()); + + template > + struct has_footprint : std::false_type {}; + + template + struct has_footprint>> : std::true_type {}; + + template + static inline constexpr bool has_footprint_v = has_footprint::value; + public: using key_type = Key; using value_type = Value; @@ -67,7 +80,12 @@ class CacheT final : private Cache { bytes_t footprint() const final { lock_guard lock(*mutex_); return std::accumulate(container_.begin(), container_.end(), 0, [](bytes_t sum, const auto& kv) { - return sum + kv.second.size() * sizeof(typename value_type::value_type); + if constexpr (has_footprint_v) { + return sum + kv.second.footprint(); + } + else { + return sum + kv.second.size() * sizeof(typename value_type::value_type); + } }); } From e036892371da4a4b32f49c64bc5a729cf6a8065b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 16 Jan 2024 23:54:25 +0000 Subject: [PATCH 430/737] eckit::geo::Grid --- src/eckit/geo/grid/unstructured/ORCA.cc | 81 ++++++++++++++++++------- src/eckit/geo/grid/unstructured/ORCA.h | 45 ++++++++------ 2 files changed, 87 insertions(+), 39 deletions(-) diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index 34277da83..62f88e9a4 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -20,6 +20,7 @@ #include "eckit/geo/Spec.h" #include "eckit/geo/area/BoundingBox.h" #include "eckit/geo/iterator/Unstructured.h" +#include "eckit/geo/util/Cache.h" #include "eckit/geo/util/mutex.h" #include "eckit/io/Length.h" #include "eckit/log/Bytes.h" @@ -66,22 +67,14 @@ class lock_type { util::lock_guard lock_guard_{MUTEX}; }; -} // namespace +util::CacheT CACHE; -ORCA::ORCA(const Spec& spec) : - Unstructured(spec), - name_(spec.get_string("orca_name")), - uid_(spec.get_string("orca_uid")), - arrangement_(arrangement_from_string(spec.get_string("orca_arrangement"))), - dimensions_{-1, -1}, - halo_{-1, -1, -1, -1}, - pivot_{-1, -1} { + +PathName orca_path(const PathName& path, const std::string& url) { // control concurrent download/access lock_type lock; - PathName path = spec.get_string("path", LibEcKitGeo::cacheDir() + "/eckit/geo/orca/" + uid_ + ".atlas"); - #if eckit_HAVE_CURL // for eckit::URLHandle if (!path.exists() && LibEcKitGeo::caching()) { auto dir = path.dirName(); @@ -89,7 +82,6 @@ ORCA::ORCA(const Spec& spec) : ASSERT(dir.exists()); auto tmp = path + ".download"; - auto url = spec.get_string("url_prefix", "") + spec.get_string("url"); Timer timer; Log::info() << "ORCA: downloading '" << url << "' to '" << path << "'..." << std::endl; @@ -117,16 +109,41 @@ ORCA::ORCA(const Spec& spec) : #endif ASSERT_MSG(path.exists(), "ORCA: file '" + path + "' not found"); + return path; +} + + +const ORCA::ORCARecord& orca_record(const PathName& p, const Spec& spec) { + if (CACHE.contains(p)) { + return CACHE[p]; + } // read and check against metadata (if present) - read(path); - check(spec); + auto& record = CACHE[p]; + record.read(p); + record.check(spec); + + return record; } -Grid::uid_t ORCA::calculate_uid() const { +} // namespace + + +ORCA::ORCA(const Spec& spec) : + Unstructured(spec), + name_(spec.get_string("orca_name")), + uid_(spec.get_string("orca_uid")), + arrangement_(arrangement_from_string(spec.get_string("orca_arrangement"))), + record_(orca_record( + orca_path(spec.get_string("path", LibEcKitGeo::cacheDir() + "/eckit/geo/grid/orca/" + uid_ + ".atlas"), + spec.get_string("url_prefix", "") + spec.get_string("url")), + spec)) {} + + +Grid::uid_t ORCA::ORCARecord::calculate_uid(Arrangement arrangement) const { MD5 hash; - hash.add(arrangement_to_string(arrangement_)); + hash.add(arrangement_to_string(arrangement)); auto sized = static_cast(longitudes_.size() * sizeof(double)); @@ -150,7 +167,26 @@ Grid::uid_t ORCA::calculate_uid() const { } -void ORCA::read(const PathName& p) { +ORCA::ORCARecord::bytes_t ORCA::ORCARecord::footprint() const { + return sizeof(dimensions_.front()) * dimensions_.size() + sizeof(halo_.front()) * halo_.size() + + sizeof(pivot_.front()) * pivot_.size() + sizeof(longitudes_.front()) * longitudes_.size() + + sizeof(latitudes_.front()) * latitudes_.size() + sizeof(flags_.front()) * flags_.size(); +} + + +size_t ORCA::ORCARecord::ni() const { + ASSERT(0 <= dimensions_[0]); + return static_cast(dimensions_[0]); +} + + +size_t ORCA::ORCARecord::nj() const { + ASSERT(0 <= dimensions_[1]); + return static_cast(dimensions_[1]); +} + + +void ORCA::ORCARecord::read(const PathName& p) { codec::RecordReader reader(p); int version = -1; @@ -171,10 +207,11 @@ void ORCA::read(const PathName& p) { } -void ORCA::check(const Spec& spec) { - ASSERT(uid_.length() == 32); +void ORCA::ORCARecord::check(const Spec& spec) const { if (spec.get_bool("orca_uid_check", false)) { - ASSERT(uid_ == uid()); + auto uid = spec.get_string("orca_uid"); + ASSERT(uid.length() == 32); + ASSERT(uid == calculate_uid(arrangement_from_string(spec.get_string("orca_arrangement")))); } if (std::vector d; spec.get("dimensions", d)) { @@ -201,7 +238,7 @@ void ORCA::check(const Spec& spec) { } -size_t ORCA::write(const PathName& p, const std::string& compression) { +size_t ORCA::ORCARecord::write(const PathName& p, const std::string& compression) { codec::RecordWriter record; codec::ArrayShape shape{static_cast(dimensions_[0]), static_cast(dimensions_[1])}; @@ -236,7 +273,7 @@ const area::BoundingBox& ORCA::boundingBox() const { std::pair, std::vector> ORCA::to_latlon() const { - return {latitudes_, longitudes_}; + return {record_.latitudes_, record_.longitudes_}; } diff --git a/src/eckit/geo/grid/unstructured/ORCA.h b/src/eckit/geo/grid/unstructured/ORCA.h index e924d0fa1..5b3f95609 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.h +++ b/src/eckit/geo/grid/unstructured/ORCA.h @@ -40,6 +40,29 @@ class ORCA final : public Unstructured { W, }; + struct ORCARecord { + explicit ORCARecord() = default; + + void read(const PathName&); + void check(const Spec&) const; + size_t write(const PathName&, const std::string& compression = "none"); + uid_t calculate_uid(Arrangement) const; + + using bytes_t = decltype(sizeof(int)); + bytes_t footprint() const; + + size_t ni() const; + size_t nj() const; + + std::array dimensions_ = {-1, -1}; + std::array halo_ = {-1, -1, -1, -1}; + std::array pivot_ = {-1, -1}; + + std::vector longitudes_; + std::vector latitudes_; + std::vector flags_; + }; + // -- Exceptions // None @@ -58,14 +81,8 @@ class ORCA final : public Unstructured { // -- Methods - uid_t calculate_uid() const; - - void read(const PathName&); - void check(const Spec&); - size_t write(const PathName&, const std::string& compression = "none"); - - size_t ni() const { return static_cast(dimensions_[0]); } - size_t nj() const { return static_cast(dimensions_[1]); } + size_t ni() const { return record_.ni(); } + size_t nj() const { return record_.nj(); } // -- Overridden methods @@ -83,8 +100,8 @@ class ORCA final : public Unstructured { std::pair, std::vector> to_latlon() const override; - const std::vector& longitudes() const override { return longitudes_; } - const std::vector& latitudes() const override { return latitudes_; } + const std::vector& longitudes() const override { return record_.longitudes_; } + const std::vector& latitudes() const override { return record_.latitudes_; } // -- Class members // None @@ -99,13 +116,7 @@ class ORCA final : public Unstructured { std::string name_; uid_t uid_; Arrangement arrangement_; - - std::array dimensions_; - std::array halo_; - std::array pivot_; - std::vector longitudes_; - std::vector latitudes_; - std::vector flags_; + const ORCARecord& record_; // -- Methods // None From a1bc71fd2fa5e2d768db5992935df4074bb45e55 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 17 Jan 2024 00:16:10 +0000 Subject: [PATCH 431/737] eckit::geo::Grid --- tests/geo/grid.cc | 48 +++++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index 9ab75bc83..3c9e7d3b2 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -14,6 +14,7 @@ #include "eckit/geo/Grid.h" #include "eckit/geo/spec/Custom.h" +#include "eckit/geo/util/Cache.h" #include "eckit/testing/Test.h" @@ -24,16 +25,14 @@ using namespace geo; CASE("GridFactory::build") { - struct test_t { - std::string name; - size_t size; - }; - - SECTION("GridFactory::build_from_name") { - for (const auto& test : {test_t{"O2", 88}, {"f2", 32}, {"h2", 48}}) { - std::unique_ptr grid( - GridFactory::build(*std::unique_ptr(new spec::Custom({{"grid", test.name}})))); + struct { + std::string name; + size_t size; + } tests[]{{"O2", 88}, {"f2", 32}, {"h2", 48}}; + + for (const auto& test : tests) { + std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", test.name}}))); auto size = grid->size(); EXPECT_EQUAL(size, test.size); @@ -42,8 +41,7 @@ CASE("GridFactory::build") { SECTION("RegularGaussian") { - std::unique_ptr grid( - GridFactory::build(*std::unique_ptr(new spec::Custom({{"grid", "f2"}, {"south", 0}})))); + std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", "f2"}, {"south", 0}}))); auto nh = grid->size(); EXPECT_EQUAL(nh, 32 / 2); @@ -51,17 +49,35 @@ CASE("GridFactory::build") { SECTION("Grid::build_from_uid") { - // TODO + spec::Custom spec({ + {"uid", "a832a12030c73928133553ec3a8d2a7e"}, + }); + + const auto footprint = util::Cache::total_footprint(); + + std::unique_ptr a(GridFactory::build(spec)); + + const auto footprint_a = util::Cache::total_footprint(); + EXPECT(footprint < footprint_a); + + std::unique_ptr b(GridFactory::build(spec)); + + const auto footprint_b = util::Cache::total_footprint(); + EXPECT_EQUAL(footprint_a, footprint_b); + + const auto size_a = a->size(); + const auto size_b = b->size(); + EXPECT_EQUAL(size_a, size_b); } SECTION("Grid::build_from_increments") { SECTION("global") { - std::unique_ptr global(GridFactory::build(*std::unique_ptr(new spec::Custom({ + std::unique_ptr global(GridFactory::build(spec::Custom({ {"type", "regular_ll"}, {"west_east_increment", 1}, {"south_north_increment", 1}, - })))); + }))); auto size = global->size(); EXPECT_EQUAL(size, 360 * 181); @@ -69,7 +85,7 @@ CASE("GridFactory::build") { SECTION("non-global") { - std::unique_ptr grid(GridFactory::build(*std::unique_ptr(new spec::Custom({ + std::unique_ptr grid(GridFactory::build(spec::Custom({ {"type", "regular_ll"}, {"west_east_increment", 1}, {"south_north_increment", 1}, @@ -77,7 +93,7 @@ CASE("GridFactory::build") { {"west", 1}, {"south", 1}, {"east", 10}, - })))); + }))); auto size = grid->size(); EXPECT_EQUAL(size, 100); From fe5b222b5e588290f0602154c526e93e62fe2d11 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 17 Jan 2024 00:57:28 +0000 Subject: [PATCH 432/737] eckit::geo::Grid --- src/eckit/geo/grid/unstructured/ORCA.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index 62f88e9a4..9baebf94a 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -114,6 +114,9 @@ PathName orca_path(const PathName& path, const std::string& url) { const ORCA::ORCARecord& orca_record(const PathName& p, const Spec& spec) { + // control concurrent reads/writes + lock_type lock; + if (CACHE.contains(p)) { return CACHE[p]; } From 19b33764ef45bfd507c7c454de197a77d7411c7a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 17 Jan 2024 10:00:05 +0000 Subject: [PATCH 433/737] eckit::geo --- src/eckit/geo/CMakeLists.txt | 4 ++-- src/eckit/geo/{util => }/Cache.cc | 14 +++++++------- src/eckit/geo/{util => }/Cache.h | 16 ++++++++-------- src/eckit/geo/grid/unstructured/ORCA.cc | 4 ++-- src/eckit/geo/util/gaussian_latitudes.cc | 2 +- src/eckit/geo/util/reduced_classical_pl.cc | 2 +- src/eckit/geo/util/reduced_octahedral_pl.cc | 2 +- tests/geo/cache.cc | 14 +++++++------- tests/geo/grid.cc | 8 ++++---- 9 files changed, 33 insertions(+), 33 deletions(-) rename src/eckit/geo/{util => }/Cache.cc (74%) rename src/eckit/geo/{util => }/Cache.h (85%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 4a774bd08..eec244070 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -8,6 +8,8 @@ install( list(APPEND eckit_geo_srcs ${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_config.h Area.h + Cache.cc + Cache.h CoordinateHelpers.cc CoordinateHelpers.h Domain.cc @@ -107,8 +109,6 @@ list(APPEND eckit_geo_srcs spec/Layered.h util.cc util.h - util/Cache.cc - util/Cache.h util/arange.cc util/gaussian_latitudes.cc util/linspace.cc diff --git a/src/eckit/geo/util/Cache.cc b/src/eckit/geo/Cache.cc similarity index 74% rename from src/eckit/geo/util/Cache.cc rename to src/eckit/geo/Cache.cc index 11f6bcbcd..f3fe3e619 100644 --- a/src/eckit/geo/util/Cache.cc +++ b/src/eckit/geo/Cache.cc @@ -10,20 +10,20 @@ */ -#include "eckit/geo/util/Cache.h" +#include "eckit/geo/Cache.h" #include -namespace eckit::geo::util { +namespace eckit::geo { -static recursive_mutex MUTEX; +static util::recursive_mutex MUTEX; static std::vector CACHES; Cache::bytes_t Cache::total_footprint() { - lock_guard lock(MUTEX); + util::lock_guard lock(MUTEX); return std::accumulate(CACHES.begin(), CACHES.end(), static_cast(0), [](bytes_t sum, const auto* cache) { return sum + cache->footprint(); }); @@ -31,15 +31,15 @@ Cache::bytes_t Cache::total_footprint() { void Cache::total_purge() { - lock_guard lock(MUTEX); + util::lock_guard lock(MUTEX); std::for_each(CACHES.begin(), CACHES.end(), [](auto* cache) { cache->purge(); }); } Cache::Cache() { - lock_guard lock(MUTEX); + util::lock_guard lock(MUTEX); CACHES.emplace_back(this); } -} // namespace eckit::geo::util +} // namespace eckit::geo diff --git a/src/eckit/geo/util/Cache.h b/src/eckit/geo/Cache.h similarity index 85% rename from src/eckit/geo/util/Cache.h rename to src/eckit/geo/Cache.h index d62681596..5dc8c0493 100644 --- a/src/eckit/geo/util/Cache.h +++ b/src/eckit/geo/Cache.h @@ -19,7 +19,7 @@ #include "eckit/geo/util/mutex.h" -namespace eckit::geo::util { +namespace eckit::geo { class Cache { @@ -58,27 +58,27 @@ class CacheT final : private Cache { using value_type = Value; CacheT() : - mutex_(new recursive_mutex) { + mutex_(new util::recursive_mutex) { ASSERT(mutex_ != nullptr); } bool contains(const key_type& key) const { - lock_guard lock(*mutex_); + util::lock_guard lock(*mutex_); return container_.find(key) != container_.end(); } const value_type& operator[](const key_type& key) const { - lock_guard lock(*mutex_); + util::lock_guard lock(*mutex_); return container_[key]; } value_type& operator[](const key_type& key) { - lock_guard lock(*mutex_); + util::lock_guard lock(*mutex_); return container_[key]; } bytes_t footprint() const final { - lock_guard lock(*mutex_); + util::lock_guard lock(*mutex_); return std::accumulate(container_.begin(), container_.end(), 0, [](bytes_t sum, const auto& kv) { if constexpr (has_footprint_v) { return sum + kv.second.footprint(); @@ -94,8 +94,8 @@ class CacheT final : private Cache { private: mutable std::map container_; - recursive_mutex* mutex_; + util::recursive_mutex* mutex_; }; -} // namespace eckit::geo::util +} // namespace eckit::geo diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index 9baebf94a..add16755b 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -16,11 +16,11 @@ #include "eckit/eckit_config.h" #include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" +#include "eckit/geo/Cache.h" #include "eckit/geo/LibEcKitGeo.h" #include "eckit/geo/Spec.h" #include "eckit/geo/area/BoundingBox.h" #include "eckit/geo/iterator/Unstructured.h" -#include "eckit/geo/util/Cache.h" #include "eckit/geo/util/mutex.h" #include "eckit/io/Length.h" #include "eckit/log/Bytes.h" @@ -68,7 +68,7 @@ class lock_type { }; -util::CacheT CACHE; +CacheT CACHE; PathName orca_path(const PathName& path, const std::string& url) { diff --git a/src/eckit/geo/util/gaussian_latitudes.cc b/src/eckit/geo/util/gaussian_latitudes.cc index e46ebb7e2..84277f7d8 100644 --- a/src/eckit/geo/util/gaussian_latitudes.cc +++ b/src/eckit/geo/util/gaussian_latitudes.cc @@ -17,7 +17,7 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/util/Cache.h" +#include "eckit/geo/Cache.h" namespace eckit::geo::util { diff --git a/src/eckit/geo/util/reduced_classical_pl.cc b/src/eckit/geo/util/reduced_classical_pl.cc index 307f10cf1..1bb1f8916 100644 --- a/src/eckit/geo/util/reduced_classical_pl.cc +++ b/src/eckit/geo/util/reduced_classical_pl.cc @@ -14,8 +14,8 @@ #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Cache.h" #include "eckit/geo/util.h" -#include "eckit/geo/util/Cache.h" namespace eckit::geo::util { diff --git a/src/eckit/geo/util/reduced_octahedral_pl.cc b/src/eckit/geo/util/reduced_octahedral_pl.cc index a3bdb1dd7..fd3e91349 100644 --- a/src/eckit/geo/util/reduced_octahedral_pl.cc +++ b/src/eckit/geo/util/reduced_octahedral_pl.cc @@ -11,8 +11,8 @@ #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Cache.h" #include "eckit/geo/util.h" -#include "eckit/geo/util/Cache.h" namespace eckit::geo::util { diff --git a/tests/geo/cache.cc b/tests/geo/cache.cc index f4b57129c..6aba42a7c 100644 --- a/tests/geo/cache.cc +++ b/tests/geo/cache.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/util/Cache.h" +#include "eckit/geo/Cache.h" #include "eckit/geo/util.h" #include "eckit/testing/Test.h" @@ -18,7 +18,7 @@ namespace eckit::test { -using namespace geo::util; +using namespace geo; CASE("eckit::geo::util") { @@ -50,11 +50,11 @@ CASE("eckit::geo::util") { SECTION("separate caches") { - reduced_classical_pl(16); + util::reduced_classical_pl(16); auto foot = Cache::total_footprint(); EXPECT(0 < foot); - reduced_octahedral_pl(16); + util::reduced_octahedral_pl(16); EXPECT(foot < Cache::total_footprint()); } @@ -64,7 +64,7 @@ CASE("eckit::geo::util") { SECTION("reduced_classical_pl, reduced_octahedral_pl") { - for (const geo::pl_type& (*cacheable)(size_t) : {&reduced_classical_pl, &reduced_octahedral_pl}) { + for (const geo::pl_type& (*cacheable)(size_t) : {&util::reduced_classical_pl, &util::reduced_octahedral_pl}) { for (const auto& test : tests) { Cache::total_purge(); (*cacheable)(test.N); @@ -87,13 +87,13 @@ CASE("eckit::geo::util") { SECTION("gaussian_latitudes") { for (const auto& test : tests) { Cache::total_purge(); - gaussian_latitudes(test.N, test.increasing); + util::gaussian_latitudes(test.N, test.increasing); EXPECT_EQUAL(Cache::total_footprint(), test.gl_footprint); } Cache::total_purge(); for (const auto& test : tests) { - gaussian_latitudes(test.N, test.increasing); + util::gaussian_latitudes(test.N, test.increasing); EXPECT_EQUAL(Cache::total_footprint(), test.gl_footprint_acc); } } diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index 3c9e7d3b2..c4f5e74ac 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -12,9 +12,9 @@ #include +#include "eckit/geo/Cache.h" #include "eckit/geo/Grid.h" #include "eckit/geo/spec/Custom.h" -#include "eckit/geo/util/Cache.h" #include "eckit/testing/Test.h" @@ -53,16 +53,16 @@ CASE("GridFactory::build") { {"uid", "a832a12030c73928133553ec3a8d2a7e"}, }); - const auto footprint = util::Cache::total_footprint(); + const auto footprint = Cache::total_footprint(); std::unique_ptr a(GridFactory::build(spec)); - const auto footprint_a = util::Cache::total_footprint(); + const auto footprint_a = Cache::total_footprint(); EXPECT(footprint < footprint_a); std::unique_ptr b(GridFactory::build(spec)); - const auto footprint_b = util::Cache::total_footprint(); + const auto footprint_b = Cache::total_footprint(); EXPECT_EQUAL(footprint_a, footprint_b); const auto size_a = a->size(); From 4907e2aa6873ea8394260642793ea82d1b37d80f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 17 Jan 2024 10:00:09 +0000 Subject: [PATCH 434/737] eckit::geo --- tests/geo/figure_sphere.cc | 357 ++++++++++++++++++------------------- 1 file changed, 176 insertions(+), 181 deletions(-) diff --git a/tests/geo/figure_sphere.cc b/tests/geo/figure_sphere.cc index 95476975a..ddc12eba8 100644 --- a/tests/geo/figure_sphere.cc +++ b/tests/geo/figure_sphere.cc @@ -11,7 +11,6 @@ #include -#include #include "eckit/geo/Point3.h" #include "eckit/geo/PointLonLat.h" @@ -19,261 +18,257 @@ #include "eckit/geo/UnitSphere.h" #include "eckit/testing/Test.h" -namespace eckit::tests::geo { + +namespace eckit::tests { using namespace eckit::geo; -// set sphere -struct DatumTwoUnits { - static double radius() { return 2.; } -}; +CASE("unit sphere") { + const auto R = UnitSphere::radius(); + const auto L = R * std::sqrt(2) / 2.; -using TwoUnitsSphere = SphereT; + const PointLonLat P1(-71.6, -33.); // Valparaíso + const PointLonLat P2(121.8, 31.4); // Shanghai -const double R = UnitSphere::radius(); + SECTION("radius") { + EXPECT(UnitSphere::radius() == 1.); + } -// ----------------------------------------------------------------------------- -// test unit sphere radius -CASE("test unit sphere radius") { - EXPECT(UnitSphere::radius() == 1.); -} + SECTION("north pole") { + auto p = UnitSphere::convertSphericalToCartesian({0., 90.}); -// ----------------------------------------------------------------------------- -// test unit sphere poles + EXPECT(p.X == 0); + EXPECT(p.Y == 0); + EXPECT(p.Z == R); + } -CASE("test unit sphere north pole") { - auto p = UnitSphere::convertSphericalToCartesian({0., 90.}); - EXPECT(p.X == 0); - EXPECT(p.Y == 0); - EXPECT(p.Z == R); -} + SECTION("south pole") { + auto p = UnitSphere::convertSphericalToCartesian({0., -90.}); -CASE("test unit sphere south pole") { - auto p = UnitSphere::convertSphericalToCartesian({0., -90.}); + EXPECT(p.X == 0); + EXPECT(p.Y == 0); + EXPECT(p.Z == -R); + } - EXPECT(p.X == 0); - EXPECT(p.Y == 0); - EXPECT(p.Z == -R); -} -// ----------------------------------------------------------------------------- -// test unit sphere quadrants + SECTION("distances") { + // Same points with added shifts + auto P1b = PointLonLat::make(288.4, -33.); // Valparaíso + longitude shift + auto P2b = PointLonLat::make(301.8, 148.6); // Shanghai + latitude/longitude shift + auto P2c = PointLonLat::make(-58.2, -211.4); // Shanghai + latitude/longitude shift -CASE("test unit sphere lon 0") { - auto p = UnitSphere::convertSphericalToCartesian({0., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-360., 0.}); + auto d0 = UnitSphere::distance(P1, P2); + auto d1 = UnitSphere::distance(P1b, P2); + auto d2 = UnitSphere::distance(P1, P2b); + auto d3 = UnitSphere::distance(P1, P2c); - EXPECT(p.X == R); - EXPECT(p.Y == 0); - EXPECT(p.Z == 0); + EXPECT(types::is_approximately_equal(d0, d1)); + EXPECT(types::is_approximately_equal(d0, d2)); + EXPECT(types::is_approximately_equal(d0, d3)); + } - EXPECT(Point3::equal(p, q)); -} -CASE("test unit sphere lon 90") { - auto p = UnitSphere::convertSphericalToCartesian({90., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-270., 0.}); + SECTION("area globe") { + EXPECT(UnitSphere::area() == 4. * M_PI * R * R); + } - EXPECT(p.X == 0); - EXPECT(p.Y == R); - EXPECT(p.Z == 0); - EXPECT(Point3::equal(p, q)); -} + SECTION("area hemispheres") { + auto area_hemisphere_north = UnitSphere::area({-180., 90.}, {180., 0.}); + auto area_hemisphere_south = UnitSphere::area({-180., 0.}, {180., -90.}); -CASE("test unit sphere lon 180") { - auto p = UnitSphere::convertSphericalToCartesian({180., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-180., 0.}); + EXPECT(area_hemisphere_north == 0.5 * UnitSphere::area()); + EXPECT(area_hemisphere_north == area_hemisphere_south); + } - EXPECT(p.X == -R); - EXPECT(p.Y == 0); - EXPECT(p.Z == 0); - EXPECT(Point3::equal(p, q)); -} + SECTION("lon 0 (quadrant)") { + auto p = UnitSphere::convertSphericalToCartesian({0., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-360., 0.}); -CASE("test unit sphere lon 270") { - auto p = UnitSphere::convertSphericalToCartesian({270., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-90., 0.}); + EXPECT(p.X == R); + EXPECT(p.Y == 0); + EXPECT(p.Z == 0); - EXPECT(p.X == 0); - EXPECT(p.Y == -R); - EXPECT(p.Z == 0); + EXPECT(Point3::equal(p, q)); + } - EXPECT(Point3::equal(p, q)); -} + SECTION("lon 90 (quadrant)") { + auto p = UnitSphere::convertSphericalToCartesian({90., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-270., 0.}); -// ----------------------------------------------------------------------------- -// test unit sphere octants + EXPECT(p.X == 0); + EXPECT(p.Y == R); + EXPECT(p.Z == 0); -const double L = R * std::sqrt(2) / 2.; + EXPECT(Point3::equal(p, q)); + } -CASE("test unit sphere lon 45") { - auto p = UnitSphere::convertSphericalToCartesian({45., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-315., 0.}); - EXPECT(types::is_approximately_equal(p.X, L)); - EXPECT(types::is_approximately_equal(p.Y, L)); - EXPECT(p.Z == 0); + SECTION("lon 180 (quadrant)") { + auto p = UnitSphere::convertSphericalToCartesian({180., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-180., 0.}); - EXPECT(Point3::equal(p, q)); -} + EXPECT(p.X == -R); + EXPECT(p.Y == 0); + EXPECT(p.Z == 0); -CASE("test unit sphere lon 135") { - auto p = UnitSphere::convertSphericalToCartesian({135., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-225., 0.}); + EXPECT(Point3::equal(p, q)); + } - EXPECT(types::is_approximately_equal(p.X, -L)); - EXPECT(types::is_approximately_equal(p.Y, L)); - EXPECT(p.Z == 0); - EXPECT(Point3::equal(p, q)); -} + SECTION("lon 270 (quadrant)") { + auto p = UnitSphere::convertSphericalToCartesian({270., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-90., 0.}); -CASE("test unit sphere lon 225") { - auto p = UnitSphere::convertSphericalToCartesian({225., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-135., 0.}); + EXPECT(p.X == 0); + EXPECT(p.Y == -R); + EXPECT(p.Z == 0); - EXPECT(types::is_approximately_equal(p.X, -L)); - EXPECT(types::is_approximately_equal(p.Y, -L)); - EXPECT(p.Z == 0); + EXPECT(Point3::equal(p, q)); + } - EXPECT(Point3::equal(p, q)); -} -CASE("test unit sphere lon 315") { - auto p = UnitSphere::convertSphericalToCartesian({315., 0.}); - auto q = UnitSphere::convertSphericalToCartesian({-45., 0.}); + SECTION("lon 45 (octant)") { + auto p = UnitSphere::convertSphericalToCartesian({45., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-315., 0.}); - EXPECT(types::is_approximately_equal(p.X, L)); - EXPECT(types::is_approximately_equal(p.Y, -L)); - EXPECT(p.Z == 0); + EXPECT(types::is_approximately_equal(p.X, L)); + EXPECT(types::is_approximately_equal(p.Y, L)); + EXPECT(p.Z == 0); - EXPECT(Point3::equal(p, q)); -} + EXPECT(Point3::equal(p, q)); + } -// ----------------------------------------------------------------------------- -// test unit sphere with non-canonical latitudes outside [-90, 90] -CASE("test unit sphere lat 100") { - // Default behavior throws - EXPECT_THROWS_AS(PointLonLat(0., 100.), BadValue); - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({0., 100.}), BadValue); + SECTION("lon 135 (octant)") { + auto p = UnitSphere::convertSphericalToCartesian({135., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-225., 0.}); - auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(0., 100.), 0.); - auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(180., 80.), 0.); + EXPECT(types::is_approximately_equal(p.X, -L)); + EXPECT(types::is_approximately_equal(p.Y, L)); + EXPECT(p.Z == 0); - // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(types::is_approximately_equal(p.X, q.X)); - EXPECT(types::is_approximately_equal(p.Y, q.Y)); - EXPECT(types::is_approximately_equal(p.Z, q.Z)); -} + EXPECT(Point3::equal(p, q)); + } -CASE("test unit sphere lat 290") { - // Default behavior throws - EXPECT_THROWS_AS(PointLonLat(15., 290.), BadValue); - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({15., 290.}), BadValue); - auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., 290.), 0.); - auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., -70.), 0.); + SECTION("lon 225 (octant)") { + auto p = UnitSphere::convertSphericalToCartesian({225., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-135., 0.}); - // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(types::is_approximately_equal(p.X, q.X)); - EXPECT(types::is_approximately_equal(p.Y, q.Y)); - EXPECT(types::is_approximately_equal(p.Z, q.Z)); -} + EXPECT(types::is_approximately_equal(p.X, -L)); + EXPECT(types::is_approximately_equal(p.Y, -L)); + EXPECT(p.Z == 0); -CASE("test unit sphere lat -120") { - // Default behavior throws - EXPECT_THROWS_AS(PointLonLat(45., -120.), BadValue); - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({45., -120.}), BadValue); + EXPECT(Point3::equal(p, q)); + } - auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(45., -120.), 0.); - auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(225., -60.), 0.); - // sin(x) and sin(pi-x) are not bitwise identical - EXPECT(types::is_approximately_equal(p.X, q.X)); - EXPECT(types::is_approximately_equal(p.Y, q.Y)); - EXPECT(types::is_approximately_equal(p.Z, q.Z)); -} + SECTION("lon 315 (octant)") { + auto p = UnitSphere::convertSphericalToCartesian({315., 0.}); + auto q = UnitSphere::convertSphericalToCartesian({-45., 0.}); -// ----------------------------------------------------------------------------- -// test unit sphere distances with non-canonical coordinates + EXPECT(types::is_approximately_equal(p.X, L)); + EXPECT(types::is_approximately_equal(p.Y, -L)); + EXPECT(p.Z == 0); -CASE("test unit sphere distances") { - const PointLonLat P1(-71.6, -33.); // Valparaíso - const PointLonLat P2(121.8, 31.4); // Shanghai + EXPECT(Point3::equal(p, q)); + } - // Same points with added shifts - const auto P1b = PointLonLat::make(288.4, -33.); // Valparaíso + longitude shift - const auto P2b = PointLonLat::make(301.8, 148.6); // Shanghai + latitude/longitude shift - const auto P2c = PointLonLat::make(-58.2, -211.4); // Shanghai + latitude/longitude shift - const double d0 = UnitSphere::distance(P1, P2); - const double d1 = UnitSphere::distance(P1b, P2); - const double d2 = UnitSphere::distance(P1, P2b); - const double d3 = UnitSphere::distance(P1, P2c); + SECTION("lat 100") { + // Default behavior throws + EXPECT_THROWS_AS(PointLonLat(0., 100.), BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({0., 100.}), BadValue); - EXPECT(types::is_approximately_equal(d0, d1)); - EXPECT(types::is_approximately_equal(d0, d2)); - EXPECT(types::is_approximately_equal(d0, d3)); -} + auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(0., 100.), 0.); + auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(180., 80.), 0.); -// ----------------------------------------------------------------------------- -// test unit sphere area + // sin(x) and sin(pi-x) are not bitwise identical + EXPECT(types::is_approximately_equal(p.X, q.X)); + EXPECT(types::is_approximately_equal(p.Y, q.Y)); + EXPECT(types::is_approximately_equal(p.Z, q.Z)); + } -CASE("test unit sphere area globe") { - EXPECT(UnitSphere::area() == 4. * M_PI * R * R); -} -CASE("test unit sphere area hemispheres") { - const double area_hemisphere_north = UnitSphere::area({-180., 90.}, {180., 0.}); - const double area_hemisphere_south = UnitSphere::area({-180., 0.}, {180., -90.}); + SECTION("lat 290") { + // Default behavior throws + EXPECT_THROWS_AS(PointLonLat(15., 290.), BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({15., 290.}), BadValue); - EXPECT(area_hemisphere_north == 0.5 * UnitSphere::area()); - EXPECT(area_hemisphere_north == area_hemisphere_south); -} + auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., 290.), 0.); + auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., -70.), 0.); -// ----------------------------------------------------------------------------- -// test two units sphere + // sin(x) and sin(pi-x) are not bitwise identical + EXPECT(types::is_approximately_equal(p.X, q.X)); + EXPECT(types::is_approximately_equal(p.Y, q.Y)); + EXPECT(types::is_approximately_equal(p.Z, q.Z)); + } -CASE("test two units sphere radius") { - EXPECT(TwoUnitsSphere::radius() == 2.); -} -CASE("test two units sphere distances") { - const PointLonLat P1(-71.6, -33.); // Valparaíso - const PointLonLat P2(121.8, 31.4); // Shanghai + SECTION("lat -120") { + // Default behavior throws + EXPECT_THROWS_AS(PointLonLat(45., -120.), BadValue); + EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({45., -120.}), BadValue); - const double d_sphere_1 = UnitSphere::distance(P1, P2); - const double d_sphere_2 = TwoUnitsSphere::distance(P1, P2); - EXPECT(2. * d_sphere_1 == d_sphere_2); -} + auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(45., -120.), 0.); + auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(225., -60.), 0.); -CASE("test two units sphere areas") { - const double area_sphere_1 = UnitSphere::area(); - const double area_sphere_2 = TwoUnitsSphere::area(); - EXPECT(4. * area_sphere_1 == area_sphere_2); + // sin(x) and sin(pi-x) are not bitwise identical + EXPECT(types::is_approximately_equal(p.X, q.X)); + EXPECT(types::is_approximately_equal(p.Y, q.Y)); + EXPECT(types::is_approximately_equal(p.Z, q.Z)); + } } -CASE("test two units sphere sub areas") { + +CASE("two-unit sphere") { + struct DatumTwoUnits { + static double radius() { return 2.; } + }; + + using TwoUnitsSphere = SphereT; + const PointLonLat P1(-71.6, -33.); // Valparaíso const PointLonLat P2(121.8, 31.4); // Shanghai - const double sub_area_sphere_1 = UnitSphere::area(P2, P1); - const double sub_area_sphere_2 = TwoUnitsSphere::area(P2, P1); - EXPECT(4. * sub_area_sphere_1 == sub_area_sphere_2); + + SECTION("radius") { + EXPECT(TwoUnitsSphere::radius() == 2.); + } + + + SECTION("distances") { + auto distance_1 = UnitSphere::distance(P1, P2); + auto distance_2 = TwoUnitsSphere::distance(P1, P2); + EXPECT(2. * distance_1 == distance_2); + } + + + SECTION("area globe") { + auto area_1 = UnitSphere::area(); + auto area_2 = TwoUnitsSphere::area(); + EXPECT(4. * area_1 == area_2); + } + + + SECTION("sub areas") { + auto area_1 = UnitSphere::area(P2, P1); + auto area_2 = TwoUnitsSphere::area(P2, P1); + EXPECT(4. * area_1 == area_2); + } } -// ----------------------------------------------------------------------------- -} // namespace eckit::tests::geo +} // namespace eckit::tests + int main(int argc, char** argv) { return eckit::testing::run_tests(argc, argv); From 9f915ebddcadf2ce5bcebb8b8b0e73735f5f068e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 19 Jan 2024 14:39:18 +0000 Subject: [PATCH 435/737] eckit::geo::area::BoundingBox --- src/eckit/geo/area/BoundingBox.cc | 13 +++++++++---- src/eckit/geo/area/BoundingBox.h | 2 ++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index a21d7016b..faacb0e6a 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -55,13 +55,18 @@ BoundingBox::BoundingBox(const Spec& spec) : BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s, e} { - if (west != east) { + ASSERT_MSG(types::is_approximately_lesser_or_equal(-90., south), "BoundingBox: latitude range (-90 <= south)"); + ASSERT_MSG(types::is_approximately_lesser_or_equal(south, north), "BoundingBox: latitude range (south <= north)"); + ASSERT_MSG(types::is_approximately_lesser_or_equal(north, 90.), "BoundingBox: latitude range (north <= 90)"); + + if (!types::is_approximately_equal(west, east)) { auto e = PointLonLat::normalise_angle_to_minimum(east, west); - east = e == west ? (e + 360.) : e; + east = types::is_approximately_equal(e, west) ? (e + 360.) : e; } - ASSERT_MSG(west <= east && east <= west + 360., "BoundingBox: longitude range"); - ASSERT_MSG(-90. <= south && south <= north && north <= 90., "BoundingBox: latitude range"); + ASSERT_MSG(types::is_approximately_lesser_or_equal(west, east), "BoundingBox: longitude range (west <= east)"); + ASSERT_MSG(types::is_approximately_lesser_or_equal(east, west + 360.), + "BoundingBox: longitude range (east <= west + 360)"); } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 6caa5283e..4eb7db37c 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -36,6 +36,8 @@ class BoundingBox : public Area, protected std::array { explicit BoundingBox(const Spec&); BoundingBox(double north, double west, double south, double east); + BoundingBox(double north, double west, double south) : + BoundingBox(north, west, south, west + 360.) {} BoundingBox(); From a30e6fdc8fb1dd2a5aaaa961c01f61f77726816e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 19 Jan 2024 16:39:48 +0000 Subject: [PATCH 436/737] eckit::geo::area::BoundingBox --- src/eckit/geo/area/BoundingBox.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index faacb0e6a..6dfcbbd37 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -36,16 +36,20 @@ static BoundingBox make_from_spec(const Spec& spec) { return {area[0], area[1], area[2], area[3]}; } - if (auto area(DEFAULT); spec.get("north", area[0]) && spec.get("west", area[1]) && spec.get("south", area[2]) && - spec.get("east", area[3])) { - return {area[0], area[1], area[2], area[3]}; - } + auto area(DEFAULT); + spec.get("north", area[0]); + spec.get("south", area[2]); - if (!spec.has("north") && !spec.has("west") && !spec.has("south") && !spec.has("east")) { - return {}; + if (spec.get("west", area[1]) != spec.get("east", area[3])) { + if (spec.has("west")) { + area[3] = area[1] + 360; + } + else { + area[1] = area[3] - 360; + } } - throw UserError("BoundingBox: expecting 'area'=north/west/south/east or ('north', 'west', 'south', 'east')"); + return {area[0], area[1], area[2], area[3]}; } From 1226e5f9ea7e9e8548574c250264dba3f7779604 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 19 Jan 2024 16:41:25 +0000 Subject: [PATCH 437/737] eckit::geo::Grid --- src/eckit/geo/Range.h | 5 +++-- src/eckit/geo/range/Gaussian.cc | 1 + tests/geo/grid.cc | 25 ++++++++++++++++++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 52ba49364..bafcf1161 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -70,7 +70,8 @@ class Range { // None // -- Methods - // None + + void resize(size_t n) { n_ = n; } // -- Overridden methods // None @@ -84,7 +85,7 @@ class Range { private: // -- Members - const size_t n_; + size_t n_; const double eps_; // -- Methods diff --git a/src/eckit/geo/range/Gaussian.cc b/src/eckit/geo/range/Gaussian.cc index a46d85449..8e9e12630 100644 --- a/src/eckit/geo/range/Gaussian.cc +++ b/src/eckit/geo/range/Gaussian.cc @@ -37,6 +37,7 @@ Gaussian::Gaussian(size_t N, double a, double b, double _eps) : v.erase(v.begin(), v.begin() + from); ASSERT(!v.empty()); + resize(v.size()); } } diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index c4f5e74ac..d57c6dc30 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -41,10 +41,29 @@ CASE("GridFactory::build") { SECTION("RegularGaussian") { - std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", "f2"}, {"south", 0}}))); + spec::Custom spec({{"grid", "f2"}}); + std::unique_ptr grid1(GridFactory::build(spec)); + auto n1 = grid1->size(); - auto nh = grid->size(); - EXPECT_EQUAL(nh, 32 / 2); + EXPECT_EQUAL(n1, 32); + + spec.set("south", 0); + std::unique_ptr grid2(GridFactory::build(spec)); + auto n2 = grid2->size(); + + EXPECT_EQUAL(n2, n1 / 2); + + spec = spec::Custom{{{"grid", "f2"}, {"west", -180}}}; + std::unique_ptr grid3(GridFactory::build(spec)); + auto n3 = grid3->size(); + + EXPECT_EQUAL(n3, n1); + + spec.set("east", 0); + std::unique_ptr grid4(GridFactory::build(spec)); + auto n4 = grid4->size(); + + EXPECT_EQUAL(n4, n1 / 2); } From ad38e70e58ce070e40e308e10b791519335ff828 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 19 Jan 2024 16:41:37 +0000 Subject: [PATCH 438/737] eckit::geo::area::BoundingBox --- src/eckit/geo/CMakeLists.txt | 1 + src/eckit/geo/Point2.h | 2 + src/eckit/geo/PointLonLat.h | 15 +- src/eckit/geo/util/bounding_box.cc | 292 +++++++++++++++++++++++++++++ 4 files changed, 309 insertions(+), 1 deletion(-) create mode 100644 src/eckit/geo/util/bounding_box.cc diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index eec244070..7c0b4407f 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -110,6 +110,7 @@ list(APPEND eckit_geo_srcs util.cc util.h util/arange.cc + util/bounding_box.cc util/gaussian_latitudes.cc util/linspace.cc util/monotonic_crop.cc diff --git a/src/eckit/geo/Point2.h b/src/eckit/geo/Point2.h index 2f8f28d5c..b46ccdbb7 100644 --- a/src/eckit/geo/Point2.h +++ b/src/eckit/geo/Point2.h @@ -88,6 +88,8 @@ class Point2 : public KPoint<2> { } operator eckit::Value() const; + + static Point2 middle(const Point2& p, const Point2& q) { return (p + q) * 0.5; } }; //------------------------------------------------------------------------------------------------------ diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index 53101d7f8..30a2d8818 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -100,13 +100,26 @@ class PointLonLat final : protected std::array { // None // -- Class methods - // None + + static PointLonLat componentsMin(const PointLonLat& p, const PointLonLat& q) { + return {std::min(p.lon, q.lon), std::min(p.lat, q.lat)}; + } + + static PointLonLat componentsMax(const PointLonLat& p, const PointLonLat& q) { + return {std::max(p.lon, q.lon), std::max(p.lat, q.lat)}; + } // -- Friends friend std::ostream& operator<<(std::ostream& out, const PointLonLat& p) { return out << '{' << p.lon << ", " << p.lat << '}'; } + + friend PointLonLat operator-(const PointLonLat& p, const PointLonLat& q) { return {p.lon - q.lon, p.lat - q.lat}; } + + friend PointLonLat operator+(const PointLonLat& p, const PointLonLat& q) { return {p.lon + q.lon, p.lat + q.lat}; } + + friend PointLonLat operator*(const PointLonLat& p, double d) { return {p.lon * d, p.lat * d}; } }; bool points_equal(const PointLonLat&, const PointLonLat&); diff --git a/src/eckit/geo/util/bounding_box.cc b/src/eckit/geo/util/bounding_box.cc new file mode 100644 index 000000000..1b70ac27e --- /dev/null +++ b/src/eckit/geo/util/bounding_box.cc @@ -0,0 +1,292 @@ +/* + * (C) Copyright 1996- 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 +#include +#include +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/Point.h" +#include "eckit/geo/Projection.h" +#include "eckit/geo/area/BoundingBox.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::util { + + +void longitude_in_range(double reference, double& lon) { + // keep longitude difference (to reference) range below +-180 degree + while (lon > reference + 180.) { + lon -= 360.; + } + while (lon <= reference - 180.) { + lon += 360.; + } +} + + +struct BoundLonLat { + BoundLonLat(PointLonLat min, PointLonLat max) : + min_(min), max_(max) {} + + operator area::BoundingBox() const { return {max_.lat, min_.lon, min_.lat, max_.lon}; } + + void extend(PointLonLat p, PointLonLat eps) { + ASSERT(0. <= eps.lon && 0. <= eps.lat); + + auto sub = p + eps; + auto add = p - eps; + min_ = first_ ? sub : PointLonLat::componentsMin(min_, sub); + max_ = first_ ? add : PointLonLat::componentsMax(max_, add); + first_ = false; + + min_.lat = std::max(min_.lat, -90.); + max_.lat = std::min(max_.lat, 90.); + max_.lon = std::min(max_.lon, min_.lon + 360.); + ASSERT(min_.lon <= max_.lon && min_.lat <= max_.lat); + + includesSouthPole(types::is_approximately_equal(min_.lat, -90.)); + includesNorthPole(types::is_approximately_equal(max_.lat, 90.)); + crossesDateLine(types::is_approximately_equal(max_.lon - min_.lon, 360.)); + } + + bool crossesDateLine(bool yes) { + if ((crossesDateLine_ = crossesDateLine_ || yes)) { + max_.lon = min_.lon + 360.; + } + return crossesDateLine_; + } + + bool includesNorthPole(bool yes) { + if ((includesNorthPole_ = includesNorthPole_ || yes)) { + max_.lat = 90.; + } + crossesDateLine(includesNorthPole_); + return includesNorthPole_; + } + + bool includesSouthPole(bool yes) { + if ((includesSouthPole_ = includesSouthPole_ || yes)) { + min_.lat = -90.; + } + crossesDateLine(includesSouthPole_); + return includesSouthPole_; + } + + bool crossesDateLine() const { return crossesDateLine_; } + bool includesNorthPole() const { return includesNorthPole_; } + bool includesSouthPole() const { return includesSouthPole_; } + +private: + PointLonLat min_; + PointLonLat max_; + bool crossesDateLine_ = false; + bool includesNorthPole_ = false; + bool includesSouthPole_ = false; + bool first_ = true; +}; + + +struct Derivate { + Derivate(const Projection& p, Point2 A, Point2 B, double h, double refLongitude = 0.) : + projection_(p), + H_{Point2::mul(Point2::normalize(Point2::sub(B, A)), h)}, + invnH_(1. / Point2::norm(H_)), + refLongitude_(refLongitude) {} + virtual ~Derivate() = default; + + virtual PointLonLat d(Point2) const = 0; + +protected: + const Projection& projection_; + const Point2 H_; + const double invnH_; + const double refLongitude_; + + PointLonLat xy2lonlat(const Point2& p) const { + auto q = std::get(projection_.inv(p)); + longitude_in_range(refLongitude_, q.lon); + return q; + } +}; + + +struct DerivateForwards final : Derivate { + using Derivate::Derivate; + PointLonLat d(Point2 P) const override { return (xy2lonlat(P + H_) - xy2lonlat(P)) * invnH_; } +}; + + +struct DerivateBackwards final : Derivate { + using Derivate::Derivate; + PointLonLat d(Point2 P) const override { return (xy2lonlat(P) - xy2lonlat(P - H_)) * invnH_; } +}; + + +struct DerivateCentral final : Derivate { + DerivateCentral(const Projection& p, Point2 A, Point2 B, double h, double refLongitude) : + Derivate(p, A, B, h, refLongitude), H2_{H_ * 0.5} {} + const Point2 H2_; + PointLonLat d(Point2 P) const override { return (xy2lonlat(P + H2_) - xy2lonlat(P - H2_)) * invnH_; } +}; + + +struct DerivateFactory { + static const Derivate* build( + const std::string& type, const Projection& p, Point2 A, Point2 B, double h, double refLongitude = 0.) { + ASSERT(0. < h); + + if (A.distance2(B) < h * h) { + struct DerivateDegenerate final : Derivate { + using Derivate::Derivate; + PointLonLat d(Point2) const override { return {99, 99}; } // FIXME + }; + return new DerivateDegenerate(p, A, B, h, refLongitude); + } + + return type == "forwards" ? static_cast(new DerivateForwards(p, A, B, h, refLongitude)) + : type == "backwards" ? static_cast(new DerivateBackwards(p, A, B, h, refLongitude)) + : type == "central" ? static_cast(new DerivateCentral(p, A, B, h, refLongitude)) + : throw; + } + + static void list(std::ostream& out) { return instance().list_(out); } + +private: + static DerivateFactory& instance() { + static DerivateFactory obj; + return obj; + } + + // This is 'const' as Grid should always be immutable + const Derivate* build_( + const std::string& type, const Projection& p, Point2 A, Point2 B, double h, double refLongitude) const; + + void list_(std::ostream&) const; +}; + + +area::BoundingBox bounding_box(Point2 min, Point2 max, Projection& projection) { + using types::is_strictly_greater; + + + // 0. setup + + // use central longitude as absolute reference (keep points within +-180 longitude range) + const Point2 centre_xy{(min.X + max.X) / 2., (min.Y + max.Y) / 2.}; + const auto centre_ll = std::get(projection.inv(centre_xy)); + const auto centre_lon = centre_ll.lon; + + const std::string derivative_type = "central"; + constexpr double h_ll = 0.5e-6; // precision to microdegrees + constexpr double h = 0.5e-1; // precision to decimeters + constexpr size_t Niter = 100; + + + // 1. determine box from projected corners + + const std::pair segments[] = {{{min.X, max.Y}, {max.X, max.Y}}, + {{max.X, max.Y}, {max.X, min.Y}}, + {{max.X, min.Y}, {min.X, min.Y}}, + {{min.X, min.Y}, {min.X, max.Y}}}; + + BoundLonLat bounds(centre_ll, centre_ll); + for (const auto& [A, dummy] : segments) { + auto q = std::get(projection.inv(A)); + longitude_in_range(centre_lon, q.lon); + bounds.extend(q, PointLonLat{h_ll, h_ll}); + } + + + // 2. locate latitude extrema by checking if poles are included (in the un-projected frame) and if not, find extrema + // not at the corners by refining iteratively + + for (auto [A, B] : segments) { + if (!bounds.includesNorthPole() || !bounds.includesSouthPole()) { + std::unique_ptr derivate( + DerivateFactory::build(derivative_type, projection, A, B, h, centre_lon)); + + double dAdy = derivate->d(A).lat; + double dBdy = derivate->d(B).lat; + + if (!is_strictly_greater(dAdy * dBdy, 0.)) { + PointLonLat H{0, h_ll}; + + for (size_t cnt = 0; cnt < Niter; ++cnt) { + Point2 M = Point2::middle(A, B); + double dMdy = derivate->d(M).lat; + if (is_strictly_greater(dAdy * dMdy, 0.)) { + A = M; + dAdy = dMdy; + } + else if (is_strictly_greater(dBdy * dMdy, 0.)) { + B = M; + dBdy = dMdy; + } + else { + break; + } + } + + // update extrema, extended by 'a small amount' (arbitrary) + bounds.extend(std::get(projection.inv(Point2::middle(A, B))), H); + } + } + } + + + // 3. locate longitude extrema not at the corners by refining iteratively + + for (auto [A, B] : segments) { + if (!bounds.crossesDateLine()) { + std::unique_ptr derivate( + DerivateFactory::build(derivative_type, projection, A, B, h, centre_lon)); + + double dAdx = derivate->d(A).lon; + double dBdx = derivate->d(B).lon; + + if (!is_strictly_greater(dAdx * dBdx, 0.)) { + PointLonLat H{h_ll, 0}; + + for (size_t cnt = 0; cnt < Niter; ++cnt) { + Point2 M = Point2::middle(A, B); + double dMdx = derivate->d(M).lon; + + if (is_strictly_greater(dAdx * dMdx, 0.)) { + A = M; + dAdx = dMdx; + } + else if (is_strictly_greater(dBdx * dMdx, 0.)) { + B = M; + dBdx = dMdx; + } + else { + break; + } + } + + // update extrema, extended by 'a small amount' (arbitrary) + bounds.extend(std::get(projection.inv(Point2::middle(A, B))), H); + } + } + } + + + // 4. return bounding box + return bounds; +} + + +} // namespace eckit::geo::util From 5b1707cd4dede6b8c9a8ce0f43f7bae1b2d42efa Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 22 Jan 2024 16:53:57 +0000 Subject: [PATCH 439/737] eckit::geo::area::BoundingBox --- src/eckit/geo/area/BoundingBox.cc | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 6dfcbbd37..cb25ab040 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -40,16 +40,10 @@ static BoundingBox make_from_spec(const Spec& spec) { spec.get("north", area[0]); spec.get("south", area[2]); - if (spec.get("west", area[1]) != spec.get("east", area[3])) { - if (spec.has("west")) { - area[3] = area[1] + 360; - } - else { - area[1] = area[3] - 360; - } - } + auto new_east = spec.get("west", area[1]) && !spec.has("east"); + auto new_west = spec.get("east", area[3]) && !spec.has("west"); - return {area[0], area[1], area[2], area[3]}; + return {area[0], new_west ? area[3] - 360 : area[1], area[2], new_east ? area[1] + 360 : area[3]}; } From 29d97f904371bc347cc0f9a5c3d7d7c98bdb4884 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 22 Jan 2024 17:09:53 +0000 Subject: [PATCH 440/737] eckit::geo::Range --- src/eckit/geo/CMakeLists.txt | 4 - src/eckit/geo/Range.cc | 68 +++++++++++++++ src/eckit/geo/Range.h | 83 +++++++----------- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 2 - src/eckit/geo/grid/regular/RegularGaussian.cc | 3 +- src/eckit/geo/grid/regular/RegularLL.cc | 2 +- src/eckit/geo/range/Gaussian.cc | 50 ----------- src/eckit/geo/range/Gaussian.h | 84 ------------------- src/eckit/geo/range/Regular.cc | 55 ------------ src/eckit/geo/range/Regular.h | 80 ------------------ tests/geo/range.cc | 3 +- 11 files changed, 102 insertions(+), 332 deletions(-) delete mode 100644 src/eckit/geo/range/Gaussian.cc delete mode 100644 src/eckit/geo/range/Gaussian.h delete mode 100644 src/eckit/geo/range/Regular.cc delete mode 100644 src/eckit/geo/range/Regular.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 7c0b4407f..32a09d69c 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -98,10 +98,6 @@ list(APPEND eckit_geo_srcs projection/None.h projection/Rotation.cc projection/Rotation.h - range/Gaussian.cc - range/Gaussian.h - range/Regular.cc - range/Regular.h spec/Custom.cc spec/Custom.h spec/Generator.h diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index a485774ff..756af7e44 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -12,7 +12,11 @@ #include "eckit/geo/Range.h" +#include + #include "eckit/exception/Exceptions.h" +#include "eckit/geo/PointLonLat.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo { @@ -25,4 +29,68 @@ Range::Range(size_t n, double eps) : } +namespace range { + + +Regular::Regular(size_t n, double a, double b, double _eps) : + Range(n, _eps), a_(a), b_(b) { + if (types::is_approximately_equal(a, b, eps())) { + b_ = a_; + endpoint_ = false; + ASSERT(n == 1); + } + else { + b = PointLonLat::normalise_angle_to_minimum(b, a + eps()); + auto inc = (b - a) / static_cast(n); + auto periodic = types::is_approximately_greater_or_equal(b - a + inc, 360.); + + endpoint_ = !periodic; + } +} + + +const std::vector& Regular::values() const { + if (values_.empty()) { + auto& v = const_cast&>(values_); + v = util::linspace(0., 360., Range::size(), false); + + auto [from, to] = util::monotonic_crop(v, a_, b_, eps()); + v.erase(v.begin() + to, v.end()); + v.erase(v.begin(), v.begin() + from); + + ASSERT(!v.empty()); + } + + return values_; +} + + +Gaussian::Gaussian(size_t N, double a, double b, double _eps) : + Range(2 * N, _eps), N_(N), a_(a), b_(b) { + ASSERT(N > 0); + + // pre-calculate on cropping + auto [min, max] = std::minmax(a_, b_); + if (!types::is_approximately_equal(min, -90., eps()) || !types::is_approximately_equal(max, 90., eps())) { + values_ = util::gaussian_latitudes(N_, a_ < b_); + auto& v = values_; + + auto [from, to] = util::monotonic_crop(v, min, max, eps()); + v.erase(v.begin() + to, v.end()); + v.erase(v.begin(), v.begin() + from); + + ASSERT(!v.empty()); + resize(v.size()); + } +} + + +const std::vector& Gaussian::values() const { + return values_.empty() ? util::gaussian_latitudes(N_, a_ < b_) : values_; +} + + +} // namespace range + + } // namespace eckit::geo diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index bafcf1161..6d272b857 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -22,87 +22,66 @@ namespace eckit::geo { class Range { public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - Range(const Range&) = delete; Range(Range&&) = delete; - // -- Destructor - virtual ~Range() = default; - // -- Convertors - // None - - // -- Operators - Range& operator=(const Range&) = delete; Range& operator=(Range&&) = delete; - // -- Methods - size_t size() const { return n_; } double eps() const { return eps_; } virtual const std::vector& values() const = 0; - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - protected: - // -- Constructors - explicit Range(size_t n, double eps = util::EPS); - // -- Members - // None + void resize(size_t n) { n_ = n; } - // -- Methods +private: + size_t n_; + const double eps_; +}; - void resize(size_t n) { n_ = n; } - // -- Overridden methods - // None +namespace range { - // -- Class members - // None - // -- Class methods - // None +class Gaussian final : public Range { +public: + explicit Gaussian(size_t N, double eps = 0.) : + Gaussian(N, 90., -90., eps) {} -private: - // -- Members + Gaussian(size_t N, double crop_a, double crop_b, double eps = 0.); - size_t n_; - const double eps_; + size_t N() const { return N_; } + const std::vector& values() const override; - // -- Methods - // None +private: + const size_t N_; + const double a_; + const double b_; + std::vector values_; +}; - // -- Overridden methods - // None - // -- Class members - // None +class Regular final : public Range { +public: + explicit Regular(size_t n, double a, double b, double eps = 0.); - // -- Class methods - // None + const std::vector& values() const override; - // -- Friends - // None +private: + double a_; + double b_; + bool endpoint_; + std::vector values_; }; +} // namespace range + + } // namespace eckit::geo diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index e7c50daf2..f89bcd2e1 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -15,8 +15,6 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Range.h" #include "eckit/geo/iterator/Reduced.h" -#include "eckit/geo/range/Gaussian.h" -#include "eckit/geo/range/Regular.h" #include "eckit/geo/spec/Custom.h" #include "eckit/utils/Translator.h" diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index 1d86ed4a0..2b7f92ec3 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -12,9 +12,8 @@ #include "eckit/geo/grid/regular/RegularGaussian.h" +#include "eckit/geo/Range.h" #include "eckit/geo/iterator/Regular.h" -#include "eckit/geo/range/Gaussian.h" -#include "eckit/geo/range/Regular.h" #include "eckit/geo/spec/Custom.h" #include "eckit/utils/Translator.h" diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index 87aa2bde3..b991e38e8 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -14,8 +14,8 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Increments.h" +#include "eckit/geo/Range.h" #include "eckit/geo/iterator/Regular.h" -#include "eckit/geo/range/Regular.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util/regex.h" #include "eckit/types/Fraction.h" diff --git a/src/eckit/geo/range/Gaussian.cc b/src/eckit/geo/range/Gaussian.cc deleted file mode 100644 index 8e9e12630..000000000 --- a/src/eckit/geo/range/Gaussian.cc +++ /dev/null @@ -1,50 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/range/Gaussian.h" - -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/util.h" -#include "eckit/types/FloatCompare.h" - - -namespace eckit::geo::range { - - -Gaussian::Gaussian(size_t N, double a, double b, double _eps) : - Range(2 * N, _eps), N_(N), a_(a), b_(b) { - ASSERT(N > 0); - - // pre-calculate on cropping - auto [min, max] = std::minmax(a_, b_); - if (!types::is_approximately_equal(min, -90., eps()) || !types::is_approximately_equal(max, 90., eps())) { - values_ = util::gaussian_latitudes(N_, a_ < b_); - auto& v = values_; - - auto [from, to] = util::monotonic_crop(v, min, max, eps()); - v.erase(v.begin() + to, v.end()); - v.erase(v.begin(), v.begin() + from); - - ASSERT(!v.empty()); - resize(v.size()); - } -} - - -const std::vector& Gaussian::values() const { - return values_.empty() ? util::gaussian_latitudes(N_, a_ < b_) : values_; -} - - -} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/Gaussian.h b/src/eckit/geo/range/Gaussian.h deleted file mode 100644 index 8f0394c1b..000000000 --- a/src/eckit/geo/range/Gaussian.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Range.h" - - -namespace eckit::geo::range { - - -class Gaussian final : public Range { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit Gaussian(size_t N, double eps = 0.) : - Gaussian(N, 90., -90., eps) {} - - Gaussian(size_t N, double crop_a, double crop_b, double eps = 0.); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - size_t N() const { return N_; } - const std::vector& values() const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - const size_t N_; - const double a_; - const double b_; - std::vector values_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc deleted file mode 100644 index ce7c0265b..000000000 --- a/src/eckit/geo/range/Regular.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/range/Regular.h" - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/PointLonLat.h" -#include "eckit/geo/util.h" -#include "eckit/types/FloatCompare.h" - - -namespace eckit::geo::range { - - -Regular::Regular(size_t n, double a, double b, double _eps) : - Range(n, _eps), a_(a), b_(b) { - if (types::is_approximately_equal(a, b, eps())) { - endpoint_ = false; - } - else { - b = PointLonLat::normalise_angle_to_minimum(b, a + eps()); - auto inc = (b - a) / static_cast(n); - auto periodic = types::is_approximately_greater_or_equal(b - a + inc, 360.); - - endpoint_ = !periodic; - } -} - - -const std::vector& Regular::values() const { - if (values_.empty()) { - auto& v = const_cast&>(values_); - v = util::linspace(0., 360., Range::size(), false); - - auto [from, to] = util::monotonic_crop(v, a_, b_, eps()); - v.erase(v.begin() + to, v.end()); - v.erase(v.begin(), v.begin() + from); - - ASSERT(!v.empty()); - } - - return values_; -} - - -} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h deleted file mode 100644 index 83c7ea3c5..000000000 --- a/src/eckit/geo/range/Regular.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Range.h" - - -namespace eckit::geo::range { - - -class Regular final : public Range { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit Regular(size_t n, double a, double b, double eps = 0.); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - const std::vector& values() const override; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - const double a_; - const double b_; - bool endpoint_; - std::vector values_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::range diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 972412c16..dc2305287 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -13,8 +13,7 @@ #include #include -#include "eckit/geo/range/Gaussian.h" -#include "eckit/geo/range/Regular.h" +#include "eckit/geo/Range.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" From c0b3aaa33c81e3713688e04865a78c61f7fbaffb Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 23 Jan 2024 09:21:58 +0000 Subject: [PATCH 441/737] eckit::geo::area::BoundingBox --- src/eckit/geo/area/BoundingBox.cc | 21 +++++++++++++-------- src/eckit/geo/area/BoundingBox.h | 10 ++++------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index cb25ab040..94cb484c3 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -27,23 +27,32 @@ namespace eckit::geo::area { -static constexpr std::array DEFAULT{90, 0, -90, 360}; +BoundingBox BoundingBox::make_global_prime() { + return {90., 0., -90., 360.}; +} + + +BoundingBox BoundingBox::make_global_antiprime() { + return {90., -180., -90., 180.}; +} static BoundingBox make_from_spec(const Spec& spec) { - if (std::vector area{DEFAULT[0], DEFAULT[1], DEFAULT[2], DEFAULT[3]}; spec.get("area", area)) { + const auto [n, w, s, e] = BoundingBox::make_global_prime().deconstruct(); + + if (std::vector area{n, w, s, e}; spec.get("area", area)) { ASSERT_MSG(area.size() == 4, "BoundingBox: 'area' expected list of size 4"); return {area[0], area[1], area[2], area[3]}; } - auto area(DEFAULT); + std::array area{n, w, s, e}; spec.get("north", area[0]); spec.get("south", area[2]); auto new_east = spec.get("west", area[1]) && !spec.has("east"); auto new_west = spec.get("east", area[3]) && !spec.has("west"); - return {area[0], new_west ? area[3] - 360 : area[1], area[2], new_east ? area[1] + 360 : area[3]}; + return {area[0], new_west ? area[3] - 360. : area[1], area[2], new_east ? area[1] + 360. : area[3]}; } @@ -68,10 +77,6 @@ BoundingBox::BoundingBox(double n, double w, double s, double e) : } -BoundingBox::BoundingBox() : - BoundingBox(DEFAULT[0], DEFAULT[1], DEFAULT[2], DEFAULT[3]) {} - - bool BoundingBox::operator==(const BoundingBox& other) const { return north == other.north && south == other.south && west == other.west && east == other.east; } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 4eb7db37c..384f9eba7 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -36,10 +36,9 @@ class BoundingBox : public Area, protected std::array { explicit BoundingBox(const Spec&); BoundingBox(double north, double west, double south, double east); - BoundingBox(double north, double west, double south) : - BoundingBox(north, west, south, west + 360.) {} - BoundingBox(); + BoundingBox() : + BoundingBox(make_global_prime()) {} BoundingBox(const BoundingBox& other) : array(other) {} @@ -83,9 +82,8 @@ class BoundingBox : public Area, protected std::array { double area(double radius) const; static BoundingBox make(const BoundingBox&, const Projection&); - - static BoundingBox make_global_prime() { return {90., 0., -90., 360.}; } - static BoundingBox make_global_antiprime() { return {90., -180., -90., 180.}; } + static BoundingBox make_global_prime(); + static BoundingBox make_global_antiprime(); // -- Overridden methods // None From 97c13540c7b589b483329c14e53ff709886e1f62 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 23 Jan 2024 10:31:48 +0000 Subject: [PATCH 442/737] eckit::geo::Grid --- src/eckit/geo/grid/regular/RegularGaussian.cc | 8 ++------ src/eckit/geo/grid/regular/RegularGaussian.h | 1 - 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index 2b7f92ec3..c3104b4f9 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -22,16 +22,12 @@ namespace eckit::geo::grid::regular { RegularGaussian::RegularGaussian(const Spec& spec) : - RegularGaussian(spec.get_unsigned("N"), spec.get_unsigned("ni"), area::BoundingBox(spec)) {} + RegularGaussian(spec.get_unsigned("N"), area::BoundingBox(spec)) {} RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : - RegularGaussian(N, 4 * N, bbox) {} - - -RegularGaussian::RegularGaussian(size_t N, size_t ni, const area::BoundingBox& bbox) : Regular(bbox), - x_(new range::Regular(ni, bbox.west, bbox.east)), + x_(new range::Regular(4 * N, bbox.west, bbox.east)), y_(new range::Gaussian(N, bbox.north, bbox.south)) { ASSERT(x_->size() > 0); ASSERT(y_->size() > 0); diff --git a/src/eckit/geo/grid/regular/RegularGaussian.h b/src/eckit/geo/grid/regular/RegularGaussian.h index cb8afdf63..f651f5184 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.h +++ b/src/eckit/geo/grid/regular/RegularGaussian.h @@ -31,7 +31,6 @@ class RegularGaussian final : public Regular { explicit RegularGaussian(const Spec&); explicit RegularGaussian(size_t N, const area::BoundingBox& = area::BoundingBox::make_global_prime()); - RegularGaussian(size_t N, size_t ni, const area::BoundingBox& = area::BoundingBox::make_global_prime()); // -- Destructor // None From 584a793411eb375806d2bcb5471e48da08930951 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 24 Jan 2024 11:19:32 +0000 Subject: [PATCH 443/737] eckit::geo::Spec --- src/eckit/geo/etc/Grid.cc | 12 ++++++------ src/eckit/geo/spec/Custom.h | 1 - src/eckit/geo/spec/Generator.h | 12 ++++++------ 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/eckit/geo/etc/Grid.cc b/src/eckit/geo/etc/Grid.cc index 28329818d..dca589729 100644 --- a/src/eckit/geo/etc/Grid.cc +++ b/src/eckit/geo/etc/Grid.cc @@ -57,12 +57,12 @@ void set_custom_value(spec::Custom& custom, const std::string& key, const Value& } -spec::Custom* config_from_value_map(const ValueMap& map) { - auto* config = new spec::Custom; +spec::Custom* spec_from_value_map(const ValueMap& map) { + auto* spec = new spec::Custom; for (const auto& kv : map) { - set_custom_value(*config, kv.first, kv.second); + set_custom_value(*spec, kv.first, kv.second); } - return config; + return spec; } @@ -103,7 +103,7 @@ Grid::Grid(const PathName& path) { for (ValueMap m : static_cast(kv.second)) { ASSERT(m.size() == 1); SpecByUID::instance().regist(m.begin()->first.as(), - new SpecByUIDGenerator(config_from_value_map(m.begin()->second))); + new SpecByUIDGenerator(spec_from_value_map(m.begin()->second))); } continue; } @@ -112,7 +112,7 @@ Grid::Grid(const PathName& path) { for (ValueMap m : static_cast(kv.second)) { ASSERT(m.size() == 1); SpecByName::instance().regist(m.begin()->first.as(), - new SpecByNameGenerator(config_from_value_map(m.begin()->second))); + new SpecByNameGenerator(spec_from_value_map(m.begin()->second))); } continue; } diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 0305cb96c..01af7817c 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -77,7 +77,6 @@ class Custom final : public Spec { void set(const std::string& name, const char* value) { set(name, std::string{value}); } - // (consistent with Configured) void set(const std::string& name, const std::string& value); void set(const std::string& name, bool value); void set(const std::string& name, int value); diff --git a/src/eckit/geo/spec/Generator.h b/src/eckit/geo/spec/Generator.h index fabd5219d..e3733643e 100644 --- a/src/eckit/geo/spec/Generator.h +++ b/src/eckit/geo/spec/Generator.h @@ -123,7 +123,7 @@ template void GeneratorT::regist(const key_t& k, generator_t* c) { lock_type lock; if (exists(k)) { - throw BadParameter("Configurator has already a builder for " + k, Here()); + throw BadParameter("Generator has already a builder for " + k, Here()); } ASSERT(c != nullptr); store_[k] = c; @@ -136,7 +136,7 @@ void GeneratorT::unregist(const key_t& k) { store_.erase(it); return; } - throw BadParameter("Configurator unknown: '" + k + "'", Here()); + throw BadParameter("Generator unknown: '" + k + "'", Here()); } template @@ -145,7 +145,7 @@ const typename GeneratorT::generator_t& GeneratorT::get(const key_t& k) co if (auto it = store_.find(k); it != store_.end()) { return *(it->second); } - throw BadParameter("Configurator unknown: '" + k + "'", Here()); + throw BadParameter("Generator unknown: '" + k + "'", Here()); } template @@ -157,7 +157,7 @@ const typename GeneratorT::generator_t& GeneratorT::match(const std::strin for (auto j = store_.cbegin(); j != end; ++j) { if (Regex(j->first).match(k)) { if (i != end) { - throw SeriousBug("Configurator name '" + k + "' matches '" + i->first + "' and '" + j->first + "'"); + throw SeriousBug("Generator name '" + k + "' matches '" + i->first + "' and '" + j->first + "'"); } i = j; } @@ -167,13 +167,13 @@ const typename GeneratorT::generator_t& GeneratorT::match(const std::strin return *(i->second); } - throw BadParameter("Configurator unknown: '" + k + "'", Here()); + throw BadParameter("Generator unknown: '" + k + "'", Here()); } template void GeneratorT::print(std::ostream& os) const { lock_type lock; - os << "Configurator" << std::endl; + os << "Generator" << std::endl; int key_width = 0; for (const auto& i : store_) { From c61d3a939aea03b916c52f3a84f2ec9e608a320e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 24 Jan 2024 15:54:49 +0000 Subject: [PATCH 444/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 1 + src/eckit/geo/Range.h | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 756af7e44..cf97bffcf 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -16,6 +16,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/PointLonLat.h" +#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 6d272b857..5bda6d47c 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -14,8 +14,6 @@ #include -#include "eckit/geo/util.h" - namespace eckit::geo { @@ -36,7 +34,7 @@ class Range { virtual const std::vector& values() const = 0; protected: - explicit Range(size_t n, double eps = util::EPS); + explicit Range(size_t n, double eps = 0.); void resize(size_t n) { n_ = n; } From ce684062316f82a693bf9dea735f2e17886efd57 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 24 Jan 2024 15:56:32 +0000 Subject: [PATCH 445/737] eckit::geo::range::Regular --- src/eckit/geo/Range.cc | 21 +++++-------------- src/eckit/geo/Range.h | 1 - src/eckit/geo/util.h | 1 - tests/geo/range.cc | 46 ++++++++++++++++++++++++++++++++++-------- 4 files changed, 43 insertions(+), 26 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index cf97bffcf..2dcc1c91d 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -35,17 +35,10 @@ namespace range { Regular::Regular(size_t n, double a, double b, double _eps) : Range(n, _eps), a_(a), b_(b) { - if (types::is_approximately_equal(a, b, eps())) { - b_ = a_; - endpoint_ = false; - ASSERT(n == 1); - } - else { - b = PointLonLat::normalise_angle_to_minimum(b, a + eps()); - auto inc = (b - a) / static_cast(n); - auto periodic = types::is_approximately_greater_or_equal(b - a + inc, 360.); - - endpoint_ = !periodic; + if (types::is_approximately_equal(a_, b_, eps())) { + resize(1); + b_ = a_; + values_ = {a_}; } } @@ -53,11 +46,7 @@ Regular::Regular(size_t n, double a, double b, double _eps) : const std::vector& Regular::values() const { if (values_.empty()) { auto& v = const_cast&>(values_); - v = util::linspace(0., 360., Range::size(), false); - - auto [from, to] = util::monotonic_crop(v, a_, b_, eps()); - v.erase(v.begin() + to, v.end()); - v.erase(v.begin(), v.begin() + from); + v = util::linspace(a_, b_, size(), true); ASSERT(!v.empty()); } diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 5bda6d47c..c8ca0fe05 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -74,7 +74,6 @@ class Regular final : public Range { private: double a_; double b_; - bool endpoint_; std::vector values_; }; diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index 11ee38371..3778dde10 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -13,7 +13,6 @@ #pragma once #include -#include #include #include #include diff --git a/tests/geo/range.cc b/tests/geo/range.cc index dc2305287..d9758685f 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -10,7 +10,6 @@ */ -#include #include #include "eckit/geo/Range.h" @@ -27,6 +26,39 @@ namespace eckit::test { using namespace geo; +constexpr auto EPS = 1e-3; + + +CASE("range::Regular") { + SECTION("degenerate") { + EXPECT_THROWS_AS(range::Regular(0, 0., 0.), eckit::AssertionFailed); + EXPECT_THROWS_AS(range::Regular(0, 0., 10.), eckit::AssertionFailed); + + range::Regular range1(1, 1., 1.); + EXPECT(range1.size() == 1); + EXPECT(range1.values().front() == 1.); + + range::Regular range2(2, 2., 2.); + EXPECT(range2.size() == 1); + EXPECT(range2.values().front() == 2.); + } + + + SECTION("global") { + const auto range = range::Regular(4, -90., 90.); + EXPECT(range.size() == 4); + + const auto& values = range.values(); + EXPECT(range.size() == values.size()); + + EXPECT_APPROX(values[0], -90., EPS); + EXPECT_APPROX(values[1], -30., EPS); + EXPECT_APPROX(values[2], 30., EPS); + EXPECT_APPROX(values[3], 90., EPS); + } +} + + CASE("range::Gaussian") { std::vector ref{59.44440828916676, 19.87571914744090, -19.87571914744090, -59.44440828916676}; @@ -43,22 +75,20 @@ CASE("range::Gaussian") { SECTION("crop [50., -50.]") { - constexpr auto eps = 1e-3; - - auto cropped = range::Gaussian(2, 50., -50., eps); + auto cropped = range::Gaussian(2, 50., -50., EPS); EXPECT(cropped.size() == ref.size() - 2); - EXPECT_APPROX(cropped.values()[0], ref[1], eps); - EXPECT_APPROX(cropped.values()[1], ref[2], eps); + EXPECT_APPROX(cropped.values()[0], ref[1], EPS); + EXPECT_APPROX(cropped.values()[1], ref[2], EPS); EXPECT(range::Gaussian(2, 59.444, -59.444, 1e-3).size() == 4); EXPECT(range::Gaussian(2, 59.444, -59.444, 1e-6).size() == 2); EXPECT(range::Gaussian(2, 59.444, -59.445, 1e-6).size() == 3); - auto single = range::Gaussian(2, -59.444, -59.444, eps); + auto single = range::Gaussian(2, -59.444, -59.444, EPS); EXPECT(single.size() == 1); - EXPECT_APPROX(single.values().front(), ref.back(), eps); + EXPECT_APPROX(single.values().front(), ref.back(), EPS); } From 4b0e5c0a590ecbb8efc1a6f66fbd8be2dc35b0f2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 24 Jan 2024 17:20:09 +0000 Subject: [PATCH 446/737] eckit::geo::Point --- tests/geo/point.cc | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tests/geo/point.cc b/tests/geo/point.cc index a3b2ddd82..3e1482db9 100644 --- a/tests/geo/point.cc +++ b/tests/geo/point.cc @@ -11,8 +11,8 @@ #include "eckit/geo/Point.h" -#include "eckit/maths/Matrix3.h" #include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" //---------------------------------------------------------------------------------------------------------------------- @@ -25,6 +25,16 @@ using namespace geo; CASE("PointLonLat normalisation") { + constexpr auto EPS = 1e-9; + constexpr auto da = 1e-3; + + for (double a = -370.; a < 370.; a += 10.) { + EXPECT(types::is_approximately_equal(a, PointLonLat::normalise_angle_to_minimum(a, a), EPS)); + EXPECT(types::is_approximately_equal(a, PointLonLat::normalise_angle_to_maximum(a, a), EPS)); + EXPECT(types::is_approximately_equal(a + 360., PointLonLat::normalise_angle_to_minimum(a - da, a) + da, EPS)); + EXPECT(types::is_approximately_equal(a - 360., PointLonLat::normalise_angle_to_maximum(a + da, a) - da, EPS)); + } + PointLonLat p(1, 90.); EXPECT_EQUAL(p.lon, 1.); EXPECT_EQUAL(p.lat, 90.); @@ -156,7 +166,7 @@ CASE("Point2 comparison") { } -CASE("Point distance comparison") { +CASE("Point2 distance comparison") { Point2 p1 = {2.0, 1.0}; Point2 p2 = {1.0, 2.0}; @@ -168,7 +178,7 @@ CASE("Point distance comparison") { } -CASE("Point distance2 comparison") { +CASE("Point2 distance2 comparison") { Point2 p1 = {2.0, 1.0}; Point2 p2 = {1.0, 2.0}; From ed143de807f7e7e536a0081b0a07a52c1d0424a9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 24 Jan 2024 17:32:04 +0000 Subject: [PATCH 447/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 40 ++++++++++++++++++++++++++++++++++++++++ src/eckit/geo/Range.h | 14 ++++++++++++++ tests/geo/range.cc | 32 +++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 2dcc1c91d..e176343d8 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -13,6 +13,7 @@ #include "eckit/geo/Range.h" #include +#include #include "eckit/exception/Exceptions.h" #include "eckit/geo/PointLonLat.h" @@ -55,6 +56,45 @@ const std::vector& Regular::values() const { } +RegularPeriodic::RegularPeriodic(size_t n, double a, double b, double _eps) : + Range(n, _eps), a_(a), b_(b) { + if (types::is_approximately_equal(a_, b_, eps())) { + resize(1); + b_ = a_; + endpoint_ = false; + values_ = {a_}; + } + else { + auto plus = a_ < b_; + auto n = + plus ? PointLonLat::normalise_angle_to_minimum(b_, a_) : PointLonLat::normalise_angle_to_maximum(b_, a_); + + b_ = types::is_approximately_equal(n, a_, eps()) ? a_ + (plus ? 360. : -360.) : n; + ASSERT(!types::is_approximately_equal(a_, b_, eps())); + + auto inc = (b_ - a_) / static_cast(size()); + endpoint_ = + plus ? types::is_strictly_greater(360., b_ - a_ + inc) : types::is_strictly_greater(b_ - a_ + inc, -360.); + } +} + + +const std::vector& RegularPeriodic::values() const { + if (values_.empty()) { + auto& v = const_cast&>(values_); + v = util::linspace(a_, b_, Range::size(), false); + + auto [from, to] = util::monotonic_crop(v, a_, b_, eps()); + v.erase(v.begin() + to, v.end()); + v.erase(v.begin(), v.begin() + from); + + ASSERT(!v.empty()); + } + + return values_; +} + + Gaussian::Gaussian(size_t N, double a, double b, double _eps) : Range(2 * N, _eps), N_(N), a_(a), b_(b) { ASSERT(N > 0); diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index c8ca0fe05..dd07a7db9 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -78,6 +78,20 @@ class Regular final : public Range { }; +class RegularPeriodic final : public Range { +public: + explicit RegularPeriodic(size_t n, double a, double b, double eps = 0.); + + const std::vector& values() const override; + +private: + double a_; + double b_; + bool endpoint_; + std::vector values_; +}; + + } // namespace range diff --git a/tests/geo/range.cc b/tests/geo/range.cc index d9758685f..4554d5f10 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -45,7 +45,7 @@ CASE("range::Regular") { SECTION("global") { - const auto range = range::Regular(4, -90., 90.); + const range::Regular range(4, -90., 90.); EXPECT(range.size() == 4); const auto& values = range.values(); @@ -59,6 +59,36 @@ CASE("range::Regular") { } +CASE("range::RegularPeriodic") { + SECTION("degenerate") { + EXPECT_THROWS_AS(range::RegularPeriodic(0, 0., 0.), eckit::AssertionFailed); + EXPECT_THROWS_AS(range::RegularPeriodic(0, 0., 10.), eckit::AssertionFailed); + + range::RegularPeriodic range1(1, 1., 1.); + EXPECT(range1.size() == 1); + EXPECT(range1.values().front() == 1.); + + range::RegularPeriodic range2(2, 2., 2.); + EXPECT(range2.size() == 1); + EXPECT(range2.values().front() == 2.); + } + + + SECTION("global") { + const range::RegularPeriodic range(4, -180., 180.); + EXPECT(range.size() == 4); + + const auto& values = range.values(); + EXPECT(range.size() == values.size()); + + EXPECT_APPROX(values[0], -180., EPS); + EXPECT_APPROX(values[1], -90., EPS); + EXPECT_APPROX(values[2], 0., EPS); + EXPECT_APPROX(values[3], 90., EPS); + } +} + + CASE("range::Gaussian") { std::vector ref{59.44440828916676, 19.87571914744090, -19.87571914744090, -59.44440828916676}; From bd18b9534e0b9989c0dd0efd1180250e0fb5dc5f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 24 Jan 2024 22:21:20 +0000 Subject: [PATCH 448/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 47 ++++++++++++++++++++++++------------------ tests/geo/range.cc | 28 ++++++++++++++++++------- 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index e176343d8..6e696977c 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -13,17 +13,20 @@ #include "eckit/geo/Range.h" #include -#include #include "eckit/exception/Exceptions.h" #include "eckit/geo/PointLonLat.h" #include "eckit/geo/util.h" +#include "eckit/geo/util/mutex.h" #include "eckit/types/FloatCompare.h" namespace eckit::geo { +util::recursive_mutex MUTEX; + + Range::Range(size_t n, double eps) : n_(n), eps_(eps) { ASSERT(n > 0); @@ -45,11 +48,11 @@ Regular::Regular(size_t n, double a, double b, double _eps) : const std::vector& Regular::values() const { - if (values_.empty()) { - auto& v = const_cast&>(values_); - v = util::linspace(a_, b_, size(), true); + util::lock_guard lock(MUTEX); - ASSERT(!v.empty()); + if (values_.empty()) { + const_cast&>(values_) = util::linspace(a_, b_, Range::size(), true); + ASSERT(!values_.empty()); } return values_; @@ -64,31 +67,33 @@ RegularPeriodic::RegularPeriodic(size_t n, double a, double b, double _eps) : endpoint_ = false; values_ = {a_}; } + else if (a_ < b_) { + auto n = PointLonLat::normalise_angle_to_minimum(b_, a_); + + b_ = types::is_approximately_equal(n, a_, eps()) ? a_ + 360. : n; + ASSERT(!types::is_approximately_equal(a_, b_, eps())); + + auto inc = (b_ - a_) / static_cast(size()); + endpoint_ = types::is_strictly_greater(360., b_ - a_ + inc); + } else { - auto plus = a_ < b_; - auto n = - plus ? PointLonLat::normalise_angle_to_minimum(b_, a_) : PointLonLat::normalise_angle_to_maximum(b_, a_); + auto n = PointLonLat::normalise_angle_to_maximum(b_, a_); - b_ = types::is_approximately_equal(n, a_, eps()) ? a_ + (plus ? 360. : -360.) : n; + b_ = types::is_approximately_equal(n, a_, eps()) ? a_ - 360. : n; ASSERT(!types::is_approximately_equal(a_, b_, eps())); - auto inc = (b_ - a_) / static_cast(size()); - endpoint_ = - plus ? types::is_strictly_greater(360., b_ - a_ + inc) : types::is_strictly_greater(b_ - a_ + inc, -360.); + auto inc = (b_ - a_) / static_cast(size()); + endpoint_ = types::is_strictly_greater(b_ - a_ + inc, -360.); } } const std::vector& RegularPeriodic::values() const { - if (values_.empty()) { - auto& v = const_cast&>(values_); - v = util::linspace(a_, b_, Range::size(), false); - - auto [from, to] = util::monotonic_crop(v, a_, b_, eps()); - v.erase(v.begin() + to, v.end()); - v.erase(v.begin(), v.begin() + from); + util::lock_guard lock(MUTEX); - ASSERT(!v.empty()); + if (values_.empty()) { + const_cast&>(values_) = util::linspace(a_, b_, Range::size(), false); + ASSERT(!values_.empty()); } return values_; @@ -116,6 +121,8 @@ Gaussian::Gaussian(size_t N, double a, double b, double _eps) : const std::vector& Gaussian::values() const { + util::lock_guard lock(MUTEX); + return values_.empty() ? util::gaussian_latitudes(N_, a_ < b_) : values_; } diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 4554d5f10..520cbf3e1 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -75,16 +75,28 @@ CASE("range::RegularPeriodic") { SECTION("global") { - const range::RegularPeriodic range(4, -180., 180.); - EXPECT(range.size() == 4); + const range::RegularPeriodic range1(4, -180., 180.); + EXPECT(range1.size() == 4); - const auto& values = range.values(); - EXPECT(range.size() == values.size()); + const auto& values1 = range1.values(); + EXPECT(range1.size() == values1.size()); - EXPECT_APPROX(values[0], -180., EPS); - EXPECT_APPROX(values[1], -90., EPS); - EXPECT_APPROX(values[2], 0., EPS); - EXPECT_APPROX(values[3], 90., EPS); + EXPECT_APPROX(values1[0], -180., EPS); + EXPECT_APPROX(values1[1], -90., EPS); + EXPECT_APPROX(values1[2], 0., EPS); + EXPECT_APPROX(values1[3], 90., EPS); + + const range::RegularPeriodic range2(8, 180., -180.); + EXPECT(range2.size() == 8); + + const auto& values2 = range2.values(); + EXPECT(range2.size() == values2.size()); + + EXPECT_APPROX(values2[0], 180., EPS); + EXPECT_APPROX(values2[1], 135., EPS); + EXPECT_APPROX(values2[2], 90., EPS); + EXPECT_APPROX(values2[3], 45., EPS); + EXPECT_APPROX(values2[7], -135., EPS); } } From 95cc316e5558f48f2fa27a56af01ff0fd94ee605 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 24 Jan 2024 23:07:55 +0000 Subject: [PATCH 449/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 6e696977c..d1d804f99 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -61,6 +61,8 @@ const std::vector& Regular::values() const { RegularPeriodic::RegularPeriodic(size_t n, double a, double b, double _eps) : Range(n, _eps), a_(a), b_(b) { + constexpr auto db = 1e-12; + if (types::is_approximately_equal(a_, b_, eps())) { resize(1); b_ = a_; @@ -68,20 +70,12 @@ RegularPeriodic::RegularPeriodic(size_t n, double a, double b, double _eps) : values_ = {a_}; } else if (a_ < b_) { - auto n = PointLonLat::normalise_angle_to_minimum(b_, a_); - - b_ = types::is_approximately_equal(n, a_, eps()) ? a_ + 360. : n; - ASSERT(!types::is_approximately_equal(a_, b_, eps())); - + b_ = PointLonLat::normalise_angle_to_minimum(b_ - db, a_) + db; auto inc = (b_ - a_) / static_cast(size()); endpoint_ = types::is_strictly_greater(360., b_ - a_ + inc); } else { - auto n = PointLonLat::normalise_angle_to_maximum(b_, a_); - - b_ = types::is_approximately_equal(n, a_, eps()) ? a_ - 360. : n; - ASSERT(!types::is_approximately_equal(a_, b_, eps())); - + b_ = PointLonLat::normalise_angle_to_maximum(b_ + db, a_) - db; auto inc = (b_ - a_) / static_cast(size()); endpoint_ = types::is_strictly_greater(b_ - a_ + inc, -360.); } From 6846d810f59c7e63f2d3794d1d911fbca27d0025 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 26 Jan 2024 11:30:37 +0000 Subject: [PATCH 450/737] eckit::geo::Point --- src/eckit/geo/Point2.cc | 4 ---- src/eckit/geo/Point2.h | 2 -- src/eckit/geo/Point3.cc | 2 -- src/eckit/geo/Point3.h | 2 -- src/eckit/geo/PointLonLat.cc | 9 --------- src/eckit/geo/PointLonLat.h | 6 ++++-- 6 files changed, 4 insertions(+), 21 deletions(-) diff --git a/src/eckit/geo/Point2.cc b/src/eckit/geo/Point2.cc index 6c32315c8..a57ecdd3d 100644 --- a/src/eckit/geo/Point2.cc +++ b/src/eckit/geo/Point2.cc @@ -24,10 +24,6 @@ bool points_equal(const Point2& a, const Point2& b) { return eckit::types::is_approximately_equal(Point2::distance2(a, b), 0.0); } -bool operator<(const Point2& a, const Point2& b) { - return eckit::types::is_approximately_equal(Point2::distance2(a, b), 0.0); -} - Point2::operator Value() const { return Value::makeList(std::vector{x_[XX], x_[YY]}); } diff --git a/src/eckit/geo/Point2.h b/src/eckit/geo/Point2.h index b46ccdbb7..67ab906eb 100644 --- a/src/eckit/geo/Point2.h +++ b/src/eckit/geo/Point2.h @@ -96,8 +96,6 @@ class Point2 : public KPoint<2> { bool points_equal(const Point2&, const Point2&); -bool operator<(const Point2&, const Point2&); - //------------------------------------------------------------------------------------------------------ } // namespace eckit::geo diff --git a/src/eckit/geo/Point3.cc b/src/eckit/geo/Point3.cc index b48eada4c..bc4a83318 100644 --- a/src/eckit/geo/Point3.cc +++ b/src/eckit/geo/Point3.cc @@ -24,8 +24,6 @@ bool points_equal(const Point3& a, const Point3& b) { types::is_approximately_equal(a.Z, b.Z, eps); } -bool operator<(const Point3& a, const Point3& b) {} - //---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geo diff --git a/src/eckit/geo/Point3.h b/src/eckit/geo/Point3.h index d80887a95..8b5c4f26d 100644 --- a/src/eckit/geo/Point3.h +++ b/src/eckit/geo/Point3.h @@ -89,8 +89,6 @@ class Point3 : public KPoint<3> { bool points_equal(const Point3&, const Point3&); -bool operator<(const Point3&, const Point3&); - //------------------------------------------------------------------------------------------------------ } // namespace eckit::geo diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index 069cc08ff..4528ab526 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -51,13 +51,4 @@ bool points_equal(const PointLonLat& a, const PointLonLat& b) { } -bool operator<(const PointLonLat& a, const PointLonLat& b) { - if (types::is_approximately_equal(a.lon, b.lon) || types::is_approximately_equal(a.lat, b.lat)) { - return false; - } - - return a.lon < b.lon && a.lat < b.lat; -} - - } // namespace eckit::geo diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index 30a2d8818..c5b47ec7b 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -120,10 +120,12 @@ class PointLonLat final : protected std::array { friend PointLonLat operator+(const PointLonLat& p, const PointLonLat& q) { return {p.lon + q.lon, p.lat + q.lat}; } friend PointLonLat operator*(const PointLonLat& p, double d) { return {p.lon * d, p.lat * d}; } + + friend bool operator<(const PointLonLat& p, const PointLonLat& q) { + return static_cast(p) < static_cast(q); + } }; bool points_equal(const PointLonLat&, const PointLonLat&); -bool operator<(const PointLonLat&, const PointLonLat&); - } // namespace eckit::geo From b90100b4108ff09f8b7362c6075fe95e97d5c2a8 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 26 Jan 2024 14:14:22 +0000 Subject: [PATCH 451/737] eckit::geo::Point --- src/eckit/geo/Point.cc | 4 ++-- src/eckit/geo/Point.h | 12 +++++++----- src/eckit/geo/Point2.cc | 4 ++-- src/eckit/geo/Point2.h | 2 +- src/eckit/geo/Point3.cc | 3 +-- src/eckit/geo/Point3.h | 2 +- src/eckit/geo/PointLonLat.cc | 7 +++---- src/eckit/geo/PointLonLat.h | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/eckit/geo/Point.cc b/src/eckit/geo/Point.cc index 4ff741b5a..669fedc34 100644 --- a/src/eckit/geo/Point.cc +++ b/src/eckit/geo/Point.cc @@ -20,9 +20,9 @@ namespace eckit::geo { -bool points_equal(const Point& p, const Point& q) { +bool points_equal(const Point& p, const Point& q, double eps) { ASSERT(p.index() == q.index()); - return std::visit([&](const auto& p, const auto& q) { return points_equal(p, q); }, p, q); + return std::visit([&](const auto& p, const auto& q) { return points_equal(p, q, eps); }, p, q); } diff --git a/src/eckit/geo/Point.h b/src/eckit/geo/Point.h index 91dd3e436..fcf75f20d 100644 --- a/src/eckit/geo/Point.h +++ b/src/eckit/geo/Point.h @@ -25,15 +25,17 @@ namespace eckit::geo { using Point = std::variant; -bool points_equal(const Point&, const Point&); +bool points_equal(const Point&, const Point&, double eps = 1.e-9); std::ostream& operator<<(std::ostream&, const Point&); -constexpr double GLOBE = 360.; -constexpr double GREENWICH = 0.; -constexpr double NORTH_POLE = 90.; -constexpr double SOUTH_POLE = -90.; +constexpr double GLOBE = 360.; +constexpr double GREENWICH = 0.; +constexpr double ANTIMERIDIAN = -180.; +constexpr double EQUATOR = 0.; +constexpr double NORTH_POLE = 90.; +constexpr double SOUTH_POLE = -90.; // FIXME remove diff --git a/src/eckit/geo/Point2.cc b/src/eckit/geo/Point2.cc index a57ecdd3d..07a68e287 100644 --- a/src/eckit/geo/Point2.cc +++ b/src/eckit/geo/Point2.cc @@ -20,8 +20,8 @@ namespace eckit::geo { //---------------------------------------------------------------------------------------------------------------------- -bool points_equal(const Point2& a, const Point2& b) { - return eckit::types::is_approximately_equal(Point2::distance2(a, b), 0.0); +bool points_equal(const Point2& a, const Point2& b, double eps) { + return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps); } Point2::operator Value() const { diff --git a/src/eckit/geo/Point2.h b/src/eckit/geo/Point2.h index 67ab906eb..a13f1d5d5 100644 --- a/src/eckit/geo/Point2.h +++ b/src/eckit/geo/Point2.h @@ -94,7 +94,7 @@ class Point2 : public KPoint<2> { //------------------------------------------------------------------------------------------------------ -bool points_equal(const Point2&, const Point2&); +bool points_equal(const Point2&, const Point2&, double eps = 1.e-9); //------------------------------------------------------------------------------------------------------ diff --git a/src/eckit/geo/Point3.cc b/src/eckit/geo/Point3.cc index bc4a83318..9e3dc90dd 100644 --- a/src/eckit/geo/Point3.cc +++ b/src/eckit/geo/Point3.cc @@ -18,8 +18,7 @@ namespace eckit::geo { //---------------------------------------------------------------------------------------------------------------------- -bool points_equal(const Point3& a, const Point3& b) { - auto eps = 1e-6; +bool points_equal(const Point3& a, const Point3& b, double eps) { return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps) && types::is_approximately_equal(a.Z, b.Z, eps); } diff --git a/src/eckit/geo/Point3.h b/src/eckit/geo/Point3.h index 8b5c4f26d..f4c4b77b3 100644 --- a/src/eckit/geo/Point3.h +++ b/src/eckit/geo/Point3.h @@ -87,7 +87,7 @@ class Point3 : public KPoint<3> { //------------------------------------------------------------------------------------------------------ -bool points_equal(const Point3&, const Point3&); +bool points_equal(const Point3&, const Point3&, double eps = 1.e-9); //------------------------------------------------------------------------------------------------------ diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index 4528ab526..88ada52de 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -40,13 +40,12 @@ double PointLonLat::normalise_angle_to_maximum(double a, double maximum) { } -bool points_equal(const PointLonLat& a, const PointLonLat& b) { +bool points_equal(const PointLonLat& a, const PointLonLat& b, double eps) { // FIXME // solved {180., 0.} == {-180., 0.} // could be more performant - auto c = PointLonLat::make(a.lon, a.lat); - auto d = PointLonLat::make(b.lon, b.lat); - auto eps = 1e-6; + auto c = PointLonLat::make(a.lon, a.lat); + auto d = PointLonLat::make(b.lon, b.lat); return types::is_approximately_equal(c.lon, d.lon, eps) && types::is_approximately_equal(c.lat, d.lat, eps); } diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index c5b47ec7b..5dc9ca39a 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -126,6 +126,6 @@ class PointLonLat final : protected std::array { } }; -bool points_equal(const PointLonLat&, const PointLonLat&); +bool points_equal(const PointLonLat&, const PointLonLat&, double eps = 1.e-9); } // namespace eckit::geo From fd7b7eb55558a53b8d6c6c149cf2b0865be53196 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 26 Jan 2024 14:32:01 +0000 Subject: [PATCH 452/737] eckit::geo::Projection --- src/eckit/geo/projection/None.cc | 29 +++++++++++++- src/eckit/geo/projection/None.h | 68 +++++++++++++++++++++++++------- 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index 7739cc0dd..02aa1f79b 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -21,11 +21,36 @@ namespace eckit::geo::projection { static ProjectionBuilder __projection1(""); static ProjectionBuilder __projection2("none"); static ProjectionBuilder __projection3("equirectangular"); -static ProjectionBuilder __projection4("plate-carree"); +static ProjectionBuilder __projection4("plate-carree"); + + +None::None() : + fwd_(new NoPointConversion), inv_(new NoPointConversion) {} + + +None::None(const std::string& source, const std::string& target) : + fwd_(new_point_conversion(source, target)), inv_(new_point_conversion(target, source)) {} + + +None::None(const Spec& spec) : + None(spec.get_string("source", "xy"), spec.get_string("target", "xy")) {} Spec* None::spec() const { - return new spec::Custom{}; + return new spec::Custom({{"type", "none"}, {"source", "xy"}, {"target", "lonlat"}}); +} + + +None::Implementation* None::new_point_conversion(const std::string& source, const std::string& target) { + ASSERT(source == "xy" || source == "lonlat"); + return source == "xy" && target == "lonlat" ? static_cast(new Point2ToPointLonLat) + : source == "lonlat" && target == "xy" ? static_cast(new PointLonLatToPoint2) + : new NoPointConversion; +} + + +Spec* PlateCaree::spec() const { + return new spec::Custom({{"type", "plate-carree"}}); } diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index 9049acefd..5e428caa5 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -12,13 +12,15 @@ #pragma once +#include + #include "eckit/geo/Projection.h" namespace eckit::geo::projection { -class None final : public Projection { +class None : public Projection { public: // -- Types // None @@ -28,8 +30,9 @@ class None final : public Projection { // -- Constructors - None() = default; - explicit None(const Spec&) {} + explicit None(); + explicit None(const std::string& source, const std::string& target); + explicit None(const Spec&); // -- Destructor // None @@ -54,33 +57,70 @@ class None final : public Projection { // None private: + // -- Types + + struct Implementation { + Implementation() = default; + virtual ~Implementation() = default; + + Implementation(const Implementation&) = delete; + Implementation(Implementation&&) = delete; + void operator=(const Implementation&) = delete; + void operator=(Implementation&&) = delete; + + virtual Point operator()(const Point&) const = 0; + }; + + struct NoPointConversion final : Implementation { + Point operator()(const Point& p) const override { return p; } + }; + + struct Point2ToPointLonLat final : Implementation { + Point operator()(const Point& p) const override { + const auto& q = std::get(p); + return PointLonLat{q.X, q.Y}; + } + }; + + struct PointLonLatToPoint2 final : Implementation { + Point operator()(const Point& p) const override { + const auto& q = std::get(p); + return Point2{q.lon, q.lat}; + } + }; + // -- Members - // None + + std::unique_ptr fwd_; + std::unique_ptr inv_; // -- Methods // None // -- Overridden methods - Point fwd(const Point& p) const override { - const auto& q = std::get(p); - return Point2{q.lon, q.lat}; - } - - Point inv(const Point& q) const override { - const auto& p = std::get(q); - return PointLonLat{p.X, p.Y}; - } + Point fwd(const Point& p) const override { return (*fwd_)(p); } + Point inv(const Point& q) const override { return (*inv_)(q); } // -- Class members // None // -- Class methods - // None + + static Implementation* new_point_conversion(const std::string& source, const std::string& target); // -- Friends // None }; +struct PlateCaree final : None { + explicit PlateCaree() : + None("xy", "lonlat") {} + explicit PlateCaree(const Spec&) : + PlateCaree() {} + Spec* spec() const override; +}; + + } // namespace eckit::geo::projection From 1586c23a7292723c47ec1420c2357e8f762318e8 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 26 Jan 2024 14:32:05 +0000 Subject: [PATCH 453/737] eckit::geo::Projection --- tests/geo/projection.cc | 353 ++++++++++++++++++++-------------------- 1 file changed, 177 insertions(+), 176 deletions(-) diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index e8a5137fd..beba54dc1 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -28,93 +28,97 @@ namespace eckit::test { using namespace geo; +using P = std::unique_ptr; -CASE("projection") { - using P = std::unique_ptr; +CASE("projection: none") { Point p = PointLonLat{1, 1}; + P projection(ProjectionFactory::instance().get("none").create(spec::Custom{})); + EXPECT(points_equal(p, projection->inv(p))); + EXPECT(points_equal(p, projection->fwd(p))); +} - SECTION("projection type: none") { - P projection(ProjectionFactory::instance().get("none").create(spec::Custom{})); - EXPECT(points_equal(p, projection->inv(p))); - EXPECT(points_equal(p, projection->fwd(p))); - } +CASE("projection: rotation") { + spec::Custom spec({ + {"projection", "rotation"}, + {"south_pole_lat", -91.}, + {"south_pole_lon", -361.}, + }); - SECTION("projection type: rotation") { - spec::Custom spec({ - {"projection", "rotation"}, - {"south_pole_lat", -91.}, - {"south_pole_lon", -361.}, - }); + Point p = PointLonLat{1, 1}; + P projection(ProjectionFactory::instance().get(spec.get_string("projection")).create(spec)); + + EXPECT(points_equal(p, projection->inv(projection->fwd(p)))); + EXPECT(points_equal(p, projection->fwd(projection->inv(p)))); +} - P projection(ProjectionFactory::instance().get(spec.get_string("projection")).create(spec)); - EXPECT(points_equal(p, projection->inv(projection->fwd(p)))); - EXPECT(points_equal(p, projection->fwd(projection->inv(p)))); +CASE("projection: ll_to_xyz") { + Point p = PointLonLat{1, 1}; + P s1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"R", 1.}}))); + P s2(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 1.}}))); + P s3(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 0.5}}))); + + EXPECT(points_equal(p, s1->inv(s1->fwd(p)))); + EXPECT(points_equal(p, s2->inv(s2->fwd(p)))); + EXPECT(points_equal(s1->fwd(p), s2->fwd(p))); + + Point q = PointLonLat{1, 0}; + + EXPECT(points_equal(s1->fwd(q), s3->fwd(q))); + EXPECT(points_equal(s2->fwd(q), s3->fwd(q))); + + struct { + PointLonLat a; + Point3 b; + } tests[] = { + {{0, 0}, {1, 0, 0}}, + {{90, 0}, {0, 1, 0}}, + {{180, 0}, {-1, 0, 0}}, + {{270, 0}, {0, -1, 0}}, + {{0, -90}, {0, 0, -0.5}}, + {{42, -90}, {0, 0, -0.5}}, + {{0, 90}, {0, 0, 0.5}}, + {{42, 90}, {0, 0, 0.5}}, + }; + + for (const auto& test : tests) { + EXPECT(points_equal(s3->fwd(test.a), test.b)); } +} - SECTION("projection type: ll_to_xyz") { - P s1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"R", 1.}}))); - P s2(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 1.}}))); - P s3(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 0.5}}))); +CASE("projection: ll_to_xyz") { + const PointLonLat p(723., 1.); // <- FIXME - EXPECT(points_equal(p, s1->inv(s1->fwd(p)))); - EXPECT(points_equal(p, s2->inv(s2->fwd(p)))); - EXPECT(points_equal(s1->fwd(p), s2->fwd(p))); + projection::LonLatToXYZ to_xyz_r(1.); - Point q = PointLonLat{1, 0}; + auto q = to_xyz_r.fwd(p); + auto r = to_xyz_r.inv(q); + std::cout << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; - EXPECT(points_equal(s1->fwd(q), s3->fwd(q))); - EXPECT(points_equal(s2->fwd(q), s3->fwd(q))); + EXPECT(points_equal(p, r)); - struct { - PointLonLat a; - Point3 b; - } tests[] = { - {{0, 0}, {1, 0, 0}}, - {{90, 0}, {0, 1, 0}}, - {{180, 0}, {-1, 0, 0}}, - {{270, 0}, {0, -1, 0}}, - {{0, -90}, {0, 0, -0.5}}, - {{42, -90}, {0, 0, -0.5}}, - {{0, 90}, {0, 0, 0.5}}, - {{42, 90}, {0, 0, 0.5}}, - }; + // oblate spheroid (supported) + projection::LonLatToXYZ to_xyz_ab(3., 2.); - for (const auto& test : tests) { - EXPECT(points_equal(s3->fwd(test.a), test.b)); - } + for (const auto& lon : {0., 90., 180., 270.}) { + PointLonLat p{lon, 0.}; + std::cout << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) << std::endl; } + // problate spheroid (not supported) + EXPECT_THROWS(projection::LonLatToXYZ(2., 3.)); +} - SECTION("projection type: ll_to_xyz") { - const PointLonLat p(723., 1.); // <- FIXME - - projection::LonLatToXYZ to_xyz_r(1.); - - auto q = to_xyz_r.fwd(p); - auto r = to_xyz_r.inv(q); - std::cout << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; - - EXPECT(points_equal(p, r)); - - // oblate spheroid (supported) - projection::LonLatToXYZ to_xyz_ab(3., 2.); - for (const auto& lon : {0., 90., 180., 270.}) { - PointLonLat p{lon, 0.}; - std::cout << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) << std::endl; - } +CASE("projection: rotation") { + constexpr double eps = 1e-6; - // problate spheroid (not supported) - EXPECT_THROWS(projection::LonLatToXYZ(2., 3.)); - } - - SECTION("projection type: rotation") { + SECTION("rotation (1)") { const PointLonLat p(1, 1); int delta[] = {-360, -180, -1, 0, 1, 90, 91, 180}; @@ -126,22 +130,21 @@ CASE("projection") { static_cast(c)); EXPECT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); - EXPECT(points_equal(p, rot.inv(rot.fwd(p)))); - EXPECT(points_equal(p, rot.fwd(rot.inv(p)))); + EXPECT(points_equal(p, rot.inv(rot.fwd(p)), eps)); + EXPECT(points_equal(p, rot.fwd(rot.inv(p)), eps)); } } } } -#if 0 - SECTION("projection type: rotation") { + SECTION("rotation (2)") { const int Ni = 12; const int Nj = 3; projection::Rotation rot(182., -46.7, 0.); const PointLonLat ref[]{ - {-178., -46.7}, + {-178., -46.7}, // {-178., -16.7}, {-178., 13.3}, {-178., 43.3}, @@ -149,39 +152,39 @@ CASE("projection") { {2., 76.7}, {2., 46.7}, {-178., -46.7}, - {-162.62343, -19.46929}, - {-152.02366, 8.65459}, - {-139.57464, 36.43683}, - {-113.10894, 61.43199}, - {-39.88245, 68.00825}, + {-162.623427, -19.469294}, + {-152.023657, 8.654593}, + {-139.574639, 36.436827}, + {-113.108943, 61.431994}, + {-39.882454, 68.008245}, {2., 46.7}, {-178., -46.7}, - {-148.83443, -27.31067}, - {-129.26346, -3.837}, - {-110.79116, 20.05422}, - {-85.87917, 41.36507}, - {-44.42496, 53.29508}, + {-148.834426, -27.310675}, + {-129.263456, -3.837005}, + {-110.791162, 20.054216}, + {-85.879167, 41.365070}, + {-44.424956, 53.295076}, {2., 46.7}, {-178., -46.7}, - {-137.90794, -39.07002}, - {-109.60146, -21.33906}, + {-137.907940, -39.070023}, + {-109.601456, -21.339065}, {-88., 0.}, - {-66.39854, 21.33906}, - {-38.09206, 39.07002}, + {-66.398544, 21.339065}, + {-38.092060, 39.070023}, {2., 46.7}, {-178., -46.7}, - {-131.57504, -53.29508}, - {-90.12083, -41.36507}, - {-65.20884, -20.05422}, - {-46.73654, 3.837}, - {-27.16557, 27.31067}, + {-131.575044, -53.295076}, + {-90.120833, -41.365070}, + {-65.208838, -20.054216}, + {-46.736544, 3.837005}, + {-27.165574, 27.310675}, {2., 46.7}, {-178., -46.7}, - {-136.11755, -68.00825}, - {-62.89106, -61.43199}, - {-36.42536, -36.43683}, - {-23.97634, -8.65459}, - {-13.37657, 19.46929}, + {-136.117546, -68.008245}, + {-62.891057, -61.431994}, + {-36.425361, -36.436827}, + {-23.976343, -8.654593}, + {-13.376573, 19.469294}, {2., 46.7}, {-178., -46.7}, {-178., -76.7}, @@ -191,39 +194,39 @@ CASE("projection") { {2., 16.7}, {2., 46.7}, {-178., -46.7}, - {140.11755, -68.00825}, - {66.89106, -61.43199}, - {40.42536, -36.43683}, - {27.97634, -8.65459}, - {17.37657, 19.46929}, + {140.117546, -68.008245}, + {66.891057, -61.431994}, + {40.425361, -36.436827}, + {27.976343, -8.654593}, + {17.376573, 19.469294}, {2., 46.7}, {-178., -46.7}, - {135.57504, -53.29508}, - {94.12083, -41.36507}, - {69.20884, -20.05422}, - {50.73654, 3.837}, - {31.16557, 27.31067}, + {135.575044, -53.295076}, + {94.120833, -41.365070}, + {69.208838, -20.054216}, + {50.736544, 3.837005}, + {31.165574, 27.310675}, {2., 46.7}, {-178., -46.7}, - {141.90794, -39.07002}, - {113.60146, -21.33906}, + {141.907940, -39.070023}, + {113.601456, -21.339065}, {92., 0.}, - {70.39854, 21.33906}, - {42.09206, 39.07002}, + {70.398544, 21.339065}, + {42.092060, 39.070023}, {2., 46.7}, {-178., -46.7}, - {152.83443, -27.31067}, - {133.26346, -3.837}, - {114.79116, 20.05422}, - {89.87917, 41.36507}, - {48.42496, 53.29508}, + {152.834426, -27.310675}, + {133.263456, -3.837005}, + {114.791162, 20.054216}, + {89.879167, 41.365070}, + {48.424956, 53.295076}, {2., 46.7}, {-178., -46.7}, - {166.62343, -19.46929}, - {156.02366, 8.65459}, - {143.57464, 36.43683}, - {117.10894, 61.43199}, - {43.88245, 68.00825}, + {166.623427, -19.469294}, + {156.023657, 8.654593}, + {143.574639, 36.436827}, + {117.108943, 61.431994}, + {43.882454, 68.008245}, {2., 46.7}, }; @@ -234,15 +237,14 @@ CASE("projection") { auto b = rot.fwd(a); auto c = rot.inv(b); - EXPECT(points_equal(b, ref[k])); - EXPECT(points_equal(a, c)); + EXPECT(points_equal(b, ref[k], eps)); + EXPECT(points_equal(a, c, eps)); } } } -#endif - SECTION("projection type: rotation") { + SECTION("rotation (3)") { const projection::Rotation non_rotated(0., -90., 0.); const projection::Rotation rotation_angle(0., -90., -180.); const projection::Rotation rotation_matrix(4., -40., 180.); @@ -274,88 +276,87 @@ CASE("projection") { for (const auto& test : tests) { auto b = test.rotation.fwd(test.a); - EXPECT(points_equal(b, test.b)); + EXPECT(points_equal(b, test.b, eps)); auto a = test.rotation.inv(b); - EXPECT(points_equal(a, test.a)); + EXPECT(points_equal(a, test.a, eps)); } } +} - SECTION("projection type: proj") { - if (ProjectionFactory::instance().exists("proj")) { - std::cout.precision(14); +CASE("projection: proj") { + constexpr double eps = 1e-6; - PointLonLat a{12., 55.}; - struct { - const Point b; - const std::string target; - } tests[] = { - {Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, - {Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, - {a, "EPSG:4326"}, - {a, "EPSG:4979"}, - {Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, - {Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, "+proj=cart +R=6371229."}, - {Point3{3574399.5431832, 759762.07693392, 5218815.216709}, "+proj=cart +ellps=sphere"}, - {a, "+proj=latlon +ellps=sphere"}, - }; + if (ProjectionFactory::instance().exists("proj")) { + std::cout.precision(14); - for (const auto& test : tests) { - P projection(ProjectionFactory::instance().get("proj").create( - spec::Custom{{{"source", "EPSG:4326"}, {"target", test.target}}})); + PointLonLat a{12., 55.}; -#if 0 - std::cout << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) - << std::endl; -#endif + struct { + const Point b; + const std::string target; + } tests[] = { + {Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, + {Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, + {a, "EPSG:4326"}, + {a, "EPSG:4979"}, + {Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, + {Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, "+proj=cart +R=6371229."}, + {Point3{3574399.5431832, 759762.07693392, 5218815.216709}, "+proj=cart +ellps=sphere"}, + {a, "+proj=latlon +ellps=sphere"}, + }; - auto b = projection->fwd(a); - auto c = projection->inv(b); + for (const auto& test : tests) { + P projection(ProjectionFactory::instance().get("proj").create( + spec::Custom{{{"source", "EPSG:4326"}, {"target", test.target}}})); - std::cout << "-> a:" << a << " -> fwd(a):" << b << " -> inv(fwd(a)):" << c << std::endl; +#if 0 + std::cout << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) + << std::endl; +#endif - EXPECT(points_equal(b, test.b)); - EXPECT(points_equal(c, a)); + auto b = projection->fwd(a); + auto c = projection->inv(b); - P reverse(ProjectionFactory::instance().get("proj").create( - spec::Custom({{"source", test.target}, {"target", "EPSG:4326"}}))); + EXPECT(points_equal(b, test.b, eps)); + EXPECT(points_equal(c, a, eps)); - auto d = reverse->fwd(test.b); - auto e = reverse->inv(d); + P reverse(ProjectionFactory::instance().get("proj").create( + spec::Custom({{"source", test.target}, {"target", "EPSG:4326"}}))); - std::cout << "-> b:" << test.b << " -> fwd(b):" << d << " -> inv(fwd(b)):" << e << std::endl; + auto d = reverse->fwd(test.b); + auto e = reverse->inv(d); - EXPECT(points_equal(d, a)); - EXPECT(points_equal(e, test.b)); - } + EXPECT(points_equal(d, a, eps)); + EXPECT(points_equal(e, test.b, eps)); } } +} - SECTION("projection type: mercator") { - PointLonLat first{262.036, 14.7365}; +CASE("projection: mercator") { + PointLonLat first{262.036, 14.7365}; - { - projection::Mercator projection(0., 14., new figure::Sphere(6371229.), first); + { + projection::Mercator projection(0., 14., new figure::Sphere(6371229.), first); - auto p = projection.inv({0, 0}); - Log::info() << p << std::endl; + Point2 a{0., 0.}; + auto b = projection.inv(a); + auto c = projection.fwd(b); - auto q = projection.fwd(p); - Log::info() << q << std::endl; - } + EXPECT(points_equal(c, a)); + } - { - projection::Mercator projection(-180., 0., new figure::Sphere(1.), {0, 0}); + { + projection::Mercator projection(-180., 0., new figure::Sphere(1.), {0, 0}); - auto q = projection.fwd({-75, 35}); - Log::info() << q << std::endl; + PointLonLat a{-75., 35.}; + auto b = projection.fwd({-75, 35}); + auto c = projection.inv(b); - auto p = projection.inv(q); - Log::info() << p << std::endl; - } + EXPECT(points_equal(c, a)); } } From eca67c766dc17809f603f35c056dbba9eb553433 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 26 Jan 2024 14:32:17 +0000 Subject: [PATCH 454/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index d1d804f99..762cdb540 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -77,7 +77,7 @@ RegularPeriodic::RegularPeriodic(size_t n, double a, double b, double _eps) : else { b_ = PointLonLat::normalise_angle_to_maximum(b_ + db, a_) - db; auto inc = (b_ - a_) / static_cast(size()); - endpoint_ = types::is_strictly_greater(b_ - a_ + inc, -360.); + endpoint_ = types::is_strictly_greater(360., a_ - b_ + inc); } } From 58c5722cd6ec6038e8fbf8ac9961bce5f5f88c10 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 26 Jan 2024 15:19:40 +0000 Subject: [PATCH 455/737] eckit::geo::Projection --- src/eckit/geo/projection/None.cc | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index 02aa1f79b..688e89a4b 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -23,6 +23,9 @@ static ProjectionBuilder __projection2("none"); static ProjectionBuilder __projection3("equirectangular"); static ProjectionBuilder __projection4("plate-carree"); +static const std::string LONLAT("lonlat"); +static const std::string XY("xy"); + None::None() : fwd_(new NoPointConversion), inv_(new NoPointConversion) {} @@ -33,22 +36,30 @@ None::None(const std::string& source, const std::string& target) : None::None(const Spec& spec) : - None(spec.get_string("source", "xy"), spec.get_string("target", "xy")) {} + None(spec.get_string("source", XY), spec.get_string("target", XY)) {} Spec* None::spec() const { - return new spec::Custom({{"type", "none"}, {"source", "xy"}, {"target", "lonlat"}}); + return new spec::Custom({{"type", "none"}, {"source", XY}, {"target", LONLAT}}); } None::Implementation* None::new_point_conversion(const std::string& source, const std::string& target) { - ASSERT(source == "xy" || source == "lonlat"); - return source == "xy" && target == "lonlat" ? static_cast(new Point2ToPointLonLat) - : source == "lonlat" && target == "xy" ? static_cast(new PointLonLatToPoint2) - : new NoPointConversion; + ASSERT(source == XY || source == LONLAT); + return source == XY && target == LONLAT ? static_cast(new Point2ToPointLonLat) + : source == LONLAT && target == XY ? static_cast(new PointLonLatToPoint2) + : new NoPointConversion; } +PlateCaree::PlateCaree() : + None(XY, LONLAT) {} + + +PlateCaree::PlateCaree(const Spec&) : + PlateCaree() {} + + Spec* PlateCaree::spec() const { return new spec::Custom({{"type", "plate-carree"}}); } From 00eac886b0047638a888985b79489ed6cfb80064 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 27 Jan 2024 09:22:14 +0000 Subject: [PATCH 456/737] eckit::geo::Projection --- src/eckit/geo/projection/None.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index 5e428caa5..441e3b25c 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -115,10 +115,8 @@ class None : public Projection { struct PlateCaree final : None { - explicit PlateCaree() : - None("xy", "lonlat") {} - explicit PlateCaree(const Spec&) : - PlateCaree() {} + explicit PlateCaree(); + explicit PlateCaree(const Spec&); Spec* spec() const override; }; From beb6b382defd76a4588ae8df947b8d2be8d215ae Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 27 Jan 2024 14:18:42 +0000 Subject: [PATCH 457/737] eckit::geo::Projection --- src/eckit/geo/projection/None.cc | 8 -------- src/eckit/geo/projection/None.h | 16 ++++++++++++---- tests/geo/projection.cc | 13 +++++++++++++ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index 688e89a4b..8f156cacd 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -52,14 +52,6 @@ None::Implementation* None::new_point_conversion(const std::string& source, cons } -PlateCaree::PlateCaree() : - None(XY, LONLAT) {} - - -PlateCaree::PlateCaree(const Spec&) : - PlateCaree() {} - - Spec* PlateCaree::spec() const { return new spec::Custom({{"type", "plate-carree"}}); } diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index 441e3b25c..b3d3ed49c 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -110,14 +110,22 @@ class None : public Projection { static Implementation* new_point_conversion(const std::string& source, const std::string& target); // -- Friends - // None + + friend struct PlateCaree; }; -struct PlateCaree final : None { - explicit PlateCaree(); - explicit PlateCaree(const Spec&); +struct PlateCaree final : Projection { + explicit PlateCaree() = default; + explicit PlateCaree(const Spec&) {} + Spec* spec() const override; + inline Point fwd(const Point& p) const override { return fwd_(p); } + inline Point inv(const Point& q) const override { return inv_(q); } + +private: + None::Point2ToPointLonLat fwd_; + None::PointLonLatToPoint2 inv_; }; diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index beba54dc1..fb57d3fd2 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -40,6 +40,19 @@ CASE("projection: none") { } +CASE("projection: plate-caree") { + Point p = PointLonLat{1, 1}; + Point q = Point2{1, 1}; + P projection(ProjectionFactory::instance().get("plate-carree").create(spec::Custom{})); + + EXPECT(points_equal(q, projection->inv(p))); + EXPECT(std::holds_alternative(projection->inv(p))); + + EXPECT(points_equal(p, projection->fwd(q))); + EXPECT(std::holds_alternative(projection->fwd(q))); +} + + CASE("projection: rotation") { spec::Custom spec({ {"projection", "rotation"}, From c19fff82ae73f566f52d915be0838c146bfeee13 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 29 Jan 2024 09:45:13 +0000 Subject: [PATCH 458/737] eckit::geo::Projection --- src/eckit/geo/CMakeLists.txt | 4 ++ src/eckit/geo/projection/LonLatToXY.cc | 29 +++++++++ src/eckit/geo/projection/LonLatToXY.h | 81 +++++++++++++++++++++++++ src/eckit/geo/projection/None.cc | 35 +---------- src/eckit/geo/projection/None.h | 71 ++++------------------ src/eckit/geo/projection/XYToLonLat.cc | 30 +++++++++ src/eckit/geo/projection/XYToLonLat.h | 84 ++++++++++++++++++++++++++ 7 files changed, 241 insertions(+), 93 deletions(-) create mode 100644 src/eckit/geo/projection/LonLatToXY.cc create mode 100644 src/eckit/geo/projection/LonLatToXY.h create mode 100644 src/eckit/geo/projection/XYToLonLat.cc create mode 100644 src/eckit/geo/projection/XYToLonLat.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 32a09d69c..5bfd38e63 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -90,6 +90,8 @@ list(APPEND eckit_geo_srcs polygon/LonLatPolygon.h polygon/Polygon.cc polygon/Polygon.h + projection/LonLatToXY.cc + projection/LonLatToXY.h projection/LonLatToXYZ.cc projection/LonLatToXYZ.h projection/Mercator.cc @@ -98,6 +100,8 @@ list(APPEND eckit_geo_srcs projection/None.h projection/Rotation.cc projection/Rotation.h + projection/XYToLonLat.cc + projection/XYToLonLat.h spec/Custom.cc spec/Custom.h spec/Generator.h diff --git a/src/eckit/geo/projection/LonLatToXY.cc b/src/eckit/geo/projection/LonLatToXY.cc new file mode 100644 index 000000000..c42538be0 --- /dev/null +++ b/src/eckit/geo/projection/LonLatToXY.cc @@ -0,0 +1,29 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/projection/LonLatToXY.h" + +#include "eckit/geo/spec/Custom.h" + + +namespace eckit::geo::projection { + + +static ProjectionBuilder __projection("ll_to_xy"); + + +Spec* LonLatToXY::spec() const { + return new spec::Custom({{"type", "ll_to_xy"}}); +} + + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LonLatToXY.h b/src/eckit/geo/projection/LonLatToXY.h new file mode 100644 index 000000000..8ebdb8fdd --- /dev/null +++ b/src/eckit/geo/projection/LonLatToXY.h @@ -0,0 +1,81 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Projection.h" + + +namespace eckit::geo::projection { + + +class LonLatToXY final : public Projection { +public: + // -- Exceptions + // None + + // -- Constructors + + explicit LonLatToXY() = default; + explicit LonLatToXY(const Spec&) {} + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + inline Point2 fwd(const PointLonLat& p) const { return {p.lon, p.lat}; } + inline PointLonLat inv(const Point2& q) const { return {q.X, q.Y}; } + + // -- Overridden methods + + Spec* spec() const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Types + // None + + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } + inline Point inv(const Point& q) const override { return inv(std::get(q)); } + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index 8f156cacd..ecbef22ff 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -18,42 +18,11 @@ namespace eckit::geo::projection { -static ProjectionBuilder __projection1(""); -static ProjectionBuilder __projection2("none"); -static ProjectionBuilder __projection3("equirectangular"); -static ProjectionBuilder __projection4("plate-carree"); - -static const std::string LONLAT("lonlat"); -static const std::string XY("xy"); - - -None::None() : - fwd_(new NoPointConversion), inv_(new NoPointConversion) {} - - -None::None(const std::string& source, const std::string& target) : - fwd_(new_point_conversion(source, target)), inv_(new_point_conversion(target, source)) {} - - -None::None(const Spec& spec) : - None(spec.get_string("source", XY), spec.get_string("target", XY)) {} +static ProjectionBuilder __projection("none"); Spec* None::spec() const { - return new spec::Custom({{"type", "none"}, {"source", XY}, {"target", LONLAT}}); -} - - -None::Implementation* None::new_point_conversion(const std::string& source, const std::string& target) { - ASSERT(source == XY || source == LONLAT); - return source == XY && target == LONLAT ? static_cast(new Point2ToPointLonLat) - : source == LONLAT && target == XY ? static_cast(new PointLonLatToPoint2) - : new NoPointConversion; -} - - -Spec* PlateCaree::spec() const { - return new spec::Custom({{"type", "plate-carree"}}); + return new spec::Custom({{"type", "none"}}); } diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index b3d3ed49c..b96962b31 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -12,15 +12,13 @@ #pragma once -#include - #include "eckit/geo/Projection.h" namespace eckit::geo::projection { -class None : public Projection { +class None final : public Projection { public: // -- Types // None @@ -30,9 +28,8 @@ class None : public Projection { // -- Constructors - explicit None(); - explicit None(const std::string& source, const std::string& target); - explicit None(const Spec&); + explicit None() = default; + explicit None(const Spec&) {} // -- Destructor // None @@ -50,6 +47,9 @@ class None : public Projection { Spec* spec() const override; + inline Point fwd(const Point& p) const override { return p; } + inline Point inv(const Point& q) const override { return q; } + // -- Class members // None @@ -58,74 +58,25 @@ class None : public Projection { private: // -- Types - - struct Implementation { - Implementation() = default; - virtual ~Implementation() = default; - - Implementation(const Implementation&) = delete; - Implementation(Implementation&&) = delete; - void operator=(const Implementation&) = delete; - void operator=(Implementation&&) = delete; - - virtual Point operator()(const Point&) const = 0; - }; - - struct NoPointConversion final : Implementation { - Point operator()(const Point& p) const override { return p; } - }; - - struct Point2ToPointLonLat final : Implementation { - Point operator()(const Point& p) const override { - const auto& q = std::get(p); - return PointLonLat{q.X, q.Y}; - } - }; - - struct PointLonLatToPoint2 final : Implementation { - Point operator()(const Point& p) const override { - const auto& q = std::get(p); - return Point2{q.lon, q.lat}; - } - }; + // None // -- Members - - std::unique_ptr fwd_; - std::unique_ptr inv_; + // None // -- Methods // None // -- Overridden methods - - Point fwd(const Point& p) const override { return (*fwd_)(p); } - Point inv(const Point& q) const override { return (*inv_)(q); } + // None // -- Class members // None // -- Class methods - - static Implementation* new_point_conversion(const std::string& source, const std::string& target); + // None // -- Friends - - friend struct PlateCaree; -}; - - -struct PlateCaree final : Projection { - explicit PlateCaree() = default; - explicit PlateCaree(const Spec&) {} - - Spec* spec() const override; - inline Point fwd(const Point& p) const override { return fwd_(p); } - inline Point inv(const Point& q) const override { return inv_(q); } - -private: - None::Point2ToPointLonLat fwd_; - None::PointLonLatToPoint2 inv_; + // None }; diff --git a/src/eckit/geo/projection/XYToLonLat.cc b/src/eckit/geo/projection/XYToLonLat.cc new file mode 100644 index 000000000..2a109cfa2 --- /dev/null +++ b/src/eckit/geo/projection/XYToLonLat.cc @@ -0,0 +1,30 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/projection/XYToLonLat.h" + +#include "eckit/geo/spec/Custom.h" + + +namespace eckit::geo::projection { + + +static ProjectionBuilder __projection1("xy_to_ll"); +static ProjectionBuilder __projection2("plate-carree"); + + +Spec* XYToLonLat::spec() const { + return new spec::Custom({{"type", "plate-carree"}}); +} + + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/XYToLonLat.h b/src/eckit/geo/projection/XYToLonLat.h new file mode 100644 index 000000000..e9d436cb7 --- /dev/null +++ b/src/eckit/geo/projection/XYToLonLat.h @@ -0,0 +1,84 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Projection.h" + + +namespace eckit::geo::projection { + + +class XYToLonLat final : public Projection { +public: + // -- Exceptions + // None + + // -- Constructors + + explicit XYToLonLat() = default; + explicit XYToLonLat(const Spec&) {} + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + + inline PointLonLat fwd(const Point2& p) const { return {p.X, p.Y}; } + inline Point2 inv(const PointLonLat& q) const { return {q.lon, q.lat}; } + + // -- Overridden methods + + Spec* spec() const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Types + // None + + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + + inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } + inline Point inv(const Point& q) const override { return inv(std::get(q)); } + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +using PlateCaree = XYToLonLat; + + +} // namespace eckit::geo::projection From a599600841560afecdd101ce02af33abcdabdad3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 29 Jan 2024 10:07:27 +0000 Subject: [PATCH 459/737] eckit::geo --- src/eckit/geo/Point2.h | 6 ++-- src/eckit/geo/Point3.h | 4 ++- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 4 ++- src/eckit/geo/util/bounding_box.cc | 34 ++++++++++++------- tests/geo/great_circle.cc | 2 +- 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/eckit/geo/Point2.h b/src/eckit/geo/Point2.h index a13f1d5d5..9941a1d0f 100644 --- a/src/eckit/geo/Point2.h +++ b/src/eckit/geo/Point2.h @@ -26,7 +26,7 @@ namespace eckit::geo { //------------------------------------------------------------------------------------------------------ -class Point2 : public KPoint<2> { +class Point2 final : public KPoint<2> { using BasePoint = KPoint<2>; public: @@ -49,6 +49,8 @@ class Point2 : public KPoint<2> { Point2(Point2&& other) : Point2(other.X, other.Y) {} + ~Point2() = default; + double x() const { return x_[XX]; } double y() const { return x_[YY]; } @@ -87,7 +89,7 @@ class Point2 : public KPoint<2> { x_[YY] = p[YY]; } - operator eckit::Value() const; + explicit operator eckit::Value() const; static Point2 middle(const Point2& p, const Point2& q) { return (p + q) * 0.5; } }; diff --git a/src/eckit/geo/Point3.h b/src/eckit/geo/Point3.h index f4c4b77b3..b2725834c 100644 --- a/src/eckit/geo/Point3.h +++ b/src/eckit/geo/Point3.h @@ -18,7 +18,7 @@ namespace eckit::geo { //------------------------------------------------------------------------------------------------------ -class Point3 : public KPoint<3> { +class Point3 final : public KPoint<3> { using BasePoint = KPoint<3>; public: @@ -42,6 +42,8 @@ class Point3 : public KPoint<3> { Point3(Point3&& other) : Point3(other.X, other.Y, other.Z) {} + ~Point3() = default; + double& X = x_[XX]; double& Y = x_[YY]; diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index f89bcd2e1..b99162d9d 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -12,6 +12,8 @@ #include "eckit/geo/grid/reduced/ReducedGaussian.h" +#include + #include "eckit/exception/Exceptions.h" #include "eckit/geo/Range.h" #include "eckit/geo/iterator/Reduced.h" @@ -61,7 +63,7 @@ const std::vector& ReducedGaussian::latitudes() const { std::vector ReducedGaussian::longitudes(size_t j) const { auto Ni = ni(j); if (!x_ || x_->size() != Ni) { - const_cast&>(x_).reset(new range::Regular(Ni, bbox().west, bbox().east)); + const_cast&>(x_) = std::make_unique(Ni, bbox().west, bbox().east); } return x_->values(); diff --git a/src/eckit/geo/util/bounding_box.cc b/src/eckit/geo/util/bounding_box.cc index 1b70ac27e..8b0052523 100644 --- a/src/eckit/geo/util/bounding_box.cc +++ b/src/eckit/geo/util/bounding_box.cc @@ -41,7 +41,7 @@ struct BoundLonLat { BoundLonLat(PointLonLat min, PointLonLat max) : min_(min), max_(max) {} - operator area::BoundingBox() const { return {max_.lat, min_.lon, min_.lat, max_.lon}; } + explicit operator area::BoundingBox() const { return {max_.lat, min_.lon, min_.lat, max_.lon}; } void extend(PointLonLat p, PointLonLat eps) { ASSERT(0. <= eps.lon && 0. <= eps.lat); @@ -107,39 +107,47 @@ struct Derivate { refLongitude_(refLongitude) {} virtual ~Derivate() = default; - virtual PointLonLat d(Point2) const = 0; + Derivate(const Derivate&) = delete; + Derivate(Derivate&&) = delete; + void operator=(const Derivate&) = delete; + void operator=(Derivate&&) = delete; -protected: - const Projection& projection_; - const Point2 H_; - const double invnH_; - const double refLongitude_; + virtual PointLonLat d(Point2) const = 0; - PointLonLat xy2lonlat(const Point2& p) const { + PointLonLat f(const Point2& p) const { auto q = std::get(projection_.inv(p)); longitude_in_range(refLongitude_, q.lon); return q; } + + inline const Point2& H() const { return H_; } + inline double invnH() const { return invnH_; } + +private: + const Projection& projection_; + const Point2 H_; + const double invnH_; + const double refLongitude_; }; struct DerivateForwards final : Derivate { using Derivate::Derivate; - PointLonLat d(Point2 P) const override { return (xy2lonlat(P + H_) - xy2lonlat(P)) * invnH_; } + PointLonLat d(Point2 P) const override { return (f(P + H()) - f(P)) * invnH(); } }; struct DerivateBackwards final : Derivate { using Derivate::Derivate; - PointLonLat d(Point2 P) const override { return (xy2lonlat(P) - xy2lonlat(P - H_)) * invnH_; } + PointLonLat d(Point2 P) const override { return (f(P) - f(P - H())) * invnH(); } }; struct DerivateCentral final : Derivate { DerivateCentral(const Projection& p, Point2 A, Point2 B, double h, double refLongitude) : - Derivate(p, A, B, h, refLongitude), H2_{H_ * 0.5} {} + Derivate(p, A, B, h, refLongitude), H2_{H() * 0.5} {} const Point2 H2_; - PointLonLat d(Point2 P) const override { return (xy2lonlat(P + H2_) - xy2lonlat(P - H2_)) * invnH_; } + PointLonLat d(Point2 P) const override { return (f(P + H2_) - f(P - H2_)) * invnH(); } }; @@ -285,7 +293,7 @@ area::BoundingBox bounding_box(Point2 min, Point2 max, Projection& projection) { // 4. return bounding box - return bounds; + return {bounds}; } diff --git a/tests/geo/great_circle.cc b/tests/geo/great_circle.cc index 9f0c50c3e..6538882c1 100644 --- a/tests/geo/great_circle.cc +++ b/tests/geo/great_circle.cc @@ -211,7 +211,7 @@ CASE("great circle intersections") { EXPECT(!gc.crossesPoles()); auto lons = gc.longitude(lat); - size_t N = is_approximately_equator(lat_gc) ? 0. + size_t N = is_approximately_equator(lat_gc) ? 0 : is_approximately_greater_or_equal(std::abs(lat_gc), std::abs(lat)) ? 2 : 0; EXPECT(lons.size() == N); From 7e96672d602822e488cb05092ad8a0b5f01e63a8 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 31 Jan 2024 11:39:55 +0000 Subject: [PATCH 460/737] eckit::geo::Projection --- src/eckit/geo/PointLonLat.h | 5 ++-- src/eckit/geo/area/BoundingBox.cc | 21 ++++++++++++-- src/eckit/geo/area/BoundingBox.h | 2 ++ tests/geo/projection.cc | 48 ++++++++++++++++++++++++++----- 4 files changed, 65 insertions(+), 11 deletions(-) diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index 5dc9ca39a..0c0649ba2 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -97,7 +97,8 @@ class PointLonLat final : protected std::array { // None // -- Class members - // None + + static constexpr double EPS = 1e-9; // -- Class methods @@ -126,6 +127,6 @@ class PointLonLat final : protected std::array { } }; -bool points_equal(const PointLonLat&, const PointLonLat&, double eps = 1.e-9); +bool points_equal(const PointLonLat&, const PointLonLat&, double eps = PointLonLat::EPS); } // namespace eckit::geo diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 94cb484c3..bf70951b4 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -78,12 +78,29 @@ BoundingBox::BoundingBox(double n, double w, double s, double e) : bool BoundingBox::operator==(const BoundingBox& other) const { - return north == other.north && south == other.south && west == other.west && east == other.east; + return types::is_approximately_equal(north, other.north, PointLonLat::EPS) && + types::is_approximately_equal(south, other.south, PointLonLat::EPS) && + types::is_approximately_equal(west, other.west, PointLonLat::EPS) && + types::is_approximately_equal(east, other.east, PointLonLat::EPS); } bool BoundingBox::isPeriodicWestEast() const { - return west != east && west == PointLonLat::normalise_angle_to_minimum(east, west); + + return west != east && + types::is_approximately_equal(west, PointLonLat::normalise_angle_to_minimum(east, west), PointLonLat::EPS); +} + + +bool BoundingBox::containsNorthPole() const { + static const auto NORTH_POLE = PointLonLat::make(0., 90.); + return points_equal({0., north}, NORTH_POLE); +} + + +bool BoundingBox::containsSouthPole() const { + static const auto SOUTH_POLE = PointLonLat::make(0., 90.); + return points_equal({0., south}, SOUTH_POLE); } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 384f9eba7..98b76b858 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -73,6 +73,8 @@ class BoundingBox : public Area, protected std::array { std::array deconstruct() const { return {north, west, south, east}; } bool isPeriodicWestEast() const; + bool containsNorthPole() const; + bool containsSouthPole() const; bool intersects(BoundingBox&) const; diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index fb57d3fd2..262ab31c9 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -14,6 +14,7 @@ #include #include "eckit/geo/Projection.h" +#include "eckit/geo/area/BoundingBox.h" #include "eckit/geo/figure/Sphere.h" #include "eckit/geo/projection/LonLatToXYZ.h" #include "eckit/geo/projection/Mercator.h" @@ -23,6 +24,11 @@ #include "eckit/testing/Test.h" +namespace eckit::geo::util { +area::BoundingBox bounding_box(Point2, Point2, Projection&); +} + + namespace eckit::test { @@ -110,7 +116,7 @@ CASE("projection: ll_to_xyz") { auto q = to_xyz_r.fwd(p); auto r = to_xyz_r.inv(q); - std::cout << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; + Log::info() << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; EXPECT(points_equal(p, r)); @@ -119,7 +125,7 @@ CASE("projection: ll_to_xyz") { for (const auto& lon : {0., 90., 180., 270.}) { PointLonLat p{lon, 0.}; - std::cout << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) << std::endl; + Log::info() << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) << std::endl; } // problate spheroid (not supported) @@ -303,14 +309,12 @@ CASE("projection: proj") { if (ProjectionFactory::instance().exists("proj")) { - std::cout.precision(14); - PointLonLat a{12., 55.}; struct { const Point b; const std::string target; - } tests[] = { + } tests_proj[] = { {Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, {Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, {a, "EPSG:4326"}, @@ -321,12 +325,12 @@ CASE("projection: proj") { {a, "+proj=latlon +ellps=sphere"}, }; - for (const auto& test : tests) { + for (const auto& test : tests_proj) { P projection(ProjectionFactory::instance().get("proj").create( spec::Custom{{{"source", "EPSG:4326"}, {"target", test.target}}})); #if 0 - std::cout << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) + Log::info() << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) << std::endl; #endif @@ -345,6 +349,35 @@ CASE("projection: proj") { EXPECT(points_equal(d, a, eps)); EXPECT(points_equal(e, test.b, eps)); } + + struct { + const Point2 min; + const Point2 max; + const bool is_periodic_west_east; + const bool contains_north_pole; + const bool contains_south_pole; + } tests_bbox[] = { + {{-2e6, -2e6}, {2e6, 2e6}, true, true, false}, + {{-2e6, -2e6}, {1e6, 1e6}, true, true, false}, + {{-2e6, -2e6}, {-1e6, -1e6}, false, false, false}, + {{-1e6, -1e6}, {2e6, 2e6}, true, true, false}, + {{-1e6, -1e6}, {1e6, 1e6}, true, true, false}, + {{1e6, 1e6}, {2e6, 2e6}, false, false, false}, + }; + + P polar_stereographic(ProjectionFactory::instance().get("proj").create( + spec::Custom{{{"source", "EPSG:4326"}, + {"target", "+proj=stere +lat_ts=90. +lat_0=90. +lon_0=-30. +k_0=1 +R=6371229."}}})); + + for (const auto& test : tests_bbox) { + auto bbox = util::bounding_box(test.min, test.max, *polar_stereographic); + + Log::info() << bbox << std::endl; + + EXPECT_EQUAL(test.is_periodic_west_east, bbox.isPeriodicWestEast()); + EXPECT_EQUAL(test.contains_north_pole, bbox.containsNorthPole()); + EXPECT_EQUAL(test.contains_south_pole, bbox.containsSouthPole()); + } } } @@ -378,5 +411,6 @@ CASE("projection: mercator") { int main(int argc, char** argv) { + eckit::Log::info().precision(1); return eckit::testing::run_tests(argc, argv); } From d5df62c4a790fa0e687dd9d5f3500fb5cb68a62e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 31 Jan 2024 11:40:00 +0000 Subject: [PATCH 461/737] eckit::geo::Projection --- src/eckit/geo/util/bounding_box.cc | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/eckit/geo/util/bounding_box.cc b/src/eckit/geo/util/bounding_box.cc index 8b0052523..c22226727 100644 --- a/src/eckit/geo/util/bounding_box.cc +++ b/src/eckit/geo/util/bounding_box.cc @@ -46,8 +46,8 @@ struct BoundLonLat { void extend(PointLonLat p, PointLonLat eps) { ASSERT(0. <= eps.lon && 0. <= eps.lat); - auto sub = p + eps; - auto add = p - eps; + auto sub = p - eps; + auto add = p + eps; min_ = first_ ? sub : PointLonLat::componentsMin(min_, sub); max_ = first_ ? add : PointLonLat::componentsMax(max_, add); first_ = false; @@ -205,6 +205,13 @@ area::BoundingBox bounding_box(Point2 min, Point2 max, Projection& projection) { // 1. determine box from projected corners + struct : public std::pair { + using pair::pair; + bool contains(const Point2& P) const { + return (first.X < P.X && P.X < second.X) && (first.Y < P.Y && P.Y < second.Y); + } + } rect(min, max); + const std::pair segments[] = {{{min.X, max.Y}, {max.X, max.Y}}, {{max.X, max.Y}, {max.X, min.Y}}, {{max.X, min.Y}, {min.X, min.Y}}, @@ -221,6 +228,16 @@ area::BoundingBox bounding_box(Point2 min, Point2 max, Projection& projection) { // 2. locate latitude extrema by checking if poles are included (in the un-projected frame) and if not, find extrema // not at the corners by refining iteratively + if (const auto P = projection.fwd(PointLonLat{0., 90.}); + !bounds.includesNorthPole() && std::holds_alternative(P)) { + bounds.includesNorthPole(rect.contains(std::get(P))); + } + + if (const auto P = projection.fwd(PointLonLat{0., -90.}); + !bounds.includesSouthPole() && std::holds_alternative(P)) { + bounds.includesSouthPole(rect.contains(std::get(P))); + } + for (auto [A, B] : segments) { if (!bounds.includesNorthPole() || !bounds.includesSouthPole()) { std::unique_ptr derivate( From c426f7f41df3a8f90e2ee4e8cbe9e3090b4888f7 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 1 Feb 2024 01:28:46 +0000 Subject: [PATCH 462/737] eckit::geo::Projection --- src/eckit/geo/area/BoundingBox.cc | 2 +- src/eckit/geo/util/bounding_box.cc | 12 +++++------ tests/geo/projection.cc | 33 ++++++++++++++++++------------ 3 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index bf70951b4..cad55b922 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -99,7 +99,7 @@ bool BoundingBox::containsNorthPole() const { bool BoundingBox::containsSouthPole() const { - static const auto SOUTH_POLE = PointLonLat::make(0., 90.); + static const auto SOUTH_POLE = PointLonLat::make(0., -90.); return points_equal({0., south}, SOUTH_POLE); } diff --git a/src/eckit/geo/util/bounding_box.cc b/src/eckit/geo/util/bounding_box.cc index c22226727..364cba414 100644 --- a/src/eckit/geo/util/bounding_box.cc +++ b/src/eckit/geo/util/bounding_box.cc @@ -194,7 +194,7 @@ area::BoundingBox bounding_box(Point2 min, Point2 max, Projection& projection) { // use central longitude as absolute reference (keep points within +-180 longitude range) const Point2 centre_xy{(min.X + max.X) / 2., (min.Y + max.Y) / 2.}; - const auto centre_ll = std::get(projection.inv(centre_xy)); + const auto centre_ll = std::get(projection.inv(centre_xy)); // asserts fwd(PointLonLat) -> Point2 const auto centre_lon = centre_ll.lon; const std::string derivative_type = "central"; @@ -228,14 +228,12 @@ area::BoundingBox bounding_box(Point2 min, Point2 max, Projection& projection) { // 2. locate latitude extrema by checking if poles are included (in the un-projected frame) and if not, find extrema // not at the corners by refining iteratively - if (const auto P = projection.fwd(PointLonLat{0., 90.}); - !bounds.includesNorthPole() && std::holds_alternative(P)) { - bounds.includesNorthPole(rect.contains(std::get(P))); + if (!bounds.includesNorthPole()) { + bounds.includesNorthPole(rect.contains(std::get(projection.fwd(PointLonLat{0., 90.})))); } - if (const auto P = projection.fwd(PointLonLat{0., -90.}); - !bounds.includesSouthPole() && std::holds_alternative(P)) { - bounds.includesSouthPole(rect.contains(std::get(P))); + if (!bounds.includesSouthPole()) { + bounds.includesSouthPole(rect.contains(std::get(projection.fwd(PointLonLat{0., -90.})))); } for (auto [A, B] : segments) { diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index 262ab31c9..1662004e0 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -350,29 +350,36 @@ CASE("projection: proj") { EXPECT(points_equal(e, test.b, eps)); } + P polar_stereographic_north(ProjectionFactory::instance().get("proj").create( + spec::Custom{{{"source", "EPSG:4326"}, {"target", "+proj=stere +lat_0=90. +lon_0=-30. +R=6371229."}}})); + + P polar_stereographic_south(ProjectionFactory::instance().get("proj").create( + spec::Custom{{{"source", "EPSG:4326"}, {"target", "+proj=stere +lat_0=-90. +lon_0=-30. +R=6371229."}}})); + struct { + const P& projection; const Point2 min; const Point2 max; const bool is_periodic_west_east; const bool contains_north_pole; const bool contains_south_pole; } tests_bbox[] = { - {{-2e6, -2e6}, {2e6, 2e6}, true, true, false}, - {{-2e6, -2e6}, {1e6, 1e6}, true, true, false}, - {{-2e6, -2e6}, {-1e6, -1e6}, false, false, false}, - {{-1e6, -1e6}, {2e6, 2e6}, true, true, false}, - {{-1e6, -1e6}, {1e6, 1e6}, true, true, false}, - {{1e6, 1e6}, {2e6, 2e6}, false, false, false}, + {polar_stereographic_north, {-2e6, -2e6}, {2e6, 2e6}, true, true, false}, + {polar_stereographic_north, {-2e6, -2e6}, {1e6, 1e6}, true, true, false}, + {polar_stereographic_north, {-2e6, -2e6}, {-1e6, -1e6}, false, false, false}, + {polar_stereographic_north, {-1e6, -1e6}, {2e6, 2e6}, true, true, false}, + {polar_stereographic_north, {-1e6, -1e6}, {1e6, 1e6}, true, true, false}, + {polar_stereographic_north, {1e6, 1e6}, {2e6, 2e6}, false, false, false}, + {polar_stereographic_south, {-2e6, -2e6}, {2e6, 2e6}, true, false, true}, + {polar_stereographic_south, {-2e6, -2e6}, {1e6, 1e6}, true, false, true}, + {polar_stereographic_south, {-2e6, -2e6}, {-1e6, -1e6}, false, false, false}, + {polar_stereographic_south, {-1e6, -1e6}, {2e6, 2e6}, true, false, true}, + {polar_stereographic_south, {-1e6, -1e6}, {1e6, 1e6}, true, false, true}, + {polar_stereographic_south, {1e6, 1e6}, {2e6, 2e6}, false, false, false}, }; - P polar_stereographic(ProjectionFactory::instance().get("proj").create( - spec::Custom{{{"source", "EPSG:4326"}, - {"target", "+proj=stere +lat_ts=90. +lat_0=90. +lon_0=-30. +k_0=1 +R=6371229."}}})); - for (const auto& test : tests_bbox) { - auto bbox = util::bounding_box(test.min, test.max, *polar_stereographic); - - Log::info() << bbox << std::endl; + auto bbox = util::bounding_box(test.min, test.max, *test.projection); EXPECT_EQUAL(test.is_periodic_west_east, bbox.isPeriodicWestEast()); EXPECT_EQUAL(test.contains_north_pole, bbox.containsNorthPole()); From eeb314d21efd3ecdf43fc08010f539c55cf5240f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 1 Feb 2024 10:10:59 +0000 Subject: [PATCH 463/737] eckit::geo --- src/eckit/geo/PointLonLat.cc | 8 ++++++++ src/eckit/geo/PointLonLat.h | 11 ++--------- src/eckit/geo/projection/LonLatToXY.cc | 2 +- src/eckit/geo/projection/None.cc | 2 +- src/eckit/geo/projection/XYToLonLat.cc | 2 +- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index 88ada52de..fe3622b1b 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -12,12 +12,20 @@ #include "eckit/geo/PointLonLat.h" +#include "eckit/exception/Exceptions.h" #include "eckit/types/FloatCompare.h" namespace eckit::geo { +PointLonLat::PointLonLat(double lon, double lat) : + P{lon, lat} { + if (!(-90. <= lat && lat <= 90.)) { + throw BadValue("PointLonLat: invalid latitude"); + } +} + double PointLonLat::normalise_angle_to_minimum(double a, double minimum) { while (a < minimum) { a += 360.; diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index 0c0649ba2..b84ed4176 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -12,12 +12,10 @@ #pragma once +#include #include -#include #include -#include "eckit/exception/Exceptions.h" - namespace eckit::geo { @@ -37,12 +35,7 @@ class PointLonLat final : protected std::array { // -- Constructors - PointLonLat(double lon, double lat) : - P{lon, lat} { - if (!(-90. <= lat && lat <= 90.)) { - throw BadValue("PointLonLat: invalid latitude"); - } - } + PointLonLat(double lon, double lat); PointLonLat(const PointLonLat& other) : P(other) {} diff --git a/src/eckit/geo/projection/LonLatToXY.cc b/src/eckit/geo/projection/LonLatToXY.cc index c42538be0..0dfd1435d 100644 --- a/src/eckit/geo/projection/LonLatToXY.cc +++ b/src/eckit/geo/projection/LonLatToXY.cc @@ -22,7 +22,7 @@ static ProjectionBuilder __projection("ll_to_xy"); Spec* LonLatToXY::spec() const { - return new spec::Custom({{"type", "ll_to_xy"}}); + return new spec::Custom({{"projection", "ll_to_xy"}}); } diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index ecbef22ff..cb2cceb43 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -22,7 +22,7 @@ static ProjectionBuilder __projection("none"); Spec* None::spec() const { - return new spec::Custom({{"type", "none"}}); + return nullptr; } diff --git a/src/eckit/geo/projection/XYToLonLat.cc b/src/eckit/geo/projection/XYToLonLat.cc index 2a109cfa2..d536c6208 100644 --- a/src/eckit/geo/projection/XYToLonLat.cc +++ b/src/eckit/geo/projection/XYToLonLat.cc @@ -23,7 +23,7 @@ static ProjectionBuilder __projection2("plate-carree"); Spec* XYToLonLat::spec() const { - return new spec::Custom({{"type", "plate-carree"}}); + return new spec::Custom({{"projection", "plate-carree"}}); } From ec6bcfc2cbee17a19245724dfb47155d653e51dc Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 1 Feb 2024 10:11:05 +0000 Subject: [PATCH 464/737] eckit::geo::Projection --- src/eckit/geo/CMakeLists.txt | 2 + src/eckit/geo/projection/Composer.cc | 80 +++++++++++++++++++++++++++ src/eckit/geo/projection/Composer.h | 52 ++++++++++++++++++ tests/geo/projection.cc | 81 +++++++++++++++++++++------- 4 files changed, 195 insertions(+), 20 deletions(-) create mode 100644 src/eckit/geo/projection/Composer.cc create mode 100644 src/eckit/geo/projection/Composer.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 5bfd38e63..9e2de2f89 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -90,6 +90,8 @@ list(APPEND eckit_geo_srcs polygon/LonLatPolygon.h polygon/Polygon.cc polygon/Polygon.h + projection/Composer.cc + projection/Composer.h projection/LonLatToXY.cc projection/LonLatToXY.h projection/LonLatToXYZ.cc diff --git a/src/eckit/geo/projection/Composer.cc b/src/eckit/geo/projection/Composer.cc new file mode 100644 index 000000000..093f76b2d --- /dev/null +++ b/src/eckit/geo/projection/Composer.cc @@ -0,0 +1,80 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/projection/Composer.h" + +#include "eckit/exception/Exceptions.h" + + +namespace eckit::geo::projection { + + +std::vector Composer::fwd_points(const Point& p) const { + if (empty()) { + return {}; + } + + std::vector points; + points.reserve(size()); + + auto q = p; + for (const auto* proj : *this) { + points.emplace_back(proj->fwd(q)); + q = points.back(); + } + + return points; +} + + +std::vector Composer::inv_points(const Point& p) const { + if (empty()) { + return {}; + } + + std::vector points; + points.reserve(size()); + + auto q = p; + for (auto proj = rbegin(); proj != rend(); ++proj) { + points.emplace_back((*proj)->inv(q)); + q = points.back(); + } + + return points; +} + + +Spec* Composer::spec() const { + NOTIMP; +} + + +Point Composer::fwd(const Point& p) const { + auto q = p; + for (const auto* proj : *this) { + q = proj->fwd(q); + } + return q; +} + + +Point Composer::inv(const Point& p) const { + auto q = p; + for (auto proj = rbegin(); proj != rend(); ++proj) { + q = (*proj)->inv(q); + } + return q; +} + + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/Composer.h b/src/eckit/geo/projection/Composer.h new file mode 100644 index 000000000..3165b1320 --- /dev/null +++ b/src/eckit/geo/projection/Composer.h @@ -0,0 +1,52 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + +#include "eckit/geo/Projection.h" + + +namespace eckit::geo::projection { + + +class Composer final : public Projection, private std::deque { +public: + // -- Constructors + + explicit Composer() = default; + using deque::deque; + + // -- Methods + + using deque::clear; + using deque::emplace_back; + using deque::emplace_front; + + using deque::empty; + using deque::size; + + std::vector fwd_points(const Point&) const; + std::vector inv_points(const Point&) const; + + // -- Overridden methods + + Spec* spec() const override; + + Point fwd(const Point&) const override; + Point inv(const Point&) const override; +}; + + +} // namespace eckit::geo::projection diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index 1662004e0..1536e7bae 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -16,6 +16,7 @@ #include "eckit/geo/Projection.h" #include "eckit/geo/area/BoundingBox.h" #include "eckit/geo/figure/Sphere.h" +#include "eckit/geo/projection/Composer.h" #include "eckit/geo/projection/LonLatToXYZ.h" #include "eckit/geo/projection/Mercator.h" #include "eckit/geo/projection/Rotation.h" @@ -59,21 +60,6 @@ CASE("projection: plate-caree") { } -CASE("projection: rotation") { - spec::Custom spec({ - {"projection", "rotation"}, - {"south_pole_lat", -91.}, - {"south_pole_lon", -361.}, - }); - - Point p = PointLonLat{1, 1}; - P projection(ProjectionFactory::instance().get(spec.get_string("projection")).create(spec)); - - EXPECT(points_equal(p, projection->inv(projection->fwd(p)))); - EXPECT(points_equal(p, projection->fwd(projection->inv(p)))); -} - - CASE("projection: ll_to_xyz") { Point p = PointLonLat{1, 1}; P s1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"R", 1.}}))); @@ -138,6 +124,21 @@ CASE("projection: rotation") { SECTION("rotation (1)") { + spec::Custom spec({ + {"projection", "rotation"}, + {"south_pole_lat", -91.}, + {"south_pole_lon", -361.}, + }); + + Point p = PointLonLat{1, 1}; + P projection(ProjectionFactory::instance().get(spec.get_string("projection")).create(spec)); + + EXPECT(points_equal(p, projection->inv(projection->fwd(p)))); + EXPECT(points_equal(p, projection->fwd(projection->inv(p)))); + } + + + SECTION("rotation (2)") { const PointLonLat p(1, 1); int delta[] = {-360, -180, -1, 0, 1, 90, 91, 180}; @@ -157,7 +158,7 @@ CASE("projection: rotation") { } - SECTION("rotation (2)") { + SECTION("rotation (3)") { const int Ni = 12; const int Nj = 3; @@ -263,7 +264,7 @@ CASE("projection: rotation") { } - SECTION("rotation (3)") { + SECTION("rotation (4)") { const projection::Rotation non_rotated(0., -90., 0.); const projection::Rotation rotation_angle(0., -90., -180.); const projection::Rotation rotation_matrix(4., -40., 180.); @@ -301,6 +302,45 @@ CASE("projection: rotation") { EXPECT(points_equal(a, test.a, eps)); } } + + + SECTION("rotation (5)") { + spec::Custom spec({ + {"projection", "rotation"}, + {"south_pole_lat", -90.}, + {"south_pole_lon", 0.}, + {"angle", 45.}, + }); + + const auto& builder = ProjectionFactory::instance().get("rotation"); + P composition(new projection::Composer{ + builder.create(spec), + builder.create(spec), + builder.create(spec), + builder.create(spec), + builder.create(spec), + builder.create(spec), + builder.create(spec), + builder.create(spec), + }); + + for (auto lat : {0., 10., -10.}) { + PointLonLat p{0., lat}; + auto q = composition->fwd(p); + + EXPECT(points_equal(p, q)); + EXPECT(points_equal(p, composition->inv(q))); + + auto qs = dynamic_cast(composition.get())->fwd_points(p); + EXPECT(qs.size() == 8); + + EXPECT(points_equal(qs.front(), PointLonLat{-45., lat})); + EXPECT(points_equal(qs[1], PointLonLat{-90., lat})); + EXPECT(points_equal(qs[2], PointLonLat{-135., lat})); + // ... + EXPECT(points_equal(qs.back(), p)); + } + } } @@ -392,7 +432,8 @@ CASE("projection: proj") { CASE("projection: mercator") { PointLonLat first{262.036, 14.7365}; - { + + SECTION("mercator (1)") { projection::Mercator projection(0., 14., new figure::Sphere(6371229.), first); Point2 a{0., 0.}; @@ -402,7 +443,8 @@ CASE("projection: mercator") { EXPECT(points_equal(c, a)); } - { + + SECTION("mercator (2)") { projection::Mercator projection(-180., 0., new figure::Sphere(1.), {0, 0}); PointLonLat a{-75., 35.}; @@ -418,6 +460,5 @@ CASE("projection: mercator") { int main(int argc, char** argv) { - eckit::Log::info().precision(1); return eckit::testing::run_tests(argc, argv); } From 00053154b324fdc9b2747a30fb2e60c77c3b65bc Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 2 Feb 2024 23:22:15 +0000 Subject: [PATCH 465/737] eckit::geo::Projection --- src/eckit/geo/projection/Composer.cc | 11 +++++++++++ src/eckit/geo/projection/Composer.h | 5 +++++ tests/geo/projection.cc | 19 +++++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/src/eckit/geo/projection/Composer.cc b/src/eckit/geo/projection/Composer.cc index 093f76b2d..1e510d934 100644 --- a/src/eckit/geo/projection/Composer.cc +++ b/src/eckit/geo/projection/Composer.cc @@ -13,6 +13,7 @@ #include "eckit/geo/projection/Composer.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Spec.h" namespace eckit::geo::projection { @@ -77,4 +78,14 @@ Point Composer::inv(const Point& p) const { } +Projection* Composer::compose_back(Projection* p, const Spec& spec) { + return new Composer{p, ProjectionFactory::instance().get(spec.get_string("projection")).create(spec)}; +} + + +Projection* Composer::compose_front(const Spec& spec, Projection* p) { + return new Composer{ProjectionFactory::instance().get(spec.get_string("projection")).create(spec), p}; +} + + } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/Composer.h b/src/eckit/geo/projection/Composer.h index 3165b1320..458e91308 100644 --- a/src/eckit/geo/projection/Composer.h +++ b/src/eckit/geo/projection/Composer.h @@ -46,6 +46,11 @@ class Composer final : public Projection, private std::deque { Point fwd(const Point&) const override; Point inv(const Point&) const override; + + // -- Class methods + + static Projection* compose_back(Projection*, const Spec&); + static Projection* compose_front(const Spec&, Projection*); }; diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index 1536e7bae..41a6bc751 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -312,6 +312,7 @@ CASE("projection: rotation") { {"angle", 45.}, }); + // compose sequentially const auto& builder = ProjectionFactory::instance().get("rotation"); P composition(new projection::Composer{ builder.create(spec), @@ -340,6 +341,24 @@ CASE("projection: rotation") { // ... EXPECT(points_equal(qs.back(), p)); } + + // compose by nesting + P composition2(builder.create(spec)); + for (size_t i = 1; i < 8; ++i) { + composition2.reset(projection::Composer::compose_back(composition2.release(), spec)); + } + + for (auto lat : {0., 10., -10.}) { + PointLonLat p{0., lat}; + + auto qs1 = dynamic_cast(composition.get())->fwd_points(p); + auto qs2 = dynamic_cast(composition2.get())->fwd_points(p); + + ASSERT(qs1.size() == 8); + EXPECT(qs2.size() == 2); + EXPECT(points_equal(qs1[6], qs2[0])); + EXPECT(points_equal(qs1[7], qs2[1])); + } } } From e72cb264834a10f0f591f5afac88257137b9bc0f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 3 Feb 2024 15:10:26 +0000 Subject: [PATCH 466/737] eckit::geo::Projection --- tests/geo/projection.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index 41a6bc751..0a6db532a 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -314,8 +314,7 @@ CASE("projection: rotation") { // compose sequentially const auto& builder = ProjectionFactory::instance().get("rotation"); - P composition(new projection::Composer{ - builder.create(spec), + P composition1(new projection::Composer{ builder.create(spec), builder.create(spec), builder.create(spec), @@ -325,14 +324,16 @@ CASE("projection: rotation") { builder.create(spec), }); + dynamic_cast(composition1.get())->emplace_back(builder.create(spec)); + for (auto lat : {0., 10., -10.}) { PointLonLat p{0., lat}; - auto q = composition->fwd(p); + auto q = composition1->fwd(p); EXPECT(points_equal(p, q)); - EXPECT(points_equal(p, composition->inv(q))); + EXPECT(points_equal(p, composition1->inv(q))); - auto qs = dynamic_cast(composition.get())->fwd_points(p); + auto qs = dynamic_cast(composition1.get())->fwd_points(p); EXPECT(qs.size() == 8); EXPECT(points_equal(qs.front(), PointLonLat{-45., lat})); @@ -351,7 +352,7 @@ CASE("projection: rotation") { for (auto lat : {0., 10., -10.}) { PointLonLat p{0., lat}; - auto qs1 = dynamic_cast(composition.get())->fwd_points(p); + auto qs1 = dynamic_cast(composition1.get())->fwd_points(p); auto qs2 = dynamic_cast(composition2.get())->fwd_points(p); ASSERT(qs1.size() == 8); From 631168c444c48fa3faa2dce8ea78fd67195cce84 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 5 Feb 2024 15:19:36 -0100 Subject: [PATCH 467/737] eckit::geo --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ecb6bf7d5..adf23fad2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +_/ .tags* CMakeLists.txt.user* *.autosave From 3d5adbc32553d7c214ff3074726bcfa2d6ed5994 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 6 Feb 2024 09:48:06 -0100 Subject: [PATCH 468/737] eckit::geo::area::BoundingBox --- src/eckit/geo/area/BoundingBox.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index cad55b922..48fe7bbd5 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -51,6 +51,7 @@ static BoundingBox make_from_spec(const Spec& spec) { auto new_east = spec.get("west", area[1]) && !spec.has("east"); auto new_west = spec.get("east", area[3]) && !spec.has("west"); + ASSERT(!new_east || !new_west); return {area[0], new_west ? area[3] - 360. : area[1], area[2], new_east ? area[1] + 360. : area[3]}; } From 5de64c8241b621dbc5e8c37fa5ee4cd04243fd48 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 6 Feb 2024 09:48:27 -0100 Subject: [PATCH 469/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 28 +++------------------------- src/eckit/geo/Range.h | 13 ------------- tests/geo/range.cc | 24 ++++-------------------- 3 files changed, 7 insertions(+), 58 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 762cdb540..8ef599a5b 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -38,31 +38,10 @@ namespace range { Regular::Regular(size_t n, double a, double b, double _eps) : - Range(n, _eps), a_(a), b_(b) { - if (types::is_approximately_equal(a_, b_, eps())) { - resize(1); - b_ = a_; - values_ = {a_}; - } -} - - -const std::vector& Regular::values() const { - util::lock_guard lock(MUTEX); - - if (values_.empty()) { - const_cast&>(values_) = util::linspace(a_, b_, Range::size(), true); - ASSERT(!values_.empty()); - } - - return values_; -} - - -RegularPeriodic::RegularPeriodic(size_t n, double a, double b, double _eps) : Range(n, _eps), a_(a), b_(b) { constexpr auto db = 1e-12; + // pre-calculate on n = 1 if (types::is_approximately_equal(a_, b_, eps())) { resize(1); b_ = a_; @@ -82,11 +61,11 @@ RegularPeriodic::RegularPeriodic(size_t n, double a, double b, double _eps) : } -const std::vector& RegularPeriodic::values() const { +const std::vector& Regular::values() const { util::lock_guard lock(MUTEX); if (values_.empty()) { - const_cast&>(values_) = util::linspace(a_, b_, Range::size(), false); + const_cast&>(values_) = util::linspace(a_, b_, Range::size(), true); ASSERT(!values_.empty()); } @@ -96,7 +75,6 @@ const std::vector& RegularPeriodic::values() const { Gaussian::Gaussian(size_t N, double a, double b, double _eps) : Range(2 * N, _eps), N_(N), a_(a), b_(b) { - ASSERT(N > 0); // pre-calculate on cropping auto [min, max] = std::minmax(a_, b_); diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index dd07a7db9..5bda6d47c 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -71,19 +71,6 @@ class Regular final : public Range { const std::vector& values() const override; -private: - double a_; - double b_; - std::vector values_; -}; - - -class RegularPeriodic final : public Range { -public: - explicit RegularPeriodic(size_t n, double a, double b, double eps = 0.); - - const std::vector& values() const override; - private: double a_; double b_; diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 520cbf3e1..671c2848b 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -44,7 +44,7 @@ CASE("range::Regular") { } - SECTION("global") { + SECTION("range [-90, 90]") { const range::Regular range(4, -90., 90.); EXPECT(range.size() == 4); @@ -56,26 +56,10 @@ CASE("range::Regular") { EXPECT_APPROX(values[2], 30., EPS); EXPECT_APPROX(values[3], 90., EPS); } -} -CASE("range::RegularPeriodic") { - SECTION("degenerate") { - EXPECT_THROWS_AS(range::RegularPeriodic(0, 0., 0.), eckit::AssertionFailed); - EXPECT_THROWS_AS(range::RegularPeriodic(0, 0., 10.), eckit::AssertionFailed); - - range::RegularPeriodic range1(1, 1., 1.); - EXPECT(range1.size() == 1); - EXPECT(range1.values().front() == 1.); - - range::RegularPeriodic range2(2, 2., 2.); - EXPECT(range2.size() == 1); - EXPECT(range2.values().front() == 2.); - } - - - SECTION("global") { - const range::RegularPeriodic range1(4, -180., 180.); + SECTION("range [-180, 180]") { + const range::Regular range1(4, -180., 180.); EXPECT(range1.size() == 4); const auto& values1 = range1.values(); @@ -86,7 +70,7 @@ CASE("range::RegularPeriodic") { EXPECT_APPROX(values1[2], 0., EPS); EXPECT_APPROX(values1[3], 90., EPS); - const range::RegularPeriodic range2(8, 180., -180.); + const range::Regular range2(8, 180., -180.); EXPECT(range2.size() == 8); const auto& values2 = range2.values(); From 4407c018256b8116f154d068f2b6b2f5602e87c2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 6 Feb 2024 11:09:56 -0100 Subject: [PATCH 470/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 53 ++++++++++++++++++++++++------------------ src/eckit/geo/Range.h | 12 ++++++---- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 8ef599a5b..3a922c0ee 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -27,8 +27,8 @@ namespace eckit::geo { util::recursive_mutex MUTEX; -Range::Range(size_t n, double eps) : - n_(n), eps_(eps) { +Range::Range(size_t n, double _a, double _b, double eps) : + n_(n), a_(_a), b_(_b), eps_(eps) { ASSERT(n > 0); ASSERT(eps_ >= 0); } @@ -37,26 +37,25 @@ Range::Range(size_t n, double eps) : namespace range { -Regular::Regular(size_t n, double a, double b, double _eps) : - Range(n, _eps), a_(a), b_(b) { +Regular::Regular(size_t n, double _a, double _b, double _eps) : + Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps), endpoint_(false) { constexpr auto db = 1e-12; // pre-calculate on n = 1 - if (types::is_approximately_equal(a_, b_, eps())) { - resize(1); - b_ = a_; - endpoint_ = false; - values_ = {a_}; + if (a() < b()) { + b(PointLonLat::normalise_angle_to_minimum(b() - db, a()) + db); + auto inc = (b() - a()) / static_cast(size()); + endpoint_ = types::is_strictly_greater(360., b() - a() + inc); } - else if (a_ < b_) { - b_ = PointLonLat::normalise_angle_to_minimum(b_ - db, a_) + db; - auto inc = (b_ - a_) / static_cast(size()); - endpoint_ = types::is_strictly_greater(360., b_ - a_ + inc); + else if (b() < a()) { + b(PointLonLat::normalise_angle_to_maximum(b() + db, a()) - db); + auto inc = (a() - b()) / static_cast(size()); + endpoint_ = types::is_strictly_greater(360., a() - b() + inc); } else { - b_ = PointLonLat::normalise_angle_to_maximum(b_ + db, a_) - db; - auto inc = (b_ - a_) / static_cast(size()); - endpoint_ = types::is_strictly_greater(360., a_ - b_ + inc); + resize(1); + endpoint_ = false; + values_ = {a()}; } } @@ -65,21 +64,29 @@ const std::vector& Regular::values() const { util::lock_guard lock(MUTEX); if (values_.empty()) { - const_cast&>(values_) = util::linspace(a_, b_, Range::size(), true); + const_cast&>(values_) = util::linspace(a(), b(), size(), endpoint_); ASSERT(!values_.empty()); } return values_; } +Range* Regular::crop(double a, double b) const {} -Gaussian::Gaussian(size_t N, double a, double b, double _eps) : - Range(2 * N, _eps), N_(N), a_(a), b_(b) { +Gaussian::Gaussian(size_t N, double _a, double _b, double _eps) : + Range(2 * N, + types::is_approximately_equal(_a, 90., _eps) ? 90. + : types::is_approximately_equal(_a, -90., _eps) ? -90. + : _a, + types::is_approximately_equal(_b, 90., _eps) ? 90. + : types::is_approximately_equal(_b, -90., _eps) ? -90. + : _b, + _eps), + N_(N) { // pre-calculate on cropping - auto [min, max] = std::minmax(a_, b_); - if (!types::is_approximately_equal(min, -90., eps()) || !types::is_approximately_equal(max, 90., eps())) { - values_ = util::gaussian_latitudes(N_, a_ < b_); + if (auto [min, max] = std::minmax(a(), b()); -90. < min || max < 90.) { + values_ = util::gaussian_latitudes(N_, a() < b()); auto& v = values_; auto [from, to] = util::monotonic_crop(v, min, max, eps()); @@ -95,7 +102,7 @@ Gaussian::Gaussian(size_t N, double a, double b, double _eps) : const std::vector& Gaussian::values() const { util::lock_guard lock(MUTEX); - return values_.empty() ? util::gaussian_latitudes(N_, a_ < b_) : values_; + return values_.empty() ? util::gaussian_latitudes(N_, a() < b()) : values_; } diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 5bda6d47c..727596ab8 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -29,17 +29,23 @@ class Range { Range& operator=(Range&&) = delete; size_t size() const { return n_; } + double a() const { return a_; } + double b() const { return b_; } double eps() const { return eps_; } virtual const std::vector& values() const = 0; protected: - explicit Range(size_t n, double eps = 0.); + explicit Range(size_t n, double a, double b, double eps = 0.); void resize(size_t n) { n_ = n; } + void a(double value) { a_ = value; } + void b(double value) { b_ = value; } private: size_t n_; + double a_; + double b_; const double eps_; }; @@ -59,8 +65,6 @@ class Gaussian final : public Range { private: const size_t N_; - const double a_; - const double b_; std::vector values_; }; @@ -72,8 +76,6 @@ class Regular final : public Range { const std::vector& values() const override; private: - double a_; - double b_; bool endpoint_; std::vector values_; }; From 851d59fd82c173778ca2db61949a85a794586361 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 6 Feb 2024 14:19:17 -0100 Subject: [PATCH 471/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 8 +++++++- src/eckit/geo/Range.h | 31 +++++++++++++++++++++++++++++++ tests/geo/range.cc | 9 ++++----- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 3a922c0ee..38d584de7 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -44,11 +44,15 @@ Regular::Regular(size_t n, double _a, double _b, double _eps) : // pre-calculate on n = 1 if (a() < b()) { b(PointLonLat::normalise_angle_to_minimum(b() - db, a()) + db); + ASSERT(b() - a() <= 360.); + auto inc = (b() - a()) / static_cast(size()); endpoint_ = types::is_strictly_greater(360., b() - a() + inc); } else if (b() < a()) { b(PointLonLat::normalise_angle_to_maximum(b() + db, a()) - db); + ASSERT(a() - b() <= 360.); + auto inc = (a() - b()) / static_cast(size()); endpoint_ = types::is_strictly_greater(360., a() - b() + inc); } @@ -71,7 +75,9 @@ const std::vector& Regular::values() const { return values_; } -Range* Regular::crop(double a, double b) const {} +Range* Regular::crop(double a, double b) const { + auto v = values(); +} Gaussian::Gaussian(size_t N, double _a, double _b, double _eps) : diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 727596ab8..7c9714fdf 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -20,14 +20,22 @@ namespace eckit::geo { class Range { public: + // -- Constructors + Range(const Range&) = delete; Range(Range&&) = delete; + // -- Destructors + virtual ~Range() = default; + // -- Operators + Range& operator=(const Range&) = delete; Range& operator=(Range&&) = delete; + // -- Methods + size_t size() const { return n_; } double a() const { return a_; } double b() const { return b_; } @@ -36,6 +44,8 @@ class Range { virtual const std::vector& values() const = 0; protected: + // -- Constructors + explicit Range(size_t n, double a, double b, double eps = 0.); void resize(size_t n) { n_ = n; } @@ -43,6 +53,8 @@ class Range { void b(double value) { b_ = value; } private: + // -- Members + size_t n_; double a_; double b_; @@ -55,15 +67,24 @@ namespace range { class Gaussian final : public Range { public: + // -- Constructors + explicit Gaussian(size_t N, double eps = 0.) : Gaussian(N, 90., -90., eps) {} Gaussian(size_t N, double crop_a, double crop_b, double eps = 0.); + // -- Methods + size_t N() const { return N_; } + + // -- Overridden methods + const std::vector& values() const override; private: + // -- Members + const size_t N_; std::vector values_; }; @@ -71,11 +92,21 @@ class Gaussian final : public Range { class Regular final : public Range { public: + // -- Constructors + explicit Regular(size_t n, double a, double b, double eps = 0.); + // -- Overridden methods + const std::vector& values() const override; + // -- Methods + + Range* crop(double a, double b) const; + private: + // -- Members + bool endpoint_; std::vector values_; }; diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 671c2848b..e176c70ef 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -45,16 +45,15 @@ CASE("range::Regular") { SECTION("range [-90, 90]") { - const range::Regular range(4, -90., 90.); - EXPECT(range.size() == 4); + const range::Regular range(3, -90., 90.); + EXPECT(range.size() == 3); const auto& values = range.values(); EXPECT(range.size() == values.size()); EXPECT_APPROX(values[0], -90., EPS); - EXPECT_APPROX(values[1], -30., EPS); - EXPECT_APPROX(values[2], 30., EPS); - EXPECT_APPROX(values[3], 90., EPS); + EXPECT_APPROX(values[1], 0., EPS); + EXPECT_APPROX(values[2], 90., EPS); } From 31b5b55383072cd0a02f9f988f6cf95d908b4f52 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 7 Feb 2024 11:57:36 -0100 Subject: [PATCH 472/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 45 ++++++++++++------- src/eckit/geo/Range.h | 7 ++- src/eckit/geo/grid/regular/RegularGaussian.cc | 2 +- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 38d584de7..2a125f7a8 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -26,9 +26,11 @@ namespace eckit::geo { util::recursive_mutex MUTEX; +constexpr auto DB = 1e-12; -Range::Range(size_t n, double _a, double _b, double eps) : - n_(n), a_(_a), b_(_b), eps_(eps) { + +Range::Range(size_t n, double _a, double _b, double _eps) : + n_(n), a_(_a), b_(_b), eps_(_eps) { ASSERT(n > 0); ASSERT(eps_ >= 0); } @@ -37,20 +39,26 @@ Range::Range(size_t n, double _a, double _b, double eps) : namespace range { +static double pole_snap(double lat, double _eps) { + return types::is_approximately_equal(lat, 90., _eps) ? 90. + : types::is_approximately_equal(lat, -90., _eps) ? -90. + : lat; +} + + Regular::Regular(size_t n, double _a, double _b, double _eps) : Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps), endpoint_(false) { - constexpr auto db = 1e-12; // pre-calculate on n = 1 if (a() < b()) { - b(PointLonLat::normalise_angle_to_minimum(b() - db, a()) + db); + b(PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB); ASSERT(b() - a() <= 360.); auto inc = (b() - a()) / static_cast(size()); endpoint_ = types::is_strictly_greater(360., b() - a() + inc); } else if (b() < a()) { - b(PointLonLat::normalise_angle_to_maximum(b() + db, a()) - db); + b(PointLonLat::normalise_angle_to_maximum(b() + DB, a()) - DB); ASSERT(a() - b() <= 360.); auto inc = (a() - b()) / static_cast(size()); @@ -75,21 +83,26 @@ const std::vector& Regular::values() const { return values_; } -Range* Regular::crop(double a, double b) const { - auto v = values(); + +Range* Regular::crop(double _a, double _b) const { + ASSERT_MSG((a() < b() && _a <= _b) || (b() < a() && _b <= _a), "Regular::crop: range does not respect ordering"); + + NOTIMP; // TODO +} + + +Regular Regular::make_global_prime(size_t n, double eps) { + return {n, 0., 360., eps}; +} + + +Regular Regular::make_global_antiprime(size_t n, double eps) { + return {n, -180, 180., eps}; } Gaussian::Gaussian(size_t N, double _a, double _b, double _eps) : - Range(2 * N, - types::is_approximately_equal(_a, 90., _eps) ? 90. - : types::is_approximately_equal(_a, -90., _eps) ? -90. - : _a, - types::is_approximately_equal(_b, 90., _eps) ? 90. - : types::is_approximately_equal(_b, -90., _eps) ? -90. - : _b, - _eps), - N_(N) { + Range(2 * N, pole_snap(_a, _eps), pole_snap(_b, _eps), _eps), N_(N) { // pre-calculate on cropping if (auto [min, max] = std::minmax(a(), b()); -90. < min || max < 90.) { values_ = util::gaussian_latitudes(N_, a() < b()); diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 7c9714fdf..64dea3b85 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -94,7 +94,7 @@ class Regular final : public Range { public: // -- Constructors - explicit Regular(size_t n, double a, double b, double eps = 0.); + Regular(size_t n, double a, double b, double eps = 0.); // -- Overridden methods @@ -102,7 +102,10 @@ class Regular final : public Range { // -- Methods - Range* crop(double a, double b) const; + Regular* crop(double a, double b) const; + + static Regular make_global_prime(size_t n, double eps = 0.); + static Regular make_global_antiprime(size_t n, double eps = 0.); private: // -- Members diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index c3104b4f9..b4c09297b 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -27,7 +27,7 @@ RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : Regular(bbox), - x_(new range::Regular(4 * N, bbox.west, bbox.east)), + x_(range::Regular::make_global_prime(4 * N).crop(bbox.west, bbox.east)), y_(new range::Gaussian(N, bbox.north, bbox.south)) { ASSERT(x_->size() > 0); ASSERT(y_->size() > 0); From 244a63fac2c5b5e814f2de4fe32409aace59850e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 8 Feb 2024 10:42:55 -0100 Subject: [PATCH 473/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 76 ++++++++++--------- src/eckit/geo/Range.h | 18 ++--- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 5 +- src/eckit/geo/grid/regular/RegularGaussian.cc | 4 +- src/eckit/geo/grid/regular/RegularLL.cc | 4 +- tests/geo/range.cc | 28 +++---- 6 files changed, 71 insertions(+), 64 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 2a125f7a8..822956aa6 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -24,11 +24,6 @@ namespace eckit::geo { -util::recursive_mutex MUTEX; - -constexpr auto DB = 1e-12; - - Range::Range(size_t n, double _a, double _b, double _eps) : n_(n), a_(_a), b_(_b), eps_(_eps) { ASSERT(n > 0); @@ -39,14 +34,49 @@ Range::Range(size_t n, double _a, double _b, double _eps) : namespace range { -static double pole_snap(double lat, double _eps) { +namespace { + + +util::recursive_mutex MUTEX; + +constexpr auto DB = 1e-12; + + +double pole_snap(double lat, double _eps) { return types::is_approximately_equal(lat, 90., _eps) ? 90. : types::is_approximately_equal(lat, -90., _eps) ? -90. : lat; } -Regular::Regular(size_t n, double _a, double _b, double _eps) : +} // namespace + + +GaussianLatitude::GaussianLatitude(size_t N, double _a, double _b, double _eps) : + Range(2 * N, pole_snap(_a, _eps), pole_snap(_b, _eps), _eps), N_(N) { + // pre-calculate on cropping + if (auto [min, max] = std::minmax(a(), b()); -90. < min || max < 90.) { + values_ = util::gaussian_latitudes(N_, a() < b()); + auto& v = values_; + + auto [from, to] = util::monotonic_crop(v, min, max, eps()); + v.erase(v.begin() + to, v.end()); + v.erase(v.begin(), v.begin() + from); + + ASSERT(!v.empty()); + resize(v.size()); + } +} + + +const std::vector& GaussianLatitude::values() const { + util::lock_guard lock(MUTEX); + + return values_.empty() ? util::gaussian_latitudes(N_, a() < b()) : values_; +} + + +RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) : Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps), endpoint_(false) { // pre-calculate on n = 1 @@ -72,7 +102,7 @@ Regular::Regular(size_t n, double _a, double _b, double _eps) : } -const std::vector& Regular::values() const { +const std::vector& RegularLongitude::values() const { util::lock_guard lock(MUTEX); if (values_.empty()) { @@ -84,47 +114,23 @@ const std::vector& Regular::values() const { } -Range* Regular::crop(double _a, double _b) const { +RegularLongitude* RegularLongitude::crop(double _a, double _b) const { ASSERT_MSG((a() < b() && _a <= _b) || (b() < a() && _b <= _a), "Regular::crop: range does not respect ordering"); NOTIMP; // TODO } -Regular Regular::make_global_prime(size_t n, double eps) { +RegularLongitude RegularLongitude::make_global_prime(size_t n, double eps) { return {n, 0., 360., eps}; } -Regular Regular::make_global_antiprime(size_t n, double eps) { +RegularLongitude RegularLongitude::make_global_antiprime(size_t n, double eps) { return {n, -180, 180., eps}; } -Gaussian::Gaussian(size_t N, double _a, double _b, double _eps) : - Range(2 * N, pole_snap(_a, _eps), pole_snap(_b, _eps), _eps), N_(N) { - // pre-calculate on cropping - if (auto [min, max] = std::minmax(a(), b()); -90. < min || max < 90.) { - values_ = util::gaussian_latitudes(N_, a() < b()); - auto& v = values_; - - auto [from, to] = util::monotonic_crop(v, min, max, eps()); - v.erase(v.begin() + to, v.end()); - v.erase(v.begin(), v.begin() + from); - - ASSERT(!v.empty()); - resize(v.size()); - } -} - - -const std::vector& Gaussian::values() const { - util::lock_guard lock(MUTEX); - - return values_.empty() ? util::gaussian_latitudes(N_, a() < b()) : values_; -} - - } // namespace range diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 64dea3b85..00d39cd8d 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -65,14 +65,14 @@ class Range { namespace range { -class Gaussian final : public Range { +class GaussianLatitude final : public Range { public: // -- Constructors - explicit Gaussian(size_t N, double eps = 0.) : - Gaussian(N, 90., -90., eps) {} + explicit GaussianLatitude(size_t N, double eps = 0.) : + GaussianLatitude(N, 90., -90., eps) {} - Gaussian(size_t N, double crop_a, double crop_b, double eps = 0.); + GaussianLatitude(size_t N, double crop_a, double crop_b, double eps = 0.); // -- Methods @@ -90,11 +90,11 @@ class Gaussian final : public Range { }; -class Regular final : public Range { +class RegularLongitude final : public Range { public: // -- Constructors - Regular(size_t n, double a, double b, double eps = 0.); + RegularLongitude(size_t n, double a, double b, double eps = 0.); // -- Overridden methods @@ -102,10 +102,10 @@ class Regular final : public Range { // -- Methods - Regular* crop(double a, double b) const; + RegularLongitude* crop(double a, double b) const; - static Regular make_global_prime(size_t n, double eps = 0.); - static Regular make_global_antiprime(size_t n, double eps = 0.); + static RegularLongitude make_global_prime(size_t n, double eps = 0.); + static RegularLongitude make_global_antiprime(size_t n, double eps = 0.); private: // -- Members diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index b99162d9d..5790243d4 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -29,7 +29,7 @@ ReducedGaussian::ReducedGaussian(const Spec& spec) : ReducedGaussian::ReducedGaussian(size_t N, const pl_type& pl, const area::BoundingBox& bbox) : - Reduced(bbox), pl_(pl), j_(0), Nj_(N * 2), y_(new range::Gaussian(N, bbox.north, bbox.south)) { + Reduced(bbox), pl_(pl), j_(0), Nj_(N * 2), y_(new range::GaussianLatitude(N, bbox.north, bbox.south)) { ASSERT(y_); } @@ -63,7 +63,8 @@ const std::vector& ReducedGaussian::latitudes() const { std::vector ReducedGaussian::longitudes(size_t j) const { auto Ni = ni(j); if (!x_ || x_->size() != Ni) { - const_cast&>(x_) = std::make_unique(Ni, bbox().west, bbox().east); + const_cast&>(x_) = + std::make_unique(Ni, bbox().west, bbox().east); } return x_->values(); diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index b4c09297b..aaa8a2c20 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -27,8 +27,8 @@ RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : Regular(bbox), - x_(range::Regular::make_global_prime(4 * N).crop(bbox.west, bbox.east)), - y_(new range::Gaussian(N, bbox.north, bbox.south)) { + x_(range::RegularLongitude::make_global_prime(4 * N).crop(bbox.west, bbox.east)), + y_(new range::GaussianLatitude(N, bbox.north, bbox.south)) { ASSERT(x_->size() > 0); ASSERT(y_->size() > 0); } diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index b991e38e8..d2c7aa579 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -146,8 +146,8 @@ RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const RegularLL::RegularLL(Internal&& internal) : Regular(internal.bbox), internal_(internal), - range_longitude_(new range::Regular(internal_.ni, internal_.bbox.east, internal_.bbox.west)), - range_latitude_(new range::Regular(internal_.nj, internal_.bbox.north, internal_.bbox.south)) { + range_longitude_(new range::RegularLongitude(internal_.ni, internal_.bbox.east, internal_.bbox.west)), + range_latitude_(new range::RegularLongitude(internal_.nj, internal_.bbox.north, internal_.bbox.south)) { ASSERT(size() > 0); ASSERT(ni() == range_longitude_->size()); ASSERT(nj() == range_latitude_->size()); diff --git a/tests/geo/range.cc b/tests/geo/range.cc index e176c70ef..383fb5146 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -31,21 +31,21 @@ constexpr auto EPS = 1e-3; CASE("range::Regular") { SECTION("degenerate") { - EXPECT_THROWS_AS(range::Regular(0, 0., 0.), eckit::AssertionFailed); - EXPECT_THROWS_AS(range::Regular(0, 0., 10.), eckit::AssertionFailed); + EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 0.), eckit::AssertionFailed); + EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 10.), eckit::AssertionFailed); - range::Regular range1(1, 1., 1.); + range::RegularLongitude range1(1, 1., 1.); EXPECT(range1.size() == 1); EXPECT(range1.values().front() == 1.); - range::Regular range2(2, 2., 2.); + range::RegularLongitude range2(2, 2., 2.); EXPECT(range2.size() == 1); EXPECT(range2.values().front() == 2.); } SECTION("range [-90, 90]") { - const range::Regular range(3, -90., 90.); + const range::RegularLongitude range(3, -90., 90.); EXPECT(range.size() == 3); const auto& values = range.values(); @@ -58,7 +58,7 @@ CASE("range::Regular") { SECTION("range [-180, 180]") { - const range::Regular range1(4, -180., 180.); + const range::RegularLongitude range1(4, -180., 180.); EXPECT(range1.size() == 4); const auto& values1 = range1.values(); @@ -69,7 +69,7 @@ CASE("range::Regular") { EXPECT_APPROX(values1[2], 0., EPS); EXPECT_APPROX(values1[3], 90., EPS); - const range::Regular range2(8, 180., -180.); + const range::RegularLongitude range2(8, 180., -180.); EXPECT(range2.size() == 8); const auto& values2 = range2.values(); @@ -89,7 +89,7 @@ CASE("range::Gaussian") { SECTION("global") { - auto global = range::Gaussian(2); + auto global = range::GaussianLatitude(2); EXPECT(global.size() == ref.size()); size_t i = 0; @@ -100,17 +100,17 @@ CASE("range::Gaussian") { SECTION("crop [50., -50.]") { - auto cropped = range::Gaussian(2, 50., -50., EPS); + auto cropped = range::GaussianLatitude(2, 50., -50., EPS); EXPECT(cropped.size() == ref.size() - 2); EXPECT_APPROX(cropped.values()[0], ref[1], EPS); EXPECT_APPROX(cropped.values()[1], ref[2], EPS); - EXPECT(range::Gaussian(2, 59.444, -59.444, 1e-3).size() == 4); - EXPECT(range::Gaussian(2, 59.444, -59.444, 1e-6).size() == 2); - EXPECT(range::Gaussian(2, 59.444, -59.445, 1e-6).size() == 3); + EXPECT(range::GaussianLatitude(2, 59.444, -59.444, 1e-3).size() == 4); + EXPECT(range::GaussianLatitude(2, 59.444, -59.444, 1e-6).size() == 2); + EXPECT(range::GaussianLatitude(2, 59.444, -59.445, 1e-6).size() == 3); - auto single = range::Gaussian(2, -59.444, -59.444, EPS); + auto single = range::GaussianLatitude(2, -59.444, -59.444, EPS); EXPECT(single.size() == 1); EXPECT_APPROX(single.values().front(), ref.back(), EPS); @@ -120,7 +120,7 @@ CASE("range::Gaussian") { SECTION("crop [90., 0.]") { constexpr auto eps = 1e-3; - auto cropped = range::Gaussian(2, 90., 0., eps); + auto cropped = range::GaussianLatitude(2, 90., 0., eps); EXPECT(cropped.size() == ref.size() / 2); EXPECT_APPROX(cropped.values()[0], ref[0], eps); From 21830f75fa404ad0cd7cb983ad903e7352194e33 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 9 Feb 2024 01:28:44 -0100 Subject: [PATCH 474/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 98 ++++++++++++------- src/eckit/geo/Range.h | 14 +-- src/eckit/geo/grid/regular/RegularGaussian.cc | 2 +- tests/geo/grid.cc | 2 +- 4 files changed, 70 insertions(+), 46 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 822956aa6..078492a12 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -19,6 +19,7 @@ #include "eckit/geo/util.h" #include "eckit/geo/util/mutex.h" #include "eckit/types/FloatCompare.h" +#include "eckit/types/Fraction.h" namespace eckit::geo { @@ -65,6 +66,9 @@ GaussianLatitude::GaussianLatitude(size_t N, double _a, double _b, double _eps) ASSERT(!v.empty()); resize(v.size()); + + a(v.front()); + b(v.back()); } } @@ -76,28 +80,69 @@ const std::vector& GaussianLatitude::values() const { } -RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) : - Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps), endpoint_(false) { +RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double crop_a, double crop_b, double _eps) : + Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps) { + // adjust range limits, before cropping + if (types::is_approximately_equal(a(), b(), eps())) { + resize(1); + periodic_ = false; + values_ = {a()}; + } + else if (a() < b()) { + if (auto x = PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB, d = x - a(); + (periodic_ = types::is_approximately_lesser_or_equal(360., d + d / static_cast(n)))) { + b(a() + 360.); - // pre-calculate on n = 1 - if (a() < b()) { - b(PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB); - ASSERT(b() - a() <= 360.); + crop_a = PointLonLat::normalise_angle_to_minimum(crop_a - DB, a()) + DB; + crop_b = PointLonLat::normalise_angle_to_minimum(crop_b - DB, crop_a) + DB; - auto inc = (b() - a()) / static_cast(size()); - endpoint_ = types::is_strictly_greater(360., b() - a() + inc); - } - else if (b() < a()) { - b(PointLonLat::normalise_angle_to_maximum(b() + DB, a()) - DB); - ASSERT(a() - b() <= 360.); + auto adjust = [](const Fraction& target, const Fraction& inc, bool up) -> Fraction { + ASSERT(inc > 0); + + auto r = target / inc; + auto n = r.integralPart(); + + if (!r.integer() && (target > 0) == up) { + n += (up ? 1 : -1); + } - auto inc = (a() - b()) / static_cast(size()); - endpoint_ = types::is_strictly_greater(360., a() - b() + inc); + return (n * inc); + }; + + Fraction inc((b() - a()) / static_cast(periodic_ ? n : (n - 1))); + auto da = (Fraction(a()) / inc).decimalPart() * inc; + + auto fraction_a = adjust(crop_a - da, inc, true) + da; + auto fraction_b = adjust(crop_b - da, inc, false) + da; + auto fraction_n = (fraction_b - fraction_a) / inc; + ASSERT(fraction_n.integer() && 0 < fraction_n && fraction_n <= n); + + if (fraction_b - fraction_a < 360) { + resize(static_cast(fraction_n.integralPart()) + 1); + periodic_ = false; + } + + a(fraction_a); + b(fraction_b); + } + else { + b(x); + + NOTIMP; // FIXME + } } else { - resize(1); - endpoint_ = false; - values_ = {a()}; + if (auto x = PointLonLat::normalise_angle_to_maximum(b() + DB, a()) - DB, d = a() - x; + (periodic_ = types::is_approximately_lesser_or_equal(360., d + d / static_cast(n)))) { + b(a() - 360.); + + NOTIMP; // FIXME + } + else { + b(x); + + NOTIMP; // FIXME + } } } @@ -106,7 +151,7 @@ const std::vector& RegularLongitude::values() const { util::lock_guard lock(MUTEX); if (values_.empty()) { - const_cast&>(values_) = util::linspace(a(), b(), size(), endpoint_); + const_cast&>(values_) = util::linspace(a(), b(), size(), !periodic_); ASSERT(!values_.empty()); } @@ -114,23 +159,6 @@ const std::vector& RegularLongitude::values() const { } -RegularLongitude* RegularLongitude::crop(double _a, double _b) const { - ASSERT_MSG((a() < b() && _a <= _b) || (b() < a() && _b <= _a), "Regular::crop: range does not respect ordering"); - - NOTIMP; // TODO -} - - -RegularLongitude RegularLongitude::make_global_prime(size_t n, double eps) { - return {n, 0., 360., eps}; -} - - -RegularLongitude RegularLongitude::make_global_antiprime(size_t n, double eps) { - return {n, -180, 180., eps}; -} - - } // namespace range diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 00d39cd8d..68051e551 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -94,23 +94,19 @@ class RegularLongitude final : public Range { public: // -- Constructors - RegularLongitude(size_t n, double a, double b, double eps = 0.); + RegularLongitude(size_t n, double a, double b, double eps = 0.) : + RegularLongitude(n, a, b, a, b, eps) {} + + RegularLongitude(size_t n, double a, double b, double crop_a, double crop_b, double eps = 0.); // -- Overridden methods const std::vector& values() const override; - // -- Methods - - RegularLongitude* crop(double a, double b) const; - - static RegularLongitude make_global_prime(size_t n, double eps = 0.); - static RegularLongitude make_global_antiprime(size_t n, double eps = 0.); - private: // -- Members - bool endpoint_; + bool periodic_; std::vector values_; }; diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index aaa8a2c20..2c4ef88c9 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -27,7 +27,7 @@ RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : Regular(bbox), - x_(range::RegularLongitude::make_global_prime(4 * N).crop(bbox.west, bbox.east)), + x_(new range::RegularLongitude(4 * N, 0., 360., bbox.west, bbox.east)), y_(new range::GaussianLatitude(N, bbox.north, bbox.south)) { ASSERT(x_->size() > 0); ASSERT(y_->size() > 0); diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index d57c6dc30..d6ad84850 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -63,7 +63,7 @@ CASE("GridFactory::build") { std::unique_ptr grid4(GridFactory::build(spec)); auto n4 = grid4->size(); - EXPECT_EQUAL(n4, n1 / 2); + EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj } From 68c178bf7682dd10fc54ece94823583304a851af Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 9 Feb 2024 22:31:43 -0100 Subject: [PATCH 475/737] eckit::geo::Range --- tests/geo/grid.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index d6ad84850..85939e3b6 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -64,6 +64,12 @@ CASE("GridFactory::build") { auto n4 = grid4->size(); EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj + + spec.set("east", -1.); + std::unique_ptr grid5(GridFactory::build(spec)); + auto n5 = grid5->size(); + + EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj } From a928a82594f6664c9aa9914d823327cca4f94f4c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 9 Feb 2024 23:22:11 -0100 Subject: [PATCH 476/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 25 +++++++++++++++++++++++++ src/eckit/geo/Range.h | 4 +--- tests/geo/range.cc | 2 +- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 078492a12..c12cc9ccd 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -80,6 +80,31 @@ const std::vector& GaussianLatitude::values() const { } +RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) : + Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps) { + // adjust range limits, before cropping + if (types::is_approximately_equal(a(), b(), eps())) { + resize(1); + periodic_ = false; + values_ = {a()}; + } + else if (a() < b()) { + auto x = PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB; + auto d = x - a(); + + periodic_ = types::is_approximately_lesser_or_equal(360., d + d / static_cast(n)); + b(periodic_ ? a() + 360. : x); + } + else { + auto x = PointLonLat::normalise_angle_to_maximum(b() + DB, a()) - DB; + auto d = a() - x; + + periodic_ = types::is_approximately_lesser_or_equal(360., d + d / static_cast(n)); + b(periodic_ ? a() - 360. : x); + } +} + + RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double crop_a, double crop_b, double _eps) : Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps) { // adjust range limits, before cropping diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 68051e551..743dd68a0 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -94,9 +94,7 @@ class RegularLongitude final : public Range { public: // -- Constructors - RegularLongitude(size_t n, double a, double b, double eps = 0.) : - RegularLongitude(n, a, b, a, b, eps) {} - + RegularLongitude(size_t n, double a, double b, double eps = 0.); RegularLongitude(size_t n, double a, double b, double crop_a, double crop_b, double eps = 0.); // -- Overridden methods diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 383fb5146..5aed49422 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -29,7 +29,7 @@ using namespace geo; constexpr auto EPS = 1e-3; -CASE("range::Regular") { +CASE("range::RegularLongitude") { SECTION("degenerate") { EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 0.), eckit::AssertionFailed); EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 10.), eckit::AssertionFailed); From fd892f9c052ff2cd823f93577989fb0152a3272c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 9 Feb 2024 23:31:08 -0100 Subject: [PATCH 477/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 1 - tests/geo/range.cc | 8 ++++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index c12cc9ccd..f0966f3e2 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -118,7 +118,6 @@ RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double crop_a (periodic_ = types::is_approximately_lesser_or_equal(360., d + d / static_cast(n)))) { b(a() + 360.); - crop_a = PointLonLat::normalise_angle_to_minimum(crop_a - DB, a()) + DB; crop_b = PointLonLat::normalise_angle_to_minimum(crop_b - DB, crop_a) + DB; auto adjust = [](const Fraction& target, const Fraction& inc, bool up) -> Fraction { diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 5aed49422..22e19b398 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -81,6 +81,14 @@ CASE("range::RegularLongitude") { EXPECT_APPROX(values2[3], 45., EPS); EXPECT_APPROX(values2[7], -135., EPS); } + + + SECTION("range [0, 360], cropped") { + const range::RegularLongitude range1(20, 0., 360., -180., 180.); + EXPECT(range1.size() == 20); + EXPECT(range1.a() == -180.); + EXPECT(range1.b() == 180.); + } } From d949b6b2e29ed9f3b850b704a6aba3722d51523b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 10 Feb 2024 00:01:38 -0100 Subject: [PATCH 478/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 53 ++++++++++++++++++++++++------------------ src/eckit/geo/Range.h | 2 +- tests/geo/range.cc | 12 ++++++++-- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index f0966f3e2..917719b91 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -32,6 +32,12 @@ Range::Range(size_t n, double _a, double _b, double _eps) : } +void Range::resize(size_t n) { + ASSERT(n > 0); + n_ = n; +} + + namespace range { @@ -107,6 +113,19 @@ RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double crop_a, double crop_b, double _eps) : Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps) { + auto adjust = [](const Fraction& target, const Fraction& inc, bool up) -> Fraction { + ASSERT(inc > 0); + + auto r = target / inc; + auto n = r.integralPart(); + + if (!r.integer() && (target > 0) == up) { + n += (up ? 1 : -1); + } + + return (n * inc); + }; + // adjust range limits, before cropping if (types::is_approximately_equal(a(), b(), eps())) { resize(1); @@ -120,34 +139,24 @@ RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double crop_a crop_b = PointLonLat::normalise_angle_to_minimum(crop_b - DB, crop_a) + DB; - auto adjust = [](const Fraction& target, const Fraction& inc, bool up) -> Fraction { - ASSERT(inc > 0); - - auto r = target / inc; - auto n = r.integralPart(); - - if (!r.integer() && (target > 0) == up) { - n += (up ? 1 : -1); - } - - return (n * inc); - }; - Fraction inc((b() - a()) / static_cast(periodic_ ? n : (n - 1))); auto da = (Fraction(a()) / inc).decimalPart() * inc; + auto af = adjust(crop_a - da, inc, true) + da; + auto bf = adjust(crop_b - da, inc, false) + da; - auto fraction_a = adjust(crop_a - da, inc, true) + da; - auto fraction_b = adjust(crop_b - da, inc, false) + da; - auto fraction_n = (fraction_b - fraction_a) / inc; - ASSERT(fraction_n.integer() && 0 < fraction_n && fraction_n <= n); + if (bf - af + inc >= 360) { + a(af); + b(af + 360); + } + else { + a(af); + b(bf); - if (fraction_b - fraction_a < 360) { - resize(static_cast(fraction_n.integralPart()) + 1); + auto nf = (bf - af) / inc; + ASSERT(nf.integer() && 0 < nf && nf <= n); + resize(static_cast(nf.integralPart()) + 1); periodic_ = false; } - - a(fraction_a); - b(fraction_b); } else { b(x); diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 743dd68a0..878cfb387 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -48,7 +48,7 @@ class Range { explicit Range(size_t n, double a, double b, double eps = 0.); - void resize(size_t n) { n_ = n; } + void resize(size_t n); void a(double value) { a_ = value; } void b(double value) { b_ = value; } diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 22e19b398..064f382e7 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -84,10 +84,18 @@ CASE("range::RegularLongitude") { SECTION("range [0, 360], cropped") { - const range::RegularLongitude range1(20, 0., 360., -180., 180.); - EXPECT(range1.size() == 20); + const range::RegularLongitude range1(36, 0., 360., -180., 180.); + EXPECT(range1.size() == 36); EXPECT(range1.a() == -180.); EXPECT(range1.b() == 180.); + + const range::RegularLongitude range2(36, 0., 360., -180., 170.); + EXPECT(range2.size() == 36); + EXPECT(range2.b() == 180.); + + const range::RegularLongitude range3(36, 0., 360., -180., 160.); + EXPECT(range3.size() == 36 - 1); + EXPECT(range3.b() == 160.); } } From a56d862b48bf0841ad91456cc0d3ca106b7f0b96 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 12 Feb 2024 17:04:17 +0000 Subject: [PATCH 479/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 67 +++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 917719b91..cf57a30bf 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -56,6 +56,16 @@ double pole_snap(double lat, double _eps) { } +Fraction regular_adjust(const Fraction& target, const Fraction& inc, bool up) { + ASSERT(inc > 0); + + auto r = target / inc; + auto n = r.integralPart() + ((r.integer() || (r > 0) != up) ? 0 : up ? 1 : -1); + + return n * inc; +}; + + } // namespace @@ -113,19 +123,6 @@ RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double crop_a, double crop_b, double _eps) : Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps) { - auto adjust = [](const Fraction& target, const Fraction& inc, bool up) -> Fraction { - ASSERT(inc > 0); - - auto r = target / inc; - auto n = r.integralPart(); - - if (!r.integer() && (target > 0) == up) { - n += (up ? 1 : -1); - } - - return (n * inc); - }; - // adjust range limits, before cropping if (types::is_approximately_equal(a(), b(), eps())) { resize(1); @@ -136,27 +133,6 @@ RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double crop_a if (auto x = PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB, d = x - a(); (periodic_ = types::is_approximately_lesser_or_equal(360., d + d / static_cast(n)))) { b(a() + 360.); - - crop_b = PointLonLat::normalise_angle_to_minimum(crop_b - DB, crop_a) + DB; - - Fraction inc((b() - a()) / static_cast(periodic_ ? n : (n - 1))); - auto da = (Fraction(a()) / inc).decimalPart() * inc; - auto af = adjust(crop_a - da, inc, true) + da; - auto bf = adjust(crop_b - da, inc, false) + da; - - if (bf - af + inc >= 360) { - a(af); - b(af + 360); - } - else { - a(af); - b(bf); - - auto nf = (bf - af) / inc; - ASSERT(nf.integer() && 0 < nf && nf <= n); - resize(static_cast(nf.integralPart()) + 1); - periodic_ = false; - } } else { b(x); @@ -177,6 +153,29 @@ RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double crop_a NOTIMP; // FIXME } } + + + // crop + crop_b = PointLonLat::normalise_angle_to_minimum(crop_b - DB, crop_a) + DB; + + Fraction inc((b() - a()) / static_cast(periodic_ ? n : (n - 1))); + auto da = (Fraction(a()) / inc).decimalPart() * inc; + auto af = regular_adjust(crop_a - da, inc, true) + da; + auto bf = regular_adjust(crop_b - da, inc, false) + da; + + if (bf - af + inc >= 360) { + a(af); + b(af + 360); + } + else { + a(af); + b(bf); + + auto nf = (bf - af) / inc; + ASSERT(nf.integer() && 0 < nf && nf <= n); + resize(static_cast(nf.integralPart()) + 1); + periodic_ = false; + } } From 490e996c30b192c475895f37a972e46f53a4fd00 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 13 Feb 2024 11:56:13 +0000 Subject: [PATCH 480/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 86 ++++++------------- src/eckit/geo/Range.h | 6 +- src/eckit/geo/grid/regular/RegularGaussian.cc | 2 +- tests/geo/range.cc | 70 ++++++++++++--- 4 files changed, 91 insertions(+), 73 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index cf57a30bf..3285f9a9c 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -89,6 +89,11 @@ GaussianLatitude::GaussianLatitude(size_t N, double _a, double _b, double _eps) } +Range* GaussianLatitude::crop(double crop_a, double crop_b) const { + NOTIMP; // FIXME +} + + const std::vector& GaussianLatitude::values() const { util::lock_guard lock(MUTEX); @@ -98,83 +103,48 @@ const std::vector& GaussianLatitude::values() const { RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) : Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps) { - // adjust range limits, before cropping if (types::is_approximately_equal(a(), b(), eps())) { resize(1); periodic_ = false; values_ = {a()}; } else if (a() < b()) { - auto x = PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB; - auto d = x - a(); - - periodic_ = types::is_approximately_lesser_or_equal(360., d + d / static_cast(n)); - b(periodic_ ? a() + 360. : x); + auto new_b = PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB; + periodic_ = types::is_approximately_lesser_or_equal(360., (new_b - a()) * (1. + 1. / static_cast(n))); + b(periodic_ ? a() + 360. : new_b); } else { - auto x = PointLonLat::normalise_angle_to_maximum(b() + DB, a()) - DB; - auto d = a() - x; - - periodic_ = types::is_approximately_lesser_or_equal(360., d + d / static_cast(n)); - b(periodic_ ? a() - 360. : x); + auto new_b = PointLonLat::normalise_angle_to_maximum(b() + DB, a()) - DB; + periodic_ = types::is_approximately_lesser_or_equal(360., (a() - new_b) * (1. + 1. / static_cast(n))); + b(periodic_ ? a() - 360. : new_b); } } -RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double crop_a, double crop_b, double _eps) : - Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps) { - // adjust range limits, before cropping - if (types::is_approximately_equal(a(), b(), eps())) { - resize(1); - periodic_ = false; - values_ = {a()}; - } - else if (a() < b()) { - if (auto x = PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB, d = x - a(); - (periodic_ = types::is_approximately_lesser_or_equal(360., d + d / static_cast(n)))) { - b(a() + 360.); - } - else { - b(x); +Range* RegularLongitude::crop(double crop_a, double crop_b) const { + auto n = size(); + crop_b = PointLonLat::normalise_angle_to_minimum(crop_b - DB, crop_a) + DB; - NOTIMP; // FIXME - } + if (types::is_approximately_equal(crop_a, crop_b, eps())) { + NOTIMP; // FIXME } - else { - if (auto x = PointLonLat::normalise_angle_to_maximum(b() + DB, a()) - DB, d = a() - x; - (periodic_ = types::is_approximately_lesser_or_equal(360., d + d / static_cast(n)))) { - b(a() - 360.); - - NOTIMP; // FIXME + else if (crop_a < crop_b) { + Fraction inc((b() - a()) / static_cast(periodic_ ? n : (n - 1))); + auto da = (Fraction(a()) / inc).decimalPart() * inc; + auto af = regular_adjust(crop_a - da, inc, true) + da; + auto bf = regular_adjust(crop_b - da, inc, false) + da; + + if (bf - af + inc >= 360) { + return new RegularLongitude(n, af, af + 360); } - else { - b(x); - - NOTIMP; // FIXME - } - } - - // crop - crop_b = PointLonLat::normalise_angle_to_minimum(crop_b - DB, crop_a) + DB; - - Fraction inc((b() - a()) / static_cast(periodic_ ? n : (n - 1))); - auto da = (Fraction(a()) / inc).decimalPart() * inc; - auto af = regular_adjust(crop_a - da, inc, true) + da; - auto bf = regular_adjust(crop_b - da, inc, false) + da; + auto nf = (bf - af) / inc; + ASSERT(nf.integer() && nf <= n); - if (bf - af + inc >= 360) { - a(af); - b(af + 360); + return new RegularLongitude(static_cast(nf.integralPart() + 1), af, bf); } else { - a(af); - b(bf); - - auto nf = (bf - af) / inc; - ASSERT(nf.integer() && 0 < nf && nf <= n); - resize(static_cast(nf.integralPart()) + 1); - periodic_ = false; + NOTIMP; // FIXME } } diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 878cfb387..1f75d0135 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -41,7 +41,8 @@ class Range { double b() const { return b_; } double eps() const { return eps_; } - virtual const std::vector& values() const = 0; + virtual Range* crop(double crop_a, double crop_b) const = 0; + virtual const std::vector& values() const = 0; protected: // -- Constructors @@ -80,6 +81,7 @@ class GaussianLatitude final : public Range { // -- Overridden methods + Range* crop(double crop_a, double crop_b) const override; const std::vector& values() const override; private: @@ -95,10 +97,10 @@ class RegularLongitude final : public Range { // -- Constructors RegularLongitude(size_t n, double a, double b, double eps = 0.); - RegularLongitude(size_t n, double a, double b, double crop_a, double crop_b, double eps = 0.); // -- Overridden methods + Range* crop(double crop_a, double crop_b) const override; const std::vector& values() const override; private: diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index 2c4ef88c9..0893be905 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -27,7 +27,7 @@ RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : Regular(bbox), - x_(new range::RegularLongitude(4 * N, 0., 360., bbox.west, bbox.east)), + x_(range::RegularLongitude(4 * N, 0., 360.).crop(bbox.west, bbox.east)), y_(new range::GaussianLatitude(N, bbox.north, bbox.south)) { ASSERT(x_->size() > 0); ASSERT(y_->size() > 0); diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 064f382e7..1e93a4de7 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -10,6 +10,7 @@ */ +#include #include #include "eckit/geo/Range.h" @@ -29,16 +30,28 @@ using namespace geo; constexpr auto EPS = 1e-3; +std::ostream& operator<<(std::ostream& out, const std::vector& v) { + const char* sep = ""; + for (const auto& e : v) { + out << sep << e; + sep = ", "; + } + return out; +} + + CASE("range::RegularLongitude") { SECTION("degenerate") { EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 0.), eckit::AssertionFailed); EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 10.), eckit::AssertionFailed); range::RegularLongitude range1(1, 1., 1.); + EXPECT(range1.size() == 1); EXPECT(range1.values().front() == 1.); range::RegularLongitude range2(2, 2., 2.); + EXPECT(range2.size() == 1); EXPECT(range2.values().front() == 2.); } @@ -46,9 +59,11 @@ CASE("range::RegularLongitude") { SECTION("range [-90, 90]") { const range::RegularLongitude range(3, -90., 90.); + EXPECT(range.size() == 3); const auto& values = range.values(); + EXPECT(range.size() == values.size()); EXPECT_APPROX(values[0], -90., EPS); @@ -59,9 +74,11 @@ CASE("range::RegularLongitude") { SECTION("range [-180, 180]") { const range::RegularLongitude range1(4, -180., 180.); + EXPECT(range1.size() == 4); const auto& values1 = range1.values(); + EXPECT(range1.size() == values1.size()); EXPECT_APPROX(values1[0], -180., EPS); @@ -70,9 +87,11 @@ CASE("range::RegularLongitude") { EXPECT_APPROX(values1[3], 90., EPS); const range::RegularLongitude range2(8, 180., -180.); + EXPECT(range2.size() == 8); const auto& values2 = range2.values(); + EXPECT(range2.size() == values2.size()); EXPECT_APPROX(values2[0], 180., EPS); @@ -84,18 +103,45 @@ CASE("range::RegularLongitude") { SECTION("range [0, 360], cropped") { - const range::RegularLongitude range1(36, 0., 360., -180., 180.); - EXPECT(range1.size() == 36); - EXPECT(range1.a() == -180.); - EXPECT(range1.b() == 180.); - - const range::RegularLongitude range2(36, 0., 360., -180., 170.); - EXPECT(range2.size() == 36); - EXPECT(range2.b() == 180.); - - const range::RegularLongitude range3(36, 0., 360., -180., 160.); - EXPECT(range3.size() == 36 - 1); - EXPECT(range3.b() == 160.); + auto range = range::RegularLongitude(36, 0., 360.); + const std::unique_ptr range1(range.crop(-180., 180.)); + + EXPECT(range1->size() == 36); + EXPECT(range1->a() == -180.); + EXPECT(range1->b() == 180.); + + const std::unique_ptr range2(range.crop(-180., 170.)); + + EXPECT(range2->size() == 36); + EXPECT(range2->b() == 180.); + + const std::unique_ptr range3(range.crop(-180., 160.)); + + EXPECT(range3->size() == 36 - 1); + EXPECT(range3->b() == 160.); + } + + + SECTION("range [0, 180], cropped") { + auto range = range::RegularLongitude(19, 0., 180.); + const std::unique_ptr range1(range.crop(1., 181.)); + + EXPECT(range1->size() == 19 - 1); + EXPECT(range1->a() == 10.); + EXPECT(range1->b() == 180.); + + const std::unique_ptr range2(range.crop(1., 170.)); + + EXPECT(range2->size() == 19 - 2); + EXPECT(range2->a() == 10.); + EXPECT(range2->b() == 170.); + + const std::unique_ptr range3(range.crop(-180., 180.)); + + std::cout << range3->values() << std::endl; + // EXPECT(range3->size() == 36 - 1); + // EXPECT(range3->a() == 180.); + // EXPECT(range3->b() == 160.); } } From f5b5bb17bcedbc455430df75df0ea33782292801 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 13 Feb 2024 17:35:52 +0000 Subject: [PATCH 481/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 86 ++++++++++++------- src/eckit/geo/Range.h | 41 +++++++-- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 2 +- tests/geo/range.cc | 38 ++++---- 4 files changed, 112 insertions(+), 55 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 3285f9a9c..4c4dde226 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -13,6 +13,7 @@ #include "eckit/geo/Range.h" #include +#include #include "eckit/exception/Exceptions.h" #include "eckit/geo/PointLonLat.h" @@ -49,13 +50,6 @@ util::recursive_mutex MUTEX; constexpr auto DB = 1e-12; -double pole_snap(double lat, double _eps) { - return types::is_approximately_equal(lat, 90., _eps) ? 90. - : types::is_approximately_equal(lat, -90., _eps) ? -90. - : lat; -} - - Fraction regular_adjust(const Fraction& target, const Fraction& inc, bool up) { ASSERT(inc > 0); @@ -69,34 +63,42 @@ Fraction regular_adjust(const Fraction& target, const Fraction& inc, bool up) { } // namespace -GaussianLatitude::GaussianLatitude(size_t N, double _a, double _b, double _eps) : - Range(2 * N, pole_snap(_a, _eps), pole_snap(_b, _eps), _eps), N_(N) { - // pre-calculate on cropping - if (auto [min, max] = std::minmax(a(), b()); -90. < min || max < 90.) { - values_ = util::gaussian_latitudes(N_, a() < b()); - auto& v = values_; +GaussianLatitude::GaussianLatitude(size_t N, bool increasing, double eps) : + Range(2 * N, increasing ? -90. : 90., increasing ? 90. : -90., eps), N_(N) {} - auto [from, to] = util::monotonic_crop(v, min, max, eps()); - v.erase(v.begin() + to, v.end()); - v.erase(v.begin(), v.begin() + from); - ASSERT(!v.empty()); - resize(v.size()); +Range* GaussianLatitude::flip() const { + std::vector flipped(size()); + const auto& v = values(); + std::reverse_copy(v.begin(), v.end(), flipped.begin()); - a(v.front()); - b(v.back()); - } + return new GaussianLatitude(N_, std::move(flipped), eps()); } Range* GaussianLatitude::crop(double crop_a, double crop_b) const { - NOTIMP; // FIXME + ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || + (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); + + auto v = values(); + + if ((a() < b()) && (a() < crop_a || crop_b < b())) { + auto [from, to] = util::monotonic_crop(v, crop_a, crop_b, eps()); + v.erase(v.begin() + to, v.end()); + v.erase(v.begin(), v.begin() + from); + } + else if ((b() < a()) && (b() < crop_b || crop_a < a())) { + auto [from, to] = util::monotonic_crop(v, crop_b, crop_a, eps()); + v.erase(v.begin() + to, v.end()); + v.erase(v.begin(), v.begin() + from); + } + + return new GaussianLatitude(N_, std::move(v), eps()); } const std::vector& GaussianLatitude::values() const { util::lock_guard lock(MUTEX); - return values_.empty() ? util::gaussian_latitudes(N_, a() < b()) : values_; } @@ -105,32 +107,52 @@ RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps) { if (types::is_approximately_equal(a(), b(), eps())) { resize(1); - periodic_ = false; + periodic_ = NonPeriodic; values_ = {a()}; } else if (a() < b()) { auto new_b = PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB; - periodic_ = types::is_approximately_lesser_or_equal(360., (new_b - a()) * (1. + 1. / static_cast(n))); - b(periodic_ ? a() + 360. : new_b); + periodic_ = types::is_approximately_lesser_or_equal(360., (new_b - a()) * (1. + 1. / static_cast(n))) + ? PeriodicNoEndPoint + : NonPeriodic; + b(periodic() ? a() + 360. : new_b); } else { auto new_b = PointLonLat::normalise_angle_to_maximum(b() + DB, a()) - DB; - periodic_ = types::is_approximately_lesser_or_equal(360., (a() - new_b) * (1. + 1. / static_cast(n))); - b(periodic_ ? a() - 360. : new_b); + periodic_ = types::is_approximately_lesser_or_equal(360., (a() - new_b) * (1. + 1. / static_cast(n))) + ? PeriodicNoEndPoint + : NonPeriodic; + b(periodic() ? a() - 360. : new_b); } } +Range* RegularLongitude::flip() const { + auto flipped = periodic_ == PeriodicNoEndPoint ? PeriodicNoStartPoint + : periodic_ == PeriodicNoStartPoint ? PeriodicNoEndPoint + : NonPeriodic; + return new RegularLongitude(size(), b(), a(), flipped, eps()); +} + + +Fraction RegularLongitude::increment() const { + return Fraction((b() - a()) / static_cast(periodic() ? size() : (size() - 1))); +} + + Range* RegularLongitude::crop(double crop_a, double crop_b) const { + ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || + (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); + auto n = size(); crop_b = PointLonLat::normalise_angle_to_minimum(crop_b - DB, crop_a) + DB; if (types::is_approximately_equal(crop_a, crop_b, eps())) { NOTIMP; // FIXME } - else if (crop_a < crop_b) { - Fraction inc((b() - a()) / static_cast(periodic_ ? n : (n - 1))); - auto da = (Fraction(a()) / inc).decimalPart() * inc; + else if (a() < b()) { + auto inc(increment()); + auto da = (a() / inc).decimalPart() * inc; auto af = regular_adjust(crop_a - da, inc, true) + da; auto bf = regular_adjust(crop_b - da, inc, false) + da; @@ -153,7 +175,7 @@ const std::vector& RegularLongitude::values() const { util::lock_guard lock(MUTEX); if (values_.empty()) { - const_cast&>(values_) = util::linspace(a(), b(), size(), !periodic_); + const_cast&>(values_) = util::linspace(a(), b(), size(), !periodic()); ASSERT(!values_.empty()); } diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 1f75d0135..3ca44032f 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -15,6 +15,11 @@ #include +namespace eckit { +class Fraction; +} + + namespace eckit::geo { @@ -41,6 +46,7 @@ class Range { double b() const { return b_; } double eps() const { return eps_; } + virtual Range* flip() const = 0; virtual Range* crop(double crop_a, double crop_b) const = 0; virtual const std::vector& values() const = 0; @@ -70,10 +76,7 @@ class GaussianLatitude final : public Range { public: // -- Constructors - explicit GaussianLatitude(size_t N, double eps = 0.) : - GaussianLatitude(N, 90., -90., eps) {} - - GaussianLatitude(size_t N, double crop_a, double crop_b, double eps = 0.); + explicit GaussianLatitude(size_t N, bool increasing, double eps = 0.); // -- Methods @@ -81,10 +84,16 @@ class GaussianLatitude final : public Range { // -- Overridden methods + Range* flip() const override; Range* crop(double crop_a, double crop_b) const override; const std::vector& values() const override; private: + // -- Constructors + + GaussianLatitude(size_t N, std::vector&& values, double _eps) : + Range(values.size(), values.front(), values.back(), _eps), N_(N), values_(values) {} + // -- Members const size_t N_; @@ -98,16 +107,38 @@ class RegularLongitude final : public Range { RegularLongitude(size_t n, double a, double b, double eps = 0.); + // -- Methods + bool periodic() const { return periodic_ != NonPeriodic; } + // -- Overridden methods + Range* flip() const override; Range* crop(double crop_a, double crop_b) const override; const std::vector& values() const override; private: + // -- Types + + enum Periodic + { + NonPeriodic = 0, + PeriodicNoEndPoint, + PeriodicNoStartPoint + }; + + // -- Constructors + + RegularLongitude(size_t n, double a, double b, Periodic periodic, double eps) : + Range(n, a, b, eps), periodic_(periodic) {} + // -- Members - bool periodic_; + Periodic periodic_; std::vector values_; + + // -- Methods + + Fraction increment() const; }; diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 5790243d4..9350bb952 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -29,7 +29,7 @@ ReducedGaussian::ReducedGaussian(const Spec& spec) : ReducedGaussian::ReducedGaussian(size_t N, const pl_type& pl, const area::BoundingBox& bbox) : - Reduced(bbox), pl_(pl), j_(0), Nj_(N * 2), y_(new range::GaussianLatitude(N, bbox.north, bbox.south)) { + Reduced(bbox), pl_(pl), j_(0), Nj_(N * 2), y_(range::GaussianLatitude(N, false).crop(bbox.north, bbox.south)) { ASSERT(y_); } diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 1e93a4de7..46622eb1e 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -41,6 +41,7 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) { CASE("range::RegularLongitude") { +#if 1 SECTION("degenerate") { EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 0.), eckit::AssertionFailed); EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 10.), eckit::AssertionFailed); @@ -120,8 +121,10 @@ CASE("range::RegularLongitude") { EXPECT(range3->size() == 36 - 1); EXPECT(range3->b() == 160.); } +#endif +#if 1 SECTION("range [0, 180], cropped") { auto range = range::RegularLongitude(19, 0., 180.); const std::unique_ptr range1(range.crop(1., 181.)); @@ -143,15 +146,17 @@ CASE("range::RegularLongitude") { // EXPECT(range3->a() == 180.); // EXPECT(range3->b() == 160.); } +#endif } +#if 1 CASE("range::Gaussian") { std::vector ref{59.44440828916676, 19.87571914744090, -19.87571914744090, -59.44440828916676}; SECTION("global") { - auto global = range::GaussianLatitude(2); + auto global = range::GaussianLatitude(2, false); EXPECT(global.size() == ref.size()); size_t i = 0; @@ -162,33 +167,32 @@ CASE("range::Gaussian") { SECTION("crop [50., -50.]") { - auto cropped = range::GaussianLatitude(2, 50., -50., EPS); - EXPECT(cropped.size() == ref.size() - 2); + std::unique_ptr cropped(range::GaussianLatitude(2, false).crop(50., -50.)); + EXPECT(cropped->size() == ref.size() - 2); - EXPECT_APPROX(cropped.values()[0], ref[1], EPS); - EXPECT_APPROX(cropped.values()[1], ref[2], EPS); + EXPECT_APPROX(cropped->values()[0], ref[1], EPS); + EXPECT_APPROX(cropped->values()[1], ref[2], EPS); - EXPECT(range::GaussianLatitude(2, 59.444, -59.444, 1e-3).size() == 4); - EXPECT(range::GaussianLatitude(2, 59.444, -59.444, 1e-6).size() == 2); - EXPECT(range::GaussianLatitude(2, 59.444, -59.445, 1e-6).size() == 3); + EXPECT(std::unique_ptr(range::GaussianLatitude(2, false, 1e-3).crop(59.444, -59.444))->size() == 4); + EXPECT(std::unique_ptr(range::GaussianLatitude(2, false, 1e-6).crop(59.444, -59.444))->size() == 2); + EXPECT(std::unique_ptr(range::GaussianLatitude(2, false, 1e-6).crop(59.444, -59.445))->size() == 3); - auto single = range::GaussianLatitude(2, -59.444, -59.444, EPS); - EXPECT(single.size() == 1); + std::unique_ptr single(range::GaussianLatitude(2, false, EPS).crop(-59.444, -59.444)); + EXPECT(single->size() == 1); - EXPECT_APPROX(single.values().front(), ref.back(), EPS); + EXPECT_APPROX(single->values().front(), ref.back(), EPS); } SECTION("crop [90., 0.]") { - constexpr auto eps = 1e-3; + std::unique_ptr cropped(range::GaussianLatitude(2, false, EPS).crop(90., 0.)); + EXPECT(cropped->size() == ref.size() / 2); - auto cropped = range::GaussianLatitude(2, 90., 0., eps); - EXPECT(cropped.size() == ref.size() / 2); - - EXPECT_APPROX(cropped.values()[0], ref[0], eps); - EXPECT_APPROX(cropped.values()[1], ref[1], eps); + EXPECT_APPROX(cropped->values()[0], ref[0], EPS); + EXPECT_APPROX(cropped->values()[1], ref[1], EPS); } } +#endif } // namespace eckit::test From c278e039793614846559f0435a9d04dc86637f6b Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Tue, 13 Feb 2024 21:18:39 +0000 Subject: [PATCH 482/737] ECC-1364: GRIB: Geoiterator for Lambert Conformal in the southern hemisphere --- src/grib_iterator_class_lambert_conformal.cc | 76 ++++++++++++++++---- 1 file changed, 64 insertions(+), 12 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.cc b/src/grib_iterator_class_lambert_conformal.cc index 3e9d51055..b50ad72cf 100644 --- a/src/grib_iterator_class_lambert_conformal.cc +++ b/src/grib_iterator_class_lambert_conformal.cc @@ -162,6 +162,25 @@ static double calculate_eccentricity(double minor, double major) return sqrt(1.0 - temp * temp); } +static void inverse(double radius, double n, double f, double rho0_bare, double LoVInRadians, double x, double y, + double* latDeg, double* lonDeg) +{ + x /= radius; + y /= radius; + y = rho0_bare - y; + double rho = hypot(x, y); + Assert(rho != 0.0); + if (n < 0.0) { + rho = -rho; + x = -x; + y = -y; + } + double lp_phi = 2. * atan(pow(f / rho, 1.0/n)) - M_PI_2; + double lp_lam = atan2(x, y) / n; + *lonDeg = lp_lam*RAD2DEG + LoVInRadians*RAD2DEG; + *latDeg = lp_phi*RAD2DEG; +} + static int init_sphere(grib_handle* h, grib_iterator_lambert_conformal* self, size_t nv, long nx, long ny, @@ -171,8 +190,8 @@ static int init_sphere(grib_handle* h, double LoVInRadians, double Latin1InRadians, double Latin2InRadians, double LaDInRadians) { - int i, j; - double f, n, rho, rho0, angle, x0, y0, x, y, tmp, tmp2; + long i, j; + double f, n, rho, rho0, angle, x0, y0, x, y; double latDeg, lonDeg, lonDiff; if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { @@ -185,8 +204,10 @@ static int init_sphere(grib_handle* h, f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); - if (n < 0) /* adjustment for southern hemisphere */ - rho0 = -rho0; + double rho0_bare = f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); + + //if (n < 0) /* adjustment for southern hemisphere */ + // rho0 = -rho0; lonDiff = lonFirstInRadians - LoVInRadians; /* Adjust longitude to range -180 to 180 */ @@ -212,21 +233,52 @@ static int init_sphere(grib_handle* h, grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } - - /* Populate our arrays */ + + //------------PROJ lcc_e_inverse ------ + //double x0_bare = x0/radius; + //double y0_bare = y0/radius; + // y0_bare = rho0_bare - y0_bare; +// rho = hypot(x0_bare, y0_bare); +// Assert(rho != 0.0); +// if (n < 0.0) { +// rho = -rho; +// x0_bare = -x0_bare; +// y0_bare = -y0_bare; +// } +// double lp_phi = 2. * atan(pow(f / rho, 1./n)) - M_PI_2; +// double lp_lam = atan2(x0_bare, y0_bare) / n; +// lonDeg = lp_lam * RAD2DEG + LoVInDegrees; +// latDeg = lp_phi * RAD2DEG; +// printf("phi=%g lam=%g\n", lp_phi ,lp_lam); + //-------------------------------------- + //inverse(radius, n, f, rho0_bare, LoVInRadians, x0, y0, &latDeg, &lonDeg); + for (j = 0; j < ny; j++) { y = y0 + j * Dy; - if (n < 0) { /* adjustment for southern hemisphere */ - y = -y; + for (i = 0; i < nx; i++) { + const long index = i + j * nx; + x = x0 + i * Dx; + inverse(radius, n, f, rho0_bare, LoVInRadians, x, y, &latDeg, &lonDeg); + self->lons[index] = lonDeg; + self->lats[index] = latDeg; } + } +#if 0 + /* Populate our arrays */ + for (j = 0; j < ny; j++) { + y = y0 + j * Dy; + //if (n < 0) { /* adjustment for southern hemisphere */ + // y = -y; + //} tmp = rho0 - y; tmp2 = tmp * tmp; for (i = 0; i < nx; i++) { int index = i + j * nx; x = x0 + i * Dx; - if (n < 0) { /* adjustment for southern hemisphere */ - x = -x; - } + //printf("j=%d i=%d xy= %.6f %.6f\t",j,i,x,y); + //if (n < 0) { /* adjustment for southern hemisphere */ + // x = -x; + //} angle = atan2(x, tmp); /* See ECC-524 */ rho = sqrt(x * x + tmp2); if (n <= 0) rho = -rho; @@ -237,7 +289,7 @@ static int init_sphere(grib_handle* h, self->lats[index] = latDeg; } } - +#endif return GRIB_SUCCESS; } From adeaba60db0cd06b44c47cfe4ee76fe9960cc35c Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 14 Feb 2024 10:48:24 +0000 Subject: [PATCH 483/737] ECC-1364: Cleanup --- src/grib_iterator_class_lambert_conformal.cc | 70 ++++++++------------ 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.cc b/src/grib_iterator_class_lambert_conformal.cc index b50ad72cf..eea6f40c9 100644 --- a/src/grib_iterator_class_lambert_conformal.cc +++ b/src/grib_iterator_class_lambert_conformal.cc @@ -162,26 +162,32 @@ static double calculate_eccentricity(double minor, double major) return sqrt(1.0 - temp * temp); } -static void inverse(double radius, double n, double f, double rho0_bare, double LoVInRadians, double x, double y, +static void xy2latlon(double radius, double n, double f, double rho0_bare, double LoVInRadians, + double x, double y, double* latDeg, double* lonDeg) { x /= radius; y /= radius; y = rho0_bare - y; double rho = hypot(x, y); - Assert(rho != 0.0); - if (n < 0.0) { - rho = -rho; - x = -x; - y = -y; + if (rho != 0.0) { + if (n < 0.0) { + rho = -rho; + x = -x; + y = -y; + } + double lp_phi = 2. * atan(pow(f / rho, 1.0/n)) - M_PI_2; + double lp_lam = atan2(x, y) / n; + *lonDeg = lp_lam*RAD2DEG + LoVInRadians*RAD2DEG; + *latDeg = lp_phi*RAD2DEG; + } + else { + *lonDeg = 0.0; + *latDeg = (n > 0.0 ? M_PI_2 : -M_PI_2) * RAD2DEG; } - double lp_phi = 2. * atan(pow(f / rho, 1.0/n)) - M_PI_2; - double lp_lam = atan2(x, y) / n; - *lonDeg = lp_lam*RAD2DEG + LoVInRadians*RAD2DEG; - *latDeg = lp_phi*RAD2DEG; } -static int init_sphere(grib_handle* h, +static int init_sphere(const grib_handle* h, grib_iterator_lambert_conformal* self, size_t nv, long nx, long ny, double LoVInDegrees, @@ -190,9 +196,7 @@ static int init_sphere(grib_handle* h, double LoVInRadians, double Latin1InRadians, double Latin2InRadians, double LaDInRadians) { - long i, j; - double f, n, rho, rho0, angle, x0, y0, x, y; - double latDeg, lonDeg, lonDiff; + double n, angle, x0, y0, x, y; if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { n = sin(Latin1InRadians); @@ -201,14 +205,14 @@ static int init_sphere(grib_handle* h, log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); } - f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; - rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); - rho0 = radius * f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); + double f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; + double rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); double rho0_bare = f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); + double rho0 = radius * rho0_bare; //if (n < 0) /* adjustment for southern hemisphere */ // rho0 = -rho0; - lonDiff = lonFirstInRadians - LoVInRadians; + double lonDiff = lonFirstInRadians - LoVInRadians; /* Adjust longitude to range -180 to 180 */ if (lonDiff > M_PI) @@ -233,32 +237,14 @@ static int init_sphere(grib_handle* h, grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); return GRIB_OUT_OF_MEMORY; } - - //------------PROJ lcc_e_inverse ------ - //double x0_bare = x0/radius; - //double y0_bare = y0/radius; - // y0_bare = rho0_bare - y0_bare; -// rho = hypot(x0_bare, y0_bare); -// Assert(rho != 0.0); -// if (n < 0.0) { -// rho = -rho; -// x0_bare = -x0_bare; -// y0_bare = -y0_bare; -// } -// double lp_phi = 2. * atan(pow(f / rho, 1./n)) - M_PI_2; -// double lp_lam = atan2(x0_bare, y0_bare) / n; -// lonDeg = lp_lam * RAD2DEG + LoVInDegrees; -// latDeg = lp_phi * RAD2DEG; -// printf("phi=%g lam=%g\n", lp_phi ,lp_lam); - //-------------------------------------- - //inverse(radius, n, f, rho0_bare, LoVInRadians, x0, y0, &latDeg, &lonDeg); - - for (j = 0; j < ny; j++) { + + double latDeg = 0, lonDeg = 0; + for (long j = 0; j < ny; j++) { y = y0 + j * Dy; - for (i = 0; i < nx; i++) { + for (long i = 0; i < nx; i++) { const long index = i + j * nx; x = x0 + i * Dx; - inverse(radius, n, f, rho0_bare, LoVInRadians, x, y, &latDeg, &lonDeg); + xy2latlon(radius, n, f, rho0_bare, LoVInRadians, x, y, &latDeg, &lonDeg); self->lons[index] = lonDeg; self->lats[index] = latDeg; } @@ -294,7 +280,7 @@ static int init_sphere(grib_handle* h, } /* Oblate spheroid */ -static int init_oblate(grib_handle* h, +static int init_oblate(const grib_handle* h, grib_iterator_lambert_conformal* self, size_t nv, long nx, long ny, double LoVInDegrees, From e3ed25e137f4467a033c6ac577bec62d53fc6371 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Wed, 14 Feb 2024 14:52:56 +0000 Subject: [PATCH 484/737] ECC-1364: Cleanup --- src/grib_iterator_class_lambert_conformal.cc | 139 +++++++++---------- 1 file changed, 68 insertions(+), 71 deletions(-) diff --git a/src/grib_iterator_class_lambert_conformal.cc b/src/grib_iterator_class_lambert_conformal.cc index eea6f40c9..5d15a67b6 100644 --- a/src/grib_iterator_class_lambert_conformal.cc +++ b/src/grib_iterator_class_lambert_conformal.cc @@ -85,21 +85,21 @@ static void init_class(grib_iterator_class* c) #define EPSILON 1.0e-10 #ifndef M_PI -#define M_PI 3.14159265358979323846 /* Whole pie */ +#define M_PI 3.14159265358979323846 // Whole pie #endif #ifndef M_PI_2 -#define M_PI_2 1.57079632679489661923 /* Half a pie */ +#define M_PI_2 1.57079632679489661923 // Half a pie #endif #ifndef M_PI_4 -#define M_PI_4 0.78539816339744830962 /* Quarter of a pie */ +#define M_PI_4 0.78539816339744830962 // Quarter of a pie #endif -#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ -#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +#define RAD2DEG 57.29577951308232087684 // 180 over pi +#define DEG2RAD 0.01745329251994329576 // pi over 180 -/* Adjust longitude (in radians) to range -180 to 180 */ +// Adjust longitude (in radians) to range -180 to 180 static double adjust_lon_radians(double lon) { if (lon > M_PI) lon -= 2 * M_PI; @@ -107,16 +107,15 @@ static double adjust_lon_radians(double lon) return lon; } -/* Function to compute the latitude angle, phi2, for the inverse - * From the book "Map Projections-A Working Manual-John P. Snyder (1987)" - * Equation (7-9) involves rapidly converging iteration: Calculate t from (15-11) - * Then, assuming an initial trial phi equal to (pi/2 - 2*arctan t) in the right side of equation (7-9), - * calculate phi on the left side. Substitute the calculated phi) into the right side, - * calculate a new phi, etc., until phi does not change significantly from the preceding trial value of phi - */ +// Function to compute the latitude angle, phi2, for the inverse +// From the book "Map Projections-A Working Manual-John P. Snyder (1987)" +// Equation (7-9) involves rapidly converging iteration: Calculate t from (15-11) +// Then, assuming an initial trial phi equal to (pi/2 - 2*arctan t) in the right side of equation (7-9), +// calculate phi on the left side. Substitute the calculated phi) into the right side, +// calculate a new phi, etc., until phi does not change significantly from the preceding trial value of phi static double compute_phi( - double eccent, /* Spheroid eccentricity */ - double ts, /* Constant value t */ + double eccent, // Spheroid eccentricity + double ts, // Constant value t int* error) { double eccnth, phi, con, dphi, sinpi; @@ -136,19 +135,19 @@ static double compute_phi( return 0; } -/* Compute the constant small m which is the radius of - a parallel of latitude, phi, divided by the semimajor axis */ +// Compute the constant small m which is the radius of +// a parallel of latitude, phi, divided by the semimajor axis static double compute_m(double eccent, double sinphi, double cosphi) { const double con = eccent * sinphi; return ((cosphi / (sqrt(1.0 - con * con)))); } -/* Compute the constant small t for use in the forward computations */ +// Compute the constant small t for use in the forward computations static double compute_t( - double eccent, /* Eccentricity of the spheroid */ - double phi, /* Latitude phi */ - double sinphi) /* Sine of the latitude */ + double eccent, // Eccentricity of the spheroid + double phi, // Latitude phi + double sinphi) // Sine of the latitude { double con = eccent * sinphi; double com = 0.5 * eccent; @@ -162,10 +161,12 @@ static double calculate_eccentricity(double minor, double major) return sqrt(1.0 - temp * temp); } -static void xy2latlon(double radius, double n, double f, double rho0_bare, double LoVInRadians, +static void xy2lonlat(double radius, double n, double f, double rho0_bare, double LoVInRadians, double x, double y, - double* latDeg, double* lonDeg) + double* lonDeg, double* latDeg) { + DEBUG_ASSERT(radius > 0); + DEBUG_ASSERT(n != 0.0); x /= radius; y /= radius; y = rho0_bare - y; @@ -176,10 +177,10 @@ static void xy2latlon(double radius, double n, double f, double rho0_bare, doubl x = -x; y = -y; } - double lp_phi = 2. * atan(pow(f / rho, 1.0/n)) - M_PI_2; - double lp_lam = atan2(x, y) / n; - *lonDeg = lp_lam*RAD2DEG + LoVInRadians*RAD2DEG; - *latDeg = lp_phi*RAD2DEG; + double latRadians = 2. * atan(pow(f / rho, 1.0/n)) - M_PI_2; + double lonRadians = atan2(x, y) / n; + *lonDeg = (lonRadians + LoVInRadians) * RAD2DEG; + *latDeg = latRadians * RAD2DEG; } else { *lonDeg = 0.0; @@ -196,7 +197,7 @@ static int init_sphere(const grib_handle* h, double LoVInRadians, double Latin1InRadians, double Latin2InRadians, double LaDInRadians) { - double n, angle, x0, y0, x, y; + double n, x, y; if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { n = sin(Latin1InRadians); @@ -208,25 +209,22 @@ static int init_sphere(const grib_handle* h, double f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; double rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); double rho0_bare = f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); - double rho0 = radius * rho0_bare; - - //if (n < 0) /* adjustment for southern hemisphere */ - // rho0 = -rho0; + double rho0 = radius * rho0_bare; // scaled double lonDiff = lonFirstInRadians - LoVInRadians; - /* Adjust longitude to range -180 to 180 */ + // Adjust longitude to range -180 to 180 if (lonDiff > M_PI) lonDiff -= 2 * M_PI; if (lonDiff < -M_PI) lonDiff += 2 * M_PI; - angle = n * lonDiff; - x0 = rho * sin(angle); - y0 = rho0 - rho * cos(angle); - /*Dx = iScansNegatively == 0 ? Dx : -Dx;*/ - /* GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint */ - /*Dy = jScansPositively == 1 ? Dy : -Dy;*/ - - /* Allocate latitude and longitude arrays */ + double angle = n * lonDiff; + double x0 = rho * sin(angle); + double y0 = rho0 - rho * cos(angle); + // Dx = iScansNegatively == 0 ? Dx : -Dx; + // GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint + // Dy = jScansPositively == 1 ? Dy : -Dy; + + // Allocate latitude and longitude arrays self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); @@ -244,13 +242,13 @@ static int init_sphere(const grib_handle* h, for (long i = 0; i < nx; i++) { const long index = i + j * nx; x = x0 + i * Dx; - xy2latlon(radius, n, f, rho0_bare, LoVInRadians, x, y, &latDeg, &lonDeg); + xy2lonlat(radius, n, f, rho0_bare, LoVInRadians, x, y, &lonDeg, &latDeg); self->lons[index] = lonDeg; self->lats[index] = latDeg; } } + #if 0 - /* Populate our arrays */ for (j = 0; j < ny; j++) { y = y0 + j * Dy; //if (n < 0) { /* adjustment for southern hemisphere */ @@ -260,8 +258,7 @@ static int init_sphere(const grib_handle* h, tmp2 = tmp * tmp; for (i = 0; i < nx; i++) { int index = i + j * nx; - x = x0 + i * Dx; - //printf("j=%d i=%d xy= %.6f %.6f\t",j,i,x,y); + x = x0 + i * Dx; //if (n < 0) { /* adjustment for southern hemisphere */ // x = -x; //} @@ -279,7 +276,7 @@ static int init_sphere(const grib_handle* h, return GRIB_SUCCESS; } -/* Oblate spheroid */ +// Oblate spheroid static int init_oblate(const grib_handle* h, grib_iterator_lambert_conformal* self, size_t nv, long nx, long ny, @@ -292,20 +289,20 @@ static int init_oblate(const grib_handle* h, { int i, j, err = 0; double x0, y0, x, y, latRad, lonRad, latDeg, lonDeg, sinphi, ts, rh1, theta; - double false_easting; /* x offset in meters */ - double false_northing; /* y offset in meters */ - - double ns; /* ratio of angle between meridian */ - double F; /* flattening of ellipsoid */ - double rh; /* height above ellipsoid */ - double sin_po; /* sin value */ - double cos_po; /* cos value */ - double con; /* temporary variable */ - double ms1; /* small m 1 */ - double ms2; /* small m 2 */ - double ts0; /* small t 0 */ - double ts1; /* small t 1 */ - double ts2; /* small t 2 */ + double false_easting; // x offset in meters + double false_northing; // y offset in meters + + double ns; // ratio of angle between meridian + double F; // flattening of ellipsoid + double rh; // height above ellipsoid + double sin_po; // sin value + double cos_po; // cos value + double con; // temporary variable + double ms1; // small m 1 + double ms2; // small m 2 + double ts0; // small t 0 + double ts1; // small t 1 + double ts2; // small t 2 double e = calculate_eccentricity(earthMinorAxisInMetres, earthMajorAxisInMetres); @@ -330,7 +327,7 @@ static int init_oblate(const grib_handle* h, F = ms1 / (ns * pow(ts1, ns)); rh = earthMajorAxisInMetres * F * pow(ts0, ns); - /* Forward projection: convert lat,lon to x,y */ + // Forward projection: convert lat,lon to x,y con = fabs(fabs(latFirstInRadians) - M_PI_2); if (con > EPSILON) { sinphi = sin(latFirstInRadians); @@ -350,7 +347,7 @@ static int init_oblate(const grib_handle* h, x0 = -x0; y0 = -y0; - /* Allocate latitude and longitude arrays */ + // Allocate latitude and longitude arrays self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); if (!self->lats) { grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); @@ -362,7 +359,7 @@ static int init_oblate(const grib_handle* h, return GRIB_OUT_OF_MEMORY; } - /* Populate our arrays */ + // Populate our arrays false_easting = x0; false_northing = y0; for (j = 0; j < ny; j++) { @@ -371,7 +368,7 @@ static int init_oblate(const grib_handle* h, const int index = i + j * nx; double _x, _y; x = i * Dx; - /* Inverse projection to convert from x,y to lat,lon */ + // Inverse projection to convert from x,y to lat,lon _x = x - false_easting; _y = rh - y + false_northing; rh1 = sqrt(_x * _x + _y * _y); @@ -401,7 +398,7 @@ static int init_oblate(const grib_handle* h, if (i == 0 && j == 0) { DEBUG_ASSERT(fabs(latFirstInRadians - latRad) <= EPSILON); } - latDeg = latRad * RAD2DEG; /* Convert to degrees */ + latDeg = latRad * RAD2DEG; // Convert to degrees lonDeg = normalise_longitude_in_degrees(lonRad * RAD2DEG); self->lons[index] = lonDeg; self->lats[index] = latDeg; @@ -431,7 +428,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) const char* sLatin2InDegrees = grib_arguments_get_name(h, args, self->carg++); const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - /* Dx and Dy are in Metres */ + // Dx and Dy are in Metres const char* sDx = grib_arguments_get_name(h, args, self->carg++); const char* sDy = grib_arguments_get_name(h, args, self->carg++); const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); @@ -481,16 +478,16 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) if ((err = grib_get_long_internal(h, salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) return err; - /* Standard Parallels cannot be equal and on opposite sides of the equator */ + // Standard Parallels cannot be equal and on opposite sides of the equator if (fabs(Latin1InDegrees + Latin2InDegrees) < EPSILON) { grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Cannot have equal latitudes for standard parallels on opposite sides of equator", ITER); return GRIB_WRONG_GRID; } - /* - * See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html - */ + // + // See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html + // latFirstInRadians = latFirstInDegrees * DEG2RAD; lonFirstInRadians = lonFirstInDegrees * DEG2RAD; Latin1InRadians = Latin1InDegrees * DEG2RAD; @@ -516,7 +513,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) iter->e = -1; - /* Apply the scanning mode flags which may require data array to be transformed */ + // Apply the scanning mode flags which may require data array to be transformed err = transform_iterator_data(h->context, iter->data, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, iter->nv, nx, ny); From 9a1ca773c9513e30bf14683e8481e8a2a2b421a8 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 14 Feb 2024 16:57:25 +0000 Subject: [PATCH 485/737] eckit::geo::Ordering --- src/eckit/geo/Ordering.h | 53 +++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/eckit/geo/Ordering.h b/src/eckit/geo/Ordering.h index 955645e86..c077c1f17 100644 --- a/src/eckit/geo/Ordering.h +++ b/src/eckit/geo/Ordering.h @@ -18,32 +18,39 @@ namespace eckit::geo { enum Ordering { - regular_scan_i_positively_j_negatively_ij_i_single_direction, - regular_scan_i_negatively_j_negatively_ij_i_single_direction, - regular_scan_i_positively_j_positively_ij_i_single_direction, - regular_scan_i_negatively_j_positively_ij_i_single_direction, - regular_scan_i_positively_j_negatively_ji_i_single_direction, - regular_scan_i_negatively_j_negatively_ji_i_single_direction, - regular_scan_i_positively_j_positively_ji_i_single_direction, - regular_scan_i_negatively_j_positively_ji_i_single_direction, - regular_scan_i_positively_j_negatively_ij_i_alternating_direction, - regular_scan_i_negatively_j_negatively_ij_i_alternating_direction, - regular_scan_i_positively_j_positively_ij_i_alternating_direction, - regular_scan_i_negatively_j_positively_ij_i_alternating_direction, - regular_scan_i_positively_j_negatively_ji_i_alternating_direction, - regular_scan_i_negatively_j_negatively_ji_i_alternating_direction, - regular_scan_i_positively_j_positively_ji_i_alternating_direction, - regular_scan_i_negatively_j_positively_ji_i_alternating_direction, - // TODO regular_scan_ ... shift - - reduced_scan_i_positively_j_negatively, - reduced_scan_i_negatively_j_negatively, - reduced_scan_i_positively_j_positively, - reduced_scan_i_negatively_j_positively, - // TODO reduced_scan_ ... shift + regular_i_positively_j_negatively_ij_i_single_direction, + regular_i_negatively_j_negatively_ij_i_single_direction, + regular_i_positively_j_positively_ij_i_single_direction, + regular_i_negatively_j_positively_ij_i_single_direction, + regular_i_positively_j_negatively_ji_i_single_direction, + regular_i_negatively_j_negatively_ji_i_single_direction, + regular_i_positively_j_positively_ji_i_single_direction, + regular_i_negatively_j_positively_ji_i_single_direction, + regular_i_positively_j_negatively_ij_i_alternating_direction, + regular_i_negatively_j_negatively_ij_i_alternating_direction, + regular_i_positively_j_positively_ij_i_alternating_direction, + regular_i_negatively_j_positively_ij_i_alternating_direction, + regular_i_positively_j_negatively_ji_i_alternating_direction, + regular_i_negatively_j_negatively_ji_i_alternating_direction, + regular_i_positively_j_positively_ji_i_alternating_direction, + regular_i_negatively_j_positively_ji_i_alternating_direction, + // TODO regular_ ... shift + + reduced_i_positively_j_negatively, + reduced_i_negatively_j_negatively, + reduced_i_positively_j_positively, + reduced_i_negatively_j_positively, + // TODO reduced_ ... shift healpix_ring, healpix_nested, + + regular_ordering = regular_i_positively_j_negatively_ij_i_single_direction, + regular_ordering_end = regular_i_negatively_j_positively_ji_i_alternating_direction, + reduced_ordering = reduced_i_positively_j_negatively, + reduced_ordering_end = reduced_i_negatively_j_positively, + healpix_ordering = healpix_ring, + healpix_ordering_end = healpix_nested, }; From 5c1a7424ee493895fb3d6c4fbc0c3162441d1f0a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 14 Feb 2024 16:57:53 +0000 Subject: [PATCH 486/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 23 ++++---- src/eckit/geo/grid/regular/RegularGaussian.cc | 2 +- tests/geo/grid.cc | 57 +++++++++++++++---- tests/geo/range.cc | 50 ++++++++-------- 4 files changed, 83 insertions(+), 49 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 4c4dde226..12787937c 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -144,30 +144,29 @@ Range* RegularLongitude::crop(double crop_a, double crop_b) const { ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); - auto n = size(); - crop_b = PointLonLat::normalise_angle_to_minimum(crop_b - DB, crop_a) + DB; - if (types::is_approximately_equal(crop_a, crop_b, eps())) { NOTIMP; // FIXME } else if (a() < b()) { + ASSERT(a() <= crop_a && crop_b <= b()); // FIXME do better + auto inc(increment()); - auto da = (a() / inc).decimalPart() * inc; - auto af = regular_adjust(crop_a - da, inc, true) + da; - auto bf = regular_adjust(crop_b - da, inc, false) + da; + auto d = (a() / inc).decimalPart() * inc; + auto _a = regular_adjust(crop_a - d, inc, true) + d; + auto _b = regular_adjust(crop_b - d, inc, false) + d; - if (bf - af + inc >= 360) { - return new RegularLongitude(n, af, af + 360); - } + auto nf = (_b - _a) / inc; + ASSERT(nf.integer()); - auto nf = (bf - af) / inc; - ASSERT(nf.integer() && nf <= n); + auto n = static_cast(nf.integralPart() + (nf * inc >= 360 ? 0 : 1)); + ASSERT(0 < n && n <= size()); - return new RegularLongitude(static_cast(nf.integralPart() + 1), af, bf); + return new RegularLongitude(n, _a, _b); } else { NOTIMP; // FIXME } + NOTIMP; } diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index 0893be905..2a3c143b9 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -28,7 +28,7 @@ RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : Regular(bbox), x_(range::RegularLongitude(4 * N, 0., 360.).crop(bbox.west, bbox.east)), - y_(new range::GaussianLatitude(N, bbox.north, bbox.south)) { + y_(range::GaussianLatitude(N, false).crop(bbox.north, bbox.south)) { ASSERT(x_->size() > 0); ASSERT(y_->size() > 0); } diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index 85939e3b6..9b506dffe 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -53,23 +53,56 @@ CASE("GridFactory::build") { EXPECT_EQUAL(n2, n1 / 2); - spec = spec::Custom{{{"grid", "f2"}, {"west", -180}}}; - std::unique_ptr grid3(GridFactory::build(spec)); - auto n3 = grid3->size(); + // spec = spec::Custom{{{"grid", "f2"}, {"west", -180}}}; + // std::unique_ptr grid3(GridFactory::build(spec)); + // auto n3 = grid3->size(); - EXPECT_EQUAL(n3, n1); + // EXPECT_EQUAL(n3, n1); - spec.set("east", 0); - std::unique_ptr grid4(GridFactory::build(spec)); - auto n4 = grid4->size(); + // spec.set("east", 0); + // std::unique_ptr grid4(GridFactory::build(spec)); + // auto n4 = grid4->size(); - EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj + // EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj - spec.set("east", -1.); - std::unique_ptr grid5(GridFactory::build(spec)); - auto n5 = grid5->size(); + // spec.set("east", -1.); + // std::unique_ptr grid5(GridFactory::build(spec)); + // auto n5 = grid5->size(); - EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj + // EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj + } + + + SECTION("ReducedGaussian") { + spec::Custom spec({{"grid", "o2"}}); + std::unique_ptr grid1(GridFactory::build(spec)); + auto n1 = grid1->size(); + + EXPECT_EQUAL(n1, 88); + + spec.set("south", 0); + std::unique_ptr grid2(GridFactory::build(spec)); + auto n2 = grid2->size(); + + EXPECT_EQUAL(n2, n1 / 2); + + // spec = spec::Custom{{{"grid", "f2"}, {"west", -180}}}; + // std::unique_ptr grid3(GridFactory::build(spec)); + // auto n3 = grid3->size(); + + // EXPECT_EQUAL(n3, n1); + + // spec.set("east", 0); + // std::unique_ptr grid4(GridFactory::build(spec)); + // auto n4 = grid4->size(); + + // EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj + + // spec.set("east", -1.); + // std::unique_ptr grid5(GridFactory::build(spec)); + // auto n5 = grid5->size(); + + // EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj } diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 46622eb1e..b9a7d601b 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -41,7 +41,6 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) { CASE("range::RegularLongitude") { -#if 1 SECTION("degenerate") { EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 0.), eckit::AssertionFailed); EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 10.), eckit::AssertionFailed); @@ -105,33 +104,32 @@ CASE("range::RegularLongitude") { SECTION("range [0, 360], cropped") { auto range = range::RegularLongitude(36, 0., 360.); - const std::unique_ptr range1(range.crop(-180., 180.)); + // const std::unique_ptr range1(range.crop(-180., 180.)); - EXPECT(range1->size() == 36); - EXPECT(range1->a() == -180.); - EXPECT(range1->b() == 180.); + // std::cout << range1->values() << std::endl; + // EXPECT(range1->size() == 36); + // EXPECT(range1->a() == -180.); + // EXPECT(range1->b() == 180.); - const std::unique_ptr range2(range.crop(-180., 170.)); + // const std::unique_ptr range2(range.crop(-180., 170.)); - EXPECT(range2->size() == 36); - EXPECT(range2->b() == 180.); + // EXPECT(range2->size() == 36); + // EXPECT(range2->b() == 180.); - const std::unique_ptr range3(range.crop(-180., 160.)); + // const std::unique_ptr range3(range.crop(-180., 160.)); - EXPECT(range3->size() == 36 - 1); - EXPECT(range3->b() == 160.); + // EXPECT(range3->size() == 36 - 1); + // EXPECT(range3->b() == 160.); } -#endif -#if 1 SECTION("range [0, 180], cropped") { auto range = range::RegularLongitude(19, 0., 180.); - const std::unique_ptr range1(range.crop(1., 181.)); + const std::unique_ptr range1(range.crop(1., 179.)); - EXPECT(range1->size() == 19 - 1); + EXPECT(range1->size() == 19 - 2); EXPECT(range1->a() == 10.); - EXPECT(range1->b() == 180.); + EXPECT(range1->b() == 170.); const std::unique_ptr range2(range.crop(1., 170.)); @@ -139,18 +137,23 @@ CASE("range::RegularLongitude") { EXPECT(range2->a() == 10.); EXPECT(range2->b() == 170.); - const std::unique_ptr range3(range.crop(-180., 180.)); + // const std::unique_ptr range3(range.crop(-180., 180.)); - std::cout << range3->values() << std::endl; - // EXPECT(range3->size() == 36 - 1); - // EXPECT(range3->a() == 180.); - // EXPECT(range3->b() == 160.); + // std::cout << range3->values() << std::endl; + // EXPECT(range3->size() == 19); + // EXPECT(range3->a() == 0.); + // EXPECT(range3->b() == 180.); + + // const std::unique_ptr range4(range.crop(-190., 170.)); + + // std::cout << range4->values() << std::endl; + // EXPECT(range4->size() == 2); + // EXPECT(range4->a() == -190.); + // EXPECT(range4->b() == -180.); } -#endif } -#if 1 CASE("range::Gaussian") { std::vector ref{59.44440828916676, 19.87571914744090, -19.87571914744090, -59.44440828916676}; @@ -192,7 +195,6 @@ CASE("range::Gaussian") { EXPECT_APPROX(cropped->values()[1], ref[1], EPS); } } -#endif } // namespace eckit::test From d8bb82e5c217d17dea7222557ca6faf7c778d56d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 14 Feb 2024 17:18:27 +0000 Subject: [PATCH 487/737] eckit::geo::Grid --- src/eckit/geo/Grid.cc | 4 ++ src/eckit/geo/grid/reduced/ReducedGaussian.cc | 21 +++++++-- src/eckit/geo/grid/reduced/ReducedGaussian.h | 3 +- src/eckit/geo/util/reduced_octahedral_pl.cc | 2 +- tests/geo/grid.cc | 44 ++++++++++--------- 5 files changed, 48 insertions(+), 26 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 70cbf84ee..e076809ce 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -150,6 +150,10 @@ Spec* GridFactory::generate_spec_(const Spec& spec) const { map->set("grid", "O" + std::to_string(N)); } + if (cfg->has("pl")) { + map->set("type", "reduced_gg"); + } + if (std::vector grid; cfg->get("grid", grid) && grid.size() == 2) { map->set("type", "regular_ll"); } diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 9350bb952..3a0d41e04 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -24,16 +24,31 @@ namespace eckit::geo::grid::reduced { +static size_t N(const pl_type& pl) { + ASSERT(!pl.empty() && pl.size() % 2 == 0); + return pl.size() / 2; +} + + ReducedGaussian::ReducedGaussian(const Spec& spec) : - ReducedGaussian(spec.get_unsigned("N"), spec.get_long_vector("pl"), area::BoundingBox(spec)) {} + ReducedGaussian(spec.get_long_vector("pl"), area::BoundingBox(spec)) {} -ReducedGaussian::ReducedGaussian(size_t N, const pl_type& pl, const area::BoundingBox& bbox) : - Reduced(bbox), pl_(pl), j_(0), Nj_(N * 2), y_(range::GaussianLatitude(N, false).crop(bbox.north, bbox.south)) { +ReducedGaussian::ReducedGaussian(const pl_type& pl, const area::BoundingBox& bbox) : + Reduced(bbox), + pl_(pl), + j_(0), + Nj_(N(pl) * 2), + y_(range::GaussianLatitude(N(pl), false).crop(bbox.north, bbox.south)) { + ASSERT(Nj_ == pl_.size()); ASSERT(y_); } +ReducedGaussian::ReducedGaussian(size_t N, const area::BoundingBox& bbox) : + ReducedGaussian(util::reduced_octahedral_pl(N), bbox) {} + + Grid::iterator ReducedGaussian::cbegin() const { return iterator{new geo::iterator::Reduced(*this, 0)}; } diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.h b/src/eckit/geo/grid/reduced/ReducedGaussian.h index 5ae7dbc37..1dea7b92f 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.h @@ -37,7 +37,8 @@ class ReducedGaussian : public Reduced { // -- Constructors explicit ReducedGaussian(const Spec&); - ReducedGaussian(size_t N, const pl_type& pl, const area::BoundingBox& = area::BoundingBox::make_global_prime()); + explicit ReducedGaussian(const pl_type& pl, const area::BoundingBox& = area::BoundingBox::make_global_prime()); + explicit ReducedGaussian(size_t N, const area::BoundingBox& = area::BoundingBox::make_global_prime()); // -- Destructor // None diff --git a/src/eckit/geo/util/reduced_octahedral_pl.cc b/src/eckit/geo/util/reduced_octahedral_pl.cc index fd3e91349..72b18fb1c 100644 --- a/src/eckit/geo/util/reduced_octahedral_pl.cc +++ b/src/eckit/geo/util/reduced_octahedral_pl.cc @@ -19,7 +19,7 @@ namespace eckit::geo::util { const pl_type& reduced_octahedral_pl(size_t N) { - ASSERT(N > 0); + ASSERT(0 < N && N % 2 == 0); static CacheT cache; if (cache.contains(N)) { diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index 9b506dffe..18b42921e 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -14,7 +14,9 @@ #include "eckit/geo/Cache.h" #include "eckit/geo/Grid.h" +#include "eckit/geo/grid/reduced/ReducedGaussian.h" #include "eckit/geo/spec/Custom.h" +#include "eckit/geo/util.h" #include "eckit/testing/Test.h" @@ -74,35 +76,35 @@ CASE("GridFactory::build") { SECTION("ReducedGaussian") { - spec::Custom spec({{"grid", "o2"}}); - std::unique_ptr grid1(GridFactory::build(spec)); - auto n1 = grid1->size(); + // different ways to instantiate the same grid (O2) + for (auto spec : {spec::Custom({{"grid", "o2"}}), + spec::Custom({{"N", 2}}), + spec::Custom({{"pl", pl_type{20, 24, 24, 20}}}), + }) { + std::unique_ptr grid1(GridFactory::build(spec)); + auto n1 = grid1->size(); - EXPECT_EQUAL(n1, 88); + EXPECT_EQUAL(n1, 88); - spec.set("south", 0); - std::unique_ptr grid2(GridFactory::build(spec)); - auto n2 = grid2->size(); + spec.set("south", 0); + std::unique_ptr grid2(GridFactory::build(spec)); + auto n2 = grid2->size(); - EXPECT_EQUAL(n2, n1 / 2); + EXPECT_EQUAL(n2, n1 / 2); + } - // spec = spec::Custom{{{"grid", "f2"}, {"west", -180}}}; - // std::unique_ptr grid3(GridFactory::build(spec)); - // auto n3 = grid3->size(); + { + std::unique_ptr grid1(new grid::reduced::ReducedGaussian(2)); + auto n1 = grid1->size(); - // EXPECT_EQUAL(n3, n1); + EXPECT_EQUAL(n1, 88); - // spec.set("east", 0); - // std::unique_ptr grid4(GridFactory::build(spec)); - // auto n4 = grid4->size(); - - // EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj + // std::unique_ptr grid2(grid1->crop(...)); + // auto n2 = grid2->size(); - // spec.set("east", -1.); - // std::unique_ptr grid5(GridFactory::build(spec)); - // auto n5 = grid5->size(); + // EXPECT_EQUAL(n2, n1 / 2); + } - // EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj } From 5c0e83907309415589aebf1e5d95ff739d7e9267 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 14 Feb 2024 17:31:46 +0000 Subject: [PATCH 488/737] eckit::geo::Grid --- src/eckit/geo/CMakeLists.txt | 4 + src/eckit/geo/Grid.cc | 5 + src/eckit/geo/Grid.h | 1 + src/eckit/geo/Range.cc | 145 +----------------- src/eckit/geo/Range.h | 76 --------- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 3 +- src/eckit/geo/grid/regular/RegularGaussian.cc | 3 +- src/eckit/geo/grid/regular/RegularLL.cc | 2 +- src/eckit/geo/range/GaussianLatitude.cc | 69 +++++++++ src/eckit/geo/range/GaussianLatitude.h | 50 ++++++ src/eckit/geo/range/RegularLongitude.cc | 119 ++++++++++++++ src/eckit/geo/range/RegularLongitude.h | 62 ++++++++ tests/geo/grid.cc | 10 +- tests/geo/range.cc | 3 +- 14 files changed, 323 insertions(+), 229 deletions(-) create mode 100644 src/eckit/geo/range/GaussianLatitude.cc create mode 100644 src/eckit/geo/range/GaussianLatitude.h create mode 100644 src/eckit/geo/range/RegularLongitude.cc create mode 100644 src/eckit/geo/range/RegularLongitude.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 9e2de2f89..b5125a719 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -104,6 +104,10 @@ list(APPEND eckit_geo_srcs projection/Rotation.h projection/XYToLonLat.cc projection/XYToLonLat.h + range/GaussianLatitude.cc + range/GaussianLatitude.h + range/RegularLongitude.cc + range/RegularLongitude.h spec/Custom.cc spec/Custom.h spec/Generator.h diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index e076809ce..91836c6a3 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -91,6 +91,11 @@ std::pair, std::vector> Grid::to_latlon() const { } +std::string Grid::spec() const { + throw NotImplemented("Grid::spec"); +} + + Ordering Grid::order() const { throw NotImplemented("Grid::order"); } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 8b0cf5415..206d9c6ed 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -121,6 +121,7 @@ class Grid { virtual std::vector to_points() const; virtual std::pair, std::vector> to_latlon() const; + virtual std::string spec() const; virtual Ordering order() const; virtual Renumber reorder(Ordering) const; virtual Grid* grid_reorder(Ordering) const; diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 12787937c..8f9108a34 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -39,150 +39,7 @@ void Range::resize(size_t n) { } -namespace range { - - -namespace { - - -util::recursive_mutex MUTEX; - -constexpr auto DB = 1e-12; - - -Fraction regular_adjust(const Fraction& target, const Fraction& inc, bool up) { - ASSERT(inc > 0); - - auto r = target / inc; - auto n = r.integralPart() + ((r.integer() || (r > 0) != up) ? 0 : up ? 1 : -1); - - return n * inc; -}; - - -} // namespace - - -GaussianLatitude::GaussianLatitude(size_t N, bool increasing, double eps) : - Range(2 * N, increasing ? -90. : 90., increasing ? 90. : -90., eps), N_(N) {} - - -Range* GaussianLatitude::flip() const { - std::vector flipped(size()); - const auto& v = values(); - std::reverse_copy(v.begin(), v.end(), flipped.begin()); - - return new GaussianLatitude(N_, std::move(flipped), eps()); -} - - -Range* GaussianLatitude::crop(double crop_a, double crop_b) const { - ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || - (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); - - auto v = values(); - - if ((a() < b()) && (a() < crop_a || crop_b < b())) { - auto [from, to] = util::monotonic_crop(v, crop_a, crop_b, eps()); - v.erase(v.begin() + to, v.end()); - v.erase(v.begin(), v.begin() + from); - } - else if ((b() < a()) && (b() < crop_b || crop_a < a())) { - auto [from, to] = util::monotonic_crop(v, crop_b, crop_a, eps()); - v.erase(v.begin() + to, v.end()); - v.erase(v.begin(), v.begin() + from); - } - - return new GaussianLatitude(N_, std::move(v), eps()); -} - - -const std::vector& GaussianLatitude::values() const { - util::lock_guard lock(MUTEX); - return values_.empty() ? util::gaussian_latitudes(N_, a() < b()) : values_; -} - - -RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) : - Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps) { - if (types::is_approximately_equal(a(), b(), eps())) { - resize(1); - periodic_ = NonPeriodic; - values_ = {a()}; - } - else if (a() < b()) { - auto new_b = PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB; - periodic_ = types::is_approximately_lesser_or_equal(360., (new_b - a()) * (1. + 1. / static_cast(n))) - ? PeriodicNoEndPoint - : NonPeriodic; - b(periodic() ? a() + 360. : new_b); - } - else { - auto new_b = PointLonLat::normalise_angle_to_maximum(b() + DB, a()) - DB; - periodic_ = types::is_approximately_lesser_or_equal(360., (a() - new_b) * (1. + 1. / static_cast(n))) - ? PeriodicNoEndPoint - : NonPeriodic; - b(periodic() ? a() - 360. : new_b); - } -} - - -Range* RegularLongitude::flip() const { - auto flipped = periodic_ == PeriodicNoEndPoint ? PeriodicNoStartPoint - : periodic_ == PeriodicNoStartPoint ? PeriodicNoEndPoint - : NonPeriodic; - return new RegularLongitude(size(), b(), a(), flipped, eps()); -} - - -Fraction RegularLongitude::increment() const { - return Fraction((b() - a()) / static_cast(periodic() ? size() : (size() - 1))); -} - - -Range* RegularLongitude::crop(double crop_a, double crop_b) const { - ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || - (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); - - if (types::is_approximately_equal(crop_a, crop_b, eps())) { - NOTIMP; // FIXME - } - else if (a() < b()) { - ASSERT(a() <= crop_a && crop_b <= b()); // FIXME do better - - auto inc(increment()); - auto d = (a() / inc).decimalPart() * inc; - auto _a = regular_adjust(crop_a - d, inc, true) + d; - auto _b = regular_adjust(crop_b - d, inc, false) + d; - - auto nf = (_b - _a) / inc; - ASSERT(nf.integer()); - - auto n = static_cast(nf.integralPart() + (nf * inc >= 360 ? 0 : 1)); - ASSERT(0 < n && n <= size()); - - return new RegularLongitude(n, _a, _b); - } - else { - NOTIMP; // FIXME - } - NOTIMP; -} - - -const std::vector& RegularLongitude::values() const { - util::lock_guard lock(MUTEX); - - if (values_.empty()) { - const_cast&>(values_) = util::linspace(a(), b(), size(), !periodic()); - ASSERT(!values_.empty()); - } - - return values_; -} - - -} // namespace range +namespace range {} // namespace range } // namespace eckit::geo diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 3ca44032f..af424caed 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -69,80 +69,4 @@ class Range { }; -namespace range { - - -class GaussianLatitude final : public Range { -public: - // -- Constructors - - explicit GaussianLatitude(size_t N, bool increasing, double eps = 0.); - - // -- Methods - - size_t N() const { return N_; } - - // -- Overridden methods - - Range* flip() const override; - Range* crop(double crop_a, double crop_b) const override; - const std::vector& values() const override; - -private: - // -- Constructors - - GaussianLatitude(size_t N, std::vector&& values, double _eps) : - Range(values.size(), values.front(), values.back(), _eps), N_(N), values_(values) {} - - // -- Members - - const size_t N_; - std::vector values_; -}; - - -class RegularLongitude final : public Range { -public: - // -- Constructors - - RegularLongitude(size_t n, double a, double b, double eps = 0.); - - // -- Methods - bool periodic() const { return periodic_ != NonPeriodic; } - - // -- Overridden methods - - Range* flip() const override; - Range* crop(double crop_a, double crop_b) const override; - const std::vector& values() const override; - -private: - // -- Types - - enum Periodic - { - NonPeriodic = 0, - PeriodicNoEndPoint, - PeriodicNoStartPoint - }; - - // -- Constructors - - RegularLongitude(size_t n, double a, double b, Periodic periodic, double eps) : - Range(n, a, b, eps), periodic_(periodic) {} - - // -- Members - - Periodic periodic_; - std::vector values_; - - // -- Methods - - Fraction increment() const; -}; - - -} // namespace range - - } // namespace eckit::geo diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 3a0d41e04..879f44717 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -15,8 +15,9 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Range.h" #include "eckit/geo/iterator/Reduced.h" +#include "eckit/geo/range/GaussianLatitude.h" +#include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" #include "eckit/utils/Translator.h" diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index 2a3c143b9..beadb0203 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -12,8 +12,9 @@ #include "eckit/geo/grid/regular/RegularGaussian.h" -#include "eckit/geo/Range.h" #include "eckit/geo/iterator/Regular.h" +#include "eckit/geo/range/GaussianLatitude.h" +#include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" #include "eckit/utils/Translator.h" diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index d2c7aa579..f7b1fbce4 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -14,8 +14,8 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Increments.h" -#include "eckit/geo/Range.h" #include "eckit/geo/iterator/Regular.h" +#include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util/regex.h" #include "eckit/types/Fraction.h" diff --git a/src/eckit/geo/range/GaussianLatitude.cc b/src/eckit/geo/range/GaussianLatitude.cc new file mode 100644 index 000000000..7404b05f1 --- /dev/null +++ b/src/eckit/geo/range/GaussianLatitude.cc @@ -0,0 +1,69 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/range/GaussianLatitude.h" + +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/util.h" +#include "eckit/geo/util/mutex.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::range { + + +static util::recursive_mutex MUTEX; + + +GaussianLatitude::GaussianLatitude(size_t N, bool increasing, double eps) : + Range(2 * N, increasing ? -90. : 90., increasing ? 90. : -90., eps), N_(N) {} + + +Range* GaussianLatitude::flip() const { + std::vector flipped(size()); + const auto& v = values(); + std::reverse_copy(v.begin(), v.end(), flipped.begin()); + + return new GaussianLatitude(N_, std::move(flipped), eps()); +} + + +Range* GaussianLatitude::crop(double crop_a, double crop_b) const { + ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || + (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); + + auto v = values(); + + if ((a() < b()) && (a() < crop_a || crop_b < b())) { + auto [from, to] = util::monotonic_crop(v, crop_a, crop_b, eps()); + v.erase(v.begin() + to, v.end()); + v.erase(v.begin(), v.begin() + from); + } + else if ((b() < a()) && (b() < crop_b || crop_a < a())) { + auto [from, to] = util::monotonic_crop(v, crop_b, crop_a, eps()); + v.erase(v.begin() + to, v.end()); + v.erase(v.begin(), v.begin() + from); + } + + return new GaussianLatitude(N_, std::move(v), eps()); +} + + +const std::vector& GaussianLatitude::values() const { + util::lock_guard lock(MUTEX); + return values_.empty() ? util::gaussian_latitudes(N_, a() < b()) : values_; +} + + +} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/GaussianLatitude.h b/src/eckit/geo/range/GaussianLatitude.h new file mode 100644 index 000000000..d2178105f --- /dev/null +++ b/src/eckit/geo/range/GaussianLatitude.h @@ -0,0 +1,50 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Range.h" + + +namespace eckit::geo::range { + + +class GaussianLatitude final : public Range { +public: + // -- Constructors + + explicit GaussianLatitude(size_t N, bool increasing, double eps = 0.); + + // -- Methods + + size_t N() const { return N_; } + + // -- Overridden methods + + Range* flip() const override; + Range* crop(double crop_a, double crop_b) const override; + const std::vector& values() const override; + +private: + // -- Constructors + + GaussianLatitude(size_t N, std::vector&& values, double _eps) : + Range(values.size(), values.front(), values.back(), _eps), N_(N), values_(values) {} + + // -- Members + + const size_t N_; + std::vector values_; +}; + + +} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/RegularLongitude.cc b/src/eckit/geo/range/RegularLongitude.cc new file mode 100644 index 000000000..6fa85709c --- /dev/null +++ b/src/eckit/geo/range/RegularLongitude.cc @@ -0,0 +1,119 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/range/RegularLongitude.h" + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/PointLonLat.h" +#include "eckit/geo/util.h" +#include "eckit/geo/util/mutex.h" +#include "eckit/types/FloatCompare.h" +#include "eckit/types/Fraction.h" + + +namespace eckit::geo::range { + + +static util::recursive_mutex MUTEX; +static constexpr auto DB = 1e-12; + + +static Fraction regular_adjust(const Fraction& target, const Fraction& inc, bool up) { + ASSERT(inc > 0); + + auto r = target / inc; + auto n = r.integralPart() + ((r.integer() || (r > 0) != up) ? 0 : up ? 1 : -1); + + return n * inc; +}; + + +RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) : + Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps) { + if (types::is_approximately_equal(a(), b(), eps())) { + resize(1); + periodic_ = NonPeriodic; + values_ = {a()}; + } + else if (a() < b()) { + auto new_b = PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB; + periodic_ = types::is_approximately_lesser_or_equal(360., (new_b - a()) * (1. + 1. / static_cast(n))) + ? PeriodicNoEndPoint + : NonPeriodic; + b(periodic() ? a() + 360. : new_b); + } + else { + auto new_b = PointLonLat::normalise_angle_to_maximum(b() + DB, a()) - DB; + periodic_ = types::is_approximately_lesser_or_equal(360., (a() - new_b) * (1. + 1. / static_cast(n))) + ? PeriodicNoEndPoint + : NonPeriodic; + b(periodic() ? a() - 360. : new_b); + } +} + + +Range* RegularLongitude::flip() const { + auto flipped = periodic_ == PeriodicNoEndPoint ? PeriodicNoStartPoint + : periodic_ == PeriodicNoStartPoint ? PeriodicNoEndPoint + : NonPeriodic; + return new RegularLongitude(size(), b(), a(), flipped, eps()); +} + + +Fraction RegularLongitude::increment() const { + return Fraction((b() - a()) / static_cast(periodic() ? size() : (size() - 1))); +} + + +Range* RegularLongitude::crop(double crop_a, double crop_b) const { + ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || + (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); + + if (types::is_approximately_equal(crop_a, crop_b, eps())) { + NOTIMP; // FIXME + } + else if (a() < b()) { + ASSERT(a() <= crop_a && crop_b <= b()); // FIXME do better + + auto inc(increment()); + auto d = (a() / inc).decimalPart() * inc; + auto _a = regular_adjust(crop_a - d, inc, true) + d; + auto _b = regular_adjust(crop_b - d, inc, false) + d; + + auto nf = (_b - _a) / inc; + ASSERT(nf.integer()); + + auto n = static_cast(nf.integralPart() + (nf * inc >= 360 ? 0 : 1)); + ASSERT(0 < n && n <= size()); + + return new RegularLongitude(n, _a, _b); + } + else { + NOTIMP; // FIXME + } + NOTIMP; +} + + +const std::vector& RegularLongitude::values() const { + util::lock_guard lock(MUTEX); + + if (values_.empty()) { + const_cast&>(values_) = util::linspace(a(), b(), size(), !periodic()); + ASSERT(!values_.empty()); + } + + return values_; +} + + +} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/RegularLongitude.h b/src/eckit/geo/range/RegularLongitude.h new file mode 100644 index 000000000..4b3c3e987 --- /dev/null +++ b/src/eckit/geo/range/RegularLongitude.h @@ -0,0 +1,62 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Range.h" + + +namespace eckit::geo::range { + + +class RegularLongitude final : public Range { +public: + // -- Constructors + + RegularLongitude(size_t n, double a, double b, double eps = 0.); + + // -- Methods + bool periodic() const { return periodic_ != NonPeriodic; } + + // -- Overridden methods + + Range* flip() const override; + Range* crop(double crop_a, double crop_b) const override; + const std::vector& values() const override; + +private: + // -- Types + + enum Periodic + { + NonPeriodic = 0, + PeriodicNoEndPoint, + PeriodicNoStartPoint + }; + + // -- Constructors + + RegularLongitude(size_t n, double a, double b, Periodic periodic, double eps) : + Range(n, a, b, eps), periodic_(periodic) {} + + // -- Members + + Periodic periodic_; + std::vector values_; + + // -- Methods + + Fraction increment() const; +}; + + +} // namespace eckit::geo::range diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index 18b42921e..5803a6d38 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -77,10 +77,11 @@ CASE("GridFactory::build") { SECTION("ReducedGaussian") { // different ways to instantiate the same grid (O2) - for (auto spec : {spec::Custom({{"grid", "o2"}}), - spec::Custom({{"N", 2}}), - spec::Custom({{"pl", pl_type{20, 24, 24, 20}}}), - }) { + for (auto spec : { + spec::Custom({{"grid", "o2"}}), + spec::Custom({{"N", 2}}), + spec::Custom({{"pl", pl_type{20, 24, 24, 20}}}), + }) { std::unique_ptr grid1(GridFactory::build(spec)); auto n1 = grid1->size(); @@ -104,7 +105,6 @@ CASE("GridFactory::build") { // EXPECT_EQUAL(n2, n1 / 2); } - } diff --git a/tests/geo/range.cc b/tests/geo/range.cc index b9a7d601b..47036fba7 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -13,7 +13,8 @@ #include #include -#include "eckit/geo/Range.h" +#include "eckit/geo/range/GaussianLatitude.h" +#include "eckit/geo/range/RegularLongitude.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" From fd399b0befb183224670c087c8ef481d879a034f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 15 Feb 2024 04:01:20 +0000 Subject: [PATCH 489/737] eckit::geo::Grid --- src/eckit/geo/CMakeLists.txt | 6 ++ src/eckit/geo/Range.cc | 4 + src/eckit/geo/Range.h | 2 + src/eckit/geo/grid/reduced/ReducedGaussian.h | 2 +- src/eckit/geo/range/Regular.cc | 58 ++++++++++ src/eckit/geo/range/Regular.h | 53 +++++++++ src/eckit/geo/range/RegularCartesian.cc | 74 +++++++++++++ src/eckit/geo/range/RegularCartesian.h | 35 ++++++ src/eckit/geo/range/RegularLatitude.cc | 64 +++++++++++ src/eckit/geo/range/RegularLatitude.h | 34 ++++++ src/eckit/geo/range/RegularLongitude.cc | 79 +++++--------- src/eckit/geo/range/RegularLongitude.h | 34 ++---- tests/geo/range.cc | 3 +- tests/geo/util.cc | 108 +++++++++++++++---- 14 files changed, 454 insertions(+), 102 deletions(-) create mode 100644 src/eckit/geo/range/Regular.cc create mode 100644 src/eckit/geo/range/Regular.h create mode 100644 src/eckit/geo/range/RegularCartesian.cc create mode 100644 src/eckit/geo/range/RegularCartesian.h create mode 100644 src/eckit/geo/range/RegularLatitude.cc create mode 100644 src/eckit/geo/range/RegularLatitude.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index b5125a719..c294d7bfe 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -106,6 +106,12 @@ list(APPEND eckit_geo_srcs projection/XYToLonLat.h range/GaussianLatitude.cc range/GaussianLatitude.h + range/Regular.cc + range/Regular.h + range/RegularCartesian.cc + range/RegularCartesian.h + range/RegularLatitude.cc + range/RegularLatitude.h range/RegularLongitude.cc range/RegularLongitude.h spec/Custom.cc diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 8f9108a34..ba71575b8 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -30,6 +30,10 @@ Range::Range(size_t n, double _a, double _b, double _eps) : n_(n), a_(_a), b_(_b), eps_(_eps) { ASSERT(n > 0); ASSERT(eps_ >= 0); + if (types::is_approximately_equal(_a, _b)) { + n_ = 1; + b(_a); + } } diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index af424caed..08b8e5120 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -55,6 +55,8 @@ class Range { explicit Range(size_t n, double a, double b, double eps = 0.); + // --Methods + void resize(size_t n); void a(double value) { a_ = value; } void b(double value) { b_ = value; } diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.h b/src/eckit/geo/grid/reduced/ReducedGaussian.h index 1dea7b92f..60305a05d 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.h @@ -37,7 +37,7 @@ class ReducedGaussian : public Reduced { // -- Constructors explicit ReducedGaussian(const Spec&); - explicit ReducedGaussian(const pl_type& pl, const area::BoundingBox& = area::BoundingBox::make_global_prime()); + explicit ReducedGaussian(const pl_type&, const area::BoundingBox& = area::BoundingBox::make_global_prime()); explicit ReducedGaussian(size_t N, const area::BoundingBox& = area::BoundingBox::make_global_prime()); // -- Destructor diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc new file mode 100644 index 000000000..f92ed8bc7 --- /dev/null +++ b/src/eckit/geo/range/Regular.cc @@ -0,0 +1,58 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/range/Regular.h" + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/util.h" +#include "eckit/geo/util/mutex.h" +#include "eckit/types/Fraction.h" + + +namespace eckit::geo::range { + + +static util::recursive_mutex MUTEX; + + +Fraction Regular::increment() const { + ASSERT(1 < size()); + return Fraction((b() - a()) / static_cast(periodic() ? size() : (size() - 1))); +} + +const std::vector& Regular::values() const { + util::lock_guard lock(MUTEX); + + if (values_.empty()) { + const_cast&>(values_) = util::linspace(a(), b(), size(), !periodic_); + ASSERT(!values_.empty()); + } + + return values_; +} + + +Regular::Regular(size_t n, double a, double b, std::vector&& values, bool periodic, double eps) : + Range(n, a, b, eps), values_(values), periodic_(periodic) {} + + +Fraction Regular::adjust(const Fraction& target, const Fraction& inc, bool up) { + ASSERT(inc > 0); + + auto r = target / inc; + auto n = r.integralPart() + ((r.integer() || (r > 0) != up) ? 0 : up ? 1 : -1); + + return n * inc; +} + + +} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h new file mode 100644 index 000000000..4e74ed8ec --- /dev/null +++ b/src/eckit/geo/range/Regular.h @@ -0,0 +1,53 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Range.h" + + +namespace eckit::geo::range { + + +class Regular : public Range { +public: + // -- Methods + + Fraction increment() const; + bool periodic() const { return periodic_; } + + // -- Overridden methods + + const std::vector& values() const override; + +protected: + // -- Constructors + + Regular(size_t n, double a, double b, double eps) : + Range(n, a, b, eps), periodic_(false) {} + + Regular(size_t n, double a, double b, std::vector&&, bool periodic, double eps); + + // -- Methods + + static Fraction adjust(const Fraction& target, const Fraction& inc, bool up); + void periodic(bool p) { periodic_ = p; } + +private: + // -- Members + + std::vector values_; + bool periodic_; +}; + + +} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/RegularCartesian.cc b/src/eckit/geo/range/RegularCartesian.cc new file mode 100644 index 000000000..64cfd9af6 --- /dev/null +++ b/src/eckit/geo/range/RegularCartesian.cc @@ -0,0 +1,74 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/range/RegularCartesian.h" + +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/types/FloatCompare.h" +#include "eckit/types/Fraction.h" + + +namespace eckit::geo::range { + + +static constexpr auto DB = 1e-12; + + +static Fraction regular_adjust(const Fraction& target, const Fraction& inc, bool up) { + ASSERT(inc > 0); + + auto r = target / inc; + auto n = r.integralPart() + ((r.integer() || (r > 0) != up) ? 0 : up ? 1 : -1); + + return n * inc; +}; + + +Range* RegularCartesian::crop(double crop_a, double crop_b) const { + ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || + (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); + + if (types::is_approximately_equal(crop_a, crop_b, eps())) { + NOTIMP; // FIXME + } + else if (a() < b()) { + ASSERT(a() <= crop_a && crop_b <= b()); // FIXME do better + + auto inc(increment()); + auto d = (a() / inc).decimalPart() * inc; + auto _a = regular_adjust(crop_a - d, inc, true) + d; + auto _b = regular_adjust(crop_b - d, inc, false) + d; + + auto nf = (_b - _a) / inc; + ASSERT(nf.integer()); + + auto n = static_cast(nf.integralPart() + 1); + ASSERT(0 < n && n <= size()); + + return new RegularCartesian(n, _a, _b, eps()); + } + else { + NOTIMP; // FIXME + } + + NOTIMP; +} + + +Range* RegularCartesian::flip() const { + return new RegularCartesian(size(), b(), a(), eps()); +} + + +} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/RegularCartesian.h b/src/eckit/geo/range/RegularCartesian.h new file mode 100644 index 000000000..72b768275 --- /dev/null +++ b/src/eckit/geo/range/RegularCartesian.h @@ -0,0 +1,35 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/range/Regular.h" + + +namespace eckit::geo::range { + + +class RegularCartesian final : public Regular { +public: + // -- Constructors + + RegularCartesian(size_t n, double a, double b, double eps = 0.) : + Regular(n, a, b, eps) {} + + // -- Overridden methods + + Range* crop(double crop_a, double crop_b) const override; + Range* flip() const override; +}; + + +} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/RegularLatitude.cc b/src/eckit/geo/range/RegularLatitude.cc new file mode 100644 index 000000000..e68a0b839 --- /dev/null +++ b/src/eckit/geo/range/RegularLatitude.cc @@ -0,0 +1,64 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/range/RegularLatitude.h" + +#include "eckit/exception/Exceptions.h" +#include "eckit/types/FloatCompare.h" +#include "eckit/types/Fraction.h" + + +namespace eckit::geo::range { + + +static constexpr auto DB = 1e-12; + + +RegularLatitude::RegularLatitude(size_t n, double _a, double _b, double _eps) : + Regular(n, _a, _b, _eps) { + ASSERT(-90 <= a() && a() <= 90); + ASSERT(-90 <= b() && b() <= 90); +} + + +Range* RegularLatitude::crop(double crop_a, double crop_b) const { + ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || + (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); + + if (types::is_approximately_equal(crop_a, crop_b, eps())) { + NOTIMP; // FIXME + } + else if (a() < b()) { + ASSERT(a() <= crop_a && crop_b <= b()); // FIXME do better + + auto inc(increment()); + auto d = (a() / inc).decimalPart() * inc; + auto _a = adjust(crop_a - d, inc, true) + d; + auto _b = adjust(crop_b - d, inc, false) + d; + + auto nf = (_b - _a) / inc; + ASSERT(nf.integer()); + + auto n = static_cast(nf.integralPart() + 1); + ASSERT(0 < n && n <= size()); + + return new RegularLatitude(n, _a, _b, eps()); + } + else { + NOTIMP; // FIXME + } + + NOTIMP; +} + + +} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/RegularLatitude.h b/src/eckit/geo/range/RegularLatitude.h new file mode 100644 index 000000000..d5b3365b4 --- /dev/null +++ b/src/eckit/geo/range/RegularLatitude.h @@ -0,0 +1,34 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/range/Regular.h" + + +namespace eckit::geo::range { + + +class RegularLatitude final : public Regular { +public: + // -- Constructors + + RegularLatitude(size_t n, double a, double b, double eps = 0.); + + // -- Overridden methods + + Range* crop(double crop_a, double crop_b) const override; + Range* flip() const override { return new RegularLatitude(size(), b(), a(), eps()); } +}; + + +} // namespace eckit::geo::range diff --git a/src/eckit/geo/range/RegularLongitude.cc b/src/eckit/geo/range/RegularLongitude.cc index 6fa85709c..441c7747c 100644 --- a/src/eckit/geo/range/RegularLongitude.cc +++ b/src/eckit/geo/range/RegularLongitude.cc @@ -12,10 +12,10 @@ #include "eckit/geo/range/RegularLongitude.h" +#include + #include "eckit/exception/Exceptions.h" #include "eckit/geo/PointLonLat.h" -#include "eckit/geo/util.h" -#include "eckit/geo/util/mutex.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" @@ -23,57 +23,34 @@ namespace eckit::geo::range { -static util::recursive_mutex MUTEX; static constexpr auto DB = 1e-12; -static Fraction regular_adjust(const Fraction& target, const Fraction& inc, bool up) { - ASSERT(inc > 0); - - auto r = target / inc; - auto n = r.integralPart() + ((r.integer() || (r > 0) != up) ? 0 : up ? 1 : -1); - - return n * inc; -}; - - RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) : - Range(n, _a, types::is_approximately_equal(_a, _b, _eps) ? _a : _b, _eps) { - if (types::is_approximately_equal(a(), b(), eps())) { - resize(1); - periodic_ = NonPeriodic; - values_ = {a()}; - } - else if (a() < b()) { + Regular(n, _a, _b, _eps) { + if (a() < b()) { auto new_b = PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB; - periodic_ = types::is_approximately_lesser_or_equal(360., (new_b - a()) * (1. + 1. / static_cast(n))) - ? PeriodicNoEndPoint - : NonPeriodic; - b(periodic() ? a() + 360. : new_b); + if (types::is_approximately_lesser_or_equal(360., (new_b - a()) * (1. + 1. / static_cast(n)))) { + periodic(true); + b(a() + 360.); + } + else { + b(new_b); + } } else { auto new_b = PointLonLat::normalise_angle_to_maximum(b() + DB, a()) - DB; - periodic_ = types::is_approximately_lesser_or_equal(360., (a() - new_b) * (1. + 1. / static_cast(n))) - ? PeriodicNoEndPoint - : NonPeriodic; - b(periodic() ? a() - 360. : new_b); + if (types::is_approximately_lesser_or_equal(360., (a() - new_b) * (1. + 1. / static_cast(n)))) { + periodic(true); + b(a() - 360.); + } + else { + b(new_b); + } } } -Range* RegularLongitude::flip() const { - auto flipped = periodic_ == PeriodicNoEndPoint ? PeriodicNoStartPoint - : periodic_ == PeriodicNoStartPoint ? PeriodicNoEndPoint - : NonPeriodic; - return new RegularLongitude(size(), b(), a(), flipped, eps()); -} - - -Fraction RegularLongitude::increment() const { - return Fraction((b() - a()) / static_cast(periodic() ? size() : (size() - 1))); -} - - Range* RegularLongitude::crop(double crop_a, double crop_b) const { ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); @@ -86,8 +63,8 @@ Range* RegularLongitude::crop(double crop_a, double crop_b) const { auto inc(increment()); auto d = (a() / inc).decimalPart() * inc; - auto _a = regular_adjust(crop_a - d, inc, true) + d; - auto _b = regular_adjust(crop_b - d, inc, false) + d; + auto _a = adjust(crop_a - d, inc, true) + d; + auto _b = adjust(crop_b - d, inc, false) + d; auto nf = (_b - _a) / inc; ASSERT(nf.integer()); @@ -95,24 +72,22 @@ Range* RegularLongitude::crop(double crop_a, double crop_b) const { auto n = static_cast(nf.integralPart() + (nf * inc >= 360 ? 0 : 1)); ASSERT(0 < n && n <= size()); - return new RegularLongitude(n, _a, _b); + return new RegularLongitude(n, _a, _b, eps()); } else { NOTIMP; // FIXME } + NOTIMP; } -const std::vector& RegularLongitude::values() const { - util::lock_guard lock(MUTEX); - - if (values_.empty()) { - const_cast&>(values_) = util::linspace(a(), b(), size(), !periodic()); - ASSERT(!values_.empty()); - } +Range* RegularLongitude::flip() const { + std::vector flipped(size()); + const auto& v = values(); + std::reverse_copy(v.begin(), v.end(), flipped.begin()); - return values_; + return new RegularLongitude(size(), b(), a(), eps()); } diff --git a/src/eckit/geo/range/RegularLongitude.h b/src/eckit/geo/range/RegularLongitude.h index 4b3c3e987..33840e40e 100644 --- a/src/eckit/geo/range/RegularLongitude.h +++ b/src/eckit/geo/range/RegularLongitude.h @@ -12,50 +12,30 @@ #pragma once -#include "eckit/geo/Range.h" +#include + +#include "eckit/geo/range/Regular.h" namespace eckit::geo::range { -class RegularLongitude final : public Range { +class RegularLongitude final : public Regular { public: // -- Constructors RegularLongitude(size_t n, double a, double b, double eps = 0.); - // -- Methods - bool periodic() const { return periodic_ != NonPeriodic; } - // -- Overridden methods - Range* flip() const override; Range* crop(double crop_a, double crop_b) const override; - const std::vector& values() const override; + Range* flip() const override; private: - // -- Types - - enum Periodic - { - NonPeriodic = 0, - PeriodicNoEndPoint, - PeriodicNoStartPoint - }; - // -- Constructors - RegularLongitude(size_t n, double a, double b, Periodic periodic, double eps) : - Range(n, a, b, eps), periodic_(periodic) {} - - // -- Members - - Periodic periodic_; - std::vector values_; - - // -- Methods - - Fraction increment() const; + RegularLongitude(size_t n, double a, double b, std::vector&& values, bool periodic, double eps) : + Regular(n, a, b, std::move(values), periodic, eps) {} }; diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 47036fba7..3cf431a28 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -42,6 +42,7 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) { CASE("range::RegularLongitude") { +#if 0 SECTION("degenerate") { EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 0.), eckit::AssertionFailed); EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 10.), eckit::AssertionFailed); @@ -71,7 +72,7 @@ CASE("range::RegularLongitude") { EXPECT_APPROX(values[1], 0., EPS); EXPECT_APPROX(values[2], 90., EPS); } - +#endif SECTION("range [-180, 180]") { const range::RegularLongitude range1(4, -180., 180.); diff --git a/tests/geo/util.cc b/tests/geo/util.cc index 8b739447a..3adeb9d6c 100644 --- a/tests/geo/util.cc +++ b/tests/geo/util.cc @@ -10,11 +10,22 @@ */ +#include #include +#include #include #include "eckit/geo/util.h" #include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" + + +template +bool is_approximately_equal_vector(const std::vector& a, const std::vector& b, double eps = 0.) { + return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin(), [=](const T& a, const T& b) { + return ::eckit::types::is_approximately_equal(a, b, eps); + }); +} template @@ -34,30 +45,85 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) { namespace eckit::test { +constexpr double EPS = 1e-9; + using namespace geo; -CASE("") { -#if 0 - std::cout << util::linspace(1, 2, 2, true) << std::endl; - std::cout << util::arange(1, 2, 0.5) << std::endl; - std::cout << util::gaussian_latitudes(64, false) << std::endl; - std::cout << util::normalise_longitude_to_maximum(0., 360.) << std::endl; - std::cout << util::normalise_longitude_to_minimum(0., -360.) << std::endl; -#elif 1 - std::cout << util::reduced_classical_pl(16) << std::endl; - std::cout << util::reduced_classical_pl(16) << std::endl; - std::cout << util::reduced_octahedral_pl(16) << std::endl; - std::cout << util::reduced_octahedral_pl(16) << std::endl; -#elif 0 - std::vector values1{1., 2., 3., 4., 5., 6.}; - std::vector values2{6., 5., 4., 3., 2., 1.}; - - std::cout << util::monotonic_crop({1.}, 1., 1., 0.) << std::endl; - std::cout << util::monotonic_crop({1., 1., 1.}, 1., 2., 0.) << std::endl; - std::cout << util::monotonic_crop(values1, 2., 3., 0.) << std::endl; - std::cout << util::monotonic_crop(values2, 2., 3., 0.) << std::endl; -#endif +CASE("eckit::geo::util::linspace") { + EXPECT(is_approximately_equal_vector(util::linspace(1, 2, 1, false), std::vector{1.}, EPS)); + EXPECT(is_approximately_equal_vector(util::linspace(1, 1, 2, true), std::vector{1., 1.}, EPS)); + EXPECT(is_approximately_equal_vector(util::linspace(1, 2, 2, true), std::vector{1., 2.}, EPS)); +} + + +CASE("eckit::geo::util::arange") { + EXPECT(is_approximately_equal_vector(util::arange(1, 2, 0.5), std::vector{1, 1.5, 2}, EPS)); +} + + +CASE("eckit::geo::util::gaussian_latitudes") { + std::vector lats_decreasing{ + 88.9277, 87.5387, 86.1415, 84.7424, 83.3426, 81.9425, 80.5421, 79.1417, 77.7412, 76.3406, 74.94, + 73.5394, 72.1387, 70.7381, 69.3374, 67.9367, 66.536, 65.1353, 63.7345, 62.3338, 60.9331, 59.5323, + 58.1316, 56.7309, 55.3301, 53.9294, 52.5286, 51.1279, 49.7271, 48.3264, 46.9256, 45.5249, 44.1241, + 42.7233, 41.3226, 39.9218, 38.5211, 37.1203, 35.7195, 34.3188, 32.918, 31.5172, 30.1165, 28.7157, + 27.315, 25.9142, 24.5134, 23.1127, 21.7119, 20.3111, 18.9104, 17.5096, 16.1088, 14.7081, 13.3073, + 11.9065, 10.5058, 9.10499, 7.70422, 6.30345, 4.90269, 3.50192, 2.10115, 0.700384, -0.700384, -2.10115, + -3.50192, -4.90269, -6.30345, -7.70422, -9.10499, -10.5058, -11.9065, -13.3073, -14.7081, -16.1088, -17.5096, + -18.9104, -20.3111, -21.7119, -23.1127, -24.5134, -25.9142, -27.315, -28.7157, -30.1165, -31.5172, -32.918, + -34.3188, -35.7195, -37.1203, -38.5211, -39.9218, -41.3226, -42.7233, -44.1241, -45.5249, -46.9256, -48.3264, + -49.7271, -51.1279, -52.5286, -53.9294, -55.3301, -56.7309, -58.1316, -59.5323, -60.9331, -62.3338, -63.7345, + -65.1353, -66.536, -67.9367, -69.3374, -70.7381, -72.1387, -73.5394, -74.94, -76.3406, -77.7412, -79.1417, + -80.5421, -81.9425, -83.3426, -84.7424, -86.1415, -87.5387, -88.9277}; + + std::vector lats_increasing(lats_decreasing); + std::reverse(lats_increasing.begin(), lats_increasing.end()); + + EXPECT(is_approximately_equal_vector(util::gaussian_latitudes(64, false), lats_decreasing, 1e-4)); + EXPECT(is_approximately_equal_vector(util::gaussian_latitudes(64, true), lats_increasing, 1e-4)); +} + + +CASE("eckit::geo::util::reduced_classical_pl") { + const pl_type pl{20, 27, 32, 40, 45, 48, 60, 60, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 60, 60, 48, 45, 40, 32, 27, 20}; + EXPECT(is_approximately_equal_vector(util::reduced_classical_pl(16), pl)); + EXPECT(is_approximately_equal_vector(util::reduced_classical_pl(16), pl)); +} + + +CASE("eckit::geo::util::reduced_octahedral_pl") { + const pl_type pl{20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72, 76, 80, + 80, 76, 72, 68, 64, 60, 56, 52, 48, 44, 40, 36, 32, 28, 24, 20}; + EXPECT(is_approximately_equal_vector(util::reduced_octahedral_pl(16), pl)); + EXPECT(is_approximately_equal_vector(util::reduced_octahedral_pl(16), pl)); +} + + +CASE("eckit::geo::util::monotonic_crop") { + struct test { + double min; + double max; + std::pair expected; + std::vector values; + std::vector cropped; + } tests[]{ + {1., 1., {0, 1}, {1.}, {1.}}, + {1., 2., {0, 3}, {1., 1., 1.}, {1., 1., 1.}}, + {2., 3., {1, 3}, {1., 2., 3., 4., 5., 6.}, {2., 3.}}, + {2., 3., {3, 5}, {6., 5., 4., 3., 2., 1.}, {3., 2.}}, + }; + + for (const auto& test : tests) { + auto [from, to] = util::monotonic_crop(test.values, test.min, test.max, 0.); + + EXPECT(from == test.expected.first); + EXPECT(to == test.expected.second); + + EXPECT(is_approximately_equal_vector(std::vector(test.values.begin() + from, test.values.begin() + to), + test.cropped)); + } } From 24dad41010a672b27a04a74d9c903ee948bf0886 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 15 Feb 2024 11:55:51 +0000 Subject: [PATCH 490/737] eckit::geo::Grid --- tests/geo/range.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 3cf431a28..47036fba7 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -42,7 +42,6 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) { CASE("range::RegularLongitude") { -#if 0 SECTION("degenerate") { EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 0.), eckit::AssertionFailed); EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 10.), eckit::AssertionFailed); @@ -72,7 +71,7 @@ CASE("range::RegularLongitude") { EXPECT_APPROX(values[1], 0., EPS); EXPECT_APPROX(values[2], 90., EPS); } -#endif + SECTION("range [-180, 180]") { const range::RegularLongitude range1(4, -180., 180.); From 7744ce4e9b01b1c4142af9b9ffdd8e48331db771 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 15 Feb 2024 12:12:55 +0000 Subject: [PATCH 491/737] eckit::geo::Spec --- tests/geo/CMakeLists.txt | 1 - tests/geo/gridspec.cc | 139 --------------------------------------- tests/geo/spec.cc | 137 +++++++++++++++++++++++++++++++++++--- 3 files changed, 128 insertions(+), 149 deletions(-) delete mode 100644 tests/geo/gridspec.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index fdb0c747b..188abbf35 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -9,7 +9,6 @@ foreach(_test grid_regular_ll grid_reorder grid_to_points - gridspec increments iterator kdtree diff --git a/tests/geo/gridspec.cc b/tests/geo/gridspec.cc deleted file mode 100644 index e430e6a01..000000000 --- a/tests/geo/gridspec.cc +++ /dev/null @@ -1,139 +0,0 @@ -/* - * (S) Copyright 1996- 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 -#include - -#include "eckit/geo/Grid.h" -#include "eckit/geo/spec/Custom.h" -#include "eckit/log/Log.h" -#include "eckit/testing/Test.h" -#include "eckit/types/FloatCompare.h" - - -#define EXPECT_APPROX(a, b, eps) EXPECT(::eckit::types::is_approximately_equal((a), (b), (eps))) - -#define EXPECT_AREA(a, b, eps) \ - EXPECT((a).size() == 4 && (b).size() == 4 && EXPECT_APPROX((a)[0], (b)[0], (eps)) && \ - EXPECT_APPROX((a)[1], (b)[1], (eps)) && EXPECT_APPROX((a)[2], (b)[2], (eps)) && \ - EXPECT_APPROX((a)[3], (b)[3], (eps))) - - -namespace eckit::test { - - -using namespace geo; - - -using S = std::unique_ptr; -using G = std::unique_ptr; -using C = spec::Custom; -using v = std::vector; - - -static const spec::Custom BAD; - - -static std::pair cases[]{ - {C({{"N", 2}}), C({{"N", 2}, {"type", "reduced_gg"}})}, - {C({{"area", v{90, -180, -90, 180}}, {"grid", v{2, 2}}}), C({{"type", "regular_ll"}})}, - {C({{"area", v{90, -180, -90, 180}}}), BAD}, - {C({{"grid", "B48"}}), BAD}, - {C({{"grid", "F48"}}), C({{"type", "regular_gg"}})}, - {C({{"grid", "N48"}}), C({{"type", "reduced_gg"}})}, - {C({{"grid", "O48"}}), C({{"type", "reduced_gg"}})}, - {C({{"grid", 48}}), BAD}, - {C({{"grid", v{2, 2}}}), C({{"grid", v{2, 2}}, {"type", "regular_ll"}})}, - {C({{"type", "latlon"}, {"grid", v{2, 2}}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "48"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "F048"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "N"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "N048"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "N48"}}), C({{"type", "reduced_gg"}})}, - {C({{"type", "reduced_gg"}, {"grid", "O048"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "O48"}}), C({{"type", "reduced_gg"}})}, - {C({{"type", "reduced_gg"}, {"grid", 48}}), BAD}, - {C({{"type", "reduced_gg"}}), BAD}, - {C({{"type", "reduced_latlon"}, {"grid", 2}}), BAD}, - {C({{"type", "reduced_ll"}, {"grid", 12}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "48"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "F048"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "F48"}}), C({{"type", "regular_gg"}})}, - {C({{"type", "regular_gg"}, {"grid", "N48"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "O48"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "a"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", 48}}), BAD}, - {C({{"type", "regular_ll"}, {"area", v{90, -180, -90, 180}}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", "F48"}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", "a"}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", 48}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", std::vector{"a", "b"}}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", v{1, 2, 3}}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", v{1, 2}}}), C({{"type", "regular_ll"}})}, - {C({{"type", "regular_ll"}, {"grid", v{1}}}), BAD}, - - {C({{"type", "mercator"}, - {"area", v{31.173058, 262.036499, 14.736453, 284.975281}}, - {"grid", v{45000.0, 45000.0}}, - {"lad", 14.0}, - {"nx", 56}, - {"ny", 44}, - {"orientation", 0.0}}), - C()}, -}; - - -CASE("gridspec") { - SECTION("user -> type") { - for (const auto& [user, gridspec] : cases) { - Log::info() << user << " -> " << gridspec << std::endl; - - S spec(GridFactory::spec(user)); - ASSERT(spec); - - if (!spec->has("type")) { - EXPECT(gridspec.empty()); - continue; - } - - if (gridspec.empty()) { - EXPECT_THROWS(GridFactory::build(*spec)); - } - else { - EXPECT_NO_THROW(GridFactory::build(*spec)); - } - } - } - - - SECTION("user -> grid -> gridspec") { - for (const auto& [user, gridspec] : cases) { - Log::info() << user << " -> " << gridspec << std::endl; - - if (gridspec.empty()) { - EXPECT_THROWS(G(GridFactory::build(user))); - continue; - } - - // G grid(GridFactory::build(*user)); - // EXPECT(grid); - } - } -} - - -} // namespace eckit::test - - -int main(int argc, char** argv) { - return eckit::testing::run_tests(argc, argv); -} diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index d1748efaf..549a78b2b 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -12,10 +12,22 @@ #include #include +#include +#include "eckit/geo/Grid.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/spec/Layered.h" +#include "eckit/log/Log.h" #include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" + + +#define EXPECT_APPROX(a, b, eps) EXPECT(::eckit::types::is_approximately_equal((a), (b), (eps))) + +#define EXPECT_AREA(a, b, eps) \ + EXPECT((a).size() == 4 && (b).size() == 4 && EXPECT_APPROX((a)[0], (b)[0], (eps)) && \ + EXPECT_APPROX((a)[1], (b)[1], (eps)) && EXPECT_APPROX((a)[2], (b)[2], (eps)) && \ + EXPECT_APPROX((a)[3], (b)[3], (eps))) //---------------------------------------------------------------------------------------------------------------------- @@ -27,7 +39,18 @@ namespace eckit::test { using namespace geo; -CASE("Custom") { +using S = std::unique_ptr; +using G = std::unique_ptr; +using C = spec::Custom; +using v = std::vector; + + +CASE("Spec <- Custom") { + int one = 1; + double two = 2.; + std::string three = "3"; + + SECTION("access") { std::unique_ptr spec(new spec::Custom({{"a", -123}, {"b", "B"}, {"c", 123UL}})); @@ -50,12 +73,9 @@ CASE("Custom") { EXPECT_EQUAL(d, 321); } - SECTION("conversion") { - int one = 1; - double two = 2.; - std::string three = "3"; - +#if 0 + SECTION("conversion (1)") { spec::Custom a({ {"double", static_cast(one)}, {"float", static_cast(one)}, @@ -84,8 +104,11 @@ CASE("Custom") { EXPECT_EQUAL(a.get_string(key), std::to_string(1)); } + } +#endif + SECTION("conversion (2)") { spec::Custom b({ {"true", true}, {"false", false}, @@ -116,8 +139,11 @@ CASE("Custom") { EXPECT(b.get_bool("one")); EXPECT(b.get_bool("one", maybe = false)); EXPECT(b.get("one", maybe = false) && maybe); + } +#if 0 + SECTION("conversion (3)") { spec::Custom c; EXPECT_NOT(c.has("foo")); @@ -152,12 +178,11 @@ CASE("Custom") { ASSERT(e.has("foo")); ASSERT(e.has("bar")); } +#endif } -//---------------------------------------------------------------------------------------------------------------------- - -CASE("Layered") { +CASE("Spec <- Layered") { int one = 1; double two = 2.; @@ -183,6 +208,100 @@ CASE("Layered") { } +CASE("spec") { + static const spec::Custom BAD; + + static std::pair cases[]{ + {C({{"N", 2}}), C({{"N", 2}, {"type", "reduced_gg"}})}, + {C({{"area", v{90, -180, -90, 180}}, {"grid", v{2, 2}}}), C({{"type", "regular_ll"}})}, + {C({{"area", v{90, -180, -90, 180}}}), BAD}, + {C({{"grid", "B48"}}), BAD}, + {C({{"grid", "F48"}}), C({{"type", "regular_gg"}})}, + {C({{"grid", "N48"}}), C({{"type", "reduced_gg"}})}, + {C({{"grid", "O48"}}), C({{"type", "reduced_gg"}})}, + {C({{"grid", 48}}), BAD}, + {C({{"grid", v{2, 2}}}), C({{"grid", v{2, 2}}, {"type", "regular_ll"}})}, + {C({{"type", "latlon"}, {"grid", v{2, 2}}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "48"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "F048"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "N"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "N048"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "N48"}}), C({{"type", "reduced_gg"}})}, + {C({{"type", "reduced_gg"}, {"grid", "O048"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "O48"}}), C({{"type", "reduced_gg"}})}, + {C({{"type", "reduced_gg"}, {"grid", 48}}), BAD}, + {C({{"type", "reduced_gg"}}), BAD}, + {C({{"type", "reduced_latlon"}, {"grid", 2}}), BAD}, + {C({{"type", "reduced_ll"}, {"grid", 12}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "48"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "F048"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "F48"}}), C({{"type", "regular_gg"}})}, + {C({{"type", "regular_gg"}, {"grid", "N48"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "O48"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "a"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", 48}}), BAD}, + {C({{"type", "regular_ll"}, {"area", v{90, -180, -90, 180}}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", "F48"}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", "a"}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", 48}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", std::vector{"a", "b"}}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", v{1, 2, 3}}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", v{1, 2}}}), C({{"type", "regular_ll"}})}, + {C({{"type", "regular_ll"}, {"grid", v{1}}}), BAD}, + + {C({{"type", "mercator"}, + {"area", v{31.173058, 262.036499, 14.736453, 284.975281}}, + {"grid", v{45000.0, 45000.0}}, + {"lad", 14.0}, + {"nx", 56}, + {"ny", 44}, + {"orientation", 0.0}}), + C()}, + }; + + +#if 0 + SECTION("user -> type") { + for (const auto& [user, spec] : cases) { + Log::info() << user << " -> " << spec << std::endl; + + S userspec(GridFactory::spec(user)); + ASSERT(userspec); + + if (!userspec->has("type")) { + EXPECT(spec.empty()); + continue; + } + + if (spec.empty()) { + EXPECT_THROWS(GridFactory::build(*userspec)); + } + else { + EXPECT_NO_THROW(GridFactory::build(*userspec)); + } + } + } +#endif + + +#if 0 + SECTION("user -> grid -> spec") { + for (const auto& [user, spec] : cases) { + Log::info() << user << " -> " << spec << std::endl; + + if (spec.empty()) { + EXPECT_THROWS(G(GridFactory::build(user))); + continue; + } + + // G grid(GridFactory::build(*user)); + // EXPECT(grid); + } + } +#endif +} + + } // namespace eckit::test From 5998ac9dc3f6f8c80d13a7da9098c5f1968ff554 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 15 Feb 2024 14:14:48 +0000 Subject: [PATCH 492/737] eckit::geo::Spec --- src/eckit/geo/Spec.cc | 44 ++++++++++++++++++------------------ src/eckit/geo/spec/Custom.cc | 17 +++++++++++--- tests/geo/spec.cc | 44 +++++++++++++++++++++--------------- 3 files changed, 62 insertions(+), 43 deletions(-) diff --git a/src/eckit/geo/Spec.cc b/src/eckit/geo/Spec.cc index 72f906a60..5c930b2f0 100644 --- a/src/eckit/geo/Spec.cc +++ b/src/eckit/geo/Spec.cc @@ -18,13 +18,20 @@ namespace eckit::geo { template -static T _get(const Spec& spec, const std::string& name, const T& _default) { +static T _get_d(const Spec& spec, const std::string& name, const T& _default) { T value{_default}; spec.get(name, value); return value; } +template +static T _get_t(const Spec& spec, const std::string& name) { + T value{}; + return spec.get(name, value) ? value : throw SpecNotFound(name); +} + + SpecNotFound::SpecNotFound(const std::string& name) { std::ostringstream s; s << "SpecNotFound: [" << name << "]"; @@ -33,79 +40,72 @@ SpecNotFound::SpecNotFound(const std::string& name) { bool Spec::get_bool(const std::string& name) const { - ASSERT(has(name)); - return _get(*this, name, false); + return _get_t(*this, name); } int Spec::get_int(const std::string& name) const { - ASSERT(has(name)); - return _get(*this, name, 0); + return _get_t(*this, name); } long Spec::get_long(const std::string& name) const { - ASSERT(has(name)); - return _get(*this, name, 0); + return _get_t(*this, name); } std::size_t Spec::get_unsigned(const std::string& name) const { - ASSERT(has(name)); - return _get(*this, name, 0); + return _get_t(*this, name); } double Spec::get_double(const std::string& name) const { - ASSERT(has(name)); - return _get(*this, name, 0); + return _get_t(*this, name); } std::string Spec::get_string(const std::string& name) const { - ASSERT(has(name)); - return _get(*this, name, {}); + return _get_t(*this, name); } std::vector Spec::get_long_vector(const std::string& name) const { - ASSERT(has(name)); - return _get>(*this, name, {}); + return _get_t>(*this, name); } bool Spec::get_bool(const std::string& name, const bool& _default) const { - return _get(*this, name, _default); + return _get_d(*this, name, _default); } int Spec::get_int(const std::string& name, const int& _default) const { - return _get(*this, name, _default); + return _get_d(*this, name, _default); } long Spec::get_long(const std::string& name, const long& _default) const { - return _get(*this, name, _default); + return _get_d(*this, name, _default); } std::size_t Spec::get_unsigned(const std::string& name, const std::size_t& _default) const { - return _get(*this, name, _default); + return _get_d(*this, name, _default); } double Spec::get_double(const std::string& name, const double& _default) const { - return _get(*this, name, _default); + return _get_d(*this, name, _default); } std::string Spec::get_string(const std::string& name, const std::string& _default) const { - return _get(*this, name, _default); + return _get_d(*this, name, _default); } std::vector Spec::get_long_vector(const std::string& name, const std::vector& _default) const { - return _get(*this, name, _default); + return _get_d(*this, name, _default); } diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 3b11beed5..4ddb31c7d 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -27,6 +27,13 @@ bool __get_s(const From& from, To& to) { } +template +bool __get_s(const From& from, std::string& to) { + to = std::to_string(from); + return true; +} + + template bool __get_s(const From& from, From& to) { to = from; @@ -230,9 +237,13 @@ bool Custom::has(const std::string& name) const { bool Custom::get(const std::string& name, std::string& value) const { - if (auto it = map_.find(name); it != map_.cend() && std::holds_alternative(it->second)) { - value = std::get(it->second); - return true; + if (auto it = map_.find(name); it != map_.cend() /*&& )*/) { + if (std::holds_alternative(it->second)) { + value = std::get(it->second); + return true; + } + + return __get_s_real(map_, name, value); } return false; } diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 549a78b2b..3e79fe2b5 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -46,9 +46,10 @@ using v = std::vector; CASE("Spec <- Custom") { - int one = 1; - double two = 2.; - std::string three = "3"; + constexpr int zero = 0; + constexpr int one = 1; + constexpr double two = 2.; + const std::string three = "3"; SECTION("access") { @@ -74,8 +75,7 @@ CASE("Spec <- Custom") { } -#if 0 - SECTION("conversion (1)") { + SECTION("conversion (2)") { spec::Custom a({ {"double", static_cast(one)}, {"float", static_cast(one)}, @@ -85,7 +85,7 @@ CASE("Spec <- Custom") { }); // test scalar type conversion - for (std::string key : {"double", "float", "int", "long", "size_t"}) { + for (const std::string& key : {"double", "float", "int", "long", "size_t"}) { double value_as_double = 0; float value_as_float = 0; @@ -100,15 +100,17 @@ CASE("Spec <- Custom") { EXPECT(a.get(key, value_as_int) && value_as_int == static_cast(one)); EXPECT(a.get(key, value_as_long) && value_as_long == static_cast(one)); EXPECT(a.get(key, value_as_size_t) && value_as_size_t == static_cast(one)); - } - EXPECT_EQUAL(a.get_string(key), std::to_string(1)); + EXPECT_EQUAL(a.get_string(key), std::to_string(1)); + } + else { + EXPECT_EQUAL(a.get_string(key), std::to_string(1.)); + } } } -#endif - SECTION("conversion (2)") { + SECTION("conversion (4)") { spec::Custom b({ {"true", true}, {"false", false}, @@ -142,8 +144,7 @@ CASE("Spec <- Custom") { } -#if 0 - SECTION("conversion (3)") { + SECTION("conversion (4)") { spec::Custom c; EXPECT_NOT(c.has("foo")); @@ -151,7 +152,7 @@ CASE("Spec <- Custom") { EXPECT(c.has("foo")); EXPECT_THROWS_AS(c.get_int("foo"), SpecNotFound); // cannot access as int EXPECT(::eckit::types::is_approximately_equal(c.get_double("foo"), two)); - EXPECT(c.get_string("foo") == "2"); + EXPECT(c.get_string("foo") == std::to_string(two)); c.set("bar", one); EXPECT_EQUAL(c.get_int("bar"), one); @@ -178,7 +179,18 @@ CASE("Spec <- Custom") { ASSERT(e.has("foo")); ASSERT(e.has("bar")); } -#endif + + + SECTION("conversion (5)") { + spec::Custom e({{"zero", zero}, {"one", one}, {"two", two}}); + + bool maybe = true; + EXPECT(!e.get("?", maybe) && maybe); // non-existant key + EXPECT(!e.get("two", maybe) && maybe); // non-convertible + + EXPECT(e.get("zero", maybe) && !maybe); + EXPECT(e.get("one", maybe) && maybe); + } } @@ -260,7 +272,6 @@ CASE("spec") { }; -#if 0 SECTION("user -> type") { for (const auto& [user, spec] : cases) { Log::info() << user << " -> " << spec << std::endl; @@ -281,10 +292,8 @@ CASE("spec") { } } } -#endif -#if 0 SECTION("user -> grid -> spec") { for (const auto& [user, spec] : cases) { Log::info() << user << " -> " << spec << std::endl; @@ -298,7 +307,6 @@ CASE("spec") { // EXPECT(grid); } } -#endif } From 071077cdaacbc1cbf44da5a589a2f4aaf3075ee2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 15 Feb 2024 17:59:46 +0000 Subject: [PATCH 493/737] eckit::geo::Spec --- src/eckit/geo/Grid.cc | 10 ++++++++-- src/eckit/geo/Increments.cc | 8 ++++---- tests/geo/spec.cc | 39 ++++++++++++------------------------- 3 files changed, 24 insertions(+), 33 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 91836c6a3..ad4acdb29 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -134,7 +134,7 @@ const Grid* GridFactory::build_(const Spec& spec) const { } list(Log::error() << "Grid: cannot build grid without 'type', choices are: "); - throw SeriousBug("Grid: cannot build grid without 'type'"); + throw SpecNotFound("Grid: cannot build grid without 'type'"); } @@ -172,7 +172,13 @@ Spec* GridFactory::generate_spec_(const Spec& spec) const { cfg->push_front(SpecByUID::instance().get(uid).spec()); } else if (std::string grid; cfg->get("grid", grid) && SpecByName::instance().matches(grid)) { - cfg->push_front(SpecByName::instance().match(grid).spec(grid)); + std::unique_ptr front(SpecByName::instance().match(grid).spec(grid)); + + if (std::string user, forced; front->get("type", forced) && cfg->get("type", user) && user != forced) { + throw BadParameter("Grid: conflicting 'type': '" + user + "' and '" + forced + "'"); + } + + cfg->push_front(front.release()); } diff --git a/src/eckit/geo/Increments.cc b/src/eckit/geo/Increments.cc index a8989aa55..bd54fddfc 100644 --- a/src/eckit/geo/Increments.cc +++ b/src/eckit/geo/Increments.cc @@ -21,11 +21,11 @@ namespace eckit::geo { static Increments make_from_spec(const Spec& spec) { - std::vector grid; - spec.get("grid", grid); + if (std::vector grid; spec.get("grid", grid) && grid.size() == 2) { + return {grid[0], grid[1]}; + } - ASSERT_MSG(grid.size() == 2, "Increments: expected list of size 2"); - return {grid[0], grid[1]}; + throw BadParameter("Increments: expected list of size 2"); } diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 3e79fe2b5..7a7f50957 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -222,6 +222,7 @@ CASE("Spec <- Layered") { CASE("spec") { static const spec::Custom BAD; + ASSERT(BAD.empty()); static std::pair cases[]{ {C({{"N", 2}}), C({{"N", 2}, {"type", "reduced_gg"}})}, @@ -273,40 +274,24 @@ CASE("spec") { SECTION("user -> type") { - for (const auto& [user, spec] : cases) { - Log::info() << user << " -> " << spec << std::endl; + for (const auto& [user, gridspec] : cases) { + Log::info() << user << " -> " << gridspec << std::endl; - S userspec(GridFactory::spec(user)); - ASSERT(userspec); + try { + S spec(GridFactory::spec(user)); + EXPECT(spec); - if (!userspec->has("type")) { - EXPECT(spec.empty()); - continue; + G grid(GridFactory::build(*spec)); + EXPECT(grid); } - - if (spec.empty()) { - EXPECT_THROWS(GridFactory::build(*userspec)); + catch (const SpecNotFound& e) { + EXPECT(gridspec.empty() /*BAD*/); } - else { - EXPECT_NO_THROW(GridFactory::build(*userspec)); + catch (const BadParameter& e) { + EXPECT(gridspec.empty() /*BAD*/); } } } - - - SECTION("user -> grid -> spec") { - for (const auto& [user, spec] : cases) { - Log::info() << user << " -> " << spec << std::endl; - - if (spec.empty()) { - EXPECT_THROWS(G(GridFactory::build(user))); - continue; - } - - // G grid(GridFactory::build(*user)); - // EXPECT(grid); - } - } } From fcbd05ef1155288d22b7ad3ba24a5bed5e17e20a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 16 Feb 2024 16:07:16 +0000 Subject: [PATCH 494/737] eckit::geo::Spec --- src/eckit/geo/Grid.cc | 5 +++-- tests/geo/grid_to_points.cc | 4 +++- tests/geo/spec.cc | 10 +++++----- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index ad4acdb29..26f13102e 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -172,13 +172,14 @@ Spec* GridFactory::generate_spec_(const Spec& spec) const { cfg->push_front(SpecByUID::instance().get(uid).spec()); } else if (std::string grid; cfg->get("grid", grid) && SpecByName::instance().matches(grid)) { - std::unique_ptr front(SpecByName::instance().match(grid).spec(grid)); + auto* front = SpecByName::instance().match(grid).spec(grid); + ASSERT(front != nullptr); if (std::string user, forced; front->get("type", forced) && cfg->get("type", user) && user != forced) { throw BadParameter("Grid: conflicting 'type': '" + user + "' and '" + forced + "'"); } - cfg->push_front(front.release()); + cfg->push_front(front); } diff --git a/tests/geo/grid_to_points.cc b/tests/geo/grid_to_points.cc index 358c667d0..baf0eda57 100644 --- a/tests/geo/grid_to_points.cc +++ b/tests/geo/grid_to_points.cc @@ -22,6 +22,8 @@ namespace eckit::test { using namespace geo; +constexpr auto EPS = 1e-3; + CASE("HEALPix") { SECTION("HEALPix::to_points") { @@ -44,7 +46,7 @@ CASE("HEALPix") { EXPECT_EQUAL(points.size(), expected_points_ring.size()); for (int i = 0; i < points.size(); ++i) { - EXPECT(points_equal(std::get(points[i]), expected_points_ring[i])); + EXPECT(points_equal(std::get(points[i]), expected_points_ring[i], EPS)); } } } diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 7a7f50957..12b84e41b 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -75,7 +75,7 @@ CASE("Spec <- Custom") { } - SECTION("conversion (2)") { + SECTION("conversion (1)") { spec::Custom a({ {"double", static_cast(one)}, {"float", static_cast(one)}, @@ -110,7 +110,7 @@ CASE("Spec <- Custom") { } - SECTION("conversion (4)") { + SECTION("conversion (2)") { spec::Custom b({ {"true", true}, {"false", false}, @@ -144,7 +144,7 @@ CASE("Spec <- Custom") { } - SECTION("conversion (4)") { + SECTION("conversion (3)") { spec::Custom c; EXPECT_NOT(c.has("foo")); @@ -174,14 +174,14 @@ CASE("Spec <- Custom") { EXPECT_EQUAL(d.get_int("foo"), one); - spec::Custom e(c); + spec::Custom e(d); ASSERT(e.has("foo")); ASSERT(e.has("bar")); } - SECTION("conversion (5)") { + SECTION("conversion (4)") { spec::Custom e({{"zero", zero}, {"one", one}, {"two", two}}); bool maybe = true; From e20bd323771296cea66afd2cf2fd135b8f1c7920 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 16 Feb 2024 17:23:56 +0000 Subject: [PATCH 495/737] eckit::geo::Point --- tests/geo/CMakeLists.txt | 3 + tests/geo/grid_to_points.cc | 62 ++++++++--- tests/geo/point.cc | 198 ++++-------------------------------- tests/geo/point2.cc | 141 +++++++++++++++++++++++++ tests/geo/point3.cc | 50 +++++++++ tests/geo/pointlonlat.cc | 97 ++++++++++++++++++ 6 files changed, 359 insertions(+), 192 deletions(-) create mode 100644 tests/geo/point2.cc create mode 100644 tests/geo/point3.cc create mode 100644 tests/geo/pointlonlat.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 188abbf35..bf6b8c15f 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -14,6 +14,9 @@ foreach(_test kdtree kpoint point + point2 + point3 + pointlonlat projection range search diff --git a/tests/geo/grid_to_points.cc b/tests/geo/grid_to_points.cc index baf0eda57..38db940b6 100644 --- a/tests/geo/grid_to_points.cc +++ b/tests/geo/grid_to_points.cc @@ -22,31 +22,67 @@ namespace eckit::test { using namespace geo; -constexpr auto EPS = 1e-3; - CASE("HEALPix") { SECTION("HEALPix::to_points") { std::unique_ptr grid(new grid::reduced::HEALPix(2, Ordering::healpix_ring)); static const std::vector expected_points_ring{ - {45, 66.443536}, {135, 66.443536}, {225, 66.443536}, {315, 66.443536}, {22.5, 41.810315}, - {67.5, 41.810315}, {112.5, 41.810315}, {157.5, 41.810315}, {202.5, 41.810315}, {247.5, 41.810315}, - {292.5, 41.810315}, {337.5, 41.810315}, {0, 19.471221}, {45, 19.471221}, {90, 19.471221}, - {135, 19.471221}, {180, 19.471221}, {225, 19.471221}, {270, 19.471221}, {315, 19.471221}, - {22.5, 0}, {67.5, 0}, {112.5, 0}, {157.5, 0}, {202.5, 0}, - {247.5, 0}, {292.5, 0}, {337.5, 0}, {0, -19.471221}, {45, -19.471221}, - {90, -19.471221}, {135, -19.471221}, {180, -19.471221}, {225, -19.471221}, {270, -19.471221}, - {315, -19.471221}, {22.5, -41.810315}, {67.5, -41.810315}, {112.5, -41.810315}, {157.5, -41.810315}, - {202.5, -41.810315}, {247.5, -41.810315}, {292.5, -41.810315}, {337.5, -41.810315}, {45, -66.443536}, - {135, -66.443536}, {225, -66.443536}, {315, -66.443536}, + {45, 66.443535691}, + {135, 66.443535691}, + {225, 66.443535691}, + {315, 66.443535691}, + {22.5, 41.810314896}, + {67.5, 41.810314896}, + {112.5, 41.810314896}, + {157.5, 41.810314896}, + {202.5, 41.810314896}, + {247.5, 41.810314896}, + {292.5, 41.810314896}, + {337.5, 41.810314896}, + {0, 19.471220634}, + {45, 19.471220634}, + {90, 19.471220634}, + {135, 19.471220634}, + {180, 19.471220634}, + {225, 19.471220634}, + {270, 19.471220634}, + {315, 19.471220634}, + {22.5, 0}, + {67.5, 0}, + {112.5, 0}, + {157.5, 0}, + {202.5, 0}, + {247.5, 0}, + {292.5, 0}, + {337.5, 0}, + {0, -19.471220634}, + {45, -19.471220634}, + {90, -19.471220634}, + {135, -19.471220634}, + {180, -19.471220634}, + {225, -19.471220634}, + {270, -19.471220634}, + {315, -19.471220634}, + {22.5, -41.810314896}, + {67.5, -41.810314896}, + {112.5, -41.810314896}, + {157.5, -41.810314896}, + {202.5, -41.810314896}, + {247.5, -41.810314896}, + {292.5, -41.810314896}, + {337.5, -41.810314896}, + {45, -66.443535691}, + {135, -66.443535691}, + {225, -66.443535691}, + {315, -66.443535691}, }; auto points = grid->to_points(); EXPECT_EQUAL(points.size(), expected_points_ring.size()); for (int i = 0; i < points.size(); ++i) { - EXPECT(points_equal(std::get(points[i]), expected_points_ring[i], EPS)); + EXPECT(points_equal(std::get(points[i]), expected_points_ring[i])); } } } diff --git a/tests/geo/point.cc b/tests/geo/point.cc index 3e1482db9..8f8e5f340 100644 --- a/tests/geo/point.cc +++ b/tests/geo/point.cc @@ -10,9 +10,13 @@ */ +#include + #include "eckit/geo/Point.h" +#include "eckit/geo/Point2.h" +#include "eckit/geo/Point3.h" +#include "eckit/geo/PointLonLat.h" #include "eckit/testing/Test.h" -#include "eckit/types/FloatCompare.h" //---------------------------------------------------------------------------------------------------------------------- @@ -24,190 +28,26 @@ namespace eckit::test { using namespace geo; -CASE("PointLonLat normalisation") { - constexpr auto EPS = 1e-9; - constexpr auto da = 1e-3; - - for (double a = -370.; a < 370.; a += 10.) { - EXPECT(types::is_approximately_equal(a, PointLonLat::normalise_angle_to_minimum(a, a), EPS)); - EXPECT(types::is_approximately_equal(a, PointLonLat::normalise_angle_to_maximum(a, a), EPS)); - EXPECT(types::is_approximately_equal(a + 360., PointLonLat::normalise_angle_to_minimum(a - da, a) + da, EPS)); - EXPECT(types::is_approximately_equal(a - 360., PointLonLat::normalise_angle_to_maximum(a + da, a) - da, EPS)); - } - - PointLonLat p(1, 90.); - EXPECT_EQUAL(p.lon, 1.); - EXPECT_EQUAL(p.lat, 90.); - - auto p2 = PointLonLat::make(p.lon, p.lat); - EXPECT_EQUAL(p2.lon, 0.); - EXPECT(points_equal(p, p2)); - - auto p3 = PointLonLat(50., 90.); - EXPECT(points_equal(p, p3)); - - PointLonLat q(1., -90.); - EXPECT_EQUAL(q.lon, 1.); - EXPECT_EQUAL(q.lat, -90.); - - auto q2 = q.antipode(); - EXPECT_EQUAL(q2.lon, 0.); - EXPECT(points_equal(q2, p)); - - auto q3 = q2.antipode(); - EXPECT(points_equal(q3, q)); -} - - -CASE("PointLonLat comparison") { +CASE("Point comparison") { auto r(PointLonLat::make(-10., -91.)); EXPECT(points_equal(r, r.antipode().antipode())); - Point a1 = PointLonLat{300, -30}; - Point a2 = PointLonLat{-59.99999999999996, -30.000000000000018}; - EXPECT(points_equal(a1, a2)); - - Point b1 = PointLonLat{-178., -46.7}; - Point b2 = PointLonLat{-178.00000000000003, -46.7}; - EXPECT(points_equal(b1, b2)); -} - - -CASE("Inits to Zero") { - Point2 q; - - EXPECT(q[XX] == 0.); - EXPECT(q[YY] == 0.); -} - - -CASE("Inits to Array/Point") { - Point2 q = {4.0, 5.0}; - - EXPECT(q[XX] == 4.0); - EXPECT(q[YY] == 5.0); - - EXPECT(q[LON] == 4.0); - EXPECT(q[LAT] == 5.0); - - Point2 r(q); - EXPECT(r[XX] == 4.0); - EXPECT(r[YY] == 5.0); - - Point3 p = {1.0, 2.0, 3.0}; - Point3 s(p); - EXPECT(s[XX] == 1.0); - EXPECT(s[YY] == 2.0); - EXPECT(s[ZZ] == 3.0); -} - - -CASE("Point2 addition") { - Point2 p1 = {1.0, 2.0}; - Point2 p2 = {2.0, 4.0}; - - Point2 r = p1 + p2; - - EXPECT(r[XX] == 3.0); - EXPECT(r[YY] == 6.0); -} - - -CASE("Point2 subtraction") { - Point2 p1 = {2.0, 5.0}; - Point2 p2 = {1.0, 2.0}; - - Point2 r = p1 - p2; - - EXPECT(r[XX] == 1.0); - EXPECT(r[YY] == 3.0); -} - - -CASE("Point2 scaling") { - Point2 p1 = {1.0, 2.0}; - Point2 p2(p1); - - Point2 r = p1 * 42.0; - - EXPECT(r[XX] == 42.0); - EXPECT(r[YY] == 84.0); - - Point2 oo; - - Point2 p3 = p2 * 2.0; - Point2 p4 = p3 + p2; - Point2 p5 = p4 - p2 * 3; - EXPECT(p5 == oo); -} - - -CASE("Point2 equality") { - Point2 p1 = {1.0, 2.0}; - Point2 p2 = {1.0, 2.0}; - - EXPECT(p1 == p2); -} - - -CASE("Point2 inequality") { - Point2 p1 = {1.0, 3.0}; - Point2 p2 = {1.0, 4.0}; - - EXPECT(p1 != p2); -} - - -CASE("Point2 comparison") { - Point2 p1 = {2.0, 1.0}; - Point2 p2 = {1.0, 2.0}; - - // EXPECT(p2 < p1); -} - - -CASE("Point2 distance comparison") { - Point2 p1 = {2.0, 1.0}; - Point2 p2 = {1.0, 2.0}; - - EXPECT(types::is_approximately_equal(sqrt(2.0), p1.distance(p2))); - - Point2 p3 = {5.0, 5.0}; - - EXPECT(types::is_approximately_equal(p1.distance(p3), 5.0)); -} - - -CASE("Point2 distance2 comparison") { - Point2 p1 = {2.0, 1.0}; - Point2 p2 = {1.0, 2.0}; - - EXPECT(types::is_approximately_equal(p1.distance2(p2), 2.0)); - - Point2 p3 = {5.0, 5.0}; - - EXPECT(types::is_approximately_equal(p1.distance2(p3), 25.0)); -} - - -CASE("Point3 cross") { - Point3 p1 = {1.0, 0.0, 0.0}; - Point3 p2 = {0.0, 1.0, 0.0}; - Point3 p3 = {0.0, 0.0, 1.0}; - - EXPECT(p3 == Point3::cross(p1, p2)); - EXPECT(p1 == Point3::cross(p2, p3)); + for (Point a1 : {PointLonLat{-180., 0.}, PointLonLat{180., 10.}, PointLonLat{0., 90.}, PointLonLat{1., -90.}}) { + auto a2 = PointLonLat::make(std::get(a1).lon + 720., std::get(a1).lat); + EXPECT(points_equal(a1, a2)); + } - Point3 p4 = {1.0, 2.0, 3.0}; - Point3 p5 = {-1.0, -2.0, 4.0}; - Point3 p6 = {2.0, -1.0, 0.0}; + Point2 p2{1., 2.}; + Point3 p3{1., 2., 3.}; + PointLonLat pll{4., 5.}; - Point3 p7 = Point3::normalize(Point3::cross(p4, p5)); - Point3 p8 = Point3::normalize(p6); + for (const auto& [a, b] : {std::pair{p2, p2}, {p3, p3}, {pll, pll}}) { + EXPECT(points_equal(a, b)); + } - EXPECT(types::is_approximately_equal(p7[XX], p8[XX])); - EXPECT(types::is_approximately_equal(p7[YY], p8[YY])); - EXPECT(types::is_approximately_equal(p7[ZZ], p8[ZZ])); + for (const auto& [a, b] : {std::pair{p2, p3}, {p2, pll}, {p3, p2}, {p3, pll}, {pll, p2}, {pll, p3}}) { + EXPECT_THROWS_AS(points_equal(a, b), AssertionFailed); + } } diff --git a/tests/geo/point2.cc b/tests/geo/point2.cc new file mode 100644 index 000000000..62b04ae42 --- /dev/null +++ b/tests/geo/point2.cc @@ -0,0 +1,141 @@ +/* + * (C) Copyright 1996- ECMWF. + * + * This software is licensed under the terms of the Apache Licence Version 2. + * which can be obtained at http://www.apache.org/licenses/LICENSE-2.. + * + * 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 "eckit/geo/Point2.h" +#include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" + + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace eckit::test { + + +using namespace geo; + + +CASE("Point2 initialisation") { + Point2 z; + + EXPECT(z[XX] == 0.); + EXPECT(z[YY] == 0.); + + Point2 q = {4., 5.}; + + EXPECT(q[XX] == 4.); + EXPECT(q[YY] == 5.); + + Point2 r(q); + + EXPECT(r[XX] == 4.); + EXPECT(r[YY] == 5.); +} + + +CASE("Point2 addition") { + Point2 p1 = {1., 2.}; + Point2 p2 = {2., 4.}; + + Point2 r = p1 + p2; + + EXPECT(r[XX] == 3.); + EXPECT(r[YY] == 6.); +} + + +CASE("Point2 subtraction") { + Point2 p1 = {2., 5.}; + Point2 p2 = {1., 2.}; + + Point2 r = p1 - p2; + + EXPECT(r[XX] == 1.); + EXPECT(r[YY] == 3.); +} + + +CASE("Point2 scaling") { + Point2 p1 = {1., 2.}; + Point2 p2(p1); + + Point2 r = p1 * 42.; + + EXPECT(r[XX] == 42.); + EXPECT(r[YY] == 84.); + + Point2 oo; + + Point2 p3 = p2 * 2.; + Point2 p4 = p3 + p2; + Point2 p5 = p4 - p2 * 3; + EXPECT(p5 == oo); +} + + +CASE("Point2 equality") { + Point2 p1 = {1., 2.}; + Point2 p2 = {1., 2.}; + + EXPECT(p1 == p2); +} + + +CASE("Point2 inequality") { + Point2 p1 = {1., 3.}; + Point2 p2 = {1., 4.}; + + EXPECT(p1 != p2); +} + + +CASE("Point2 comparison") { + Point2 p1 = {2., 1.}; + Point2 p2 = {1., 2.}; + + // EXPECT(p2 < p1); +} + + +CASE("Point2 distance comparison") { + Point2 p1 = {2., 1.}; + Point2 p2 = {1., 2.}; + + EXPECT(types::is_approximately_equal(sqrt(2.), p1.distance(p2))); + + Point2 p3 = {5., 5.}; + + EXPECT(types::is_approximately_equal(p1.distance(p3), 5.)); +} + + +CASE("Point2 distance2 comparison") { + Point2 p1 = {2., 1.}; + Point2 p2 = {1., 2.}; + + EXPECT(types::is_approximately_equal(p1.distance2(p2), 2.)); + + Point2 p3 = {5., 5.}; + + EXPECT(types::is_approximately_equal(p1.distance2(p3), 25.)); +} + + +} // namespace eckit::test + + +//---------------------------------------------------------------------------------------------------------------------- + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/point3.cc b/tests/geo/point3.cc new file mode 100644 index 000000000..7c3e4bb6e --- /dev/null +++ b/tests/geo/point3.cc @@ -0,0 +1,50 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Point3.h" +#include "eckit/testing/Test.h" + + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace eckit::test { + + +using namespace geo; + + +CASE("Point3 initialisation") { + Point3 z; + + EXPECT(z[XX] == 0.); + EXPECT(z[YY] == 0.); + EXPECT(z[ZZ] == 0.); + + Point3 p = {1., 2., 3.}; + Point3 s(p); + + EXPECT(s[XX] == 1.); + EXPECT(s[YY] == 2.); + EXPECT(s[ZZ] == 3.); +} + + +} // namespace eckit::test + + +//---------------------------------------------------------------------------------------------------------------------- + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/pointlonlat.cc b/tests/geo/pointlonlat.cc new file mode 100644 index 000000000..d0c19c345 --- /dev/null +++ b/tests/geo/pointlonlat.cc @@ -0,0 +1,97 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/PointLonLat.h" +#include "eckit/geo/Point.h" +#include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" + + +//---------------------------------------------------------------------------------------------------------------------- + + +namespace eckit::test { + + +using namespace geo; + + +CASE("PointLonLat normalisation") { + constexpr auto da = 1e-3; + + for (double a : {-370., -190., -100., -90., -80., -10., 0., 10., 80., 90., 100., 190., 370.}) { + EXPECT(types::is_approximately_equal(a, PointLonLat::normalise_angle_to_minimum(a, a), PointLonLat::EPS)); + EXPECT(types::is_approximately_equal(a, PointLonLat::normalise_angle_to_maximum(a, a), PointLonLat::EPS)); + + EXPECT(types::is_approximately_equal(a + 360., + PointLonLat::normalise_angle_to_minimum(a - da, a) + da, + PointLonLat::EPS)); + EXPECT(types::is_approximately_equal(a - 360., + PointLonLat::normalise_angle_to_maximum(a + da, a) - da, + PointLonLat::EPS)); + } + + PointLonLat p(1, 90.); + EXPECT_EQUAL(p.lon, 1.); + EXPECT_EQUAL(p.lat, 90.); + + auto p2 = PointLonLat::make(p.lon, p.lat); + EXPECT_EQUAL(p2.lon, 0.); + EXPECT(points_equal(p, p2)); + + auto p3 = PointLonLat(50., 90.); + EXPECT(points_equal(p, p3)); + + PointLonLat q(1., -90.); + EXPECT_EQUAL(q.lon, 1.); + EXPECT_EQUAL(q.lat, -90.); + + auto q2 = q.antipode(); + EXPECT_EQUAL(q2.lon, 0.); + EXPECT(points_equal(q2, p)); + + auto q3 = q2.antipode(); + EXPECT(points_equal(q3, q)); +} + + +CASE("PointLonLat comparison") { + auto r(PointLonLat::make(-10., -91.)); + EXPECT(points_equal(r, r.antipode().antipode())); + + Point a1 = PointLonLat{180., 0.}; + Point a2 = PointLonLat{-180., 0.}; + EXPECT(points_equal(a1, a2)); + + Point b1 = PointLonLat{0., -90.}; + Point b2 = PointLonLat::make(1., 270.); + EXPECT(points_equal(b1, b2)); + + Point c1 = PointLonLat{300, -30}; + Point c2 = PointLonLat{-59.99999999999996, -30.000000000000018}; + EXPECT(points_equal(c1, c2)); + + Point d1 = PointLonLat{-178., -46.7}; + Point d2 = PointLonLat{-178.00000000000003, -46.7}; + EXPECT(points_equal(d1, d2)); +} + + +} // namespace eckit::test + + +//---------------------------------------------------------------------------------------------------------------------- + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From 8e2833a4b87ef1cd4121d6225a6519ce3166799c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 17 Feb 2024 11:53:14 +0000 Subject: [PATCH 496/737] eckit::geo::Point --- src/eckit/geo/Point.cc | 6 ++++++ src/eckit/geo/Point.h | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/Point.cc b/src/eckit/geo/Point.cc index 669fedc34..970ab30d7 100644 --- a/src/eckit/geo/Point.cc +++ b/src/eckit/geo/Point.cc @@ -20,6 +20,12 @@ namespace eckit::geo { +bool points_equal(const Point& p, const Point& q) { + ASSERT(p.index() == q.index()); + return std::visit([&](const auto& p, const auto& q) { return points_equal(p, q); }, p, q); +} + + bool points_equal(const Point& p, const Point& q, double eps) { ASSERT(p.index() == q.index()); return std::visit([&](const auto& p, const auto& q) { return points_equal(p, q, eps); }, p, q); diff --git a/src/eckit/geo/Point.h b/src/eckit/geo/Point.h index fcf75f20d..331eb5d4f 100644 --- a/src/eckit/geo/Point.h +++ b/src/eckit/geo/Point.h @@ -25,7 +25,8 @@ namespace eckit::geo { using Point = std::variant; -bool points_equal(const Point&, const Point&, double eps = 1.e-9); +bool points_equal(const Point&, const Point&); +bool points_equal(const Point&, const Point&, double eps); std::ostream& operator<<(std::ostream&, const Point&); From 2514dbd0d05268f35f98f8fbedfe72fe8207bcaa Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 18 Feb 2024 02:49:50 +0000 Subject: [PATCH 497/737] eckit::geo::Spec --- src/eckit/geo/Spec.cc | 10 ++++++++++ src/eckit/geo/Spec.h | 2 ++ src/eckit/geo/spec/Custom.h | 2 +- src/eckit/geo/spec/Layered.h | 4 ++-- tests/geo/spec.cc | 29 +++++++++++++++++++++++++++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/eckit/geo/Spec.cc b/src/eckit/geo/Spec.cc index 5c930b2f0..c78104b62 100644 --- a/src/eckit/geo/Spec.cc +++ b/src/eckit/geo/Spec.cc @@ -11,6 +11,8 @@ #include "eckit/geo/Spec.h" +#include + #include "eckit/log/JSON.h" @@ -109,6 +111,14 @@ std::vector Spec::get_long_vector(const std::string& name, const std::vect } +std::string Spec::str() const { + std::ostringstream str; + JSON j(str); + json(j); + return str.str(); +} + + void Spec::print(std::ostream& out) const { JSON j(out); json(j); diff --git a/src/eckit/geo/Spec.h b/src/eckit/geo/Spec.h index 9cb7849f8..d60a478b5 100644 --- a/src/eckit/geo/Spec.h +++ b/src/eckit/geo/Spec.h @@ -58,6 +58,8 @@ class Spec : public Parametrisation { std::string get_string(const std::string& name, const std::string&) const; std::vector get_long_vector(const std::string& name, const std::vector&) const; + std::string str() const; + private: virtual void print(std::ostream&) const; virtual void json(JSON&) const = 0; diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 01af7817c..df1d5320e 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -129,7 +129,7 @@ class Custom final : public Spec { // -- Overridden methods - void json(JSON&) const final; + void json(JSON&) const override; // -- Class members // None diff --git a/src/eckit/geo/spec/Layered.h b/src/eckit/geo/spec/Layered.h index e8806ed9e..a0d5cb80f 100644 --- a/src/eckit/geo/spec/Layered.h +++ b/src/eckit/geo/spec/Layered.h @@ -112,8 +112,8 @@ class Layered final : public Spec { // -- Overridden methods - void print(std::ostream&) const final; - void json(JSON&) const final; + void print(std::ostream&) const override; + void json(JSON&) const override; // -- Class members // None diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 12b84e41b..f135d5d4e 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -191,6 +191,35 @@ CASE("Spec <- Custom") { EXPECT(e.get("zero", maybe) && !maybe); EXPECT(e.get("one", maybe) && maybe); } + + + SECTION("json") { + std::unique_ptr spec( + new spec::Custom({{"string", "string"}, + {"bool", true}, + {"int", static_cast(1)}, + {"long", static_cast(2)}, + {"long long", static_cast(3)}, + {"size_t", static_cast(4)}, + {"float", static_cast(5)}, + {"double", static_cast(6)}, + {"vector", std::vector{1, 1}}, + {"vector", std::vector{2, 2}}, + {"vector", std::vector{3, 3}}, + {"vector", std::vector{4, 4}}, + {"vector", std::vector{5, 5}}, + {"vector", std::vector{6, 6}}, + {"vector", std::vector{"string", "string"}}})); + + // this also tests the order of the keys in the json output + const std::string str = spec->str(); + const std::string ref = + "{\"bool\":true,\"double\":6,\"float\":5,\"int\":1,\"long\":2,\"long " + "long\":3,\"size_t\":4,\"string\":\"string\",\"vector\":[6,6],\"vector\":[5,5],\"vector" + "\":[1,1],\"vector\":[3,3],\"vector\":[2,2],\"vector\":[4,4],\"vector\":[\"string\",\"string\"]}"; + EXPECT_EQUAL(str, ref); + } } From d570eb07abbd23269f5d6d3d2273f88b6b2bbd04 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 18 Feb 2024 10:17:15 +0000 Subject: [PATCH 498/737] eckit::geo::Spec --- tests/geo/spec.cc | 53 +++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index f135d5d4e..dfc39b98d 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -194,31 +194,34 @@ CASE("Spec <- Custom") { SECTION("json") { - std::unique_ptr spec( - new spec::Custom({{"string", "string"}, - {"bool", true}, - {"int", static_cast(1)}, - {"long", static_cast(2)}, - {"long long", static_cast(3)}, - {"size_t", static_cast(4)}, - {"float", static_cast(5)}, - {"double", static_cast(6)}, - {"vector", std::vector{1, 1}}, - {"vector", std::vector{2, 2}}, - {"vector", std::vector{3, 3}}, - {"vector", std::vector{4, 4}}, - {"vector", std::vector{5, 5}}, - {"vector", std::vector{6, 6}}, - {"vector", std::vector{"string", "string"}}})); - - // this also tests the order of the keys in the json output - const std::string str = spec->str(); - const std::string ref = - "{\"bool\":true,\"double\":6,\"float\":5,\"int\":1,\"long\":2,\"long " - "long\":3,\"size_t\":4,\"string\":\"string\",\"vector\":[6,6],\"vector\":[5,5],\"vector" - "\":[1,1],\"vector\":[3,3],\"vector\":[2,2],\"vector\":[4,4],\"vector\":[\"string\",\"string\"]}"; - EXPECT_EQUAL(str, ref); + // test ordering + std::unique_ptr a(new spec::Custom({{"c", "c"}, {"a", "a"}, {"b", 1}})); + + const std::string a_str = a->str(); + const std::string a_ref = R"({"a":"a","b":1,"c":"c"})"; + EXPECT_EQUAL(a_str, a_ref); + + // test types + std::unique_ptr b(new spec::Custom({{"string", "string"}, + {"bool", true}, + {"int", static_cast(1)}, + {"long", static_cast(2)}, + {"long long", static_cast(3)}, + {"size_t", static_cast(4)}, + {"float", static_cast(5)}, + {"double", static_cast(6)}, + {"vector", std::vector{1, 1}}, + {"vector", std::vector{2, 2}}, + {"vector", std::vector{3, 3}}, + {"vector", std::vector{4, 4}}, + {"vector", std::vector{5, 5}}, + {"vector", std::vector{6, 6}}, + {"vector", std::vector{"string", "string"}}})); + + const std::string b_str = b->str(); + const std::string b_ref = + R"({"bool":true,"double":6,"float":5,"int":1,"long":2,"long long":3,"size_t":4,"string":"string","vector":[6,6],"vector":[5,5],"vector":[1,1],"vector":[3,3],"vector":[2,2],"vector":[4,4],"vector":["string","string"]})"; + EXPECT_EQUAL(b_str, b_ref); } } From bea1520ec3af597025c3b541ff9e18ff6639abc9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 19 Feb 2024 08:31:59 +0000 Subject: [PATCH 499/737] eckit::geo::Spec --- src/tools/CMakeLists.txt | 6 +++ src/tools/eckit-grid-spec.cc | 79 ++++++++++++++++++++++++++++++++++++ tests/geo/spec.cc | 2 +- 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/tools/eckit-grid-spec.cc diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 27c2bef4e..804d10f96 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -30,6 +30,12 @@ ecbuild_add_executable( TARGET eckit_grid_list SOURCES eckit-grid-list.cc LIBS eckit_geo eckit_option ) +ecbuild_add_executable( TARGET eckit_grid_spec + OUTPUT_NAME eckit-grid-spec + CONDITION eckit_HAVE_ECKIT_GEO + SOURCES eckit-grid-spec.cc + LIBS eckit_geo eckit_option ) + ### NOT TO INSTALL ecbuild_add_executable( TARGET dhcopy diff --git a/src/tools/eckit-grid-spec.cc b/src/tools/eckit-grid-spec.cc new file mode 100644 index 000000000..d30462a57 --- /dev/null +++ b/src/tools/eckit-grid-spec.cc @@ -0,0 +1,79 @@ +/* + * (C) Copyright 1996- 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 +#include +#include + +// #include "eckit/geo/Grid.h" +#include "eckit/log/Log.h" +#include "eckit/option/CmdArgs.h" +#include "eckit/option/EckitTool.h" +#include "eckit/option/SimpleOption.h" +#include "eckit/option/VectorOption.h" +#include "eckit/parser/YAMLParser.h" + + +namespace eckit { + +class EckitGrid final : public EckitTool { +public: + EckitGrid(int argc, char** argv) : + EckitTool(argc, argv) { + options_.push_back(new option::SimpleOption("grid", "")); + options_.push_back(new option::VectorOption("area", "", 4)); + } + +private: + void execute(const option::CmdArgs& args) override { + std::string user; + + if (args.count() == 0) { + std::ostringstream out; + YAMLParser(std::cin).parse().dump(out); + + user = out.str(); + } + else { + std::stringstream in; + in << "{"; + in << "grid: " + args.getString("grid"); + if (args.has("area")) { + auto area = args.getDoubleVector("area"); + in << ", area: [" << area[0] << ", " << area[1] << ", " << area[2] << ", " << area[3] << "]"; + } + in << "}"; + + std::ostringstream out; + YAMLParser(in).parse().dump(out); + + user = out.str(); + } + + // std::unique_ptr grid(geo::GridFactory::build(user)) + } + + void usage(const std::string& tool) const override { + Log::info() << "\n" + "Usage: " + << tool << "[options] ..." << std::endl; + } + + int minimumPositionalArguments() const override { return 0; } +}; + +} // namespace eckit + + +int main(int argc, char** argv) { + eckit::EckitGrid app(argc, argv); + return app.start(); +} diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index dfc39b98d..364975051 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -10,7 +10,7 @@ */ -#include +#include #include #include From 9466ae6d5dcd12c5998d4430c4d30aad1bd7d391 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 19 Feb 2024 11:17:56 +0000 Subject: [PATCH 500/737] eckit::geo::Spec --- src/eckit/geo/CMakeLists.txt | 2 + src/eckit/geo/Grid.cc | 8 +++ src/eckit/geo/Grid.h | 3 + src/eckit/geo/spec/Valued.cc | 134 +++++++++++++++++++++++++++++++++++ src/eckit/geo/spec/Valued.h | 69 ++++++++++++++++++ src/tools/eckit-grid-spec.cc | 7 +- 6 files changed, 220 insertions(+), 3 deletions(-) create mode 100644 src/eckit/geo/spec/Valued.cc create mode 100644 src/eckit/geo/spec/Valued.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index c294d7bfe..956b967b5 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -119,6 +119,8 @@ list(APPEND eckit_geo_srcs spec/Generator.h spec/Layered.cc spec/Layered.h + spec/Valued.cc + spec/Valued.h util.cc util.h util/arange.cc diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 26f13102e..678c42b85 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -20,8 +20,10 @@ #include "eckit/geo/etc/Grid.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/spec/Layered.h" +#include "eckit/geo/spec/Valued.h" #include "eckit/geo/util/mutex.h" #include "eckit/log/Log.h" +#include "eckit/parser/YAMLParser.h" namespace eckit::geo { @@ -118,6 +120,12 @@ Renumber Grid::no_reorder(size_t size) { } +const Grid* GridFactory::make_from_string(const std::string& str) { + std::unique_ptr spec(new spec::Valued(YAMLParser::decodeString(str))); + return instance().build_(*spec); +} + + GridFactory& GridFactory::instance() { static GridFactory obj; return obj; diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 206d9c6ed..7c76e3825 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -198,6 +198,9 @@ struct GridFactory { // This is 'const' as Grid should always be immutable static const Grid* build(const Spec& spec) { return instance().build_(spec); } + // This is 'const' as Grid should always be immutable + static const Grid* make_from_string(const std::string&); + static Spec* spec(const Spec& spec) { return instance().generate_spec_(spec); } static void list(std::ostream& out) { return instance().list_(out); } diff --git a/src/eckit/geo/spec/Valued.cc b/src/eckit/geo/spec/Valued.cc new file mode 100644 index 000000000..2fe2ccee9 --- /dev/null +++ b/src/eckit/geo/spec/Valued.cc @@ -0,0 +1,134 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/spec/Valued.h" + +#include "eckit/log/JSON.h" + + +namespace eckit::geo::spec { + + +namespace { + + +template +bool __get_a(const ValueMap& map, const std::string& name, As& value) { + if (auto it = map.find(name); it != map.end()) { + value = it->second.as(); + return true; + } + + return false; +} + + +// FIXME there are conversion issues with the above (?) so we use this for now +template +bool __get_b(const ValueMap& map, const std::string& name, As& value) { + return false; +} + + +} // namespace + + +bool Valued::has(const std::string& name) const { + return map_.find(name) != map_.end(); +} + + +bool Valued::get(const std::string& name, std::string& value) const { + return __get_a(map_, name, value); +} + + +bool Valued::get(const std::string& name, bool& value) const { + return __get_a(map_, name, value); +} + + +bool Valued::get(const std::string& name, int& value) const { + return __get_b(map_, name, value); +} + + +bool Valued::get(const std::string& name, long& value) const { + return __get_b(map_, name, value); +} + + +bool Valued::get(const std::string& name, long long& value) const { + return __get_a(map_, name, value); +} + + +bool Valued::get(const std::string& name, std::size_t& value) const { + return __get_b(map_, name, value); +} + + +bool Valued::get(const std::string& name, float& value) const { + return __get_b(map_, name, value); +} + + +bool Valued::get(const std::string& name, double& value) const { + return __get_a(map_, name, value); +} + + +bool Valued::get(const std::string& name, std::vector& value) const { + return __get_b(map_, name, value); +} + + +bool Valued::get(const std::string& name, std::vector& value) const { + return __get_b(map_, name, value); +} + + +bool Valued::get(const std::string& name, std::vector& value) const { + return __get_b(map_, name, value); +} + + +bool Valued::get(const std::string& name, std::vector& value) const { + return __get_b(map_, name, value); +} + + +bool Valued::get(const std::string& name, std::vector& value) const { + return __get_b(map_, name, value); +} + + +bool Valued::get(const std::string& name, std::vector& value) const { + return __get_b(map_, name, value); +} + + +bool Valued::get(const std::string& name, std::vector& value) const { + return __get_b(map_, name, value); +} + + +void Valued::json(JSON& j) const { + j.startObject(); + for (auto& [key, value] : map_) { + j << key; + j << value; + } + j.endObject(); +} + + +} // namespace eckit::geo::spec diff --git a/src/eckit/geo/spec/Valued.h b/src/eckit/geo/spec/Valued.h new file mode 100644 index 000000000..4d4da2019 --- /dev/null +++ b/src/eckit/geo/spec/Valued.h @@ -0,0 +1,69 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Spec.h" +#include "eckit/value/Content.h" // for ValueMap +#include "eckit/value/Value.h" + + +namespace eckit { +class JSON; +} + + +namespace eckit::geo::spec { + + +class Valued final : public Spec { +public: + explicit Valued(const Value& value) : + map_(value) {} + + explicit Valued(Value&& value) : + map_(value) {} + + Valued& operator=(const Value& value) { + map_ = value; + return *this; + } + Valued& operator=(Value&& value) { + map_ = value; + return *this; + } + + bool has(const std::string& name) const override; + + bool get(const std::string& name, std::string& value) const override; + bool get(const std::string& name, bool& value) const override; + bool get(const std::string& name, int& value) const override; + bool get(const std::string& name, long& value) const override; + bool get(const std::string& name, long long& value) const override; + bool get(const std::string& name, std::size_t& value) const override; + bool get(const std::string& name, float& value) const override; + bool get(const std::string& name, double& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; + +private: + ValueMap map_; + + void json(JSON& j) const override; +}; + + +} // namespace eckit::geo::spec diff --git a/src/tools/eckit-grid-spec.cc b/src/tools/eckit-grid-spec.cc index d30462a57..66876b978 100644 --- a/src/tools/eckit-grid-spec.cc +++ b/src/tools/eckit-grid-spec.cc @@ -9,11 +9,11 @@ */ -// #include +#include #include #include -// #include "eckit/geo/Grid.h" +#include "eckit/geo/Grid.h" #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" #include "eckit/option/EckitTool.h" @@ -58,7 +58,8 @@ class EckitGrid final : public EckitTool { user = out.str(); } - // std::unique_ptr grid(geo::GridFactory::build(user)) + std::unique_ptr grid(geo::GridFactory::make_from_string(user)); + Log::info() << grid->spec() << std::endl; } void usage(const std::string& tool) const override { From 7a00f1850bdebffc3892cb293e33a3c264c82321 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 19 Feb 2024 11:26:02 +0000 Subject: [PATCH 501/737] eckit::geo::Spec --- src/eckit/geo/spec/Custom.h | 9 --------- src/tools/eckit-grid-spec.cc | 22 +++------------------- tests/geo/CMakeLists.txt | 7 +++++++ 3 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index df1d5320e..4fc39a4e5 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -17,11 +17,6 @@ #include "eckit/geo/Spec.h" -namespace eckit { -class JSON; -} - - namespace eckit::geo::spec { @@ -58,10 +53,6 @@ class Custom final : public Spec { Custom(const Custom&); Custom(Custom&&); - // -- Destructor - - ~Custom() final = default; - // -- Convertors // None diff --git a/src/tools/eckit-grid-spec.cc b/src/tools/eckit-grid-spec.cc index 66876b978..9af85f1c5 100644 --- a/src/tools/eckit-grid-spec.cc +++ b/src/tools/eckit-grid-spec.cc @@ -17,8 +17,6 @@ #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" #include "eckit/option/EckitTool.h" -#include "eckit/option/SimpleOption.h" -#include "eckit/option/VectorOption.h" #include "eckit/parser/YAMLParser.h" @@ -27,10 +25,7 @@ namespace eckit { class EckitGrid final : public EckitTool { public: EckitGrid(int argc, char** argv) : - EckitTool(argc, argv) { - options_.push_back(new option::SimpleOption("grid", "")); - options_.push_back(new option::VectorOption("area", "", 4)); - } + EckitTool(argc, argv) {} private: void execute(const option::CmdArgs& args) override { @@ -39,23 +34,12 @@ class EckitGrid final : public EckitTool { if (args.count() == 0) { std::ostringstream out; YAMLParser(std::cin).parse().dump(out); - user = out.str(); } else { - std::stringstream in; - in << "{"; - in << "grid: " + args.getString("grid"); - if (args.has("area")) { - auto area = args.getDoubleVector("area"); - in << ", area: [" << area[0] << ", " << area[1] << ", " << area[2] << ", " << area[3] << "]"; + for (const auto& arg : args) { + user += " " + arg; } - in << "}"; - - std::ostringstream out; - YAMLParser(in).parse().dump(out); - - user = out.str(); } std::unique_ptr grid(geo::GridFactory::make_from_string(user)); diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index bf6b8c15f..f60053610 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -28,3 +28,10 @@ foreach(_test LIBS eckit_geo ) endforeach() +ecbuild_add_test( + TARGET eckit_test_geo_tool_grid_spec_1_1 + COMMAND eckit_grid_spec 1/1. ) + +#set_tests_properties(eckit_test_geo_tool_grid_spec_1_1 PROPERTIES +# PASS_REGULAR_EXPRESSION "GridSpec: 1/1") + From 054792fa6eb0e099ac7bf0a261acc8f57b02cfe7 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 19 Feb 2024 15:18:03 +0000 Subject: [PATCH 502/737] eckit::geo::Spec --- src/eckit/geo/spec/Valued.cc | 150 ++++++++++++++++++++++++++++++----- src/eckit/geo/spec/Valued.h | 7 +- 2 files changed, 129 insertions(+), 28 deletions(-) diff --git a/src/eckit/geo/spec/Valued.cc b/src/eckit/geo/spec/Valued.cc index 2fe2ccee9..964534f33 100644 --- a/src/eckit/geo/spec/Valued.cc +++ b/src/eckit/geo/spec/Valued.cc @@ -20,20 +20,98 @@ namespace eckit::geo::spec { namespace { -template -bool __get_a(const ValueMap& map, const std::string& name, As& value) { - if (auto it = map.find(name); it != map.end()) { - value = it->second.as(); +template +bool __get_s(const From& from, To& to) { + to = static_cast(from); + return true; +} + + +template +bool __get_s(const From& from, std::string& to) { + to = std::to_string(from); + return true; +} + + +template +bool __get_s(const From& from, From& to) { + to = from; + return true; +} + + +template +bool __get_v(const std::vector& from, std::vector& to) { + to.clear(); + for (const auto& f : from) { + to.emplace_back(static_cast(f)); + } + return true; +} + + +template +bool __get_v(const std::vector& from, std::vector& to) { + to = from; + return true; +} + + +template +bool __get_s_integral(const ValueMap& map, const std::string& name, T& value) { + if (auto it = map.find(name); it != map.cend() && it->second.isNumber()) { + value = static_cast(it->second); // (range constraint) + return true; + } + return false; +} + + +template +bool __get_s_real(const ValueMap& map, const std::string& name, T& value) { + if (__get_s_integral(map, name, value)) { + return true; + } + + if (auto it = map.find(name); it != map.cend() && it->second.isDouble()) { + value = static_cast(it->second); // (range constraint) return true; } + return false; +} + +template +bool __get_v_integral(const ValueMap& map, const std::string& name, T& value) { + if (auto it = map.find(name); it != map.cend() && it->second.isList()) { + if (ValueList l(it->second); !l.empty() && l.front().isNumber()) { + value.clear(); + for (const auto& v : l) { + value.emplace_back(static_cast(v)); + } + return true; + } + } return false; } -// FIXME there are conversion issues with the above (?) so we use this for now -template -bool __get_b(const ValueMap& map, const std::string& name, As& value) { +template +bool __get_v_real(const ValueMap& map, const std::string& name, T& value) { + if (__get_v_integral(map, name, value)) { + return true; + } + + if (auto it = map.find(name); it != map.cend() && it->second.isList()) { + if (ValueList l(it->second); !l.empty() && l.front().isDouble()) { + value.clear(); + for (const auto& v : l) { + value.emplace_back(static_cast(v)); + } + return true; + } + } return false; } @@ -47,77 +125,105 @@ bool Valued::has(const std::string& name) const { bool Valued::get(const std::string& name, std::string& value) const { - return __get_a(map_, name, value); + if (auto it = map_.find(name); it != map_.cend()) { + if (it->second.isString()) { + value = static_cast(it->second); + return true; + } + + return __get_s_real(map_, name, value); + } + return false; } bool Valued::get(const std::string& name, bool& value) const { - return __get_a(map_, name, value); + if (auto it = map_.find(name); it != map_.cend()) { + if (it->second.isBool()) { + value = it->second; + return true; + } + + if (int i = 0; __get_s_integral(map_, name, i)) { + value = i != 0; + return true; + } + } + return false; } bool Valued::get(const std::string& name, int& value) const { - return __get_b(map_, name, value); + return __get_s_integral(map_, name, value); } bool Valued::get(const std::string& name, long& value) const { - return __get_b(map_, name, value); + return __get_s_integral(map_, name, value); } bool Valued::get(const std::string& name, long long& value) const { - return __get_a(map_, name, value); + return __get_s_integral(map_, name, value); } bool Valued::get(const std::string& name, std::size_t& value) const { - return __get_b(map_, name, value); + return __get_s_integral(map_, name, value); } bool Valued::get(const std::string& name, float& value) const { - return __get_b(map_, name, value); + return __get_s_real(map_, name, value); } bool Valued::get(const std::string& name, double& value) const { - return __get_a(map_, name, value); + return __get_s_real(map_, name, value); } bool Valued::get(const std::string& name, std::vector& value) const { - return __get_b(map_, name, value); + return __get_v_integral(map_, name, value); } bool Valued::get(const std::string& name, std::vector& value) const { - return __get_b(map_, name, value); + return __get_v_integral(map_, name, value); } bool Valued::get(const std::string& name, std::vector& value) const { - return __get_b(map_, name, value); + return __get_v_integral(map_, name, value); } bool Valued::get(const std::string& name, std::vector& value) const { - return __get_b(map_, name, value); + return __get_v_integral(map_, name, value); } bool Valued::get(const std::string& name, std::vector& value) const { - return __get_b(map_, name, value); + return __get_v_real(map_, name, value); } bool Valued::get(const std::string& name, std::vector& value) const { - return __get_b(map_, name, value); + return __get_v_real(map_, name, value); } bool Valued::get(const std::string& name, std::vector& value) const { - return __get_b(map_, name, value); + if (auto it = map_.find(name); it != map_.cend() && it->second.isList()) { + if (ValueList l(it->second); !l.empty() && l.front().isString()) { + value.clear(); + for (const auto& v : l) { + value.emplace_back(v); + } + return true; + } + } + return false; } diff --git a/src/eckit/geo/spec/Valued.h b/src/eckit/geo/spec/Valued.h index 4d4da2019..3cc841675 100644 --- a/src/eckit/geo/spec/Valued.h +++ b/src/eckit/geo/spec/Valued.h @@ -12,15 +12,10 @@ #pragma once #include "eckit/geo/Spec.h" -#include "eckit/value/Content.h" // for ValueMap +#include "eckit/value/Content.h" // for ValueList, ValueMap #include "eckit/value/Value.h" -namespace eckit { -class JSON; -} - - namespace eckit::geo::spec { From 836426dc8ff61b7c54d50e33b4e59deb281946c9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 19 Feb 2024 15:18:08 +0000 Subject: [PATCH 503/737] eckit::geo::Grid --- src/eckit/geo/Grid.cc | 12 ++++++------ src/eckit/geo/grid/regular/RegularLL.cc | 11 +++-------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 678c42b85..5063bde97 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -156,22 +156,22 @@ Spec* GridFactory::generate_spec_(const Spec& spec) const { // hardcoded, interpreted options (contributing to gridspec) - auto* map = new spec::Custom; - ASSERT(map != nullptr); + auto* back = new spec::Custom; + ASSERT(back != nullptr); if (size_t N = 0; cfg->get("N", N)) { - map->set("grid", "O" + std::to_string(N)); + back->set("grid", "O" + std::to_string(N)); } if (cfg->has("pl")) { - map->set("type", "reduced_gg"); + back->set("type", "reduced_gg"); } if (std::vector grid; cfg->get("grid", grid) && grid.size() == 2) { - map->set("type", "regular_ll"); + back->set("type", "regular_ll"); } - cfg->push_back(map); + cfg->push_back(back); // configurable options diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index f7b1fbce4..d9606a230 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -174,7 +174,7 @@ const std::vector& RegularLL::latitudes() const { } -#define POSITIVE_REAL "[+]?([0-9]*[.])?[0-9]+([eE][-+][0-9]+)?" +#define POSITIVE_REAL "[+]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][-+][0-9]+)?" Spec* RegularLL::spec(const std::string& name) { @@ -182,16 +182,11 @@ Spec* RegularLL::spec(const std::string& name) { auto match = util::regex_match(pattern, name); ASSERT(match); - ASSERT(match.size() == 7); // because of sub-matches + ASSERT(match.size() == 9); // because of sub-matches auto d = Translator{}; - std::vector increments{d(match[1]), d(match[4])}; - auto ni = 1; // detail::RegularIterator(Fraction(0), Fraction(360), Fraction(increments[0]), Fraction(0), - // Fraction(360)).n(); - auto nj = 1; // detail::RegularIterator(Fraction(-90), Fraction(90), Fraction(increments[1]), Fraction(0)).n(); - - return new spec::Custom({{"type", "regular_ll"}, {"grid", increments}, {"ni", ni}, {"nj", nj}}); + return new spec::Custom({{"type", "regular_ll"}, {"grid", std::vector{d(match[1]), d(match[5])}}}); } From cd5b103ac21c4800e28ac3ee3aeca246d2050203 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 19 Feb 2024 16:50:03 +0000 Subject: [PATCH 504/737] eckit::geo::Grid --- src/eckit/geo/Grid.cc | 24 +++++++++++++++++++----- src/eckit/geo/Grid.h | 11 ++++++++--- src/eckit/geo/grid/regular/RegularLL.cc | 7 +++++++ src/eckit/geo/grid/regular/RegularLL.h | 2 ++ src/tools/eckit-grid-spec.cc | 21 +++++++++++++++++---- tests/geo/CMakeLists.txt | 7 ++++--- 6 files changed, 57 insertions(+), 15 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 5063bde97..f5540eb90 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -15,6 +15,7 @@ #include #include #include +#include #include "eckit/exception/Exceptions.h" #include "eckit/geo/etc/Grid.h" @@ -22,6 +23,7 @@ #include "eckit/geo/spec/Layered.h" #include "eckit/geo/spec/Valued.h" #include "eckit/geo/util/mutex.h" +#include "eckit/log/JSON.h" #include "eckit/log/Log.h" #include "eckit/parser/YAMLParser.h" @@ -45,6 +47,18 @@ Grid::Grid(const area::BoundingBox& bbox) : bbox_(bbox) {} +std::string Grid::spec() const { + std::ostringstream ss; + JSON j(ss); + + j.startObject(); + json(j); + j.endObject(); + + return ss.str(); +} + + const area::BoundingBox& Grid::boundingBox() const { throw NotImplemented("Grid::boundingBox", Here()); } @@ -93,11 +107,6 @@ std::pair, std::vector> Grid::to_latlon() const { } -std::string Grid::spec() const { - throw NotImplemented("Grid::spec"); -} - - Ordering Grid::order() const { throw NotImplemented("Grid::order"); } @@ -120,6 +129,11 @@ Renumber Grid::no_reorder(size_t size) { } +void Grid::json(JSON&) const { + throw NotImplemented("Grid::json"); +} + + const Grid* GridFactory::make_from_string(const std::string& str) { std::unique_ptr spec(new spec::Valued(YAMLParser::decodeString(str))); return instance().build_(*spec); diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 7c76e3825..b78d17d1a 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -30,9 +30,12 @@ #include "eckit/memory/Factory.h" -namespace eckit::geo { +namespace eckit { +class JSON; +namespace geo { class Spec; } +} // namespace eckit namespace eckit::geo { @@ -106,6 +109,8 @@ class Grid { iterator begin() const { return cbegin(); } iterator end() const { return cend(); } + std::string spec() const; + virtual iterator cbegin() const = 0; virtual iterator cend() const = 0; @@ -121,7 +126,6 @@ class Grid { virtual std::vector to_points() const; virtual std::pair, std::vector> to_latlon() const; - virtual std::string spec() const; virtual Ordering order() const; virtual Renumber reorder(Ordering) const; virtual Grid* grid_reorder(Ordering) const; @@ -163,7 +167,8 @@ class Grid { area::BoundingBox bbox_; // -- Methods - // None + + virtual void json(JSON&) const; // -- Overridden methods // None diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index d9606a230..ce9d06cb1 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -18,6 +18,7 @@ #include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util/regex.h" +#include "eckit/log/JSON.h" #include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" @@ -174,6 +175,12 @@ const std::vector& RegularLL::latitudes() const { } +void RegularLL::json(JSON& j) const { + j << "grid"; + j << std::vector{internal_.inc.west_east, internal_.inc.south_north}; +} + + #define POSITIVE_REAL "[+]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][-+][0-9]+)?" diff --git a/src/eckit/geo/grid/regular/RegularLL.h b/src/eckit/geo/grid/regular/RegularLL.h index a26794900..d7d923643 100644 --- a/src/eckit/geo/grid/regular/RegularLL.h +++ b/src/eckit/geo/grid/regular/RegularLL.h @@ -100,6 +100,8 @@ class RegularLL final : public Regular { const std::vector& longitudes() const override; const std::vector& latitudes() const override; + void json(JSON&) const override; + // -- Class members // None diff --git a/src/tools/eckit-grid-spec.cc b/src/tools/eckit-grid-spec.cc index 9af85f1c5..1d3edad0f 100644 --- a/src/tools/eckit-grid-spec.cc +++ b/src/tools/eckit-grid-spec.cc @@ -10,13 +10,16 @@ #include +#include #include #include +#include "eckit/exception/Exceptions.h" #include "eckit/geo/Grid.h" #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" #include "eckit/option/EckitTool.h" +#include "eckit/option/SimpleOption.h" #include "eckit/parser/YAMLParser.h" @@ -25,7 +28,9 @@ namespace eckit { class EckitGrid final : public EckitTool { public: EckitGrid(int argc, char** argv) : - EckitTool(argc, argv) {} + EckitTool(argc, argv) { + options_.push_back(new option::SimpleOption("check", "regex to check against result")); + } private: void execute(const option::CmdArgs& args) override { @@ -43,13 +48,21 @@ class EckitGrid final : public EckitTool { } std::unique_ptr grid(geo::GridFactory::make_from_string(user)); - Log::info() << grid->spec() << std::endl; + auto spec = grid->spec(); + Log::info() << spec << std::endl; + + if (std::string check; args.get("check", check)) { + std::regex regex(check); + ASSERT_MSG(std::regex_match(spec, regex), "Check failed: '" + check + "'"); + } } void usage(const std::string& tool) const override { Log::info() << "\n" - "Usage: " - << tool << "[options] ..." << std::endl; + "Usage: \n" + << tool << " \n" + << "echo | " << tool << "\n" + << "Note: ':' should be followed by a space/' '" << std::endl; } int minimumPositionalArguments() const override { return 0; } diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index f60053610..018b82a14 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -30,8 +30,9 @@ endforeach() ecbuild_add_test( TARGET eckit_test_geo_tool_grid_spec_1_1 - COMMAND eckit_grid_spec 1/1. ) + COMMAND eckit_grid_spec ARGS "grid: 1/1.0" [=[--check=[{]"grid":\[1,1\][}]]=] ) -#set_tests_properties(eckit_test_geo_tool_grid_spec_1_1 PROPERTIES -# PASS_REGULAR_EXPRESSION "GridSpec: 1/1") +ecbuild_add_test( + TARGET eckit_test_geo_tool_grid_spec_025_01 + COMMAND eckit_grid_spec ARGS "grid: .250/001e-1" [=[--check=[{]"grid":\[0\.25,0\.1\][}]]=] ) From 68394fb3f5effa02d596a342810338cbf4b0c8bf Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 19 Feb 2024 23:10:59 +0000 Subject: [PATCH 505/737] eckit::geo::Grid --- src/tools/eckit-grid-spec.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tools/eckit-grid-spec.cc b/src/tools/eckit-grid-spec.cc index 1d3edad0f..bf0249fc9 100644 --- a/src/tools/eckit-grid-spec.cc +++ b/src/tools/eckit-grid-spec.cc @@ -61,8 +61,7 @@ class EckitGrid final : public EckitTool { Log::info() << "\n" "Usage: \n" << tool << " \n" - << "echo | " << tool << "\n" - << "Note: ':' should be followed by a space/' '" << std::endl; + << "echo | " << tool << std::endl; } int minimumPositionalArguments() const override { return 0; } From c23b507cff5a263a86cce700f55038444ca61aed Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 20 Feb 2024 00:12:01 +0000 Subject: [PATCH 506/737] eckit::geo::Grid --- src/eckit/geo/CMakeLists.txt | 2 - src/eckit/geo/Grid.cc | 3 +- src/eckit/geo/spec/Custom.cc | 27 ++++ src/eckit/geo/spec/Custom.h | 7 + src/eckit/geo/spec/Valued.cc | 240 ----------------------------------- src/eckit/geo/spec/Valued.h | 64 ---------- 6 files changed, 35 insertions(+), 308 deletions(-) delete mode 100644 src/eckit/geo/spec/Valued.cc delete mode 100644 src/eckit/geo/spec/Valued.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 956b967b5..c294d7bfe 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -119,8 +119,6 @@ list(APPEND eckit_geo_srcs spec/Generator.h spec/Layered.cc spec/Layered.h - spec/Valued.cc - spec/Valued.h util.cc util.h util/arange.cc diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index f5540eb90..0d6e2175c 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -21,7 +21,6 @@ #include "eckit/geo/etc/Grid.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/spec/Layered.h" -#include "eckit/geo/spec/Valued.h" #include "eckit/geo/util/mutex.h" #include "eckit/log/JSON.h" #include "eckit/log/Log.h" @@ -135,7 +134,7 @@ void Grid::json(JSON&) const { const Grid* GridFactory::make_from_string(const std::string& str) { - std::unique_ptr spec(new spec::Valued(YAMLParser::decodeString(str))); + std::unique_ptr spec(new spec::Custom(YAMLParser::decodeString(str))); return instance().build_(*spec); } diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 4ddb31c7d..76771ad45 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -11,7 +11,10 @@ #include "eckit/geo/spec/Custom.h" +#include "eckit/exception/Exceptions.h" #include "eckit/log/JSON.h" +#include "eckit/value/Content.h" // for ValueList, ValueMap +#include "eckit/value/Value.h" namespace eckit::geo::spec { @@ -136,6 +139,30 @@ Custom::Custom(Custom::container_type&& map) : map_(map) {} +Custom::Custom(const Value& value) { + auto scalar = [](const Value& value) -> value_type { + return value.isNumber() ? value_type(static_cast(value)) + : value.isDouble() ? value_type(static_cast(value)) + : value.isString() ? static_cast(value) + : throw BadValue(value); + }; + + auto vector = [](const Value& value) -> value_type { + const ValueList list(value); + ASSERT(!list.empty()); + return list.front().isNumber() ? value_type(std::vector(list.begin(), list.end())) + : list.front().isDouble() ? value_type(std::vector(list.begin(), list.end())) + : list.front().isString() ? std::vector(list.begin(), list.end()) + : throw BadValue(value); + }; + + ASSERT(value.isMap()); + for (const auto& [key, value] : static_cast(value)) { + map_[key] = value.isList() ? vector(value) : scalar(value); + } +} + + Custom::Custom(const Custom& custom) : Custom(custom.map_) {} diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 4fc39a4e5..54144b017 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -17,6 +17,11 @@ #include "eckit/geo/Spec.h" +namespace eckit { +class Value; +} + + namespace eckit::geo::spec { @@ -50,6 +55,8 @@ class Custom final : public Spec { explicit Custom(const container_type& = {}); explicit Custom(container_type&&); + explicit Custom(const Value&); + Custom(const Custom&); Custom(Custom&&); diff --git a/src/eckit/geo/spec/Valued.cc b/src/eckit/geo/spec/Valued.cc deleted file mode 100644 index 964534f33..000000000 --- a/src/eckit/geo/spec/Valued.cc +++ /dev/null @@ -1,240 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/spec/Valued.h" - -#include "eckit/log/JSON.h" - - -namespace eckit::geo::spec { - - -namespace { - - -template -bool __get_s(const From& from, To& to) { - to = static_cast(from); - return true; -} - - -template -bool __get_s(const From& from, std::string& to) { - to = std::to_string(from); - return true; -} - - -template -bool __get_s(const From& from, From& to) { - to = from; - return true; -} - - -template -bool __get_v(const std::vector& from, std::vector& to) { - to.clear(); - for (const auto& f : from) { - to.emplace_back(static_cast(f)); - } - return true; -} - - -template -bool __get_v(const std::vector& from, std::vector& to) { - to = from; - return true; -} - - -template -bool __get_s_integral(const ValueMap& map, const std::string& name, T& value) { - if (auto it = map.find(name); it != map.cend() && it->second.isNumber()) { - value = static_cast(it->second); // (range constraint) - return true; - } - return false; -} - - -template -bool __get_s_real(const ValueMap& map, const std::string& name, T& value) { - if (__get_s_integral(map, name, value)) { - return true; - } - - if (auto it = map.find(name); it != map.cend() && it->second.isDouble()) { - value = static_cast(it->second); // (range constraint) - return true; - } - return false; -} - - -template -bool __get_v_integral(const ValueMap& map, const std::string& name, T& value) { - if (auto it = map.find(name); it != map.cend() && it->second.isList()) { - if (ValueList l(it->second); !l.empty() && l.front().isNumber()) { - value.clear(); - for (const auto& v : l) { - value.emplace_back(static_cast(v)); - } - return true; - } - } - return false; -} - - -template -bool __get_v_real(const ValueMap& map, const std::string& name, T& value) { - if (__get_v_integral(map, name, value)) { - return true; - } - - if (auto it = map.find(name); it != map.cend() && it->second.isList()) { - if (ValueList l(it->second); !l.empty() && l.front().isDouble()) { - value.clear(); - for (const auto& v : l) { - value.emplace_back(static_cast(v)); - } - return true; - } - } - return false; -} - - -} // namespace - - -bool Valued::has(const std::string& name) const { - return map_.find(name) != map_.end(); -} - - -bool Valued::get(const std::string& name, std::string& value) const { - if (auto it = map_.find(name); it != map_.cend()) { - if (it->second.isString()) { - value = static_cast(it->second); - return true; - } - - return __get_s_real(map_, name, value); - } - return false; -} - - -bool Valued::get(const std::string& name, bool& value) const { - if (auto it = map_.find(name); it != map_.cend()) { - if (it->second.isBool()) { - value = it->second; - return true; - } - - if (int i = 0; __get_s_integral(map_, name, i)) { - value = i != 0; - return true; - } - } - return false; -} - - -bool Valued::get(const std::string& name, int& value) const { - return __get_s_integral(map_, name, value); -} - - -bool Valued::get(const std::string& name, long& value) const { - return __get_s_integral(map_, name, value); -} - - -bool Valued::get(const std::string& name, long long& value) const { - return __get_s_integral(map_, name, value); -} - - -bool Valued::get(const std::string& name, std::size_t& value) const { - return __get_s_integral(map_, name, value); -} - - -bool Valued::get(const std::string& name, float& value) const { - return __get_s_real(map_, name, value); -} - - -bool Valued::get(const std::string& name, double& value) const { - return __get_s_real(map_, name, value); -} - - -bool Valued::get(const std::string& name, std::vector& value) const { - return __get_v_integral(map_, name, value); -} - - -bool Valued::get(const std::string& name, std::vector& value) const { - return __get_v_integral(map_, name, value); -} - - -bool Valued::get(const std::string& name, std::vector& value) const { - return __get_v_integral(map_, name, value); -} - - -bool Valued::get(const std::string& name, std::vector& value) const { - return __get_v_integral(map_, name, value); -} - - -bool Valued::get(const std::string& name, std::vector& value) const { - return __get_v_real(map_, name, value); -} - - -bool Valued::get(const std::string& name, std::vector& value) const { - return __get_v_real(map_, name, value); -} - - -bool Valued::get(const std::string& name, std::vector& value) const { - if (auto it = map_.find(name); it != map_.cend() && it->second.isList()) { - if (ValueList l(it->second); !l.empty() && l.front().isString()) { - value.clear(); - for (const auto& v : l) { - value.emplace_back(v); - } - return true; - } - } - return false; -} - - -void Valued::json(JSON& j) const { - j.startObject(); - for (auto& [key, value] : map_) { - j << key; - j << value; - } - j.endObject(); -} - - -} // namespace eckit::geo::spec diff --git a/src/eckit/geo/spec/Valued.h b/src/eckit/geo/spec/Valued.h deleted file mode 100644 index 3cc841675..000000000 --- a/src/eckit/geo/spec/Valued.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Spec.h" -#include "eckit/value/Content.h" // for ValueList, ValueMap -#include "eckit/value/Value.h" - - -namespace eckit::geo::spec { - - -class Valued final : public Spec { -public: - explicit Valued(const Value& value) : - map_(value) {} - - explicit Valued(Value&& value) : - map_(value) {} - - Valued& operator=(const Value& value) { - map_ = value; - return *this; - } - Valued& operator=(Value&& value) { - map_ = value; - return *this; - } - - bool has(const std::string& name) const override; - - bool get(const std::string& name, std::string& value) const override; - bool get(const std::string& name, bool& value) const override; - bool get(const std::string& name, int& value) const override; - bool get(const std::string& name, long& value) const override; - bool get(const std::string& name, long long& value) const override; - bool get(const std::string& name, std::size_t& value) const override; - bool get(const std::string& name, float& value) const override; - bool get(const std::string& name, double& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - -private: - ValueMap map_; - - void json(JSON& j) const override; -}; - - -} // namespace eckit::geo::spec From 53c175228150ff47fee10967616473e8ec964080 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 20 Feb 2024 00:41:36 +0000 Subject: [PATCH 507/737] eckit::geo::Grid --- tests/geo/grid.cc | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index 5803a6d38..c7a6e1897 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -14,6 +14,7 @@ #include "eckit/geo/Cache.h" #include "eckit/geo/Grid.h" +#include "eckit/geo/LibEcKitGeo.h" #include "eckit/geo/grid/reduced/ReducedGaussian.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" @@ -108,26 +109,28 @@ CASE("GridFactory::build") { } - SECTION("Grid::build_from_uid") { - spec::Custom spec({ - {"uid", "a832a12030c73928133553ec3a8d2a7e"}, - }); + if (LibEcKitGeo::caching()) { + SECTION("Grid::build_from_uid") { + spec::Custom spec({ + {"uid", "a832a12030c73928133553ec3a8d2a7e"}, + }); - const auto footprint = Cache::total_footprint(); + const auto footprint = Cache::total_footprint(); - std::unique_ptr a(GridFactory::build(spec)); + std::unique_ptr a(GridFactory::build(spec)); - const auto footprint_a = Cache::total_footprint(); - EXPECT(footprint < footprint_a); + const auto footprint_a = Cache::total_footprint(); + EXPECT(footprint < footprint_a); - std::unique_ptr b(GridFactory::build(spec)); + std::unique_ptr b(GridFactory::build(spec)); - const auto footprint_b = Cache::total_footprint(); - EXPECT_EQUAL(footprint_a, footprint_b); + const auto footprint_b = Cache::total_footprint(); + EXPECT_EQUAL(footprint_a, footprint_b); - const auto size_a = a->size(); - const auto size_b = b->size(); - EXPECT_EQUAL(size_a, size_b); + const auto size_a = a->size(); + const auto size_b = b->size(); + EXPECT_EQUAL(size_a, size_b); + } } From 9a36b4a338d3d9da53e85c2bb9f6cd31a790cdd4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 20 Feb 2024 17:33:53 +0000 Subject: [PATCH 508/737] eckit::geo::Grid --- src/eckit/geo/Grid.h | 3 ++- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 13 +++++++++++-- src/eckit/geo/grid/reduced/ReducedGaussian.h | 3 +++ tests/geo/grid.cc | 10 ++++++++++ 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index b78d17d1a..001d8ffd4 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -180,7 +180,8 @@ class Grid { // None // -- Friends - // None + + friend bool operator==(const Grid& a, const Grid& b) { return a.spec() == b.spec(); } }; diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 879f44717..0d3655b42 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -19,6 +19,8 @@ #include "eckit/geo/range/GaussianLatitude.h" #include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" +#include "eckit/geo/util.h" +#include "eckit/log/JSON.h" #include "eckit/utils/Translator.h" @@ -37,10 +39,11 @@ ReducedGaussian::ReducedGaussian(const Spec& spec) : ReducedGaussian::ReducedGaussian(const pl_type& pl, const area::BoundingBox& bbox) : Reduced(bbox), + N_(N(pl)), pl_(pl), j_(0), - Nj_(N(pl) * 2), - y_(range::GaussianLatitude(N(pl), false).crop(bbox.north, bbox.south)) { + Nj_(N_ * 2), + y_(range::GaussianLatitude(N_, false).crop(bbox.north, bbox.south)) { ASSERT(Nj_ == pl_.size()); ASSERT(y_); } @@ -87,6 +90,12 @@ std::vector ReducedGaussian::longitudes(size_t j) const { } +void ReducedGaussian::json(JSON& j) const { + j << "grid"; + j << (pl_ == util::reduced_octahedral_pl(N_) ? "O" : "N") + std::to_string(N_); +} + + struct ReducedGaussianClassical { static Spec* spec(const std::string& name) { auto N = Translator{}(name.substr(1)); diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.h b/src/eckit/geo/grid/reduced/ReducedGaussian.h index 60305a05d..bd8bb6479 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.h @@ -69,6 +69,7 @@ class ReducedGaussian : public Reduced { private: // -- Members + const size_t N_; const pl_type pl_; size_t j_; size_t Nj_; @@ -84,6 +85,8 @@ class ReducedGaussian : public Reduced { const std::vector& latitudes() const override; std::vector longitudes(size_t j) const override; + void json(JSON& j) const override; + // -- Class members // None diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index c7a6e1897..a9505a6d8 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -106,6 +106,16 @@ CASE("GridFactory::build") { // EXPECT_EQUAL(n2, n1 / 2); } + + { + std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "o2"}}))); + std::unique_ptr grid2(GridFactory::make_from_string("N: 2")); + std::unique_ptr grid3(new grid::reduced::ReducedGaussian(pl_type{20, 24, 24, 20})); + + EXPECT(*grid1 == *grid2); + EXPECT(*grid2 == *grid3); + EXPECT(*grid3 == *grid1); + } } From 74f8963a7102799478081a17847030675a52a13a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 21 Feb 2024 12:56:44 +0000 Subject: [PATCH 509/737] eckit::geo::Grid --- src/eckit/geo/Grid.cc | 17 +++----- src/eckit/geo/Grid.h | 5 ++- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 7 ++-- src/eckit/geo/grid/reduced/ReducedGaussian.h | 2 +- src/eckit/geo/grid/regular/RegularGaussian.cc | 9 ++++- src/eckit/geo/grid/regular/RegularGaussian.h | 4 ++ src/eckit/geo/grid/regular/RegularLL.cc | 39 ++++++------------- src/eckit/geo/grid/regular/RegularLL.h | 21 +++++----- src/eckit/geo/range/Regular.cc | 4 +- 9 files changed, 49 insertions(+), 59 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 0d6e2175c..7320f476e 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -15,14 +15,12 @@ #include #include #include -#include #include "eckit/exception/Exceptions.h" #include "eckit/geo/etc/Grid.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/spec/Layered.h" #include "eckit/geo/util/mutex.h" -#include "eckit/log/JSON.h" #include "eckit/log/Log.h" #include "eckit/parser/YAMLParser.h" @@ -47,14 +45,9 @@ Grid::Grid(const area::BoundingBox& bbox) : std::string Grid::spec() const { - std::ostringstream ss; - JSON j(ss); - - j.startObject(); - json(j); - j.endObject(); - - return ss.str(); + spec::Custom gridspec; + this->spec(gridspec); + return gridspec.str(); } @@ -128,8 +121,8 @@ Renumber Grid::no_reorder(size_t size) { } -void Grid::json(JSON&) const { - throw NotImplemented("Grid::json"); +void Grid::spec(spec::Custom&) const { + throw NotImplemented("Grid::spec"); } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 001d8ffd4..81a5f251e 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -34,7 +34,10 @@ namespace eckit { class JSON; namespace geo { class Spec; +namespace spec { +class Custom; } +} // namespace geo } // namespace eckit @@ -168,7 +171,7 @@ class Grid { // -- Methods - virtual void json(JSON&) const; + virtual void spec(spec::Custom&) const; // -- Overridden methods // None diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 0d3655b42..7018cc322 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -20,7 +20,6 @@ #include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" -#include "eckit/log/JSON.h" #include "eckit/utils/Translator.h" @@ -90,9 +89,9 @@ std::vector ReducedGaussian::longitudes(size_t j) const { } -void ReducedGaussian::json(JSON& j) const { - j << "grid"; - j << (pl_ == util::reduced_octahedral_pl(N_) ? "O" : "N") + std::to_string(N_); +void ReducedGaussian::spec(spec::Custom& custom) const { + ASSERT(!custom.has("grid")); + custom.set("grid", (pl_ == util::reduced_octahedral_pl(N_) ? "O" : "N") + std::to_string(N_)); } diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.h b/src/eckit/geo/grid/reduced/ReducedGaussian.h index bd8bb6479..708de43bf 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.h @@ -85,7 +85,7 @@ class ReducedGaussian : public Reduced { const std::vector& latitudes() const override; std::vector longitudes(size_t j) const override; - void json(JSON& j) const override; + void spec(spec::Custom&) const override; // -- Class members // None diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index beadb0203..379db5efa 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -28,6 +28,7 @@ RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : Regular(bbox), + N_(N), x_(range::RegularLongitude(4 * N, 0., 360.).crop(bbox.west, bbox.east)), y_(range::GaussianLatitude(N, false).crop(bbox.north, bbox.south)) { ASSERT(x_->size() > 0); @@ -47,7 +48,7 @@ Grid::iterator RegularGaussian::cend() const { Spec* RegularGaussian::spec(const std::string& name) { auto N = Translator{}(name.substr(1)); - return new spec::Custom({{"type", "regular_gg"}, {"N", N}, {"ni", 4 * N}}); + return new spec::Custom({{"type", "regular_gg"}, {"N", N}}); } @@ -61,6 +62,12 @@ const std::vector& RegularGaussian::latitudes() const { } +void RegularGaussian::spec(spec::Custom& custom) const { + ASSERT(!custom.has("grid")); + custom.set("grid", "F" + std::to_string(N_)); +} + + static const GridRegisterType __grid_type("regular_gg"); static const GridRegisterName __grid_pattern("[fF][1-9][0-9]*"); diff --git a/src/eckit/geo/grid/regular/RegularGaussian.h b/src/eckit/geo/grid/regular/RegularGaussian.h index f651f5184..69eaaffb3 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.h +++ b/src/eckit/geo/grid/regular/RegularGaussian.h @@ -62,6 +62,8 @@ class RegularGaussian final : public Regular { private: // -- Members + const size_t N_; + std::unique_ptr x_; std::unique_ptr y_; @@ -73,6 +75,8 @@ class RegularGaussian final : public Regular { const std::vector& longitudes() const override; const std::vector& latitudes() const override; + void spec(spec::Custom&) const override; + // -- Class members // None diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index ce9d06cb1..d45ebe846 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -15,10 +15,8 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Increments.h" #include "eckit/geo/iterator/Regular.h" -#include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util/regex.h" -#include "eckit/log/JSON.h" #include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" @@ -104,7 +102,7 @@ struct DiscreteRange { }; -PointLonLat make_reference_from_spec(const Spec& spec) { +PointLonLat reference_from_spec(const Spec& spec) { if (double lon = 0, lat = 0; spec.get("reference_lon", lon) && spec.get("reference_lat", lat)) { return {lon, lat}; } @@ -118,8 +116,7 @@ PointLonLat make_reference_from_spec(const Spec& spec) { RegularLL::Internal::Internal(const Increments& _inc, const area::BoundingBox& _bbox, const PointLonLat& _ref) : - inc(_inc), bbox(_bbox), first(_ref) { - + inc(_inc), bbox(_bbox) { const DiscreteRange lon(bbox.west, bbox.east, inc.west_east, _ref.lon, 360); const DiscreteRange lat(bbox.south, bbox.north, inc.south_north, _ref.lat); @@ -133,7 +130,7 @@ RegularLL::Internal::Internal(const Increments& _inc, const area::BoundingBox& _ RegularLL::RegularLL(const Spec& spec) : - RegularLL(Increments{spec}, area::BoundingBox{spec}, make_reference_from_spec(spec)) {} + RegularLL(Increments{spec}, area::BoundingBox{spec}, reference_from_spec(spec)) {} RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : @@ -146,12 +143,9 @@ RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const RegularLL::RegularLL(Internal&& internal) : Regular(internal.bbox), - internal_(internal), - range_longitude_(new range::RegularLongitude(internal_.ni, internal_.bbox.east, internal_.bbox.west)), - range_latitude_(new range::RegularLongitude(internal_.nj, internal_.bbox.north, internal_.bbox.south)) { + lon_(internal.ni, internal.bbox.west, internal.bbox.east), + lat_(internal.nj, internal.bbox.north, internal.bbox.south) { ASSERT(size() > 0); - ASSERT(ni() == range_longitude_->size()); - ASSERT(nj() == range_latitude_->size()); } @@ -165,29 +159,20 @@ Grid::iterator RegularLL::cend() const { } -const std::vector& RegularLL::longitudes() const { - return range_longitude_->values(); -} - - -const std::vector& RegularLL::latitudes() const { - return range_latitude_->values(); -} - - -void RegularLL::json(JSON& j) const { - j << "grid"; - j << std::vector{internal_.inc.west_east, internal_.inc.south_north}; +void RegularLL::spec(spec::Custom& custom) const { + ASSERT(!custom.has("grid")); + custom.set("grid", std::vector{lon_.increment(), lat_.increment()}); } #define POSITIVE_REAL "[+]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][-+][0-9]+)?" +static const std::string __pattern("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); +#undef POSITIVE_REAL Spec* RegularLL::spec(const std::string& name) { - static const std::string pattern("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); - auto match = util::regex_match(pattern, name); + auto match = util::regex_match(__pattern, name); ASSERT(match); ASSERT(match.size() == 9); // because of sub-matches @@ -198,7 +183,7 @@ Spec* RegularLL::spec(const std::string& name) { static const GridRegisterType __grid_type("regular_ll"); -static const GridRegisterName __grid_pattern(POSITIVE_REAL "/" POSITIVE_REAL); +static const GridRegisterName __grid_pattern(__pattern); } // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/grid/regular/RegularLL.h b/src/eckit/geo/grid/regular/RegularLL.h index d7d923643..f43dacf81 100644 --- a/src/eckit/geo/grid/regular/RegularLL.h +++ b/src/eckit/geo/grid/regular/RegularLL.h @@ -12,14 +12,13 @@ #pragma once -#include - #include "eckit/geo/grid/Regular.h" +#include "eckit/geo/range/RegularLatitude.h" +#include "eckit/geo/range/RegularLongitude.h" namespace eckit::geo { class Increments; -class Range; } // namespace eckit::geo @@ -35,7 +34,6 @@ class RegularLL final : public Regular { Increments inc; area::BoundingBox bbox; - PointLonLat first; size_t ni = 0; size_t nj = 0; @@ -75,8 +73,8 @@ class RegularLL final : public Regular { iterator cbegin() const override; iterator cend() const override; - size_t ni() const override { return internal_.ni; } - size_t nj() const override { return internal_.nj; } + size_t ni() const override { return lat_.size(); } + size_t nj() const override { return lon_.size(); } // -- Class members // None @@ -88,19 +86,18 @@ class RegularLL final : public Regular { private: // -- Members - const Internal internal_; - const std::unique_ptr range_longitude_; - const std::unique_ptr range_latitude_; + const range::RegularLongitude lon_; + const range::RegularLatitude lat_; // -- Methods // None // -- Overridden methods - const std::vector& longitudes() const override; - const std::vector& latitudes() const override; + const std::vector& longitudes() const override { return lon_.values(); } + const std::vector& latitudes() const override { return lat_.values(); } - void json(JSON&) const override; + void spec(spec::Custom&) const override; // -- Class members // None diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc index f92ed8bc7..870d81091 100644 --- a/src/eckit/geo/range/Regular.cc +++ b/src/eckit/geo/range/Regular.cc @@ -12,6 +12,8 @@ #include "eckit/geo/range/Regular.h" +#include + #include "eckit/exception/Exceptions.h" #include "eckit/geo/util.h" #include "eckit/geo/util/mutex.h" @@ -26,7 +28,7 @@ static util::recursive_mutex MUTEX; Fraction Regular::increment() const { ASSERT(1 < size()); - return Fraction((b() - a()) / static_cast(periodic() ? size() : (size() - 1))); + return Fraction(std::abs(b() - a()) / static_cast(periodic() ? size() : (size() - 1))); } const std::vector& Regular::values() const { From f5af2b53222ae21e2cc00f74991a92ebee98626b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 21 Feb 2024 12:56:21 +0000 Subject: [PATCH 510/737] eckit::geo::Spec --- src/eckit/geo/Spec.h | 3 ++- src/eckit/geo/spec/Custom.h | 30 ++---------------------------- src/eckit/geo/spec/Layered.cc | 34 +++++++++++++++++++++------------- src/eckit/geo/spec/Layered.h | 30 ------------------------------ 4 files changed, 25 insertions(+), 72 deletions(-) diff --git a/src/eckit/geo/Spec.h b/src/eckit/geo/Spec.h index d60a478b5..13bac13b3 100644 --- a/src/eckit/geo/Spec.h +++ b/src/eckit/geo/Spec.h @@ -60,9 +60,10 @@ class Spec : public Parametrisation { std::string str() const; + virtual void json(JSON&) const = 0; + private: virtual void print(std::ostream&) const; - virtual void json(JSON&) const = 0; friend std::ostream& operator<<(std::ostream& out, const Spec& spec) { spec.print(out); diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 54144b017..77c0a6e03 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -47,9 +47,6 @@ class Custom final : public Spec { using container_type = std::map; - // -- Exceptions - // None - // -- Constructors explicit Custom(const container_type& = {}); @@ -60,9 +57,6 @@ class Custom final : public Spec { Custom(const Custom&); Custom(Custom&&); - // -- Convertors - // None - // -- Operators Custom& operator=(const Custom&); @@ -73,6 +67,8 @@ class Custom final : public Spec { bool empty() const { return map_.empty(); } void clear() { map_.clear(); } + void json(JSON&) const override; + void set(const std::string& name, const char* value) { set(name, std::string{value}); } void set(const std::string& name, const std::string& value); @@ -111,32 +107,10 @@ class Custom final : public Spec { bool get(const std::string& name, std::vector& value) const override; bool get(const std::string& name, std::vector& value) const override; - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members container_type map_; - - // -- Methods - // None - - // -- Overridden methods - - void json(JSON&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/spec/Layered.cc b/src/eckit/geo/spec/Layered.cc index 682240500..5058843e7 100644 --- a/src/eckit/geo/spec/Layered.cc +++ b/src/eckit/geo/spec/Layered.cc @@ -12,6 +12,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/spec/Custom.h" +#include "eckit/log/JSON.h" #include "eckit/value/Value.h" @@ -52,27 +53,34 @@ void Layered::push_front(Spec* spec) { void Layered::print(std::ostream& out) const { - const auto* sep = ""; - out << "Layered[hide["; + JSON j(out); + j.startObject(); + + j << "hide"; + j.startList(); for (const auto& name : hide_) { - out << sep << name; - sep = ","; + j << name; } + j.endList(); - sep = ""; - out << "],spec=" << spec_ << ",before["; + j << "before"; + j.startList(); for (const auto& spec : before_) { - out << sep << *spec; - sep = ","; + spec->json(j); } + j.endList(); + + j << "spec"; + spec_.json(j); - sep = ""; - out << ",after["; + j << "after"; + j.startList(); for (const auto& spec : after_) { - out << sep << *spec; - sep = ","; + spec->json(j); } - out << "]]"; + j.endList(); + + j.endObject(); } diff --git a/src/eckit/geo/spec/Layered.h b/src/eckit/geo/spec/Layered.h index a0d5cb80f..b15e5a607 100644 --- a/src/eckit/geo/spec/Layered.h +++ b/src/eckit/geo/spec/Layered.h @@ -23,26 +23,11 @@ namespace eckit::geo::spec { class Layered final : public Spec { public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors Layered(); explicit Layered(const Spec&); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - // -- Methods void hide(const std::string&); @@ -79,12 +64,6 @@ class Layered final : public Spec { bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members @@ -114,15 +93,6 @@ class Layered final : public Spec { void print(std::ostream&) const override; void json(JSON&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; From cb721e9c26e154436aa384bd574d40f3f5fe163d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 21 Feb 2024 15:38:25 +0000 Subject: [PATCH 511/737] eckit::geo tests --- tests/geo/CMakeLists.txt | 2 + tests/geo/area_boundingbox.cc | 13 +---- tests/geo/area_polygon.cc | 25 ++++++++-- tests/geo/cache.cc | 7 +-- tests/geo/coordinate_helpers.cc | 10 +--- tests/geo/figure_sphere.cc | 7 +-- tests/geo/great_circle.cc | 13 ++--- tests/geo/grid.cc | 84 +------------------------------ tests/geo/grid_reduced_gg.cc | 77 +++++++++++++++++++++++++++++ tests/geo/grid_regular_gg.cc | 88 +++++++++++++++++++++++++++++++++ tests/geo/grid_regular_ll.cc | 7 +-- tests/geo/grid_reorder.cc | 7 +-- tests/geo/grid_to_points.cc | 7 +-- tests/geo/increments.cc | 13 +---- tests/geo/iterator.cc | 13 +---- tests/geo/kdtree.cc | 4 +- tests/geo/kpoint.cc | 9 ++-- tests/geo/point.cc | 13 +---- tests/geo/point2.cc | 13 +---- tests/geo/point3.cc | 13 +---- tests/geo/pointlonlat.cc | 13 +---- tests/geo/projection.cc | 6 +-- tests/geo/range.cc | 7 +-- tests/geo/search.cc | 13 +---- tests/geo/spec.cc | 13 +---- tests/geo/util.cc | 12 +---- 26 files changed, 234 insertions(+), 255 deletions(-) create mode 100644 tests/geo/grid_reduced_gg.cc create mode 100644 tests/geo/grid_regular_gg.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 018b82a14..d10d1fd20 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -6,6 +6,8 @@ foreach(_test figure_sphere great_circle grid + grid_reduced_gg + grid_regular_gg grid_regular_ll grid_reorder grid_to_points diff --git a/tests/geo/area_boundingbox.cc b/tests/geo/area_boundingbox.cc index 59409ca9d..76c381c19 100644 --- a/tests/geo/area_boundingbox.cc +++ b/tests/geo/area_boundingbox.cc @@ -14,13 +14,7 @@ #include "eckit/testing/Test.h" -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("global") { @@ -79,10 +73,7 @@ CASE("assignment") { } -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/area_polygon.cc b/tests/geo/area_polygon.cc index 4ddcfd6a8..ce272a9c9 100644 --- a/tests/geo/area_polygon.cc +++ b/tests/geo/area_polygon.cc @@ -17,15 +17,14 @@ #include "eckit/geo/polygon/Polygon.h" #include "eckit/testing/Test.h" -namespace eckit::test { - -using namespace geo; +namespace eckit::geo::test { CASE("Polygon") { using geo::polygon::Polygon; + SECTION("empty polygon") { Polygon poly1; Polygon poly2; @@ -33,6 +32,7 @@ CASE("Polygon") { EXPECT(poly1.sameAs(poly2)); } + SECTION("equality") { Polygon poly1; Polygon poly2; @@ -57,6 +57,7 @@ CASE("Polygon") { EXPECT(!poly1.sameAs(poly2)); } + SECTION("congruence") { Polygon poly1; Polygon poly2; @@ -91,9 +92,11 @@ CASE("Polygon") { } } + CASE("LonLatPolygon") { using Polygon = geo::polygon::LonLatPolygon; + SECTION("Construction") { const std::vector points1{{0, 0}, {1, 1}, {2, 2}, {0, 0}}; const std::vector @@ -106,6 +109,7 @@ CASE("LonLatPolygon") { EXPECT_EQUAL(Polygon(points2.begin(), points2.end()).size(), 5); } + SECTION("Contains North pole") { const std::vector points{{0, 90}, {0, 0}, {1, 0}, {1, 90}, {0, 90}}; @@ -122,6 +126,7 @@ CASE("LonLatPolygon") { EXPECT_NOT(poly2.contains({10, -90})); } + SECTION("Contains South pole") { const std::vector points{{0, -90}, {0, 0}, {1, 0}, {1, -90}, {0, -90}}; @@ -138,6 +143,7 @@ CASE("LonLatPolygon") { EXPECT_NOT(poly2.contains({10, -90})); } + SECTION("Contains South and North poles") { Polygon poly({{0, -90}, {0, 90}, {1, 90}, {1, -90}, {0, -90}}); EXPECT(poly.contains({0, 90})); @@ -148,6 +154,7 @@ CASE("LonLatPolygon") { EXPECT(poly.contains({10, -90})); } + SECTION("MIR-566: wide polygon") { Polygon poly1({{0, 0}, {361, 0}, {361, 2}, {0, 2}, {0, 0}}); EXPECT(poly1.contains({0, 1})); @@ -227,12 +234,14 @@ CASE("LonLatPolygon") { EXPECT(poly.contains({721, 0})); } + SECTION("MIR-566: winding number strict check of edges") { Polygon poly({{110, -34}, {90, -62}, {100, -59}, {110, -50}, {132, -40}, {110, -34}}); EXPECT_NOT(poly.contains({90, -40})); EXPECT_NOT(poly.contains({90, -34})); } + SECTION("Simple rectangular polygon") { double lonmin = 0; double lonmax = 360; @@ -244,6 +253,7 @@ CASE("LonLatPolygon") { Polygon poly({{lonmin, latmax}, {lonmax, latmax}, {lonmax, latmin}, {lonmin, latmin}, {lonmin, latmax}}); + SECTION("Contains edges") { EXPECT(poly.contains({lonmin, latmax})); EXPECT(poly.contains({lonmid, latmax})); @@ -255,6 +265,7 @@ CASE("LonLatPolygon") { EXPECT(poly.contains({lonmin, latmid})); } + SECTION("Contains in/outward of edges") { constexpr auto eps = 0.001; @@ -281,6 +292,7 @@ CASE("LonLatPolygon") { EXPECT(poly.contains({lonmid, 180. - latmid}, true)); } + SECTION("Parallelogram") { const std::vector points{{0, 0}, {1, 1}, {2, 1}, {1, 0}, {0, 0}}; Polygon poly(points); @@ -292,6 +304,7 @@ CASE("LonLatPolygon") { EXPECT_NOT(poly.contains({2, 0})); } + SECTION("Degenerate polygon") { const std::vector points{{0, 0}, {2, 0}, {2, 0} /*duplicate*/, {0, 2}, {0, 0}}; @@ -306,6 +319,7 @@ CASE("LonLatPolygon") { } } + SECTION("Self-intersecting polygon") { Polygon poly1({{-1, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}); @@ -335,6 +349,7 @@ CASE("LonLatPolygon") { } } + SECTION("Partitioning (includePoles=false)") { auto mid = [](double a, double b) { return (a + b) / 2.; }; @@ -394,7 +409,9 @@ CASE("LonLatPolygon") { } } -} // namespace eckit::test + +} // namespace eckit::geo::test + int main(int argc, char** argv) { return eckit::testing::run_tests(argc, argv); diff --git a/tests/geo/cache.cc b/tests/geo/cache.cc index 6aba42a7c..3aba24123 100644 --- a/tests/geo/cache.cc +++ b/tests/geo/cache.cc @@ -15,10 +15,7 @@ #include "eckit/testing/Test.h" -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("eckit::geo::util") { @@ -104,7 +101,7 @@ CASE("eckit::geo::util") { } -} // namespace eckit::test +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/coordinate_helpers.cc b/tests/geo/coordinate_helpers.cc index ad4ea4459..3ea675b5e 100644 --- a/tests/geo/coordinate_helpers.cc +++ b/tests/geo/coordinate_helpers.cc @@ -11,14 +11,9 @@ #include "eckit/testing/Test.h" -namespace eckit::test { +namespace eckit::geo::test { -using namespace geo; - - -// ----------------------------------------------------------------------------- - CASE("normalise angles") { EXPECT(0. == normalise_angle(360., 0.)); EXPECT(14. == normalise_angle(374., 0.)); @@ -62,9 +57,8 @@ CASE("canonicalise on sphere") { EXPECT(q2d.y() == 32.); } -// ----------------------------------------------------------------------------- -} // namespace eckit::test +} // namespace eckit::geo::test int main(int argc, char** argv) { return eckit::testing::run_tests(argc, argv); diff --git a/tests/geo/figure_sphere.cc b/tests/geo/figure_sphere.cc index ddc12eba8..8c5bc2361 100644 --- a/tests/geo/figure_sphere.cc +++ b/tests/geo/figure_sphere.cc @@ -19,10 +19,7 @@ #include "eckit/testing/Test.h" -namespace eckit::tests { - - -using namespace eckit::geo; +namespace eckit::geo::test { CASE("unit sphere") { @@ -267,7 +264,7 @@ CASE("two-unit sphere") { } -} // namespace eckit::tests +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/great_circle.cc b/tests/geo/great_circle.cc index 6538882c1..9f1818bfe 100644 --- a/tests/geo/great_circle.cc +++ b/tests/geo/great_circle.cc @@ -22,13 +22,7 @@ #define EXPECT_APPROX(a, b, eps) EXPECT(::eckit::types::is_approximately_equal((a), (b), (eps))) -namespace eckit::test { - - -using namespace geo; - - -// ----------------------------------------------------------------------------- +namespace eckit::geo::test { CASE("great circle intersections") { @@ -243,7 +237,6 @@ CASE("great circle intersections") { } } -// ----------------------------------------------------------------------------- CASE("great circle course") { SECTION("Valparaíso-Shanghai") { @@ -261,9 +254,9 @@ CASE("great circle course") { } } -// ----------------------------------------------------------------------------- -} // namespace eckit::test +} // namespace eckit::geo::test + int main(int argc, char** argv) { return eckit::testing::run_tests(argc, argv); diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index a9505a6d8..e7cc5effd 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -15,16 +15,12 @@ #include "eckit/geo/Cache.h" #include "eckit/geo/Grid.h" #include "eckit/geo/LibEcKitGeo.h" -#include "eckit/geo/grid/reduced/ReducedGaussian.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/testing/Test.h" -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("GridFactory::build") { @@ -43,82 +39,6 @@ CASE("GridFactory::build") { } - SECTION("RegularGaussian") { - spec::Custom spec({{"grid", "f2"}}); - std::unique_ptr grid1(GridFactory::build(spec)); - auto n1 = grid1->size(); - - EXPECT_EQUAL(n1, 32); - - spec.set("south", 0); - std::unique_ptr grid2(GridFactory::build(spec)); - auto n2 = grid2->size(); - - EXPECT_EQUAL(n2, n1 / 2); - - // spec = spec::Custom{{{"grid", "f2"}, {"west", -180}}}; - // std::unique_ptr grid3(GridFactory::build(spec)); - // auto n3 = grid3->size(); - - // EXPECT_EQUAL(n3, n1); - - // spec.set("east", 0); - // std::unique_ptr grid4(GridFactory::build(spec)); - // auto n4 = grid4->size(); - - // EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj - - // spec.set("east", -1.); - // std::unique_ptr grid5(GridFactory::build(spec)); - // auto n5 = grid5->size(); - - // EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj - } - - - SECTION("ReducedGaussian") { - // different ways to instantiate the same grid (O2) - for (auto spec : { - spec::Custom({{"grid", "o2"}}), - spec::Custom({{"N", 2}}), - spec::Custom({{"pl", pl_type{20, 24, 24, 20}}}), - }) { - std::unique_ptr grid1(GridFactory::build(spec)); - auto n1 = grid1->size(); - - EXPECT_EQUAL(n1, 88); - - spec.set("south", 0); - std::unique_ptr grid2(GridFactory::build(spec)); - auto n2 = grid2->size(); - - EXPECT_EQUAL(n2, n1 / 2); - } - - { - std::unique_ptr grid1(new grid::reduced::ReducedGaussian(2)); - auto n1 = grid1->size(); - - EXPECT_EQUAL(n1, 88); - - // std::unique_ptr grid2(grid1->crop(...)); - // auto n2 = grid2->size(); - - // EXPECT_EQUAL(n2, n1 / 2); - } - - { - std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "o2"}}))); - std::unique_ptr grid2(GridFactory::make_from_string("N: 2")); - std::unique_ptr grid3(new grid::reduced::ReducedGaussian(pl_type{20, 24, 24, 20})); - - EXPECT(*grid1 == *grid2); - EXPECT(*grid2 == *grid3); - EXPECT(*grid3 == *grid1); - } - } - - if (LibEcKitGeo::caching()) { SECTION("Grid::build_from_uid") { spec::Custom spec({ @@ -175,7 +95,7 @@ CASE("GridFactory::build") { } -} // namespace eckit::test +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/grid_reduced_gg.cc b/tests/geo/grid_reduced_gg.cc new file mode 100644 index 000000000..8adec9ee8 --- /dev/null +++ b/tests/geo/grid_reduced_gg.cc @@ -0,0 +1,77 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/geo/Grid.h" +#include "eckit/geo/grid/reduced/ReducedGaussian.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/geo/util.h" +#include "eckit/testing/Test.h" + + +namespace eckit::geo::test { + + +CASE("ReducedGaussian") { + SECTION("gridspec") { + // different ways to instantiate the same grid (O2) + for (auto spec : { + spec::Custom({{"grid", "o2"}}), + spec::Custom({{"N", 2}}), + spec::Custom({{"pl", pl_type{20, 24, 24, 20}}}), + }) { + std::unique_ptr grid1(GridFactory::build(spec)); + auto n1 = grid1->size(); + + EXPECT_EQUAL(n1, 88); + + spec.set("south", 0); + std::unique_ptr grid2(GridFactory::build(spec)); + auto n2 = grid2->size(); + + EXPECT_EQUAL(n2, n1 / 2); + } + } + + + SECTION("crop") { + std::unique_ptr grid1(new grid::reduced::ReducedGaussian(2)); + auto n1 = grid1->size(); + + EXPECT_EQUAL(n1, 88); + + // std::unique_ptr grid2(grid1->crop(...)); + // auto n2 = grid2->size(); + + // EXPECT_EQUAL(n2, n1 / 2); + } + + + SECTION("equals") { + std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "o3"}}))); + std::unique_ptr grid2(GridFactory::make_from_string("N: 3")); + std::unique_ptr grid3(new grid::reduced::ReducedGaussian(pl_type{20, 24, 28, 28, 24, 20})); + + EXPECT(*grid1 == *grid2); + EXPECT(*grid2 == *grid3); + EXPECT(*grid3 == *grid1); + } +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc new file mode 100644 index 000000000..3789812e2 --- /dev/null +++ b/tests/geo/grid_regular_gg.cc @@ -0,0 +1,88 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/geo/Grid.h" +#include "eckit/geo/grid/regular/RegularGaussian.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/geo/util.h" +#include "eckit/testing/Test.h" + + +namespace eckit::geo::test { + + +CASE("RegularGaussian") { + SECTION("gridspec") { + struct { + std::string name; + size_t size; + } tests[]{{"f2", 32}}; + + for (const auto& test : tests) { + std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", test.name}}))); + + auto size = grid->size(); + EXPECT_EQUAL(size, test.size); + } + } + + + SECTION("crop") { + spec::Custom spec({{"grid", "f2"}}); + std::unique_ptr grid1(GridFactory::build(spec)); + auto n1 = grid1->size(); + + EXPECT_EQUAL(n1, 32); + + spec.set("south", 0); + std::unique_ptr grid2(GridFactory::build(spec)); + auto n2 = grid2->size(); + + EXPECT_EQUAL(n2, n1 / 2); + + // spec = spec::Custom{{{"grid", "f2"}, {"west", -180}}}; + // std::unique_ptr grid3(GridFactory::build(spec)); + // auto n3 = grid3->size(); + + // EXPECT_EQUAL(n3, n1); + + // spec.set("east", 0); + // std::unique_ptr grid4(GridFactory::build(spec)); + // auto n4 = grid4->size(); + + // EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj + + // spec.set("east", -1.); + // std::unique_ptr grid5(GridFactory::build(spec)); + // auto n5 = grid5->size(); + + // EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj + } + + + SECTION("equals") { + std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "f3"}}))); + std::unique_ptr grid2(new grid::regular::RegularGaussian(3)); + + EXPECT(*grid1 == *grid2); + } +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index addaed4b1..ccaf429be 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -17,10 +17,7 @@ #include "eckit/testing/Test.h" -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("") { @@ -43,7 +40,7 @@ CASE("") { } -} // namespace eckit::test +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/grid_reorder.cc b/tests/geo/grid_reorder.cc index 17e37ed62..6319fd6bb 100644 --- a/tests/geo/grid_reorder.cc +++ b/tests/geo/grid_reorder.cc @@ -26,10 +26,7 @@ } -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("HEALPix") { @@ -76,7 +73,7 @@ CASE("HEALPix") { } -} // namespace eckit::test +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/grid_to_points.cc b/tests/geo/grid_to_points.cc index 38db940b6..3c8131d03 100644 --- a/tests/geo/grid_to_points.cc +++ b/tests/geo/grid_to_points.cc @@ -17,10 +17,7 @@ #include "eckit/testing/Test.h" -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("HEALPix") { @@ -88,7 +85,7 @@ CASE("HEALPix") { } -} // namespace eckit::test +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/increments.cc b/tests/geo/increments.cc index 23f681aa9..4db8a1ce6 100644 --- a/tests/geo/increments.cc +++ b/tests/geo/increments.cc @@ -14,13 +14,7 @@ #include "eckit/testing/Test.h" -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("checks") { @@ -68,10 +62,7 @@ CASE("assignment") { } -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/iterator.cc b/tests/geo/iterator.cc index 67ddd73fa..f83ab760f 100644 --- a/tests/geo/iterator.cc +++ b/tests/geo/iterator.cc @@ -14,22 +14,13 @@ #include "eckit/testing/Test.h" -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { - - -using namespace eckit::geo; +namespace eckit::geo::test { CASE("") {} -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/kdtree.cc b/tests/geo/kdtree.cc index 6e3098450..ae01d61d6 100644 --- a/tests/geo/kdtree.cc +++ b/tests/geo/kdtree.cc @@ -17,7 +17,7 @@ #include "eckit/testing/Test.h" -namespace eckit::test { +namespace eckit::geo::test { //---------------------------------------------------------------------------------------------------------------------- @@ -295,7 +295,7 @@ CASE("test_kdtree_iterate_empty") { //---------------------------------------------------------------------------------------------------------------------- -} // namespace eckit::test +} // namespace eckit::geo::test int main(int argc, char** argv) { return eckit::testing::run_tests(argc, argv); diff --git a/tests/geo/kpoint.cc b/tests/geo/kpoint.cc index 99d0438c9..02893c0de 100644 --- a/tests/geo/kpoint.cc +++ b/tests/geo/kpoint.cc @@ -14,10 +14,7 @@ #include "eckit/testing/Test.h" -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("KPoint Inits to Zero") { @@ -108,9 +105,9 @@ CASE("KPoint distance2 comparison") { EXPECT(p1.distance2(zz) < p2.distance2(zz)); } -} // namespace eckit::test -//---------------------------------------------------------------------------------------------------------------------- +} // namespace eckit::geo::test + int main(int argc, char** argv) { return eckit::testing::run_tests(argc, argv); diff --git a/tests/geo/point.cc b/tests/geo/point.cc index 8f8e5f340..fb9c5a493 100644 --- a/tests/geo/point.cc +++ b/tests/geo/point.cc @@ -19,13 +19,7 @@ #include "eckit/testing/Test.h" -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("Point comparison") { @@ -51,10 +45,7 @@ CASE("Point comparison") { } -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/point2.cc b/tests/geo/point2.cc index 62b04ae42..2f88d18c1 100644 --- a/tests/geo/point2.cc +++ b/tests/geo/point2.cc @@ -15,13 +15,7 @@ #include "eckit/types/FloatCompare.h" -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("Point2 initialisation") { @@ -130,10 +124,7 @@ CASE("Point2 distance2 comparison") { } -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/point3.cc b/tests/geo/point3.cc index 7c3e4bb6e..1688fe584 100644 --- a/tests/geo/point3.cc +++ b/tests/geo/point3.cc @@ -14,13 +14,7 @@ #include "eckit/testing/Test.h" -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("Point3 initialisation") { @@ -39,10 +33,7 @@ CASE("Point3 initialisation") { } -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/pointlonlat.cc b/tests/geo/pointlonlat.cc index d0c19c345..89863daf7 100644 --- a/tests/geo/pointlonlat.cc +++ b/tests/geo/pointlonlat.cc @@ -16,13 +16,7 @@ #include "eckit/types/FloatCompare.h" -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("PointLonLat normalisation") { @@ -86,10 +80,7 @@ CASE("PointLonLat comparison") { } -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index 0a6db532a..03a5c7204 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -30,11 +30,9 @@ area::BoundingBox bounding_box(Point2, Point2, Projection&); } -namespace eckit::test { +namespace eckit::geo::test { -using namespace geo; - using P = std::unique_ptr; @@ -476,7 +474,7 @@ CASE("projection: mercator") { } -} // namespace eckit::test +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 47036fba7..a6e85134b 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -22,10 +22,7 @@ #define EXPECT_APPROX(a, b, eps) EXPECT(::eckit::types::is_approximately_equal((a), (b), (eps))) -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { constexpr auto EPS = 1e-3; @@ -198,7 +195,7 @@ CASE("range::Gaussian") { } -} // namespace eckit::test +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/search.cc b/tests/geo/search.cc index 8e7d993ab..91b0885af 100644 --- a/tests/geo/search.cc +++ b/tests/geo/search.cc @@ -17,13 +17,7 @@ #include "eckit/testing/Test.h" -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { CASE("") { @@ -62,10 +56,7 @@ CASE("") { } -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 364975051..9ee0742fe 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -30,13 +30,7 @@ EXPECT_APPROX((a)[3], (b)[3], (eps))) -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { - - -using namespace geo; +namespace eckit::geo::test { using S = std::unique_ptr; @@ -327,10 +321,7 @@ CASE("spec") { } -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- +} // namespace eckit::geo::test int main(int argc, char** argv) { diff --git a/tests/geo/util.cc b/tests/geo/util.cc index 3adeb9d6c..24cd74152 100644 --- a/tests/geo/util.cc +++ b/tests/geo/util.cc @@ -39,16 +39,11 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) { } -//---------------------------------------------------------------------------------------------------------------------- - - -namespace eckit::test { +namespace eckit::geo::test { constexpr double EPS = 1e-9; -using namespace geo; - CASE("eckit::geo::util::linspace") { EXPECT(is_approximately_equal_vector(util::linspace(1, 2, 1, false), std::vector{1.}, EPS)); @@ -127,10 +122,7 @@ CASE("eckit::geo::util::monotonic_crop") { } -} // namespace eckit::test - - -//---------------------------------------------------------------------------------------------------------------------- +} // namespace eckit::geo::test int main(int argc, char** argv) { From 887ee8350c25a51d5b5c1e6da9ffeb64dacce37c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 21 Feb 2024 15:39:50 +0000 Subject: [PATCH 512/737] eckit::geo tests fix --- src/eckit/geo/util/reduced_octahedral_pl.cc | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/eckit/geo/util/reduced_octahedral_pl.cc b/src/eckit/geo/util/reduced_octahedral_pl.cc index 72b18fb1c..864aa857e 100644 --- a/src/eckit/geo/util/reduced_octahedral_pl.cc +++ b/src/eckit/geo/util/reduced_octahedral_pl.cc @@ -10,7 +10,6 @@ */ -#include "eckit/exception/Exceptions.h" #include "eckit/geo/Cache.h" #include "eckit/geo/util.h" @@ -19,8 +18,6 @@ namespace eckit::geo::util { const pl_type& reduced_octahedral_pl(size_t N) { - ASSERT(0 < N && N % 2 == 0); - static CacheT cache; if (cache.contains(N)) { return cache[N]; From 1a509f8bf1060e49a5076082f8997f638c272bfa Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 21 Feb 2024 19:14:04 +0000 Subject: [PATCH 513/737] eckit::geo::Spec --- src/eckit/geo/Spec.cc | 38 +++++++++++++++++++++++-------- src/eckit/geo/Spec.h | 14 ++++++++---- src/eckit/geo/spec/Custom.cc | 43 ++++++++++++++++++++++++++---------- src/eckit/geo/spec/Custom.h | 18 ++++++++++----- src/eckit/geo/spec/Layered.h | 4 ++-- 5 files changed, 84 insertions(+), 33 deletions(-) diff --git a/src/eckit/geo/Spec.cc b/src/eckit/geo/Spec.cc index c78104b62..df32f1e5f 100644 --- a/src/eckit/geo/Spec.cc +++ b/src/eckit/geo/Spec.cc @@ -41,6 +41,11 @@ SpecNotFound::SpecNotFound(const std::string& name) { } +std::string Spec::get_string(const std::string& name) const { + return _get_t(*this, name); +} + + bool Spec::get_bool(const std::string& name) const { return _get_t(*this, name); } @@ -56,8 +61,8 @@ long Spec::get_long(const std::string& name) const { } -std::size_t Spec::get_unsigned(const std::string& name) const { - return _get_t(*this, name); +size_t Spec::get_unsigned(const std::string& name) const { + return _get_t(*this, name); } @@ -66,13 +71,23 @@ double Spec::get_double(const std::string& name) const { } -std::string Spec::get_string(const std::string& name) const { - return _get_t(*this, name); +std::vector Spec::get_long_vector(const std::string& name) const { + return _get_t>(*this, name); } -std::vector Spec::get_long_vector(const std::string& name) const { - return _get_t>(*this, name); +std::vector Spec::get_unsigned_vector(const std::string& name) const { + return _get_t>(*this, name); +} + + +std::vector Spec::get_double_vector(const std::string& name) const { + return _get_t>(*this, name); +} + + +std::string Spec::get_string(const std::string& name, const std::string& _default) const { + return _get_d(*this, name, _default); } @@ -91,7 +106,7 @@ long Spec::get_long(const std::string& name, const long& _default) const { } -std::size_t Spec::get_unsigned(const std::string& name, const std::size_t& _default) const { +size_t Spec::get_unsigned(const std::string& name, const size_t& _default) const { return _get_d(*this, name, _default); } @@ -101,12 +116,17 @@ double Spec::get_double(const std::string& name, const double& _default) const { } -std::string Spec::get_string(const std::string& name, const std::string& _default) const { +std::vector Spec::get_long_vector(const std::string& name, const std::vector& _default) const { return _get_d(*this, name, _default); } -std::vector Spec::get_long_vector(const std::string& name, const std::vector& _default) const { +std::vector Spec::get_unsigned_vector(const std::string& name, const std::vector& _default) const { + return _get_d(*this, name, _default); +} + + +std::vector Spec::get_double_vector(const std::string& name, const std::vector& _default) const { return _get_d(*this, name, _default); } diff --git a/src/eckit/geo/Spec.h b/src/eckit/geo/Spec.h index 13bac13b3..3f7c5a453 100644 --- a/src/eckit/geo/Spec.h +++ b/src/eckit/geo/Spec.h @@ -42,21 +42,27 @@ class Spec : public Parametrisation { Spec& operator=(const Spec&) = delete; Spec& operator=(Spec&&) = delete; + std::string get_string(const std::string& name) const; bool get_bool(const std::string& name) const; int get_int(const std::string& name) const; long get_long(const std::string& name) const; - std::size_t get_unsigned(const std::string& name) const; + size_t get_unsigned(const std::string& name) const; double get_double(const std::string& name) const; - std::string get_string(const std::string& name) const; + std::vector get_long_vector(const std::string& name) const; + std::vector get_unsigned_vector(const std::string& name) const; + std::vector get_double_vector(const std::string& name) const; + std::string get_string(const std::string& name, const std::string&) const; bool get_bool(const std::string& name, const bool&) const; int get_int(const std::string& name, const int&) const; long get_long(const std::string& name, const long&) const; - std::size_t get_unsigned(const std::string& name, const std::size_t&) const; + size_t get_unsigned(const std::string& name, const size_t&) const; double get_double(const std::string& name, const double&) const; - std::string get_string(const std::string& name, const std::string&) const; + std::vector get_long_vector(const std::string& name, const std::vector&) const; + std::vector get_unsigned_vector(const std::string& name, const std::vector&) const; + std::vector get_double_vector(const std::string& name, const std::vector&) const; std::string str() const; diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 76771ad45..84ef277f5 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -11,6 +11,9 @@ #include "eckit/geo/spec/Custom.h" +#include +#include + #include "eckit/exception/Exceptions.h" #include "eckit/log/JSON.h" #include "eckit/value/Content.h" // for ValueList, ValueMap @@ -65,11 +68,11 @@ template bool __get_s_integral(const Custom::container_type& map, const std::string& name, T& value) { if (auto it = map.find(name); it != map.cend()) { const auto& v = it->second; - return std::holds_alternative(v) ? __get_s(std::get(v), value) - : std::holds_alternative(v) ? __get_s(std::get(v), value) - : std::holds_alternative(v) ? __get_s(std::get(v), value) - : std::holds_alternative(v) ? __get_s(std::get(v), value) - : false; + return std::holds_alternative(v) ? __get_s(std::get(v), value) + : std::holds_alternative(v) ? __get_s(std::get(v), value) + : std::holds_alternative(v) ? __get_s(std::get(v), value) + : std::holds_alternative(v) ? __get_s(std::get(v), value) + : false; } return false; } @@ -98,9 +101,8 @@ bool __get_v_integral(const Custom::container_type& map, const std::string& name return std::holds_alternative>(v) ? __get_v(std::get>(v), value) : std::holds_alternative>(v) ? __get_v(std::get>(v), value) : std::holds_alternative>(v) ? __get_v(std::get>(v), value) - : std::holds_alternative>(v) - ? __get_v(std::get>(v), value) - : false; + : std::holds_alternative>(v) ? __get_v(std::get>(v), value) + : false; } return false; } @@ -177,6 +179,23 @@ Custom& Custom::operator=(Custom&& custom) { } +bool Custom::operator==(const Custom& other) const { + auto custom_value_equal = [](const auto& a, const auto& b) -> bool { + if constexpr (std::is_same_v) { + return a == b; + } + else { + return false; + } + }; + + return std::all_of(map_.begin(), map_.end(), [&](const auto& _a) { + auto _b = other.map_.find(_a.first); + return _b != other.map_.end() && custom_value_equal(_a.second, _b->second); + }); +} + + Custom& Custom::operator=(const Custom& custom) { map_ = custom.map_; return *this; @@ -208,7 +227,7 @@ void Custom::set(const std::string& name, long long value) { } -void Custom::set(const std::string& name, std::size_t value) { +void Custom::set(const std::string& name, size_t value) { map_[name] = value; } @@ -238,7 +257,7 @@ void Custom::set(const std::string& name, const std::vector& value) { } -void Custom::set(const std::string& name, const std::vector& value) { +void Custom::set(const std::string& name, const std::vector& value) { map_[name] = value; } @@ -307,7 +326,7 @@ bool Custom::get(const std::string& name, long long& value) const { } -bool Custom::get(const std::string& name, std::size_t& value) const { +bool Custom::get(const std::string& name, size_t& value) const { return __get_s_integral(map_, name, value); } @@ -337,7 +356,7 @@ bool Custom::get(const std::string& name, std::vector& value) const { } -bool Custom::get(const std::string& name, std::vector& value) const { +bool Custom::get(const std::string& name, std::vector& value) const { return __get_v_integral(map_, name, value); } diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 77c0a6e03..69e6be492 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -34,13 +34,13 @@ class Custom final : public Spec { int, long, long long, - std::size_t, + size_t, float, double, std::vector, std::vector, std::vector, - std::vector, + std::vector, std::vector, std::vector, std::vector>; @@ -57,11 +57,17 @@ class Custom final : public Spec { Custom(const Custom&); Custom(Custom&&); + // -- Destructor + + ~Custom() override = default; + // -- Operators Custom& operator=(const Custom&); Custom& operator=(Custom&&); + bool operator==(const Custom&) const; + // -- Methods bool empty() const { return map_.empty(); } @@ -76,13 +82,13 @@ class Custom final : public Spec { void set(const std::string& name, int value); void set(const std::string& name, long value); void set(const std::string& name, long long value); - void set(const std::string& name, std::size_t value); + void set(const std::string& name, size_t value); void set(const std::string& name, float value); void set(const std::string& name, double value); void set(const std::string& name, const std::vector& value); void set(const std::string& name, const std::vector& value); void set(const std::string& name, const std::vector& value); - void set(const std::string& name, const std::vector& value); + void set(const std::string& name, const std::vector& value); void set(const std::string& name, const std::vector& value); void set(const std::string& name, const std::vector& value); void set(const std::string& name, const std::vector& value); @@ -96,13 +102,13 @@ class Custom final : public Spec { bool get(const std::string& name, int& value) const override; bool get(const std::string& name, long& value) const override; bool get(const std::string& name, long long& value) const override; - bool get(const std::string& name, std::size_t& value) const override; + bool get(const std::string& name, size_t& value) const override; bool get(const std::string& name, float& value) const override; bool get(const std::string& name, double& value) const override; bool get(const std::string& name, std::vector& value) const override; bool get(const std::string& name, std::vector& value) const override; bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::vector& value) const override; bool get(const std::string& name, std::vector& value) const override; bool get(const std::string& name, std::vector& value) const override; bool get(const std::string& name, std::vector& value) const override; diff --git a/src/eckit/geo/spec/Layered.h b/src/eckit/geo/spec/Layered.h index b15e5a607..ab58ea971 100644 --- a/src/eckit/geo/spec/Layered.h +++ b/src/eckit/geo/spec/Layered.h @@ -53,13 +53,13 @@ class Layered final : public Spec { bool get(const std::string& name, int& value) const override { return __get(name, value); } bool get(const std::string& name, long& value) const override { return __get(name, value); } bool get(const std::string& name, long long& value) const override { return __get(name, value); } - bool get(const std::string& name, std::size_t& value) const override { return __get(name, value); } + bool get(const std::string& name, size_t& value) const override { return __get(name, value); } bool get(const std::string& name, float& value) const override { return __get(name, value); } bool get(const std::string& name, double& value) const override { return __get(name, value); } bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } - bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } + bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } From 7e7f84562b597d784ecf4ac38bcd3bdda7e8a40a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 21 Feb 2024 19:14:54 +0000 Subject: [PATCH 514/737] eckit::geo::Grid --- src/eckit/geo/CMakeLists.txt | 2 + src/eckit/geo/etc/Grid.cc | 2 + .../grid/regular/LambertAzimuthalEqualArea.cc | 97 +++++++++++++++++++ .../grid/regular/LambertAzimuthalEqualArea.h | 68 +++++++++++++ src/eckit/geo/spec/Generator.h | 17 ++++ 5 files changed, 186 insertions(+) create mode 100644 src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.cc create mode 100644 src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index c294d7bfe..eff1ec0b5 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -72,6 +72,8 @@ list(APPEND eckit_geo_srcs grid/reduced/ReducedLL.h grid/regular/IrregularLL.cc grid/regular/IrregularLL.h + grid/regular/LambertAzimuthalEqualArea.cc + grid/regular/LambertAzimuthalEqualArea.h grid/regular/Mercator.cc grid/regular/Mercator.h grid/regular/RegularGaussian.cc diff --git a/src/eckit/geo/etc/Grid.cc b/src/eckit/geo/etc/Grid.cc index dca589729..aa56c7f2a 100644 --- a/src/eckit/geo/etc/Grid.cc +++ b/src/eckit/geo/etc/Grid.cc @@ -83,6 +83,7 @@ Grid::Grid(const PathName& path) { explicit SpecByUIDGenerator(spec::Custom* spec) : spec_(spec) {} Spec* spec() const override { return new spec::Custom(*spec_); } + bool match(const spec::Custom& other) const override { return other == *spec_; } std::unique_ptr spec_; }; @@ -90,6 +91,7 @@ Grid::Grid(const PathName& path) { explicit SpecByNameGenerator(spec::Custom* spec) : spec_(spec) {} Spec* spec(SpecByName::generator_t::arg1_t) const override { return new spec::Custom(*spec_); } + bool match(const spec::Custom& other) const override { return other == *spec_; } std::unique_ptr spec_; }; diff --git a/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.cc b/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.cc new file mode 100644 index 000000000..0cac1f866 --- /dev/null +++ b/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.cc @@ -0,0 +1,97 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/regular/LambertAzimuthalEqualArea.h" + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/Spec.h" +#include "eckit/geo/area/BoundingBox.h" +#include "eckit/geo/etc/Grid.h" +#include "eckit/geo/iterator/Regular.h" +#include "eckit/geo/spec/Custom.h" +// #include "eckit/geo/util/regex.h" +// #include "eckit/types/Fraction.h" +// #include "eckit/utils/Translator.h" + + +namespace eckit::geo::grid::regular { + + +static const GridRegisterType __grid_type("lambert_azimuthal_equal_area"); + + +LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Spec& spec) : + LambertAzimuthalEqualArea(Internal(spec)) {} + + +LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(size_t ni, size_t nj, double Dx, double Dy) : + Regular(area::BoundingBox{}), Nx_(ni), Ny_(nj), Dx_(Dx), Dy_(Dy) {} + + +Grid::iterator LambertAzimuthalEqualArea::cbegin() const { + return iterator{new geo::iterator::Regular(*this, 0)}; +} + + +Grid::iterator LambertAzimuthalEqualArea::cend() const { + return iterator{new geo::iterator::Regular(*this, size())}; +} + + +LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(Internal&& internal) : + LambertAzimuthalEqualArea(internal.Nx, internal.Ny, internal.Dx, internal.Dy) {} + + +const std::vector& LambertAzimuthalEqualArea::longitudes() const { + NOTIMP; +} + + +const std::vector& LambertAzimuthalEqualArea::latitudes() const { + NOTIMP; +} + + +void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { + // FIXME a lot more stuff to add here! + spec::Custom spec({ + {"type", "lambert_azimuthal_equal_area"}, + {"grid", std::vector{Dx_, Dy_}}, + {"dimensions", std::vector{static_cast(Nx_), static_cast(Ny_)}}, + // ... + }); + + if (std::string name; SpecByName::instance().match(spec, name)) { + custom.set("grid", name); + return; + } + + NOTIMP; +} + + +LambertAzimuthalEqualArea::Internal::Internal(const Spec& spec) { + auto dimensions(spec.get_unsigned_vector("dimensions", {0, 0})); + Nx = dimensions.size() == 2 ? dimensions[0] : spec.get_unsigned("Nx"); + Ny = dimensions.size() == 2 ? dimensions[1] : spec.get_unsigned("Ny"); + ASSERT(Nx > 0); + ASSERT(Ny > 0); + + auto grid(spec.get_double_vector("grid", {0., 0.})); + Dx = grid.size() == 2 ? grid[0] : spec.get_double("Nx"); + Dy = grid.size() == 2 ? grid[1] : spec.get_double("Ny"); + ASSERT(Dx > 0.); + ASSERT(Dy > 0.); +} + + +} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.h b/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.h new file mode 100644 index 000000000..95ba0af35 --- /dev/null +++ b/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.h @@ -0,0 +1,68 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Regular.h" + + +namespace eckit::geo::grid::regular { + + +class LambertAzimuthalEqualArea final : public Regular { +public: + // -- Constructors + + explicit LambertAzimuthalEqualArea(const Spec&); + + LambertAzimuthalEqualArea(size_t Nx, size_t Ny, double Dx, double Dy); + + // -- Overridden methods + + iterator cbegin() const override; + iterator cend() const override; + + size_t ni() const override { return Ny_; } + size_t nj() const override { return Nx_; } + +private: + // -- Types + + struct Internal { + explicit Internal(const Spec&); + size_t Nx; + size_t Ny; + double Dx; + double Dy; + }; + + // -- Constructors + + explicit LambertAzimuthalEqualArea(Internal&&); + + // -- Members + + const size_t Nx_; + const size_t Ny_; + const double Dx_; + const double Dy_; + + // -- Overridden methods + + const std::vector& longitudes() const override; + const std::vector& latitudes() const override; + + void spec(spec::Custom&) const override; +}; + + +} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/spec/Generator.h b/src/eckit/geo/spec/Generator.h index e3733643e..aece035b7 100644 --- a/src/eckit/geo/spec/Generator.h +++ b/src/eckit/geo/spec/Generator.h @@ -26,7 +26,10 @@ namespace eckit::geo { class Spec; +namespace spec { +class Custom; } +} // namespace eckit::geo namespace eckit::geo::spec { @@ -65,6 +68,16 @@ class GeneratorT { const generator_t& get(const key_t&) const; const generator_t& match(const std::string&) const; + bool match(const Custom& spec, std::string& name) const { + for (const auto& [another_name, another_spec] : store_) { + if (another_spec->match(spec)) { + name = another_name; + return true; + } + } + return false; + } + private: // -- Constructors @@ -209,6 +222,10 @@ class SpecGenerator { void operator=(const SpecGenerator&) = delete; void operator=(SpecGenerator&&) = delete; + + // -- Methods + + virtual bool match(const spec::Custom&) const { return false; } }; //------------------------------------------------------------------------------------------------------ From b944b2bb42034d1676e88ee1a36e2749ab5efcb0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 21 Feb 2024 19:15:09 +0000 Subject: [PATCH 515/737] eckit::geo::Grid --- etc/eckit/geo/grid.yaml | 6 +- tests/geo/spec.cc | 128 +++++++++++++++++++++------------------- 2 files changed, 68 insertions(+), 66 deletions(-) diff --git a/etc/eckit/geo/grid.yaml b/etc/eckit/geo/grid.yaml index 108a977ab..27fe1d395 100644 --- a/etc/eckit/geo/grid.yaml +++ b/etc/eckit/geo/grid.yaml @@ -15,8 +15,7 @@ grid_names: centralLongitudeInDegrees: 10. latitudeOfFirstGridPointInDegrees: 66.982143 longitudeOfFirstGridPointInDegrees: -35.034024 - numberOfPointsAlongXAxis: 1000 - numberOfPointsAlongYAxis: 950 + dimensions: [1000, 950] - SMUFF-OPERA-2km: type: lambert_azimuthal_equal_area @@ -26,8 +25,7 @@ grid_names: gaussianNumber: 1280 latitudeOfFirstGridPointInDegrees: 67.035186732680 longitudeOfFirstGridPointInDegrees: -39.535385563614 - numberOfPointsAlongXAxis: 1900 - numberOfPointsAlongYAxis: 2200 + dimensions: [1900, 2200] - ORCA2_F: &ORCA2_F type: ORCA diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 9ee0742fe..72d59e7e6 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -10,7 +10,6 @@ */ -#include #include #include @@ -33,12 +32,6 @@ namespace eckit::geo::test { -using S = std::unique_ptr; -using G = std::unique_ptr; -using C = spec::Custom; -using v = std::vector; - - CASE("Spec <- Custom") { constexpr int zero = 0; constexpr int one = 1; @@ -247,67 +240,69 @@ CASE("Spec <- Layered") { CASE("spec") { - static const spec::Custom BAD; - ASSERT(BAD.empty()); - - static std::pair cases[]{ - {C({{"N", 2}}), C({{"N", 2}, {"type", "reduced_gg"}})}, - {C({{"area", v{90, -180, -90, 180}}, {"grid", v{2, 2}}}), C({{"type", "regular_ll"}})}, - {C({{"area", v{90, -180, -90, 180}}}), BAD}, - {C({{"grid", "B48"}}), BAD}, - {C({{"grid", "F48"}}), C({{"type", "regular_gg"}})}, - {C({{"grid", "N48"}}), C({{"type", "reduced_gg"}})}, - {C({{"grid", "O48"}}), C({{"type", "reduced_gg"}})}, - {C({{"grid", 48}}), BAD}, - {C({{"grid", v{2, 2}}}), C({{"grid", v{2, 2}}, {"type", "regular_ll"}})}, - {C({{"type", "latlon"}, {"grid", v{2, 2}}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "48"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "F048"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "N"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "N048"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "N48"}}), C({{"type", "reduced_gg"}})}, - {C({{"type", "reduced_gg"}, {"grid", "O048"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "O48"}}), C({{"type", "reduced_gg"}})}, - {C({{"type", "reduced_gg"}, {"grid", 48}}), BAD}, - {C({{"type", "reduced_gg"}}), BAD}, - {C({{"type", "reduced_latlon"}, {"grid", 2}}), BAD}, - {C({{"type", "reduced_ll"}, {"grid", 12}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "48"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "F048"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "F48"}}), C({{"type", "regular_gg"}})}, - {C({{"type", "regular_gg"}, {"grid", "N48"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "O48"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "a"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", 48}}), BAD}, - {C({{"type", "regular_ll"}, {"area", v{90, -180, -90, 180}}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", "F48"}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", "a"}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", 48}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", std::vector{"a", "b"}}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", v{1, 2, 3}}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", v{1, 2}}}), C({{"type", "regular_ll"}})}, - {C({{"type", "regular_ll"}, {"grid", v{1}}}), BAD}, - - {C({{"type", "mercator"}, - {"area", v{31.173058, 262.036499, 14.736453, 284.975281}}, - {"grid", v{45000.0, 45000.0}}, - {"lad", 14.0}, - {"nx", 56}, - {"ny", 44}, - {"orientation", 0.0}}), - C()}, - }; - - SECTION("user -> type") { - for (const auto& [user, gridspec] : cases) { + using C = spec::Custom; + using v = std::vector; + + static const C BAD; + ASSERT(BAD.empty()); + + static std::pair tests[]{ + {C({{"N", 2}}), C({{"N", 2}, {"type", "reduced_gg"}})}, + {C({{"area", v{90, -180, -90, 180}}, {"grid", v{2, 2}}}), C({{"type", "regular_ll"}})}, + {C({{"area", v{90, -180, -90, 180}}}), BAD}, + {C({{"grid", "B48"}}), BAD}, + {C({{"grid", "F48"}}), C({{"type", "regular_gg"}})}, + {C({{"grid", "N48"}}), C({{"type", "reduced_gg"}})}, + {C({{"grid", "O48"}}), C({{"type", "reduced_gg"}})}, + {C({{"grid", 48}}), BAD}, + {C({{"grid", v{2, 2}}}), C({{"grid", v{2, 2}}, {"type", "regular_ll"}})}, + {C({{"type", "latlon"}, {"grid", v{2, 2}}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "48"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "F048"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "N"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "N048"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "N48"}}), C({{"type", "reduced_gg"}})}, + {C({{"type", "reduced_gg"}, {"grid", "O048"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "O48"}}), C({{"type", "reduced_gg"}})}, + {C({{"type", "reduced_gg"}, {"grid", 48}}), BAD}, + {C({{"type", "reduced_gg"}}), BAD}, + {C({{"type", "reduced_latlon"}, {"grid", 2}}), BAD}, + {C({{"type", "reduced_ll"}, {"grid", 12}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "48"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "F048"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "F48"}}), C({{"type", "regular_gg"}})}, + {C({{"type", "regular_gg"}, {"grid", "N48"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "O48"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "a"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", 48}}), BAD}, + {C({{"type", "regular_ll"}, {"area", v{90, -180, -90, 180}}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", "F48"}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", "a"}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", 48}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", std::vector{"a", "b"}}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", v{1, 2, 3}}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", v{1, 2}}}), C({{"type", "regular_ll"}})}, + {C({{"type", "regular_ll"}, {"grid", v{1}}}), BAD}, + + {C({{"type", "mercator"}, + {"area", v{31.173058, 262.036499, 14.736453, 284.975281}}, + {"grid", v{45000.0, 45000.0}}, + {"lad", 14.0}, + {"nx", 56}, + {"ny", 44}, + {"orientation", 0.0}}), + C()}, + }; + + for (const auto& [user, gridspec] : tests) { Log::info() << user << " -> " << gridspec << std::endl; try { - S spec(GridFactory::spec(user)); + std::unique_ptr spec(GridFactory::spec(user)); EXPECT(spec); - G grid(GridFactory::build(*spec)); + std::unique_ptr grid(GridFactory::build(*spec)); EXPECT(grid); } catch (const SpecNotFound& e) { @@ -318,6 +313,15 @@ CASE("spec") { } } } + + + SECTION("user -> spec -> str") { + std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", "SMUFF-OPERA-2km"}}))); + EXPECT(grid); + + auto gridspec = grid->spec(); + EXPECT(gridspec == R"({"grid":"SMUFF-OPERA-2km"})"); + } } From da7215b6ca1731682515c0c46acb834d392b96d5 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 22 Feb 2024 17:56:09 +0000 Subject: [PATCH 516/737] eckit::geo::Grid --- src/eckit/geo/spec/Generator.h | 19 +++++++++++++++---- tests/geo/spec.cc | 12 +++++++----- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/eckit/geo/spec/Generator.h b/src/eckit/geo/spec/Generator.h index aece035b7..b48d0039c 100644 --- a/src/eckit/geo/spec/Generator.h +++ b/src/eckit/geo/spec/Generator.h @@ -69,12 +69,23 @@ class GeneratorT { const generator_t& match(const std::string&) const; bool match(const Custom& spec, std::string& name) const { - for (const auto& [another_name, another_spec] : store_) { - if (another_spec->match(spec)) { - name = another_name; - return true; + auto end = store_.cend(); + auto i = end; + for (auto j = store_.cbegin(); j != end; ++j) { + if (!(j->first.empty()) && j->second->match(spec)) { + if (i != end) { + throw SeriousBug("Generator matches names '" + i->first + "' and '" + j->first + "'"); + } + i = j; } } + + if (i != end) { + name = i->first; + ASSERT(!name.empty()); + return true; + } + return false; } diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 72d59e7e6..fa28e5dc4 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -315,12 +315,14 @@ CASE("spec") { } - SECTION("user -> spec -> str") { - std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", "SMUFF-OPERA-2km"}}))); - EXPECT(grid); + SECTION("grid: name -> spec -> grid: name") { + for (const std::string name : {"LAEA-EFAS-5km", "SMUFF-OPERA-2km"}) { + std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", name}}))); + EXPECT(grid); - auto gridspec = grid->spec(); - EXPECT(gridspec == R"({"grid":"SMUFF-OPERA-2km"})"); + auto gridspec = grid->spec(); + EXPECT(gridspec == R"({"grid":")" + name + R"("})"); + } } } From ab19af666574d850db8a16ac3487ffefbe54ad53 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 23 Feb 2024 09:38:53 +0000 Subject: [PATCH 517/737] eckit::geo::Range --- src/eckit/geo/grid/regular/RegularLL.cc | 106 +++--------------------- src/eckit/geo/range/Regular.cc | 61 +++++++++++++- src/eckit/geo/range/Regular.h | 24 ++++++ 3 files changed, 95 insertions(+), 96 deletions(-) diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index d45ebe846..58852eb78 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -15,110 +15,19 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Increments.h" #include "eckit/geo/iterator/Regular.h" +#include "eckit/geo/range/Regular.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util/regex.h" -#include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" namespace eckit::geo::grid::regular { -namespace { - - -struct DiscreteRange { - DiscreteRange(double _a, double _b, double _inc, double _ref) : - DiscreteRange(Fraction{_a}, Fraction{_b}, Fraction{_inc}, Fraction{_ref}) {} - - DiscreteRange(double _a, double _b, double _inc, double _ref, double period) : - DiscreteRange(Fraction{_a}, Fraction{_b}, Fraction{_inc}, Fraction{_ref}, Fraction{period}) {} - - DiscreteRange(const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref) : - inc(_inc), periodic(false) { - ASSERT(_a <= _b); - ASSERT(_inc >= 0); - - auto adjust = [](const Fraction& target, const Fraction& inc, bool up) -> Fraction { - ASSERT(inc > 0); - - auto r = target / inc; - auto n = r.integralPart(); - - if (!r.integer() && (r > 0) == up) { - n += (up ? 1 : -1); - } - - return n * inc; - }; - - if (inc == 0) { - b = a = _a; - n = 1; - return; - } - - auto shift = (_ref / inc).decimalPart() * _inc; - a = shift + adjust(_a - shift, inc, true); - - if (_b == _a) { - b = a; - } - else { - auto c = shift + adjust(_b - shift, inc, false); - c = a + ((c - a) / inc).integralPart() * inc; - b = c < a ? a : c; - } - - n = static_cast(((b - a) / inc).integralPart() + 1); - - ASSERT(a <= b); - ASSERT(n >= 1); - } - - DiscreteRange( - const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref, const Fraction& period) : - DiscreteRange(_a, _b, _inc, _ref) { - ASSERT(period > 0); - - if ((n - 1) * inc >= period) { - n -= 1; - ASSERT(n * inc == period || (n - 1) * inc < period); - - b = a + (n - 1) * inc; - } - - if (n * inc == period) { - periodic = true; - b = a + n * inc; - } - } - - Fraction a; - Fraction b; - Fraction inc; - size_t n; - bool periodic; -}; - - -PointLonLat reference_from_spec(const Spec& spec) { - if (double lon = 0, lat = 0; spec.get("reference_lon", lon) && spec.get("reference_lat", lat)) { - return {lon, lat}; - } - - area::BoundingBox area(spec); - return {area.west, area.south}; -} - - -} // namespace - - RegularLL::Internal::Internal(const Increments& _inc, const area::BoundingBox& _bbox, const PointLonLat& _ref) : inc(_inc), bbox(_bbox) { - const DiscreteRange lon(bbox.west, bbox.east, inc.west_east, _ref.lon, 360); - const DiscreteRange lat(bbox.south, bbox.north, inc.south_north, _ref.lat); + const range::DiscreteRange lon(bbox.west, bbox.east, inc.west_east, _ref.lon, 360); + const range::DiscreteRange lat(bbox.south, bbox.north, inc.south_north, _ref.lat); ni = lon.n; nj = lat.n; @@ -130,7 +39,14 @@ RegularLL::Internal::Internal(const Increments& _inc, const area::BoundingBox& _ RegularLL::RegularLL(const Spec& spec) : - RegularLL(Increments{spec}, area::BoundingBox{spec}, reference_from_spec(spec)) {} + RegularLL(Increments{spec}, area::BoundingBox{spec}, [&spec]() -> PointLonLat { + if (double lon = 0., lat = 0.; spec.get("reference_lon", lon) && spec.get("reference_lat", lat)) { + return {lon, lat}; + } + + area::BoundingBox area{spec}; + return {area.west, area.south}; + }()) {} RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc index 870d81091..9503a0a05 100644 --- a/src/eckit/geo/range/Regular.cc +++ b/src/eckit/geo/range/Regular.cc @@ -17,7 +17,6 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/util.h" #include "eckit/geo/util/mutex.h" -#include "eckit/types/Fraction.h" namespace eckit::geo::range { @@ -56,5 +55,65 @@ Fraction Regular::adjust(const Fraction& target, const Fraction& inc, bool up) { return n * inc; } +DiscreteRange::DiscreteRange(const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref) : + inc(_inc), periodic(false) { + ASSERT(_a <= _b); + ASSERT(_inc >= 0); + + auto adjust = [](const Fraction& target, const Fraction& inc, bool up) -> Fraction { + ASSERT(inc > 0); + + auto r = target / inc; + auto n = r.integralPart(); + + if (!r.integer() && (r > 0) == up) { + n += (up ? 1 : -1); + } + + return n * inc; + }; + + if (inc == 0) { + b = a = _a; + n = 1; + return; + } + + auto shift = (_ref / inc).decimalPart() * _inc; + a = shift + adjust(_a - shift, inc, true); + + if (_b == _a) { + b = a; + } + else { + auto c = shift + adjust(_b - shift, inc, false); + c = a + ((c - a) / inc).integralPart() * inc; + b = c < a ? a : c; + } + + n = static_cast(((b - a) / inc).integralPart() + 1); + + ASSERT(a <= b); + ASSERT(n >= 1); +} + +DiscreteRange::DiscreteRange( + const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref, const Fraction& period) : + DiscreteRange(_a, _b, _inc, _ref) { + ASSERT(period > 0); + + if ((n - 1) * inc >= period) { + n -= 1; + ASSERT(n * inc == period || (n - 1) * inc < period); + + b = a + (n - 1) * inc; + } + + if (n * inc == period) { + periodic = true; + b = a + n * inc; + } +} + } // namespace eckit::geo::range diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h index 4e74ed8ec..13429ba3f 100644 --- a/src/eckit/geo/range/Regular.h +++ b/src/eckit/geo/range/Regular.h @@ -13,11 +13,35 @@ #pragma once #include "eckit/geo/Range.h" +#include "eckit/types/Fraction.h" namespace eckit::geo::range { +class DiscreteRange { +public: + DiscreteRange(double _a, double _b, double _inc, double _ref) : + DiscreteRange(Fraction{_a}, Fraction{_b}, Fraction{_inc}, Fraction{_ref}) {} + + DiscreteRange(double _a, double _b, double _inc, double _ref, double period) : + DiscreteRange(Fraction{_a}, Fraction{_b}, Fraction{_inc}, Fraction{_ref}, Fraction{period}) {} + +private: + DiscreteRange(const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref); + + DiscreteRange( + const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref, const Fraction& period); + +public: + Fraction a; + Fraction b; + Fraction inc; + size_t n; + bool periodic; +}; + + class Regular : public Range { public: // -- Methods From bf114d1a3a121df8716c040d6b3953c5b02e46a3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 23 Feb 2024 09:47:57 +0000 Subject: [PATCH 518/737] eckit::geo::Range --- src/eckit/geo/range/Regular.cc | 46 ++++++++++++++++++---------------- src/eckit/geo/range/Regular.h | 17 +++---------- 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc index 9503a0a05..8c65c9208 100644 --- a/src/eckit/geo/range/Regular.cc +++ b/src/eckit/geo/range/Regular.cc @@ -46,19 +46,10 @@ Regular::Regular(size_t n, double a, double b, std::vector&& values, boo Range(n, a, b, eps), values_(values), periodic_(periodic) {} -Fraction Regular::adjust(const Fraction& target, const Fraction& inc, bool up) { - ASSERT(inc > 0); - - auto r = target / inc; - auto n = r.integralPart() + ((r.integer() || (r > 0) != up) ? 0 : up ? 1 : -1); - - return n * inc; -} - -DiscreteRange::DiscreteRange(const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref) : - inc(_inc), periodic(false) { - ASSERT(_a <= _b); - ASSERT(_inc >= 0); +DiscreteRange::DiscreteRange(double _a, double _b, double _inc, double _ref) : + a(_a), b(_b), inc(_inc), periodic(false) { + ASSERT(_a <= _b && a <= b); + ASSERT(0 <= _inc && 0 <= inc); auto adjust = [](const Fraction& target, const Fraction& inc, bool up) -> Fraction { ASSERT(inc > 0); @@ -74,19 +65,19 @@ DiscreteRange::DiscreteRange(const Fraction& _a, const Fraction& _b, const Fract }; if (inc == 0) { - b = a = _a; - n = 1; + b = a; + n = 1; return; } - auto shift = (_ref / inc).decimalPart() * _inc; - a = shift + adjust(_a - shift, inc, true); + auto shift = (Fraction(_ref) / inc).decimalPart() * inc; + a = shift + adjust(a - shift, inc, true); - if (_b == _a) { + if (b == a) { b = a; } else { - auto c = shift + adjust(_b - shift, inc, false); + auto c = shift + adjust(b - shift, inc, false); c = a + ((c - a) / inc).integralPart() * inc; b = c < a ? a : c; } @@ -94,12 +85,13 @@ DiscreteRange::DiscreteRange(const Fraction& _a, const Fraction& _b, const Fract n = static_cast(((b - a) / inc).integralPart() + 1); ASSERT(a <= b); - ASSERT(n >= 1); + ASSERT(1 <= n); } -DiscreteRange::DiscreteRange( - const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref, const Fraction& period) : + +DiscreteRange::DiscreteRange(double _a, double _b, double _inc, double _ref, double _period) : DiscreteRange(_a, _b, _inc, _ref) { + Fraction period(_period); ASSERT(period > 0); if ((n - 1) * inc >= period) { @@ -116,4 +108,14 @@ DiscreteRange::DiscreteRange( } +Fraction Regular::adjust(const Fraction& target, const Fraction& inc, bool up) { + ASSERT(inc > 0); + + auto r = target / inc; + auto n = r.integralPart() + ((r.integer() || (r > 0) != up) ? 0 : up ? 1 : -1); + + return n * inc; +} + + } // namespace eckit::geo::range diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h index 13429ba3f..7a6125e30 100644 --- a/src/eckit/geo/range/Regular.h +++ b/src/eckit/geo/range/Regular.h @@ -19,21 +19,10 @@ namespace eckit::geo::range { -class DiscreteRange { -public: - DiscreteRange(double _a, double _b, double _inc, double _ref) : - DiscreteRange(Fraction{_a}, Fraction{_b}, Fraction{_inc}, Fraction{_ref}) {} - - DiscreteRange(double _a, double _b, double _inc, double _ref, double period) : - DiscreteRange(Fraction{_a}, Fraction{_b}, Fraction{_inc}, Fraction{_ref}, Fraction{period}) {} - -private: - DiscreteRange(const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref); - - DiscreteRange( - const Fraction& _a, const Fraction& _b, const Fraction& _inc, const Fraction& _ref, const Fraction& period); +struct DiscreteRange { + DiscreteRange(double a, double b, double inc, double ref); + DiscreteRange(double a, double b, double inc, double ref, double period); -public: Fraction a; Fraction b; Fraction inc; From c2484a90552df4c7a86b11c0a3d6ea206a6d9b53 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 23 Feb 2024 13:58:35 +0000 Subject: [PATCH 519/737] eckit::geo::Range --- src/eckit/geo/Range.cc | 10 --- src/eckit/geo/Range.h | 5 -- src/eckit/geo/grid/regular/RegularLL.cc | 28 ++------ src/eckit/geo/grid/regular/RegularLL.h | 17 ----- src/eckit/geo/range/Regular.cc | 94 +++++++------------------ src/eckit/geo/range/Regular.h | 23 +++--- src/eckit/geo/range/RegularLatitude.cc | 19 ++--- src/eckit/geo/range/RegularLatitude.h | 3 +- src/eckit/geo/range/RegularLongitude.cc | 19 ++++- src/eckit/geo/range/RegularLongitude.h | 3 +- 10 files changed, 74 insertions(+), 147 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index ba71575b8..a30e92df9 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -12,15 +12,8 @@ #include "eckit/geo/Range.h" -#include -#include - #include "eckit/exception/Exceptions.h" -#include "eckit/geo/PointLonLat.h" -#include "eckit/geo/util.h" -#include "eckit/geo/util/mutex.h" #include "eckit/types/FloatCompare.h" -#include "eckit/types/Fraction.h" namespace eckit::geo { @@ -43,7 +36,4 @@ void Range::resize(size_t n) { } -namespace range {} // namespace range - - } // namespace eckit::geo diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 08b8e5120..f6a16569b 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -15,11 +15,6 @@ #include -namespace eckit { -class Fraction; -} - - namespace eckit::geo { diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index 58852eb78..88776c90c 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -15,29 +15,17 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Increments.h" #include "eckit/geo/iterator/Regular.h" -#include "eckit/geo/range/Regular.h" +#include "eckit/geo/range/RegularLatitude.h" +#include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util/regex.h" +#include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" namespace eckit::geo::grid::regular { -RegularLL::Internal::Internal(const Increments& _inc, const area::BoundingBox& _bbox, const PointLonLat& _ref) : - inc(_inc), bbox(_bbox) { - const range::DiscreteRange lon(bbox.west, bbox.east, inc.west_east, _ref.lon, 360); - const range::DiscreteRange lat(bbox.south, bbox.north, inc.south_north, _ref.lat); - - ni = lon.n; - nj = lat.n; - ASSERT(ni > 0); - ASSERT(nj > 0); - - bbox = {lat.b, lon.a, lat.a, lon.b}; -} - - RegularLL::RegularLL(const Spec& spec) : RegularLL(Increments{spec}, area::BoundingBox{spec}, [&spec]() -> PointLonLat { if (double lon = 0., lat = 0.; spec.get("reference_lon", lon) && spec.get("reference_lat", lat)) { @@ -54,13 +42,9 @@ RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& ref) : - RegularLL(Internal{inc, bbox, ref}) {} - - -RegularLL::RegularLL(Internal&& internal) : - Regular(internal.bbox), - lon_(internal.ni, internal.bbox.west, internal.bbox.east), - lat_(internal.nj, internal.bbox.north, internal.bbox.south) { + Regular(bbox), + lon_(inc.west_east, bbox.west, bbox.east, ref.lon), + lat_(inc.south_north, bbox.north, bbox.south, ref.lat) { ASSERT(size() > 0); } diff --git a/src/eckit/geo/grid/regular/RegularLL.h b/src/eckit/geo/grid/regular/RegularLL.h index f43dacf81..1327d9e4c 100644 --- a/src/eckit/geo/grid/regular/RegularLL.h +++ b/src/eckit/geo/grid/regular/RegularLL.h @@ -26,23 +26,6 @@ namespace eckit::geo::grid::regular { class RegularLL final : public Regular { -private: - // -- Types - - struct Internal { - Internal(const Increments&, const area::BoundingBox&, const PointLonLat& _ref); - - Increments inc; - area::BoundingBox bbox; - - size_t ni = 0; - size_t nj = 0; - }; - - // -- Constructors - - explicit RegularLL(Internal&&); - public: // -- Types // None diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc index 8c65c9208..281fa3bd5 100644 --- a/src/eckit/geo/range/Regular.cc +++ b/src/eckit/geo/range/Regular.cc @@ -17,12 +17,36 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/util.h" #include "eckit/geo/util/mutex.h" +#include "eckit/types/Fraction.h" namespace eckit::geo::range { -static util::recursive_mutex MUTEX; +Regular::Regular(double _inc, double _a, double _b, double _ref, double eps) : + Range(2, _a, _b, eps), periodic_(false) { + ASSERT(0. <= _inc); + + Fraction inc(_inc); + Fraction __a(_a); + Fraction __b(_b); + if (inc == 0 || __b == __a) { + a(__a); + b(__a); + resize(1); + return; + } + + bool up = __a < __b; + auto shift = (Fraction(_ref) / inc).decimalPart() * inc; + auto c = shift + adjust(__b - shift, inc, !up); + + a(shift + adjust(__a - shift, inc, up)); + b(__a + ((c - __a) / inc).integralPart() * inc); + + auto n = static_cast((Fraction::abs(__b - __a) / inc).integralPart() + 1); + resize(n); +} Fraction Regular::increment() const { @@ -30,7 +54,9 @@ Fraction Regular::increment() const { return Fraction(std::abs(b() - a()) / static_cast(periodic() ? size() : (size() - 1))); } + const std::vector& Regular::values() const { + static util::recursive_mutex MUTEX; util::lock_guard lock(MUTEX); if (values_.empty()) { @@ -42,72 +68,6 @@ const std::vector& Regular::values() const { } -Regular::Regular(size_t n, double a, double b, std::vector&& values, bool periodic, double eps) : - Range(n, a, b, eps), values_(values), periodic_(periodic) {} - - -DiscreteRange::DiscreteRange(double _a, double _b, double _inc, double _ref) : - a(_a), b(_b), inc(_inc), periodic(false) { - ASSERT(_a <= _b && a <= b); - ASSERT(0 <= _inc && 0 <= inc); - - auto adjust = [](const Fraction& target, const Fraction& inc, bool up) -> Fraction { - ASSERT(inc > 0); - - auto r = target / inc; - auto n = r.integralPart(); - - if (!r.integer() && (r > 0) == up) { - n += (up ? 1 : -1); - } - - return n * inc; - }; - - if (inc == 0) { - b = a; - n = 1; - return; - } - - auto shift = (Fraction(_ref) / inc).decimalPart() * inc; - a = shift + adjust(a - shift, inc, true); - - if (b == a) { - b = a; - } - else { - auto c = shift + adjust(b - shift, inc, false); - c = a + ((c - a) / inc).integralPart() * inc; - b = c < a ? a : c; - } - - n = static_cast(((b - a) / inc).integralPart() + 1); - - ASSERT(a <= b); - ASSERT(1 <= n); -} - - -DiscreteRange::DiscreteRange(double _a, double _b, double _inc, double _ref, double _period) : - DiscreteRange(_a, _b, _inc, _ref) { - Fraction period(_period); - ASSERT(period > 0); - - if ((n - 1) * inc >= period) { - n -= 1; - ASSERT(n * inc == period || (n - 1) * inc < period); - - b = a + (n - 1) * inc; - } - - if (n * inc == period) { - periodic = true; - b = a + n * inc; - } -} - - Fraction Regular::adjust(const Fraction& target, const Fraction& inc, bool up) { ASSERT(inc > 0); diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h index 7a6125e30..12bb3ead1 100644 --- a/src/eckit/geo/range/Regular.h +++ b/src/eckit/geo/range/Regular.h @@ -13,22 +13,14 @@ #pragma once #include "eckit/geo/Range.h" -#include "eckit/types/Fraction.h" -namespace eckit::geo::range { - +namespace eckit { +class Fraction; +} -struct DiscreteRange { - DiscreteRange(double a, double b, double inc, double ref); - DiscreteRange(double a, double b, double inc, double ref, double period); - Fraction a; - Fraction b; - Fraction inc; - size_t n; - bool periodic; -}; +namespace eckit::geo::range { class Regular : public Range { @@ -45,10 +37,13 @@ class Regular : public Range { protected: // -- Constructors - Regular(size_t n, double a, double b, double eps) : + explicit Regular(double inc, double a, double b, double ref, double eps); + + explicit Regular(size_t n, double a, double b, double eps) : Range(n, a, b, eps), periodic_(false) {} - Regular(size_t n, double a, double b, std::vector&&, bool periodic, double eps); + explicit Regular(size_t n, double a, double b, std::vector&& values, bool periodic, double eps) : + Range(n, a, b, eps), values_(values), periodic_(periodic) {} // -- Methods diff --git a/src/eckit/geo/range/RegularLatitude.cc b/src/eckit/geo/range/RegularLatitude.cc index e68a0b839..0250ee4b7 100644 --- a/src/eckit/geo/range/RegularLatitude.cc +++ b/src/eckit/geo/range/RegularLatitude.cc @@ -20,13 +20,14 @@ namespace eckit::geo::range { -static constexpr auto DB = 1e-12; +RegularLatitude::RegularLatitude(double _inc, double _a, double _b, double _ref, double _eps) : + Regular(_inc, _a, _b, _ref, _eps) {} RegularLatitude::RegularLatitude(size_t n, double _a, double _b, double _eps) : Regular(n, _a, _b, _eps) { - ASSERT(-90 <= a() && a() <= 90); - ASSERT(-90 <= b() && b() <= 90); + ASSERT(-90. <= a() && a() <= 90.); + ASSERT(-90. <= b() && b() <= 90.); } @@ -40,15 +41,15 @@ Range* RegularLatitude::crop(double crop_a, double crop_b) const { else if (a() < b()) { ASSERT(a() <= crop_a && crop_b <= b()); // FIXME do better - auto inc(increment()); - auto d = (a() / inc).decimalPart() * inc; - auto _a = adjust(crop_a - d, inc, true) + d; - auto _b = adjust(crop_b - d, inc, false) + d; + const auto inc(increment()); + const auto d = (a() / inc).decimalPart() * inc; + const auto _a = adjust(crop_a - d, inc, true) + d; + const auto _b = adjust(crop_b - d, inc, false) + d; - auto nf = (_b - _a) / inc; + const auto nf = (_b - _a) / inc; ASSERT(nf.integer()); - auto n = static_cast(nf.integralPart() + 1); + const auto n = static_cast(nf.integralPart() + 1); ASSERT(0 < n && n <= size()); return new RegularLatitude(n, _a, _b, eps()); diff --git a/src/eckit/geo/range/RegularLatitude.h b/src/eckit/geo/range/RegularLatitude.h index d5b3365b4..7c608f0b5 100644 --- a/src/eckit/geo/range/RegularLatitude.h +++ b/src/eckit/geo/range/RegularLatitude.h @@ -22,7 +22,8 @@ class RegularLatitude final : public Regular { public: // -- Constructors - RegularLatitude(size_t n, double a, double b, double eps = 0.); + explicit RegularLatitude(double inc, double a, double b, double ref, double eps = 0.); + explicit RegularLatitude(size_t n, double a, double b, double eps = 0.); // -- Overridden methods diff --git a/src/eckit/geo/range/RegularLongitude.cc b/src/eckit/geo/range/RegularLongitude.cc index 441c7747c..9ef60e863 100644 --- a/src/eckit/geo/range/RegularLongitude.cc +++ b/src/eckit/geo/range/RegularLongitude.cc @@ -23,11 +23,28 @@ namespace eckit::geo::range { -static constexpr auto DB = 1e-12; +RegularLongitude::RegularLongitude(double _inc, double _a, double _b, double _ref, double _eps) : + Regular(_inc, _a, _b, _ref, _eps) { + const Fraction period(360, 1); + const Fraction inc(_inc); + + auto n = size(); + if ((n - 1) * inc >= period) { + n -= 1; + } + + ASSERT(n * inc <= period); + resize(n); + + periodic((n + 1) * inc >= period); + b(Fraction(a()) + n * inc); +} RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) : Regular(n, _a, _b, _eps) { + static constexpr auto DB = 1e-12; + if (a() < b()) { auto new_b = PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB; if (types::is_approximately_lesser_or_equal(360., (new_b - a()) * (1. + 1. / static_cast(n)))) { diff --git a/src/eckit/geo/range/RegularLongitude.h b/src/eckit/geo/range/RegularLongitude.h index 33840e40e..75ab26a98 100644 --- a/src/eckit/geo/range/RegularLongitude.h +++ b/src/eckit/geo/range/RegularLongitude.h @@ -24,7 +24,8 @@ class RegularLongitude final : public Regular { public: // -- Constructors - RegularLongitude(size_t n, double a, double b, double eps = 0.); + explicit RegularLongitude(double inc, double a, double b, double ref, double eps = 0.); + explicit RegularLongitude(size_t n, double a, double b, double eps = 0.); // -- Overridden methods From 6332f4a69482a72bac952e66fd28655fc3767901 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 23 Feb 2024 16:00:22 +0000 Subject: [PATCH 520/737] eckit::geo::Range --- src/eckit/geo/grid/regular/RegularLL.cc | 8 +++-- src/eckit/geo/range/Regular.h | 4 +-- src/eckit/geo/range/RegularCartesian.h | 2 +- src/eckit/geo/range/RegularLatitude.cc | 2 +- src/eckit/geo/range/RegularLongitude.cc | 39 ++++++------------------- src/eckit/geo/range/RegularLongitude.h | 3 ++ tests/geo/range.cc | 24 +++++++++------ 7 files changed, 36 insertions(+), 46 deletions(-) diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index 88776c90c..e41a83c3e 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -34,7 +34,9 @@ RegularLL::RegularLL(const Spec& spec) : area::BoundingBox area{spec}; return {area.west, area.south}; - }()) {} + }()) { + ASSERT(size() > 0); +} RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : @@ -43,8 +45,8 @@ RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& ref) : Regular(bbox), - lon_(inc.west_east, bbox.west, bbox.east, ref.lon), - lat_(inc.south_north, bbox.north, bbox.south, ref.lat) { + lon_(inc.west_east, bbox.west, bbox.east, ref.lon, 0.), + lat_(inc.south_north, bbox.north, bbox.south, ref.lat, 0.) { ASSERT(size() > 0); } diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h index 12bb3ead1..0a0ebc2ca 100644 --- a/src/eckit/geo/range/Regular.h +++ b/src/eckit/geo/range/Regular.h @@ -39,8 +39,8 @@ class Regular : public Range { explicit Regular(double inc, double a, double b, double ref, double eps); - explicit Regular(size_t n, double a, double b, double eps) : - Range(n, a, b, eps), periodic_(false) {} + explicit Regular(size_t n, double a, double b, bool periodic, double eps) : + Range(n, a, b, eps), periodic_(periodic) {} explicit Regular(size_t n, double a, double b, std::vector&& values, bool periodic, double eps) : Range(n, a, b, eps), values_(values), periodic_(periodic) {} diff --git a/src/eckit/geo/range/RegularCartesian.h b/src/eckit/geo/range/RegularCartesian.h index 72b768275..b790d0f57 100644 --- a/src/eckit/geo/range/RegularCartesian.h +++ b/src/eckit/geo/range/RegularCartesian.h @@ -23,7 +23,7 @@ class RegularCartesian final : public Regular { // -- Constructors RegularCartesian(size_t n, double a, double b, double eps = 0.) : - Regular(n, a, b, eps) {} + Regular(n, a, b, false, eps) {} // -- Overridden methods diff --git a/src/eckit/geo/range/RegularLatitude.cc b/src/eckit/geo/range/RegularLatitude.cc index 0250ee4b7..4890962c8 100644 --- a/src/eckit/geo/range/RegularLatitude.cc +++ b/src/eckit/geo/range/RegularLatitude.cc @@ -25,7 +25,7 @@ RegularLatitude::RegularLatitude(double _inc, double _a, double _b, double _ref, RegularLatitude::RegularLatitude(size_t n, double _a, double _b, double _eps) : - Regular(n, _a, _b, _eps) { + Regular(n, _a, _b, false, _eps) { ASSERT(-90. <= a() && a() <= 90.); ASSERT(-90. <= b() && b() <= 90.); } diff --git a/src/eckit/geo/range/RegularLongitude.cc b/src/eckit/geo/range/RegularLongitude.cc index 9ef60e863..444014db4 100644 --- a/src/eckit/geo/range/RegularLongitude.cc +++ b/src/eckit/geo/range/RegularLongitude.cc @@ -13,9 +13,9 @@ #include "eckit/geo/range/RegularLongitude.h" #include +#include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/PointLonLat.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" @@ -23,49 +23,28 @@ namespace eckit::geo::range { +static const Fraction PERIOD(360, 1); + + RegularLongitude::RegularLongitude(double _inc, double _a, double _b, double _ref, double _eps) : Regular(_inc, _a, _b, _ref, _eps) { - const Fraction period(360, 1); const Fraction inc(_inc); auto n = size(); - if ((n - 1) * inc >= period) { + if ((n - 1) * inc >= PERIOD) { n -= 1; } - ASSERT(n * inc <= period); + ASSERT(n * inc <= PERIOD); resize(n); - periodic((n + 1) * inc >= period); + periodic((n + 1) * inc >= PERIOD); b(Fraction(a()) + n * inc); } RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) : - Regular(n, _a, _b, _eps) { - static constexpr auto DB = 1e-12; - - if (a() < b()) { - auto new_b = PointLonLat::normalise_angle_to_minimum(b() - DB, a()) + DB; - if (types::is_approximately_lesser_or_equal(360., (new_b - a()) * (1. + 1. / static_cast(n)))) { - periodic(true); - b(a() + 360.); - } - else { - b(new_b); - } - } - else { - auto new_b = PointLonLat::normalise_angle_to_maximum(b() + DB, a()) - DB; - if (types::is_approximately_lesser_or_equal(360., (a() - new_b) * (1. + 1. / static_cast(n)))) { - periodic(true); - b(a() - 360.); - } - else { - b(new_b); - } - } -} + Regular(n, _a, _b, types::is_approximately_lesser_or_equal(PERIOD, std::abs(_b - _a)), _eps) {} Range* RegularLongitude::crop(double crop_a, double crop_b) const { @@ -86,7 +65,7 @@ Range* RegularLongitude::crop(double crop_a, double crop_b) const { auto nf = (_b - _a) / inc; ASSERT(nf.integer()); - auto n = static_cast(nf.integralPart() + (nf * inc >= 360 ? 0 : 1)); + auto n = static_cast(nf.integralPart() + (nf * inc >= PERIOD ? 0 : 1)); ASSERT(0 < n && n <= size()); return new RegularLongitude(n, _a, _b, eps()); diff --git a/src/eckit/geo/range/RegularLongitude.h b/src/eckit/geo/range/RegularLongitude.h index 75ab26a98..e01921996 100644 --- a/src/eckit/geo/range/RegularLongitude.h +++ b/src/eckit/geo/range/RegularLongitude.h @@ -25,6 +25,9 @@ class RegularLongitude final : public Regular { // -- Constructors explicit RegularLongitude(double inc, double a, double b, double ref, double eps = 0.); + explicit RegularLongitude(double inc, double a, double b, double eps = 0.) : + RegularLongitude(inc, a, b, a, eps) {} + explicit RegularLongitude(size_t n, double a, double b, double eps = 0.); // -- Overridden methods diff --git a/tests/geo/range.cc b/tests/geo/range.cc index a6e85134b..3dd1a14e4 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -39,16 +39,22 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) { CASE("range::RegularLongitude") { + SECTION("simple") { + const range::RegularLongitude range(1., -1., 2.); + EXPECT(range.size() == 4); + } + + SECTION("degenerate") { - EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 0.), eckit::AssertionFailed); - EXPECT_THROWS_AS(range::RegularLongitude(0, 0., 10.), eckit::AssertionFailed); + EXPECT_THROWS_AS(range::RegularLongitude(static_cast(0), 0., 0.), eckit::AssertionFailed); + EXPECT_THROWS_AS(range::RegularLongitude(static_cast(0), 0., 10.), eckit::AssertionFailed); - range::RegularLongitude range1(1, 1., 1.); + range::RegularLongitude range1(static_cast(1), 1., 1.); EXPECT(range1.size() == 1); EXPECT(range1.values().front() == 1.); - range::RegularLongitude range2(2, 2., 2.); + range::RegularLongitude range2(static_cast(2), 2., 2.); EXPECT(range2.size() == 1); EXPECT(range2.values().front() == 2.); @@ -56,7 +62,7 @@ CASE("range::RegularLongitude") { SECTION("range [-90, 90]") { - const range::RegularLongitude range(3, -90., 90.); + const range::RegularLongitude range(static_cast(3), -90., 90.); EXPECT(range.size() == 3); @@ -71,7 +77,7 @@ CASE("range::RegularLongitude") { SECTION("range [-180, 180]") { - const range::RegularLongitude range1(4, -180., 180.); + const range::RegularLongitude range1(static_cast(4), -180., 180.); EXPECT(range1.size() == 4); @@ -84,7 +90,7 @@ CASE("range::RegularLongitude") { EXPECT_APPROX(values1[2], 0., EPS); EXPECT_APPROX(values1[3], 90., EPS); - const range::RegularLongitude range2(8, 180., -180.); + const range::RegularLongitude range2(static_cast(8), 180., -180.); EXPECT(range2.size() == 8); @@ -101,7 +107,7 @@ CASE("range::RegularLongitude") { SECTION("range [0, 360], cropped") { - auto range = range::RegularLongitude(36, 0., 360.); + auto range = range::RegularLongitude(static_cast(36), 0., 360.); // const std::unique_ptr range1(range.crop(-180., 180.)); // std::cout << range1->values() << std::endl; @@ -122,7 +128,7 @@ CASE("range::RegularLongitude") { SECTION("range [0, 180], cropped") { - auto range = range::RegularLongitude(19, 0., 180.); + auto range = range::RegularLongitude(static_cast(19), 0., 180.); const std::unique_ptr range1(range.crop(1., 179.)); EXPECT(range1->size() == 19 - 2); From 0d3d5c395221c5f07ceb58c1b32efc720107b7e4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 23 Feb 2024 16:39:52 +0000 Subject: [PATCH 521/737] eckit::geo::Grid --- src/eckit/geo/Range.cc | 6 ++--- src/eckit/geo/grid/regular/RegularLL.h | 4 +-- src/eckit/geo/iterator/Regular.cc | 9 +++---- src/eckit/geo/range/RegularLongitude.cc | 2 +- tests/geo/grid_regular_ll.cc | 36 ++++++++++++++++++++++--- tests/geo/range.cc | 19 ++++++++++--- 6 files changed, 59 insertions(+), 17 deletions(-) diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index a30e92df9..263d1fd97 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -21,8 +21,8 @@ namespace eckit::geo { Range::Range(size_t n, double _a, double _b, double _eps) : n_(n), a_(_a), b_(_b), eps_(_eps) { - ASSERT(n > 0); - ASSERT(eps_ >= 0); + ASSERT(0 < n); + ASSERT(0. <= eps_); if (types::is_approximately_equal(_a, _b)) { n_ = 1; b(_a); @@ -31,7 +31,7 @@ Range::Range(size_t n, double _a, double _b, double _eps) : void Range::resize(size_t n) { - ASSERT(n > 0); + ASSERT(0 < n); n_ = n; } diff --git a/src/eckit/geo/grid/regular/RegularLL.h b/src/eckit/geo/grid/regular/RegularLL.h index 1327d9e4c..c850c7855 100644 --- a/src/eckit/geo/grid/regular/RegularLL.h +++ b/src/eckit/geo/grid/regular/RegularLL.h @@ -56,8 +56,8 @@ class RegularLL final : public Regular { iterator cbegin() const override; iterator cend() const override; - size_t ni() const override { return lat_.size(); } - size_t nj() const override { return lon_.size(); } + size_t ni() const override { return lon_.size(); } + size_t nj() const override { return lat_.size(); } // -- Class members // None diff --git a/src/eckit/geo/iterator/Regular.cc b/src/eckit/geo/iterator/Regular.cc index 06d000b05..691d6290c 100644 --- a/src/eckit/geo/iterator/Regular.cc +++ b/src/eckit/geo/iterator/Regular.cc @@ -27,12 +27,11 @@ Regular::Regular(const Grid& grid, size_t index) : i_(0), j_(0), index_(index), - ni_(grid_.ni()), - nj_(grid_.nj()), + ni_(longitudes_.size()), + nj_(latitudes_.size()), index_size_(ni_ * nj_) { - if (index_ < index_size_) { - ASSERT(latitudes_.size() == grid_.nj()); - } + ASSERT(longitudes_.size() == grid_.ni()); + ASSERT(latitudes_.size() == grid_.nj()); } diff --git a/src/eckit/geo/range/RegularLongitude.cc b/src/eckit/geo/range/RegularLongitude.cc index 444014db4..0c8ba63ad 100644 --- a/src/eckit/geo/range/RegularLongitude.cc +++ b/src/eckit/geo/range/RegularLongitude.cc @@ -39,7 +39,7 @@ RegularLongitude::RegularLongitude(double _inc, double _a, double _b, double _re resize(n); periodic((n + 1) * inc >= PERIOD); - b(Fraction(a()) + n * inc); + b(Fraction(a()) + (periodic() ? n : n - 1) * inc); } diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index ccaf429be..ccab98392 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -20,7 +20,7 @@ namespace eckit::geo::test { -CASE("") { +CASE("global") { std::unique_ptr global(new grid::regular::RegularLL(spec::Custom{{{"grid", std::vector{1, 1}}}})); size_t global_size = global->size(); @@ -32,14 +32,44 @@ CASE("") { size_t local_size = local->size(); EXPECT_EQUAL(local_size, 5 * 10); - std::unique_ptr almost_global(new grid::regular::RegularLL( - spec::Custom{{{"grid", std::vector{1, 1}}, {"area", std::vector{89.5, 0., -89.5, 359.1}}}})); + std::unique_ptr almost_global(new grid::regular::RegularLL({1, 1}, {89.5, 0., -89.5, 359.1})); size_t almost_global_size = almost_global->size(); EXPECT_EQUAL(almost_global_size, 360 * 180); } +CASE("non-global") { + /* + * 1 . . . . + * 0 + * -1 . . . . + * -1 0 1 2 + */ + grid::regular::RegularLL grid({1, 2}, {1, -1, -1, 2}); + + const std::vector ref{ + PointLonLat{-1, 1}, + PointLonLat{0, 1}, + PointLonLat{1, 1}, + PointLonLat{2, 1}, + PointLonLat{-1, -1}, + PointLonLat{0, -1}, + PointLonLat{1, -1}, + PointLonLat{2, -1}, + }; + + auto points = grid.to_points(); + + EXPECT(points.size() == grid.size()); + ASSERT(points.size() == ref.size()); + + for (size_t i = 0; i < points.size(); ++i) { + EXPECT(points_equal(points[i], ref[i])); + } +} + + } // namespace eckit::geo::test diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 3dd1a14e4..674fd00a8 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -17,9 +17,10 @@ #include "eckit/geo/range/RegularLongitude.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" +#include "eckit/types/Fraction.h" -#define EXPECT_APPROX(a, b, eps) EXPECT(::eckit::types::is_approximately_equal((a), (b), (eps))) +#define EXPECT_APPROX(a, b, eps) EXPECT(::eckit::types::is_approximately_equal((a), (b), (eps))) namespace eckit::geo::test { @@ -40,8 +41,20 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) { CASE("range::RegularLongitude") { SECTION("simple") { - const range::RegularLongitude range(1., -1., 2.); - EXPECT(range.size() == 4); + const range::RegularLongitude range1(1., -1., 2.); + + EXPECT(range1.size() == 4); + + EXPECT_APPROX(range1.a(), -1., EPS); + EXPECT_APPROX(range1.b(), 2., EPS); + EXPECT_APPROX(range1.increment(), 1., EPS); + + const auto& values = range1.values(); + + EXPECT_APPROX(values[0], -1., EPS); + EXPECT_APPROX(values[1], 0., EPS); + EXPECT_APPROX(values[2], 1., EPS); + EXPECT_APPROX(values[3], 2., EPS); } From 22a0aeaa3c41b3ecec9745bf5ead0aa73dfc79a1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 24 Feb 2024 01:02:19 +0000 Subject: [PATCH 522/737] eckit::geo::Grid --- src/eckit/geo/range/Regular.cc | 20 +++++++++----------- src/eckit/geo/range/RegularLongitude.cc | 14 +++++--------- tests/geo/grid_regular_ll.cc | 20 ++++++++++---------- tests/geo/range.cc | 21 +++++++++++++++++++++ 4 files changed, 45 insertions(+), 30 deletions(-) diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc index 281fa3bd5..932c1ec13 100644 --- a/src/eckit/geo/range/Regular.cc +++ b/src/eckit/geo/range/Regular.cc @@ -17,6 +17,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/util.h" #include "eckit/geo/util/mutex.h" +#include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" @@ -28,23 +29,20 @@ Regular::Regular(double _inc, double _a, double _b, double _ref, double eps) : ASSERT(0. <= _inc); Fraction inc(_inc); - Fraction __a(_a); - Fraction __b(_b); - if (inc == 0 || __b == __a) { - a(__a); - b(__a); + if (inc == 0 || types::is_approximately_equal(_a, _b)) { + b(_a); resize(1); return; } - bool up = __a < __b; + bool up = _a < _b; auto shift = (Fraction(_ref) / inc).decimalPart() * inc; - auto c = shift + adjust(__b - shift, inc, !up); + auto __a = shift + adjust(Fraction(_a) - shift, inc, up); + auto __b = shift + adjust(Fraction(_b) - shift, inc, !up); + auto n = static_cast((Fraction::abs(__b - __a) / inc).integralPart() + 1); - a(shift + adjust(__a - shift, inc, up)); - b(__a + ((c - __a) / inc).integralPart() * inc); - - auto n = static_cast((Fraction::abs(__b - __a) / inc).integralPart() + 1); + a(__a); + b(__b); resize(n); } diff --git a/src/eckit/geo/range/RegularLongitude.cc b/src/eckit/geo/range/RegularLongitude.cc index 0c8ba63ad..5913fa57e 100644 --- a/src/eckit/geo/range/RegularLongitude.cc +++ b/src/eckit/geo/range/RegularLongitude.cc @@ -28,18 +28,14 @@ static const Fraction PERIOD(360, 1); RegularLongitude::RegularLongitude(double _inc, double _a, double _b, double _ref, double _eps) : Regular(_inc, _a, _b, _ref, _eps) { + ASSERT(_a < _b); // FIXME temporary const Fraction inc(_inc); - auto n = size(); - if ((n - 1) * inc >= PERIOD) { - n -= 1; - } - - ASSERT(n * inc <= PERIOD); - resize(n); + auto n = 1 + (std::min(Fraction(b() - a()), PERIOD) / inc).integralPart(); + periodic(n * inc >= PERIOD); - periodic((n + 1) * inc >= PERIOD); - b(Fraction(a()) + (periodic() ? n : n - 1) * inc); + b(Fraction(a()) + (n - 1) * inc); + resize(periodic() ? (PERIOD / inc).integralPart() : n); } diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index ccab98392..3205fa352 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -21,21 +21,21 @@ namespace eckit::geo::test { CASE("global") { - std::unique_ptr global(new grid::regular::RegularLL(spec::Custom{{{"grid", std::vector{1, 1}}}})); + std::unique_ptr grid1(new grid::regular::RegularLL(spec::Custom{{{"grid", std::vector{1, 1}}}})); - size_t global_size = global->size(); - EXPECT_EQUAL(global_size, 360 * 181); + EXPECT(grid1->size() == 360 * 181); - std::unique_ptr local(new grid::regular::RegularLL( + std::unique_ptr grid2(new grid::regular::RegularLL( spec::Custom{{{"grid", std::vector{2, 1}}, {"area", std::vector{10, 1, 1, 10}}}})); - size_t local_size = local->size(); - EXPECT_EQUAL(local_size, 5 * 10); + EXPECT(grid2->size() == 5 * 10); - std::unique_ptr almost_global(new grid::regular::RegularLL({1, 1}, {89.5, 0., -89.5, 359.1})); - - size_t almost_global_size = almost_global->size(); - EXPECT_EQUAL(almost_global_size, 360 * 180); + for (const auto& grid : {grid::regular::RegularLL({1., 1.}, {89.5, 0.5, -89.5, 359.5}), + grid::regular::RegularLL({1., 1.}, {90., 0., -90, 360.}, {0.5, 0.5})}) { + EXPECT(grid.ni() == 360); + EXPECT(grid.nj() == 180); + EXPECT(grid.size() == 360 * 180); + } } diff --git a/tests/geo/range.cc b/tests/geo/range.cc index 674fd00a8..cdbcefb8c 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -14,6 +14,7 @@ #include #include "eckit/geo/range/GaussianLatitude.h" +#include "eckit/geo/range/RegularLatitude.h" #include "eckit/geo/range/RegularLongitude.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" @@ -55,6 +56,15 @@ CASE("range::RegularLongitude") { EXPECT_APPROX(values[1], 0., EPS); EXPECT_APPROX(values[2], 1., EPS); EXPECT_APPROX(values[3], 2., EPS); + + for (const auto& range : { + range::RegularLongitude(1., 0., 360.), + range::RegularLongitude(1., 0.5, 359.5), + range::RegularLongitude(1., 0., 360., 0.5, 0.), + }) { + EXPECT(range.periodic()); + EXPECT(range.size() == 360); + } } @@ -171,6 +181,17 @@ CASE("range::RegularLongitude") { } +CASE("range::RegularLatitude") { + SECTION("simple") { + const range::RegularLatitude range1(1., 90., -90., 0.5); + + EXPECT(range1.size() == 180); + EXPECT(range1.a() == 89.5); + EXPECT(range1.b() == -89.5); + } +} + + CASE("range::Gaussian") { std::vector ref{59.44440828916676, 19.87571914744090, -19.87571914744090, -59.44440828916676}; From 1b47a41730dc4c9ab450db46c01276763333c01b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 26 Feb 2024 15:42:47 +0000 Subject: [PATCH 523/737] eckit::geo::Grid --- src/eckit/geo/Grid.cc | 23 ++++------ src/eckit/geo/grid/regular/RegularGaussian.cc | 2 +- src/eckit/geo/spec/Layered.cc | 8 ++-- src/eckit/geo/spec/Layered.h | 21 ++++----- tests/geo/grid_regular_gg.cc | 46 ++++++++++++++++--- 5 files changed, 62 insertions(+), 38 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 7320f476e..0616da908 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -162,8 +162,8 @@ Spec* GridFactory::generate_spec_(const Spec& spec) const { // hardcoded, interpreted options (contributing to gridspec) - auto* back = new spec::Custom; - ASSERT(back != nullptr); + auto back = std::make_unique(); + ASSERT(back); if (size_t N = 0; cfg->get("N", N)) { back->set("grid", "O" + std::to_string(N)); @@ -177,24 +177,17 @@ Spec* GridFactory::generate_spec_(const Spec& spec) const { back->set("type", "regular_ll"); } - cfg->push_back(back); - + if (!back->empty()) { + cfg->push_back(back.release()); + } - // configurable options + if (std::string grid; cfg->get("grid", grid) && SpecByName::instance().matches(grid)) { + cfg->push_back(SpecByName::instance().match(grid).spec(grid)); + } if (std::string uid; cfg->get("uid", uid)) { cfg->push_front(SpecByUID::instance().get(uid).spec()); } - else if (std::string grid; cfg->get("grid", grid) && SpecByName::instance().matches(grid)) { - auto* front = SpecByName::instance().match(grid).spec(grid); - ASSERT(front != nullptr); - - if (std::string user, forced; front->get("type", forced) && cfg->get("type", user) && user != forced) { - throw BadParameter("Grid: conflicting 'type': '" + user + "' and '" + forced + "'"); - } - - cfg->push_front(front); - } // finalise diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index 379db5efa..605fc612a 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -58,7 +58,7 @@ const std::vector& RegularGaussian::longitudes() const { const std::vector& RegularGaussian::latitudes() const { - return x_->values(); + return y_->values(); } diff --git a/src/eckit/geo/spec/Layered.cc b/src/eckit/geo/spec/Layered.cc index 5058843e7..d1b4e0164 100644 --- a/src/eckit/geo/spec/Layered.cc +++ b/src/eckit/geo/spec/Layered.cc @@ -42,13 +42,13 @@ void Layered::unhide(const std::string& name) { void Layered::push_back(Spec* spec) { ASSERT(spec != nullptr); - after_.emplace_back(spec); + back_.emplace_back(spec); } void Layered::push_front(Spec* spec) { ASSERT(spec != nullptr); - before_.emplace_back(spec); + front_.emplace_back(spec); } @@ -65,7 +65,7 @@ void Layered::print(std::ostream& out) const { j << "before"; j.startList(); - for (const auto& spec : before_) { + for (const auto& spec : front_) { spec->json(j); } j.endList(); @@ -75,7 +75,7 @@ void Layered::print(std::ostream& out) const { j << "after"; j.startList(); - for (const auto& spec : after_) { + for (const auto& spec : back_) { spec->json(j); } j.endList(); diff --git a/src/eckit/geo/spec/Layered.h b/src/eckit/geo/spec/Layered.h index ab58ea971..7a49522d5 100644 --- a/src/eckit/geo/spec/Layered.h +++ b/src/eckit/geo/spec/Layered.h @@ -39,11 +39,10 @@ class Layered final : public Spec { bool has(const std::string& name) const override { return !hide_.contains(name) && - (std::any_of(before_.begin(), - before_.end(), - [&](const decltype(before_)::value_type& c) { return c->has(name); }) || - spec_.has(name) || - std::any_of(after_.begin(), after_.end(), [&](const decltype(after_)::value_type& c) { + (std::any_of(front_.begin(), + front_.end(), + [&](const decltype(front_)::value_type& c) { return c->has(name); }) || + spec_.has(name) || std::any_of(back_.begin(), back_.end(), [&](const decltype(back_)::value_type& c) { return c->has(name); })); } @@ -72,19 +71,19 @@ class Layered final : public Spec { } hide_; const Spec& spec_; - std::vector> before_; - std::vector> after_; + std::vector> front_; + std::vector> back_; // -- Methods template bool __get(const std::string& name, T& value) const { return !hide_.contains(name) && - (std::any_of(before_.begin(), - before_.end(), - [&](const decltype(before_)::value_type& c) { return c->get(name, value); }) || + (std::any_of(front_.rbegin(), + front_.rend(), + [&](const decltype(front_)::value_type& c) { return c->get(name, value); }) || spec_.get(name, value) || - std::any_of(after_.begin(), after_.end(), [&](const decltype(after_)::value_type& c) { + std::any_of(back_.begin(), back_.end(), [&](const decltype(back_)::value_type& c) { return c->get(name, value); })); } diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index 3789812e2..10498726e 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -23,17 +23,49 @@ namespace eckit::geo::test { CASE("RegularGaussian") { - SECTION("gridspec") { - struct { - std::string name; + SECTION("sizes") { + struct test_t { + explicit test_t(size_t N) : + N(N), size(4 * N * 2 * N) {} + size_t N; size_t size; - } tests[]{{"f2", 32}}; + } tests[]{test_t{2}, test_t{3}, test_t{64}}; for (const auto& test : tests) { - std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", test.name}}))); + std::unique_ptr grid1( + GridFactory::build(spec::Custom({{"grid", "f" + std::to_string(test.N)}}))); + std::unique_ptr grid2( + GridFactory::build(spec::Custom({{"type", "regular_gg"}, {"N", test.N}}))); + grid::regular::RegularGaussian grid3(test.N); + + EXPECT(grid1->size() == test.size); + EXPECT(grid2->size() == test.size); + EXPECT(grid3.size() == test.size); + } + } + + + SECTION("points") { + grid::regular::RegularGaussian grid(1); + + const std::vector ref{ + PointLonLat{0., 35.264389683}, + PointLonLat{90., 35.264389683}, + PointLonLat{180., 35.264389683}, + PointLonLat{270., 35.264389683}, + PointLonLat{0., -35.264389683}, + PointLonLat{90., -35.264389683}, + PointLonLat{180., -35.264389683}, + PointLonLat{270., -35.264389683}, + }; + + auto points = grid.to_points(); + + EXPECT(points.size() == grid.size()); + ASSERT(points.size() == ref.size()); - auto size = grid->size(); - EXPECT_EQUAL(size, test.size); + for (size_t i = 0; i < points.size(); ++i) { + EXPECT(points_equal(points[i], ref[i])); } } From 78dc27effb4335d6333d68dfc54dcb34d93d5810 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 5 Mar 2024 17:28:53 +0000 Subject: [PATCH 524/737] eckit::geo::Grid --- src/eckit/geo/Grid.cc | 10 ++++++++++ src/eckit/geo/Grid.h | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 0616da908..1020c323e 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -114,6 +114,16 @@ Grid* Grid::grid_reorder(Ordering) const { } +Renumber Grid::crop(const Area&) const { + throw NotImplemented("Grid::crop"); +} + + +Grid* Grid::grid_crop(const Area&) const { + throw NotImplemented("Grid::grid_crop"); +} + + Renumber Grid::no_reorder(size_t size) { Renumber ren(size); std::iota(ren.begin(), ren.end(), 0); diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 81a5f251e..73ceef782 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -33,6 +33,7 @@ namespace eckit { class JSON; namespace geo { +class Area; class Spec; namespace spec { class Custom; @@ -133,6 +134,9 @@ class Grid { virtual Renumber reorder(Ordering) const; virtual Grid* grid_reorder(Ordering) const; + virtual Renumber crop(const Area&) const; + virtual Grid* grid_crop(const Area&) const; + // -- Overridden methods // None From 1a43b892b2aab7642269099053de3bfe9051ebaa Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 6 Mar 2024 00:11:13 +0000 Subject: [PATCH 525/737] eckit::geo::Grid --- src/eckit/geo/Grid.cc | 25 +++++++++++--- src/eckit/geo/Grid.h | 7 ++-- src/eckit/geo/grid/reduced/HEALPix.cc | 2 +- src/eckit/geo/grid/reduced/HEALPix.h | 2 +- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 4 +-- src/eckit/geo/grid/regular/RegularGaussian.cc | 10 ++++++ src/eckit/geo/grid/regular/RegularGaussian.h | 2 ++ src/eckit/geo/grid/unstructured/ORCA.cc | 2 +- src/eckit/geo/grid/unstructured/ORCA.h | 2 +- .../grid/unstructured/UnstructuredFromGrid.cc | 5 --- .../grid/unstructured/UnstructuredFromGrid.h | 2 -- tests/geo/grid_regular_gg.cc | 33 +++++++++++-------- 12 files changed, 63 insertions(+), 33 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 1020c323e..febf16300 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -51,11 +51,6 @@ std::string Grid::spec() const { } -const area::BoundingBox& Grid::boundingBox() const { - throw NotImplemented("Grid::boundingBox", Here()); -} - - size_t Grid::size() const { throw NotImplemented("Grid::size", Here()); } @@ -114,6 +109,11 @@ Grid* Grid::grid_reorder(Ordering) const { } +Area* Grid::area() const { + return new area::BoundingBox(bbox_); +} + + Renumber Grid::crop(const Area&) const { throw NotImplemented("Grid::crop"); } @@ -124,6 +124,21 @@ Grid* Grid::grid_crop(const Area&) const { } +area::BoundingBox Grid::boundingBox() const { + return bbox_; +} + + +Renumber Grid::crop(const area::BoundingBox& bbox) const { + return crop(static_cast(bbox)); +} + + +Grid* Grid::grid_crop(const area::BoundingBox& bbox) const { + return grid_crop(static_cast(bbox)); +} + + Renumber Grid::no_reorder(size_t size) { Renumber ren(size); std::iota(ren.begin(), ren.end(), 0); diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 73ceef782..3c8f7b109 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -118,7 +118,6 @@ class Grid { virtual iterator cbegin() const = 0; virtual iterator cend() const = 0; - virtual const area::BoundingBox& boundingBox() const; virtual size_t size() const; virtual uid_t uid() const; @@ -134,9 +133,14 @@ class Grid { virtual Renumber reorder(Ordering) const; virtual Grid* grid_reorder(Ordering) const; + virtual Area* area() const; virtual Renumber crop(const Area&) const; virtual Grid* grid_crop(const Area&) const; + virtual area::BoundingBox boundingBox() const; + virtual Renumber crop(const area::BoundingBox&) const; + virtual Grid* grid_crop(const area::BoundingBox&) const; + // -- Overridden methods // None @@ -154,7 +158,6 @@ class Grid { // -- Methods - area::BoundingBox bbox() const { return bbox_; } void bbox(const area::BoundingBox& bbox) { bbox_ = bbox; } static Renumber no_reorder(size_t size); diff --git a/src/eckit/geo/grid/reduced/HEALPix.cc b/src/eckit/geo/grid/reduced/HEALPix.cc index fefcab6f0..c7aca9ba4 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.cc +++ b/src/eckit/geo/grid/reduced/HEALPix.cc @@ -300,7 +300,7 @@ Spec* HEALPix::spec(const std::string& name) { } -const area::BoundingBox& HEALPix::boundingBox() const { +area::BoundingBox HEALPix::boundingBox() const { static const auto __bbox(area::BoundingBox::make_global_prime()); return __bbox; } diff --git a/src/eckit/geo/grid/reduced/HEALPix.h b/src/eckit/geo/grid/reduced/HEALPix.h index 007e24ce5..910a341c8 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.h +++ b/src/eckit/geo/grid/reduced/HEALPix.h @@ -75,7 +75,7 @@ class HEALPix final : public Reduced { // -- Overridden methods - const area::BoundingBox& boundingBox() const override; + area::BoundingBox boundingBox() const override; size_t size() const override; diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 7018cc322..3c57727b7 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -81,8 +81,8 @@ const std::vector& ReducedGaussian::latitudes() const { std::vector ReducedGaussian::longitudes(size_t j) const { auto Ni = ni(j); if (!x_ || x_->size() != Ni) { - const_cast&>(x_) = - std::make_unique(Ni, bbox().west, bbox().east); + auto bbox = boundingBox(); + const_cast&>(x_) = std::make_unique(Ni, bbox.west, bbox.east); } return x_->values(); diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index 605fc612a..4f76278e9 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -12,6 +12,7 @@ #include "eckit/geo/grid/regular/RegularGaussian.h" +#include "eckit/exception/Exceptions.h" #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/range/GaussianLatitude.h" #include "eckit/geo/range/RegularLongitude.h" @@ -68,6 +69,15 @@ void RegularGaussian::spec(spec::Custom& custom) const { } +Grid* RegularGaussian::grid_crop(const area::BoundingBox& bbox) const { + if (auto intersection(boundingBox()); bbox.intersects(intersection)) { + return new RegularGaussian(N_, bbox); + } + + throw eckit::Exception("RegularGaussian: cannot crop grid (empty intersection)"); +} + + static const GridRegisterType __grid_type("regular_gg"); static const GridRegisterName __grid_pattern("[fF][1-9][0-9]*"); diff --git a/src/eckit/geo/grid/regular/RegularGaussian.h b/src/eckit/geo/grid/regular/RegularGaussian.h index 69eaaffb3..c676e9d3c 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.h +++ b/src/eckit/geo/grid/regular/RegularGaussian.h @@ -77,6 +77,8 @@ class RegularGaussian final : public Regular { void spec(spec::Custom&) const override; + Grid* grid_crop(const area::BoundingBox& bbox) const override; + // -- Class members // None diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index add16755b..8894f7314 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -269,7 +269,7 @@ Grid::iterator ORCA::cend() const { } -const area::BoundingBox& ORCA::boundingBox() const { +area::BoundingBox ORCA::boundingBox() const { static const auto __bbox(area::BoundingBox::make_global_prime()); return __bbox; } diff --git a/src/eckit/geo/grid/unstructured/ORCA.h b/src/eckit/geo/grid/unstructured/ORCA.h index 5b3f95609..5922f6bfe 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.h +++ b/src/eckit/geo/grid/unstructured/ORCA.h @@ -89,7 +89,7 @@ class ORCA final : public Unstructured { iterator cbegin() const override; iterator cend() const override; - const area::BoundingBox& boundingBox() const override; + area::BoundingBox boundingBox() const override; size_t size() const override { return ni() * nj(); } uid_t uid() const override { return uid_; } diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc index c0d4721ff..97dcb119c 100644 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc @@ -61,11 +61,6 @@ Grid::iterator UnstructuredFromGrid::cend() const { } -const area::BoundingBox& UnstructuredFromGrid::boundingBox() const { - return Unstructured::boundingBox(); -} - - std::vector UnstructuredFromGrid::to_points() const { std::vector p; for (size_t i = 0; i < size(); ++i) { diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h index 4604bfbbe..0d5452517 100644 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h @@ -56,8 +56,6 @@ class UnstructuredFromGrid final : public Unstructured { iterator cbegin() const override; iterator cend() const override; - const area::BoundingBox& boundingBox() const override; - size_t size() const override { return latitudes_.size(); } uid_t uid() const override; diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index 10498726e..e6a2a3989 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -77,29 +77,36 @@ CASE("RegularGaussian") { EXPECT_EQUAL(n1, 32); - spec.set("south", 0); + spec.set("south", 0.); std::unique_ptr grid2(GridFactory::build(spec)); auto n2 = grid2->size(); EXPECT_EQUAL(n2, n1 / 2); - // spec = spec::Custom{{{"grid", "f2"}, {"west", -180}}}; - // std::unique_ptr grid3(GridFactory::build(spec)); - // auto n3 = grid3->size(); + spec = spec::Custom{{{"grid", "f2"}, {"west", -180}}}; + std::unique_ptr grid3(GridFactory::build(spec)); + auto n3 = grid3->size(); - // EXPECT_EQUAL(n3, n1); + EXPECT_EQUAL(n3, n1); - // spec.set("east", 0); - // std::unique_ptr grid4(GridFactory::build(spec)); - // auto n4 = grid4->size(); + auto bbox3 = grid3->boundingBox(); - // EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj + EXPECT(bbox3.isPeriodicWestEast()); - // spec.set("east", -1.); - // std::unique_ptr grid5(GridFactory::build(spec)); - // auto n5 = grid5->size(); + bbox3.east = 0.; - // EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj + EXPECT_NOT(bbox3.isPeriodicWestEast()); + + std::unique_ptr grid4(grid3->grid_crop(bbox3)); + auto n4 = grid4->size(); + + EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj + + spec.set("east", -1.); + std::unique_ptr grid5(GridFactory::build(spec)); + auto n5 = grid5->size(); + + EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj } From 8d399e8bb34143fc6b0e40c5488be8c9222dde78 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 6 Mar 2024 00:11:30 +0000 Subject: [PATCH 526/737] eckit::geo::Grid --- src/eckit/geo/range/RegularLongitude.cc | 27 ++++++++++++++++--------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/eckit/geo/range/RegularLongitude.cc b/src/eckit/geo/range/RegularLongitude.cc index 5913fa57e..56f237a27 100644 --- a/src/eckit/geo/range/RegularLongitude.cc +++ b/src/eckit/geo/range/RegularLongitude.cc @@ -16,6 +16,7 @@ #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/PointLonLat.h" #include "eckit/types/FloatCompare.h" #include "eckit/types/Fraction.h" @@ -28,6 +29,7 @@ static const Fraction PERIOD(360, 1); RegularLongitude::RegularLongitude(double _inc, double _a, double _b, double _ref, double _eps) : Regular(_inc, _a, _b, _ref, _eps) { + ASSERT(!types::is_approximately_equal(_a, _b)); ASSERT(_a < _b); // FIXME temporary const Fraction inc(_inc); @@ -44,16 +46,24 @@ RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) Range* RegularLongitude::crop(double crop_a, double crop_b) const { - ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || - (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); + ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b)); + + if (a() < b()) { + const auto inc(increment()); + + if (periodic()) { + return new RegularLongitude(inc, crop_a, crop_b, a(), eps()); + } + + RegularLongitude crop(inc, crop_a, crop_b, a(), eps()); + if (crop.periodic()) { + auto _a = PointLonLat::normalise_angle_to_minimum(crop_a, crop.a()); + auto _b = PointLonLat::normalise_angle_to_minimum(crop_b, _a); + return new RegularLongitude(inc, _a, _b, a(), eps()); + } - if (types::is_approximately_equal(crop_a, crop_b, eps())) { - NOTIMP; // FIXME - } - else if (a() < b()) { ASSERT(a() <= crop_a && crop_b <= b()); // FIXME do better - auto inc(increment()); auto d = (a() / inc).decimalPart() * inc; auto _a = adjust(crop_a - d, inc, true) + d; auto _b = adjust(crop_b - d, inc, false) + d; @@ -66,9 +76,6 @@ Range* RegularLongitude::crop(double crop_a, double crop_b) const { return new RegularLongitude(n, _a, _b, eps()); } - else { - NOTIMP; // FIXME - } NOTIMP; } From 895d67c893e612c065978ad50f35c90ac9b7c6fb Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 6 Mar 2024 09:36:21 +0000 Subject: [PATCH 527/737] eckit::geo::Grid --- src/eckit/geo/grid/regular/RegularGaussian.cc | 4 +-- tests/geo/grid_regular_gg.cc | 28 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index 4f76278e9..cf765f90b 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -69,8 +69,8 @@ void RegularGaussian::spec(spec::Custom& custom) const { } -Grid* RegularGaussian::grid_crop(const area::BoundingBox& bbox) const { - if (auto intersection(boundingBox()); bbox.intersects(intersection)) { +Grid* RegularGaussian::grid_crop(const area::BoundingBox& crop) const { + if (auto bbox(boundingBox()); crop.intersects(bbox)) { return new RegularGaussian(N_, bbox); } diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index e6a2a3989..5163a0f0c 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -107,6 +107,34 @@ CASE("RegularGaussian") { auto n5 = grid5->size(); EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj + + const std::vector ref{ + PointLonLat{-180., 59.444408289}, + PointLonLat{-135., 59.444408289}, + PointLonLat{-90., 59.444408289}, + PointLonLat{-45., 59.444408289}, + PointLonLat{-180., 19.875719147}, + PointLonLat{-135., 19.875719147}, + PointLonLat{-90., 19.875719147}, + PointLonLat{-45., 19.875719147}, + PointLonLat{-180., -19.875719147}, + PointLonLat{-135., -19.875719147}, + PointLonLat{-90., -19.875719147}, + PointLonLat{-45., -19.875719147}, + PointLonLat{-180., -59.444408289}, + PointLonLat{-135., -59.444408289}, + PointLonLat{-90., -59.444408289}, + PointLonLat{-45., -59.444408289}, + }; + + auto points5 = grid5->to_points(); + + EXPECT(points5.size() == grid5->size()); + ASSERT(points5.size() == ref.size()); + + for (size_t i = 0; i < points5.size(); ++i) { + EXPECT(points_equal(points5[i], ref[i])); + } } From b47ded501310a546e35884eab3128a4406cba05e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 13 Mar 2024 07:25:38 +0000 Subject: [PATCH 528/737] eckit::geo --- src/eckit/geo/Grid.cc | 16 ++++++++-------- src/eckit/geo/Grid.h | 17 ++++++++--------- src/eckit/geo/grid/Reduced.h | 2 +- src/eckit/geo/grid/Regular.h | 2 +- src/eckit/geo/grid/Unstructured.h | 2 +- src/eckit/geo/grid/reduced/HEALPix.h | 2 +- src/eckit/geo/grid/regular/RegularGaussian.cc | 2 +- src/eckit/geo/grid/regular/RegularGaussian.h | 2 +- tests/geo/grid_regular_gg.cc | 2 +- tests/geo/grid_reorder.cc | 2 +- tests/geo/spec.cc | 2 +- 11 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index febf16300..c1e2d087a 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -104,7 +104,7 @@ Renumber Grid::reorder(Ordering) const { } -Grid* Grid::grid_reorder(Ordering) const { +Grid* Grid::make_grid_reordered(Ordering) const { throw NotImplemented("Grid::grid_reorder"); } @@ -119,7 +119,7 @@ Renumber Grid::crop(const Area&) const { } -Grid* Grid::grid_crop(const Area&) const { +Grid* Grid::make_grid_cropped(const Area&) const { throw NotImplemented("Grid::grid_crop"); } @@ -134,8 +134,8 @@ Renumber Grid::crop(const area::BoundingBox& bbox) const { } -Grid* Grid::grid_crop(const area::BoundingBox& bbox) const { - return grid_crop(static_cast(bbox)); +Grid* Grid::make_grid_cropped(const area::BoundingBox& bbox) const { + return make_grid_cropped(static_cast(bbox)); } @@ -153,7 +153,7 @@ void Grid::spec(spec::Custom&) const { const Grid* GridFactory::make_from_string(const std::string& str) { std::unique_ptr spec(new spec::Custom(YAMLParser::decodeString(str))); - return instance().build_(*spec); + return instance().make_from_spec_(*spec); } @@ -163,10 +163,10 @@ GridFactory& GridFactory::instance() { } -const Grid* GridFactory::build_(const Spec& spec) const { +const Grid* GridFactory::make_from_spec_(const Spec& spec) const { lock_type lock; - std::unique_ptr cfg(generate_spec_(spec)); + std::unique_ptr cfg(make_spec_(spec)); if (std::string type; cfg->get("type", type)) { return GridFactoryType::instance().get(type).create(*cfg); @@ -177,7 +177,7 @@ const Grid* GridFactory::build_(const Spec& spec) const { } -Spec* GridFactory::generate_spec_(const Spec& spec) const { +Spec* GridFactory::make_spec_(const Spec& spec) const { lock_type lock; etc::Grid::instance(); diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 3c8f7b109..60f082ac0 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -113,11 +113,10 @@ class Grid { iterator begin() const { return cbegin(); } iterator end() const { return cend(); } - std::string spec() const; - virtual iterator cbegin() const = 0; virtual iterator cend() const = 0; + std::string spec() const; virtual size_t size() const; virtual uid_t uid() const; @@ -131,15 +130,15 @@ class Grid { virtual Ordering order() const; virtual Renumber reorder(Ordering) const; - virtual Grid* grid_reorder(Ordering) const; + virtual Grid* make_grid_reordered(Ordering) const; virtual Area* area() const; virtual Renumber crop(const Area&) const; - virtual Grid* grid_crop(const Area&) const; + virtual Grid* make_grid_cropped(const Area&) const; virtual area::BoundingBox boundingBox() const; virtual Renumber crop(const area::BoundingBox&) const; - virtual Grid* grid_crop(const area::BoundingBox&) const; + virtual Grid* make_grid_cropped(const area::BoundingBox&) const; // -- Overridden methods // None @@ -212,21 +211,21 @@ using GridRegisterName = spec::ConcreteSpecGeneratorT1; struct GridFactory { // This is 'const' as Grid should always be immutable - static const Grid* build(const Spec& spec) { return instance().build_(spec); } + static const Grid* build(const Spec& spec) { return instance().make_from_spec_(spec); } // This is 'const' as Grid should always be immutable static const Grid* make_from_string(const std::string&); - static Spec* spec(const Spec& spec) { return instance().generate_spec_(spec); } + static Spec* make_spec(const Spec& spec) { return instance().make_spec_(spec); } static void list(std::ostream& out) { return instance().list_(out); } private: static GridFactory& instance(); // This is 'const' as Grid should always be immutable - const Grid* build_(const Spec&) const; + const Grid* make_from_spec_(const Spec&) const; - Spec* generate_spec_(const Spec&) const; + Spec* make_spec_(const Spec&) const; void list_(std::ostream&) const; }; diff --git a/src/eckit/geo/grid/Reduced.h b/src/eckit/geo/grid/Reduced.h index fbc507a39..87a2ebf4e 100644 --- a/src/eckit/geo/grid/Reduced.h +++ b/src/eckit/geo/grid/Reduced.h @@ -105,7 +105,7 @@ class Reduced : public Grid { // -- Friends - friend class ::eckit::geo::iterator::Reduced; + friend class geo::iterator::Reduced; }; diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index f4a527f2c..98777a6d9 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -99,7 +99,7 @@ class Regular : public Grid { // -- Friends - friend class ::eckit::geo::iterator::Regular; + friend class geo::iterator::Regular; }; diff --git a/src/eckit/geo/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h index 7326cf4e7..9aa38ec01 100644 --- a/src/eckit/geo/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -98,7 +98,7 @@ class Unstructured : public Grid { // -- Friends - friend class ::eckit::geo::iterator::Unstructured; + friend class geo::iterator::Unstructured; }; diff --git a/src/eckit/geo/grid/reduced/HEALPix.h b/src/eckit/geo/grid/reduced/HEALPix.h index 910a341c8..7757a7441 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.h +++ b/src/eckit/geo/grid/reduced/HEALPix.h @@ -53,7 +53,7 @@ class HEALPix final : public Reduced { Ordering order() const override { return ordering_; } Renumber reorder(Ordering) const override; - Grid* grid_reorder(Ordering ordering) const override { return new HEALPix(N_, ordering); } + Grid* make_grid_reordered(Ordering ordering) const override { return new HEALPix(N_, ordering); } // -- Class members diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index cf765f90b..b8ab96e01 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -69,7 +69,7 @@ void RegularGaussian::spec(spec::Custom& custom) const { } -Grid* RegularGaussian::grid_crop(const area::BoundingBox& crop) const { +Grid* RegularGaussian::make_grid_cropped(const area::BoundingBox& crop) const { if (auto bbox(boundingBox()); crop.intersects(bbox)) { return new RegularGaussian(N_, bbox); } diff --git a/src/eckit/geo/grid/regular/RegularGaussian.h b/src/eckit/geo/grid/regular/RegularGaussian.h index c676e9d3c..6cd0ff770 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.h +++ b/src/eckit/geo/grid/regular/RegularGaussian.h @@ -77,7 +77,7 @@ class RegularGaussian final : public Regular { void spec(spec::Custom&) const override; - Grid* grid_crop(const area::BoundingBox& bbox) const override; + Grid* make_grid_cropped(const area::BoundingBox& bbox) const override; // -- Class members // None diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index 5163a0f0c..19723585d 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -97,7 +97,7 @@ CASE("RegularGaussian") { EXPECT_NOT(bbox3.isPeriodicWestEast()); - std::unique_ptr grid4(grid3->grid_crop(bbox3)); + std::unique_ptr grid4(grid3->make_grid_cropped(bbox3)); auto n4 = grid4->size(); EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj diff --git a/tests/geo/grid_reorder.cc b/tests/geo/grid_reorder.cc index 6319fd6bb..b1f1b9fab 100644 --- a/tests/geo/grid_reorder.cc +++ b/tests/geo/grid_reorder.cc @@ -59,7 +59,7 @@ CASE("HEALPix") { EXPECT_EQUAL_VECTOR(ren_to_nested, expected_ren_ring_to_nested); - std::unique_ptr nested(ring->grid_reorder(Ordering::healpix_nested)); + std::unique_ptr nested(ring->make_grid_reordered(Ordering::healpix_nested)); auto order_nested = nested->order(); EXPECT_EQUAL(order_nested, Ordering::healpix_nested); diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index fa28e5dc4..35304e3ad 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -299,7 +299,7 @@ CASE("spec") { Log::info() << user << " -> " << gridspec << std::endl; try { - std::unique_ptr spec(GridFactory::spec(user)); + std::unique_ptr spec(GridFactory::make_spec(user)); EXPECT(spec); std::unique_ptr grid(GridFactory::build(*spec)); From d1176ef79ea858d115719d85288684134da041a0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 14 Mar 2024 14:16:11 +0000 Subject: [PATCH 529/737] eckit::geo::Grid --- src/eckit/geo/grid/reduced/ReducedGaussian.h | 6 +----- src/eckit/geo/grid/regular/RegularGaussian.h | 2 ++ 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.h b/src/eckit/geo/grid/reduced/ReducedGaussian.h index 708de43bf..9357b0286 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.h @@ -14,15 +14,11 @@ #include +#include "eckit/geo/Range.h" #include "eckit/geo/grid/Reduced.h" #include "eckit/geo/util.h" -namespace eckit::geo { -class Range; -} - - namespace eckit::geo::grid::reduced { diff --git a/src/eckit/geo/grid/regular/RegularGaussian.h b/src/eckit/geo/grid/regular/RegularGaussian.h index 6cd0ff770..b386e486c 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.h +++ b/src/eckit/geo/grid/regular/RegularGaussian.h @@ -12,6 +12,8 @@ #pragma once +#include + #include "eckit/geo/Range.h" #include "eckit/geo/grid/Regular.h" From 0fd3f28c9662160c5124d9ff24c741761316fb52 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 14 Mar 2024 15:04:03 +0000 Subject: [PATCH 530/737] eckit::geo::grid::reduced::ReducedGaussian --- tests/geo/grid_reduced_gg.cc | 111 ++++++++++++++++++++++++++++++++--- 1 file changed, 104 insertions(+), 7 deletions(-) diff --git a/tests/geo/grid_reduced_gg.cc b/tests/geo/grid_reduced_gg.cc index 8adec9ee8..9e7a646a5 100644 --- a/tests/geo/grid_reduced_gg.cc +++ b/tests/geo/grid_reduced_gg.cc @@ -22,7 +22,7 @@ namespace eckit::geo::test { -CASE("ReducedGaussian") { +CASE("ReducedGaussianOctahedral") { SECTION("gridspec") { // different ways to instantiate the same grid (O2) for (auto spec : { @@ -44,27 +44,124 @@ CASE("ReducedGaussian") { } + SECTION("sizes") { + struct test_t { + explicit test_t(size_t N) : + N(N), size(4 * N * (N + 9)) {} + size_t N; + size_t size; + } tests[]{test_t{2}, test_t{3}, test_t{64}}; + + for (const auto& test : tests) { + std::unique_ptr grid1( + GridFactory::build(spec::Custom({{"grid", "o" + std::to_string(test.N)}}))); + std::unique_ptr grid2( + GridFactory::build(spec::Custom({{"type", "reduced_gg"}, {"N", test.N}}))); + grid::reduced::ReducedGaussian grid3(test.N); + + EXPECT(grid1->size() == test.size); + EXPECT(grid2->size() == test.size); + EXPECT(grid3.size() == test.size); + } + } + + + SECTION("points") { + grid::reduced::ReducedGaussian grid(1); + + const std::vector ref{ + PointLonLat{0., 35.264389683}, PointLonLat{18., 35.264389683}, PointLonLat{36., 35.264389683}, + PointLonLat{54., 35.264389683}, PointLonLat{72., 35.264389683}, PointLonLat{90., 35.264389683}, + PointLonLat{108., 35.264389683}, PointLonLat{126., 35.264389683}, PointLonLat{144., 35.264389683}, + PointLonLat{162., 35.264389683}, PointLonLat{180., 35.264389683}, PointLonLat{198., 35.264389683}, + PointLonLat{216., 35.264389683}, PointLonLat{234., 35.264389683}, PointLonLat{252., 35.264389683}, + PointLonLat{270., 35.264389683}, PointLonLat{288., 35.264389683}, PointLonLat{306., 35.264389683}, + PointLonLat{324., 35.264389683}, PointLonLat{342., 35.264389683}, PointLonLat{0., -35.264389683}, + PointLonLat{18., -35.264389683}, PointLonLat{36., -35.264389683}, PointLonLat{54., -35.264389683}, + PointLonLat{72., -35.264389683}, PointLonLat{90., -35.264389683}, PointLonLat{108., -35.264389683}, + PointLonLat{126., -35.264389683}, PointLonLat{144., -35.264389683}, PointLonLat{162., -35.264389683}, + PointLonLat{180., -35.264389683}, PointLonLat{198., -35.264389683}, PointLonLat{216., -35.264389683}, + PointLonLat{234., -35.264389683}, PointLonLat{252., -35.264389683}, PointLonLat{270., -35.264389683}, + PointLonLat{288., -35.264389683}, PointLonLat{306., -35.264389683}, PointLonLat{324., -35.264389683}, + PointLonLat{342., -35.264389683}, + }; + + auto points = grid.to_points(); + + EXPECT(points.size() == grid.size()); + ASSERT(points.size() == ref.size()); + + for (size_t i = 0; i < points.size(); ++i) { + EXPECT(points_equal(points[i], ref[i])); + } + } + + SECTION("crop") { - std::unique_ptr grid1(new grid::reduced::ReducedGaussian(2)); + spec::Custom spec({{"grid", "o2"}}); + std::unique_ptr grid1(GridFactory::build(spec)); auto n1 = grid1->size(); EXPECT_EQUAL(n1, 88); - // std::unique_ptr grid2(grid1->crop(...)); - // auto n2 = grid2->size(); + spec.set("south", 0.); + std::unique_ptr grid2(GridFactory::build(spec)); + auto n2 = grid2->size(); + + EXPECT_EQUAL(n2, n1 / 2); + +#if 0 + spec = spec::Custom{{{"grid", "o2"}, {"west", -180}}}; + std::unique_ptr grid3(GridFactory::build(spec)); + auto n3 = grid3->size(); + + EXPECT_EQUAL(n3, n1); + + auto bbox3 = grid3->boundingBox(); - // EXPECT_EQUAL(n2, n1 / 2); + EXPECT(bbox3.isPeriodicWestEast()); + + bbox3.east = 0.; + + EXPECT_NOT(bbox3.isPeriodicWestEast()); + + std::unique_ptr grid4(grid3->make_grid_cropped(bbox3)); + auto n4 = grid4->size(); + + EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj + + spec.set("east", -1.); + std::unique_ptr grid5(GridFactory::build(spec)); + auto n5 = grid5->size(); + + EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj + + const std::vector ref{ + ... + }; + + auto points5 = grid5->to_points(); + + EXPECT(points5.size() == grid5->size()); + ASSERT(points5.size() == ref.size()); + + for (size_t i = 0; i < points5.size(); ++i) { + EXPECT(points_equal(points5[i], ref[i])); + } +#endif } SECTION("equals") { std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "o3"}}))); std::unique_ptr grid2(GridFactory::make_from_string("N: 3")); - std::unique_ptr grid3(new grid::reduced::ReducedGaussian(pl_type{20, 24, 28, 28, 24, 20})); + std::unique_ptr grid3(new grid::reduced::ReducedGaussian(3)); + std::unique_ptr grid4(new grid::reduced::ReducedGaussian(pl_type{20, 24, 28, 28, 24, 20})); EXPECT(*grid1 == *grid2); EXPECT(*grid2 == *grid3); - EXPECT(*grid3 == *grid1); + EXPECT(*grid3 == *grid4); + EXPECT(*grid4 == *grid1); } } From 0e23c11ee088531d575934f86d935833634d86cc Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 14 Mar 2024 15:28:09 +0000 Subject: [PATCH 531/737] eckit::geo::Spec --- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 9 ++++++++- tests/geo/spec.cc | 13 +++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 3c57727b7..2ecab366e 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -91,7 +91,14 @@ std::vector ReducedGaussian::longitudes(size_t j) const { void ReducedGaussian::spec(spec::Custom& custom) const { ASSERT(!custom.has("grid")); - custom.set("grid", (pl_ == util::reduced_octahedral_pl(N_) ? "O" : "N") + std::to_string(N_)); + + if (pl_ == util::reduced_octahedral_pl(N_)) { + custom.set("grid", "O" + std::to_string(N_)); + } + else { + custom.set("grid", "N" + std::to_string(N_)); + custom.set("pl", pl_); + } } diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 35304e3ad..b2e38eddd 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -324,6 +324,19 @@ CASE("spec") { EXPECT(gridspec == R"({"grid":")" + name + R"("})"); } } + + + SECTION("grid: reduced_gg") { + std::unique_ptr n16(GridFactory::build(spec::Custom({{"grid", "n16"}}))); + + EXPECT( + n16->spec() == + R"({"grid":"N16","pl":[20,27,32,40,45,48,60,60,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,60,60,48,45,40,32,27,20]})"); + + std::unique_ptr o16(GridFactory::build(spec::Custom({{"grid", "o16"}}))); + + EXPECT(o16->spec() == R"({"grid":"O16"})"); + } } From 3bbc10ee4692bbffce221fd38ad1179c29ecb8d3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 15 Mar 2024 09:52:43 +0000 Subject: [PATCH 532/737] eckit::geo::Spec --- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 4 ++- src/eckit/geo/util.h | 3 +++ src/eckit/geo/util/reduced_classical_pl.cc | 11 +++++--- tests/geo/spec.cc | 25 +++++++++++++++---- 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 2ecab366e..c29ee33c9 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -97,7 +97,9 @@ void ReducedGaussian::spec(spec::Custom& custom) const { } else { custom.set("grid", "N" + std::to_string(N_)); - custom.set("pl", pl_); + if (!util::reduced_classical_pl_known(N_)) { + custom.set("pl", pl_); + } } } diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index 3778dde10..00c937249 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -65,6 +65,9 @@ std::pair monotonic_crop(const std::vector __classical_pls{ +static const std::map CLASSICAL_PLS{ {16, {20, 27, 32, 40, 45, 48, 60, 60, 64, 64, 64, 64, 64, 64, 64, 64}}, {24, {20, 25, 36, 40, 45, 48, 54, 60, 64, 72, 80, 80, 90, 90, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96}}, {32, {20, 27, 36, 40, 45, 50, 60, 64, 72, 75, 80, 90, 90, 96, 100, 108, @@ -1332,6 +1332,11 @@ static const std::map __classical_pls{ }; +bool reduced_classical_pl_known(size_t N) { + return CLASSICAL_PLS.find(N) != CLASSICAL_PLS.end(); +} + + const pl_type& reduced_classical_pl(size_t N) { ASSERT(N > 0); @@ -1340,8 +1345,8 @@ const pl_type& reduced_classical_pl(size_t N) { return cache[N]; } - auto pl_half = __classical_pls.find(N); - if (pl_half == __classical_pls.end()) { + auto pl_half = CLASSICAL_PLS.find(N); + if (pl_half == CLASSICAL_PLS.end()) { throw BadValue("reduced_classical_pl: unknown N=" + std::to_string(N)); } diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index b2e38eddd..56f0065c3 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -16,6 +16,7 @@ #include "eckit/geo/Grid.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/spec/Layered.h" +#include "eckit/geo/util.h" #include "eckit/log/Log.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" @@ -327,15 +328,29 @@ CASE("spec") { SECTION("grid: reduced_gg") { + std::unique_ptr o16(GridFactory::build(spec::Custom({{"grid", "o16"}}))); + + EXPECT(o16->spec() == R"({"grid":"O16"})"); + std::unique_ptr n16(GridFactory::build(spec::Custom({{"grid", "n16"}}))); - EXPECT( - n16->spec() == - R"({"grid":"N16","pl":[20,27,32,40,45,48,60,60,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,60,60,48,45,40,32,27,20]})"); + EXPECT(n16->spec() == R"({"grid":"N16"})"); - std::unique_ptr o16(GridFactory::build(spec::Custom({{"grid", "o16"}}))); + std::unique_ptr known_pl_1(GridFactory::build( + spec::Custom({{"pl", pl_type{20, 27, 32, 40, 45, 48, 60, 60, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 60, 60, 48, 45, 40, 32, 27, 20}}}))); - EXPECT(o16->spec() == R"({"grid":"O16"})"); + EXPECT(known_pl_1->spec() == R"({"grid":"N16"})"); + + std::unique_ptr known_pl_2( + GridFactory::build(spec::Custom({{"pl", pl_type{20, 24, 28, 32, 32, 28, 24, 20}}}))); + + EXPECT(known_pl_2->spec() == R"({"grid":"O4"})"); + + std::unique_ptr unknown_pl( + GridFactory::build(spec::Custom({{"pl", pl_type{20, 24, 28, 32, 32, 28, 24, 99}}}))); + + EXPECT(unknown_pl->spec() == R"({"grid":"N4","pl":[20,24,28,32,32,28,24,99]})"); } } From 170719dbc97c30f616f0beb28b045d4c867dd3d9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 14 Mar 2024 15:28:25 +0000 Subject: [PATCH 533/737] eckit::geo::grid::reduced::ReducedGaussian --- src/eckit/geo/Grid.cc | 4 +-- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 9 ++++++ src/eckit/geo/grid/reduced/ReducedGaussian.h | 2 ++ src/eckit/geo/grid/regular/RegularGaussian.h | 2 +- tests/geo/grid_reduced_gg.cc | 31 ++++++------------- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index c1e2d087a..977bde8de 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -105,7 +105,7 @@ Renumber Grid::reorder(Ordering) const { Grid* Grid::make_grid_reordered(Ordering) const { - throw NotImplemented("Grid::grid_reorder"); + throw NotImplemented("Grid::make_grid_reordered"); } @@ -120,7 +120,7 @@ Renumber Grid::crop(const Area&) const { Grid* Grid::make_grid_cropped(const Area&) const { - throw NotImplemented("Grid::grid_crop"); + throw NotImplemented("Grid::make_grid_cropped"); } diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index c29ee33c9..163f2ffd6 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -104,6 +104,15 @@ void ReducedGaussian::spec(spec::Custom& custom) const { } +Grid* ReducedGaussian::make_grid_cropped(const area::BoundingBox& crop) const { + if (auto bbox(boundingBox()); crop.intersects(bbox)) { + return new ReducedGaussian(pl_, bbox); + } + + throw eckit::Exception("RegularGaussian: cannot crop grid (empty intersection)"); +} + + struct ReducedGaussianClassical { static Spec* spec(const std::string& name) { auto N = Translator{}(name.substr(1)); diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.h b/src/eckit/geo/grid/reduced/ReducedGaussian.h index 9357b0286..ca3ea15d6 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.h @@ -83,6 +83,8 @@ class ReducedGaussian : public Reduced { void spec(spec::Custom&) const override; + Grid* make_grid_cropped(const area::BoundingBox&) const override; + // -- Class members // None diff --git a/src/eckit/geo/grid/regular/RegularGaussian.h b/src/eckit/geo/grid/regular/RegularGaussian.h index b386e486c..166318964 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.h +++ b/src/eckit/geo/grid/regular/RegularGaussian.h @@ -79,7 +79,7 @@ class RegularGaussian final : public Regular { void spec(spec::Custom&) const override; - Grid* make_grid_cropped(const area::BoundingBox& bbox) const override; + Grid* make_grid_cropped(const area::BoundingBox&) const override; // -- Class members // None diff --git a/tests/geo/grid_reduced_gg.cc b/tests/geo/grid_reduced_gg.cc index 9e7a646a5..263e0bdd3 100644 --- a/tests/geo/grid_reduced_gg.cc +++ b/tests/geo/grid_reduced_gg.cc @@ -110,43 +110,32 @@ CASE("ReducedGaussianOctahedral") { EXPECT_EQUAL(n2, n1 / 2); -#if 0 spec = spec::Custom{{{"grid", "o2"}, {"west", -180}}}; std::unique_ptr grid3(GridFactory::build(spec)); auto n3 = grid3->size(); EXPECT_EQUAL(n3, n1); - auto bbox3 = grid3->boundingBox(); - - EXPECT(bbox3.isPeriodicWestEast()); - - bbox3.east = 0.; - - EXPECT_NOT(bbox3.isPeriodicWestEast()); + EXPECT(grid3->boundingBox().isPeriodicWestEast()); - std::unique_ptr grid4(grid3->make_grid_cropped(bbox3)); + // (exclude Greenwhich meridian) + std::unique_ptr grid4(grid3->make_grid_cropped(area::BoundingBox(90., -180., 0., -1.))); auto n4 = grid4->size(); - EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj - - spec.set("east", -1.); - std::unique_ptr grid5(GridFactory::build(spec)); - auto n5 = grid5->size(); - - EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj + EXPECT_EQUAL(n4, n3 / 4); +#if 0 const std::vector ref{ ... }; - auto points5 = grid5->to_points(); + auto points4 = grid4->to_points(); - EXPECT(points5.size() == grid5->size()); - ASSERT(points5.size() == ref.size()); + EXPECT(points4.size() == grid4->size()); + ASSERT(points4.size() == ref.size()); - for (size_t i = 0; i < points5.size(); ++i) { - EXPECT(points_equal(points5[i], ref[i])); + for (size_t i = 0; i < points4.size(); ++i) { + EXPECT(points_equal(points4[i], ref[i])); } #endif } From c19afc8dc55e4ef2899796b0dde8a0adfbc3ba5a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 15 Mar 2024 15:03:23 +0000 Subject: [PATCH 534/737] eckit::geo::Spec --- src/eckit/geo/grid/unstructured/ORCA.cc | 7 +++++++ src/eckit/geo/grid/unstructured/ORCA.h | 3 ++- src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc | 7 +++++++ src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h | 4 ++-- 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index 8894f7314..0d6e53fc1 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -21,6 +21,7 @@ #include "eckit/geo/Spec.h" #include "eckit/geo/area/BoundingBox.h" #include "eckit/geo/iterator/Unstructured.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/geo/util/mutex.h" #include "eckit/io/Length.h" #include "eckit/log/Bytes.h" @@ -285,6 +286,12 @@ Spec* ORCA::spec(const std::string& name) { } +void ORCA::spec(spec::Custom& custom) const { + custom.set("type", "ORCA"); + custom.set("uid", uid_); +} + + static const GridRegisterType __grid_type("ORCA"); static const GridRegisterName __grid_pattern(GridRegisterName::uid_pattern); diff --git a/src/eckit/geo/grid/unstructured/ORCA.h b/src/eckit/geo/grid/unstructured/ORCA.h index 5922f6bfe..8f7757e91 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.h +++ b/src/eckit/geo/grid/unstructured/ORCA.h @@ -122,7 +122,8 @@ class ORCA final : public Unstructured { // None // -- Overridden methods - // None + + void spec(spec::Custom&) const override; // -- Class members // None diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc index 97dcb119c..b842a989d 100644 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc @@ -14,6 +14,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/iterator/Unstructured.h" +#include "eckit/geo/spec/Custom.h" namespace eckit::geo::grid::unstructured { @@ -75,6 +76,12 @@ Spec* UnstructuredFromGrid::spec(const std::string& name) { } +void UnstructuredFromGrid::spec(spec::Custom& custom) const { + custom.set("type", "unstructured"); + custom.set("uid", uid()); +} + + Grid::uid_t UnstructuredFromGrid::uid() const { NOTIMP; } diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h index 0d5452517..569db4435 100644 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h @@ -12,7 +12,6 @@ #pragma once -#include #include #include @@ -86,7 +85,8 @@ class UnstructuredFromGrid final : public Unstructured { // None // -- Overridden methods - // None + + void spec(spec::Custom&) const override; // -- Class members // None From 16b776308c438619b97d44c435c464b6776e28ba Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 15 Mar 2024 15:03:38 +0000 Subject: [PATCH 535/737] eckit::geo::Spec --- src/eckit/geo/Area.cc | 26 ++++++++++++++++++++++++++ src/eckit/geo/Area.h | 5 +++++ src/eckit/geo/CMakeLists.txt | 1 + src/eckit/geo/area/BoundingBox.cc | 17 ++++++++++++++--- src/eckit/geo/area/BoundingBox.h | 3 ++- 5 files changed, 48 insertions(+), 4 deletions(-) create mode 100644 src/eckit/geo/Area.cc diff --git a/src/eckit/geo/Area.cc b/src/eckit/geo/Area.cc new file mode 100644 index 000000000..612352723 --- /dev/null +++ b/src/eckit/geo/Area.cc @@ -0,0 +1,26 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Area.h" + +#include "eckit/exception/Exceptions.h" + + +namespace eckit::geo { + + +void Area::spec(spec::Custom&) const { + throw NotImplemented("Area::spec"); +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Area.h b/src/eckit/geo/Area.h index fa45d11fb..3f76efc43 100644 --- a/src/eckit/geo/Area.h +++ b/src/eckit/geo/Area.h @@ -20,7 +20,10 @@ namespace eckit::geo { class Spec; +namespace spec { +class Custom; } +} // namespace eckit::geo namespace eckit::geo { @@ -58,6 +61,8 @@ class Area { static std::string className() { return "area"; } + virtual void spec(spec::Custom&) const; + // -- Overridden methods // None diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index eff1ec0b5..73d6c2b06 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -7,6 +7,7 @@ install( list(APPEND eckit_geo_srcs ${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_config.h + Area.cc Area.h Cache.cc Cache.h diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 48fe7bbd5..7532ef35c 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -18,8 +18,8 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/PointLonLat.h" -#include "eckit/geo/Spec.h" #include "eckit/geo/Sphere.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -27,13 +27,24 @@ namespace eckit::geo::area { +static const BoundingBox GLOBE_PRIME{90., 0., -90., 360.}; +static const BoundingBox GLOBE_ANTIPRIME{90., -180., -90., 180.}; + + BoundingBox BoundingBox::make_global_prime() { - return {90., 0., -90., 360.}; + return GLOBE_PRIME; } BoundingBox BoundingBox::make_global_antiprime() { - return {90., -180., -90., 180.}; + return GLOBE_ANTIPRIME; +} + + +void BoundingBox::spec(spec::Custom& custom) const { + if (operator!=(GLOBE_PRIME)) { + custom.set("area", std::vector{north, west, south, east}); + } } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 98b76b858..bf1e589ca 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -88,7 +88,8 @@ class BoundingBox : public Area, protected std::array { static BoundingBox make_global_antiprime(); // -- Overridden methods - // None + + void spec(spec::Custom&) const override; // -- Class members // None From 55fe55ed6adfeb76e629668c01e2adb0dc8d4fc3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 15 Mar 2024 15:04:06 +0000 Subject: [PATCH 536/737] eckit::geo::Spec --- src/eckit/geo/grid/reduced/ReducedGaussian.cc | 5 ++--- src/eckit/geo/grid/regular/RegularGaussian.cc | 2 +- src/eckit/geo/grid/regular/RegularLL.cc | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced/ReducedGaussian.cc index 163f2ffd6..6a2774113 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced/ReducedGaussian.cc @@ -63,7 +63,6 @@ Grid::iterator ReducedGaussian::cend() const { size_t ReducedGaussian::ni(size_t j) const { - ASSERT(j < Nj_); return pl_.at(j + j_); } @@ -90,8 +89,6 @@ std::vector ReducedGaussian::longitudes(size_t j) const { void ReducedGaussian::spec(spec::Custom& custom) const { - ASSERT(!custom.has("grid")); - if (pl_ == util::reduced_octahedral_pl(N_)) { custom.set("grid", "O" + std::to_string(N_)); } @@ -101,6 +98,8 @@ void ReducedGaussian::spec(spec::Custom& custom) const { custom.set("pl", pl_); } } + + boundingBox().spec(custom); } diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index b8ab96e01..c5a876d74 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -64,8 +64,8 @@ const std::vector& RegularGaussian::latitudes() const { void RegularGaussian::spec(spec::Custom& custom) const { - ASSERT(!custom.has("grid")); custom.set("grid", "F" + std::to_string(N_)); + boundingBox().spec(custom); } diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index e41a83c3e..0a004d707 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -62,8 +62,8 @@ Grid::iterator RegularLL::cend() const { void RegularLL::spec(spec::Custom& custom) const { - ASSERT(!custom.has("grid")); custom.set("grid", std::vector{lon_.increment(), lat_.increment()}); + boundingBox().spec(custom); } From 74ff2101c4ba1a84976c866f555a2e9f05aa65fa Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 15 Mar 2024 15:11:59 +0000 Subject: [PATCH 537/737] eckit::geo::Spec --- src/eckit/geo/grid/reduced/HEALPix.cc | 10 +++++++++- src/eckit/geo/grid/reduced/HEALPix.h | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/grid/reduced/HEALPix.cc b/src/eckit/geo/grid/reduced/HEALPix.cc index c7aca9ba4..3aac0276b 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.cc +++ b/src/eckit/geo/grid/reduced/HEALPix.cc @@ -228,7 +228,7 @@ static Ordering ordering_from_string(const std::string& str) { HEALPix::HEALPix(const Spec& spec) : - HEALPix(spec.get_unsigned("Nside"), ordering_from_string(spec.get_string("orderingConvention", "ring"))) {} + HEALPix(spec.get_unsigned("Nside"), ordering_from_string(spec.get_string("ordering", "ring"))) {} HEALPix::HEALPix(size_t Nside, Ordering ordering) : @@ -363,6 +363,14 @@ std::vector HEALPix::longitudes(size_t j) const { } +void HEALPix::spec(spec::Custom& custom) const { + custom.set("grid", "H" + std::to_string(N_)); + if (ordering_ != Ordering::healpix_ring) { + custom.set("ordering", "nested"); + } +} + + static const GridRegisterType __grid_type("HEALPix"); static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); diff --git a/src/eckit/geo/grid/reduced/HEALPix.h b/src/eckit/geo/grid/reduced/HEALPix.h index 7757a7441..ee1960705 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.h +++ b/src/eckit/geo/grid/reduced/HEALPix.h @@ -88,6 +88,8 @@ class HEALPix final : public Reduced { const std::vector& latitudes() const override; std::vector longitudes(size_t j) const override; + void spec(spec::Custom&) const override; + // -- Class members // None From cd694ce46429324fc84cd13366d8cf9ae07e614f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 15 Mar 2024 15:12:12 +0000 Subject: [PATCH 538/737] eckit::geo::Spec --- src/eckit/geo/grid/reduced/ReducedLL.cc | 32 +++++++++++++++++++++---- src/eckit/geo/grid/reduced/ReducedLL.h | 13 +++++++++- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/grid/reduced/ReducedLL.cc b/src/eckit/geo/grid/reduced/ReducedLL.cc index b525a081a..3227de852 100644 --- a/src/eckit/geo/grid/reduced/ReducedLL.cc +++ b/src/eckit/geo/grid/reduced/ReducedLL.cc @@ -13,13 +13,22 @@ #include "eckit/geo/grid/reduced/ReducedLL.h" #include "eckit/geo/iterator/Reduced.h" +#include "eckit/geo/range/RegularLatitude.h" +#include "eckit/geo/range/RegularLongitude.h" +#include "eckit/geo/spec/Custom.h" namespace eckit::geo::grid::reduced { ReducedLL::ReducedLL(const Spec& spec) : - Reduced(spec) {} + ReducedLL(spec.get_long_vector("pl"), area::BoundingBox(spec)) {} + + +ReducedLL::ReducedLL(const pl_type& pl, const area::BoundingBox& bbox) : + Reduced(bbox), pl_(pl), y_(new range::RegularLatitude(pl_.size(), bbox.north, bbox.south)) { + ASSERT(y_); +} Grid::iterator ReducedLL::cbegin() const { @@ -33,22 +42,35 @@ Grid::iterator ReducedLL::cend() const { size_t ReducedLL::ni(size_t j) const { - NOTIMP; + return pl_.at(j); } size_t ReducedLL::nj() const { - NOTIMP; + return pl_.size(); } const std::vector& ReducedLL::latitudes() const { - NOTIMP; + return y_->values(); } std::vector ReducedLL::longitudes(size_t j) const { - NOTIMP; + auto Ni = ni(j); + if (!x_ || x_->size() != Ni) { + auto bbox = boundingBox(); + const_cast&>(x_) = std::make_unique(Ni, bbox.west, bbox.east); + } + + return x_->values(); +} + + +void ReducedLL::spec(spec::Custom& custom) const { + custom.set("type", "reduced_ll"); + custom.set("pl", pl_); + boundingBox().spec(custom); } diff --git a/src/eckit/geo/grid/reduced/ReducedLL.h b/src/eckit/geo/grid/reduced/ReducedLL.h index e890bf215..4cfa3e53f 100644 --- a/src/eckit/geo/grid/reduced/ReducedLL.h +++ b/src/eckit/geo/grid/reduced/ReducedLL.h @@ -12,7 +12,11 @@ #pragma once +#include + +#include "eckit/geo/Range.h" #include "eckit/geo/grid/Reduced.h" +#include "eckit/geo/util.h" namespace eckit::geo::grid::reduced { @@ -29,6 +33,7 @@ class ReducedLL : public Reduced { // -- Constructors explicit ReducedLL(const Spec&); + explicit ReducedLL(const pl_type&, const area::BoundingBox& = area::BoundingBox::make_global_prime()); // -- Destructor // None @@ -58,7 +63,11 @@ class ReducedLL : public Reduced { private: // -- Members - // None + + const pl_type pl_; + + std::unique_ptr x_; + std::unique_ptr y_; // -- Methods // None @@ -68,6 +77,8 @@ class ReducedLL : public Reduced { const std::vector& latitudes() const override; std::vector longitudes(size_t j) const override; + void spec(spec::Custom&) const override; + // -- Class members // None From b8eb275be8f9a1d35775a35f69b46d427ae40978 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 15 Mar 2024 15:12:52 +0000 Subject: [PATCH 539/737] eckit::geo::Spec --- .../grid/regular/LambertAzimuthalEqualArea.cc | 34 +++++------ src/eckit/geo/grid/regular/Mercator.cc | 44 ++++++++++--- src/eckit/geo/grid/regular/Mercator.h | 61 +++++++------------ 3 files changed, 71 insertions(+), 68 deletions(-) diff --git a/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.cc b/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.cc index 0cac1f866..367f19a90 100644 --- a/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.cc @@ -18,9 +18,6 @@ #include "eckit/geo/etc/Grid.h" #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/spec/Custom.h" -// #include "eckit/geo/util/regex.h" -// #include "eckit/types/Fraction.h" -// #include "eckit/utils/Translator.h" namespace eckit::geo::grid::regular { @@ -33,8 +30,8 @@ LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Spec& spec) : LambertAzimuthalEqualArea(Internal(spec)) {} -LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(size_t ni, size_t nj, double Dx, double Dy) : - Regular(area::BoundingBox{}), Nx_(ni), Ny_(nj), Dx_(Dx), Dy_(Dy) {} +LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(size_t Nx, size_t Ny, double Dx, double Dy) : + Regular(area::BoundingBox{}), Nx_(Nx), Ny_(Ny), Dx_(Dx), Dy_(Dy) {} Grid::iterator LambertAzimuthalEqualArea::cbegin() const { @@ -62,27 +59,26 @@ const std::vector& LambertAzimuthalEqualArea::latitudes() const { void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { + custom.set("type", "lambert_azimuthal_equal_area"); + custom.set("grid", std::vector{Dx_, Dy_}); + custom.set("shape", std::vector{static_cast(Nx_), static_cast(Ny_)}); + // FIXME a lot more stuff to add here! - spec::Custom spec({ - {"type", "lambert_azimuthal_equal_area"}, - {"grid", std::vector{Dx_, Dy_}}, - {"dimensions", std::vector{static_cast(Nx_), static_cast(Ny_)}}, - // ... - }); - - if (std::string name; SpecByName::instance().match(spec, name)) { - custom.set("grid", name); - return; - } + //... NOTIMP; + + if (std::string name; SpecByName::instance().match(custom, name)) { + custom.clear(); + custom.set("grid", name); + } } LambertAzimuthalEqualArea::Internal::Internal(const Spec& spec) { - auto dimensions(spec.get_unsigned_vector("dimensions", {0, 0})); - Nx = dimensions.size() == 2 ? dimensions[0] : spec.get_unsigned("Nx"); - Ny = dimensions.size() == 2 ? dimensions[1] : spec.get_unsigned("Ny"); + auto shape(spec.get_unsigned_vector("shape", {0, 0})); + Nx = shape.size() == 2 ? shape[0] : spec.get_unsigned("Nx"); + Ny = shape.size() == 2 ? shape[1] : spec.get_unsigned("Ny"); ASSERT(Nx > 0); ASSERT(Ny > 0); diff --git a/src/eckit/geo/grid/regular/Mercator.cc b/src/eckit/geo/grid/regular/Mercator.cc index 26707493a..9f7c4fff5 100644 --- a/src/eckit/geo/grid/regular/Mercator.cc +++ b/src/eckit/geo/grid/regular/Mercator.cc @@ -15,9 +15,6 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/spec/Custom.h" -#include "eckit/geo/util/regex.h" -#include "eckit/types/Fraction.h" -#include "eckit/utils/Translator.h" namespace eckit::geo::grid::regular { @@ -27,14 +24,11 @@ static const GridRegisterType __grid_type("mercator"); Mercator::Mercator(const Spec& spec) : - Mercator(spec.get_unsigned("ni"), spec.get_unsigned("nj"), Increments{spec}, area::BoundingBox{spec}) {} + Mercator(Internal(spec)) {} -Mercator::Mercator(size_t ni, size_t nj, const Increments& inc, const area::BoundingBox& bbox) : - Regular(bbox), inc_(inc), ni_(ni), nj_(nj) { - ASSERT(ni_ > 0); - ASSERT(nj_ > 0); -} +Mercator::Mercator(size_t Nx, size_t Ny, double Dx, double Dy) : + Regular(area::BoundingBox{}), Nx_(Nx), Ny_(Ny), Dx_(Dx), Dy_(Dy) {} Grid::iterator Mercator::cbegin() const { @@ -56,4 +50,36 @@ const std::vector& Mercator::latitudes() const { } +void Mercator::spec(spec::Custom& custom) const { + custom.set("type", "mercator"); + custom.set("grid", std::vector{Dx_, Dy_}); + custom.set("shape", std::vector{static_cast(Nx_), static_cast(Ny_)}); + + // FIXME a lot more stuff to add here! + //... + + NOTIMP; + + if (std::string name; SpecByName::instance().match(custom, name)) { + custom.clear(); + custom.set("grid", name); + } +} + + +Mercator::Internal::Internal(const Spec& spec) { + auto shape(spec.get_unsigned_vector("shape", {0, 0})); + Nx = shape.size() == 2 ? shape[0] : spec.get_unsigned("Nx"); + Ny = shape.size() == 2 ? shape[1] : spec.get_unsigned("Ny"); + ASSERT(Nx > 0); + ASSERT(Ny > 0); + + auto grid(spec.get_double_vector("grid", {0., 0.})); + Dx = grid.size() == 2 ? grid[0] : spec.get_double("Nx"); + Dy = grid.size() == 2 ? grid[1] : spec.get_double("Ny"); + ASSERT(Dx > 0.); + ASSERT(Dy > 0.); +} + + } // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/grid/regular/Mercator.h b/src/eckit/geo/grid/regular/Mercator.h index 06c79a1c8..7481736f6 100644 --- a/src/eckit/geo/grid/regular/Mercator.h +++ b/src/eckit/geo/grid/regular/Mercator.h @@ -22,67 +22,48 @@ namespace eckit::geo::grid::regular { class Mercator final : public Regular { public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors explicit Mercator(const Spec&); - Mercator(size_t ni, size_t nj, const Increments&, const area::BoundingBox&); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None + Mercator(size_t Nx, size_t Ny, double Dx, double Dy); // -- Overridden methods iterator cbegin() const override; iterator cend() const override; - size_t ni() const override { return ni_; } - size_t nj() const override { return nj_; } + size_t ni() const override { return Ny_; } + size_t nj() const override { return Nx_; } + +private: + // -- Types - // -- Class members - // None + struct Internal { + explicit Internal(const Spec&); + size_t Nx; + size_t Ny; + double Dx; + double Dy; + }; - // -- Class methods - // None + // -- Constructors -private: - // -- Members + explicit Mercator(Internal&&); - Increments inc_; - size_t ni_; - size_t nj_; + // -- Members - // -- Methods - // None + size_t Nx_; + size_t Ny_; + const double Dx_; + const double Dy_; // -- Overridden methods const std::vector& longitudes() const override; const std::vector& latitudes() const override; - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None + void spec(spec::Custom&) const override; }; From 3248c05ed5a4b93ec8a7c1359192c6570e112285 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 15 Mar 2024 17:16:22 +0000 Subject: [PATCH 540/737] eckit::geo::Grid --- etc/eckit/geo/grid.yaml | 4 +- src/eckit/geo/CMakeLists.txt | 6 +- src/eckit/geo/grid/Regular.h | 2 +- .../grid/regular/LambertAzimuthalEqualArea.h | 68 --------------- src/eckit/geo/grid/regular/Mercator.cc | 85 ------------------- ...ertAzimuthalEqualArea.cc => XYToLonLat.cc} | 75 +++++++++------- .../grid/regular/{Mercator.h => XYToLonLat.h} | 80 +++++++++++++++-- 7 files changed, 121 insertions(+), 199 deletions(-) delete mode 100644 src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.h delete mode 100644 src/eckit/geo/grid/regular/Mercator.cc rename src/eckit/geo/grid/regular/{LambertAzimuthalEqualArea.cc => XYToLonLat.cc} (56%) rename src/eckit/geo/grid/regular/{Mercator.h => XYToLonLat.h} (50%) diff --git a/etc/eckit/geo/grid.yaml b/etc/eckit/geo/grid.yaml index 27fe1d395..150d9fd19 100644 --- a/etc/eckit/geo/grid.yaml +++ b/etc/eckit/geo/grid.yaml @@ -15,7 +15,7 @@ grid_names: centralLongitudeInDegrees: 10. latitudeOfFirstGridPointInDegrees: 66.982143 longitudeOfFirstGridPointInDegrees: -35.034024 - dimensions: [1000, 950] + shape: [1000, 950] - SMUFF-OPERA-2km: type: lambert_azimuthal_equal_area @@ -25,7 +25,7 @@ grid_names: gaussianNumber: 1280 latitudeOfFirstGridPointInDegrees: 67.035186732680 longitudeOfFirstGridPointInDegrees: -39.535385563614 - dimensions: [1900, 2200] + shape: [1900, 2200] - ORCA2_F: &ORCA2_F type: ORCA diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 73d6c2b06..78705451c 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -73,14 +73,12 @@ list(APPEND eckit_geo_srcs grid/reduced/ReducedLL.h grid/regular/IrregularLL.cc grid/regular/IrregularLL.h - grid/regular/LambertAzimuthalEqualArea.cc - grid/regular/LambertAzimuthalEqualArea.h - grid/regular/Mercator.cc - grid/regular/Mercator.h grid/regular/RegularGaussian.cc grid/regular/RegularGaussian.h grid/regular/RegularLL.cc grid/regular/RegularLL.h + grid/regular/XYToLonLat.cc + grid/regular/XYToLonLat.h grid/unstructured/UnstructuredFromGrid.cc grid/unstructured/UnstructuredFromGrid.h iterator/Reduced.cc diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index 98777a6d9..0deb33b5b 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -62,7 +62,7 @@ class Regular : public Grid { // -- Constructors explicit Regular(const Spec&); - explicit Regular(const area::BoundingBox&); + explicit Regular(const area::BoundingBox& = area::BoundingBox::make_global_prime()); // -- Members // None diff --git a/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.h b/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.h deleted file mode 100644 index 95ba0af35..000000000 --- a/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/Regular.h" - - -namespace eckit::geo::grid::regular { - - -class LambertAzimuthalEqualArea final : public Regular { -public: - // -- Constructors - - explicit LambertAzimuthalEqualArea(const Spec&); - - LambertAzimuthalEqualArea(size_t Nx, size_t Ny, double Dx, double Dy); - - // -- Overridden methods - - iterator cbegin() const override; - iterator cend() const override; - - size_t ni() const override { return Ny_; } - size_t nj() const override { return Nx_; } - -private: - // -- Types - - struct Internal { - explicit Internal(const Spec&); - size_t Nx; - size_t Ny; - double Dx; - double Dy; - }; - - // -- Constructors - - explicit LambertAzimuthalEqualArea(Internal&&); - - // -- Members - - const size_t Nx_; - const size_t Ny_; - const double Dx_; - const double Dy_; - - // -- Overridden methods - - const std::vector& longitudes() const override; - const std::vector& latitudes() const override; - - void spec(spec::Custom&) const override; -}; - - -} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/grid/regular/Mercator.cc b/src/eckit/geo/grid/regular/Mercator.cc deleted file mode 100644 index 9f7c4fff5..000000000 --- a/src/eckit/geo/grid/regular/Mercator.cc +++ /dev/null @@ -1,85 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/regular/Mercator.h" - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/iterator/Regular.h" -#include "eckit/geo/spec/Custom.h" - - -namespace eckit::geo::grid::regular { - - -static const GridRegisterType __grid_type("mercator"); - - -Mercator::Mercator(const Spec& spec) : - Mercator(Internal(spec)) {} - - -Mercator::Mercator(size_t Nx, size_t Ny, double Dx, double Dy) : - Regular(area::BoundingBox{}), Nx_(Nx), Ny_(Ny), Dx_(Dx), Dy_(Dy) {} - - -Grid::iterator Mercator::cbegin() const { - return iterator{new geo::iterator::Regular(*this, 0)}; -} - - -Grid::iterator Mercator::cend() const { - return iterator{new geo::iterator::Regular(*this, size())}; -} - -const std::vector& Mercator::longitudes() const { - NOTIMP; -} - - -const std::vector& Mercator::latitudes() const { - NOTIMP; -} - - -void Mercator::spec(spec::Custom& custom) const { - custom.set("type", "mercator"); - custom.set("grid", std::vector{Dx_, Dy_}); - custom.set("shape", std::vector{static_cast(Nx_), static_cast(Ny_)}); - - // FIXME a lot more stuff to add here! - //... - - NOTIMP; - - if (std::string name; SpecByName::instance().match(custom, name)) { - custom.clear(); - custom.set("grid", name); - } -} - - -Mercator::Internal::Internal(const Spec& spec) { - auto shape(spec.get_unsigned_vector("shape", {0, 0})); - Nx = shape.size() == 2 ? shape[0] : spec.get_unsigned("Nx"); - Ny = shape.size() == 2 ? shape[1] : spec.get_unsigned("Ny"); - ASSERT(Nx > 0); - ASSERT(Ny > 0); - - auto grid(spec.get_double_vector("grid", {0., 0.})); - Dx = grid.size() == 2 ? grid[0] : spec.get_double("Nx"); - Dy = grid.size() == 2 ? grid[1] : spec.get_double("Ny"); - ASSERT(Dx > 0.); - ASSERT(Dy > 0.); -} - - -} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.cc b/src/eckit/geo/grid/regular/XYToLonLat.cc similarity index 56% rename from src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.cc rename to src/eckit/geo/grid/regular/XYToLonLat.cc index 367f19a90..c0863592f 100644 --- a/src/eckit/geo/grid/regular/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/grid/regular/XYToLonLat.cc @@ -10,11 +10,10 @@ */ -#include "eckit/geo/grid/regular/LambertAzimuthalEqualArea.h" +#include "eckit/geo/grid/regular/XYToLonLat.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/Spec.h" -#include "eckit/geo/area/BoundingBox.h" #include "eckit/geo/etc/Grid.h" #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/spec/Custom.h" @@ -23,51 +22,63 @@ namespace eckit::geo::grid::regular { -static const GridRegisterType __grid_type("lambert_azimuthal_equal_area"); +XYToLonLat::XYToLonLat(const Spec& spec) : + XYToLonLat(Internal(spec)) {} -LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Spec& spec) : - LambertAzimuthalEqualArea(Internal(spec)) {} +XYToLonLat::XYToLonLat(Internal&& internal) : + Nx_(internal.Nx), Ny_(internal.Ny), Dx_(internal.Dx), Dy_(internal.Dy) {} -LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(size_t Nx, size_t Ny, double Dx, double Dy) : - Regular(area::BoundingBox{}), Nx_(Nx), Ny_(Ny), Dx_(Dx), Dy_(Dy) {} +XYToLonLat::XYToLonLat(size_t Nx, size_t Ny, double Dx, double Dy) : + XYToLonLat(Internal{Nx, Ny, Dx, Dy}) {} +XYToLonLat::Internal::Internal(const Spec& spec) { + auto shape(spec.get_unsigned_vector("shape", {0, 0})); + Nx = shape.size() == 2 ? shape[0] : spec.get_unsigned("Nx"); + Ny = shape.size() == 2 ? shape[1] : spec.get_unsigned("Ny"); + ASSERT(Nx > 0); + ASSERT(Ny > 0); + + auto grid(spec.get_double_vector("grid", {0., 0.})); + Dx = grid.size() == 2 ? grid[0] : spec.get_double("Nx"); + Dy = grid.size() == 2 ? grid[1] : spec.get_double("Ny"); + ASSERT(Dx > 0.); + ASSERT(Dy > 0.); +} -Grid::iterator LambertAzimuthalEqualArea::cbegin() const { +Grid::iterator XYToLonLat::cbegin() const { return iterator{new geo::iterator::Regular(*this, 0)}; } -Grid::iterator LambertAzimuthalEqualArea::cend() const { +Grid::iterator XYToLonLat::cend() const { return iterator{new geo::iterator::Regular(*this, size())}; } -LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(Internal&& internal) : - LambertAzimuthalEqualArea(internal.Nx, internal.Ny, internal.Dx, internal.Dy) {} - - -const std::vector& LambertAzimuthalEqualArea::longitudes() const { +const std::vector& XYToLonLat::longitudes() const { NOTIMP; } -const std::vector& LambertAzimuthalEqualArea::latitudes() const { +const std::vector& XYToLonLat::latitudes() const { NOTIMP; } -void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { - custom.set("type", "lambert_azimuthal_equal_area"); - custom.set("grid", std::vector{Dx_, Dy_}); - custom.set("shape", std::vector{static_cast(Nx_), static_cast(Ny_)}); +static const GridRegisterType __grid_type1("lambert_azimuthal_equal_area"); +static const GridRegisterType __grid_type2("mercator"); + + +void Mercator::spec(spec::Custom& custom) const { + custom.set("type", "mercator"); + custom.set("grid", std::vector{dj(), di()}); + custom.set("shape", std::vector{static_cast(nj()), static_cast(ni())}); // FIXME a lot more stuff to add here! //... - NOTIMP; - if (std::string name; SpecByName::instance().match(custom, name)) { custom.clear(); custom.set("grid", name); @@ -75,18 +86,18 @@ void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { } -LambertAzimuthalEqualArea::Internal::Internal(const Spec& spec) { - auto shape(spec.get_unsigned_vector("shape", {0, 0})); - Nx = shape.size() == 2 ? shape[0] : spec.get_unsigned("Nx"); - Ny = shape.size() == 2 ? shape[1] : spec.get_unsigned("Ny"); - ASSERT(Nx > 0); - ASSERT(Ny > 0); +void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { + custom.set("type", "lambert_azimuthal_equal_area"); + custom.set("grid", std::vector{dj(), di()}); + custom.set("shape", std::vector{static_cast(nj()), static_cast(ni())}); - auto grid(spec.get_double_vector("grid", {0., 0.})); - Dx = grid.size() == 2 ? grid[0] : spec.get_double("Nx"); - Dy = grid.size() == 2 ? grid[1] : spec.get_double("Ny"); - ASSERT(Dx > 0.); - ASSERT(Dy > 0.); + // FIXME a lot more stuff to add here! + //... + + if (std::string name; SpecByName::instance().match(custom, name)) { + custom.clear(); + custom.set("grid", name); + } } diff --git a/src/eckit/geo/grid/regular/Mercator.h b/src/eckit/geo/grid/regular/XYToLonLat.h similarity index 50% rename from src/eckit/geo/grid/regular/Mercator.h rename to src/eckit/geo/grid/regular/XYToLonLat.h index 7481736f6..e67933d5c 100644 --- a/src/eckit/geo/grid/regular/Mercator.h +++ b/src/eckit/geo/grid/regular/XYToLonLat.h @@ -14,19 +14,35 @@ #include "eckit/geo/grid/Regular.h" -#include "eckit/geo/Increments.h" - namespace eckit::geo::grid::regular { -class Mercator final : public Regular { +class XYToLonLat : public Regular { public: + // -- Types + // None + + // -- Exceptions + // None + // -- Constructors - explicit Mercator(const Spec&); + explicit XYToLonLat(const Spec&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods - Mercator(size_t Nx, size_t Ny, double Dx, double Dy); + double di() const { return Dy_; }; + double dj() const { return Dx_; }; // -- Overridden methods @@ -36,11 +52,20 @@ class Mercator final : public Regular { size_t ni() const override { return Ny_; } size_t nj() const override { return Nx_; } -private: + // -- Class members + // None + + // -- Class methods + // None + +protected: // -- Types struct Internal { explicit Internal(const Spec&); + Internal(size_t Nx, size_t Ny, double Dx, double Dy) : + Nx(Nx), Ny(Ny), Dx(Dx), Dy(Dy) {} + size_t Nx; size_t Ny; double Dx; @@ -49,8 +74,26 @@ class Mercator final : public Regular { // -- Constructors - explicit Mercator(Internal&&); + explicit XYToLonLat(Internal&&); + + XYToLonLat(size_t Nx, size_t Ny, double Dx, double Dy); + + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + // -- Class methods + // None + +private: // -- Members size_t Nx_; @@ -58,11 +101,34 @@ class Mercator final : public Regular { const double Dx_; const double Dy_; + // -- Methods + // None + // -- Overridden methods const std::vector& longitudes() const override; const std::vector& latitudes() const override; + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +struct Mercator final : public XYToLonLat { + explicit Mercator(const Spec& spec) : + XYToLonLat(spec) {} + void spec(spec::Custom&) const override; +}; + +struct LambertAzimuthalEqualArea final : public XYToLonLat { + explicit LambertAzimuthalEqualArea(const Spec& spec) : + XYToLonLat(spec) {} void spec(spec::Custom&) const override; }; From e6332719919c357aaefc486cc07928997887ecdc Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 15 Mar 2024 17:26:22 +0000 Subject: [PATCH 541/737] eckit::geo::PointLonLat --- src/eckit/geo/PointLonLat.cc | 1 + tests/geo/CMakeLists.txt | 1 - tests/geo/coordinate_helpers.cc | 65 --------------------------------- tests/geo/pointlonlat.cc | 43 ++++++++++++++++++++++ 4 files changed, 44 insertions(+), 66 deletions(-) delete mode 100644 tests/geo/coordinate_helpers.cc diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index fe3622b1b..802d02d32 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -26,6 +26,7 @@ PointLonLat::PointLonLat(double lon, double lat) : } } + double PointLonLat::normalise_angle_to_minimum(double a, double minimum) { while (a < minimum) { a += 360.; diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index d10d1fd20..c6862acef 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -2,7 +2,6 @@ foreach(_test area_boundingbox area_polygon cache - coordinate_helpers figure_sphere great_circle grid diff --git a/tests/geo/coordinate_helpers.cc b/tests/geo/coordinate_helpers.cc deleted file mode 100644 index 3ea675b5e..000000000 --- a/tests/geo/coordinate_helpers.cc +++ /dev/null @@ -1,65 +0,0 @@ -/* - * (C) Copyright 2023 UCAR - * - * 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. - */ - - -#include "eckit/geo/CoordinateHelpers.h" -#include "eckit/geo/Point2.h" -#include "eckit/testing/Test.h" - - -namespace eckit::geo::test { - - -CASE("normalise angles") { - EXPECT(0. == normalise_angle(360., 0.)); - EXPECT(14. == normalise_angle(374., 0.)); - EXPECT(14. == normalise_angle(374., -90.)); - EXPECT(374. == normalise_angle(374., 90.)); -} - -CASE("canonicalise on sphere") { - using types::is_approximately_equal; - - const Point2 p1(108., 32.); - - // Worse coordinates for the same point: - const Point2 p2(-252., 32.); - const Point2 p3(288., 148.); - const Point2 p4(108., -328.); - - // Check each of these is correctly shifted back to original point: - const Point2 q2 = canonicaliseOnSphere(p2); - const Point2 q3 = canonicaliseOnSphere(p3); - const Point2 q4 = canonicaliseOnSphere(p4); - - EXPECT(p1.x() == q2.x()); - EXPECT(p1.y() == q2.y()); - EXPECT(p1.x() == q3.x()); - EXPECT(p1.y() == q3.y()); - EXPECT(p1.x() == q4.x()); - EXPECT(p1.y() == q4.y()); - - // Check with longitude offset - const Point2 q2b = canonicaliseOnSphere(p2, -90.); - EXPECT(q2b.x() == 108.); - EXPECT(q2b.y() == 32.); - - const Point2 q2c = canonicaliseOnSphere(p2, 90.); - EXPECT(q2c.x() == 108.); - EXPECT(q2c.y() == 32.); - - const Point2 q2d = canonicaliseOnSphere(p2, 180.); - EXPECT(q2d.x() == 468.); - EXPECT(q2d.y() == 32.); -} - - -} // namespace eckit::geo::test - -int main(int argc, char** argv) { - return eckit::testing::run_tests(argc, argv); -} diff --git a/tests/geo/pointlonlat.cc b/tests/geo/pointlonlat.cc index 89863daf7..a0c90afa5 100644 --- a/tests/geo/pointlonlat.cc +++ b/tests/geo/pointlonlat.cc @@ -77,6 +77,49 @@ CASE("PointLonLat comparison") { Point d1 = PointLonLat{-178., -46.7}; Point d2 = PointLonLat{-178.00000000000003, -46.7}; EXPECT(points_equal(d1, d2)); + + Point e1 = PointLonLat(0., 90.); + Point e2 = PointLonLat(180., 90.); + EXPECT(points_equal(e1, e2)); + + Point f1 = PointLonLat(-0., -90.); + Point f2 = PointLonLat(-180., -90.); + EXPECT(points_equal(f1, f2)); +} + + +CASE("PointLonLat normalise angles") { + EXPECT(0. == PointLonLat::normalise_angle_to_minimum(360., 0.)); + EXPECT(14. == PointLonLat::normalise_angle_to_minimum(374., 0.)); + EXPECT(14. == PointLonLat::normalise_angle_to_minimum(374., -90.)); + EXPECT(374. == PointLonLat::normalise_angle_to_minimum(374., 90.)); +} + + +CASE("PointLonLat canonicalise on sphere") { + const PointLonLat p1(108., 32.); + + // Worse coordinates for the same point: + const auto p2 = PointLonLat::make(-252., 32.); + const auto p3 = PointLonLat::make(288., 148.); + const auto p4 = PointLonLat::make(108., -328.); + + // Check each of these is correctly shifted back to original point: + const PointLonLat q2 = PointLonLat::make(p2.lon, p2.lat); + const PointLonLat q3 = PointLonLat::make(p3.lon, p3.lat); + const PointLonLat q4 = PointLonLat::make(p4.lon, p4.lat); + + EXPECT(p1.lon == q2.lon); + EXPECT(p1.lat == q2.lat); + EXPECT(p1.lon == q3.lon); + EXPECT(p1.lat == q3.lat); + EXPECT(p1.lon == q4.lon); + EXPECT(p1.lat == q4.lat); + + // Check with longitude offset + EXPECT(points_equal(PointLonLat::make(1., -90.), PointLonLat(0., -90.))); + EXPECT(points_equal(PointLonLat::make(2., 90.), PointLonLat(0., 90.))); + EXPECT(points_equal(PointLonLat::make(3., 180.), PointLonLat(183., 0.))); } From 658830172d0d9801d411cd5b7256cccafe1f3093 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 15 Mar 2024 20:04:25 +0000 Subject: [PATCH 542/737] eckit::geo::Projection --- tests/geo/CMakeLists.txt | 5 + tests/geo/projection.cc | 442 ---------------------------- tests/geo/projection_ll_to_xyz.cc | 90 ++++++ tests/geo/projection_mercator.cc | 58 ++++ tests/geo/projection_plate-caree.cc | 44 +++ tests/geo/projection_proj.cc | 122 ++++++++ tests/geo/projection_rotation.cc | 275 +++++++++++++++++ 7 files changed, 594 insertions(+), 442 deletions(-) create mode 100644 tests/geo/projection_ll_to_xyz.cc create mode 100644 tests/geo/projection_mercator.cc create mode 100644 tests/geo/projection_plate-caree.cc create mode 100644 tests/geo/projection_proj.cc create mode 100644 tests/geo/projection_rotation.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index c6862acef..608fd5395 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -19,6 +19,11 @@ foreach(_test point3 pointlonlat projection + projection_ll_to_xyz + projection_mercator + projection_plate-caree + projection_proj + projection_rotation range search spec diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index 03a5c7204..b1f2e7b70 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -10,26 +10,13 @@ */ -#include #include #include "eckit/geo/Projection.h" -#include "eckit/geo/area/BoundingBox.h" -#include "eckit/geo/figure/Sphere.h" -#include "eckit/geo/projection/Composer.h" -#include "eckit/geo/projection/LonLatToXYZ.h" -#include "eckit/geo/projection/Mercator.h" -#include "eckit/geo/projection/Rotation.h" #include "eckit/geo/spec/Custom.h" -#include "eckit/log/Log.h" #include "eckit/testing/Test.h" -namespace eckit::geo::util { -area::BoundingBox bounding_box(Point2, Point2, Projection&); -} - - namespace eckit::geo::test { @@ -45,435 +32,6 @@ CASE("projection: none") { } -CASE("projection: plate-caree") { - Point p = PointLonLat{1, 1}; - Point q = Point2{1, 1}; - P projection(ProjectionFactory::instance().get("plate-carree").create(spec::Custom{})); - - EXPECT(points_equal(q, projection->inv(p))); - EXPECT(std::holds_alternative(projection->inv(p))); - - EXPECT(points_equal(p, projection->fwd(q))); - EXPECT(std::holds_alternative(projection->fwd(q))); -} - - -CASE("projection: ll_to_xyz") { - Point p = PointLonLat{1, 1}; - P s1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"R", 1.}}))); - P s2(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 1.}}))); - P s3(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 0.5}}))); - - EXPECT(points_equal(p, s1->inv(s1->fwd(p)))); - EXPECT(points_equal(p, s2->inv(s2->fwd(p)))); - EXPECT(points_equal(s1->fwd(p), s2->fwd(p))); - - Point q = PointLonLat{1, 0}; - - EXPECT(points_equal(s1->fwd(q), s3->fwd(q))); - EXPECT(points_equal(s2->fwd(q), s3->fwd(q))); - - struct { - PointLonLat a; - Point3 b; - } tests[] = { - {{0, 0}, {1, 0, 0}}, - {{90, 0}, {0, 1, 0}}, - {{180, 0}, {-1, 0, 0}}, - {{270, 0}, {0, -1, 0}}, - {{0, -90}, {0, 0, -0.5}}, - {{42, -90}, {0, 0, -0.5}}, - {{0, 90}, {0, 0, 0.5}}, - {{42, 90}, {0, 0, 0.5}}, - }; - - for (const auto& test : tests) { - EXPECT(points_equal(s3->fwd(test.a), test.b)); - } -} - - -CASE("projection: ll_to_xyz") { - const PointLonLat p(723., 1.); // <- FIXME - - projection::LonLatToXYZ to_xyz_r(1.); - - auto q = to_xyz_r.fwd(p); - auto r = to_xyz_r.inv(q); - Log::info() << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; - - EXPECT(points_equal(p, r)); - - // oblate spheroid (supported) - projection::LonLatToXYZ to_xyz_ab(3., 2.); - - for (const auto& lon : {0., 90., 180., 270.}) { - PointLonLat p{lon, 0.}; - Log::info() << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) << std::endl; - } - - // problate spheroid (not supported) - EXPECT_THROWS(projection::LonLatToXYZ(2., 3.)); -} - - -CASE("projection: rotation") { - constexpr double eps = 1e-6; - - - SECTION("rotation (1)") { - spec::Custom spec({ - {"projection", "rotation"}, - {"south_pole_lat", -91.}, - {"south_pole_lon", -361.}, - }); - - Point p = PointLonLat{1, 1}; - P projection(ProjectionFactory::instance().get(spec.get_string("projection")).create(spec)); - - EXPECT(points_equal(p, projection->inv(projection->fwd(p)))); - EXPECT(points_equal(p, projection->fwd(projection->inv(p)))); - } - - - SECTION("rotation (2)") { - const PointLonLat p(1, 1); - int delta[] = {-360, -180, -1, 0, 1, 90, 91, 180}; - - for (auto a : delta) { - for (auto b : delta) { - for (auto c : delta) { - projection::Rotation rot(0. + static_cast(b), - -90. + static_cast(a), - static_cast(c)); - EXPECT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); - - EXPECT(points_equal(p, rot.inv(rot.fwd(p)), eps)); - EXPECT(points_equal(p, rot.fwd(rot.inv(p)), eps)); - } - } - } - } - - - SECTION("rotation (3)") { - const int Ni = 12; - const int Nj = 3; - - projection::Rotation rot(182., -46.7, 0.); - const PointLonLat ref[]{ - {-178., -46.7}, // - {-178., -16.7}, - {-178., 13.3}, - {-178., 43.3}, - {-178., 73.3}, - {2., 76.7}, - {2., 46.7}, - {-178., -46.7}, - {-162.623427, -19.469294}, - {-152.023657, 8.654593}, - {-139.574639, 36.436827}, - {-113.108943, 61.431994}, - {-39.882454, 68.008245}, - {2., 46.7}, - {-178., -46.7}, - {-148.834426, -27.310675}, - {-129.263456, -3.837005}, - {-110.791162, 20.054216}, - {-85.879167, 41.365070}, - {-44.424956, 53.295076}, - {2., 46.7}, - {-178., -46.7}, - {-137.907940, -39.070023}, - {-109.601456, -21.339065}, - {-88., 0.}, - {-66.398544, 21.339065}, - {-38.092060, 39.070023}, - {2., 46.7}, - {-178., -46.7}, - {-131.575044, -53.295076}, - {-90.120833, -41.365070}, - {-65.208838, -20.054216}, - {-46.736544, 3.837005}, - {-27.165574, 27.310675}, - {2., 46.7}, - {-178., -46.7}, - {-136.117546, -68.008245}, - {-62.891057, -61.431994}, - {-36.425361, -36.436827}, - {-23.976343, -8.654593}, - {-13.376573, 19.469294}, - {2., 46.7}, - {-178., -46.7}, - {-178., -76.7}, - {2., -73.3}, - {2., -43.3}, - {2., -13.3}, - {2., 16.7}, - {2., 46.7}, - {-178., -46.7}, - {140.117546, -68.008245}, - {66.891057, -61.431994}, - {40.425361, -36.436827}, - {27.976343, -8.654593}, - {17.376573, 19.469294}, - {2., 46.7}, - {-178., -46.7}, - {135.575044, -53.295076}, - {94.120833, -41.365070}, - {69.208838, -20.054216}, - {50.736544, 3.837005}, - {31.165574, 27.310675}, - {2., 46.7}, - {-178., -46.7}, - {141.907940, -39.070023}, - {113.601456, -21.339065}, - {92., 0.}, - {70.398544, 21.339065}, - {42.092060, 39.070023}, - {2., 46.7}, - {-178., -46.7}, - {152.834426, -27.310675}, - {133.263456, -3.837005}, - {114.791162, 20.054216}, - {89.879167, 41.365070}, - {48.424956, 53.295076}, - {2., 46.7}, - {-178., -46.7}, - {166.623427, -19.469294}, - {156.023657, 8.654593}, - {143.574639, 36.436827}, - {117.108943, 61.431994}, - {43.882454, 68.008245}, - {2., 46.7}, - }; - - for (int i = 0, k = 0; i < Ni; i++) { - for (int j = 0; j < 2 * Nj + 1; j++, k++) { - PointLonLat a(static_cast(i) * 360. / static_cast(Ni), - static_cast(j - Nj) * 90. / static_cast(Nj)); - auto b = rot.fwd(a); - auto c = rot.inv(b); - - EXPECT(points_equal(b, ref[k], eps)); - EXPECT(points_equal(a, c, eps)); - } - } - } - - - SECTION("rotation (4)") { - const projection::Rotation non_rotated(0., -90., 0.); - const projection::Rotation rotation_angle(0., -90., -180.); - const projection::Rotation rotation_matrix(4., -40., 180.); - - EXPECT(not non_rotated.rotated()); - EXPECT(rotation_angle.rotated()); - EXPECT(rotation_matrix.rotated()); - - const PointLonLat p[] = {{0., 90.}, {0., 0.}, {270., 25.}, {-180., 45.}}; - - struct { - const projection::Rotation& rotation; - const PointLonLat a; - const PointLonLat b; - } tests[] = { - {non_rotated, p[0], p[0]}, - {non_rotated, p[1], p[1]}, - {non_rotated, p[2], p[2]}, - {non_rotated, p[3], p[3]}, - {rotation_angle, p[0], {p[0].lon - 180., p[0].lat}}, - {rotation_angle, p[1], {p[1].lon - 180., p[1].lat}}, - {rotation_angle, p[2], {p[2].lon - 180., p[2].lat}}, - {rotation_angle, p[3], {p[3].lon - 180., p[3].lat}}, - {rotation_matrix, p[0], {-176., 40.}}, - {rotation_matrix, p[1], {-176., -50.}}, - {rotation_matrix, p[2], {113.657357, 15.762700}}, - {rotation_matrix, p[3], {-176., 85.}}, - }; - - for (const auto& test : tests) { - auto b = test.rotation.fwd(test.a); - EXPECT(points_equal(b, test.b, eps)); - - auto a = test.rotation.inv(b); - EXPECT(points_equal(a, test.a, eps)); - } - } - - - SECTION("rotation (5)") { - spec::Custom spec({ - {"projection", "rotation"}, - {"south_pole_lat", -90.}, - {"south_pole_lon", 0.}, - {"angle", 45.}, - }); - - // compose sequentially - const auto& builder = ProjectionFactory::instance().get("rotation"); - P composition1(new projection::Composer{ - builder.create(spec), - builder.create(spec), - builder.create(spec), - builder.create(spec), - builder.create(spec), - builder.create(spec), - builder.create(spec), - }); - - dynamic_cast(composition1.get())->emplace_back(builder.create(spec)); - - for (auto lat : {0., 10., -10.}) { - PointLonLat p{0., lat}; - auto q = composition1->fwd(p); - - EXPECT(points_equal(p, q)); - EXPECT(points_equal(p, composition1->inv(q))); - - auto qs = dynamic_cast(composition1.get())->fwd_points(p); - EXPECT(qs.size() == 8); - - EXPECT(points_equal(qs.front(), PointLonLat{-45., lat})); - EXPECT(points_equal(qs[1], PointLonLat{-90., lat})); - EXPECT(points_equal(qs[2], PointLonLat{-135., lat})); - // ... - EXPECT(points_equal(qs.back(), p)); - } - - // compose by nesting - P composition2(builder.create(spec)); - for (size_t i = 1; i < 8; ++i) { - composition2.reset(projection::Composer::compose_back(composition2.release(), spec)); - } - - for (auto lat : {0., 10., -10.}) { - PointLonLat p{0., lat}; - - auto qs1 = dynamic_cast(composition1.get())->fwd_points(p); - auto qs2 = dynamic_cast(composition2.get())->fwd_points(p); - - ASSERT(qs1.size() == 8); - EXPECT(qs2.size() == 2); - EXPECT(points_equal(qs1[6], qs2[0])); - EXPECT(points_equal(qs1[7], qs2[1])); - } - } -} - - -CASE("projection: proj") { - constexpr double eps = 1e-6; - - - if (ProjectionFactory::instance().exists("proj")) { - PointLonLat a{12., 55.}; - - struct { - const Point b; - const std::string target; - } tests_proj[] = { - {Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, - {Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, - {a, "EPSG:4326"}, - {a, "EPSG:4979"}, - {Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, - {Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, "+proj=cart +R=6371229."}, - {Point3{3574399.5431832, 759762.07693392, 5218815.216709}, "+proj=cart +ellps=sphere"}, - {a, "+proj=latlon +ellps=sphere"}, - }; - - for (const auto& test : tests_proj) { - P projection(ProjectionFactory::instance().get("proj").create( - spec::Custom{{{"source", "EPSG:4326"}, {"target", test.target}}})); - -#if 0 - Log::info() << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) - << std::endl; -#endif - - auto b = projection->fwd(a); - auto c = projection->inv(b); - - EXPECT(points_equal(b, test.b, eps)); - EXPECT(points_equal(c, a, eps)); - - P reverse(ProjectionFactory::instance().get("proj").create( - spec::Custom({{"source", test.target}, {"target", "EPSG:4326"}}))); - - auto d = reverse->fwd(test.b); - auto e = reverse->inv(d); - - EXPECT(points_equal(d, a, eps)); - EXPECT(points_equal(e, test.b, eps)); - } - - P polar_stereographic_north(ProjectionFactory::instance().get("proj").create( - spec::Custom{{{"source", "EPSG:4326"}, {"target", "+proj=stere +lat_0=90. +lon_0=-30. +R=6371229."}}})); - - P polar_stereographic_south(ProjectionFactory::instance().get("proj").create( - spec::Custom{{{"source", "EPSG:4326"}, {"target", "+proj=stere +lat_0=-90. +lon_0=-30. +R=6371229."}}})); - - struct { - const P& projection; - const Point2 min; - const Point2 max; - const bool is_periodic_west_east; - const bool contains_north_pole; - const bool contains_south_pole; - } tests_bbox[] = { - {polar_stereographic_north, {-2e6, -2e6}, {2e6, 2e6}, true, true, false}, - {polar_stereographic_north, {-2e6, -2e6}, {1e6, 1e6}, true, true, false}, - {polar_stereographic_north, {-2e6, -2e6}, {-1e6, -1e6}, false, false, false}, - {polar_stereographic_north, {-1e6, -1e6}, {2e6, 2e6}, true, true, false}, - {polar_stereographic_north, {-1e6, -1e6}, {1e6, 1e6}, true, true, false}, - {polar_stereographic_north, {1e6, 1e6}, {2e6, 2e6}, false, false, false}, - {polar_stereographic_south, {-2e6, -2e6}, {2e6, 2e6}, true, false, true}, - {polar_stereographic_south, {-2e6, -2e6}, {1e6, 1e6}, true, false, true}, - {polar_stereographic_south, {-2e6, -2e6}, {-1e6, -1e6}, false, false, false}, - {polar_stereographic_south, {-1e6, -1e6}, {2e6, 2e6}, true, false, true}, - {polar_stereographic_south, {-1e6, -1e6}, {1e6, 1e6}, true, false, true}, - {polar_stereographic_south, {1e6, 1e6}, {2e6, 2e6}, false, false, false}, - }; - - for (const auto& test : tests_bbox) { - auto bbox = util::bounding_box(test.min, test.max, *test.projection); - - EXPECT_EQUAL(test.is_periodic_west_east, bbox.isPeriodicWestEast()); - EXPECT_EQUAL(test.contains_north_pole, bbox.containsNorthPole()); - EXPECT_EQUAL(test.contains_south_pole, bbox.containsSouthPole()); - } - } -} - - -CASE("projection: mercator") { - PointLonLat first{262.036, 14.7365}; - - - SECTION("mercator (1)") { - projection::Mercator projection(0., 14., new figure::Sphere(6371229.), first); - - Point2 a{0., 0.}; - auto b = projection.inv(a); - auto c = projection.fwd(b); - - EXPECT(points_equal(c, a)); - } - - - SECTION("mercator (2)") { - projection::Mercator projection(-180., 0., new figure::Sphere(1.), {0, 0}); - - PointLonLat a{-75., 35.}; - auto b = projection.fwd({-75, 35}); - auto c = projection.inv(b); - - EXPECT(points_equal(c, a)); - } -} - - } // namespace eckit::geo::test diff --git a/tests/geo/projection_ll_to_xyz.cc b/tests/geo/projection_ll_to_xyz.cc new file mode 100644 index 000000000..2f9b6dd90 --- /dev/null +++ b/tests/geo/projection_ll_to_xyz.cc @@ -0,0 +1,90 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/geo/projection/LonLatToXYZ.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/testing/Test.h" + + +namespace eckit::geo::test { + + +using P = std::unique_ptr; + + +CASE("projection: ll_to_xyz") { + Point p = PointLonLat{1, 1}; + P s1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"R", 1.}}))); + P s2(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 1.}}))); + P s3(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 0.5}}))); + + EXPECT(points_equal(p, s1->inv(s1->fwd(p)))); + EXPECT(points_equal(p, s2->inv(s2->fwd(p)))); + EXPECT(points_equal(s1->fwd(p), s2->fwd(p))); + + Point q = PointLonLat{1, 0}; + + EXPECT(points_equal(s1->fwd(q), s3->fwd(q))); + EXPECT(points_equal(s2->fwd(q), s3->fwd(q))); + + struct { + PointLonLat a; + Point3 b; + } tests[] = { + {{0, 0}, {1, 0, 0}}, + {{90, 0}, {0, 1, 0}}, + {{180, 0}, {-1, 0, 0}}, + {{270, 0}, {0, -1, 0}}, + {{0, -90}, {0, 0, -0.5}}, + {{42, -90}, {0, 0, -0.5}}, + {{0, 90}, {0, 0, 0.5}}, + {{42, 90}, {0, 0, 0.5}}, + }; + + for (const auto& test : tests) { + EXPECT(points_equal(s3->fwd(test.a), test.b)); + } +} + + +CASE("projection: ll_to_xyz") { + const PointLonLat p(723., 1.); // <- FIXME + + projection::LonLatToXYZ to_xyz_r(1.); + + auto q = to_xyz_r.fwd(p); + auto r = to_xyz_r.inv(q); + Log::info() << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; + + EXPECT(points_equal(p, r)); + + // oblate spheroid (supported) + projection::LonLatToXYZ to_xyz_ab(3., 2.); + + for (const auto& lon : {0., 90., 180., 270.}) { + PointLonLat p{lon, 0.}; + Log::info() << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) << std::endl; + } + + // problate spheroid (not supported) + EXPECT_THROWS(projection::LonLatToXYZ(2., 3.)); +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/projection_mercator.cc b/tests/geo/projection_mercator.cc new file mode 100644 index 000000000..2c95b379d --- /dev/null +++ b/tests/geo/projection_mercator.cc @@ -0,0 +1,58 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/geo/figure/Sphere.h" +#include "eckit/geo/projection/Mercator.h" +#include "eckit/testing/Test.h" + + +namespace eckit::geo::test { + + +using P = std::unique_ptr; + + +CASE("projection: mercator") { + PointLonLat first{262.036, 14.7365}; + + + SECTION("mercator (1)") { + projection::Mercator projection(0., 14., new figure::Sphere(6371229.), first); + + Point2 a{0., 0.}; + auto b = projection.inv(a); + auto c = projection.fwd(b); + + EXPECT(points_equal(c, a)); + } + + + SECTION("mercator (2)") { + projection::Mercator projection(-180., 0., new figure::Sphere(1.), {0, 0}); + + PointLonLat a{-75., 35.}; + auto b = projection.fwd({-75, 35}); + auto c = projection.inv(b); + + EXPECT(points_equal(c, a)); + } +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/projection_plate-caree.cc b/tests/geo/projection_plate-caree.cc new file mode 100644 index 000000000..1791750ad --- /dev/null +++ b/tests/geo/projection_plate-caree.cc @@ -0,0 +1,44 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/geo/Projection.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/testing/Test.h" + + +namespace eckit::geo::test { + + +using P = std::unique_ptr; + + +CASE("projection: plate-caree") { + Point p = PointLonLat{1, 1}; + Point q = Point2{1, 1}; + P projection(ProjectionFactory::instance().get("plate-carree").create(spec::Custom{})); + + EXPECT(points_equal(q, projection->inv(p))); + EXPECT(std::holds_alternative(projection->inv(p))); + + EXPECT(points_equal(p, projection->fwd(q))); + EXPECT(std::holds_alternative(projection->fwd(q))); +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/projection_proj.cc b/tests/geo/projection_proj.cc new file mode 100644 index 000000000..490affa25 --- /dev/null +++ b/tests/geo/projection_proj.cc @@ -0,0 +1,122 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/geo/Projection.h" +#include "eckit/geo/area/BoundingBox.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/testing/Test.h" + + +namespace eckit::geo::util { +area::BoundingBox bounding_box(Point2, Point2, Projection&); +} + + +namespace eckit::geo::test { + + +using P = std::unique_ptr; + + +CASE("projection: proj") { + constexpr double eps = 1e-6; + + + if (ProjectionFactory::instance().exists("proj")) { + PointLonLat a{12., 55.}; + + struct { + const Point b; + const std::string target; + } tests_proj[] = { + {Point2{691875.632137542, 6098907.825129169}, "+proj=utm +zone=32 +datum=WGS84"}, + {Point2{691875.632137542, 6098907.825129169}, "EPSG:32632"}, + {a, "EPSG:4326"}, + {a, "EPSG:4979"}, + {Point3{3586469.6567764, 762327.65877826, 5201383.5232023}, "EPSG:4978"}, + {Point3{3574529.7050235, 759789.74368715, 5219005.2599833}, "+proj=cart +R=6371229."}, + {Point3{3574399.5431832, 759762.07693392, 5218815.216709}, "+proj=cart +ellps=sphere"}, + {a, "+proj=latlon +ellps=sphere"}, + }; + + for (const auto& test : tests_proj) { + P projection(ProjectionFactory::instance().get("proj").create( + spec::Custom{{{"source", "EPSG:4326"}, {"target", test.target}}})); + +#if 0 + Log::info() << "ellipsoid: '" << PROJ::ellipsoid(projection.target()) + << std::endl; +#endif + + auto b = projection->fwd(a); + auto c = projection->inv(b); + + EXPECT(points_equal(b, test.b, eps)); + EXPECT(points_equal(c, a, eps)); + + P reverse(ProjectionFactory::instance().get("proj").create( + spec::Custom({{"source", test.target}, {"target", "EPSG:4326"}}))); + + auto d = reverse->fwd(test.b); + auto e = reverse->inv(d); + + EXPECT(points_equal(d, a, eps)); + EXPECT(points_equal(e, test.b, eps)); + } + + P polar_stereographic_north(ProjectionFactory::instance().get("proj").create( + spec::Custom{{{"source", "EPSG:4326"}, {"target", "+proj=stere +lat_0=90. +lon_0=-30. +R=6371229."}}})); + + P polar_stereographic_south(ProjectionFactory::instance().get("proj").create( + spec::Custom{{{"source", "EPSG:4326"}, {"target", "+proj=stere +lat_0=-90. +lon_0=-30. +R=6371229."}}})); + + struct { + const P& projection; + const Point2 min; + const Point2 max; + const bool is_periodic_west_east; + const bool contains_north_pole; + const bool contains_south_pole; + } tests_bbox[] = { + {polar_stereographic_north, {-2e6, -2e6}, {2e6, 2e6}, true, true, false}, + {polar_stereographic_north, {-2e6, -2e6}, {1e6, 1e6}, true, true, false}, + {polar_stereographic_north, {-2e6, -2e6}, {-1e6, -1e6}, false, false, false}, + {polar_stereographic_north, {-1e6, -1e6}, {2e6, 2e6}, true, true, false}, + {polar_stereographic_north, {-1e6, -1e6}, {1e6, 1e6}, true, true, false}, + {polar_stereographic_north, {1e6, 1e6}, {2e6, 2e6}, false, false, false}, + {polar_stereographic_south, {-2e6, -2e6}, {2e6, 2e6}, true, false, true}, + {polar_stereographic_south, {-2e6, -2e6}, {1e6, 1e6}, true, false, true}, + {polar_stereographic_south, {-2e6, -2e6}, {-1e6, -1e6}, false, false, false}, + {polar_stereographic_south, {-1e6, -1e6}, {2e6, 2e6}, true, false, true}, + {polar_stereographic_south, {-1e6, -1e6}, {1e6, 1e6}, true, false, true}, + {polar_stereographic_south, {1e6, 1e6}, {2e6, 2e6}, false, false, false}, + }; + + for (const auto& test : tests_bbox) { + auto bbox = util::bounding_box(test.min, test.max, *test.projection); + + EXPECT_EQUAL(test.is_periodic_west_east, bbox.isPeriodicWestEast()); + EXPECT_EQUAL(test.contains_north_pole, bbox.containsNorthPole()); + EXPECT_EQUAL(test.contains_south_pole, bbox.containsSouthPole()); + } + } +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/projection_rotation.cc b/tests/geo/projection_rotation.cc new file mode 100644 index 000000000..9502494d8 --- /dev/null +++ b/tests/geo/projection_rotation.cc @@ -0,0 +1,275 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/geo/projection/Composer.h" +#include "eckit/geo/projection/Rotation.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/testing/Test.h" + + +namespace eckit::geo::test { + + +using P = std::unique_ptr; + + +constexpr double eps = 1e-6; + + +CASE("rotation (1)") { + spec::Custom spec({ + {"projection", "rotation"}, + {"south_pole_lat", -91.}, + {"south_pole_lon", -361.}, + }); + + Point p = PointLonLat{1, 1}; + P projection(ProjectionFactory::instance().get(spec.get_string("projection")).create(spec)); + + EXPECT(points_equal(p, projection->inv(projection->fwd(p)))); + EXPECT(points_equal(p, projection->fwd(projection->inv(p)))); +} + + +CASE("rotation (2)") { + const PointLonLat p(1, 1); + int delta[] = {-360, -180, -1, 0, 1, 90, 91, 180}; + + for (auto a : delta) { + for (auto b : delta) { + for (auto c : delta) { + projection::Rotation rot(0. + static_cast(b), + -90. + static_cast(a), + static_cast(c)); + EXPECT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); + + EXPECT(points_equal(p, rot.inv(rot.fwd(p)), eps)); + EXPECT(points_equal(p, rot.fwd(rot.inv(p)), eps)); + } + } + } +} + + +CASE("rotation (3)") { + const int Ni = 12; + const int Nj = 3; + + projection::Rotation rot(182., -46.7, 0.); + const PointLonLat ref[]{ + {-178., -46.7}, // + {-178., -16.7}, + {-178., 13.3}, + {-178., 43.3}, + {-178., 73.3}, + {2., 76.7}, + {2., 46.7}, + {-178., -46.7}, + {-162.623427, -19.469294}, + {-152.023657, 8.654593}, + {-139.574639, 36.436827}, + {-113.108943, 61.431994}, + {-39.882454, 68.008245}, + {2., 46.7}, + {-178., -46.7}, + {-148.834426, -27.310675}, + {-129.263456, -3.837005}, + {-110.791162, 20.054216}, + {-85.879167, 41.365070}, + {-44.424956, 53.295076}, + {2., 46.7}, + {-178., -46.7}, + {-137.907940, -39.070023}, + {-109.601456, -21.339065}, + {-88., 0.}, + {-66.398544, 21.339065}, + {-38.092060, 39.070023}, + {2., 46.7}, + {-178., -46.7}, + {-131.575044, -53.295076}, + {-90.120833, -41.365070}, + {-65.208838, -20.054216}, + {-46.736544, 3.837005}, + {-27.165574, 27.310675}, + {2., 46.7}, + {-178., -46.7}, + {-136.117546, -68.008245}, + {-62.891057, -61.431994}, + {-36.425361, -36.436827}, + {-23.976343, -8.654593}, + {-13.376573, 19.469294}, + {2., 46.7}, + {-178., -46.7}, + {-178., -76.7}, + {2., -73.3}, + {2., -43.3}, + {2., -13.3}, + {2., 16.7}, + {2., 46.7}, + {-178., -46.7}, + {140.117546, -68.008245}, + {66.891057, -61.431994}, + {40.425361, -36.436827}, + {27.976343, -8.654593}, + {17.376573, 19.469294}, + {2., 46.7}, + {-178., -46.7}, + {135.575044, -53.295076}, + {94.120833, -41.365070}, + {69.208838, -20.054216}, + {50.736544, 3.837005}, + {31.165574, 27.310675}, + {2., 46.7}, + {-178., -46.7}, + {141.907940, -39.070023}, + {113.601456, -21.339065}, + {92., 0.}, + {70.398544, 21.339065}, + {42.092060, 39.070023}, + {2., 46.7}, + {-178., -46.7}, + {152.834426, -27.310675}, + {133.263456, -3.837005}, + {114.791162, 20.054216}, + {89.879167, 41.365070}, + {48.424956, 53.295076}, + {2., 46.7}, + {-178., -46.7}, + {166.623427, -19.469294}, + {156.023657, 8.654593}, + {143.574639, 36.436827}, + {117.108943, 61.431994}, + {43.882454, 68.008245}, + {2., 46.7}, + }; + + for (int i = 0, k = 0; i < Ni; i++) { + for (int j = 0; j < 2 * Nj + 1; j++, k++) { + PointLonLat a(static_cast(i) * 360. / static_cast(Ni), + static_cast(j - Nj) * 90. / static_cast(Nj)); + auto b = rot.fwd(a); + auto c = rot.inv(b); + + EXPECT(points_equal(b, ref[k], eps)); + EXPECT(points_equal(a, c, eps)); + } + } +} + + +CASE("rotation (4)") { + const projection::Rotation non_rotated(0., -90., 0.); + const projection::Rotation rotation_angle(0., -90., -180.); + const projection::Rotation rotation_matrix(4., -40., 180.); + + EXPECT(not non_rotated.rotated()); + EXPECT(rotation_angle.rotated()); + EXPECT(rotation_matrix.rotated()); + + const PointLonLat p[] = {{0., 90.}, {0., 0.}, {270., 25.}, {-180., 45.}}; + + struct { + const projection::Rotation& rotation; + const PointLonLat a; + const PointLonLat b; + } tests[] = { + {non_rotated, p[0], p[0]}, + {non_rotated, p[1], p[1]}, + {non_rotated, p[2], p[2]}, + {non_rotated, p[3], p[3]}, + {rotation_angle, p[0], {p[0].lon - 180., p[0].lat}}, + {rotation_angle, p[1], {p[1].lon - 180., p[1].lat}}, + {rotation_angle, p[2], {p[2].lon - 180., p[2].lat}}, + {rotation_angle, p[3], {p[3].lon - 180., p[3].lat}}, + {rotation_matrix, p[0], {-176., 40.}}, + {rotation_matrix, p[1], {-176., -50.}}, + {rotation_matrix, p[2], {113.657357, 15.762700}}, + {rotation_matrix, p[3], {-176., 85.}}, + }; + + for (const auto& test : tests) { + auto b = test.rotation.fwd(test.a); + EXPECT(points_equal(b, test.b, eps)); + + auto a = test.rotation.inv(b); + EXPECT(points_equal(a, test.a, eps)); + } +} + + +CASE("rotation (5)") { + spec::Custom spec({ + {"projection", "rotation"}, + {"south_pole_lat", -90.}, + {"south_pole_lon", 0.}, + {"angle", 45.}, + }); + + // compose sequentially + const auto& builder = ProjectionFactory::instance().get("rotation"); + P composition1(new projection::Composer{ + builder.create(spec), + builder.create(spec), + builder.create(spec), + builder.create(spec), + builder.create(spec), + builder.create(spec), + builder.create(spec), + }); + + dynamic_cast(composition1.get())->emplace_back(builder.create(spec)); + + for (auto lat : {0., 10., -10.}) { + PointLonLat p{0., lat}; + auto q = composition1->fwd(p); + + EXPECT(points_equal(p, q)); + EXPECT(points_equal(p, composition1->inv(q))); + + auto qs = dynamic_cast(composition1.get())->fwd_points(p); + EXPECT(qs.size() == 8); + + EXPECT(points_equal(qs.front(), PointLonLat{-45., lat})); + EXPECT(points_equal(qs[1], PointLonLat{-90., lat})); + EXPECT(points_equal(qs[2], PointLonLat{-135., lat})); + // ... + EXPECT(points_equal(qs.back(), p)); + } + + // compose by nesting + P composition2(builder.create(spec)); + for (size_t i = 1; i < 8; ++i) { + composition2.reset(projection::Composer::compose_back(composition2.release(), spec)); + } + + for (auto lat : {0., 10., -10.}) { + PointLonLat p{0., lat}; + + auto qs1 = dynamic_cast(composition1.get())->fwd_points(p); + auto qs2 = dynamic_cast(composition2.get())->fwd_points(p); + + ASSERT(qs1.size() == 8); + EXPECT(qs2.size() == 2); + EXPECT(points_equal(qs1[6], qs2[0])); + EXPECT(points_equal(qs1[7], qs2[1])); + } +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From 7e683110d840d6b8cca15d8fd92524cde66074a8 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 16 Mar 2024 07:40:11 +0000 Subject: [PATCH 543/737] eckit::geo::Spec --- src/eckit/geo/Spec.h | 2 +- src/eckit/geo/grid/regular/XYToLonLat.cc | 54 ++++++++++++++++-------- src/eckit/geo/grid/regular/XYToLonLat.h | 34 ++++++++------- src/eckit/geo/spec/Layered.cc | 4 +- tests/geo/spec.cc | 3 +- 5 files changed, 60 insertions(+), 37 deletions(-) diff --git a/src/eckit/geo/Spec.h b/src/eckit/geo/Spec.h index 3f7c5a453..aa022ff8f 100644 --- a/src/eckit/geo/Spec.h +++ b/src/eckit/geo/Spec.h @@ -27,7 +27,7 @@ namespace eckit::geo { class SpecNotFound : public Exception { public: - explicit SpecNotFound(const std::string& name); + explicit SpecNotFound(const std::string&); }; diff --git a/src/eckit/geo/grid/regular/XYToLonLat.cc b/src/eckit/geo/grid/regular/XYToLonLat.cc index c0863592f..f22e6e83c 100644 --- a/src/eckit/geo/grid/regular/XYToLonLat.cc +++ b/src/eckit/geo/grid/regular/XYToLonLat.cc @@ -27,23 +27,43 @@ XYToLonLat::XYToLonLat(const Spec& spec) : XYToLonLat::XYToLonLat(Internal&& internal) : - Nx_(internal.Nx), Ny_(internal.Ny), Dx_(internal.Dx), Dy_(internal.Dy) {} - - -XYToLonLat::XYToLonLat(size_t Nx, size_t Ny, double Dx, double Dy) : - XYToLonLat(Internal{Nx, Ny, Dx, Dy}) {} -XYToLonLat::Internal::Internal(const Spec& spec) { - auto shape(spec.get_unsigned_vector("shape", {0, 0})); - Nx = shape.size() == 2 ? shape[0] : spec.get_unsigned("Nx"); - Ny = shape.size() == 2 ? shape[1] : spec.get_unsigned("Ny"); - ASSERT(Nx > 0); - ASSERT(Ny > 0); - - auto grid(spec.get_double_vector("grid", {0., 0.})); - Dx = grid.size() == 2 ? grid[0] : spec.get_double("Nx"); - Dy = grid.size() == 2 ? grid[1] : spec.get_double("Ny"); - ASSERT(Dx > 0.); - ASSERT(Dy > 0.); + internal_(internal) {} + + +XYToLonLat::XYToLonLat(double dx, double dy, size_t nx, size_t ny) : + XYToLonLat(Internal{dx, dy, nx, ny}) {} + + +XYToLonLat::Internal::Internal(const Spec& spec) : + grid{0., 0.}, shape{0, 0} { + if (std::vector value; spec.get("shape", value) && value.size() == 2) { + shape = {value[0], value[1]}; + } + else if (!spec.get("nx", shape[0]) || !spec.get("ny", shape[1])) { + throw SpecNotFound("'shape': ['nx', 'ny'] expected"); + } + + if (std::vector value; spec.get("grid", value) && value.size() == 2) { + grid = {value[0], value[1]}; + } + else if (!spec.get("dx", grid[0]) || !spec.get("dy", grid[1])) { + throw SpecNotFound("'grid': ['dx', 'dy'] expected"); + } + + check(); +} + +XYToLonLat::Internal::Internal(double dx, double dy, size_t nx, size_t ny) : + grid{dx, dy}, shape{nx, ny} { + check(); +} + + +void XYToLonLat::Internal::check() const { + ASSERT_MSG(grid[0] > 0 && grid[1] > 0, + "'grid' > 0 failed, got grid: [" + std::to_string(grid[0]) + ", " + std::to_string(grid[0]) + "]"); + ASSERT_MSG(shape[0] > 0 && shape[1] > 0, + "'shape' > 0 failed, got shape: [" + std::to_string(shape[0]) + ", " + std::to_string(shape[0]) + "]"); } diff --git a/src/eckit/geo/grid/regular/XYToLonLat.h b/src/eckit/geo/grid/regular/XYToLonLat.h index e67933d5c..d82a3b95a 100644 --- a/src/eckit/geo/grid/regular/XYToLonLat.h +++ b/src/eckit/geo/grid/regular/XYToLonLat.h @@ -12,6 +12,8 @@ #pragma once +#include + #include "eckit/geo/grid/Regular.h" @@ -41,16 +43,22 @@ class XYToLonLat : public Regular { // -- Methods - double di() const { return Dy_; }; - double dj() const { return Dx_; }; + double dx() const { return internal_.grid[0]; }; + double dy() const { return internal_.grid[1]; }; + + size_t nx() const { return internal_.shape[0]; } + size_t ny() const { return internal_.shape[1]; } + + double di() const { return dy(); }; + double dj() const { return dx(); }; // -- Overridden methods iterator cbegin() const override; iterator cend() const override; - size_t ni() const override { return Ny_; } - size_t nj() const override { return Nx_; } + size_t ni() const override { return ny(); } + size_t nj() const override { return nx(); } // -- Class members // None @@ -63,20 +71,19 @@ class XYToLonLat : public Regular { struct Internal { explicit Internal(const Spec&); - Internal(size_t Nx, size_t Ny, double Dx, double Dy) : - Nx(Nx), Ny(Ny), Dx(Dx), Dy(Dy) {} + Internal(double dx, double dy, size_t nx, size_t ny); + + void check() const; - size_t Nx; - size_t Ny; - double Dx; - double Dy; + std::array grid; + std::array shape; }; // -- Constructors explicit XYToLonLat(Internal&&); - XYToLonLat(size_t Nx, size_t Ny, double Dx, double Dy); + XYToLonLat(double dx, double dy, size_t nx, size_t ny); // -- Members // None @@ -96,10 +103,7 @@ class XYToLonLat : public Regular { private: // -- Members - size_t Nx_; - size_t Ny_; - const double Dx_; - const double Dy_; + const Internal internal_; // -- Methods // None diff --git a/src/eckit/geo/spec/Layered.cc b/src/eckit/geo/spec/Layered.cc index d1b4e0164..4fc9afb9d 100644 --- a/src/eckit/geo/spec/Layered.cc +++ b/src/eckit/geo/spec/Layered.cc @@ -19,11 +19,11 @@ namespace eckit::geo::spec { -static const Custom __empty_spec; +static const Custom EMPTY; Layered::Layered() : - Layered(__empty_spec) {} + Layered(EMPTY) {} Layered::Layered(const Spec& spec) : diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 56f0065c3..34a04d349 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -289,9 +289,8 @@ CASE("spec") { {C({{"type", "mercator"}, {"area", v{31.173058, 262.036499, 14.736453, 284.975281}}, {"grid", v{45000.0, 45000.0}}, + {"shape", std::vector{56, 44}}, {"lad", 14.0}, - {"nx", 56}, - {"ny", 44}, {"orientation", 0.0}}), C()}, }; From a5b30f27ea0b6e6f656b170279665869be1159db Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 16 Mar 2024 09:00:01 +0000 Subject: [PATCH 544/737] eckit::geo::Spec --- src/eckit/geo/spec/Custom.cc | 19 ++++++++++++++----- src/eckit/geo/spec/Custom.h | 8 +++++++- tests/geo/spec.cc | 14 +++++--------- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 84ef277f5..8563beb37 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -12,6 +12,7 @@ #include "eckit/geo/spec/Custom.h" #include +#include #include #include "eckit/exception/Exceptions.h" @@ -133,6 +134,12 @@ JSON& operator<<(JSON& out, const Custom::value_type& value) { } // namespace +Custom::key_type::key_type(const std::string& s) : + std::string{s} { + std::transform(begin(), end(), begin(), [](unsigned char c) -> unsigned char { return std::tolower(c); }); +} + + Custom::Custom(const Custom::container_type& map) : map_(map) {} @@ -160,7 +167,8 @@ Custom::Custom(const Value& value) { ASSERT(value.isMap()); for (const auto& [key, value] : static_cast(value)) { - map_[key] = value.isList() ? vector(value) : scalar(value); + const std::string name = key; + map_[name] = value.isList() ? vector(value) : scalar(value); } } @@ -372,10 +380,11 @@ bool Custom::get(const std::string& name, std::vector& value) const { bool Custom::get(const std::string& name, std::vector& value) const { - auto it = map_.find(name); - if (it != map_.cend() && std::holds_alternative>(it->second)) { - value = std::get>(it->second); - return true; + if (auto it = map_.find(name); it != map_.cend()) { + if (std::holds_alternative>(it->second)) { + value = std::get>(it->second); + return true; + } } return false; } diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 69e6be492..229fd4d4a 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -29,6 +29,12 @@ class Custom final : public Spec { public: // -- Types + struct key_type : std::string { + key_type(const std::string&); + key_type(const char* s) : + key_type(std::string{s}) {}; + }; + using value_type = std::variant, std::vector>; - using container_type = std::map; + using container_type = std::map; // -- Constructors diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 34a04d349..804dfd58a 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -22,14 +22,6 @@ #include "eckit/types/FloatCompare.h" -#define EXPECT_APPROX(a, b, eps) EXPECT(::eckit::types::is_approximately_equal((a), (b), (eps))) - -#define EXPECT_AREA(a, b, eps) \ - EXPECT((a).size() == 4 && (b).size() == 4 && EXPECT_APPROX((a)[0], (b)[0], (eps)) && \ - EXPECT_APPROX((a)[1], (b)[1], (eps)) && EXPECT_APPROX((a)[2], (b)[2], (eps)) && \ - EXPECT_APPROX((a)[3], (b)[3], (eps))) - - namespace eckit::geo::test { @@ -56,8 +48,12 @@ CASE("Spec <- Custom") { EXPECT(spec->get("c", c)); EXPECT_EQUAL(c, 123UL); + std::string b2; + EXPECT(spec->get("B", b2)); + EXPECT_EQUAL(b2, b); + int d = 0; - dynamic_cast(spec.get())->set("b", 321); + dynamic_cast(spec.get())->set("B", 321); EXPECT(spec->get("b", d)); EXPECT_EQUAL(d, 321); } From 506399905113d98fb3d3fa4a5182c1c4ebc97f55 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 16 Mar 2024 10:01:12 +0000 Subject: [PATCH 545/737] eckit::geo::PointLonLat --- tests/geo/projection_rotation.cc | 223 +++++++++++++++++-------------- 1 file changed, 120 insertions(+), 103 deletions(-) diff --git a/tests/geo/projection_rotation.cc b/tests/geo/projection_rotation.cc index 9502494d8..871ab42d2 100644 --- a/tests/geo/projection_rotation.cc +++ b/tests/geo/projection_rotation.cc @@ -24,7 +24,7 @@ namespace eckit::geo::test { using P = std::unique_ptr; -constexpr double eps = 1e-6; +constexpr double EPS = 1e-6; CASE("rotation (1)") { @@ -54,8 +54,8 @@ CASE("rotation (2)") { static_cast(c)); EXPECT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); - EXPECT(points_equal(p, rot.inv(rot.fwd(p)), eps)); - EXPECT(points_equal(p, rot.fwd(rot.inv(p)), eps)); + EXPECT(points_equal(p, rot.inv(rot.fwd(p)), EPS)); + EXPECT(points_equal(p, rot.fwd(rot.inv(p)), EPS)); } } } @@ -63,106 +63,123 @@ CASE("rotation (2)") { CASE("rotation (3)") { - const int Ni = 12; - const int Nj = 3; - - projection::Rotation rot(182., -46.7, 0.); - const PointLonLat ref[]{ - {-178., -46.7}, // - {-178., -16.7}, - {-178., 13.3}, - {-178., 43.3}, - {-178., 73.3}, - {2., 76.7}, - {2., 46.7}, - {-178., -46.7}, - {-162.623427, -19.469294}, - {-152.023657, 8.654593}, - {-139.574639, 36.436827}, - {-113.108943, 61.431994}, - {-39.882454, 68.008245}, - {2., 46.7}, - {-178., -46.7}, - {-148.834426, -27.310675}, - {-129.263456, -3.837005}, - {-110.791162, 20.054216}, - {-85.879167, 41.365070}, - {-44.424956, 53.295076}, - {2., 46.7}, - {-178., -46.7}, - {-137.907940, -39.070023}, - {-109.601456, -21.339065}, - {-88., 0.}, - {-66.398544, 21.339065}, - {-38.092060, 39.070023}, - {2., 46.7}, - {-178., -46.7}, - {-131.575044, -53.295076}, - {-90.120833, -41.365070}, - {-65.208838, -20.054216}, - {-46.736544, 3.837005}, - {-27.165574, 27.310675}, - {2., 46.7}, - {-178., -46.7}, - {-136.117546, -68.008245}, - {-62.891057, -61.431994}, - {-36.425361, -36.436827}, - {-23.976343, -8.654593}, - {-13.376573, 19.469294}, - {2., 46.7}, - {-178., -46.7}, - {-178., -76.7}, - {2., -73.3}, - {2., -43.3}, - {2., -13.3}, - {2., 16.7}, - {2., 46.7}, - {-178., -46.7}, - {140.117546, -68.008245}, - {66.891057, -61.431994}, - {40.425361, -36.436827}, - {27.976343, -8.654593}, - {17.376573, 19.469294}, - {2., 46.7}, - {-178., -46.7}, - {135.575044, -53.295076}, - {94.120833, -41.365070}, - {69.208838, -20.054216}, - {50.736544, 3.837005}, - {31.165574, 27.310675}, - {2., 46.7}, - {-178., -46.7}, - {141.907940, -39.070023}, - {113.601456, -21.339065}, - {92., 0.}, - {70.398544, 21.339065}, - {42.092060, 39.070023}, - {2., 46.7}, - {-178., -46.7}, - {152.834426, -27.310675}, - {133.263456, -3.837005}, - {114.791162, 20.054216}, - {89.879167, 41.365070}, - {48.424956, 53.295076}, - {2., 46.7}, - {-178., -46.7}, - {166.623427, -19.469294}, - {156.023657, 8.654593}, - {143.574639, 36.436827}, - {117.108943, 61.431994}, - {43.882454, 68.008245}, - {2., 46.7}, - }; + const PointLonLat sp(182., -46.7); + projection::Rotation rot(sp.lon, sp.lat, 0.); + + ASSERT(points_equal(sp.antipode(), PointLonLat{2., 46.7})); - for (int i = 0, k = 0; i < Ni; i++) { - for (int j = 0; j < 2 * Nj + 1; j++, k++) { - PointLonLat a(static_cast(i) * 360. / static_cast(Ni), - static_cast(j - Nj) * 90. / static_cast(Nj)); - auto b = rot.fwd(a); - auto c = rot.inv(b); - EXPECT(points_equal(b, ref[k], eps)); - EXPECT(points_equal(a, c, eps)); + SECTION("pole point") { + PointLonLat a(0., 90.); + auto b = rot.fwd(a); + auto c = rot.inv(b); + + EXPECT(points_equal(b, sp.antipode(), EPS)); + EXPECT(points_equal(a, c, EPS)); + } + + + SECTION("many points") { + const int Ni = 12; + const int Nj = 3; + + const PointLonLat ref[]{ + {-178., -46.7}, // + {-178., -16.7}, + {-178., 13.3}, + {-178., 43.3}, + {-178., 73.3}, + {2., 76.7}, + {2., 46.7}, + {-178., -46.7}, + {-162.623427, -19.469294}, + {-152.023657, 8.654593}, + {-139.574639, 36.436827}, + {-113.108943, 61.431994}, + {-39.882454, 68.008245}, + {2., 46.7}, + {-178., -46.7}, + {-148.834426, -27.310675}, + {-129.263456, -3.837005}, + {-110.791162, 20.054216}, + {-85.879167, 41.365070}, + {-44.424956, 53.295076}, + {2., 46.7}, + {-178., -46.7}, + {-137.907940, -39.070023}, + {-109.601456, -21.339065}, + {-88., 0.}, + {-66.398544, 21.339065}, + {-38.092060, 39.070023}, + {2., 46.7}, + {-178., -46.7}, + {-131.575044, -53.295076}, + {-90.120833, -41.365070}, + {-65.208838, -20.054216}, + {-46.736544, 3.837005}, + {-27.165574, 27.310675}, + {2., 46.7}, + {-178., -46.7}, + {-136.117546, -68.008245}, + {-62.891057, -61.431994}, + {-36.425361, -36.436827}, + {-23.976343, -8.654593}, + {-13.376573, 19.469294}, + {2., 46.7}, + {-178., -46.7}, + {-178., -76.7}, + {2., -73.3}, + {2., -43.3}, + {2., -13.3}, + {2., 16.7}, + {2., 46.7}, + {-178., -46.7}, + {140.117546, -68.008245}, + {66.891057, -61.431994}, + {40.425361, -36.436827}, + {27.976343, -8.654593}, + {17.376573, 19.469294}, + {2., 46.7}, + {-178., -46.7}, + {135.575044, -53.295076}, + {94.120833, -41.365070}, + {69.208838, -20.054216}, + {50.736544, 3.837005}, + {31.165574, 27.310675}, + {2., 46.7}, + {-178., -46.7}, + {141.907940, -39.070023}, + {113.601456, -21.339065}, + {92., 0.}, + {70.398544, 21.339065}, + {42.092060, 39.070023}, + {2., 46.7}, + {-178., -46.7}, + {152.834426, -27.310675}, + {133.263456, -3.837005}, + {114.791162, 20.054216}, + {89.879167, 41.365070}, + {48.424956, 53.295076}, + {2., 46.7}, + {-178., -46.7}, + {166.623427, -19.469294}, + {156.023657, 8.654593}, + {143.574639, 36.436827}, + {117.108943, 61.431994}, + {43.882454, 68.008245}, + {2., 46.7}, + }; + + for (int i = 0, k = 0; i < Ni; i++) { + for (int j = 0; j < 2 * Nj + 1; j++, k++) { + PointLonLat a(static_cast(i) * 360. / static_cast(Ni), + static_cast(j - Nj) * 90. / static_cast(Nj)); + auto b = rot.fwd(a); + auto c = rot.inv(b); + + EXPECT(points_equal(b, ref[k], EPS)); + EXPECT(points_equal(a, c, EPS)); + } } } } @@ -200,10 +217,10 @@ CASE("rotation (4)") { for (const auto& test : tests) { auto b = test.rotation.fwd(test.a); - EXPECT(points_equal(b, test.b, eps)); + EXPECT(points_equal(b, test.b, EPS)); auto a = test.rotation.inv(b); - EXPECT(points_equal(a, test.a, eps)); + EXPECT(points_equal(a, test.a, EPS)); } } From 2c3c0742019e58166d458a82eafd3f06d2c7f70b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 16 Mar 2024 10:25:53 +0000 Subject: [PATCH 546/737] eckit::geo::PointLonLat --- src/eckit/geo/PointLonLat.cc | 22 +++++++++++++++++----- src/eckit/geo/PointLonLat.h | 11 +---------- tests/geo/pointlonlat.cc | 6 ++++++ 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index 802d02d32..aefc09847 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -49,12 +49,24 @@ double PointLonLat::normalise_angle_to_maximum(double a, double maximum) { } +PointLonLat PointLonLat::make(double lon, double lat, double lon_minimum, double eps) { + lat = normalise_angle_to_minimum(lat, -90.); + + if (types::is_strictly_greater(lat, 90., eps)) { + lat = 180. - lat; + lon += 180.; + } + + return types::is_approximately_equal(lat, 90., eps) ? PointLonLat{0., 90.} + : types::is_approximately_equal(lat, -90., eps) + ? PointLonLat{0., -90.} + : PointLonLat{normalise_angle_to_minimum(lon, lon_minimum), lat}; +} + + bool points_equal(const PointLonLat& a, const PointLonLat& b, double eps) { - // FIXME - // solved {180., 0.} == {-180., 0.} - // could be more performant - auto c = PointLonLat::make(a.lon, a.lat); - auto d = PointLonLat::make(b.lon, b.lat); + auto c = PointLonLat::make(a.lon, a.lat, 0., eps); + auto d = PointLonLat::make(b.lon, b.lat, 0., eps); return types::is_approximately_equal(c.lon, d.lon, eps) && types::is_approximately_equal(c.lat, d.lat, eps); } diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index b84ed4176..48c449aef 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -73,16 +73,7 @@ class PointLonLat final : protected std::array { static double normalise_angle_to_maximum(double, double maximum); - static PointLonLat make(double lon, double lat, double lon_minimum = 0) { - lat = normalise_angle_to_minimum(lat, -90.); - - if (lat > 90.) { - lat = 180. - lat; - lon += 180.; - } - - return {lat == -90. || lat == 90. ? 0. : normalise_angle_to_minimum(lon, lon_minimum), lat}; - } + static PointLonLat make(double lon, double lat, double lon_minimum = 0, double eps = EPS); PointLonLat antipode() const { return make(lon, lat + 180.); } diff --git a/tests/geo/pointlonlat.cc b/tests/geo/pointlonlat.cc index a0c90afa5..75989d0a6 100644 --- a/tests/geo/pointlonlat.cc +++ b/tests/geo/pointlonlat.cc @@ -120,6 +120,12 @@ CASE("PointLonLat canonicalise on sphere") { EXPECT(points_equal(PointLonLat::make(1., -90.), PointLonLat(0., -90.))); EXPECT(points_equal(PointLonLat::make(2., 90.), PointLonLat(0., 90.))); EXPECT(points_equal(PointLonLat::make(3., 180.), PointLonLat(183., 0.))); + + // Check with latitude offset + constexpr double eps = 1.e-6; + + EXPECT(points_equal(PointLonLat::make(-1., 89.99999914622634, 0., eps), {0., 90.})); + EXPECT(points_equal(PointLonLat::make(1., -89.99999914622634, 0., eps), {0., -90.})); } From 98d145a52956579fad2b119167af2537a68378e9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 16 Mar 2024 11:05:15 +0000 Subject: [PATCH 547/737] eckit::geo::PointLonLat port of PR Normalise angle fix #103 Co-authored-by: John Haiducek Co-authored-by: Willem Deconinck --- src/eckit/geo/PointLonLat.cc | 11 ++++------- tests/geo/pointlonlat.cc | 8 ++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index aefc09847..de86a94a5 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -12,6 +12,8 @@ #include "eckit/geo/PointLonLat.h" +#include + #include "eckit/exception/Exceptions.h" #include "eckit/types/FloatCompare.h" @@ -28,13 +30,8 @@ PointLonLat::PointLonLat(double lon, double lat) : double PointLonLat::normalise_angle_to_minimum(double a, double minimum) { - while (a < minimum) { - a += 360.; - } - while (a >= minimum + 360.) { - a -= 360.; - } - return a; + auto modulo_360 = [](double a) { return a - 360. * std::floor(a / 360.); }; + return minimum + modulo_360(a - minimum); } diff --git a/tests/geo/pointlonlat.cc b/tests/geo/pointlonlat.cc index 75989d0a6..7015a6bea 100644 --- a/tests/geo/pointlonlat.cc +++ b/tests/geo/pointlonlat.cc @@ -93,6 +93,14 @@ CASE("PointLonLat normalise angles") { EXPECT(14. == PointLonLat::normalise_angle_to_minimum(374., 0.)); EXPECT(14. == PointLonLat::normalise_angle_to_minimum(374., -90.)); EXPECT(374. == PointLonLat::normalise_angle_to_minimum(374., 90.)); + + EXPECT(14. == PointLonLat::normalise_angle_to_minimum(-346., 0.)); + EXPECT(14. == PointLonLat::normalise_angle_to_minimum(-346., -90.)); + EXPECT(374. == PointLonLat::normalise_angle_to_minimum(-346., 90.)); + EXPECT(0. == PointLonLat::normalise_angle_to_minimum(360. * 1e12, 0.)); + EXPECT(14. == PointLonLat::normalise_angle_to_minimum(360. * 1e12 + 14, 0.)); + EXPECT(0. == PointLonLat::normalise_angle_to_minimum(-360. * 1e12, 0.)); + EXPECT(14. == PointLonLat::normalise_angle_to_minimum(-360. * 1e12 + 14, 0.)); } From f2d5f32b65e221e1e4dcf9b6e4e06599b15fe720 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 16 Mar 2024 11:05:33 +0000 Subject: [PATCH 548/737] eckit::geo::PointLonLat --- src/eckit/geo/PointLonLat.cc | 9 ++---- tests/geo/pointlonlat.cc | 54 ++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index de86a94a5..5907777f4 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -36,13 +36,8 @@ double PointLonLat::normalise_angle_to_minimum(double a, double minimum) { double PointLonLat::normalise_angle_to_maximum(double a, double maximum) { - while (a > maximum) { - a -= 360.; - } - while (a <= maximum - 360.) { - a += 360.; - } - return a; + auto modulo_360 = [](double a) { return a - 360. * std::ceil(a / 360.); }; + return maximum + modulo_360(a - maximum); } diff --git a/tests/geo/pointlonlat.cc b/tests/geo/pointlonlat.cc index 7015a6bea..edc8e487c 100644 --- a/tests/geo/pointlonlat.cc +++ b/tests/geo/pointlonlat.cc @@ -19,6 +19,60 @@ namespace eckit::geo::test { +CASE("PointLonLat normalise_angle_to_*") { + SECTION("normalise_angle_to_minimum") { + struct { + double angle; + double lim; + double ref; + } tests[]{ + {10., 0., 10.}, + {0., 0., 0.}, + {-10., 0., 350.}, + {720., 0., 0.}, + {100., 90., 100.}, + {-370., 0., 350.}, + {100000., 0., static_cast(100000 % 360)}, + {-100., -180., -100.}, + {360., 0., 0.}, + {100000., 99960., 100000.}, + }; + + for (const auto& test : tests) { + EXPECT(types::is_approximately_equal(test.ref, + PointLonLat::normalise_angle_to_minimum(test.angle, test.lim), + PointLonLat::EPS)); + } + } + + + SECTION("normalise_angle_to_maximum") { + struct { + double angle; + double lim; + double ref; + } tests[]{ + {350., 360., 350.}, + {360., 360., 360.}, + {361., 360., 1.}, + {-720., 360., 360.}, + {100., 180., 100.}, + {-370., 360., 350.}, + {100000., 360., static_cast(100000 % 360)}, + {-100., -90., -100.}, + {720., 360., 360.}, + {100040., 100080., 100040.}, + }; + + for (const auto& test : tests) { + EXPECT(types::is_approximately_equal(test.ref, + PointLonLat::normalise_angle_to_maximum(test.angle, test.lim), + PointLonLat::EPS)); + } + } +} + + CASE("PointLonLat normalisation") { constexpr auto da = 1e-3; From 243b7ff787a70b5c518f9c73572649290258913b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 19 Mar 2024 08:49:56 +0000 Subject: [PATCH 549/737] eckit::geo::Grid --- src/eckit/geo/grid/Reduced.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/eckit/geo/grid/Reduced.cc b/src/eckit/geo/grid/Reduced.cc index 686c841a2..8cecab46a 100644 --- a/src/eckit/geo/grid/Reduced.cc +++ b/src/eckit/geo/grid/Reduced.cc @@ -12,7 +12,7 @@ #include "eckit/geo/grid/Reduced.h" -// #include <> +#include "eckit/exception/Exceptions.h" namespace eckit::geo::grid { @@ -44,11 +44,14 @@ std::vector Reduced::to_points() const { } -std::pair, std::vector > Reduced::to_latlon() const { - std::vector lat; - std::vector lon; - lat.reserve(size()); - lon.reserve(size()); +std::pair, std::vector> Reduced::to_latlon() const { + const auto N = size(); + + std::pair, std::vector> latlon; + auto& lat = latlon.first; + auto& lon = latlon.second; + lat.reserve(N); + lon.reserve(N); const auto& lats = latitudes(); ASSERT(lats.size() == nj()); @@ -60,7 +63,8 @@ std::pair, std::vector > Reduced::to_latlon() const lon.insert(lon.end(), lons.begin(), lons.end()); } - return {lat, lon}; + ASSERT(lat.size() == N && lon.size() == N); + return latlon; } From f480dfb36ca7be32d6b4864f9f23c274d556eb5e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 19 Mar 2024 16:14:50 +0000 Subject: [PATCH 550/737] eckit::geo::PointLonLat bit-reproducibility tests --- CMakeLists.txt | 5 + src/eckit/geo/PointLonLat.cc | 8 +- src/eckit/geo/eckit_geo_config.h.in | 1 + tests/geo/pointlonlat.cc | 297 ++++++++++++++++++++++++---- 4 files changed, 273 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 07ca1e37c..f35f87c1d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,6 +162,11 @@ ecbuild_add_option( FEATURE GEO_CACHING CONDITION HAVE_ECKIT_GEO DESCRIPTION "eckit::geo geometry library default caching behaviour" ) +ecbuild_add_option( FEATURE GEO_BITREPRODUCIBLE + DEFAULT OFF + CONDITION HAVE_ECKIT_GEO + DESCRIPTION "eckit::geo geometry library bit reproducibility tests" ) + set( eckit_GEO_CACHE_PATH "/tmp/cache" ) ### LAPACK diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index 5907777f4..013e06ed3 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -31,13 +31,17 @@ PointLonLat::PointLonLat(double lon, double lat) : double PointLonLat::normalise_angle_to_minimum(double a, double minimum) { auto modulo_360 = [](double a) { return a - 360. * std::floor(a / 360.); }; - return minimum + modulo_360(a - minimum); + + auto diff = a - minimum; + return 0. <= diff && diff < 360. ? a : modulo_360(diff) + minimum; } double PointLonLat::normalise_angle_to_maximum(double a, double maximum) { auto modulo_360 = [](double a) { return a - 360. * std::ceil(a / 360.); }; - return maximum + modulo_360(a - maximum); + + auto diff = a - maximum; + return -360. < diff && diff <= 0. ? a : modulo_360(a - maximum) + maximum; } diff --git a/src/eckit/geo/eckit_geo_config.h.in b/src/eckit/geo/eckit_geo_config.h.in index 707e321f5..8ba4211c8 100644 --- a/src/eckit/geo/eckit_geo_config.h.in +++ b/src/eckit/geo/eckit_geo_config.h.in @@ -13,6 +13,7 @@ #pragma once #cmakedefine01 eckit_HAVE_ECKIT_CODEC +#cmakedefine01 eckit_HAVE_GEO_BITREPRODUCIBLE #cmakedefine01 eckit_HAVE_GEO_CACHING #cmakedefine01 eckit_HAVE_GEO_CONVEX_HULL #cmakedefine eckit_GEO_CACHE_PATH "@eckit_GEO_CACHE_PATH@" diff --git a/tests/geo/pointlonlat.cc b/tests/geo/pointlonlat.cc index edc8e487c..c88fd75a8 100644 --- a/tests/geo/pointlonlat.cc +++ b/tests/geo/pointlonlat.cc @@ -12,6 +12,7 @@ #include "eckit/geo/PointLonLat.h" #include "eckit/geo/Point.h" +#include "eckit/geo/eckit_geo_config.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" @@ -20,25 +21,26 @@ namespace eckit::geo::test { CASE("PointLonLat normalise_angle_to_*") { - SECTION("normalise_angle_to_minimum") { - struct { - double angle; - double lim; - double ref; - } tests[]{ - {10., 0., 10.}, - {0., 0., 0.}, - {-10., 0., 350.}, - {720., 0., 0.}, - {100., 90., 100.}, - {-370., 0., 350.}, - {100000., 0., static_cast(100000 % 360)}, - {-100., -180., -100.}, - {360., 0., 0.}, - {100000., 99960., 100000.}, - }; + struct test_t { + double angle; + double lim; + double ref; + }; - for (const auto& test : tests) { + + SECTION("normalise_angle_to_minimum") { + for (const test_t& test : { + test_t{10., 0., 10.}, + {0., 0., 0.}, + {-10., 0., 350.}, + {720., 0., 0.}, + {100., 90., 100.}, + {-370., 0., 350.}, + {100000., 0., static_cast(100000 % 360)}, + {-100., -180., -100.}, + {360., 0., 0.}, + {100000., 99960., 100000.}, + }) { EXPECT(types::is_approximately_equal(test.ref, PointLonLat::normalise_angle_to_minimum(test.angle, test.lim), PointLonLat::EPS)); @@ -47,29 +49,252 @@ CASE("PointLonLat normalise_angle_to_*") { SECTION("normalise_angle_to_maximum") { - struct { - double angle; - double lim; - double ref; - } tests[]{ - {350., 360., 350.}, - {360., 360., 360.}, - {361., 360., 1.}, - {-720., 360., 360.}, - {100., 180., 100.}, - {-370., 360., 350.}, - {100000., 360., static_cast(100000 % 360)}, - {-100., -90., -100.}, - {720., 360., 360.}, - {100040., 100080., 100040.}, - }; - - for (const auto& test : tests) { + for (const auto& test : { + test_t{350., 360., 350.}, + {360., 360., 360.}, + {361., 360., 1.}, + {-720., 360., 360.}, + {100., 180., 100.}, + {-370., 360., 350.}, + {100000., 360., static_cast(100000 % 360)}, + {-100., -90., -100.}, + {720., 360., 360.}, + {100040., 100080., 100040.}, + }) { EXPECT(types::is_approximately_equal(test.ref, PointLonLat::normalise_angle_to_maximum(test.angle, test.lim), PointLonLat::EPS)); } } + + +#if eckit_HAVE_GEO_BITREPRODUCIBLE + SECTION("bit-identical behaviour normalising angles") { + auto normalise = [](double a, double minimum) -> double { + auto modulo_360 = [](double a) { return a - 360. * std::floor(a / 360.); }; + auto diff = a - minimum; + return 0. <= diff && diff < 360. ? a : modulo_360(diff) + minimum; + }; + + struct test_t { + double angle; + double ref_norm_angle_m_360; + double ref_norm_angle_m_720; + double ref_norm_angle_p_360; + double ref_norm_angle_p_720; + }; + + for (const auto& test : { + test_t{0x1.a99999999999fp+3, + 0x1.a9999999999ap+3, + 0x1.a99999999998p+3, + 0x1.a99999999998p+3, + 0x1.a99999999998p+3}, // 13.30000000000001 + {0x1.7599999999999p+5, + 0x1.7599999999998p+5, + 0x1.75999999999ap+5, + 0x1.75999999999ap+5, + 0x1.75999999999ap+5}, // 46.699999999999996 + {-0x1.37823af2187f7p+4, + -0x1.37823af2187fp+4, + -0x1.37823af2188p+4, + -0x1.37823af2188p+4, + -0x1.37823af2188p+4}, //-19.469294496237094 + {0x1.14f26c8adc252p+3, + 0x1.14f26c8adc26p+3, + 0x1.14f26c8adc24p+3, + 0x1.14f26c8adc28p+3, + 0x1.14f26c8adc24p+3}, // 8.6545927726848824 + {0x1.237e9f537dd2dp+5, + 0x1.237e9f537dd3p+5, + 0x1.237e9f537dd3p+5, + 0x1.237e9f537dd3p+5, + 0x1.237e9f537dd3p+5}, // 36.436827327992752 + {0x1.eb74b977e1e89p+5, + 0x1.eb74b977e1e88p+5, + 0x1.eb74b977e1e9p+5, + 0x1.eb74b977e1e8p+5, + 0x1.eb74b977e1e9p+5}, // 61.431994377690962 + {0x1.1008717af4f67p+6, + 0x1.1008717af4f68p+6, + 0x1.1008717af4f68p+6, + 0x1.1008717af4f68p+6, + 0x1.1008717af4f68p+6}, // 68.008245392991384 + {-0x1.b4f88656270d9p+4, + -0x1.b4f88656270ep+4, + -0x1.b4f88656270ep+4, + -0x1.b4f88656270ep+4, + -0x1.b4f88656270ep+4}, //-27.31067498830166 + {-0x1.eb22f87f6ac12p+1, + -0x1.eb22f87f6acp+1, + -0x1.eb22f87f6acp+1, + -0x1.eb22f87f6acp+1, + -0x1.eb22f87f6acp+1}, //-3.8370047208932272 + {0x1.40de11e0c3e99p+4, + 0x1.40de11e0c3eap+4, + 0x1.40de11e0c3eap+4, + 0x1.40de11e0c3eap+4, + 0x1.40de11e0c3eap+4}, // 20.054216268529306 + {0x1.4aeba99be1331p+5, + 0x1.4aeba99be133p+5, + 0x1.4aeba99be133p+5, + 0x1.4aeba99be133p+5, + 0x1.4aeba99be133p+5}, // 41.365069597063105 + {0x1.aa5c50f727ae6p+5, + 0x1.aa5c50f727ae8p+5, + 0x1.aa5c50f727aep+5, + 0x1.aa5c50f727aep+5, + 0x1.aa5c50f727aep+5}, // 53.295076304338906 + {-0x1.556ccf04ef1bbp+4, + -0x1.556ccf04ef1cp+4, + -0x1.556ccf04ef1cp+4, + -0x1.556ccf04ef1cp+4, + -0x1.556ccf04ef1cp+4}, //-21.339064616464139 + {0x1.556ccf04ef1bbp+4, + 0x1.556ccf04ef1cp+4, + 0x1.556ccf04ef1cp+4, + 0x1.556ccf04ef1cp+4, + 0x1.556ccf04ef1cp+4}, // 21.339064616464139 + {0x1.388f683df92bbp+5, + 0x1.388f683df92b8p+5, + 0x1.388f683df92cp+5, + 0x1.388f683df92cp+5, + 0x1.388f683df92cp+5}, // 39.070023044745049 + {-0x1.40de11e0c3e9dp+4, + -0x1.40de11e0c3eap+4, + -0x1.40de11e0c3eap+4, + -0x1.40de11e0c3eap+4, + -0x1.40de11e0c3eap+4}, //-20.05421626852932 + {0x1.eb22f87f6abf5p+1, + 0x1.eb22f87f6acp+1, + 0x1.eb22f87f6acp+1, + 0x1.eb22f87f6acp+1, + 0x1.eb22f87f6acp+1}, // 3.8370047208932143 + {0x1.b4f88656270d7p+4, + 0x1.b4f88656270dp+4, + 0x1.b4f88656270ep+4, + 0x1.b4f88656270cp+4, + 0x1.b4f88656270ep+4}, // 27.310674988301653 + {-0x1.3f0f4411db559p+5, + -0x1.3f0f4411db558p+5, + -0x1.3f0f4411db56p+5, + -0x1.3f0f4411db558p+5, + -0x1.3f0f4411db56p+5}, //-39.882454051500368 + {-0x1.63664f7d2181dp+5, + -0x1.63664f7d2182p+5, + -0x1.63664f7d2182p+5, + -0x1.63664f7d2182p+5, + -0x1.63664f7d2182p+5}, //-44.424956300339751 + {-0x1.75e470fd085aap+5, + -0x1.75e470fd085a8p+5, + -0x1.75e470fd085bp+5, + -0x1.75e470fd085a8p+5, + -0x1.75e470fd085bp+5}, //-46.7365436332869 + {-0x1.b2a6314996231p+4, + -0x1.b2a631499623p+4, + -0x1.b2a631499624p+4, + -0x1.b2a631499624p+4, + -0x1.b2a631499624p+4}, //-27.165574347922476 + {-0x1.f720e2a9525edp+5, + -0x1.f720e2a9525fp+5, + -0x1.f720e2a9525fp+5, + -0x1.f720e2a9525fp+5, + -0x1.f720e2a9525fp+5}, //-62.89105732233643 + {-0x1.236723c039272p+5, + -0x1.236723c03927p+5, + -0x1.236723c03927p+5, + -0x1.236723c03927p+5, + -0x1.236723c03927p+5}, //-36.425361158126989 + {-0x1.7f9f1a40a5d1fp+4, + -0x1.7f9f1a40a5d2p+4, + -0x1.7f9f1a40a5d2p+4, + -0x1.7f9f1a40a5d2p+4, + -0x1.7f9f1a40a5d2p+4}, //-23.976343395738805 + {0x1.ffffffffffffep+0, 0x1p+1, 0x1p+1, 0x1p+1, 0x1p+1}, // 1.9999999999999996 + {0x1.0b907154a92f7p+6, + 0x1.0b907154a92f8p+6, + 0x1.0b907154a92f8p+6, + 0x1.0b907154a92f8p+6, + 0x1.0b907154a92f8p+6}, // 66.891057322336437 + {0x1.436723c039272p+5, + 0x1.436723c03927p+5, + 0x1.436723c03927p+5, + 0x1.436723c03927p+5, + 0x1.436723c03927p+5}, // 40.425361158126989 + {0x1.bf9f1a40a5d1fp+4, + 0x1.bf9f1a40a5d2p+4, + 0x1.bf9f1a40a5d2p+4, + 0x1.bf9f1a40a5d2p+4, + 0x1.bf9f1a40a5d2p+4}, // 27.976343395738805 + {0x1.0f266c20b79f9p+7, + 0x1.0f266c20b79f8p+7, + 0x1.0f266c20b79f8p+7, + 0x1.0f266c20b79f8p+7, + 0x1.0f266c20b79f8p+7}, // 135.57504369966026 + {0x1.787bbbb54c676p+6, + 0x1.787bbbb54c678p+6, + 0x1.787bbbb54c678p+6, + 0x1.787bbbb54c678p+6, + 0x1.787bbbb54c678p+6}, // 94.120833237446135 + {0x1.95e470fd085aap+5, + 0x1.95e470fd085a8p+5, + 0x1.95e470fd085bp+5, + 0x1.95e470fd085ap+5, + 0x1.95e470fd085bp+5}, // 50.7365436332869 + {0x1.1bd0dd7b42b69p+7, + 0x1.1bd0dd7b42b68p+7, + 0x1.1bd0dd7b42b68p+7, + 0x1.1bd0dd7b42b68p+7, + 0x1.1bd0dd7b42b68p+7}, // 141.90793976964349 + {0x1.19981bd70b549p+6, + 0x1.19981bd70b548p+6, + 0x1.19981bd70b548p+6, + 0x1.19981bd70b548p+6, + 0x1.19981bd70b548p+6}, // 70.39854370123534 + {0x1.50bc8a12f525bp+5, + 0x1.50bc8a12f5258p+5, + 0x1.50bc8a12f526p+5, + 0x1.50bc8a12f526p+5, + 0x1.50bc8a12f526p+5}, // 42.092060230356502 + {0x1.cb2a2664f7bbdp+6, + 0x1.cb2a2664f7bbcp+6, + 0x1.cb2a2664f7bcp+6, + 0x1.cb2a2664f7bcp+6, + 0x1.cb2a2664f7bcp+6}, // 114.79116208803221 + {0x1.6784444ab398ap+6, + 0x1.6784444ab3988p+6, + 0x1.6784444ab3988p+6, + 0x1.6784444ab3988p+6, + 0x1.6784444ab3988p+6}, // 89.879166762553865 + {0x1.83664f7d2181ep+5, + 0x1.83664f7d2182p+5, + 0x1.83664f7d2182p+5, + 0x1.83664f7d2182p+5, + 0x1.83664f7d2182p+5}, // 48.424956300339758 + {0x1.380c1cb7eb45dp+7, + 0x1.380c1cb7eb45cp+7, + 0x1.380c1cb7eb45cp+7, + 0x1.380c1cb7eb45cp+7, + 0x1.380c1cb7eb46p+7}, // 156.02365660426122 + {0x1.d46f8eab56d0bp+6, + 0x1.d46f8eab56d0cp+6, + 0x1.d46f8eab56d08p+6, + 0x1.d46f8eab56d1p+6, + 0x1.d46f8eab56d08p+6}, // 117.10894267766359 + {0x1.5f0f4411db559p+5, + 0x1.5f0f4411db558p+5, + 0x1.5f0f4411db56p+5, + 0x1.5f0f4411db56p+5, + 0x1.5f0f4411db56p+5}, // 43.882454051500368 + }) { + EXPECT(test.angle == normalise(test.angle, -180.)); + EXPECT(test.ref_norm_angle_m_360 == normalise(test.angle - 360., -180.)); + EXPECT(test.ref_norm_angle_m_720 == normalise(test.angle - 720., -180.)); + EXPECT(test.ref_norm_angle_p_360 == normalise(test.angle + 360., -180.)); + EXPECT(test.ref_norm_angle_p_720 == normalise(test.angle + 720., -180.)); + } + } +#endif } From 8473c61d524ffc55f443228ce5166f786ce92203 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 21 Mar 2024 08:57:02 +0000 Subject: [PATCH 551/737] eckit::geo::Grid --- src/eckit/geo/CMakeLists.txt | 20 ++-- src/eckit/geo/grid/ReducedGlobal.cc | 96 +++++++++++++++ src/eckit/geo/grid/ReducedGlobal.h | 112 ++++++++++++++++++ .../geo/grid/{Reduced.cc => ReducedLocal.cc} | 14 +-- .../geo/grid/{Reduced.h => ReducedLocal.h} | 6 +- .../{reduced => reduced-global}/HEALPix.cc | 4 +- .../{reduced => reduced-global}/HEALPix.h | 4 +- .../ReducedGaussian.cc | 4 +- .../ReducedGaussian.h | 4 +- .../{reduced => reduced-local}/ReducedLL.cc | 4 +- .../{reduced => reduced-local}/ReducedLL.h | 4 +- src/eckit/geo/iterator/Reduced.cc | 4 +- src/eckit/geo/iterator/Reduced.h | 4 +- tests/geo/grid_reduced_gg.cc | 2 +- tests/geo/grid_to_points.cc | 2 +- 15 files changed, 248 insertions(+), 36 deletions(-) create mode 100644 src/eckit/geo/grid/ReducedGlobal.cc create mode 100644 src/eckit/geo/grid/ReducedGlobal.h rename src/eckit/geo/grid/{Reduced.cc => ReducedLocal.cc} (82%) rename src/eckit/geo/grid/{Reduced.h => ReducedLocal.h} (93%) rename src/eckit/geo/grid/{reduced => reduced-global}/HEALPix.cc (98%) rename src/eckit/geo/grid/{reduced => reduced-global}/HEALPix.h (96%) rename src/eckit/geo/grid/{reduced => reduced-global}/ReducedGaussian.cc (97%) rename src/eckit/geo/grid/{reduced => reduced-global}/ReducedGaussian.h (95%) rename src/eckit/geo/grid/{reduced => reduced-local}/ReducedLL.cc (91%) rename src/eckit/geo/grid/{reduced => reduced-local}/ReducedLL.h (95%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 78705451c..e0fda9db0 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -59,18 +59,20 @@ list(APPEND eckit_geo_srcs figure/OblateSpheroid.h figure/Sphere.cc figure/Sphere.h - grid/Reduced.cc - grid/Reduced.h + grid/ReducedGlobal.cc + grid/ReducedGlobal.h + grid/ReducedLocal.cc + grid/ReducedLocal.h grid/Regular.cc grid/Regular.h grid/Unstructured.cc grid/Unstructured.h - grid/reduced/HEALPix.cc - grid/reduced/HEALPix.h - grid/reduced/ReducedGaussian.cc - grid/reduced/ReducedGaussian.h - grid/reduced/ReducedLL.cc - grid/reduced/ReducedLL.h + grid/reduced-global/HEALPix.cc + grid/reduced-global/HEALPix.h + grid/reduced-global/ReducedGaussian.cc + grid/reduced-global/ReducedGaussian.h + grid/reduced-local/ReducedLL.cc + grid/reduced-local/ReducedLL.h grid/regular/IrregularLL.cc grid/regular/IrregularLL.h grid/regular/RegularGaussian.cc @@ -79,6 +81,8 @@ list(APPEND eckit_geo_srcs grid/regular/RegularLL.h grid/regular/XYToLonLat.cc grid/regular/XYToLonLat.h + grid/unstructured/ORCA.cc + grid/unstructured/ORCA.h grid/unstructured/UnstructuredFromGrid.cc grid/unstructured/UnstructuredFromGrid.h iterator/Reduced.cc diff --git a/src/eckit/geo/grid/ReducedGlobal.cc b/src/eckit/geo/grid/ReducedGlobal.cc new file mode 100644 index 000000000..97528f165 --- /dev/null +++ b/src/eckit/geo/grid/ReducedGlobal.cc @@ -0,0 +1,96 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/ReducedGlobal.h" + +#include "eckit/exception/Exceptions.h" + + +namespace eckit::geo::grid { + + +size_t ReducedGlobal::size() const { + return niacc().back(); +} + + +std::vector ReducedGlobal::to_points() const { + std::vector points; + points.reserve(size()); + + const auto& lats = latitudes(); + ASSERT(lats.size() == nj()); + + for (size_t j = 0; j < nj(); ++j) { + const auto lons = longitudes(j); + ASSERT(lons.size() == ni(j)); + + const auto lat = lats.at(j); + for (auto lon : lons) { + points.emplace_back(PointLonLat{lon, lat}); + } + } + + return points; +} + + +std::pair, std::vector> ReducedGlobal::to_latlon() const { + const auto N = size(); + + std::pair, std::vector> latlon; + auto& lat = latlon.first; + auto& lon = latlon.second; + lat.reserve(N); + lon.reserve(N); + + const auto& lats = latitudes(); + ASSERT(lats.size() == nj()); + + for (size_t j = 0; j < nj(); ++j) { + const auto lons = longitudes(j); + + lat.insert(lat.end(), lons.size(), lats.at(j)); + lon.insert(lon.end(), lons.begin(), lons.end()); + } + + ASSERT(lat.size() == N && lon.size() == N); + return latlon; +} + + +ReducedGlobal::ReducedGlobal(const Spec& spec) : + Grid(spec) {} + + +ReducedGlobal::ReducedGlobal(const area::BoundingBox& bbox) : + Grid(bbox) {} + + +const std::vector& ReducedGlobal::niacc() const { + if (niacc_.empty()) { + niacc_.resize(1 + nj()); + niacc_.front() = 0; + + size_t j = 0; + for (auto a = niacc_.begin(), b = a + 1; b != niacc_.end(); ++j, ++a, ++b) { + *b = *a + ni(j); + } + + ASSERT(niacc_.back() == size()); + } + + return niacc_; +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedGlobal.h b/src/eckit/geo/grid/ReducedGlobal.h new file mode 100644 index 000000000..3a0ff3c65 --- /dev/null +++ b/src/eckit/geo/grid/ReducedGlobal.h @@ -0,0 +1,112 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Grid.h" + + +namespace eckit::geo::iterator { +class Reduced; +} + + +namespace eckit::geo::grid { + + +class ReducedGlobal : public Grid { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + // None + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + size_t size() const override; + std::vector to_points() const override; + std::pair, std::vector> to_latlon() const override; + + // -- Class members + // None + + // -- Class methods + // None + +protected: + // -- Constructors + + explicit ReducedGlobal(const Spec&); + explicit ReducedGlobal(const area::BoundingBox&); + + // -- Members + // None + + // -- Methods + + const std::vector& niacc() const; + + virtual size_t ni(size_t j) const = 0; + virtual size_t nj() const = 0; + + virtual const std::vector& latitudes() const = 0; + virtual std::vector longitudes(size_t i) const = 0; + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + + mutable std::vector niacc_; + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + + friend class geo::iterator::Reduced; +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Reduced.cc b/src/eckit/geo/grid/ReducedLocal.cc similarity index 82% rename from src/eckit/geo/grid/Reduced.cc rename to src/eckit/geo/grid/ReducedLocal.cc index 8cecab46a..a1bc93ae2 100644 --- a/src/eckit/geo/grid/Reduced.cc +++ b/src/eckit/geo/grid/ReducedLocal.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/Reduced.h" +#include "eckit/geo/grid/ReducedLocal.h" #include "eckit/exception/Exceptions.h" @@ -18,12 +18,12 @@ namespace eckit::geo::grid { -size_t Reduced::size() const { +size_t ReducedLocal::size() const { return niacc().back(); } -std::vector Reduced::to_points() const { +std::vector ReducedLocal::to_points() const { std::vector points; points.reserve(size()); @@ -44,7 +44,7 @@ std::vector Reduced::to_points() const { } -std::pair, std::vector> Reduced::to_latlon() const { +std::pair, std::vector> ReducedLocal::to_latlon() const { const auto N = size(); std::pair, std::vector> latlon; @@ -68,15 +68,15 @@ std::pair, std::vector> Reduced::to_latlon() const { } -Reduced::Reduced(const Spec& spec) : +ReducedLocal::ReducedLocal(const Spec& spec) : Grid(spec) {} -Reduced::Reduced(const area::BoundingBox& bbox) : +ReducedLocal::ReducedLocal(const area::BoundingBox& bbox) : Grid(bbox) {} -const std::vector& Reduced::niacc() const { +const std::vector& ReducedLocal::niacc() const { if (niacc_.empty()) { niacc_.resize(1 + nj()); niacc_.front() = 0; diff --git a/src/eckit/geo/grid/Reduced.h b/src/eckit/geo/grid/ReducedLocal.h similarity index 93% rename from src/eckit/geo/grid/Reduced.h rename to src/eckit/geo/grid/ReducedLocal.h index 87a2ebf4e..a81eee461 100644 --- a/src/eckit/geo/grid/Reduced.h +++ b/src/eckit/geo/grid/ReducedLocal.h @@ -23,7 +23,7 @@ class Reduced; namespace eckit::geo::grid { -class Reduced : public Grid { +class ReducedLocal : public Grid { public: // -- Types // None @@ -61,8 +61,8 @@ class Reduced : public Grid { protected: // -- Constructors - explicit Reduced(const Spec&); - explicit Reduced(const area::BoundingBox&); + explicit ReducedLocal(const Spec&); + explicit ReducedLocal(const area::BoundingBox&); // -- Members // None diff --git a/src/eckit/geo/grid/reduced/HEALPix.cc b/src/eckit/geo/grid/reduced-global/HEALPix.cc similarity index 98% rename from src/eckit/geo/grid/reduced/HEALPix.cc rename to src/eckit/geo/grid/reduced-global/HEALPix.cc index 3aac0276b..7ae4037ed 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.cc +++ b/src/eckit/geo/grid/reduced-global/HEALPix.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/reduced/HEALPix.h" +#include "eckit/geo/grid/reduced-global/HEALPix.h" #include #include @@ -232,7 +232,7 @@ HEALPix::HEALPix(const Spec& spec) : HEALPix::HEALPix(size_t Nside, Ordering ordering) : - Reduced(area::BoundingBox::make_global_prime()), N_(Nside), ordering_(ordering) { + ReducedGlobal(area::BoundingBox::make_global_prime()), N_(Nside), ordering_(ordering) { ASSERT(N_ > 0); ASSERT_MSG(ordering == Ordering::healpix_ring || ordering == Ordering::healpix_nested, "HEALPix: supported orderings: ring, nested"); diff --git a/src/eckit/geo/grid/reduced/HEALPix.h b/src/eckit/geo/grid/reduced-global/HEALPix.h similarity index 96% rename from src/eckit/geo/grid/reduced/HEALPix.h rename to src/eckit/geo/grid/reduced-global/HEALPix.h index ee1960705..2516aeb13 100644 --- a/src/eckit/geo/grid/reduced/HEALPix.h +++ b/src/eckit/geo/grid/reduced-global/HEALPix.h @@ -12,13 +12,13 @@ #pragma once -#include "eckit/geo/grid/Reduced.h" +#include "eckit/geo/grid/ReducedGlobal.h" namespace eckit::geo::grid::reduced { -class HEALPix final : public Reduced { +class HEALPix final : public ReducedGlobal { public: // -- Types // None diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.cc b/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc similarity index 97% rename from src/eckit/geo/grid/reduced/ReducedGaussian.cc rename to src/eckit/geo/grid/reduced-global/ReducedGaussian.cc index 6a2774113..9a6c299a9 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/reduced/ReducedGaussian.h" +#include "eckit/geo/grid/reduced-global/ReducedGaussian.h" #include @@ -37,7 +37,7 @@ ReducedGaussian::ReducedGaussian(const Spec& spec) : ReducedGaussian::ReducedGaussian(const pl_type& pl, const area::BoundingBox& bbox) : - Reduced(bbox), + ReducedGlobal(bbox), N_(N(pl)), pl_(pl), j_(0), diff --git a/src/eckit/geo/grid/reduced/ReducedGaussian.h b/src/eckit/geo/grid/reduced-global/ReducedGaussian.h similarity index 95% rename from src/eckit/geo/grid/reduced/ReducedGaussian.h rename to src/eckit/geo/grid/reduced-global/ReducedGaussian.h index ca3ea15d6..40827d567 100644 --- a/src/eckit/geo/grid/reduced/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced-global/ReducedGaussian.h @@ -15,14 +15,14 @@ #include #include "eckit/geo/Range.h" -#include "eckit/geo/grid/Reduced.h" +#include "eckit/geo/grid/ReducedGlobal.h" #include "eckit/geo/util.h" namespace eckit::geo::grid::reduced { -class ReducedGaussian : public Reduced { +class ReducedGaussian : public ReducedGlobal { public: // -- Types // None diff --git a/src/eckit/geo/grid/reduced/ReducedLL.cc b/src/eckit/geo/grid/reduced-local/ReducedLL.cc similarity index 91% rename from src/eckit/geo/grid/reduced/ReducedLL.cc rename to src/eckit/geo/grid/reduced-local/ReducedLL.cc index 3227de852..09b28fdae 100644 --- a/src/eckit/geo/grid/reduced/ReducedLL.cc +++ b/src/eckit/geo/grid/reduced-local/ReducedLL.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/reduced/ReducedLL.h" +#include "eckit/geo/grid/reduced-local/ReducedLL.h" #include "eckit/geo/iterator/Reduced.h" #include "eckit/geo/range/RegularLatitude.h" @@ -26,7 +26,7 @@ ReducedLL::ReducedLL(const Spec& spec) : ReducedLL::ReducedLL(const pl_type& pl, const area::BoundingBox& bbox) : - Reduced(bbox), pl_(pl), y_(new range::RegularLatitude(pl_.size(), bbox.north, bbox.south)) { + ReducedLocal(bbox), pl_(pl), y_(new range::RegularLatitude(pl_.size(), bbox.north, bbox.south)) { ASSERT(y_); } diff --git a/src/eckit/geo/grid/reduced/ReducedLL.h b/src/eckit/geo/grid/reduced-local/ReducedLL.h similarity index 95% rename from src/eckit/geo/grid/reduced/ReducedLL.h rename to src/eckit/geo/grid/reduced-local/ReducedLL.h index 4cfa3e53f..8238d06e4 100644 --- a/src/eckit/geo/grid/reduced/ReducedLL.h +++ b/src/eckit/geo/grid/reduced-local/ReducedLL.h @@ -15,14 +15,14 @@ #include #include "eckit/geo/Range.h" -#include "eckit/geo/grid/Reduced.h" +#include "eckit/geo/grid/ReducedLocal.h" #include "eckit/geo/util.h" namespace eckit::geo::grid::reduced { -class ReducedLL : public Reduced { +class ReducedLL : public ReducedLocal { public: // -- Types // None diff --git a/src/eckit/geo/iterator/Reduced.cc b/src/eckit/geo/iterator/Reduced.cc index a2b39dc8e..4485b8bdd 100644 --- a/src/eckit/geo/iterator/Reduced.cc +++ b/src/eckit/geo/iterator/Reduced.cc @@ -16,7 +16,7 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/grid/Reduced.h" +#include "eckit/geo/grid/ReducedGlobal.h" namespace eckit::geo::iterator { @@ -24,7 +24,7 @@ namespace eckit::geo::iterator { Reduced::Reduced(const Grid& grid, size_t index) : geo::Iterator(grid), - grid_(dynamic_cast(grid)), + grid_(dynamic_cast(grid)), latitudes_(grid_.latitudes()), niacc_(grid_.niacc()), index_(index), diff --git a/src/eckit/geo/iterator/Reduced.h b/src/eckit/geo/iterator/Reduced.h index 3f84e3079..3e5a6a9c2 100644 --- a/src/eckit/geo/iterator/Reduced.h +++ b/src/eckit/geo/iterator/Reduced.h @@ -16,7 +16,7 @@ namespace eckit::geo::grid { -class Reduced; +class ReducedGlobal; } @@ -59,7 +59,7 @@ class Reduced final : public geo::Iterator { private: // -- Members - const grid::Reduced& grid_; + const grid::ReducedGlobal& grid_; std::vector longitudes_j_; const std::vector& latitudes_; const std::vector& niacc_; diff --git a/tests/geo/grid_reduced_gg.cc b/tests/geo/grid_reduced_gg.cc index 263e0bdd3..52a90c36c 100644 --- a/tests/geo/grid_reduced_gg.cc +++ b/tests/geo/grid_reduced_gg.cc @@ -13,7 +13,7 @@ #include #include "eckit/geo/Grid.h" -#include "eckit/geo/grid/reduced/ReducedGaussian.h" +#include "eckit/geo/grid/reduced-global/ReducedGaussian.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/testing/Test.h" diff --git a/tests/geo/grid_to_points.cc b/tests/geo/grid_to_points.cc index 3c8131d03..ecfc911ca 100644 --- a/tests/geo/grid_to_points.cc +++ b/tests/geo/grid_to_points.cc @@ -13,7 +13,7 @@ #include #include -#include "eckit/geo/grid/reduced/HEALPix.h" +#include "eckit/geo/grid/reduced-global/HEALPix.h" #include "eckit/testing/Test.h" From 0d24112336ff3d671dddf0eafacf6f9980189673 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 21 Mar 2024 12:18:20 +0000 Subject: [PATCH 552/737] eckit::geo::Grid --- src/eckit/geo/grid/reduced-global/HEALPix.cc | 8 ++++---- src/eckit/geo/grid/reduced-global/HEALPix.h | 4 ++-- src/eckit/geo/grid/reduced-global/ReducedGaussian.cc | 4 ++-- src/eckit/geo/grid/reduced-global/ReducedGaussian.h | 4 ++-- src/eckit/geo/grid/reduced-local/ReducedLL.cc | 4 ++-- src/eckit/geo/grid/reduced-local/ReducedLL.h | 4 ++-- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/eckit/geo/grid/reduced-global/HEALPix.cc b/src/eckit/geo/grid/reduced-global/HEALPix.cc index 7ae4037ed..68cebb5e4 100644 --- a/src/eckit/geo/grid/reduced-global/HEALPix.cc +++ b/src/eckit/geo/grid/reduced-global/HEALPix.cc @@ -24,6 +24,9 @@ #include "eckit/utils/Translator.h" +namespace eckit::geo::grid::reducedglobal { + + namespace { @@ -217,9 +220,6 @@ class Reorder { } // unnamed namespace -namespace eckit::geo::grid::reduced { - - static Ordering ordering_from_string(const std::string& str) { return str == "ring" ? Ordering::healpix_ring : str == "nested" ? Ordering::healpix_nested @@ -375,4 +375,4 @@ static const GridRegisterType __grid_type("HEALPix"); static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); -} // namespace eckit::geo::grid::reduced +} // namespace eckit::geo::grid::reducedglobal diff --git a/src/eckit/geo/grid/reduced-global/HEALPix.h b/src/eckit/geo/grid/reduced-global/HEALPix.h index 2516aeb13..f78a9e922 100644 --- a/src/eckit/geo/grid/reduced-global/HEALPix.h +++ b/src/eckit/geo/grid/reduced-global/HEALPix.h @@ -15,7 +15,7 @@ #include "eckit/geo/grid/ReducedGlobal.h" -namespace eckit::geo::grid::reduced { +namespace eckit::geo::grid::reducedglobal { class HEALPix final : public ReducedGlobal { @@ -101,4 +101,4 @@ class HEALPix final : public ReducedGlobal { }; -} // namespace eckit::geo::grid::reduced +} // namespace eckit::geo::grid::reducedglobal diff --git a/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc b/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc index 9a6c299a9..81cf3f9b3 100644 --- a/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc @@ -23,7 +23,7 @@ #include "eckit/utils/Translator.h" -namespace eckit::geo::grid::reduced { +namespace eckit::geo::grid::reducedglobal { static size_t N(const pl_type& pl) { @@ -133,4 +133,4 @@ static const GridRegisterName __grid_pattern_1("[nN][1 static const GridRegisterName __grid_pattern_2("[oO][1-9][0-9]*"); -} // namespace eckit::geo::grid::reduced +} // namespace eckit::geo::grid::reducedglobal diff --git a/src/eckit/geo/grid/reduced-global/ReducedGaussian.h b/src/eckit/geo/grid/reduced-global/ReducedGaussian.h index 40827d567..f781af793 100644 --- a/src/eckit/geo/grid/reduced-global/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced-global/ReducedGaussian.h @@ -19,7 +19,7 @@ #include "eckit/geo/util.h" -namespace eckit::geo::grid::reduced { +namespace eckit::geo::grid::reducedglobal { class ReducedGaussian : public ReducedGlobal { @@ -96,4 +96,4 @@ class ReducedGaussian : public ReducedGlobal { }; -} // namespace eckit::geo::grid::reduced +} // namespace eckit::geo::grid::reducedglobal diff --git a/src/eckit/geo/grid/reduced-local/ReducedLL.cc b/src/eckit/geo/grid/reduced-local/ReducedLL.cc index 09b28fdae..e9dc04f33 100644 --- a/src/eckit/geo/grid/reduced-local/ReducedLL.cc +++ b/src/eckit/geo/grid/reduced-local/ReducedLL.cc @@ -18,7 +18,7 @@ #include "eckit/geo/spec/Custom.h" -namespace eckit::geo::grid::reduced { +namespace eckit::geo::grid::reducedlocal { ReducedLL::ReducedLL(const Spec& spec) : @@ -74,4 +74,4 @@ void ReducedLL::spec(spec::Custom& custom) const { } -} // namespace eckit::geo::grid::reduced +} // namespace eckit::geo::grid::reducedlocal diff --git a/src/eckit/geo/grid/reduced-local/ReducedLL.h b/src/eckit/geo/grid/reduced-local/ReducedLL.h index 8238d06e4..c7e5de28c 100644 --- a/src/eckit/geo/grid/reduced-local/ReducedLL.h +++ b/src/eckit/geo/grid/reduced-local/ReducedLL.h @@ -19,7 +19,7 @@ #include "eckit/geo/util.h" -namespace eckit::geo::grid::reduced { +namespace eckit::geo::grid::reducedlocal { class ReducedLL : public ReducedLocal { @@ -90,4 +90,4 @@ class ReducedLL : public ReducedLocal { }; -} // namespace eckit::geo::grid::reduced +} // namespace eckit::geo::grid::reducedlocal From fa888c198f36a2c4bbae501bb8fbb9b7eaf5ed96 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 22 Mar 2024 09:49:20 +0000 Subject: [PATCH 553/737] eckit::geo::Grid --- tests/geo/grid_reduced_gg.cc | 11 +++++++---- tests/geo/grid_to_points.cc | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/geo/grid_reduced_gg.cc b/tests/geo/grid_reduced_gg.cc index 52a90c36c..07f254539 100644 --- a/tests/geo/grid_reduced_gg.cc +++ b/tests/geo/grid_reduced_gg.cc @@ -23,6 +23,9 @@ namespace eckit::geo::test { CASE("ReducedGaussianOctahedral") { + using grid::reducedglobal::ReducedGaussian; + + SECTION("gridspec") { // different ways to instantiate the same grid (O2) for (auto spec : { @@ -57,7 +60,7 @@ CASE("ReducedGaussianOctahedral") { GridFactory::build(spec::Custom({{"grid", "o" + std::to_string(test.N)}}))); std::unique_ptr grid2( GridFactory::build(spec::Custom({{"type", "reduced_gg"}, {"N", test.N}}))); - grid::reduced::ReducedGaussian grid3(test.N); + ReducedGaussian grid3(test.N); EXPECT(grid1->size() == test.size); EXPECT(grid2->size() == test.size); @@ -67,7 +70,7 @@ CASE("ReducedGaussianOctahedral") { SECTION("points") { - grid::reduced::ReducedGaussian grid(1); + ReducedGaussian grid(1); const std::vector ref{ PointLonLat{0., 35.264389683}, PointLonLat{18., 35.264389683}, PointLonLat{36., 35.264389683}, @@ -144,8 +147,8 @@ CASE("ReducedGaussianOctahedral") { SECTION("equals") { std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "o3"}}))); std::unique_ptr grid2(GridFactory::make_from_string("N: 3")); - std::unique_ptr grid3(new grid::reduced::ReducedGaussian(3)); - std::unique_ptr grid4(new grid::reduced::ReducedGaussian(pl_type{20, 24, 28, 28, 24, 20})); + std::unique_ptr grid3(new ReducedGaussian(3)); + std::unique_ptr grid4(new ReducedGaussian(pl_type{20, 24, 28, 28, 24, 20})); EXPECT(*grid1 == *grid2); EXPECT(*grid2 == *grid3); diff --git a/tests/geo/grid_to_points.cc b/tests/geo/grid_to_points.cc index ecfc911ca..646098333 100644 --- a/tests/geo/grid_to_points.cc +++ b/tests/geo/grid_to_points.cc @@ -22,7 +22,7 @@ namespace eckit::geo::test { CASE("HEALPix") { SECTION("HEALPix::to_points") { - std::unique_ptr grid(new grid::reduced::HEALPix(2, Ordering::healpix_ring)); + std::unique_ptr grid(new grid::reducedglobal::HEALPix(2, Ordering::healpix_ring)); static const std::vector expected_points_ring{ {45, 66.443535691}, From c2040ce4cc42ae2ff626963d1f98d4a17344e1ff Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 24 Mar 2024 08:08:39 +0000 Subject: [PATCH 554/737] eckit::geo::Grid --- src/eckit/geo/grid/ReducedGlobal.cc | 5 ----- src/eckit/geo/grid/ReducedGlobal.h | 1 - src/eckit/geo/grid/reduced-global/HEALPix.h | 3 +-- src/eckit/geo/grid/reduced-global/ReducedGaussian.cc | 5 +++++ src/eckit/geo/grid/reduced-global/ReducedGaussian.h | 1 + 5 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/eckit/geo/grid/ReducedGlobal.cc b/src/eckit/geo/grid/ReducedGlobal.cc index 97528f165..1c87f380c 100644 --- a/src/eckit/geo/grid/ReducedGlobal.cc +++ b/src/eckit/geo/grid/ReducedGlobal.cc @@ -18,11 +18,6 @@ namespace eckit::geo::grid { -size_t ReducedGlobal::size() const { - return niacc().back(); -} - - std::vector ReducedGlobal::to_points() const { std::vector points; points.reserve(size()); diff --git a/src/eckit/geo/grid/ReducedGlobal.h b/src/eckit/geo/grid/ReducedGlobal.h index 3a0ff3c65..7bece248e 100644 --- a/src/eckit/geo/grid/ReducedGlobal.h +++ b/src/eckit/geo/grid/ReducedGlobal.h @@ -48,7 +48,6 @@ class ReducedGlobal : public Grid { // -- Overridden methods - size_t size() const override; std::vector to_points() const override; std::pair, std::vector> to_latlon() const override; diff --git a/src/eckit/geo/grid/reduced-global/HEALPix.h b/src/eckit/geo/grid/reduced-global/HEALPix.h index f78a9e922..a3b51aa53 100644 --- a/src/eckit/geo/grid/reduced-global/HEALPix.h +++ b/src/eckit/geo/grid/reduced-global/HEALPix.h @@ -48,6 +48,7 @@ class HEALPix final : public ReducedGlobal { iterator cbegin() const override; iterator cend() const override; + size_t size() const override; size_t ni(size_t j) const override; size_t nj() const override; @@ -77,8 +78,6 @@ class HEALPix final : public ReducedGlobal { area::BoundingBox boundingBox() const override; - size_t size() const override; - bool includesNorthPole() const override { return true; } bool includesSouthPole() const override { return true; } bool isPeriodicWestEast() const override { return true; } diff --git a/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc b/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc index 81cf3f9b3..2b3bb8abf 100644 --- a/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc @@ -62,6 +62,11 @@ Grid::iterator ReducedGaussian::cend() const { } +size_t ReducedGaussian::size() const { + return niacc().back(); +} + + size_t ReducedGaussian::ni(size_t j) const { return pl_.at(j + j_); } diff --git a/src/eckit/geo/grid/reduced-global/ReducedGaussian.h b/src/eckit/geo/grid/reduced-global/ReducedGaussian.h index f781af793..38db232f1 100644 --- a/src/eckit/geo/grid/reduced-global/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced-global/ReducedGaussian.h @@ -53,6 +53,7 @@ class ReducedGaussian : public ReducedGlobal { iterator cbegin() const override; iterator cend() const override; + size_t size() const override; size_t ni(size_t j) const override; size_t nj() const override; From dfb8f0135e29aaf2c775fefe68d4a3d847b80a8a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 3 Apr 2024 09:05:26 +0100 Subject: [PATCH 555/737] eckit::geo::Grid --- src/eckit/geo/projection/Mercator.cc | 13 +++++++++---- src/eckit/geo/util/bounding_box.cc | 4 ++-- tests/geo/projection_mercator.cc | 15 ++++++++++++--- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/eckit/geo/projection/Mercator.cc b/src/eckit/geo/projection/Mercator.cc index 3ccca7f06..1e1c2b12d 100644 --- a/src/eckit/geo/projection/Mercator.cc +++ b/src/eckit/geo/projection/Mercator.cc @@ -13,6 +13,7 @@ #include "eckit/geo/projection/Mercator.h" #include +#include #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" @@ -85,10 +86,14 @@ double Mercator::calculate_phi(double t) const { Point2 Mercator::fwd(const PointLonLat& p) const { auto phi = util::DEGREE_TO_RADIAN * p.lat; auto lam = util::DEGREE_TO_RADIAN * p.lon; - - return {x0_ + m_ * (lam - lam0_), - y0_ - m_ * std::log(std::tan(M_PI_4 - 0.5 * phi) / - std::pow(((1. - e_ * std::sin(phi)) / (1. + e_ * std::sin(phi))), 0.5 * e_))}; + auto s = std::sin(phi); + + return { + x0_ + m_ * (lam - lam0_), + types::is_approximately_equal(s, 1.) ? std::numeric_limits::infinity() + : types::is_approximately_equal(s, -1.) + ? -std::numeric_limits::infinity() + : y0_ - m_ * std::log(std::tan(M_PI_4 - 0.5 * phi) / std::pow(((1. - e_ * s) / (1. + e_ * s)), 0.5 * e_))}; } diff --git a/src/eckit/geo/util/bounding_box.cc b/src/eckit/geo/util/bounding_box.cc index 364cba414..d4b2896ef 100644 --- a/src/eckit/geo/util/bounding_box.cc +++ b/src/eckit/geo/util/bounding_box.cc @@ -229,11 +229,11 @@ area::BoundingBox bounding_box(Point2 min, Point2 max, Projection& projection) { // not at the corners by refining iteratively if (!bounds.includesNorthPole()) { - bounds.includesNorthPole(rect.contains(std::get(projection.fwd(PointLonLat{0., 90.})))); + bounds.includesNorthPole(rect.contains(std::get(projection.fwd(PointLonLat{0., 90. - h_ll})))); } if (!bounds.includesSouthPole()) { - bounds.includesSouthPole(rect.contains(std::get(projection.fwd(PointLonLat{0., -90.})))); + bounds.includesSouthPole(rect.contains(std::get(projection.fwd(PointLonLat{0., -90. + h_ll})))); } for (auto [A, B] : segments) { diff --git a/tests/geo/projection_mercator.cc b/tests/geo/projection_mercator.cc index 2c95b379d..808efb356 100644 --- a/tests/geo/projection_mercator.cc +++ b/tests/geo/projection_mercator.cc @@ -10,6 +10,7 @@ */ +#include #include #include "eckit/geo/figure/Sphere.h" @@ -24,11 +25,19 @@ using P = std::unique_ptr; CASE("projection: mercator") { - PointLonLat first{262.036, 14.7365}; + SECTION("mercator (poles)") { + projection::Mercator projection(0., 14., new figure::Sphere(1.), {0., 0.}); + + auto a = projection.fwd(PointLonLat{0., 90.}); + EXPECT(a.Y > std::numeric_limits::max()); + + auto b = projection.fwd(PointLonLat{0., -90.}); + EXPECT(b.Y < std::numeric_limits::lowest()); + } SECTION("mercator (1)") { - projection::Mercator projection(0., 14., new figure::Sphere(6371229.), first); + projection::Mercator projection(0., 14., new figure::Sphere(6371229.), {262.036, 14.7365}); Point2 a{0., 0.}; auto b = projection.inv(a); @@ -39,7 +48,7 @@ CASE("projection: mercator") { SECTION("mercator (2)") { - projection::Mercator projection(-180., 0., new figure::Sphere(1.), {0, 0}); + projection::Mercator projection(-180., 0., new figure::Sphere(1.), {0., 0.}); PointLonLat a{-75., 35.}; auto b = projection.fwd({-75, 35}); From 83639d56b78fed45403a7421659a3a17104d0e94 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 3 Apr 2024 09:06:30 +0100 Subject: [PATCH 556/737] eckit::geo::Grid --- tests/geo/projection_mercator.cc | 46 ++++++++++++++------------------ 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/tests/geo/projection_mercator.cc b/tests/geo/projection_mercator.cc index 808efb356..20a6ccefa 100644 --- a/tests/geo/projection_mercator.cc +++ b/tests/geo/projection_mercator.cc @@ -11,7 +11,6 @@ #include -#include #include "eckit/geo/figure/Sphere.h" #include "eckit/geo/projection/Mercator.h" @@ -21,41 +20,36 @@ namespace eckit::geo::test { -using P = std::unique_ptr; +CASE("projection: mercator (poles)") { + projection::Mercator projection(0., 14., new figure::Sphere(1.), {0., 0.}); + auto a = projection.fwd(PointLonLat{0., 90.}); + EXPECT(a.Y > std::numeric_limits::max()); -CASE("projection: mercator") { - SECTION("mercator (poles)") { - projection::Mercator projection(0., 14., new figure::Sphere(1.), {0., 0.}); - - auto a = projection.fwd(PointLonLat{0., 90.}); - EXPECT(a.Y > std::numeric_limits::max()); - - auto b = projection.fwd(PointLonLat{0., -90.}); - EXPECT(b.Y < std::numeric_limits::lowest()); - } + auto b = projection.fwd(PointLonLat{0., -90.}); + EXPECT(b.Y < std::numeric_limits::lowest()); +} - SECTION("mercator (1)") { - projection::Mercator projection(0., 14., new figure::Sphere(6371229.), {262.036, 14.7365}); +CASE("projection: mercator (1)") { + projection::Mercator projection(0., 14., new figure::Sphere(6371229.), {262.036, 14.7365}); - Point2 a{0., 0.}; - auto b = projection.inv(a); - auto c = projection.fwd(b); + Point2 a{0., 0.}; + auto b = projection.inv(a); + auto c = projection.fwd(b); - EXPECT(points_equal(c, a)); - } + EXPECT(points_equal(c, a)); +} - SECTION("mercator (2)") { - projection::Mercator projection(-180., 0., new figure::Sphere(1.), {0., 0.}); +CASE("projection: mercator (2)") { + projection::Mercator projection(-180., 0., new figure::Sphere(1.), {0., 0.}); - PointLonLat a{-75., 35.}; - auto b = projection.fwd({-75, 35}); - auto c = projection.inv(b); + PointLonLat a{-75., 35.}; + auto b = projection.fwd(a); + auto c = projection.inv(b); - EXPECT(points_equal(c, a)); - } + EXPECT(points_equal(c, a)); } From 243a375e088ac4c6af51b9da41208b54167a79be Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 4 Apr 2024 00:47:36 +0100 Subject: [PATCH 557/737] eckit::geo::Grid --- .../grid/reduced-global/ReducedGaussian.cc | 27 ++++++++++++++----- .../geo/grid/reduced-global/ReducedGaussian.h | 3 ++- tests/geo/grid_reduced_gg.cc | 15 +++++++---- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc b/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc index 2b3bb8abf..e138dd376 100644 --- a/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc @@ -42,6 +42,7 @@ ReducedGaussian::ReducedGaussian(const pl_type& pl, const area::BoundingBox& bbo pl_(pl), j_(0), Nj_(N_ * 2), + x_(Nj_), y_(range::GaussianLatitude(N_, false).crop(bbox.north, bbox.south)) { ASSERT(Nj_ == pl_.size()); ASSERT(y_); @@ -68,7 +69,17 @@ size_t ReducedGaussian::size() const { size_t ReducedGaussian::ni(size_t j) const { - return pl_.at(j + j_); + if (!x_.at(j_ + j)) { + auto bbox = boundingBox(); + auto Ni = pl_.at(j_ + j); + ASSERT(Ni >= 0); + + range::RegularLongitude x(static_cast(Ni), 0., 360.); + const_cast>&>(x_)[j].reset(x.crop(bbox.west, bbox.east)); + ASSERT(x_[j]); + } + + return x_[j]->size(); } @@ -83,13 +94,17 @@ const std::vector& ReducedGaussian::latitudes() const { std::vector ReducedGaussian::longitudes(size_t j) const { - auto Ni = ni(j); - if (!x_ || x_->size() != Ni) { - auto bbox = boundingBox(); - const_cast&>(x_) = std::make_unique(Ni, bbox.west, bbox.east); + if (!x_.at(j_ + j)) { + auto bbox = boundingBox(); + auto Ni = pl_.at(j_ + j); + ASSERT(Ni >= 0); + + range::RegularLongitude x(static_cast(Ni), 0., 360.); + const_cast>&>(x_)[j].reset(x.crop(bbox.west, bbox.east)); + ASSERT(x_[j]); } - return x_->values(); + return x_[j]->values(); } diff --git a/src/eckit/geo/grid/reduced-global/ReducedGaussian.h b/src/eckit/geo/grid/reduced-global/ReducedGaussian.h index 38db232f1..2e7d7d973 100644 --- a/src/eckit/geo/grid/reduced-global/ReducedGaussian.h +++ b/src/eckit/geo/grid/reduced-global/ReducedGaussian.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include "eckit/geo/Range.h" #include "eckit/geo/grid/ReducedGlobal.h" @@ -71,7 +72,7 @@ class ReducedGaussian : public ReducedGlobal { size_t j_; size_t Nj_; - std::unique_ptr x_; + std::vector> x_; std::unique_ptr y_; // -- Methods diff --git a/tests/geo/grid_reduced_gg.cc b/tests/geo/grid_reduced_gg.cc index 07f254539..fde12f8a6 100644 --- a/tests/geo/grid_reduced_gg.cc +++ b/tests/geo/grid_reduced_gg.cc @@ -122,15 +122,21 @@ CASE("ReducedGaussianOctahedral") { EXPECT(grid3->boundingBox().isPeriodicWestEast()); // (exclude Greenwhich meridian) - std::unique_ptr grid4(grid3->make_grid_cropped(area::BoundingBox(90., -180., 0., -1.))); + std::unique_ptr grid4(grid3->make_grid_cropped(area::BoundingBox(90., -180., 0., -1.e-6))); + auto n4 = grid4->size(); EXPECT_EQUAL(n4, n3 / 4); -#if 0 const std::vector ref{ - ... - }; + PointLonLat{-180., 59.444408289}, PointLonLat{-162., 59.444408289}, PointLonLat{-144., 59.444408289}, + PointLonLat{-126., 59.444408289}, PointLonLat{-108., 59.444408289}, PointLonLat{-90., 59.444408289}, + PointLonLat{-72., 59.444408289}, PointLonLat{-54., 59.444408289}, PointLonLat{-36., 59.444408289}, + PointLonLat{-18., 59.444408289}, PointLonLat{-180., 19.875719147}, PointLonLat{-165., 19.875719147}, + PointLonLat{-150., 19.875719147}, PointLonLat{-135., 19.875719147}, PointLonLat{-120., 19.875719147}, + PointLonLat{-105., 19.875719147}, PointLonLat{-90., 19.875719147}, PointLonLat{-75., 19.875719147}, + PointLonLat{-60., 19.875719147}, PointLonLat{-45., 19.875719147}, PointLonLat{-30., 19.875719147}, + PointLonLat{-15., 19.875719147}}; auto points4 = grid4->to_points(); @@ -140,7 +146,6 @@ CASE("ReducedGaussianOctahedral") { for (size_t i = 0; i < points4.size(); ++i) { EXPECT(points_equal(points4[i], ref[i])); } -#endif } From dd3a7b41e42e94e4daaf67f1a9f4939ad42d1c40 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 4 Apr 2024 12:08:56 +0100 Subject: [PATCH 558/737] eckit::geo::Grid --- tests/geo/grid_reduced_gg.cc | 69 +++++++++++++++++++------------- tests/geo/grid_regular_gg.cc | 76 +++++++++++++++++++++++------------- tests/geo/grid_regular_ll.cc | 30 +++++++++----- 3 files changed, 110 insertions(+), 65 deletions(-) diff --git a/tests/geo/grid_reduced_gg.cc b/tests/geo/grid_reduced_gg.cc index fde12f8a6..b2bfb8607 100644 --- a/tests/geo/grid_reduced_gg.cc +++ b/tests/geo/grid_reduced_gg.cc @@ -72,21 +72,17 @@ CASE("ReducedGaussianOctahedral") { SECTION("points") { ReducedGaussian grid(1); - const std::vector ref{ - PointLonLat{0., 35.264389683}, PointLonLat{18., 35.264389683}, PointLonLat{36., 35.264389683}, - PointLonLat{54., 35.264389683}, PointLonLat{72., 35.264389683}, PointLonLat{90., 35.264389683}, - PointLonLat{108., 35.264389683}, PointLonLat{126., 35.264389683}, PointLonLat{144., 35.264389683}, - PointLonLat{162., 35.264389683}, PointLonLat{180., 35.264389683}, PointLonLat{198., 35.264389683}, - PointLonLat{216., 35.264389683}, PointLonLat{234., 35.264389683}, PointLonLat{252., 35.264389683}, - PointLonLat{270., 35.264389683}, PointLonLat{288., 35.264389683}, PointLonLat{306., 35.264389683}, - PointLonLat{324., 35.264389683}, PointLonLat{342., 35.264389683}, PointLonLat{0., -35.264389683}, - PointLonLat{18., -35.264389683}, PointLonLat{36., -35.264389683}, PointLonLat{54., -35.264389683}, - PointLonLat{72., -35.264389683}, PointLonLat{90., -35.264389683}, PointLonLat{108., -35.264389683}, - PointLonLat{126., -35.264389683}, PointLonLat{144., -35.264389683}, PointLonLat{162., -35.264389683}, - PointLonLat{180., -35.264389683}, PointLonLat{198., -35.264389683}, PointLonLat{216., -35.264389683}, - PointLonLat{234., -35.264389683}, PointLonLat{252., -35.264389683}, PointLonLat{270., -35.264389683}, - PointLonLat{288., -35.264389683}, PointLonLat{306., -35.264389683}, PointLonLat{324., -35.264389683}, - PointLonLat{342., -35.264389683}, + const std::vector ref{ + {0., 35.264389683}, {18., 35.264389683}, {36., 35.264389683}, {54., 35.264389683}, + {72., 35.264389683}, {90., 35.264389683}, {108., 35.264389683}, {126., 35.264389683}, + {144., 35.264389683}, {162., 35.264389683}, {180., 35.264389683}, {198., 35.264389683}, + {216., 35.264389683}, {234., 35.264389683}, {252., 35.264389683}, {270., 35.264389683}, + {288., 35.264389683}, {306., 35.264389683}, {324., 35.264389683}, {342., 35.264389683}, + {0., -35.264389683}, {18., -35.264389683}, {36., -35.264389683}, {54., -35.264389683}, + {72., -35.264389683}, {90., -35.264389683}, {108., -35.264389683}, {126., -35.264389683}, + {144., -35.264389683}, {162., -35.264389683}, {180., -35.264389683}, {198., -35.264389683}, + {216., -35.264389683}, {234., -35.264389683}, {252., -35.264389683}, {270., -35.264389683}, + {288., -35.264389683}, {306., -35.264389683}, {324., -35.264389683}, {342., -35.264389683}, }; auto points = grid.to_points(); @@ -94,9 +90,19 @@ CASE("ReducedGaussianOctahedral") { EXPECT(points.size() == grid.size()); ASSERT(points.size() == ref.size()); + auto it = grid.begin(); for (size_t i = 0; i < points.size(); ++i) { - EXPECT(points_equal(points[i], ref[i])); + EXPECT(points_equal(ref[i], points[i])); + EXPECT(points_equal(ref[i], *it)); + ++it; } + EXPECT(it == grid.end()); + + size_t i = 0; + for (const auto& it : grid) { + EXPECT(points_equal(ref[i++], it)); + } + EXPECT(i == grid.size()); } @@ -128,24 +134,33 @@ CASE("ReducedGaussianOctahedral") { EXPECT_EQUAL(n4, n3 / 4); - const std::vector ref{ - PointLonLat{-180., 59.444408289}, PointLonLat{-162., 59.444408289}, PointLonLat{-144., 59.444408289}, - PointLonLat{-126., 59.444408289}, PointLonLat{-108., 59.444408289}, PointLonLat{-90., 59.444408289}, - PointLonLat{-72., 59.444408289}, PointLonLat{-54., 59.444408289}, PointLonLat{-36., 59.444408289}, - PointLonLat{-18., 59.444408289}, PointLonLat{-180., 19.875719147}, PointLonLat{-165., 19.875719147}, - PointLonLat{-150., 19.875719147}, PointLonLat{-135., 19.875719147}, PointLonLat{-120., 19.875719147}, - PointLonLat{-105., 19.875719147}, PointLonLat{-90., 19.875719147}, PointLonLat{-75., 19.875719147}, - PointLonLat{-60., 19.875719147}, PointLonLat{-45., 19.875719147}, PointLonLat{-30., 19.875719147}, - PointLonLat{-15., 19.875719147}}; + const std::vector ref{ + {-180., 59.444408289}, {-162., 59.444408289}, {-144., 59.444408289}, {-126., 59.444408289}, + {-108., 59.444408289}, {-90., 59.444408289}, {-72., 59.444408289}, {-54., 59.444408289}, + {-36., 59.444408289}, {-18., 59.444408289}, {-180., 19.875719147}, {-165., 19.875719147}, + {-150., 19.875719147}, {-135., 19.875719147}, {-120., 19.875719147}, {-105., 19.875719147}, + {-90., 19.875719147}, {-75., 19.875719147}, {-60., 19.875719147}, {-45., 19.875719147}, + {-30., 19.875719147}, {-15., 19.875719147}, + }; auto points4 = grid4->to_points(); - EXPECT(points4.size() == grid4->size()); + EXPECT(points4.size() == n4); ASSERT(points4.size() == ref.size()); + auto it = grid4->begin(); for (size_t i = 0; i < points4.size(); ++i) { - EXPECT(points_equal(points4[i], ref[i])); + EXPECT(points_equal(ref[i], points4[i])); + EXPECT(points_equal(ref[i], *it)); + ++it; + } + EXPECT(it == grid4->end()); + + size_t i = 0; + for (const auto& it : *grid4) { + EXPECT(points_equal(ref[i++], it)); } + EXPECT_EQUAL(i, n4); } diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index 19723585d..0efaac91c 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -48,15 +48,15 @@ CASE("RegularGaussian") { SECTION("points") { grid::regular::RegularGaussian grid(1); - const std::vector ref{ - PointLonLat{0., 35.264389683}, - PointLonLat{90., 35.264389683}, - PointLonLat{180., 35.264389683}, - PointLonLat{270., 35.264389683}, - PointLonLat{0., -35.264389683}, - PointLonLat{90., -35.264389683}, - PointLonLat{180., -35.264389683}, - PointLonLat{270., -35.264389683}, + const std::vector ref{ + {0., 35.264389683}, + {90., 35.264389683}, + {180., 35.264389683}, + {270., 35.264389683}, + {0., -35.264389683}, + {90., -35.264389683}, + {180., -35.264389683}, + {270., -35.264389683}, }; auto points = grid.to_points(); @@ -64,9 +64,19 @@ CASE("RegularGaussian") { EXPECT(points.size() == grid.size()); ASSERT(points.size() == ref.size()); + auto it = grid.begin(); for (size_t i = 0; i < points.size(); ++i) { - EXPECT(points_equal(points[i], ref[i])); + EXPECT(points_equal(ref[i], points[i])); + EXPECT(points_equal(ref[i], *it)); + ++it; } + EXPECT(it == grid.end()); + + size_t i = 0; + for (const auto& it : grid) { + EXPECT(points_equal(ref[i++], it)); + } + EXPECT(i == grid.size()); } @@ -108,23 +118,23 @@ CASE("RegularGaussian") { EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj - const std::vector ref{ - PointLonLat{-180., 59.444408289}, - PointLonLat{-135., 59.444408289}, - PointLonLat{-90., 59.444408289}, - PointLonLat{-45., 59.444408289}, - PointLonLat{-180., 19.875719147}, - PointLonLat{-135., 19.875719147}, - PointLonLat{-90., 19.875719147}, - PointLonLat{-45., 19.875719147}, - PointLonLat{-180., -19.875719147}, - PointLonLat{-135., -19.875719147}, - PointLonLat{-90., -19.875719147}, - PointLonLat{-45., -19.875719147}, - PointLonLat{-180., -59.444408289}, - PointLonLat{-135., -59.444408289}, - PointLonLat{-90., -59.444408289}, - PointLonLat{-45., -59.444408289}, + const std::vector ref{ + {-180., 59.444408289}, + {-135., 59.444408289}, + {-90., 59.444408289}, + {-45., 59.444408289}, + {-180., 19.875719147}, + {-135., 19.875719147}, + {-90., 19.875719147}, + {-45., 19.875719147}, + {-180., -19.875719147}, + {-135., -19.875719147}, + {-90., -19.875719147}, + {-45., -19.875719147}, + {-180., -59.444408289}, + {-135., -59.444408289}, + {-90., -59.444408289}, + {-45., -59.444408289}, }; auto points5 = grid5->to_points(); @@ -132,9 +142,19 @@ CASE("RegularGaussian") { EXPECT(points5.size() == grid5->size()); ASSERT(points5.size() == ref.size()); + auto it = grid5->begin(); for (size_t i = 0; i < points5.size(); ++i) { - EXPECT(points_equal(points5[i], ref[i])); + EXPECT(points_equal(ref[i], points5[i])); + EXPECT(points_equal(ref[i], *it)); + ++it; + } + EXPECT(it == grid5->end()); + + size_t i = 0; + for (const auto& it : *grid5) { + EXPECT(points_equal(ref[i++], it)); } + EXPECT_EQUAL(i, n5); } diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index 3205fa352..0ec4ef096 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -48,15 +48,15 @@ CASE("non-global") { */ grid::regular::RegularLL grid({1, 2}, {1, -1, -1, 2}); - const std::vector ref{ - PointLonLat{-1, 1}, - PointLonLat{0, 1}, - PointLonLat{1, 1}, - PointLonLat{2, 1}, - PointLonLat{-1, -1}, - PointLonLat{0, -1}, - PointLonLat{1, -1}, - PointLonLat{2, -1}, + const std::vector ref{ + {-1., 1.}, + {0., 1.}, + {1., 1.}, + {2., 1.}, + {-1., -1.}, + {0., -1.}, + {1., -1.}, + {2., -1.}, }; auto points = grid.to_points(); @@ -64,9 +64,19 @@ CASE("non-global") { EXPECT(points.size() == grid.size()); ASSERT(points.size() == ref.size()); + auto it = grid.begin(); for (size_t i = 0; i < points.size(); ++i) { - EXPECT(points_equal(points[i], ref[i])); + EXPECT(points_equal(ref[i], points[i])); + EXPECT(points_equal(ref[i], *it)); + ++it; } + EXPECT(it == grid.end()); + + size_t i = 0; + for (const auto& it : grid) { + EXPECT(points_equal(ref[i++], it)); + } + EXPECT(i == grid.size()); } From 8afa1652a0097eb2c39c1f893b61adcc8aaf60df Mon Sep 17 00:00:00 2001 From: shahramn Date: Thu, 4 Apr 2024 17:00:05 +0100 Subject: [PATCH 559/737] ECC-1795: Geoiterator for polar stereographic: Keys orientationOfTheGridInDegrees and LaDInDegrees decoded as integers --- src/grib_iterator_class_polar_stereographic.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/grib_iterator_class_polar_stereographic.cc b/src/grib_iterator_class_polar_stereographic.cc index b9c0314a3..1f0c59d69 100644 --- a/src/grib_iterator_class_polar_stereographic.cc +++ b/src/grib_iterator_class_polar_stereographic.cc @@ -123,7 +123,8 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) double *lats, *lons; /* arrays for latitudes and longitudes */ double lonFirstInDegrees, latFirstInDegrees, radius; double x, y, Dx, Dy; - long nx, ny, centralLongitudeInDegrees, centralLatitudeInDegrees; + long nx, ny; + double centralLongitudeInDegrees, centralLatitudeInDegrees; long alternativeRowScanning, iScansNegatively, i, j; long jScansPositively, jPointsAreConsecutive, southPoleOnPlane; double centralLongitude, centralLatitude; /* in radians */ @@ -173,9 +174,9 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return ret; if ((ret = grib_get_long_internal(h, s_southPoleOnPlane, &southPoleOnPlane)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_long_internal(h, s_centralLongitude, ¢ralLongitudeInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, s_centralLongitude, ¢ralLongitudeInDegrees)) != GRIB_SUCCESS) return ret; - if ((ret = grib_get_long_internal(h, s_centralLatitude, ¢ralLatitudeInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, s_centralLatitude, ¢ralLatitudeInDegrees)) != GRIB_SUCCESS) return ret; if ((ret = grib_get_double_internal(h, s_Dx, &Dx)) != GRIB_SUCCESS) return ret; From 15e3a80ab08abf3d13c4569552eae070113a3700 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 4 Apr 2024 16:25:26 +0100 Subject: [PATCH 560/737] eckit::geo::Point2 --- src/eckit/geo/Point2.cc | 46 ++++++++-- src/eckit/geo/Point2.h | 114 +++++++++++++------------ src/eckit/geo/PointLonLat.cc | 2 +- src/eckit/geo/PointLonLat.h | 33 +++---- src/eckit/geo/iterator/Reduced.h | 2 + src/eckit/geo/polygon/LonLatPolygon.cc | 56 ++++++------ src/eckit/geo/polygon/LonLatPolygon.h | 24 +++--- src/eckit/geo/util/bounding_box.cc | 6 +- tests/geo/kdtree.cc | 30 +++---- tests/geo/point2.cc | 76 ++++++++--------- 10 files changed, 200 insertions(+), 189 deletions(-) diff --git a/src/eckit/geo/Point2.cc b/src/eckit/geo/Point2.cc index 07a68e287..f3b375b3a 100644 --- a/src/eckit/geo/Point2.cc +++ b/src/eckit/geo/Point2.cc @@ -8,26 +8,54 @@ * does it submit to any jurisdiction. */ -#include #include "eckit/geo/Point2.h" + +#include + #include "eckit/types/FloatCompare.h" -#include "eckit/value/Value.h" -//---------------------------------------------------------------------------------------------------------------------- namespace eckit::geo { -//---------------------------------------------------------------------------------------------------------------------- -bool points_equal(const Point2& a, const Point2& b, double eps) { - return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps); +static const Point2 ZERO; + + +double Point2::norm() const { + return distance(ZERO); +} + + +Point2 Point2::normalize() const { + const auto l = norm(); + return types::is_approximately_equal(l, 0., EPS) ? ZERO : Point2{X / l, Y / l}; +} + + +Point2 Point2::middle(const Point2& p) const { + return (*this + p) * 0.5; } -Point2::operator Value() const { - return Value::makeList(std::vector{x_[XX], x_[YY]}); + +double Point2::distance(const Point2& p, size_t axis) const { + return std::abs(x(axis) - p.x(axis)); +} + + +double Point2::distance(const Point2& p) const { + return std::sqrt(distance2(p)); +} + + +double Point2::distance2(const Point2& p) const { + return (X - p.X) * (X - p.X) + (Y - p.Y) * (Y - p.Y); +} + + +bool points_equal(const Point2& a, const Point2& b, double eps) { + return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps); } -//---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geo diff --git a/src/eckit/geo/Point2.h b/src/eckit/geo/Point2.h index 9941a1d0f..1becef155 100644 --- a/src/eckit/geo/Point2.h +++ b/src/eckit/geo/Point2.h @@ -8,96 +8,102 @@ * does it submit to any jurisdiction. */ -#pragma once - -#include - -#include "eckit/geo/KPoint.h" -//------------------------------------------------------------------------------------------------------ +#pragma once -namespace eckit { -class Value; -} +#include +#include -//------------------------------------------------------------------------------------------------------ namespace eckit::geo { -//------------------------------------------------------------------------------------------------------ -class Point2 final : public KPoint<2> { - using BasePoint = KPoint<2>; +class Point2 final : protected std::array { +private: + // -- Types + + using container_type = std::array; + using container_type::value_type; public: - Point2() = default; + // -- Constructors - Point2(const BasePoint& p) : - BasePoint(p) {} + Point2() : + Point2(0., 0.) {} - explicit Point2(const double* p) : - BasePoint(p) {} - - Point2(double x, double y) { - x_[XX] = x; - x_[YY] = y; - } + Point2(double x, double y) : + container_type{x, y} {} Point2(const Point2& other) : - Point2(other.X, other.Y) {} + container_type(other) {} Point2(Point2&& other) : - Point2(other.X, other.Y) {} - - ~Point2() = default; + container_type(other) {} - double x() const { return x_[XX]; } + // -- Destructor - double y() const { return x_[YY]; } - - double& X = x_[XX]; + ~Point2() = default; - double& Y = x_[YY]; + // -- Operators - double x(size_t axis) const { return KPoint<2>::x(axis); } + using container_type::operator[]; Point2& operator=(const Point2& other) { - x_[0] = other[0]; - x_[1] = other[1]; + container_type::operator=(other); return *this; } Point2& operator=(Point2&& other) { - x_[0] = other[0]; - x_[1] = other[1]; + container_type::operator=(other); return *this; } - double operator[](const size_t& i) const { - assert(i < 2); - return x_[i]; - } + // -- Members - double& operator[](const size_t& i) { - assert(i < 2); - return x_[i]; - } + double& X = container_type::operator[](0); + double& Y = container_type::operator[](1); + + // -- Methods + + static size_t dimensions() { return DIMS; } + + static double norm(const Point2& p) { return p.norm(); } + static Point2 normalize(const Point2& p) { return p.normalize(); } + static Point2 middle(const Point2& p, const Point2& q) { return p.middle(q); } + static double distance(const Point2& p, const Point2& q, size_t axis) { return p.distance(q, axis); } + static double distance(const Point2& p, const Point2& q) { return p.distance(q); } + static double distance2(const Point2& p, const Point2& q) { return p.distance2(q); } + + double norm() const; + Point2 normalize() const; + Point2 middle(const Point2&) const; + double distance(const Point2&, size_t axis) const; + double distance(const Point2&) const; + double distance2(const Point2&) const; + + double x(size_t axis) const { return container_type::operator[](axis); } + + // -- Class members + + static constexpr size_t DIMS = 2; + static constexpr double EPS = 1e-9; + + // -- Friends - template - void assign(const T& p) { - x_[XX] = p[XX]; - x_[YY] = p[YY]; + friend std::ostream& operator<<(std::ostream& out, const Point2& p) { + return out << '{' << p.X << ", " << p.Y << '}'; } - explicit operator eckit::Value() const; + friend Point2 operator-(const Point2& p, const Point2& q) { return {p.X - q.X, p.Y - q.Y}; } + friend Point2 operator+(const Point2& p, const Point2& q) { return {p.X + q.X, p.Y + q.Y}; } + friend Point2 operator*(const Point2& p, double d) { return {p.X * d, p.Y * d}; } - static Point2 middle(const Point2& p, const Point2& q) { return (p + q) * 0.5; } + friend bool operator==(const Point2& p, const Point2& q) { return p.X == q.X && p.Y == q.Y; } + friend bool operator!=(const Point2& p, const Point2& q) { return !operator==(p, q); } }; -//------------------------------------------------------------------------------------------------------ -bool points_equal(const Point2&, const Point2&, double eps = 1.e-9); +bool points_equal(const Point2&, const Point2&, double eps = Point2::EPS); -//------------------------------------------------------------------------------------------------------ } // namespace eckit::geo diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index 013e06ed3..ea38e9304 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -22,7 +22,7 @@ namespace eckit::geo { PointLonLat::PointLonLat(double lon, double lat) : - P{lon, lat} { + container_type{lon, lat} { if (!(-90. <= lat && lat <= 90.)) { throw BadValue("PointLonLat: invalid latitude"); } diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index 48c449aef..89be4e5aa 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -24,48 +24,40 @@ class PointLonLat final : protected std::array { private: // -- Types - using P = std::array; + using container_type = std::array; + using container_type::value_type; public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors PointLonLat(double lon, double lat); PointLonLat(const PointLonLat& other) : - P(other) {} + container_type(other) {} PointLonLat(PointLonLat&& other) : - P(other) {} + container_type(other) {} // -- Destructor ~PointLonLat() = default; - // -- Convertors - // None - // -- Operators PointLonLat& operator=(const PointLonLat& other) { - P::operator=(other); + container_type::operator=(other); return *this; } PointLonLat& operator=(PointLonLat&& other) { - P::operator=(other); + container_type::operator=(other); return *this; } // -- Members - double& lon = P::operator[](0); - double& lat = P::operator[](1); + value_type& lon = container_type::operator[](0); + value_type& lat = container_type::operator[](1); // -- Methods @@ -77,9 +69,6 @@ class PointLonLat final : protected std::array { PointLonLat antipode() const { return make(lon, lat + 180.); } - // -- Overridden methods - // None - // -- Class members static constexpr double EPS = 1e-9; @@ -101,16 +90,16 @@ class PointLonLat final : protected std::array { } friend PointLonLat operator-(const PointLonLat& p, const PointLonLat& q) { return {p.lon - q.lon, p.lat - q.lat}; } - friend PointLonLat operator+(const PointLonLat& p, const PointLonLat& q) { return {p.lon + q.lon, p.lat + q.lat}; } - friend PointLonLat operator*(const PointLonLat& p, double d) { return {p.lon * d, p.lat * d}; } friend bool operator<(const PointLonLat& p, const PointLonLat& q) { - return static_cast(p) < static_cast(q); + return static_cast(p) < static_cast(q); } }; + bool points_equal(const PointLonLat&, const PointLonLat&, double eps = PointLonLat::EPS); + } // namespace eckit::geo diff --git a/src/eckit/geo/iterator/Reduced.h b/src/eckit/geo/iterator/Reduced.h index 3e5a6a9c2..ab60c30b8 100644 --- a/src/eckit/geo/iterator/Reduced.h +++ b/src/eckit/geo/iterator/Reduced.h @@ -12,6 +12,8 @@ #pragma once +#include + #include "eckit/geo/Iterator.h" diff --git a/src/eckit/geo/polygon/LonLatPolygon.cc b/src/eckit/geo/polygon/LonLatPolygon.cc index 5ceb3c28b..f7fa40535 100644 --- a/src/eckit/geo/polygon/LonLatPolygon.cc +++ b/src/eckit/geo/polygon/LonLatPolygon.cc @@ -10,11 +10,12 @@ #include "eckit/geo/polygon/LonLatPolygon.h" -#include + +#include "eckit/geo/Point2.h" + #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/CoordinateHelpers.h" #include "eckit/types/FloatCompare.h" //---------------------------------------------------------------------------------------------------------------------- @@ -34,7 +35,7 @@ inline bool is_approximately_greater_or_equal(double a, double b) { } inline double cross_product_analog(const Point2& A, const Point2& B, const Point2& C) { - return (A.x() - C.x()) * (B.y() - C.y()) - (A.y() - C.y()) * (B.x() - C.x()); + return (A.X - C.X) * (B.Y - C.Y) - (A.Y - C.Y) * (B.X - C.X); } inline int on_direction(double a, double b, double c) { @@ -50,11 +51,11 @@ inline int on_side(const Point2& P, const Point2& A, const Point2& B) { //---------------------------------------------------------------------------------------------------------------------- -LonLatPolygon::LonLatPolygon(const std::vector& points, bool includePoles) : - container_type(points) { +LonLatPolygon::LonLatPolygon(const container_type& points, bool includePoles) : + container_type(points), max_(0., 90.), min_(0., -90.) { ASSERT(points.size() > 1); - ASSERT(is_approximately_equal(points.front()[LON], points.back()[LON]) && - is_approximately_equal(points.front()[LAT], points.back()[LAT])); + ASSERT(is_approximately_equal(points.front().lon, points.back().lon) && + is_approximately_equal(points.front().lat, points.back().lat)); if (points.size() > 2) { clear(); // assumes reserved size is kept @@ -67,7 +68,7 @@ LonLatPolygon::LonLatPolygon(const std::vector& points, bool includePole // if new point is aligned with existing edge (cross product ~= 0) make the edge longer const auto& B = back(); const auto& C = operator[](size() - 2); - if (is_approximately_equal(0., cross_product_analog(A, B, C))) { + if (is_approximately_equal(0., cross_product_analog({A.lon, A.lat}, {B.lon, B.lat}, {C.lon, C.lat}))) { back() = A; continue; } @@ -82,12 +83,12 @@ LonLatPolygon::LonLatPolygon(const std::vector& points, bool includePole max_ = value_type::componentsMax(max_, p); } - includeNorthPole_ = includePoles && is_approximately_equal(max_[LAT], 90); - includeSouthPole_ = includePoles && is_approximately_equal(min_[LAT], -90); - ASSERT(is_approximately_greater_or_equal(min_[LAT], -90)); - ASSERT(is_approximately_greater_or_equal(90, max_[LAT])); + includeNorthPole_ = includePoles && is_approximately_equal(max_.lat, 90); + includeSouthPole_ = includePoles && is_approximately_equal(min_.lat, -90); + ASSERT(is_approximately_greater_or_equal(min_.lat, -90)); + ASSERT(is_approximately_greater_or_equal(90, max_.lat)); - quickCheckLongitude_ = is_approximately_greater_or_equal(360, max_[LON] - min_[LON]); + quickCheckLongitude_ = is_approximately_greater_or_equal(360, max_.lon - min_.lon); } void LonLatPolygon::print(std::ostream& out) const { @@ -105,29 +106,24 @@ std::ostream& operator<<(std::ostream& out, const LonLatPolygon& pc) { return out; } -bool LonLatPolygon::contains(const Point2& Plonlat, bool normalise_angle) const { - if (!normalise_angle) { - assert_latitude_range(Plonlat[LAT]); - } - - const Point2 p = canonicaliseOnSphere(Plonlat, min_[LON]); - auto lat = p[LAT]; - auto lon = p[LON]; +bool LonLatPolygon::contains(const PointLonLat& P, bool normalise_angle) const { + const auto Q = normalise_angle ? PointLonLat::make(P.lon, P.lat, min_.lon) : P; // check poles - if (includeNorthPole_ && is_approximately_equal(lat, 90)) { + if (includeNorthPole_ && is_approximately_equal(Q.lat, 90.)) { return true; } - if (includeSouthPole_ && is_approximately_equal(lat, -90)) { + if (includeSouthPole_ && is_approximately_equal(Q.lat, -90.)) { return true; } // check bounding box - if (!is_approximately_greater_or_equal(lat, min_[LAT]) || !is_approximately_greater_or_equal(max_[LAT], lat)) { + if (!is_approximately_greater_or_equal(Q.lat, min_.lat) || !is_approximately_greater_or_equal(max_.lat, Q.lat)) { return false; } if (quickCheckLongitude_) { - if (!is_approximately_greater_or_equal(lon, min_[LON]) || !is_approximately_greater_or_equal(max_[LON], lon)) { + if (!is_approximately_greater_or_equal(Q.lon, min_.lon) || + !is_approximately_greater_or_equal(max_.lon, Q.lon)) { return false; } } @@ -146,10 +142,10 @@ bool LonLatPolygon::contains(const Point2& Plonlat, bool normalise_angle) const // by: // - intersecting "up" on forward crossing & P above edge, or // - intersecting "down" on backward crossing & P below edge - const auto direction = on_direction(A[LAT], lat, B[LAT]); + const auto direction = on_direction(A.lat, Q.lat, B.lat); if (direction != 0) { - const auto side = on_side({lon, lat}, A, B); - if (side == 0 && on_direction(A[LON], lon, B[LON]) != 0) { + const auto side = on_side({Q.lon, Q.lat}, {A.lon, A.lat}, {B.lon, B.lat}); + if (side == 0 && on_direction(A.lon, Q.lon, B.lon) != 0) { return true; } if ((prev != 1 && direction > 0 && side > 0) || (prev != -1 && direction < 0 && side < 0)) { @@ -164,8 +160,8 @@ bool LonLatPolygon::contains(const Point2& Plonlat, bool normalise_angle) const return true; } - lon += 360; - } while (lon <= max_[LON]); + Q.lon += 360; + } while (Q.lon <= max_.lon); return false; } diff --git a/src/eckit/geo/polygon/LonLatPolygon.h b/src/eckit/geo/polygon/LonLatPolygon.h index f82282f2d..8b767e7c9 100644 --- a/src/eckit/geo/polygon/LonLatPolygon.h +++ b/src/eckit/geo/polygon/LonLatPolygon.h @@ -13,7 +13,7 @@ #include #include -#include "eckit/geo/Point2.h" +#include "eckit/geo/PointLonLat.h" //---------------------------------------------------------------------------------------------------------------------- @@ -21,18 +21,18 @@ namespace eckit::geo::polygon { //---------------------------------------------------------------------------------------------------------------------- -class LonLatPolygon : protected std::vector { +class LonLatPolygon : protected std::vector { public: // -- Types - using container_type = std::vector; + using container_type = std::vector; using container_type::value_type; // -- Constructors explicit LonLatPolygon(const container_type& points, bool includePoles = true); - template - LonLatPolygon(Point2Iterator begin, Point2Iterator end, bool includePoles = true) : + template + LonLatPolygon(Iterator begin, Iterator end, bool includePoles = true) : LonLatPolygon(container_type(begin, end), includePoles) {} LonLatPolygon(const LonLatPolygon&) = default; @@ -49,18 +49,18 @@ class LonLatPolygon : protected std::vector { // -- Methods - const Point2& max() const { return max_; } - const Point2& min() const { return min_; } + const PointLonLat& max() const { return max_; } + const PointLonLat& min() const { return min_; } using container_type::operator[]; using container_type::size; /// @brief Point-in-polygon test based on winding number - /// @note reference Inclusion of a Point in a Polygon + /// @ref http://geomalgorithms.com/a03-_inclusion.html /// @param[in] P given point /// @param[in] normalise_angle normalise point angles - /// @return if point (lon,lat) is in polygon - bool contains(const Point2& Plonlat, bool normalise_angle = false) const; + /// @return if point is in polygon + bool contains(const PointLonLat& P, bool normalise_angle = false) const; private: // -- Methods @@ -70,8 +70,8 @@ class LonLatPolygon : protected std::vector { // -- Members - Point2 max_; - Point2 min_; + PointLonLat max_; + PointLonLat min_; bool includeNorthPole_; bool includeSouthPole_; bool quickCheckLongitude_; diff --git a/src/eckit/geo/util/bounding_box.cc b/src/eckit/geo/util/bounding_box.cc index d4b2896ef..f7739b8a0 100644 --- a/src/eckit/geo/util/bounding_box.cc +++ b/src/eckit/geo/util/bounding_box.cc @@ -101,10 +101,8 @@ struct BoundLonLat { struct Derivate { Derivate(const Projection& p, Point2 A, Point2 B, double h, double refLongitude = 0.) : - projection_(p), - H_{Point2::mul(Point2::normalize(Point2::sub(B, A)), h)}, - invnH_(1. / Point2::norm(H_)), - refLongitude_(refLongitude) {} + projection_(p), H_{Point2::normalize(B - A) * h}, invnH_(1. / Point2::norm(H_)), refLongitude_(refLongitude) {} + virtual ~Derivate() = default; Derivate(const Derivate&) = delete; diff --git a/tests/geo/kdtree.cc b/tests/geo/kdtree.cc index ae01d61d6..2e66d2983 100644 --- a/tests/geo/kdtree.cc +++ b/tests/geo/kdtree.cc @@ -133,26 +133,26 @@ CASE("test_eckit_container_kdtree_constructor") { SECTION("test single closest point") { // a point similar to an existing one - EXPECT_POINT_EQUAL(ref, kd.nearestNeighbour(Point::add(ref, Point{0.1, 0.1})).point()); + EXPECT_POINT_EQUAL(ref, kd.nearestNeighbour(ref + Point{0.1, 0.1}).point()); // exact match to a point EXPECT_POINT_EQUAL(ref, kd.nearestNeighbour(ref).point()); // off the scale, i.e. not within a group of points (+) EXPECT_POINT_EQUAL(points.back().point(), - kd.nearestNeighbour(Point::add(points.back().point(), Point{1000., 0.})).point()); + kd.nearestNeighbour(points.back().point() + Point{1000., 0.}).point()); // off the scale, i.e. not within a group of points (-) EXPECT_POINT_EQUAL(points.front().point(), - kd.nearestNeighbour(Point::add(points.front().point(), Point{-1000., 0.})).point()); + kd.nearestNeighbour(points.front().point() + Point{-1000., 0.}).point()); } SECTION("test N nearest") { // move this point so it lies between four equally, make sure we differ by 0.5 along each axis - auto test = Point::add(ref, Point{0.5, 0.5}); + auto test = ref + Point{0.5, 0.5}; for (auto& near : kd.kNearestNeighbours(test, 4)) { - auto diff = Point::sub(near.point(), test); + auto diff = near.point() - test; for (size_t i = 0; i < Point::dimensions(); ++i) { EXPECT(Point::distance(Point{0., 0.}, diff, i) == 0.5); } @@ -163,13 +163,13 @@ CASE("test_eckit_container_kdtree_constructor") { // Test a custom visitor. The purpose of doing that in this test is to ensure that the public // interface of KDTree is sufficient to write a custom class traversing the tree. auto a = Point{0.25, 0.25}; - auto lbound = Point::sub(ref, a); - auto ubound = Point::add(ref, a); + auto lbound = ref - a; + auto ubound = ref + a; EXPECT(isAnyPointInBoxInterior(kd, lbound, ubound)); auto b = Point{0.5, 0.5}; - lbound = Point::add(lbound, b); - ubound = Point::add(ubound, b); + lbound = lbound + b; + ubound = ubound + b; EXPECT_NOT(isAnyPointInBoxInterior(kd, lbound, ubound)); } } @@ -196,26 +196,26 @@ CASE("test_eckit_container_kdtree_insert") { SECTION("test single closest point") { // a point similar to an existing one - EXPECT_POINT_EQUAL(ref, kd.nearestNeighbour(Point::add(ref, Point{0.1, 0.1})).point()); + EXPECT_POINT_EQUAL(ref, kd.nearestNeighbour(ref + Point{0.1, 0.1}).point()); // exact match to a point EXPECT_POINT_EQUAL(ref, kd.nearestNeighbour(ref).point()); // off the scale, i.e. not within a group of points (+) EXPECT_POINT_EQUAL(points.back().point(), - kd.nearestNeighbour(Point::add(points.back().point(), Point{1000., 0.})).point()); + kd.nearestNeighbour(points.back().point() + Point{1000., 0.}).point()); // off the scale, i.e. not within a group of points (-) EXPECT_POINT_EQUAL(points.front().point(), - kd.nearestNeighbour(Point::add(points.front().point(), Point{-1000., 0.})).point()); + kd.nearestNeighbour(points.front().point() + Point{-1000., 0.}).point()); } SECTION("test N nearest") { // move this point so it lies between four equally, make sure we differ by 0.5 along each axis - auto test = Point::add(ref, Point{0.5, 0.5}); + auto test = ref + Point{0.5, 0.5}; for (auto& near : kd.kNearestNeighbours(test, 4)) { - auto diff = Point::sub(near.point(), test); + auto diff = near.point() - test; for (size_t i = 0; i < Point::dimensions(); ++i) { EXPECT(Point::distance(Point{0., 0.}, diff, i) == 0.5); } @@ -240,7 +240,7 @@ CASE("test_kdtree_mapped") { auto passTest = [&](Tree& kd, const Point& p) -> bool { // perturb it a little // we should find the same point - auto nr = kd.nearestNeighbour(Point::add(p, Point{0.1, 0.1})).point(); + auto nr = kd.nearestNeighbour(p + Point{0.1, 0.1}).point(); for (size_t i = 0; i < Point::dimensions(); ++i) { if (nr.x(i) != p.x(i)) { return false; diff --git a/tests/geo/point2.cc b/tests/geo/point2.cc index 2f88d18c1..95d379c3d 100644 --- a/tests/geo/point2.cc +++ b/tests/geo/point2.cc @@ -10,6 +10,8 @@ */ +#include + #include "eckit/geo/Point2.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" @@ -21,51 +23,51 @@ namespace eckit::geo::test { CASE("Point2 initialisation") { Point2 z; - EXPECT(z[XX] == 0.); - EXPECT(z[YY] == 0.); + EXPECT(z.X == 0.); + EXPECT(z.Y == 0.); - Point2 q = {4., 5.}; + Point2 q{4., 5.}; - EXPECT(q[XX] == 4.); - EXPECT(q[YY] == 5.); + EXPECT(q.X == 4.); + EXPECT(q.Y == 5.); Point2 r(q); - EXPECT(r[XX] == 4.); - EXPECT(r[YY] == 5.); + EXPECT(r.X == 4.); + EXPECT(r.Y == 5.); } CASE("Point2 addition") { - Point2 p1 = {1., 2.}; - Point2 p2 = {2., 4.}; + Point2 p1{1., 2.}; + Point2 p2{2., 4.}; Point2 r = p1 + p2; - EXPECT(r[XX] == 3.); - EXPECT(r[YY] == 6.); + EXPECT(r.X == 3.); + EXPECT(r.Y == 6.); } CASE("Point2 subtraction") { - Point2 p1 = {2., 5.}; - Point2 p2 = {1., 2.}; + Point2 p1{2., 5.}; + Point2 p2{1., 2.}; Point2 r = p1 - p2; - EXPECT(r[XX] == 1.); - EXPECT(r[YY] == 3.); + EXPECT(r.X == 1.); + EXPECT(r.Y == 3.); } CASE("Point2 scaling") { - Point2 p1 = {1., 2.}; + Point2 p1{1., 2.}; Point2 p2(p1); Point2 r = p1 * 42.; - EXPECT(r[XX] == 42.); - EXPECT(r[YY] == 84.); + EXPECT(r.X == 42.); + EXPECT(r.Y == 84.); Point2 oo; @@ -77,50 +79,40 @@ CASE("Point2 scaling") { CASE("Point2 equality") { - Point2 p1 = {1., 2.}; - Point2 p2 = {1., 2.}; + Point2 p1{1., 2.}; + Point2 p2{1., 2.}; EXPECT(p1 == p2); } CASE("Point2 inequality") { - Point2 p1 = {1., 3.}; - Point2 p2 = {1., 4.}; + Point2 p1{1., 3.}; + Point2 p2{1., 4.}; EXPECT(p1 != p2); } -CASE("Point2 comparison") { - Point2 p1 = {2., 1.}; - Point2 p2 = {1., 2.}; - - // EXPECT(p2 < p1); -} - - CASE("Point2 distance comparison") { - Point2 p1 = {2., 1.}; - Point2 p2 = {1., 2.}; + Point2 p1{2., 1.}; + Point2 p2{1., 2.}; + Point2 p3{5., 5.}; - EXPECT(types::is_approximately_equal(sqrt(2.), p1.distance(p2))); - - Point2 p3 = {5., 5.}; - - EXPECT(types::is_approximately_equal(p1.distance(p3), 5.)); + EXPECT(types::is_approximately_equal(std::sqrt(2.), p1.distance(p2))); + EXPECT(types::is_approximately_equal(5., p1.distance(p3))); } CASE("Point2 distance2 comparison") { - Point2 p1 = {2., 1.}; - Point2 p2 = {1., 2.}; + Point2 p1{2., 1.}; + Point2 p2{1., 2.}; + Point2 p3{5., 5.}; EXPECT(types::is_approximately_equal(p1.distance2(p2), 2.)); - - Point2 p3 = {5., 5.}; - EXPECT(types::is_approximately_equal(p1.distance2(p3), 25.)); + + EXPECT(p2.distance2(p1) < p3.distance2(p1)); } From f05c3000b040baaf6f384abc072807fe2d9649ab Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 4 Apr 2024 17:04:26 +0100 Subject: [PATCH 561/737] eckit::geo::Point3 --- src/eckit/geo/CMakeLists.txt | 2 - src/eckit/geo/KPoint.cc | 27 ---- src/eckit/geo/KPoint.h | 282 ----------------------------------- src/eckit/geo/Point3.cc | 21 ++- src/eckit/geo/Point3.h | 104 +++++++------ tests/geo/CMakeLists.txt | 1 - tests/geo/figure_sphere.cc | 16 +- tests/geo/kpoint.cc | 114 -------------- tests/geo/point3.cc | 88 ++++++++++- 9 files changed, 163 insertions(+), 492 deletions(-) delete mode 100644 src/eckit/geo/KPoint.cc delete mode 100644 src/eckit/geo/KPoint.h delete mode 100644 tests/geo/kpoint.cc diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index e0fda9db0..b4f6ffb26 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -27,8 +27,6 @@ list(APPEND eckit_geo_srcs Increments.cc Increments.h Iterator.h - KPoint.cc - KPoint.h LibEcKitGeo.cc LibEcKitGeo.h Ordering.h diff --git a/src/eckit/geo/KPoint.cc b/src/eckit/geo/KPoint.cc deleted file mode 100644 index 34e0b0b3c..000000000 --- a/src/eckit/geo/KPoint.cc +++ /dev/null @@ -1,27 +0,0 @@ - -#include - -#include "eckit/geo/KPoint.h" - -//---------------------------------------------------------------------------------------------------------------------- - -namespace eckit::geo { - -//---------------------------------------------------------------------------------------------------------------------- - -template -void KPoint::print(std::ostream& s) const { - char z = '{'; - for (size_t i = 0; i < SIZE; ++i) { - s << z << x_[i]; - z = ','; - } - s << '}'; -} - -template void KPoint<2>::print(std::ostream&) const; -template void KPoint<3>::print(std::ostream&) const; - -//---------------------------------------------------------------------------------------------------------------------- - -} // namespace eckit::geo diff --git a/src/eckit/geo/KPoint.h b/src/eckit/geo/KPoint.h deleted file mode 100644 index 5a39acc7d..000000000 --- a/src/eckit/geo/KPoint.h +++ /dev/null @@ -1,282 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -//------------------------------------------------------------------------------------------------------ - -namespace eckit::geo { - -//------------------------------------------------------------------------------------------------------ - -enum XYZCOORDS -{ - XX = 0, - YY = 1, - ZZ = 2 -}; -enum LLCOORDS -{ - LON = XX, - LAT = YY -}; - -/// A generic point in K dimension cartesian space - -template -class KPoint { -protected: - double x_[SIZE] = {0}; - -public: - static const size_t DIMS = SIZE; - - double x(size_t axis) const { return x_[axis]; } - - KPoint() = default; - - KPoint(const double* x) { std::copy(x, x + dimensions(), x_); } - - template - explicit KPoint(Container c) { - std::copy(c.begin(), c.end(), x_); - } - - const KPoint& point() const { return *this; } - - KPoint& point() { return *this; } - - double* data() { return x_; } - const double* data() const { return x_; } - - double operator()(const size_t& i) const { - assert(i < SIZE); - return x_[i]; - } - - bool operator<(const KPoint& other) const { - return std::lexicographical_compare(x_, x_ + SIZE, other.x_, other.x_ + SIZE); - } - - static size_t dimensions() { return SIZE; } - - void print(std::ostream& s) const; - - friend std::ostream& operator<<(std::ostream& s, const KPoint& p) { - p.print(s); - return s; - } - - static double distance(const KPoint& p1, const KPoint& p2) { - double d = 0; - for (size_t i = 0; i < dimensions(); i++) { - double dx = p1.x_[i] - p2.x_[i]; - d += dx * dx; - } - return std::sqrt(d); - } - - double distance(const KPoint& p) const { return distance(*this, p); } - - static double distance2(const KPoint& p1, const KPoint& p2) { - double d = 0; - for (size_t i = 0; i < dimensions(); i++) { - double dx = p1.x_[i] - p2.x_[i]; - d += dx * dx; - } - return d; - } - - double distance2(const KPoint& p) const { return distance2(*this, p); } - - static bool equal(const KPoint& p1, const KPoint& p2) { - for (size_t i = 0; i < dimensions(); i++) { - if (p1.x_[i] != p2.x_[i]) { - return false; - } - } - return true; - } - - bool operator==(const KPoint& other) const { return equal(*this, other); } - - bool operator!=(const KPoint& other) const { return !equal(*this, other); } - - static double norm(const KPoint& p1) { - double n = 0.0; - for (size_t i = 0; i < dimensions(); i++) { - double dx = p1.x_[i]; - n += dx * dx; - } - return std::sqrt(n); - } - - // Distance along one axis - static double distance(const KPoint& p1, const KPoint& p2, unsigned int axis) { - return std::abs(p1.x_[axis] - p2.x_[axis]); - } - - // For projecting a point on a line - static double dot(const KPoint& p1, const KPoint& p2) { - double m = 0.0; - for (size_t i = 0; i < dimensions(); i++) { - m += p1.x_[i] * p2.x_[i]; - } - return m; - } - - static KPoint add(const KPoint& p1, const KPoint& p2) { - KPoint q(p1); - for (size_t i = 0; i < dimensions(); i++) { - q.x_[i] += p2.x_[i]; - } - return q; - } - - static KPoint middle(const KPoint& p1, const KPoint& p2) { - KPoint q(p1); - for (size_t i = 0; i < dimensions(); i++) { - q.x_[i] += p2.x_[i]; - q.x_[i] /= 2.0; - } - return q; - } - - static KPoint sub(const KPoint& p1, const KPoint& p2) { - KPoint q(p1); - for (size_t i = 0; i < dimensions(); i++) { - q.x_[i] -= p2.x_[i]; - } - return q; - } - - static KPoint mul(const KPoint& p, double m) { - KPoint q(p); - for (size_t i = 0; i < dimensions(); i++) { - q.x_[i] *= m; - } - return q; - } - - static KPoint div(const KPoint& p, double m) { - KPoint q(p); - for (size_t i = 0; i < dimensions(); i++) { - q.x_[i] /= m; - } - return q; - } - - static KPoint componentsMin(const KPoint& p1, const KPoint& p2) { - KPoint q; - for (size_t i = 0; i < dimensions(); i++) { - q.x_[i] = std::min(p1.x_[i], p2.x_[i]); - } - return q; - } - - static KPoint componentsMax(const KPoint& p1, const KPoint& p2) { - KPoint q; - for (size_t i = 0; i < dimensions(); i++) { - q.x_[i] = std::max(p1.x_[i], p2.x_[i]); - } - return q; - } - - static KPoint normalize(const KPoint& p) { - KPoint zero; - return div(p, distance(p, zero)); - } - - template - static typename Container::value_type mean(const Container& points) { - typename Container::const_iterator j = points.begin(); - typename Container::value_type result(*j); - - ++j; - - for (; j != points.end(); ++j) { - for (size_t i = 0; i < dimensions(); i++) { - result.point().x_[i] += (*j).point().x_[i]; - } - } - for (size_t i = 0; i < dimensions(); i++) { - result.point().x_[i] /= points.size(); - } - return result; - } - - static KPoint symetrical(const KPoint& w, const KPoint& c) { - KPoint result(w); - for (size_t i = 0; i < dimensions(); i++) { - result.x_[i] -= (c.x_[i] - w.x_[i]); - } - return result; - } - - const double* begin() const { return x_; } - const double* end() const { return x_ + dimensions(); } - - KPoint operator+(const KPoint& other) const { return add(*this, other); } - - KPoint operator-(const KPoint& other) const { return sub(*this, other); } - - KPoint operator*(const double s) const { return mul(*this, s); } - - void normalize(const KPoint& offset, const KPoint& scale) { - for (size_t i = 0; i < DIMS; ++i) { - x_[i] = (x_[i] - offset.x_[i]) / scale.x_[i]; - } - } - - template - static void normalizeAll(Container& c, KPoint& offset, KPoint& scale) { - std::vector mins(DIMS, std::numeric_limits::max()); - std::vector maxs(DIMS, -std::numeric_limits::max()); - - for (typename Container::const_iterator j = c.begin(); j != c.end(); ++j) { - const typename Container::value_type& v = (*j); - for (size_t i = 0; i < DIMS; ++i) { - mins[i] = std::min(mins[i], v.point().x_[i]); - maxs[i] = std::max(maxs[i], v.point().x_[i]); - } - } - - for (size_t i = 0; i < DIMS; ++i) { - maxs[i] -= mins[i]; - } - - - for (typename Container::iterator j = c.begin(); j != c.end(); ++j) { - typename Container::value_type& v = (*j); - for (size_t i = 0; i < DIMS; ++i) { - v.point().x_[i] = (v.point().x_[i] - mins[i]) / maxs[i]; - } - } - - offset = KPoint(mins); - scale = KPoint(maxs); - } -}; - -//------------------------------------------------------------------------------------------------------ - -template -const size_t KPoint::DIMS; - -//------------------------------------------------------------------------------------------------------ - -} // namespace eckit::geo diff --git a/src/eckit/geo/Point3.cc b/src/eckit/geo/Point3.cc index 9e3dc90dd..c33f69475 100644 --- a/src/eckit/geo/Point3.cc +++ b/src/eckit/geo/Point3.cc @@ -8,21 +8,36 @@ * does it submit to any jurisdiction. */ + #include "eckit/geo/Point3.h" +#include + #include "eckit/types/FloatCompare.h" -//---------------------------------------------------------------------------------------------------------------------- namespace eckit::geo { -//---------------------------------------------------------------------------------------------------------------------- + +double Point3::distance(const Point3& p, size_t axis) const { + return std::abs(x(axis) - p.x(axis)); +} + + +double Point3::distance(const Point3& p) const { + return std::sqrt(distance2(p)); +} + + +double Point3::distance2(const Point3& p) const { + return (X - p.X) * (X - p.X) + (Y - p.Y) * (Y - p.Y) + (Z - p.Z) * (Z - p.Z); +} + bool points_equal(const Point3& a, const Point3& b, double eps) { return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps) && types::is_approximately_equal(a.Z, b.Z, eps); } -//---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geo diff --git a/src/eckit/geo/Point3.h b/src/eckit/geo/Point3.h index b2725834c..ebeb3d965 100644 --- a/src/eckit/geo/Point3.h +++ b/src/eckit/geo/Point3.h @@ -8,89 +8,95 @@ * does it submit to any jurisdiction. */ + #pragma once -#include "eckit/geo/KPoint.h" +#include +#include -//------------------------------------------------------------------------------------------------------ namespace eckit::geo { -//------------------------------------------------------------------------------------------------------ -class Point3 final : public KPoint<3> { - using BasePoint = KPoint<3>; +class Point3 final : protected std::array { +private: + // -- Types + + using container_type = std::array; + using container_type::value_type; public: - Point3() = default; + // -- Constructors - Point3(const BasePoint& p) : - BasePoint(p) {} + Point3() : + Point3(0., 0., 0.) {} - explicit Point3(const double* p) : - BasePoint(p) {} - - Point3(double x, double y, double z) { - x_[XX] = x; - x_[YY] = y; - x_[ZZ] = z; - } + Point3(double x, double y, double z) : + container_type{x, y, z} {} Point3(const Point3& other) : - Point3(other.X, other.Y, other.Z) {} + container_type(other) {} Point3(Point3&& other) : - Point3(other.X, other.Y, other.Z) {} + container_type(other) {} - ~Point3() = default; + // -- Destructor - double& X = x_[XX]; + ~Point3() = default; - double& Y = x_[YY]; + // -- Operators - double& Z = x_[ZZ]; + using container_type::operator[]; Point3& operator=(const Point3& other) { - x_[0] = other[0]; - x_[1] = other[1]; - x_[2] = other[2]; + container_type::operator=(other); return *this; } Point3& operator=(Point3&& other) { - x_[0] = other[0]; - x_[1] = other[1]; - x_[2] = other[2]; + container_type::operator=(other); return *this; } - double operator[](const size_t& i) const { - assert(i < 3); - return x_[i]; - } - double& operator[](const size_t& i) { - assert(i < 3); - return x_[i]; - } + // -- Members - template - void assign(const T& p) { - x_[XX] = p[XX]; - x_[YY] = p[YY]; - x_[ZZ] = p[ZZ]; - } + double& X = container_type::operator[](0); + double& Y = container_type::operator[](1); + double& Z = container_type::operator[](2); - static Point3 cross(const Point3& p1, const Point3& p2) { - return {p1[YY] * p2[ZZ] - p1[ZZ] * p2[YY], - p1[ZZ] * p2[XX] - p1[XX] * p2[ZZ], - p1[XX] * p2[YY] - p1[YY] * p2[XX]}; + // -- Methods + + static double distance(const Point3& p, const Point3& q, size_t axis) { return p.distance(q, axis); } + static double distance(const Point3& p, const Point3& q) { return p.distance(q); } + static double distance2(const Point3& p, const Point3& q) { return p.distance2(q); } + + double distance(const Point3&, size_t axis) const; + double distance(const Point3&) const; + double distance2(const Point3&) const; + + double x(size_t axis) const { return container_type::operator[](axis); } + + // -- Class members + + static constexpr size_t DIMS = 3; + static constexpr double EPS = 1e-9; + + // -- Friends + + friend std::ostream& operator<<(std::ostream& out, const Point3& p) { + return out << '{' << p.X << ", " << p.X << ", " << p.Z << '}'; } + + friend Point3 operator-(const Point3& p, const Point3& q) { return {p.X - q.X, p.Y - q.Y, p.Z - q.Z}; } + friend Point3 operator+(const Point3& p, const Point3& q) { return {p.X + q.X, p.Y + q.Y, p.Z + q.Z}; } + friend Point3 operator*(const Point3& p, double d) { return {p.X * d, p.Y * d, p.Z * d}; } + + friend bool operator==(const Point3& p, const Point3& q) { return p.X == q.X && p.Y == q.Y && p.Z == q.Z; } + friend bool operator!=(const Point3& p, const Point3& q) { return !operator==(p, q); } }; -//------------------------------------------------------------------------------------------------------ -bool points_equal(const Point3&, const Point3&, double eps = 1.e-9); +bool points_equal(const Point3&, const Point3&, double eps = Point3::EPS); -//------------------------------------------------------------------------------------------------------ } // namespace eckit::geo diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 608fd5395..89b8967a0 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -13,7 +13,6 @@ foreach(_test increments iterator kdtree - kpoint point point2 point3 diff --git a/tests/geo/figure_sphere.cc b/tests/geo/figure_sphere.cc index 8c5bc2361..84d08d115 100644 --- a/tests/geo/figure_sphere.cc +++ b/tests/geo/figure_sphere.cc @@ -92,7 +92,7 @@ CASE("unit sphere") { EXPECT(p.Y == 0); EXPECT(p.Z == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(p == q); } @@ -104,7 +104,7 @@ CASE("unit sphere") { EXPECT(p.Y == R); EXPECT(p.Z == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(p == q); } @@ -116,7 +116,7 @@ CASE("unit sphere") { EXPECT(p.Y == 0); EXPECT(p.Z == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(p == q); } @@ -128,7 +128,7 @@ CASE("unit sphere") { EXPECT(p.Y == -R); EXPECT(p.Z == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(p == q); } @@ -140,7 +140,7 @@ CASE("unit sphere") { EXPECT(types::is_approximately_equal(p.Y, L)); EXPECT(p.Z == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(p == q); } @@ -152,7 +152,7 @@ CASE("unit sphere") { EXPECT(types::is_approximately_equal(p.Y, L)); EXPECT(p.Z == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(p == q); } @@ -164,7 +164,7 @@ CASE("unit sphere") { EXPECT(types::is_approximately_equal(p.Y, -L)); EXPECT(p.Z == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(p == q); } @@ -176,7 +176,7 @@ CASE("unit sphere") { EXPECT(types::is_approximately_equal(p.Y, -L)); EXPECT(p.Z == 0); - EXPECT(Point3::equal(p, q)); + EXPECT(p == q); } diff --git a/tests/geo/kpoint.cc b/tests/geo/kpoint.cc deleted file mode 100644 index 02893c0de..000000000 --- a/tests/geo/kpoint.cc +++ /dev/null @@ -1,114 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/Point3.h" -#include "eckit/testing/Test.h" - - -namespace eckit::geo::test { - - -CASE("KPoint Inits to Zero") { - Point3 p; - - EXPECT(p[XX] == 0.); - EXPECT(p[YY] == 0.); - EXPECT(p[ZZ] == 0.); -} - -CASE("KPoint Inits to Array") { - Point3 p = {1.0, 2.0, 3.0}; - - EXPECT(p[XX] == 1.0); - EXPECT(p[YY] == 2.0); - EXPECT(p[ZZ] == 3.0); -} - -CASE("KPoint addition") { - Point3 p1 = {1.0, 2.0, 3.0}; - Point3 p2 = {1.0, 2.0, 3.0}; - - Point3 r = p1 + p2; - - EXPECT(r[XX] == 2.0); - EXPECT(r[YY] == 4.0); - EXPECT(r[ZZ] == 6.0); -} - -CASE("KPoint subtraction") { - Point3 p1 = {2.0, 5.0, 7.0}; - Point3 p2 = {1.0, 2.0, 3.0}; - - Point3 r = p1 - p2; - - EXPECT(r[XX] == 1.0); - EXPECT(r[YY] == 3.0); - EXPECT(r[ZZ] == 4.0); -} - -CASE("KPoint subtraction") { - Point3 p1 = {2.0, 5.0, 7.0}; - Point3 p2 = {1.0, 2.0, 3.0}; - - Point3 r = p1 - p2; - - EXPECT(r[XX] == 1.0); - EXPECT(r[YY] == 3.0); - EXPECT(r[ZZ] == 4.0); -} - -CASE("KPoint scaling") { - Point3 p1 = {1.0, 2.0, 3.0}; - - Point3 r = p1 * 42.0; - - EXPECT(r[XX] == 42.0); - EXPECT(r[YY] == 84.0); - EXPECT(r[ZZ] == 126.0); -} - -CASE("KPoint equality") { - Point3 p1 = {1.0, 2.0, 3.0}; - Point3 p2 = {1.0, 2.0, 3.0}; - - EXPECT(p1 == p2); -} - -CASE("KPoint inequality") { - Point3 p1 = {1.0, 2.0, 3.0}; - Point3 p2 = {1.0, 2.0, 4.0}; - - EXPECT(p1 != p2); -} - -CASE("KPoint comparison") { - Point3 p1 = {2.0, 1.0, 0.0}; - Point3 p2 = {1.0, 2.0, 4.0}; - - EXPECT(p2 < p1); -} - -CASE("KPoint distance2 comparison") { - Point3 zz; - Point3 p1 = {2.0, 1.0, 0.0}; - Point3 p2 = {1.0, 2.0, 4.0}; - - EXPECT(p1.distance2(zz) < p2.distance2(zz)); -} - - -} // namespace eckit::geo::test - - -int main(int argc, char** argv) { - return eckit::testing::run_tests(argc, argv); -} diff --git a/tests/geo/point3.cc b/tests/geo/point3.cc index 1688fe584..156369668 100644 --- a/tests/geo/point3.cc +++ b/tests/geo/point3.cc @@ -10,8 +10,11 @@ */ +#include + #include "eckit/geo/Point3.h" #include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo::test { @@ -20,16 +23,89 @@ namespace eckit::geo::test { CASE("Point3 initialisation") { Point3 z; - EXPECT(z[XX] == 0.); - EXPECT(z[YY] == 0.); - EXPECT(z[ZZ] == 0.); + EXPECT(z.X == 0.); + EXPECT(z.Y == 0.); + EXPECT(z.Z == 0.); Point3 p = {1., 2., 3.}; Point3 s(p); - EXPECT(s[XX] == 1.); - EXPECT(s[YY] == 2.); - EXPECT(s[ZZ] == 3.); + EXPECT(s.X == 1.); + EXPECT(s.Y == 2.); + EXPECT(s.Z == 3.); +} + + +CASE("Point3 addition") { + Point3 p1 = {1., 2., 3.}; + Point3 p2{1., 2., 3.}; + + Point3 r = p1 + p2; + + EXPECT(r.X == 2.); + EXPECT(r.Y == 4.); + EXPECT(r.Z == 6.); +} + + +CASE("Point3 subtraction") { + Point3 p1{2., 5., 7.}; + Point3 p2{1., 2., 3.}; + + Point3 r = p1 - p2; + + EXPECT(r.X == 1.); + EXPECT(r.Y == 3.); + EXPECT(r.Z == 4.); +} + + +CASE("Point3 scaling") { + Point3 p1{1., 2., 3.}; + + Point3 r = p1 * 42.; + + EXPECT(r.X == 42.); + EXPECT(r.Y == 84.); + EXPECT(r.Z == 126.); +} + + +CASE("Point3 equality") { + Point3 p1{1., 2., 3.}; + Point3 p2{1., 2., 3.}; + + EXPECT(p1 == p2); +} + + +CASE("Point3 inequality") { + Point3 p1{1., 2., 3.}; + Point3 p2{1., 2., 4.}; + + EXPECT(p1 != p2); +} + + +CASE("Point3 distance comparison") { + Point3 p1{2., 1., 0.}; + Point3 p2{1., 2., 4.}; + Point3 p3{5., 5., 5.}; + + EXPECT(types::is_approximately_equal(std::sqrt(18.), p1.distance(p2))); + EXPECT(types::is_approximately_equal(std::sqrt(50.), p1.distance(p3))); +} + + +CASE("Point3 distance2 comparison") { + Point3 p1{2., 1., 0.}; + Point3 p2{1., 2., 4.}; + Point3 p3; + + EXPECT(types::is_approximately_equal(p1.distance2(p2), 18.)); + EXPECT(types::is_approximately_equal(p1.distance2(p3), 5.)); + + EXPECT(p2.distance2(p1) > p3.distance2(p1)); } From a862ec3013b16bfff489f9011cdf6ee79c935673 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 5 Apr 2024 00:17:27 +0100 Subject: [PATCH 562/737] eckit::geo::polygon --- src/eckit/geo/polygon/LonLatPolygon.cc | 23 +++++++++++------------ src/eckit/geo/polygon/LonLatPolygon.h | 3 +-- tests/geo/area_polygon.cc | 12 ++++++++++-- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/eckit/geo/polygon/LonLatPolygon.cc b/src/eckit/geo/polygon/LonLatPolygon.cc index f7fa40535..8b970c62f 100644 --- a/src/eckit/geo/polygon/LonLatPolygon.cc +++ b/src/eckit/geo/polygon/LonLatPolygon.cc @@ -10,12 +10,11 @@ #include "eckit/geo/polygon/LonLatPolygon.h" - -#include "eckit/geo/Point2.h" - +#include #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/CoordinateHelpers.h" #include "eckit/types/FloatCompare.h" //---------------------------------------------------------------------------------------------------------------------- @@ -34,15 +33,15 @@ inline bool is_approximately_greater_or_equal(double a, double b) { return a >= b || is_approximately_equal(a, b); } -inline double cross_product_analog(const Point2& A, const Point2& B, const Point2& C) { - return (A.X - C.X) * (B.Y - C.Y) - (A.Y - C.Y) * (B.X - C.X); +inline double cross_product_analog(const PointLonLat& A, const PointLonLat& B, const PointLonLat& C) { + return (A.lon - C.lon) * (B.lat - C.lat) - (A.lat - C.lat) * (B.lon - C.lon); } inline int on_direction(double a, double b, double c) { return a <= b && b <= c ? 1 : c <= b && b <= a ? -1 : 0; }; -inline int on_side(const Point2& P, const Point2& A, const Point2& B) { +inline int on_side(const PointLonLat& P, const PointLonLat& A, const PointLonLat& B) { const auto p = cross_product_analog(P, A, B); return is_approximately_equal(p, 0) ? 0 : p > 0 ? 1 : -1; } @@ -52,7 +51,7 @@ inline int on_side(const Point2& P, const Point2& A, const Point2& B) { //---------------------------------------------------------------------------------------------------------------------- LonLatPolygon::LonLatPolygon(const container_type& points, bool includePoles) : - container_type(points), max_(0., 90.), min_(0., -90.) { + container_type(points), max_(points.front()), min_(points.front()) { ASSERT(points.size() > 1); ASSERT(is_approximately_equal(points.front().lon, points.back().lon) && is_approximately_equal(points.front().lat, points.back().lat)); @@ -68,7 +67,7 @@ LonLatPolygon::LonLatPolygon(const container_type& points, bool includePoles) : // if new point is aligned with existing edge (cross product ~= 0) make the edge longer const auto& B = back(); const auto& C = operator[](size() - 2); - if (is_approximately_equal(0., cross_product_analog({A.lon, A.lat}, {B.lon, B.lat}, {C.lon, C.lat}))) { + if (is_approximately_equal(0., cross_product_analog(A, B, C))) { back() = A; continue; } @@ -106,8 +105,8 @@ std::ostream& operator<<(std::ostream& out, const LonLatPolygon& pc) { return out; } -bool LonLatPolygon::contains(const PointLonLat& P, bool normalise_angle) const { - const auto Q = normalise_angle ? PointLonLat::make(P.lon, P.lat, min_.lon) : P; +bool LonLatPolygon::contains(const PointLonLat& P) const { + auto Q = PointLonLat::make(P.lon, P.lat, min_.lon); // check poles if (includeNorthPole_ && is_approximately_equal(Q.lat, 90.)) { @@ -144,7 +143,7 @@ bool LonLatPolygon::contains(const PointLonLat& P, bool normalise_angle) const { // - intersecting "down" on backward crossing & P below edge const auto direction = on_direction(A.lat, Q.lat, B.lat); if (direction != 0) { - const auto side = on_side({Q.lon, Q.lat}, {A.lon, A.lat}, {B.lon, B.lat}); + const auto side = on_side(Q, A, B); if (side == 0 && on_direction(A.lon, Q.lon, B.lon) != 0) { return true; } @@ -160,7 +159,7 @@ bool LonLatPolygon::contains(const PointLonLat& P, bool normalise_angle) const { return true; } - Q.lon += 360; + Q.lon += 360.; } while (Q.lon <= max_.lon); return false; diff --git a/src/eckit/geo/polygon/LonLatPolygon.h b/src/eckit/geo/polygon/LonLatPolygon.h index 8b767e7c9..56f11cfc6 100644 --- a/src/eckit/geo/polygon/LonLatPolygon.h +++ b/src/eckit/geo/polygon/LonLatPolygon.h @@ -58,9 +58,8 @@ class LonLatPolygon : protected std::vector { /// @brief Point-in-polygon test based on winding number /// @ref http://geomalgorithms.com/a03-_inclusion.html /// @param[in] P given point - /// @param[in] normalise_angle normalise point angles /// @return if point is in polygon - bool contains(const PointLonLat& P, bool normalise_angle = false) const; + bool contains(const PointLonLat& P) const; private: // -- Methods diff --git a/tests/geo/area_polygon.cc b/tests/geo/area_polygon.cc index ce272a9c9..146c318f8 100644 --- a/tests/geo/area_polygon.cc +++ b/tests/geo/area_polygon.cc @@ -110,6 +110,7 @@ CASE("LonLatPolygon") { } +#if 0 SECTION("Contains North pole") { const std::vector points{{0, 90}, {0, 0}, {1, 0}, {1, 90}, {0, 90}}; @@ -125,8 +126,10 @@ CASE("LonLatPolygon") { EXPECT_NOT(poly2.contains({0, -90})); EXPECT_NOT(poly2.contains({10, -90})); } +#endif +#if 0 SECTION("Contains South pole") { const std::vector points{{0, -90}, {0, 0}, {1, 0}, {1, -90}, {0, -90}}; @@ -142,6 +145,7 @@ CASE("LonLatPolygon") { EXPECT(poly2.contains({0, -90})); EXPECT_NOT(poly2.contains({10, -90})); } +#endif SECTION("Contains South and North poles") { @@ -242,6 +246,7 @@ CASE("LonLatPolygon") { } +#if 0 SECTION("Simple rectangular polygon") { double lonmin = 0; double lonmax = 360; @@ -288,9 +293,10 @@ CASE("LonLatPolygon") { // Default behavior throws EXPECT_THROWS_AS(poly.contains({lonmid, 180. - latmid}), BadValue); - EXPECT(poly.contains({lonmid + 360., latmid}, true)); - EXPECT(poly.contains({lonmid, 180. - latmid}, true)); + EXPECT(poly.contains({lonmid + 360., latmid})); + EXPECT(poly.contains({lonmid, 180. - latmid})); } +#endif SECTION("Parallelogram") { @@ -350,6 +356,7 @@ CASE("LonLatPolygon") { } +#if 0 SECTION("Partitioning (includePoles=false)") { auto mid = [](double a, double b) { return (a + b) / 2.; }; @@ -407,6 +414,7 @@ CASE("LonLatPolygon") { EXPECT(counts[i + 9] == 1); } } +#endif } From c1ec6375f3f509e5fe9a8c09c6e21507a1fd9157 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 5 Apr 2024 15:09:18 +0100 Subject: [PATCH 563/737] eckit::geo::PointLonLat --- src/eckit/geo/PointLonLat.cc | 20 ++++--- src/eckit/geo/PointLonLat.h | 5 +- src/eckit/geo/polygon/LonLatPolygon.cc | 75 ++++++++++++++++---------- src/eckit/geo/polygon/LonLatPolygon.h | 25 ++++----- tests/geo/area_polygon.cc | 71 +++++++++++------------- tests/geo/figure_sphere.cc | 9 ++-- 6 files changed, 111 insertions(+), 94 deletions(-) diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index ea38e9304..3ca7f83c0 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -13,6 +13,8 @@ #include "eckit/geo/PointLonLat.h" #include +#include +#include #include "eckit/exception/Exceptions.h" #include "eckit/types/FloatCompare.h" @@ -21,14 +23,6 @@ namespace eckit::geo { -PointLonLat::PointLonLat(double lon, double lat) : - container_type{lon, lat} { - if (!(-90. <= lat && lat <= 90.)) { - throw BadValue("PointLonLat: invalid latitude"); - } -} - - double PointLonLat::normalise_angle_to_minimum(double a, double minimum) { auto modulo_360 = [](double a) { return a - 360. * std::floor(a / 360.); }; @@ -45,6 +39,16 @@ double PointLonLat::normalise_angle_to_maximum(double a, double maximum) { } +void PointLonLat::assert_latitude_range(const PointLonLat& P) { + if (!(-90. <= P.lat && P.lat <= 90.)) { + std::ostringstream oss; + oss.precision(std::numeric_limits::max_digits10); + oss << "Invalid latitude " << P.lat; + throw BadValue(oss.str(), Here()); + } +} + + PointLonLat PointLonLat::make(double lon, double lat, double lon_minimum, double eps) { lat = normalise_angle_to_minimum(lat, -90.); diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index 89be4e5aa..2357281c5 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -30,7 +30,8 @@ class PointLonLat final : protected std::array { public: // -- Constructors - PointLonLat(double lon, double lat); + PointLonLat(double lon, double lat) : + container_type{lon, lat} {} PointLonLat(const PointLonLat& other) : container_type(other) {} @@ -65,6 +66,8 @@ class PointLonLat final : protected std::array { static double normalise_angle_to_maximum(double, double maximum); + static void assert_latitude_range(const PointLonLat&); + static PointLonLat make(double lon, double lat, double lon_minimum = 0, double eps = EPS); PointLonLat antipode() const { return make(lon, lat + 180.); } diff --git a/src/eckit/geo/polygon/LonLatPolygon.cc b/src/eckit/geo/polygon/LonLatPolygon.cc index 8b970c62f..1203db2c8 100644 --- a/src/eckit/geo/polygon/LonLatPolygon.cc +++ b/src/eckit/geo/polygon/LonLatPolygon.cc @@ -10,11 +10,11 @@ #include "eckit/geo/polygon/LonLatPolygon.h" -#include +#include #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/CoordinateHelpers.h" +#include "eckit/geo/PointLonLat.h" #include "eckit/types/FloatCompare.h" //---------------------------------------------------------------------------------------------------------------------- @@ -33,28 +33,39 @@ inline bool is_approximately_greater_or_equal(double a, double b) { return a >= b || is_approximately_equal(a, b); } -inline double cross_product_analog(const PointLonLat& A, const PointLonLat& B, const PointLonLat& C) { - return (A.lon - C.lon) * (B.lat - C.lat) - (A.lat - C.lat) * (B.lon - C.lon); +inline double cross_product_analog(const Point2& A, const Point2& B, const Point2& C) { + return (A.X - C.X) * (B.Y - C.Y) - (A.Y - C.Y) * (B.X - C.X); } inline int on_direction(double a, double b, double c) { return a <= b && b <= c ? 1 : c <= b && b <= a ? -1 : 0; }; -inline int on_side(const PointLonLat& P, const PointLonLat& A, const PointLonLat& B) { +inline int on_side(const Point2& P, const Point2& A, const Point2& B) { const auto p = cross_product_analog(P, A, B); return is_approximately_equal(p, 0) ? 0 : p > 0 ? 1 : -1; } +constexpr int LON = 0; +constexpr int LAT = 1; + +inline Point2 componentsMin(const Point2& A, const Point2& B) { + return {std::min(A.X, B.X), std::min(A.Y, B.Y)}; +} + +inline Point2 componentsMax(const Point2& A, const Point2& B) { + return {std::max(A.X, B.X), std::max(A.Y, B.Y)}; +} + } // namespace //---------------------------------------------------------------------------------------------------------------------- -LonLatPolygon::LonLatPolygon(const container_type& points, bool includePoles) : - container_type(points), max_(points.front()), min_(points.front()) { +LonLatPolygon::LonLatPolygon(const std::vector& points, bool includePoles) : + container_type(points) { ASSERT(points.size() > 1); - ASSERT(is_approximately_equal(points.front().lon, points.back().lon) && - is_approximately_equal(points.front().lat, points.back().lat)); + ASSERT(is_approximately_equal(points.front()[LON], points.back()[LON]) && + is_approximately_equal(points.front()[LAT], points.back()[LAT])); if (points.size() > 2) { clear(); // assumes reserved size is kept @@ -78,16 +89,16 @@ LonLatPolygon::LonLatPolygon(const container_type& points, bool includePoles) : max_ = min_ = front(); for (const auto& p : *this) { - min_ = value_type::componentsMin(min_, p); - max_ = value_type::componentsMax(max_, p); + min_ = componentsMin(min_, p); + max_ = componentsMax(max_, p); } - includeNorthPole_ = includePoles && is_approximately_equal(max_.lat, 90); - includeSouthPole_ = includePoles && is_approximately_equal(min_.lat, -90); - ASSERT(is_approximately_greater_or_equal(min_.lat, -90)); - ASSERT(is_approximately_greater_or_equal(90, max_.lat)); + includeNorthPole_ = includePoles && is_approximately_equal(max_[LAT], 90.); + includeSouthPole_ = includePoles && is_approximately_equal(min_[LAT], -90.); + ASSERT(is_approximately_greater_or_equal(min_[LAT], -90.)); + ASSERT(is_approximately_greater_or_equal(90., max_[LAT])); - quickCheckLongitude_ = is_approximately_greater_or_equal(360, max_.lon - min_.lon); + quickCheckLongitude_ = is_approximately_greater_or_equal(360, max_[LON] - min_[LON]); } void LonLatPolygon::print(std::ostream& out) const { @@ -105,24 +116,34 @@ std::ostream& operator<<(std::ostream& out, const LonLatPolygon& pc) { return out; } -bool LonLatPolygon::contains(const PointLonLat& P) const { - auto Q = PointLonLat::make(P.lon, P.lat, min_.lon); +bool LonLatPolygon::contains(const Point2& Plonlat, bool normalise_angle) const { + if (!normalise_angle) { + if (const auto lat = Plonlat[LAT]; !(-90. <= lat && lat <= 90.)) { + std::ostringstream oss; + oss.precision(std::numeric_limits::max_digits10); + oss << "Invalid latitude " << lat; + throw BadValue(oss.str(), Here()); + } + } + + Point2 Q{PointLonLat::normalise_angle_to_minimum(Plonlat[LON], min_[LON]), Plonlat[LAT]}; // check poles - if (includeNorthPole_ && is_approximately_equal(Q.lat, 90.)) { + if (includeNorthPole_ && is_approximately_equal(Q[LAT], 90.)) { return true; } - if (includeSouthPole_ && is_approximately_equal(Q.lat, -90.)) { + if (includeSouthPole_ && is_approximately_equal(Q[LAT], -90.)) { return true; } // check bounding box - if (!is_approximately_greater_or_equal(Q.lat, min_.lat) || !is_approximately_greater_or_equal(max_.lat, Q.lat)) { + if (!is_approximately_greater_or_equal(Q[LAT], min_[LAT]) || + !is_approximately_greater_or_equal(max_[LAT], Q[LAT])) { return false; } if (quickCheckLongitude_) { - if (!is_approximately_greater_or_equal(Q.lon, min_.lon) || - !is_approximately_greater_or_equal(max_.lon, Q.lon)) { + if (!is_approximately_greater_or_equal(Q[LON], min_[LON]) || + !is_approximately_greater_or_equal(max_[LON], Q[LON])) { return false; } } @@ -141,10 +162,10 @@ bool LonLatPolygon::contains(const PointLonLat& P) const { // by: // - intersecting "up" on forward crossing & P above edge, or // - intersecting "down" on backward crossing & P below edge - const auto direction = on_direction(A.lat, Q.lat, B.lat); + const auto direction = on_direction(A[LAT], Q[LAT], B[LAT]); if (direction != 0) { const auto side = on_side(Q, A, B); - if (side == 0 && on_direction(A.lon, Q.lon, B.lon) != 0) { + if (side == 0 && on_direction(A[LON], Q[LON], B[LON]) != 0) { return true; } if ((prev != 1 && direction > 0 && side > 0) || (prev != -1 && direction < 0 && side < 0)) { @@ -159,8 +180,8 @@ bool LonLatPolygon::contains(const PointLonLat& P) const { return true; } - Q.lon += 360.; - } while (Q.lon <= max_.lon); + Q[LON] += 360.; + } while (Q[LON] <= max_[LON]); return false; } diff --git a/src/eckit/geo/polygon/LonLatPolygon.h b/src/eckit/geo/polygon/LonLatPolygon.h index 56f11cfc6..f82282f2d 100644 --- a/src/eckit/geo/polygon/LonLatPolygon.h +++ b/src/eckit/geo/polygon/LonLatPolygon.h @@ -13,7 +13,7 @@ #include #include -#include "eckit/geo/PointLonLat.h" +#include "eckit/geo/Point2.h" //---------------------------------------------------------------------------------------------------------------------- @@ -21,18 +21,18 @@ namespace eckit::geo::polygon { //---------------------------------------------------------------------------------------------------------------------- -class LonLatPolygon : protected std::vector { +class LonLatPolygon : protected std::vector { public: // -- Types - using container_type = std::vector; + using container_type = std::vector; using container_type::value_type; // -- Constructors explicit LonLatPolygon(const container_type& points, bool includePoles = true); - template - LonLatPolygon(Iterator begin, Iterator end, bool includePoles = true) : + template + LonLatPolygon(Point2Iterator begin, Point2Iterator end, bool includePoles = true) : LonLatPolygon(container_type(begin, end), includePoles) {} LonLatPolygon(const LonLatPolygon&) = default; @@ -49,17 +49,18 @@ class LonLatPolygon : protected std::vector { // -- Methods - const PointLonLat& max() const { return max_; } - const PointLonLat& min() const { return min_; } + const Point2& max() const { return max_; } + const Point2& min() const { return min_; } using container_type::operator[]; using container_type::size; /// @brief Point-in-polygon test based on winding number - /// @ref http://geomalgorithms.com/a03-_inclusion.html + /// @note reference Inclusion of a Point in a Polygon /// @param[in] P given point - /// @return if point is in polygon - bool contains(const PointLonLat& P) const; + /// @param[in] normalise_angle normalise point angles + /// @return if point (lon,lat) is in polygon + bool contains(const Point2& Plonlat, bool normalise_angle = false) const; private: // -- Methods @@ -69,8 +70,8 @@ class LonLatPolygon : protected std::vector { // -- Members - PointLonLat max_; - PointLonLat min_; + Point2 max_; + Point2 min_; bool includeNorthPole_; bool includeSouthPole_; bool quickCheckLongitude_; diff --git a/tests/geo/area_polygon.cc b/tests/geo/area_polygon.cc index 146c318f8..ad860ab26 100644 --- a/tests/geo/area_polygon.cc +++ b/tests/geo/area_polygon.cc @@ -13,6 +13,7 @@ #include #include "eckit/geo/Point2.h" +#include "eckit/geo/PointLonLat.h" #include "eckit/geo/polygon/LonLatPolygon.h" #include "eckit/geo/polygon/Polygon.h" #include "eckit/testing/Test.h" @@ -110,7 +111,6 @@ CASE("LonLatPolygon") { } -#if 0 SECTION("Contains North pole") { const std::vector points{{0, 90}, {0, 0}, {1, 0}, {1, 90}, {0, 90}}; @@ -126,10 +126,8 @@ CASE("LonLatPolygon") { EXPECT_NOT(poly2.contains({0, -90})); EXPECT_NOT(poly2.contains({10, -90})); } -#endif -#if 0 SECTION("Contains South pole") { const std::vector points{{0, -90}, {0, 0}, {1, 0}, {1, -90}, {0, -90}}; @@ -145,7 +143,6 @@ CASE("LonLatPolygon") { EXPECT(poly2.contains({0, -90})); EXPECT_NOT(poly2.contains({10, -90})); } -#endif SECTION("Contains South and North poles") { @@ -246,7 +243,6 @@ CASE("LonLatPolygon") { } -#if 0 SECTION("Simple rectangular polygon") { double lonmin = 0; double lonmax = 360; @@ -258,45 +254,42 @@ CASE("LonLatPolygon") { Polygon poly({{lonmin, latmax}, {lonmax, latmax}, {lonmax, latmin}, {lonmin, latmin}, {lonmin, latmax}}); - - SECTION("Contains edges") { - EXPECT(poly.contains({lonmin, latmax})); - EXPECT(poly.contains({lonmid, latmax})); - EXPECT(poly.contains({lonmax, latmax})); - EXPECT(poly.contains({lonmax, latmid})); - EXPECT(poly.contains({lonmax, latmin})); - EXPECT(poly.contains({lonmid, latmin})); - EXPECT(poly.contains({lonmin, latmin})); - EXPECT(poly.contains({lonmin, latmid})); - } - - - SECTION("Contains in/outward of edges") { - constexpr auto eps = 0.001; - - for (size_t i = 0; i <= 100; ++i) { - const auto lon = lonmin + static_cast(i) * (lonmax - lonmin) / 99.; - EXPECT(poly.contains({lon, latmin + eps})); - EXPECT(poly.contains({lon, latmax - eps})); - EXPECT_NOT(poly.contains({lon, latmin - eps})); - EXPECT_NOT(poly.contains({lon, latmax + eps})); - - const auto lat = latmin + static_cast(i) * (latmax - latmin) / 99.; - EXPECT(poly.contains({lonmin + eps, lat})); - EXPECT(poly.contains({lonmax - eps, lat})); - EXPECT_NOT(poly.contains({lonmin - eps, lat})); - EXPECT_NOT(poly.contains({lonmax + eps, lat})); - } + EXPECT(poly.contains({lonmin, latmax})); + EXPECT(poly.contains({lonmid, latmax})); + EXPECT(poly.contains({lonmax, latmax})); + EXPECT(poly.contains({lonmax, latmid})); + EXPECT(poly.contains({lonmax, latmin})); + EXPECT(poly.contains({lonmid, latmin})); + EXPECT(poly.contains({lonmin, latmin})); + EXPECT(poly.contains({lonmin, latmid})); + + // Test contains in/outward of edges + constexpr auto eps = 0.001; + + for (size_t i = 0; i <= 100; ++i) { + const auto lon = lonmin + static_cast(i) * (lonmax - lonmin) / 100.; + EXPECT(poly.contains({lon, latmin + eps})); + EXPECT(poly.contains({lon, latmax - eps})); + EXPECT_NOT(poly.contains({lon, latmin - eps})); + EXPECT_NOT(poly.contains({lon, latmax + eps})); + + const auto lat = latmin + static_cast(i) * (latmax - latmin) / 100.; + EXPECT(poly.contains({lonmin + eps, lat})); + EXPECT(poly.contains({lonmax - eps, lat})); + EXPECT(poly.contains({lonmin - eps, lat})); + EXPECT(poly.contains({lonmax + eps, lat})); } // Test points at non-canonical coordinates // Default behavior throws - EXPECT_THROWS_AS(poly.contains({lonmid, 180. - latmid}), BadValue); + EXPECT_THROWS_AS(poly.contains({lonmid, 91.}), BadValue); + + auto A = PointLonLat::make(lonmid + 360., latmid, lonmin); + EXPECT(poly.contains({A.lon, A.lat})); - EXPECT(poly.contains({lonmid + 360., latmid})); - EXPECT(poly.contains({lonmid, 180. - latmid})); + auto B = PointLonLat::make(lonmid, 180. - latmid, lonmin); + EXPECT(poly.contains({B.lon, B.lat})); } -#endif SECTION("Parallelogram") { @@ -356,7 +349,6 @@ CASE("LonLatPolygon") { } -#if 0 SECTION("Partitioning (includePoles=false)") { auto mid = [](double a, double b) { return (a + b) / 2.; }; @@ -414,7 +406,6 @@ CASE("LonLatPolygon") { EXPECT(counts[i + 9] == 1); } } -#endif } diff --git a/tests/geo/figure_sphere.cc b/tests/geo/figure_sphere.cc index 84d08d115..43057ff59 100644 --- a/tests/geo/figure_sphere.cc +++ b/tests/geo/figure_sphere.cc @@ -182,8 +182,7 @@ CASE("unit sphere") { SECTION("lat 100") { // Default behavior throws - EXPECT_THROWS_AS(PointLonLat(0., 100.), BadValue); - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({0., 100.}), BadValue); + EXPECT_THROWS_AS(PointLonLat::assert_latitude_range(PointLonLat(0., 100.)), BadValue); auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(0., 100.), 0.); auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(180., 80.), 0.); @@ -197,8 +196,7 @@ CASE("unit sphere") { SECTION("lat 290") { // Default behavior throws - EXPECT_THROWS_AS(PointLonLat(15., 290.), BadValue); - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({15., 290.}), BadValue); + EXPECT_THROWS_AS(PointLonLat::assert_latitude_range(PointLonLat(15., 290.)), BadValue); auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., 290.), 0.); auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(15., -70.), 0.); @@ -212,8 +210,7 @@ CASE("unit sphere") { SECTION("lat -120") { // Default behavior throws - EXPECT_THROWS_AS(PointLonLat(45., -120.), BadValue); - EXPECT_THROWS_AS(UnitSphere::convertSphericalToCartesian({45., -120.}), BadValue); + EXPECT_THROWS_AS(PointLonLat::assert_latitude_range(PointLonLat(45., -120.)), BadValue); auto p = UnitSphere::convertSphericalToCartesian(PointLonLat::make(45., -120.), 0.); auto q = UnitSphere::convertSphericalToCartesian(PointLonLat::make(225., -60.), 0.); From e812ce9f3aec406dc7c33f257d7a79e5220e788b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 5 Apr 2024 15:54:08 +0100 Subject: [PATCH 564/737] Refactor --- src/eckit/geo/CMakeLists.txt | 2 -- src/eckit/geo/CoordinateHelpers.cc | 55 ------------------------------ src/eckit/geo/CoordinateHelpers.h | 47 ------------------------- 3 files changed, 104 deletions(-) delete mode 100644 src/eckit/geo/CoordinateHelpers.cc delete mode 100644 src/eckit/geo/CoordinateHelpers.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index b4f6ffb26..0706d235b 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -11,8 +11,6 @@ list(APPEND eckit_geo_srcs Area.h Cache.cc Cache.h - CoordinateHelpers.cc - CoordinateHelpers.h Domain.cc Domain.h Earth.h diff --git a/src/eckit/geo/CoordinateHelpers.cc b/src/eckit/geo/CoordinateHelpers.cc deleted file mode 100644 index 3f6107702..000000000 --- a/src/eckit/geo/CoordinateHelpers.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (C) Copyright 2023 UCAR - * - * 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. - */ - -#include -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/CoordinateHelpers.h" -#include "eckit/geo/Point2.h" - -namespace eckit::geo { - -//---------------------------------------------------------------------------------------------------------------------- - -double normalise_angle(double a, const double minimum) { - while (a < minimum) { - a += 360.; - } - while (a >= minimum + 360.) { - a -= 360.; - } - return a; -} - -//---------------------------------------------------------------------------------------------------------------------- - -Point2 canonicaliseOnSphere(const Point2& lonlat, const double minimum_lon) { - const double lat = normalise_angle(lonlat[1], -90.); - const bool across_pole = (lat > 90.); - - if (!across_pole) { - return {normalise_angle(lonlat[0], minimum_lon), lat}; - } - - return {normalise_angle(lonlat[0] + 180., minimum_lon), 180. - lat}; -} - -//---------------------------------------------------------------------------------------------------------------------- - -void assert_latitude_range(double lat) { - if (!(-90. <= lat && lat <= 90.)) { - std::ostringstream oss; - oss.precision(std::numeric_limits::max_digits10); - oss << "Invalid latitude " << lat; - throw BadValue(oss.str(), Here()); - } -} - -//---------------------------------------------------------------------------------------------------------------------- - -} // namespace eckit::geo diff --git a/src/eckit/geo/CoordinateHelpers.h b/src/eckit/geo/CoordinateHelpers.h deleted file mode 100644 index 52358ffda..000000000 --- a/src/eckit/geo/CoordinateHelpers.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * (C) Copyright 2023 UCAR. - * - * 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. - */ - -#ifndef CoordinateHelpers_H -#define CoordinateHelpers_H - -namespace eckit::geo { - -class Point2; - -//---------------------------------------------------------------------------------------------------------------------- - -/// Shift angle in increments of 360° until it lies in [minimum, minimum+360°). -/// -/// Inputs angle and minimum are in degrees, returned angle is in degrees. -double normalise_angle(double angle, double minimum); - -//---------------------------------------------------------------------------------------------------------------------- - -/// Shift input point on sphere so its longitude lies in [minimum_lon, minimum_lon+360°) -/// and its latitude lies in [-90°, 90°]. -/// -/// Latitudes outside the canonical interval [-90°,90°] are first shifted into the interval -/// [-90°,270°], then any points with latitudes in [90°,270°] are flagged as "across the pole". -/// Such points are re-labeled with equivalent coordinates that lie within the canonical coordinate -/// patch by the transformation: (λ, ϕ) -> (λ+180°, 180°-ϕ). -/// -/// Finally, the longitude is shifted into [minimum_lon, minimum_lon+360°). -/// -/// Inputs lonlat and minimum_lon are in degrees, returned angles are in degrees. -Point2 canonicaliseOnSphere(const Point2& lonlat, double minimum_lon = 0.); - -//---------------------------------------------------------------------------------------------------------------------- - -/// Assert latitude lies in [-90°, 90°]. -void assert_latitude_range(double lat); - - -//---------------------------------------------------------------------------------------------------------------------- - -} // namespace eckit::geo - -#endif // CoordinateHelpers_H From 6f3393455975335d849b82b1a4409cc23c472738 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 5 Apr 2024 17:39:41 +0100 Subject: [PATCH 565/737] Refactor --- src/eckit/geo/EllipsoidOfRevolution.cc | 38 ++---- src/eckit/geo/EllipsoidOfRevolution.h | 13 +-- src/eckit/geo/Sphere.cc | 141 ++++++++++------------- src/eckit/geo/Sphere.h | 14 +-- src/eckit/geo/SphereT.h | 6 +- src/eckit/geo/polygon/LonLatPolygon.cc | 7 +- src/eckit/geo/util/gaussian_latitudes.cc | 3 +- tests/geo/grid_regular_gg.cc | 1 + 8 files changed, 86 insertions(+), 137 deletions(-) diff --git a/src/eckit/geo/EllipsoidOfRevolution.cc b/src/eckit/geo/EllipsoidOfRevolution.cc index 807f24198..eb82ef9d8 100644 --- a/src/eckit/geo/EllipsoidOfRevolution.cc +++ b/src/eckit/geo/EllipsoidOfRevolution.cc @@ -11,52 +11,36 @@ #include "eckit/geo/EllipsoidOfRevolution.h" #include -#include -#include #include "eckit/exception/Exceptions.h" #include "eckit/geo/Point3.h" #include "eckit/geo/PointLonLat.h" +#include "eckit/geo/util.h" -//---------------------------------------------------------------------------------------------------------------------- namespace eckit::geo { -//---------------------------------------------------------------------------------------------------------------------- -Point3 EllipsoidOfRevolution::convertSphericalToCartesian( - double a, double b, const PointLonLat& P, double height, bool normalise_angle) { +Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, double b, const PointLonLat& P, double height) { ASSERT(a > 0.); ASSERT(b > 0.); - if (!(-90. <= P.lat && P.lat <= 90.)) { - std::ostringstream oss; - oss.precision(std::numeric_limits::max_digits10); - oss << "Invalid latitude " << P.lat; - throw BadValue(oss.str(), Here()); - } - - static const double degrees_to_radians = M_PI / 180.; - // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) - const double lambda_deg = PointLonLat::normalise_angle_to_minimum(P.lon, -180.); - const double lambda = degrees_to_radians * lambda_deg; - const double phi = degrees_to_radians * P.lat; + const auto Q = PointLonLat::make(P.lon, P.lat, -180.); + const auto lambda = util::DEGREE_TO_RADIAN * Q.lon; + const auto phi = util::DEGREE_TO_RADIAN * Q.lat; - const double sin_phi = std::sin(phi); - const double cos_phi = std::sqrt(1. - sin_phi * sin_phi); - const double sin_lambda = std::abs(lambda_deg) < 180. ? std::sin(lambda) : 0.; - const double cos_lambda = std::abs(lambda_deg) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); + const auto sp = std::sin(phi); + const auto cp = std::sqrt(1. - sp * sp); + const auto sl = std::abs(Q.lon) < 180. ? std::sin(lambda) : 0.; + const auto cl = std::abs(Q.lon) > 90. ? std::cos(lambda) : std::sqrt(1. - sl * sl); - const double N_phi = a * a / std::sqrt(a * a * cos_phi * cos_phi + b * b * sin_phi * sin_phi); + const auto N_phi = a * a / std::sqrt(a * a * cp * cp + b * b * sp * sp); - return {(N_phi + height) * cos_phi * cos_lambda, - (N_phi + height) * cos_phi * sin_lambda, - (N_phi * (b * b) / (a * a) + height) * sin_phi}; + return {(N_phi + height) * cp * cl, (N_phi + height) * cp * sl, (N_phi * (b * b) / (a * a) + height) * sp}; } -//---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geo diff --git a/src/eckit/geo/EllipsoidOfRevolution.h b/src/eckit/geo/EllipsoidOfRevolution.h index e0290f4d3..c427d9723 100644 --- a/src/eckit/geo/EllipsoidOfRevolution.h +++ b/src/eckit/geo/EllipsoidOfRevolution.h @@ -8,28 +8,21 @@ * does it submit to any jurisdiction. */ -#ifndef EllipsoidOfRevolution_H -#define EllipsoidOfRevolution_H -//---------------------------------------------------------------------------------------------------------------------- +#pragma once + namespace eckit::geo { -//---------------------------------------------------------------------------------------------------------------------- class Point3; class PointLonLat; -//---------------------------------------------------------------------------------------------------------------------- struct EllipsoidOfRevolution { // Convert elliptic coordinates to Cartesian - static Point3 convertSphericalToCartesian( - double a, double b, const PointLonLat&, double height = 0., bool normalise_angle = false); + static Point3 convertSphericalToCartesian(double a, double b, const PointLonLat&, double height = 0.); }; -//---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geo - -#endif diff --git a/src/eckit/geo/Sphere.cc b/src/eckit/geo/Sphere.cc index 1961933d5..6ff38060f 100644 --- a/src/eckit/geo/Sphere.cc +++ b/src/eckit/geo/Sphere.cc @@ -13,45 +13,22 @@ #include #include #include -#include #include "eckit/exception/Exceptions.h" #include "eckit/geo/GreatCircle.h" #include "eckit/geo/Point3.h" #include "eckit/geo/PointLonLat.h" +#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" -//---------------------------------------------------------------------------------------------------------------------- namespace eckit::geo { -//---------------------------------------------------------------------------------------------------------------------- using types::is_approximately_equal; -static constexpr double radians_to_degrees = 180. * M_1_PI; - -static constexpr double degrees_to_radians = M_PI / 180.; - -void assert_latitude(double lat) { - if (!(-90. <= lat && lat <= 90.)) { - std::ostringstream oss; - oss.precision(std::numeric_limits::max_digits10); - oss << "Invalid latitude " << lat; - throw BadValue(oss.str(), Here()); - } -} - -inline double squared(double x) { - return x * x; -} - -//---------------------------------------------------------------------------------------------------------------------- - -double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { - assert_latitude(A.lat); - assert_latitude(B.lat); +double Sphere::centralAngle(const PointLonLat& P1, const PointLonLat& P2) { /* * Δσ = atan( ((cos(ϕ2) * sin(Δλ))^2 + (cos(ϕ1) * sin(ϕ2) - sin(ϕ1) * cos(ϕ2) * cos(Δλ))^2) / * (sin(ϕ1) * sin(ϕ2) + cos(ϕ1) * cos(ϕ2) * cos(Δλ)) ) @@ -68,20 +45,24 @@ double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { * } */ - const double phi1 = degrees_to_radians * A.lat; - const double phi2 = degrees_to_radians * B.lat; - const double lambda = degrees_to_radians * (B.lon - A.lon); + const auto Q1 = PointLonLat::make(P1.lon, P1.lat, -180.); + const auto Q2 = PointLonLat::make(P2.lon, P2.lat, -180.); + + const auto phi1 = util::DEGREE_TO_RADIAN * Q1.lat; + const auto phi2 = util::DEGREE_TO_RADIAN * Q2.lat; + const auto lambda = util::DEGREE_TO_RADIAN * PointLonLat::normalise_angle_to_minimum(Q1.lon - Q2.lon, -180.); - const double cos_phi1 = cos(phi1); - const double sin_phi1 = sin(phi1); - const double cos_phi2 = cos(phi2); - const double sin_phi2 = sin(phi2); - const double cos_lambda = cos(lambda); - const double sin_lambda = sin(lambda); + const auto cp1 = std::cos(phi1); + const auto sp1 = std::sin(phi1); + const auto cp2 = std::cos(phi2); + const auto sp2 = std::sin(phi2); + const auto cl = std::cos(lambda); + const auto sl = std::sin(lambda); - const double angle = std::atan2( - std::sqrt(squared(cos_phi2 * sin_lambda) + squared(cos_phi1 * sin_phi2 - sin_phi1 * cos_phi2 * cos_lambda)), - sin_phi1 * sin_phi2 + cos_phi1 * cos_phi2 * cos_lambda); + auto squared = [](double x) { return x * x; }; + + const auto angle = + std::atan2(std::sqrt(squared(cp2 * sl) + squared(cp1 * sp2 - sp1 * cp2 * cl)), sp1 * sp2 + cp1 * cp2 * cl); if (is_approximately_equal(angle, 0.)) { return 0.; @@ -91,76 +72,84 @@ double Sphere::centralAngle(const PointLonLat& A, const PointLonLat& B) { return angle; } -double Sphere::centralAngle(double radius, const Point3& A, const Point3& B) { + +double Sphere::centralAngle(double radius, const Point3& P1, const Point3& P2) { ASSERT(radius > 0.); // Δσ = 2 * asin( chord / 2 ) - const double d2 = Point3::distance2(A, B); + const auto d2 = Point3::distance2(P1, P2); if (is_approximately_equal(d2, 0.)) { return 0.; } - const double chord = std::sqrt(d2) / radius; - const double angle = std::asin(chord * 0.5) * 2.; + const auto chord = std::sqrt(d2) / radius; + const auto angle = std::asin(chord * 0.5) * 2.; return angle; } -double Sphere::distance(double radius, const PointLonLat& A, const PointLonLat& B) { - return radius * centralAngle(A, B); + +double Sphere::distance(double radius, const PointLonLat& P1, const PointLonLat& P2) { + return radius * centralAngle(P1, P2); } -double Sphere::distance(double radius, const Point3& A, const Point3& B) { - return radius * centralAngle(radius, A, B); + +double Sphere::distance(double radius, const Point3& P1, const Point3& P2) { + return radius * centralAngle(radius, P1, P2); } + double Sphere::area(double radius) { ASSERT(radius > 0.); return 4. * M_PI * radius * radius; } + double Sphere::area(double radius, const PointLonLat& WestNorth, const PointLonLat& EastSouth) { ASSERT(radius > 0.); - assert_latitude(WestNorth.lat); - assert_latitude(EastSouth.lat); + PointLonLat::assert_latitude_range(WestNorth); + PointLonLat::assert_latitude_range(EastSouth); // Set longitude fraction - double W = WestNorth.lon; - double E = PointLonLat::normalise_angle_to_minimum(EastSouth.lon, W); - double longitude_range( - is_approximately_equal(W, E) && !is_approximately_equal(EastSouth.lon, WestNorth.lon) ? 360. : E - W); + auto W = WestNorth.lon; + auto E = PointLonLat::normalise_angle_to_minimum(EastSouth.lon, W); + auto longitude_range(is_approximately_equal(W, E) && !is_approximately_equal(EastSouth.lon, WestNorth.lon) ? 360. + : E - W); ASSERT(longitude_range <= 360.); - double longitude_fraction = longitude_range / 360.; + auto longitude_fraction = longitude_range / 360.; // Set latitude fraction - double N = WestNorth.lat; - double S = EastSouth.lat; + auto N = WestNorth.lat; + auto S = EastSouth.lat; ASSERT(S <= N); - double latitude_fraction = 0.5 * (std::sin(degrees_to_radians * N) - std::sin(degrees_to_radians * S)); + auto latitude_fraction = 0.5 * (std::sin(util::DEGREE_TO_RADIAN * N) - std::sin(util::DEGREE_TO_RADIAN * S)); // Calculate area return area(radius) * latitude_fraction * longitude_fraction; } -double Sphere::greatCircleLatitudeGivenLongitude(const PointLonLat& A, const PointLonLat& B, double Clon) { - GreatCircle gc(A, B); + +double Sphere::greatCircleLatitudeGivenLongitude(const PointLonLat& P1, const PointLonLat& P2, double Clon) { + GreatCircle gc(P1, P2); auto lat = gc.latitude(Clon); return lat.size() == 1 ? lat[0] : std::numeric_limits::signaling_NaN(); } + void Sphere::greatCircleLongitudeGivenLatitude( - const PointLonLat& A, const PointLonLat& B, double Clat, double& Clon1, double& Clon2) { - GreatCircle gc(A, B); + const PointLonLat& P1, const PointLonLat& P2, double Clat, double& Clon1, double& Clon2) { + GreatCircle gc(P1, P2); auto lon = gc.longitude(Clat); Clon1 = lon.size() > 0 ? lon[0] : std::numeric_limits::signaling_NaN(); Clon2 = lon.size() > 1 ? lon[1] : std::numeric_limits::signaling_NaN(); } -Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, double height, bool normalise_angle) { + +Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& P, double height) { ASSERT(radius > 0.); /* @@ -176,36 +165,30 @@ Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& A, * poles and quadrants. */ - if (!normalise_angle) { - assert_latitude(A.lat); - } + const auto Q = PointLonLat::make(P.lon, P.lat, -180.); + const auto lambda = util::DEGREE_TO_RADIAN * Q.lon; + const auto phi = util::DEGREE_TO_RADIAN * Q.lat; - const auto P = PointLonLat::make(A.lon, A.lat, -180.); - const auto lambda = degrees_to_radians * P.lon; - const auto phi = degrees_to_radians * P.lat; + const auto sp = std::sin(phi); + const auto cp = std::sqrt(1. - sp * sp); + const auto sl = std::abs(Q.lon) < 180. ? std::sin(lambda) : 0.; + const auto cl = std::abs(Q.lon) > 90. ? std::cos(lambda) : std::sqrt(1. - sl * sl); - const auto sin_phi = std::sin(phi); - const auto cos_phi = std::sqrt(1. - sin_phi * sin_phi); - const auto sin_lambda = std::abs(P.lon) < 180. ? std::sin(lambda) : 0.; - const auto cos_lambda = std::abs(P.lon) > 90. ? std::cos(lambda) : std::sqrt(1. - sin_lambda * sin_lambda); - - return {(radius + height) * cos_phi * cos_lambda, - (radius + height) * cos_phi * sin_lambda, - (radius + height) * sin_phi}; + return {(radius + height) * cp * cl, (radius + height) * cp * sl, (radius + height) * sp}; } + PointLonLat Sphere::convertCartesianToSpherical(double radius, const Point3& A) { ASSERT(radius > 0.); // numerical conditioning for both z (poles) and y - const double x = A[0]; - const double y = is_approximately_equal(A[1], 0.) ? 0. : A[1]; - const double z = std::min(radius, std::max(-radius, A[2])) / radius; + const auto x = A[0]; + const auto y = is_approximately_equal(A[1], 0.) ? 0. : A[1]; + const auto z = std::min(radius, std::max(-radius, A[2])) / radius; - return {radians_to_degrees * std::atan2(y, x), radians_to_degrees * std::asin(z)}; + return {util::RADIAN_TO_DEGREE * std::atan2(y, x), util::RADIAN_TO_DEGREE * std::asin(z)}; } -//---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geo diff --git a/src/eckit/geo/Sphere.h b/src/eckit/geo/Sphere.h index e144a205b..048108668 100644 --- a/src/eckit/geo/Sphere.h +++ b/src/eckit/geo/Sphere.h @@ -8,18 +8,16 @@ * does it submit to any jurisdiction. */ + #pragma once -//---------------------------------------------------------------------------------------------------------------------- namespace eckit::geo { -//---------------------------------------------------------------------------------------------------------------------- class Point3; class PointLonLat; -//---------------------------------------------------------------------------------------------------------------------- struct Sphere { /// Great-circle central angle between two points in radians @@ -47,16 +45,12 @@ struct Sphere { static void greatCircleLongitudeGivenLatitude( const PointLonLat&, const PointLonLat&, double lat, double& lon1, double& lon2); - // Convert spherical to Cartesian coordinates - static Point3 convertSphericalToCartesian(double radius, - const PointLonLat&, - double height = 0., - bool normalise_angle = false); + /// Convert spherical to Cartesian coordinates + static Point3 convertSphericalToCartesian(double radius, const PointLonLat&, double height = 0.); - // Convert Cartesian to spherical coordinates + /// Convert Cartesian to spherical coordinates static PointLonLat convertCartesianToSpherical(double radius, const Point3&); }; -//---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geo diff --git a/src/eckit/geo/SphereT.h b/src/eckit/geo/SphereT.h index abb4f1cab..17d3ff74c 100644 --- a/src/eckit/geo/SphereT.h +++ b/src/eckit/geo/SphereT.h @@ -68,10 +68,8 @@ struct SphereT { } // Convert spherical to Cartesian coordinates - inline static Point3 convertSphericalToCartesian(const PointLonLat& P, - double height = 0., - bool normalise_angle = false) { - return Sphere::convertSphericalToCartesian(DATUM::radius(), P, height, normalise_angle); + inline static Point3 convertSphericalToCartesian(const PointLonLat& P, double height = 0.) { + return Sphere::convertSphericalToCartesian(DATUM::radius(), P, height); } // Convert Cartesian to spherical coordinates diff --git a/src/eckit/geo/polygon/LonLatPolygon.cc b/src/eckit/geo/polygon/LonLatPolygon.cc index 1203db2c8..102e326d9 100644 --- a/src/eckit/geo/polygon/LonLatPolygon.cc +++ b/src/eckit/geo/polygon/LonLatPolygon.cc @@ -118,12 +118,7 @@ std::ostream& operator<<(std::ostream& out, const LonLatPolygon& pc) { bool LonLatPolygon::contains(const Point2& Plonlat, bool normalise_angle) const { if (!normalise_angle) { - if (const auto lat = Plonlat[LAT]; !(-90. <= lat && lat <= 90.)) { - std::ostringstream oss; - oss.precision(std::numeric_limits::max_digits10); - oss << "Invalid latitude " << lat; - throw BadValue(oss.str(), Here()); - } + PointLonLat::assert_latitude_range({Plonlat[LON], Plonlat[LAT]}); } Point2 Q{PointLonLat::normalise_angle_to_minimum(Plonlat[LON], min_[LON]), Plonlat[LAT]}; diff --git a/src/eckit/geo/util/gaussian_latitudes.cc b/src/eckit/geo/util/gaussian_latitudes.cc index 84277f7d8..cebdfee0e 100644 --- a/src/eckit/geo/util/gaussian_latitudes.cc +++ b/src/eckit/geo/util/gaussian_latitudes.cc @@ -18,6 +18,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Cache.h" +#include "eckit/geo/util.h" namespace eckit::geo::util { @@ -99,7 +100,7 @@ const std::vector& gaussian_latitudes(size_t N, bool increasing) { // Convert colatitude [rad] to latitude [degree], symmetry const auto j = 2 * N - 1 - i; - lats[i] = (increasing ? (x - M_PI_2) : (M_PI_2 - x)) * 180. * M_1_PI; + lats[i] = (increasing ? (x - M_PI_2) : (M_PI_2 - x)) * RADIAN_TO_DEGREE; lats[j] = -lats[i]; } diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index 0efaac91c..85647d00d 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -66,6 +66,7 @@ CASE("RegularGaussian") { auto it = grid.begin(); for (size_t i = 0; i < points.size(); ++i) { + std::cout << ref[i] << '\n' < Date: Fri, 5 Apr 2024 23:14:15 +0100 Subject: [PATCH 566/737] eckit::geo testing --- tests/geo/grid_regular_gg.cc | 1 - tests/geo/search.cc | 49 ++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index 85647d00d..0efaac91c 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -66,7 +66,6 @@ CASE("RegularGaussian") { auto it = grid.begin(); for (size_t i = 0; i < points.size(); ++i) { - std::cout << ref[i] << '\n' < #include #include "eckit/geo/Search.h" @@ -20,39 +19,51 @@ namespace eckit::geo::test { -CASE("") { - std::vector points{ - {{0, 0, 0}, 0}, +CASE("Search2") { + std::vector points{ + {{0., 0.}, 0}, }; - Search3 search; + Search2 search; search.build(points); - std::cout << search.nearestNeighbour({0.1, 0, 0}) << std::endl; - std::cout << search.nearestNeighbour({0.9, 0, 0}) << std::endl; + auto a = search.nearestNeighbour({0.1, 0.}); + EXPECT_EQUAL(a.payload(), 0); + + auto b = search.nearestNeighbour({0.9, 0.}); + EXPECT_EQUAL(b.payload(), 0); + + search.insert({{1., 0.}, 1}); - search.insert({{1, 0, 0}, 1}); + auto c = search.nearestNeighbour({0.1, 0.}); + EXPECT_EQUAL(c.payload(), 0); - std::cout << search.nearestNeighbour({0.1, 0, 0}) << std::endl; - std::cout << search.nearestNeighbour({0.9, 0, 0}) << std::endl; + auto d = search.nearestNeighbour({0.9, 0.}); + EXPECT_EQUAL(d.payload(), 1); } -CASE("") { - std::vector points{ - {{0, 0}, 0}, +CASE("Search3") { + std::vector points{ + {{0., 0., 0.}, 0}, }; - Search2 search; + Search3 search; search.build(points); - std::cout << search.nearestNeighbour({0.1, 0}) << std::endl; - std::cout << search.nearestNeighbour({0.9, 0}) << std::endl; + auto a = search.nearestNeighbour({0.1, 0., 0.}); + EXPECT_EQUAL(a.payload(), 0); + + auto b = search.nearestNeighbour({0.9, 0., 0.}); + EXPECT_EQUAL(b.payload(), 0); + + search.insert({{1., 0., 0.}, 1}); - search.insert({{1, 0}, 1}); + auto c = search.nearestNeighbour({0.1, 0., 0.}); + EXPECT_EQUAL(c.payload(), 0); - std::cout << search.nearestNeighbour({0.1, 0}) << std::endl; - std::cout << search.nearestNeighbour({0.9, 0}) << std::endl; + auto d = search.nearestNeighbour({0.9, 0., 0.}); + EXPECT_EQUAL(d.payload(), 1); } From c25da019775a0bc0ed846a24eccdef7c533a2710 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 6 Apr 2024 00:48:09 +0100 Subject: [PATCH 567/737] eckit::geo::Range --- src/eckit/geo/Range.h | 2 + src/eckit/geo/range/Regular.h | 5 +- src/eckit/geo/range/RegularLongitude.cc | 14 ++- src/eckit/geo/range/RegularLongitude.h | 2 + tests/geo/range.cc | 113 +++++++++++++----------- 5 files changed, 78 insertions(+), 58 deletions(-) diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index f6a16569b..844ef97b8 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -41,6 +41,8 @@ class Range { double b() const { return b_; } double eps() const { return eps_; } + virtual bool periodic() const { return false; } + virtual Range* flip() const = 0; virtual Range* crop(double crop_a, double crop_b) const = 0; virtual const std::vector& values() const = 0; diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h index 0a0ebc2ca..6ded7488e 100644 --- a/src/eckit/geo/range/Regular.h +++ b/src/eckit/geo/range/Regular.h @@ -28,7 +28,6 @@ class Regular : public Range { // -- Methods Fraction increment() const; - bool periodic() const { return periodic_; } // -- Overridden methods @@ -48,7 +47,9 @@ class Regular : public Range { // -- Methods static Fraction adjust(const Fraction& target, const Fraction& inc, bool up); - void periodic(bool p) { periodic_ = p; } + + void setPeriodic(bool p) { periodic_ = p; } + bool getPeriodic() const { return periodic_; } private: // -- Members diff --git a/src/eckit/geo/range/RegularLongitude.cc b/src/eckit/geo/range/RegularLongitude.cc index 56f237a27..171412b90 100644 --- a/src/eckit/geo/range/RegularLongitude.cc +++ b/src/eckit/geo/range/RegularLongitude.cc @@ -34,10 +34,16 @@ RegularLongitude::RegularLongitude(double _inc, double _a, double _b, double _re const Fraction inc(_inc); auto n = 1 + (std::min(Fraction(b() - a()), PERIOD) / inc).integralPart(); - periodic(n * inc >= PERIOD); + setPeriodic(n * inc >= PERIOD); - b(Fraction(a()) + (n - 1) * inc); - resize(periodic() ? (PERIOD / inc).integralPart() : n); + if (periodic()) { + b(a() + PERIOD); + resize((PERIOD / inc).integralPart()); + } + else { + b(Fraction(a()) + (n - 1) * inc); + resize(n); + } } @@ -57,7 +63,7 @@ Range* RegularLongitude::crop(double crop_a, double crop_b) const { RegularLongitude crop(inc, crop_a, crop_b, a(), eps()); if (crop.periodic()) { - auto _a = PointLonLat::normalise_angle_to_minimum(crop_a, crop.a()); + auto _a = std::max(a(), PointLonLat::normalise_angle_to_minimum(crop_a, crop.a())); auto _b = PointLonLat::normalise_angle_to_minimum(crop_b, _a); return new RegularLongitude(inc, _a, _b, a(), eps()); } diff --git a/src/eckit/geo/range/RegularLongitude.h b/src/eckit/geo/range/RegularLongitude.h index e01921996..2bf97b079 100644 --- a/src/eckit/geo/range/RegularLongitude.h +++ b/src/eckit/geo/range/RegularLongitude.h @@ -35,6 +35,8 @@ class RegularLongitude final : public Regular { Range* crop(double crop_a, double crop_b) const override; Range* flip() const override; + bool periodic() const override { return getPeriodic(); } + private: // -- Constructors diff --git a/tests/geo/range.cc b/tests/geo/range.cc index cdbcefb8c..c01ee55c5 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -21,15 +21,13 @@ #include "eckit/types/Fraction.h" -#define EXPECT_APPROX(a, b, eps) EXPECT(::eckit::types::is_approximately_equal((a), (b), (eps))) +#define EXPECT_APPROX(a, b) EXPECT(::eckit::types::is_approximately_equal((a), (b), 1e-3)) namespace eckit::geo::test { -constexpr auto EPS = 1e-3; - - +#if 0 std::ostream& operator<<(std::ostream& out, const std::vector& v) { const char* sep = ""; for (const auto& e : v) { @@ -38,6 +36,7 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) { } return out; } +#endif CASE("range::RegularLongitude") { @@ -46,16 +45,16 @@ CASE("range::RegularLongitude") { EXPECT(range1.size() == 4); - EXPECT_APPROX(range1.a(), -1., EPS); - EXPECT_APPROX(range1.b(), 2., EPS); - EXPECT_APPROX(range1.increment(), 1., EPS); + EXPECT_APPROX(range1.a(), -1.); + EXPECT_APPROX(range1.b(), 2.); + EXPECT_APPROX(range1.increment(), 1.); const auto& values = range1.values(); - EXPECT_APPROX(values[0], -1., EPS); - EXPECT_APPROX(values[1], 0., EPS); - EXPECT_APPROX(values[2], 1., EPS); - EXPECT_APPROX(values[3], 2., EPS); + EXPECT_APPROX(values[0], -1.); + EXPECT_APPROX(values[1], 0.); + EXPECT_APPROX(values[2], 1.); + EXPECT_APPROX(values[3], 2.); for (const auto& range : { range::RegularLongitude(1., 0., 360.), @@ -93,9 +92,9 @@ CASE("range::RegularLongitude") { EXPECT(range.size() == values.size()); - EXPECT_APPROX(values[0], -90., EPS); - EXPECT_APPROX(values[1], 0., EPS); - EXPECT_APPROX(values[2], 90., EPS); + EXPECT_APPROX(values[0], -90.); + EXPECT_APPROX(values[1], 0.); + EXPECT_APPROX(values[2], 90.); } @@ -108,10 +107,10 @@ CASE("range::RegularLongitude") { EXPECT(range1.size() == values1.size()); - EXPECT_APPROX(values1[0], -180., EPS); - EXPECT_APPROX(values1[1], -90., EPS); - EXPECT_APPROX(values1[2], 0., EPS); - EXPECT_APPROX(values1[3], 90., EPS); + EXPECT_APPROX(values1[0], -180.); + EXPECT_APPROX(values1[1], -90.); + EXPECT_APPROX(values1[2], 0.); + EXPECT_APPROX(values1[3], 90.); const range::RegularLongitude range2(static_cast(8), 180., -180.); @@ -121,62 +120,72 @@ CASE("range::RegularLongitude") { EXPECT(range2.size() == values2.size()); - EXPECT_APPROX(values2[0], 180., EPS); - EXPECT_APPROX(values2[1], 135., EPS); - EXPECT_APPROX(values2[2], 90., EPS); - EXPECT_APPROX(values2[3], 45., EPS); - EXPECT_APPROX(values2[7], -135., EPS); + EXPECT_APPROX(values2[0], 180.); + EXPECT_APPROX(values2[1], 135.); + EXPECT_APPROX(values2[2], 90.); + EXPECT_APPROX(values2[3], 45.); + EXPECT_APPROX(values2[7], -135.); } SECTION("range [0, 360], cropped") { auto range = range::RegularLongitude(static_cast(36), 0., 360.); - // const std::unique_ptr range1(range.crop(-180., 180.)); - // std::cout << range1->values() << std::endl; - // EXPECT(range1->size() == 36); - // EXPECT(range1->a() == -180.); - // EXPECT(range1->b() == 180.); + EXPECT(range.periodic()); + + const std::unique_ptr range1(range.crop(-180., 180.)); - // const std::unique_ptr range2(range.crop(-180., 170.)); + EXPECT(range1->size() == 36); + EXPECT(range1->a() == -180.); + EXPECT(range1->b() == 180.); + EXPECT(range1->periodic()); - // EXPECT(range2->size() == 36); - // EXPECT(range2->b() == 180.); + const std::unique_ptr range2(range.crop(-180., 170.)); - // const std::unique_ptr range3(range.crop(-180., 160.)); + EXPECT(range2->size() == 36); + EXPECT(range2->b() == 180.); // because it's how we can distinguish without additional metadata + EXPECT(range2->periodic()); - // EXPECT(range3->size() == 36 - 1); - // EXPECT(range3->b() == 160.); + const std::unique_ptr range3(range.crop(-180., 160.)); + + EXPECT(range3->size() == 36 - 1); + EXPECT(range3->b() == 160.); + EXPECT_NOT(range3->periodic()); } SECTION("range [0, 180], cropped") { auto range = range::RegularLongitude(static_cast(19), 0., 180.); + + EXPECT_NOT(range.periodic()); + const std::unique_ptr range1(range.crop(1., 179.)); EXPECT(range1->size() == 19 - 2); EXPECT(range1->a() == 10.); EXPECT(range1->b() == 170.); + EXPECT_NOT(range1->periodic()); const std::unique_ptr range2(range.crop(1., 170.)); EXPECT(range2->size() == 19 - 2); EXPECT(range2->a() == 10.); EXPECT(range2->b() == 170.); + EXPECT_NOT(range2->periodic()); - // const std::unique_ptr range3(range.crop(-180., 180.)); + const std::unique_ptr range3(range.crop(-180., 180.)); - // std::cout << range3->values() << std::endl; - // EXPECT(range3->size() == 19); - // EXPECT(range3->a() == 0.); - // EXPECT(range3->b() == 180.); + EXPECT(range3->size() == 19); + EXPECT(range3->a() == 0.); + EXPECT(range3->b() == 180.); + EXPECT_NOT(range3->periodic()); - // const std::unique_ptr range4(range.crop(-190., 170.)); + const std::unique_ptr range4(range.crop(-190., 170.)); - // std::cout << range4->values() << std::endl; - // EXPECT(range4->size() == 2); - // EXPECT(range4->a() == -190.); - // EXPECT(range4->b() == -180.); + EXPECT(range4->size() == 19 - 1); + EXPECT(range4->a() == 0.); + EXPECT(range4->b() == 170.); + EXPECT_NOT(range4->periodic()); } } @@ -202,7 +211,7 @@ CASE("range::Gaussian") { size_t i = 0; for (const auto& test : global.values()) { - EXPECT_APPROX(test, ref[i++], 1e-12); + EXPECT_APPROX(test, ref[i++]); } } @@ -211,26 +220,26 @@ CASE("range::Gaussian") { std::unique_ptr cropped(range::GaussianLatitude(2, false).crop(50., -50.)); EXPECT(cropped->size() == ref.size() - 2); - EXPECT_APPROX(cropped->values()[0], ref[1], EPS); - EXPECT_APPROX(cropped->values()[1], ref[2], EPS); + EXPECT_APPROX(cropped->values()[0], ref[1]); + EXPECT_APPROX(cropped->values()[1], ref[2]); EXPECT(std::unique_ptr(range::GaussianLatitude(2, false, 1e-3).crop(59.444, -59.444))->size() == 4); EXPECT(std::unique_ptr(range::GaussianLatitude(2, false, 1e-6).crop(59.444, -59.444))->size() == 2); EXPECT(std::unique_ptr(range::GaussianLatitude(2, false, 1e-6).crop(59.444, -59.445))->size() == 3); - std::unique_ptr single(range::GaussianLatitude(2, false, EPS).crop(-59.444, -59.444)); + std::unique_ptr single(range::GaussianLatitude(2, false, 1e-3).crop(-59.444, -59.444)); EXPECT(single->size() == 1); - EXPECT_APPROX(single->values().front(), ref.back(), EPS); + EXPECT_APPROX(single->values().front(), ref.back()); } SECTION("crop [90., 0.]") { - std::unique_ptr cropped(range::GaussianLatitude(2, false, EPS).crop(90., 0.)); + std::unique_ptr cropped(range::GaussianLatitude(2, false, 1e-3).crop(90., 0.)); EXPECT(cropped->size() == ref.size() / 2); - EXPECT_APPROX(cropped->values()[0], ref[0], EPS); - EXPECT_APPROX(cropped->values()[1], ref[1], EPS); + EXPECT_APPROX(cropped->values()[0], ref[0]); + EXPECT_APPROX(cropped->values()[1], ref[1]); } } From ef0fa5e01ad1d3da9e66bb256911c2957e11df77 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 6 Apr 2024 00:55:34 +0100 Subject: [PATCH 568/737] eckit::geo::Spec --- tests/geo/spec.cc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 804dfd58a..553497f8d 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -347,6 +347,17 @@ CASE("spec") { EXPECT(unknown_pl->spec() == R"({"grid":"N4","pl":[20,24,28,32,32,28,24,99]})"); } + + + SECTION("grid: HEALPix") { + std::unique_ptr h2(GridFactory::build(spec::Custom({{"grid", "h2"}}))); + + EXPECT(h2->spec() == R"({"grid":"H2"})"); + + std::unique_ptr h2n(GridFactory::build(spec::Custom({{"grid", "H2"}, {"ordering", "nested"}}))); + + EXPECT(h2n->spec() == R"({"grid":"H2","ordering":"nested"})"); + } } From 4ccf6f47308dd46978e914134f8fbb9cae7a98ab Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 6 Apr 2024 01:38:21 +0100 Subject: [PATCH 569/737] eckit::geo testing --- src/eckit/geo/grid/unstructured/ORCA.cc | 3 +-- src/eckit/geo/spec/Generator.h | 8 +++++--- tests/geo/grid.cc | 2 +- tests/geo/spec.cc | 12 ++++++++++++ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index 0d6e53fc1..5e81f7c6e 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -287,8 +287,7 @@ Spec* ORCA::spec(const std::string& name) { void ORCA::spec(spec::Custom& custom) const { - custom.set("type", "ORCA"); - custom.set("uid", uid_); + custom.set("grid", uid_); } diff --git a/src/eckit/geo/spec/Generator.h b/src/eckit/geo/spec/Generator.h index b48d0039c..038c8a389 100644 --- a/src/eckit/geo/spec/Generator.h +++ b/src/eckit/geo/spec/Generator.h @@ -17,11 +17,11 @@ #include #include #include +#include #include #include "eckit/exception/Exceptions.h" #include "eckit/geo/util/mutex.h" -#include "eckit/utils/Regex.h" namespace eckit::geo { @@ -140,7 +140,9 @@ bool GeneratorT::exists(const key_t& k) const { template bool GeneratorT::matches(const std::string& k) const { lock_type lock; - return std::any_of(store_.begin(), store_.end(), [&](const auto& p) { return Regex(p.first).match(k); }); + return std::any_of(store_.begin(), store_.end(), [&](const auto& p) -> bool { + return std::regex_match(k, std::regex(p.first)); + }); } template @@ -179,7 +181,7 @@ const typename GeneratorT::generator_t& GeneratorT::match(const std::strin auto end = store_.cend(); auto i = end; for (auto j = store_.cbegin(); j != end; ++j) { - if (Regex(j->first).match(k)) { + if (std::regex_match(k, std::regex(j->first))) { if (i != end) { throw SeriousBug("Generator name '" + k + "' matches '" + i->first + "' and '" + j->first + "'"); } diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index e7cc5effd..7aeebe283 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -42,7 +42,7 @@ CASE("GridFactory::build") { if (LibEcKitGeo::caching()) { SECTION("Grid::build_from_uid") { spec::Custom spec({ - {"uid", "a832a12030c73928133553ec3a8d2a7e"}, + {"uid", "d5bde4f52ff3a9bea5629cd9ac514410"}, }); const auto footprint = Cache::total_footprint(); diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 553497f8d..c3952d20f 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -358,6 +358,18 @@ CASE("spec") { EXPECT(h2n->spec() == R"({"grid":"H2","ordering":"nested"})"); } + + + SECTION("grid: ORCA") { + std::unique_ptr o1(GridFactory::build(spec::Custom({{"grid", "ORCA2_T"}}))); + + EXPECT(o1->spec() == R"({"grid":"d5bde4f52ff3a9bea5629cd9ac514410"})"); + + std::unique_ptr o2( + GridFactory::build(spec::Custom({{"grid", "d5bde4f52ff3a9bea5629cd9ac514410"}}))); + + EXPECT(o1->spec() == o2->spec()); + } } From 000542999f0e6d66009bef112af71b93113d96be Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 6 Apr 2024 01:54:42 +0100 Subject: [PATCH 570/737] Revert a couple of files --- .clang-format | 172 +++++--------------------------------- src/eckit/runtime/Tool.cc | 14 +++- 2 files changed, 34 insertions(+), 152 deletions(-) diff --git a/.clang-format b/.clang-format index cf6d896d8..837ba8a32 100644 --- a/.clang-format +++ b/.clang-format @@ -2,66 +2,27 @@ Language: Cpp AccessModifierOffset: -4 AlignAfterOpenBracket: Align -AlignArrayOfStructures: None -AlignConsecutiveAssignments: - Enabled: true - AcrossEmptyLines: false - AcrossComments: false - AlignCompound: false - PadOperators: true -AlignConsecutiveBitFields: - Enabled: false - AcrossEmptyLines: false - AcrossComments: false - AlignCompound: false - PadOperators: false -AlignConsecutiveDeclarations: - Enabled: false - AcrossEmptyLines: false - AcrossComments: false - AlignCompound: false - PadOperators: true -AlignConsecutiveMacros: - Enabled: false - AcrossEmptyLines: false - AcrossComments: false - AlignCompound: false - PadOperators: false -AlignConsecutiveShortCaseStatements: - Enabled: false - AcrossEmptyLines: false - AcrossComments: false - AlignCaseColons: false +AlignConsecutiveAssignments: true +AlignConsecutiveDeclarations: false AlignEscapedNewlines: Left -AlignOperands: Align -AlignTrailingComments: - Kind: Always - OverEmptyLines: 0 -AllowAllArgumentsOnNextLine: false +AlignOperands: true +AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true -AllowBreakBeforeNoexceptSpecifier: Never -AllowShortBlocksOnASingleLine: Always +AllowShortBlocksOnASingleLine: true AllowShortCaseLabelsOnASingleLine: false -AllowShortEnumsOnASingleLine: true AllowShortFunctionsOnASingleLine: Inline -AllowShortIfStatementsOnASingleLine: Never -AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true -AlwaysBreakTemplateDeclarations: Yes -AttributeMacros: - - __capability -BinPackArguments: false -BinPackParameters: false -BitFieldColonSpacing: Both +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true BraceWrapping: - AfterCaseLabel: false AfterClass: false - AfterControlStatement: Never + AfterControlStatement: false AfterEnum: true - AfterExternBlock: false AfterFunction: false AfterNamespace: false AfterObjCDeclaration: false @@ -69,168 +30,77 @@ BraceWrapping: AfterUnion: false BeforeCatch: true BeforeElse: true - BeforeLambdaBody: false - BeforeWhile: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true -BreakAfterAttributes: Never -BreakAfterJavaFieldAnnotations: false -BreakArrays: true -BreakBeforeBinaryOperators: None -BreakBeforeConceptDeclarations: Always +BreakBeforeBinaryOperators: All BreakBeforeBraces: Custom -BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeInheritanceComma: false BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: AfterColon -BreakInheritanceList: BeforeColon +BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true ColumnLimit: 120 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true DerivePointerAlignment: false DisableFormat: false -EmptyLineAfterAccessModifier: Never -EmptyLineBeforeAccessModifier: LogicalBlock ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true ForEachMacros: - foreach - Q_FOREACH - BOOST_FOREACH -IfMacros: - - KJ_IF_MAYBE -IncludeBlocks: Preserve IncludeCategories: - Regex: '^<.*\.h>' Priority: 1 - SortPriority: 0 - CaseSensitive: false - Regex: '^<.*' Priority: 2 - SortPriority: 0 - CaseSensitive: false - Regex: '.*' Priority: 3 - SortPriority: 0 - CaseSensitive: false IncludeIsMainRegex: '([-_](test|unittest))?$' -IncludeIsMainSourceRegex: '' -IndentAccessModifiers: false -IndentCaseBlocks: false IndentCaseLabels: true -IndentExternBlock: AfterExternBlock -IndentGotoLabels: true -IndentPPDirectives: None -IndentRequiresClause: true IndentWidth: 4 IndentWrappedFunctionNames: false -InsertBraces: false -InsertNewlineAtEOF: false -InsertTrailingCommas: None -IntegerLiteralSeparator: - Binary: 0 - BinaryMinDigits: 0 - Decimal: 0 - DecimalMinDigits: 0 - Hex: 0 - HexMinDigits: 0 JavaScriptQuotes: Leave JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: true -KeepEmptyLinesAtEOF: false -LambdaBodyIndentation: Signature -LineEnding: DeriveLF MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 2 NamespaceIndentation: None -ObjCBinPackProtocolList: Auto ObjCBlockIndentWidth: 2 -ObjCBreakBeforeNestedBlockParam: true ObjCSpaceAfterProperty: false ObjCSpaceBeforeProtocolList: false -PackConstructorInitializers: NextLineOnly PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 300 PenaltyBreakFirstLessLess: 120 -PenaltyBreakOpenParenthesis: 0 PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 -PenaltyIndentedWhitespace: 0 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Left -PPIndentWidth: -1 -QualifierAlignment: Leave -ReferenceAlignment: Pointer ReflowComments: true -RemoveBracesLLVM: false -RemoveParentheses: Leave -RemoveSemicolon: false -RequiresClausePosition: OwnLine -RequiresExpressionIndentation: OuterScope -SeparateDefinitionBlocks: Leave -ShortNamespaceLines: 1 -SortIncludes: CaseSensitive -SortJavaStaticImport: Before -SortUsingDeclarations: LexicographicNumeric +SortIncludes: true +SortUsingDeclarations: true SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false SpaceAfterTemplateKeyword: true -SpaceAroundPointerQualifiers: Default SpaceBeforeAssignmentOperators: true -SpaceBeforeCaseColon: false -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeJsonColon: false SpaceBeforeParens: ControlStatements -SpaceBeforeParensOptions: - AfterControlStatements: true - AfterForeachMacros: true - AfterFunctionDefinitionName: false - AfterFunctionDeclarationName: false - AfterIfMacros: true - AfterOverloadedOperator: false - AfterRequiresInClause: false - AfterRequiresInExpression: false - BeforeNonEmptyParentheses: false -SpaceBeforeRangeBasedForLoopColon: true -SpaceBeforeSquareBrackets: false -SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 -SpacesInAngles: Never +SpacesInAngles: false SpacesInContainerLiterals: true -SpacesInLineCommentPrefix: - Minimum: 1 - Maximum: -1 -SpacesInParens: Never -SpacesInParensOptions: - InCStyleCasts: false - InConditionalStatements: false - InEmptyParentheses: false - Other: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Auto -StatementAttributeLikeMacros: - - Q_EMIT -StatementMacros: - - Q_UNUSED - - QT_REQUIRE_VERSION TabWidth: 4 UseTab: Never -VerilogBreakBetweenInstancePorts: true -WhitespaceSensitiveMacros: - - BOOST_PP_STRINGIZE - - CF_SWIFT_NAME - - NS_SWIFT_NAME - - PP_STRINGIZE - - STRINGIZE ... - diff --git a/src/eckit/runtime/Tool.cc b/src/eckit/runtime/Tool.cc index 0a45742ea..2774dc733 100644 --- a/src/eckit/runtime/Tool.cc +++ b/src/eckit/runtime/Tool.cc @@ -24,7 +24,19 @@ Tool::~Tool() {} int Tool::start() { int status = 0; - run(); + try { + run(); + } + catch (Exception& e) { + status = 1; + Log::error() << "** " << e.what() << " Caught in " << Here() << std::endl; + Log::error() << "** Exception terminates " << name() << std::endl; + } + catch (std::exception& e) { + status = 1; + Log::error() << "** " << e.what() << " Caught in " << Here() << std::endl; + Log::error() << "** Exception terminates " << name() << std::endl; + } return status; } From f49dc5709879b6a48bb908a73b0775d2016192c0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 6 Apr 2024 02:14:07 +0100 Subject: [PATCH 571/737] Revert a file --- tests/types/test_floatcompare.cc | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/tests/types/test_floatcompare.cc b/tests/types/test_floatcompare.cc index 60dab9bde..be63c9716 100644 --- a/tests/types/test_floatcompare.cc +++ b/tests/types/test_floatcompare.cc @@ -26,10 +26,14 @@ bool is_equal(float a, float b, float epsilon, int maxUlps) { return eckit::types::is_approximately_equal(a, b, epsilon, maxUlps); } -bool is_equal(float a, float b, float epsilon = 0.00001F) { +bool is_equal(float a, float b, float epsilon) { return eckit::types::is_approximately_equal(a, b, epsilon); } +bool is_equal(float a, float b) { + return eckit::types::is_approximately_equal(a, b, 0.00001f); +} + const float dEps = std::numeric_limits::epsilon(); const float dInf = std::numeric_limits::infinity(); const float sMin = std::numeric_limits::denorm_min(); @@ -42,30 +46,6 @@ const float sNaN = std::numeric_limits::signaling_NaN(); //---------------------------------------------------------------------------------------------------------------------- -CASE("test_epsilon_zero") { - Log::info() << "test_tolerance_limit" << std::endl; - - { - constexpr auto eps = std::numeric_limits::epsilon(); - EXPECT_EQUAL(1., 1.); // sanity check - EXPECT(types::is_approximately_equal(1., 1., 0.)); - EXPECT_NOT(types::is_approximately_equal(1., 1. + eps, 0.)); - EXPECT_NOT(types::is_approximately_equal(1., 1.1 + eps, 0.1)); - EXPECT(types::is_approximately_equal(1., 1.1, 0.1 + eps)); - } - - { - // constexpr auto eps = std::numeric_limits::epsilon(); - // EXPECT_EQUAL(1.F, 1.F); // sanity check - // EXPECT(types::is_approximately_equal(1.F, 1.F, 0.F)); - // EXPECT(types::is_approximately_equal(1.F, 1.1F, 0.1F)); - // EXPECT_NOT(types::is_approximately_equal(1.F, 1.F + eps, 0.F)); - } -} - -//---------------------------------------------------------------------------------------------------------------------- - -#if 0 CASE("test_large_numbers") { Log::info() << "test_large_numbers" << std::endl; @@ -337,7 +317,6 @@ CASE("test_comparisons_ulps") { EXPECT(!is_equal(-dMin, 0, 0, 0)); EXPECT(!is_equal(0, -dMin, 0, 0)); } -#endif //---------------------------------------------------------------------------------------------------------------------- From 2a78261ef488f731a38eca28ce5b510f8db86f4f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 8 Apr 2024 01:00:39 +0100 Subject: [PATCH 572/737] eckit::geo::Grid --- src/eckit/geo/Iterator.h | 2 +- src/eckit/geo/iterator/Reduced.cc | 1 - src/eckit/geo/iterator/Regular.cc | 1 - src/eckit/geo/iterator/Unstructured.cc | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index e34f76799..fd5a43b75 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -79,7 +79,7 @@ class Iterator { protected: // -- Constructors - explicit Iterator(const Grid&) {} + Iterator() = default; // -- Members // None diff --git a/src/eckit/geo/iterator/Reduced.cc b/src/eckit/geo/iterator/Reduced.cc index 4485b8bdd..067cd8fba 100644 --- a/src/eckit/geo/iterator/Reduced.cc +++ b/src/eckit/geo/iterator/Reduced.cc @@ -23,7 +23,6 @@ namespace eckit::geo::iterator { Reduced::Reduced(const Grid& grid, size_t index) : - geo::Iterator(grid), grid_(dynamic_cast(grid)), latitudes_(grid_.latitudes()), niacc_(grid_.niacc()), diff --git a/src/eckit/geo/iterator/Regular.cc b/src/eckit/geo/iterator/Regular.cc index 691d6290c..53616aeca 100644 --- a/src/eckit/geo/iterator/Regular.cc +++ b/src/eckit/geo/iterator/Regular.cc @@ -20,7 +20,6 @@ namespace eckit::geo::iterator { Regular::Regular(const Grid& grid, size_t index) : - geo::Iterator(grid), grid_(dynamic_cast(grid)), longitudes_(grid_.longitudes()), latitudes_(grid_.latitudes()), diff --git a/src/eckit/geo/iterator/Unstructured.cc b/src/eckit/geo/iterator/Unstructured.cc index 27ad5cb60..304f12c28 100644 --- a/src/eckit/geo/iterator/Unstructured.cc +++ b/src/eckit/geo/iterator/Unstructured.cc @@ -20,7 +20,6 @@ namespace eckit::geo::iterator { Unstructured::Unstructured(const Grid& grid, size_t index) : - geo::Iterator(grid), index_(index), index_size_(grid.size()), longitudes_(dynamic_cast(grid).longitudes()), From 01df3e9659bebe11dc3ae5cfb153a44713f599ef Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 8 Apr 2024 01:00:49 +0100 Subject: [PATCH 573/737] eckit::geo::Grid --- src/eckit/geo/Grid.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 60f082ac0..673d66274 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -191,6 +191,7 @@ class Grid { // -- Friends friend bool operator==(const Grid& a, const Grid& b) { return a.spec() == b.spec(); } + friend bool operator!=(const Grid& a, const Grid& b) { return !(a == b); } }; From bad98fa0f88a447fd2da9217e1add6f5f1b45a01 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 8 Apr 2024 01:02:21 +0100 Subject: [PATCH 574/737] eckit::geo::grid::reducedglobal::HEALPix --- src/eckit/geo/grid/reduced-global/HEALPix.cc | 7 +++---- tests/geo/spec.cc | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/eckit/geo/grid/reduced-global/HEALPix.cc b/src/eckit/geo/grid/reduced-global/HEALPix.cc index 68cebb5e4..133ad377c 100644 --- a/src/eckit/geo/grid/reduced-global/HEALPix.cc +++ b/src/eckit/geo/grid/reduced-global/HEALPix.cc @@ -365,13 +365,12 @@ std::vector HEALPix::longitudes(size_t j) const { void HEALPix::spec(spec::Custom& custom) const { custom.set("grid", "H" + std::to_string(N_)); - if (ordering_ != Ordering::healpix_ring) { - custom.set("ordering", "nested"); - } + custom.set("ordering", ordering_ == Ordering::healpix_ring ? "ring" : "nested"); } -static const GridRegisterType __grid_type("HEALPix"); +static const GridRegisterType __grid_type_1("HEALPix"); +static const GridRegisterType __grid_type_2("healpix"); static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index c3952d20f..5b9e70186 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -352,7 +352,7 @@ CASE("spec") { SECTION("grid: HEALPix") { std::unique_ptr h2(GridFactory::build(spec::Custom({{"grid", "h2"}}))); - EXPECT(h2->spec() == R"({"grid":"H2"})"); + EXPECT(h2->spec() == R"({"grid":"H2","ordering":"ring"})"); std::unique_ptr h2n(GridFactory::build(spec::Custom({{"grid", "H2"}, {"ordering", "nested"}}))); From 26590b0e9ca4431faf4eb59016a803dd9e18349d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 8 Apr 2024 01:02:37 +0100 Subject: [PATCH 575/737] eckit::geo::grid::reducedglobal::HEALPix --- src/eckit/geo/grid/reduced-global/HEALPix.cc | 91 ++++++++++++++++---- src/eckit/geo/grid/reduced-global/HEALPix.h | 10 ++- 2 files changed, 83 insertions(+), 18 deletions(-) diff --git a/src/eckit/geo/grid/reduced-global/HEALPix.cc b/src/eckit/geo/grid/reduced-global/HEALPix.cc index 133ad377c..cdbf58044 100644 --- a/src/eckit/geo/grid/reduced-global/HEALPix.cc +++ b/src/eckit/geo/grid/reduced-global/HEALPix.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "eckit/geo/iterator/Reduced.h" @@ -217,6 +218,42 @@ class Reorder { }; +class NestedIterator final : public geo::Iterator { +public: + explicit NestedIterator(const HEALPix& grid, size_t index = 0) : + points_(grid.to_points()), index_(index), index_size_(grid.size()) {} + + explicit NestedIterator() : + index_(std::numeric_limits::max()), index_size_(std::numeric_limits::max()) {} + +private: + const std::vector points_; + + size_t index_; + const size_t index_size_; + + bool operator==(const Iterator& other) const override { + const auto* another = dynamic_cast(&other); + return another != nullptr && (operator bool() ? index_ == another->index_ : !another->operator bool()); + } + + bool operator++() override { + index_++; + return index_ < index_size_; + } + + bool operator+=(diff_t d) override { + index_ += d; + return index_ < index_size_; + } + + explicit operator bool() const override { return index_ < index_size_; } + Point operator*() const override { return points_.at(index_); } + + size_t index() const override { return index_; } +}; + + } // unnamed namespace @@ -232,8 +269,8 @@ HEALPix::HEALPix(const Spec& spec) : HEALPix::HEALPix(size_t Nside, Ordering ordering) : - ReducedGlobal(area::BoundingBox::make_global_prime()), N_(Nside), ordering_(ordering) { - ASSERT(N_ > 0); + ReducedGlobal(area::BoundingBox::make_global_prime()), Nside_(Nside), ordering_(ordering) { + ASSERT(Nside_ > 0); ASSERT_MSG(ordering == Ordering::healpix_ring || ordering == Ordering::healpix_nested, "HEALPix: supported orderings: ring, nested"); @@ -252,7 +289,7 @@ Renumber HEALPix::reorder(Ordering ordering) const { } if (ordering == Ordering::healpix_ring) { - const Reorder reorder(static_cast(N_)); + const Reorder reorder(static_cast(Nside_)); Renumber ren(size()); for (int i = 0, N = static_cast(size()); i < N; ++i) { ren[i] = reorder.nest_to_ring(i); @@ -261,7 +298,7 @@ Renumber HEALPix::reorder(Ordering ordering) const { } if (ordering == Ordering::healpix_nested) { - const Reorder reorder(static_cast(N_)); + const Reorder reorder(static_cast(Nside_)); Renumber ren(size()); for (int i = 0, N = static_cast(size()); i < N; ++i) { ren[i] = reorder.ring_to_nest(i); @@ -274,29 +311,31 @@ Renumber HEALPix::reorder(Ordering ordering) const { Grid::iterator HEALPix::cbegin() const { - return ordering_ == Ordering::healpix_ring ? iterator{new geo::iterator::Reduced(*this, 0)} : NOTIMP; + return ordering_ == Ordering::healpix_ring ? iterator{new geo::iterator::Reduced(*this)} + : iterator{new NestedIterator(*this)}; } Grid::iterator HEALPix::cend() const { - return ordering_ == Ordering::healpix_ring ? iterator{new geo::iterator::Reduced(*this, size())} : NOTIMP; + return ordering_ == Ordering::healpix_ring ? iterator{new geo::iterator::Reduced(*this, size())} + : iterator{new NestedIterator()}; } size_t HEALPix::ni(size_t j) const { ASSERT(j < nj()); - return j < N_ ? 4 * (j + 1) : j < 3 * N_ ? 4 * N_ : ni(nj() - 1 - j); + return j < Nside_ ? 4 * (j + 1) : j < 3 * Nside_ ? 4 * Nside_ : ni(nj() - 1 - j); } size_t HEALPix::nj() const { - return 4 * N_ - 1; + return 4 * Nside_ - 1; } Spec* HEALPix::spec(const std::string& name) { auto Nside = Translator{}(name.substr(1)); - return new spec::Custom({{"type", "HEALPix"}, {"Nside", Nside}, {"orderingConvention", "ring"}}); + return new spec::Custom({{"type", "HEALPix"}, {"Nside", Nside}, {"ordering", "ring"}}); } @@ -307,7 +346,28 @@ area::BoundingBox HEALPix::boundingBox() const { size_t HEALPix::size() const { - return 12 * N_ * N_; + return 12 * Nside_ * Nside_; +} + + +std::vector HEALPix::to_points() const { + const auto points = ReducedGlobal::to_points(); + + if (ordering_ == Ordering::healpix_ring) { + return points; + } + + ASSERT(ordering_ == Ordering::healpix_nested); + + std::vector points_nested; + points_nested.reserve(size()); + + const Reorder reorder(static_cast(Nside_)); + for (size_t i = 0; i < size(); ++i) { + points_nested.emplace_back(std::get(points[reorder.nest_to_ring(static_cast(i))])); + } + + return points_nested; } @@ -334,9 +394,10 @@ const std::vector& HEALPix::latitudes() const { auto i = latitudes_.begin(); auto j = latitudes_.rbegin(); - for (size_t ring = 1; ring < 2 * N_; ++ring, ++i, ++j) { - const auto f = ring < N_ ? 1. - static_cast(ring * ring) / (3 * static_cast(N_ * N_)) - : 4. / 3. - 2 * static_cast(ring) / (3 * static_cast(N_)); + for (size_t ring = 1; ring < 2 * Nside_; ++ring, ++i, ++j) { + const auto f = ring < Nside_ + ? 1. - static_cast(ring * ring) / (3 * static_cast(Nside_ * Nside_)) + : 4. / 3. - 2 * static_cast(ring) / (3 * static_cast(Nside_)); *i = 90. - util::RADIAN_TO_DEGREE * std::acos(f); *j = -*i; @@ -352,7 +413,7 @@ const std::vector& HEALPix::latitudes() const { std::vector HEALPix::longitudes(size_t j) const { const auto Ni = ni(j); const auto step = 360. / static_cast(Ni); - const auto start = j < N_ || 3 * N_ - 1 < j || static_cast((j + N_) % 2) ? step / 2. : 0.; + const auto start = j < Nside_ || 3 * Nside_ - 1 < j || static_cast((j + Nside_) % 2) ? step / 2. : 0.; std::vector lons(Ni); std::generate_n(lons.begin(), Ni, [start, step, n = 0ULL]() mutable { @@ -364,7 +425,7 @@ std::vector HEALPix::longitudes(size_t j) const { void HEALPix::spec(spec::Custom& custom) const { - custom.set("grid", "H" + std::to_string(N_)); + custom.set("grid", "H" + std::to_string(Nside_)); custom.set("ordering", ordering_ == Ordering::healpix_ring ? "ring" : "nested"); } diff --git a/src/eckit/geo/grid/reduced-global/HEALPix.h b/src/eckit/geo/grid/reduced-global/HEALPix.h index a3b51aa53..b68c6fd2e 100644 --- a/src/eckit/geo/grid/reduced-global/HEALPix.h +++ b/src/eckit/geo/grid/reduced-global/HEALPix.h @@ -41,7 +41,8 @@ class HEALPix final : public ReducedGlobal { // None // -- Methods - // None + + size_t Nside() const { return Nside_; } // -- Overridden methods @@ -49,12 +50,15 @@ class HEALPix final : public ReducedGlobal { iterator cend() const override; size_t size() const override; + + std::vector to_points() const override; + size_t ni(size_t j) const override; size_t nj() const override; Ordering order() const override { return ordering_; } Renumber reorder(Ordering) const override; - Grid* make_grid_reordered(Ordering ordering) const override { return new HEALPix(N_, ordering); } + Grid* make_grid_reordered(Ordering ordering) const override { return new HEALPix(Nside_, ordering); } // -- Class members @@ -66,7 +70,7 @@ class HEALPix final : public ReducedGlobal { private: // -- Members - const size_t N_; + const size_t Nside_; const Ordering ordering_; mutable std::vector latitudes_; From 784ad84ade3cd7708a3fe5740aeaa3d60a18306e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 8 Apr 2024 01:02:50 +0100 Subject: [PATCH 576/737] eckit::geo::grid::reducedglobal::HEALPix tests --- tests/geo/CMakeLists.txt | 1 + tests/geo/grid_healpix.cc | 196 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 197 insertions(+) create mode 100644 tests/geo/grid_healpix.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 89b8967a0..6a41a7763 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -5,6 +5,7 @@ foreach(_test figure_sphere great_circle grid + grid_healpix grid_reduced_gg grid_regular_gg grid_regular_ll diff --git a/tests/geo/grid_healpix.cc b/tests/geo/grid_healpix.cc new file mode 100644 index 000000000..003c07aaf --- /dev/null +++ b/tests/geo/grid_healpix.cc @@ -0,0 +1,196 @@ +/* + * (C) Copyright 1996- 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 itr by virtue of its status as an intergovernmental organisation nor + * does itr submit to any jurisdiction. + */ + + +#include + +#include "eckit/geo/Grid.h" +#include "eckit/geo/grid/reduced-global/HEALPix.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/testing/Test.h" + + +namespace eckit::geo::test { + + +CASE("HEALPIX") { + using grid::reducedglobal::HEALPix; + + + SECTION("gridspec") { + spec::Custom spec({{"grid", "h2"}}); + std::unique_ptr grid1(GridFactory::build(spec)); + auto n1 = grid1->size(); + + EXPECT_EQUAL(n1, 48); + } + + + SECTION("sizes") { + struct test_t { + explicit test_t(size_t N) : + N(N), size(12 * N * N) {} + size_t N; + size_t size; + } tests[]{test_t{2}, test_t{3}, test_t{64}}; + + for (const auto& test : tests) { + std::unique_ptr grid1( + GridFactory::build(spec::Custom({{"grid", "h" + std::to_string(test.N)}}))); + std::unique_ptr grid2( + GridFactory::build(spec::Custom({{"type", "HEALPix"}, {"Nside", test.N}}))); + HEALPix grid3(test.N); + + EXPECT(grid1->size() == test.size); + EXPECT(grid2->size() == test.size); + EXPECT(grid3.size() == test.size); + } + } + + + SECTION("points") { + + std::unique_ptr ring(new HEALPix(2)); + + EXPECT(ring->order() == Ordering::healpix_ring); + + + std::unique_ptr nested(new HEALPix(2, Ordering::healpix_nested)); + + EXPECT(nested->order() == Ordering::healpix_nested); + + // reference coordinates in ring ordering + const std::vector ref{ + {45., 66.443535691}, + {135., 66.443535691}, + {225., 66.443535691}, + {315., 66.443535691}, + {22.5, 41.810314896}, + {67.5, 41.810314896}, + {112.5, 41.810314896}, + {157.5, 41.810314896}, + {202.5, 41.810314896}, + {247.5, 41.810314896}, + {292.5, 41.810314896}, + {337.5, 41.810314896}, + {0., 19.471220634}, + {45., 19.471220634}, + {90., 19.471220634}, + {135., 19.471220634}, + {180., 19.471220634}, + {225., 19.471220634}, + {270., 19.471220634}, + {315., 19.471220634}, + {22.5, 0.}, + {67.5, 0.}, + {112.5, 0.}, + {157.5, 0.}, + {202.5, 0.}, + {247.5, 0.}, + {292.5, 0.}, + {337.5, 0.}, + {0., -19.471220634}, + {45., -19.471220634}, + {90., -19.471220634}, + {135., -19.471220634}, + {180., -19.471220634}, + {225., -19.471220634}, + {270., -19.471220634}, + {315., -19.471220634}, + {22.5, -41.810314896}, + {67.5, -41.810314896}, + {112.5, -41.810314896}, + {157.5, -41.810314896}, + {202.5, -41.810314896}, + {247.5, -41.810314896}, + {292.5, -41.810314896}, + {337.5, -41.810314896}, + {45., -66.443535691}, + {135., -66.443535691}, + {225., -66.443535691}, + {315., -66.443535691}, + }; + + + auto points_r = ring->to_points(); + + EXPECT(points_r.size() == ring->size()); + ASSERT(points_r.size() == ref.size()); + + auto itr = ring->begin(); + for (size_t i = 0; i < points_r.size(); ++i) { + EXPECT(points_equal(ref[i], points_r[i])); + EXPECT(points_equal(ref[i], *itr)); + ++itr; + } + + EXPECT(itr == ring->end()); + + size_t i = 0; + for (const auto& it : *ring) { + EXPECT(points_equal(ref[i++], it)); + } + + EXPECT(i == ring->size()); + + + auto ren = nested->reorder(Ordering::healpix_ring); + auto points_n = nested->to_points(); + + EXPECT(points_n.size() == nested->size()); + ASSERT(points_n.size() == ref.size()); + + auto it = nested->begin(); + for (size_t i = 0; i < points_n.size(); ++i) { + EXPECT(points_equal(ref[ren.at(i)], points_n[i])); + EXPECT(points_equal(ref[ren.at(i)], *it)); + ++it; + } + + EXPECT(it == nested->end()); + + size_t j = 0; + for (const auto& it : *nested) { + EXPECT(points_equal(ref[ren.at(j++)], it)); + } + + EXPECT(i == nested->size()); + } + + + SECTION("equals") { + std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "h2"}}))); + std::unique_ptr grid2(GridFactory::make_from_string("{type: HEALPix, Nside: 2}")); + std::unique_ptr grid3(new HEALPix(2)); + + EXPECT(*grid1 == *grid2); + EXPECT(*grid2 == *grid3); + EXPECT(*grid3 == *grid1); + + std::unique_ptr grid4(GridFactory::build(spec::Custom({{"grid", "h2"}, {"ordering", "nested"}}))); + std::unique_ptr grid5(GridFactory::make_from_string("{type: HEALPix, Nside: 2, ordering: nested}")); + std::unique_ptr grid6(new HEALPix(2, Ordering::healpix_nested)); + + EXPECT(*grid4 != *grid1); + + EXPECT(*grid4 == *grid5); + EXPECT(*grid5 == *grid6); + EXPECT(*grid6 == *grid4); + } +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From e756c4a5cc0245395b3a5748825c7fc600df06aa Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 8 Apr 2024 09:58:04 +0100 Subject: [PATCH 577/737] eckit::geo::grid::reducedglobal::HEALPix cleanup --- src/eckit/geo/grid/reduced-global/HEALPix.cc | 40 ++++++-------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/src/eckit/geo/grid/reduced-global/HEALPix.cc b/src/eckit/geo/grid/reduced-global/HEALPix.cc index cdbf58044..ebf96de87 100644 --- a/src/eckit/geo/grid/reduced-global/HEALPix.cc +++ b/src/eckit/geo/grid/reduced-global/HEALPix.cc @@ -223,7 +223,7 @@ class NestedIterator final : public geo::Iterator { explicit NestedIterator(const HEALPix& grid, size_t index = 0) : points_(grid.to_points()), index_(index), index_size_(grid.size()) {} - explicit NestedIterator() : + NestedIterator() : index_(std::numeric_limits::max()), index_size_(std::numeric_limits::max()) {} private: @@ -257,15 +257,12 @@ class NestedIterator final : public geo::Iterator { } // unnamed namespace -static Ordering ordering_from_string(const std::string& str) { - return str == "ring" ? Ordering::healpix_ring - : str == "nested" ? Ordering::healpix_nested - : throw AssertionFailed("HEALPix: supported orderings: ring, nested", Here()); -} - - HEALPix::HEALPix(const Spec& spec) : - HEALPix(spec.get_unsigned("Nside"), ordering_from_string(spec.get_string("ordering", "ring"))) {} + HEALPix(spec.get_unsigned("Nside"), [](const std::string& str) { + return str == "ring" ? Ordering::healpix_ring + : str == "nested" ? Ordering::healpix_nested + : throw AssertionFailed("HEALPix: supported orderings: ring, nested", Here()); + }(spec.get_string("ordering", "ring"))) {} HEALPix::HEALPix(size_t Nside, Ordering ordering) : @@ -288,25 +285,14 @@ Renumber HEALPix::reorder(Ordering ordering) const { return Grid::no_reorder(size()); } - if (ordering == Ordering::healpix_ring) { - const Reorder reorder(static_cast(Nside_)); - Renumber ren(size()); - for (int i = 0, N = static_cast(size()); i < N; ++i) { - ren[i] = reorder.nest_to_ring(i); - } - return ren; - } + const Reorder reorder(static_cast(Nside_)); + const auto N = static_cast(size()); - if (ordering == Ordering::healpix_nested) { - const Reorder reorder(static_cast(Nside_)); - Renumber ren(size()); - for (int i = 0, N = static_cast(size()); i < N; ++i) { - ren[i] = reorder.ring_to_nest(i); - } - return ren; + Renumber ren(N); + for (int i = 0; i < N; ++i) { + ren[i] = ordering == Ordering::healpix_ring ? reorder.nest_to_ring(i) : reorder.ring_to_nest(i); } - - throw AssertionFailed("HEALPix: supported orderings: ring, nested", Here()); + return ren; } @@ -357,8 +343,6 @@ std::vector HEALPix::to_points() const { return points; } - ASSERT(ordering_ == Ordering::healpix_nested); - std::vector points_nested; points_nested.reserve(size()); From 87047b64236023d0244c6b5e51eb86838d90c153 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 17 Apr 2024 16:25:38 +0100 Subject: [PATCH 578/737] eckit::maths re-enable option ENABLE_CONVEX_HULL (accidentally deleted) --- CMakeLists.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 26b2c25b7..81717d600 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -151,6 +151,24 @@ ecbuild_add_option( FEATURE ECKIT_CODEC set( eckit_CODEC_STATIC_ASSERT ON CACHE BOOL "eckit::codec static assertions" ) +### eckit::maths + +ecbuild_add_option( FEATURE CONVEX_HULL + DEFAULT OFF + DESCRIPTION "eckit::maths library convex hull/Delaunay triangulation" + REQUIRED_PACKAGES "Qhull COMPONENTS C CXX" ) + +if( eckit_HAVE_CONVEX_HULL ) + find_package( Qhull REQUIRED CONFIG ) + + if( NOT TARGET Qhull::qhullcpp OR NOT TARGET Qhull::qhullstatic_r ) + message( FATAL_ERROR "eckit::maths ENABLE_CONVEX_HULL requires Qhull C/C++ libraries" ) + endif() + + add_library(Qhull::Qhull INTERFACE IMPORTED) + target_link_libraries(Qhull::Qhull INTERFACE Qhull::qhullcpp Qhull::qhullstatic_r ) +endif() + ### eckit::geo ecbuild_add_option( FEATURE ECKIT_GEO From c20e2b135ba5354bca1749c398e5023868dd1287 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 9 Apr 2024 23:31:19 +0100 Subject: [PATCH 579/737] eckit::geo::Grid, eckit::geo::Iterator refactor --- src/eckit/geo/Grid.h | 6 +++--- src/eckit/geo/Iterator.h | 10 +++++----- src/eckit/geo/iterator/Reduced.cc | 5 +++-- src/eckit/geo/iterator/Reduced.h | 2 +- src/eckit/geo/iterator/Regular.cc | 2 +- src/eckit/geo/iterator/Regular.h | 2 +- src/eckit/geo/iterator/Unstructured.cc | 4 ++-- src/eckit/geo/iterator/Unstructured.h | 2 +- 8 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 673d66274..d57a91cb7 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -59,7 +59,7 @@ class Grid { ASSERT(unique_ptr::operator bool()); } - using diff_t = unique_ptr::element_type::diff_t; + using difference_type = unique_ptr::element_type::difference_type; Iterator(const Iterator&) = delete; Iterator(Iterator&&) = delete; @@ -73,10 +73,10 @@ class Grid { bool operator!=(const Iterator& other) const { return get()->operator!=(*(other.get())); } bool operator++() { return get()->operator++(); } - bool operator+=(diff_t d) { return get()->operator+=(d); } + bool operator+=(difference_type d) { return get()->operator+=(d); } bool operator--() { return get()->operator--(); } - bool operator-=(diff_t d) { return get()->operator-=(d); } + bool operator-=(difference_type d) { return get()->operator-=(d); } explicit operator bool() const { return get()->operator bool(); } Point operator*() const { return get()->operator*(); } diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index fd5a43b75..a075c8b15 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -12,7 +12,7 @@ #pragma once -#include +#include #include "eckit/geo/Point.h" @@ -29,7 +29,7 @@ class Iterator { public: // -- Types - using diff_t = std::make_signed::type; + using difference_type = std::ptrdiff_t; // -- Exceptions // None @@ -54,11 +54,11 @@ class Iterator { virtual bool operator==(const Iterator&) const = 0; bool operator!=(const Iterator& other) const { return !operator==(other); } - virtual bool operator++() = 0; - virtual bool operator+=(diff_t) = 0; + virtual bool operator++() = 0; + virtual bool operator+=(difference_type) = 0; virtual bool operator--() { return operator-=(1); } - virtual bool operator-=(diff_t diff) { return operator+=(-diff); } + virtual bool operator-=(difference_type diff) { return operator+=(-diff); } virtual explicit operator bool() const = 0; virtual Point operator*() const = 0; diff --git a/src/eckit/geo/iterator/Reduced.cc b/src/eckit/geo/iterator/Reduced.cc index 067cd8fba..1e9e685a8 100644 --- a/src/eckit/geo/iterator/Reduced.cc +++ b/src/eckit/geo/iterator/Reduced.cc @@ -57,8 +57,9 @@ bool Reduced::operator++() { } -bool Reduced::operator+=(diff_t d) { - if (auto di = static_cast(index_); 0 <= di + d && di + d < static_cast(index_size_)) { +bool Reduced::operator+=(difference_type d) { + if (auto di = static_cast(index_); + 0 <= di + d && di + d < static_cast(index_size_)) { if (index_ = static_cast(di + d); !(niacc_[j_] <= index_ && index_ < niacc_[j_ + 1])) { longitudes_j_ = grid_.longitudes(j_ = j(index_)); } diff --git a/src/eckit/geo/iterator/Reduced.h b/src/eckit/geo/iterator/Reduced.h index ab60c30b8..1c125c9c6 100644 --- a/src/eckit/geo/iterator/Reduced.h +++ b/src/eckit/geo/iterator/Reduced.h @@ -76,7 +76,7 @@ class Reduced final : public geo::Iterator { bool operator==(const Iterator&) const override; bool operator++() override; - bool operator+=(diff_t) override; + bool operator+=(difference_type) override; explicit operator bool() const override; Point operator*() const override; diff --git a/src/eckit/geo/iterator/Regular.cc b/src/eckit/geo/iterator/Regular.cc index 53616aeca..7140b1505 100644 --- a/src/eckit/geo/iterator/Regular.cc +++ b/src/eckit/geo/iterator/Regular.cc @@ -55,7 +55,7 @@ bool Regular::operator++() { } -bool Regular::operator+=(diff_t d) { +bool Regular::operator+=(difference_type d) { NOTIMP; } diff --git a/src/eckit/geo/iterator/Regular.h b/src/eckit/geo/iterator/Regular.h index c4b925bb3..6756d207c 100644 --- a/src/eckit/geo/iterator/Regular.h +++ b/src/eckit/geo/iterator/Regular.h @@ -76,7 +76,7 @@ class Regular final : public Iterator { bool operator==(const Iterator&) const override; bool operator++() override; - bool operator+=(diff_t) override; + bool operator+=(difference_type) override; explicit operator bool() const override; Point operator*() const override; diff --git a/src/eckit/geo/iterator/Unstructured.cc b/src/eckit/geo/iterator/Unstructured.cc index 304f12c28..d16f62867 100644 --- a/src/eckit/geo/iterator/Unstructured.cc +++ b/src/eckit/geo/iterator/Unstructured.cc @@ -46,8 +46,8 @@ bool Unstructured::operator++() { } -bool Unstructured::operator+=(diff_t d) { - if (auto di = static_cast(index_); 0 <= di + d && di + d < static_cast(index_size_)) { +bool Unstructured::operator+=(difference_type d) { + if (auto di = static_cast(index_); 0 <= di + d && di + d < static_cast(index_size_)) { index_ = static_cast(di + d); return true; } diff --git a/src/eckit/geo/iterator/Unstructured.h b/src/eckit/geo/iterator/Unstructured.h index 57109f1b2..f066db1b9 100644 --- a/src/eckit/geo/iterator/Unstructured.h +++ b/src/eckit/geo/iterator/Unstructured.h @@ -71,7 +71,7 @@ class Unstructured final : public Iterator { bool operator==(const geo::Iterator&) const override; bool operator++() override; - bool operator+=(diff_t) override; + bool operator+=(difference_type) override; explicit operator bool() const override; Point operator*() const override; From b01e19671eab4367f1b45b75111412f1ccdb3d09 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 9 Apr 2024 23:44:09 +0100 Subject: [PATCH 580/737] eckit::geo::Grid --- src/eckit/geo/Grid.cc | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 977bde8de..c96f52a7e 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -12,6 +12,7 @@ #include "eckit/geo/Grid.h" +#include #include #include #include @@ -80,17 +81,24 @@ std::vector Grid::to_points() const { std::vector points; points.reserve(size()); - for (const auto& p : *this) { - const auto& q = std::get(p); - points.push_back(p); - } + std::for_each(cbegin(), cend(), [&points](const auto& p) { points.emplace_back(p); }); return points; } -std::pair, std::vector> Grid::to_latlon() const { - throw NotImplemented("Grid::to_latlon"); +std::pair, std::vector > Grid::to_latlon() const { + std::pair, std::vector > ll; + ll.first.reserve(size()); + ll.second.reserve(size()); + + std::for_each(cbegin(), cend(), [&ll](const auto& p) { + auto q = std::get(p); + ll.first.emplace_back(q.lat); + ll.second.emplace_back(q.lon); + }); + + return ll; } From 41d250e6cdf42a83e89bb392859a584f56044319 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 00:55:50 +0100 Subject: [PATCH 581/737] eckit::geo::Grid --- src/eckit/geo/CMakeLists.txt | 2 - src/eckit/geo/grid/unstructured/ORCA.cc | 48 ++++++++++++++- src/eckit/geo/grid/unstructured/ORCA.h | 10 +++- tests/geo/CMakeLists.txt | 6 ++ tests/geo/grid_orca.cc | 77 +++++++++++++++++++++++++ tests/geo/spec.cc | 7 ++- 6 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 tests/geo/grid_orca.cc diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 0706d235b..feed21e88 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -77,8 +77,6 @@ list(APPEND eckit_geo_srcs grid/regular/RegularLL.h grid/regular/XYToLonLat.cc grid/regular/XYToLonLat.h - grid/unstructured/ORCA.cc - grid/unstructured/ORCA.h grid/unstructured/UnstructuredFromGrid.cc grid/unstructured/UnstructuredFromGrid.h iterator/Reduced.cc diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/unstructured/ORCA.cc index 5e81f7c6e..cd991e09e 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/unstructured/ORCA.cc @@ -12,6 +12,8 @@ #include "eckit/geo/grid/unstructured/ORCA.h" +#include + #include "eckit/codec/codec.h" #include "eckit/eckit_config.h" #include "eckit/exception/Exceptions.h" @@ -145,6 +147,15 @@ ORCA::ORCA(const Spec& spec) : spec)) {} +ORCA::ORCA(uid_t uid) : + ORCA(*std::unique_ptr(GridFactory::make_spec(spec::Custom(spec::Custom::container_type{{"uid", uid}})))) {} + + +std::string ORCA::arrangement() const { + return arrangement_to_string(arrangement_); +} + + Grid::uid_t ORCA::ORCARecord::calculate_uid(Arrangement arrangement) const { MD5 hash; hash.add(arrangement_to_string(arrangement)); @@ -261,12 +272,12 @@ size_t ORCA::ORCARecord::write(const PathName& p, const std::string& compression Grid::iterator ORCA::cbegin() const { - return iterator{new geo::iterator::Unstructured(*this, 0)}; + return iterator{new geo::iterator::Unstructured(*this, 0, record_.longitudes_, record_.latitudes_)}; } Grid::iterator ORCA::cend() const { - return iterator{new geo::iterator::Unstructured(*this, size())}; + return iterator{new geo::iterator::Unstructured(*this)}; } @@ -276,6 +287,37 @@ area::BoundingBox ORCA::boundingBox() const { } +Grid::uid_t ORCA::calculate_uid() const { + MD5 hash(arrangement_to_string(arrangement_)); + + if (const auto len = static_cast(size() * sizeof(double)); eckit_LITTLE_ENDIAN) { + hash.add(record_.latitudes_.data(), len); + hash.add(record_.longitudes_.data(), len); + } + else { + auto ll = to_latlon(); + byteswap(ll.first.data(), size()); + byteswap(ll.second.data(), size()); + + hash.add(ll.first.data(), len); + hash.add(ll.second.data(), len); + } + + return hash; +} + + +std::vector ORCA::to_points() const { + std::vector p; + p.reserve(size()); + + for (size_t i = 0; i < size(); ++i) { + p.emplace_back(PointLonLat{record_.longitudes_[i], record_.latitudes_[i]}); + } + return p; +} + + std::pair, std::vector> ORCA::to_latlon() const { return {record_.latitudes_, record_.longitudes_}; } @@ -287,7 +329,7 @@ Spec* ORCA::spec(const std::string& name) { void ORCA::spec(spec::Custom& custom) const { - custom.set("grid", uid_); + custom.set("uid", uid_); } diff --git a/src/eckit/geo/grid/unstructured/ORCA.h b/src/eckit/geo/grid/unstructured/ORCA.h index 8f7757e91..a08fbd40b 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.h +++ b/src/eckit/geo/grid/unstructured/ORCA.h @@ -69,6 +69,7 @@ class ORCA final : public Unstructured { // -- Constructors explicit ORCA(const Spec&); + explicit ORCA(uid_t); // -- Destructor // None @@ -84,6 +85,11 @@ class ORCA final : public Unstructured { size_t ni() const { return record_.ni(); } size_t nj() const { return record_.nj(); } + std::string name() const { return name_; } + std::string arrangement() const; + + uid_t calculate_uid() const; + // -- Overridden methods iterator cbegin() const override; @@ -98,11 +104,9 @@ class ORCA final : public Unstructured { bool includesSouthPole() const override { return true; } // FIXME: not sure this is semanticaly correct bool isPeriodicWestEast() const override { return true; } + std::vector to_points() const override; std::pair, std::vector> to_latlon() const override; - const std::vector& longitudes() const override { return record_.longitudes_; } - const std::vector& latitudes() const override { return record_.latitudes_; } - // -- Class members // None diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 6a41a7763..adf307441 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -34,6 +34,12 @@ foreach(_test LIBS eckit_geo ) endforeach() +ecbuild_add_test( + TARGET eckit_test_geo_grid_orca + SOURCES grid_orca.cc + LIBS eckit_geo + CONDITION eckit_HAVE_ECKIT_CODEC ) + ecbuild_add_test( TARGET eckit_test_geo_tool_grid_spec_1_1 COMMAND eckit_grid_spec ARGS "grid: 1/1.0" [=[--check=[{]"grid":\[1,1\][}]]=] ) diff --git a/tests/geo/grid_orca.cc b/tests/geo/grid_orca.cc new file mode 100644 index 000000000..6820daf84 --- /dev/null +++ b/tests/geo/grid_orca.cc @@ -0,0 +1,77 @@ +/* + * (C) Copyright 1996- 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 itr by virtue of its status as an intergovernmental organisation nor + * does itr submit to any jurisdiction. + */ + + +#include + +#include "eckit/geo/grid/regular/ORCA.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/testing/Test.h" + + +namespace eckit::geo::test { + + +CASE("ORCA") { + using grid::regular::ORCA; + + const Grid::uid_t uid = "d5bde4f52ff3a9bea5629cd9ac514410"; + const std::vector dimensions{182, 149}; + + + SECTION("gridspec") { + + std::unique_ptr spec(GridFactory::make_spec(spec::Custom({{"uid", uid}}))); + + EXPECT(spec->get_string("type") == "ORCA"); + EXPECT(spec->get_string("orca_name") == "ORCA2"); + EXPECT(spec->get_string("orca_arrangement") == "T"); + EXPECT(spec->get_string("orca_uid") == uid); + EXPECT(spec->get_long_vector("dimensions") == dimensions); + + std::unique_ptr grid1(GridFactory::make_from_string("{uid:" + uid + "}")); + + EXPECT(grid1->size() == dimensions[0] * dimensions[1]); + EXPECT(grid1->uid() == uid); + + std::unique_ptr grid2(GridFactory::build(spec::Custom({{"uid", uid}}))); + + EXPECT(grid2->size() == dimensions[0] * dimensions[1]); + EXPECT(grid2->uid() == uid); + + ORCA grid3(uid); + + EXPECT(grid3.uid() == uid); + EXPECT(grid3.calculate_uid() == uid); + EXPECT(static_cast(grid3).spec() == R"({"uid":")" + uid + R"("})"); + + EXPECT(grid1->spec() == grid2->spec()); + } + + + SECTION("equals") { + std::unique_ptr grid1(GridFactory::make_from_string("{uid:" + uid + "}")); + std::unique_ptr grid2(GridFactory::build(spec::Custom({{"uid", uid}}))); + ORCA grid3(uid); + + EXPECT(*grid1 == *grid2); + EXPECT(*grid2 == grid3); + EXPECT(grid3 == *grid1); + } +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 5b9e70186..9d8396732 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -361,12 +361,13 @@ CASE("spec") { SECTION("grid: ORCA") { + Grid::uid_t uid = "d5bde4f52ff3a9bea5629cd9ac514410"; + std::unique_ptr o1(GridFactory::build(spec::Custom({{"grid", "ORCA2_T"}}))); - EXPECT(o1->spec() == R"({"grid":"d5bde4f52ff3a9bea5629cd9ac514410"})"); + EXPECT(o1->spec() == R"({"uid":")" + uid + R"("})"); - std::unique_ptr o2( - GridFactory::build(spec::Custom({{"grid", "d5bde4f52ff3a9bea5629cd9ac514410"}}))); + std::unique_ptr o2(GridFactory::build(spec::Custom({{"uid", uid}}))); EXPECT(o1->spec() == o2->spec()); } From fdb5222564d5b2f91f8e88f9c43bf0167e5c802a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 00:57:42 +0100 Subject: [PATCH 582/737] Cleanup --- src/eckit/geo/grid/Regular.cc | 2 -- tests/geo/grid_healpix.cc | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index 070b3962d..366ba9a7d 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -12,8 +12,6 @@ #include "eckit/geo/grid/Regular.h" -// #include <> - namespace eckit::geo::grid { diff --git a/tests/geo/grid_healpix.cc b/tests/geo/grid_healpix.cc index 003c07aaf..5206e313b 100644 --- a/tests/geo/grid_healpix.cc +++ b/tests/geo/grid_healpix.cc @@ -21,7 +21,7 @@ namespace eckit::geo::test { -CASE("HEALPIX") { +CASE("HEALPix") { using grid::reducedglobal::HEALPix; From 5a108020841b90f75cd5b65c26dbbcc29cf77119 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 00:56:17 +0100 Subject: [PATCH 583/737] eckit::geo::Iterator --- src/eckit/geo/grid/reduced-global/HEALPix.cc | 44 +--------- src/eckit/geo/iterator/Unstructured.cc | 88 ++++++++++++++++---- src/eckit/geo/iterator/Unstructured.h | 25 ++++-- 3 files changed, 97 insertions(+), 60 deletions(-) diff --git a/src/eckit/geo/grid/reduced-global/HEALPix.cc b/src/eckit/geo/grid/reduced-global/HEALPix.cc index ebf96de87..affcb97e6 100644 --- a/src/eckit/geo/grid/reduced-global/HEALPix.cc +++ b/src/eckit/geo/grid/reduced-global/HEALPix.cc @@ -16,10 +16,10 @@ #include #include #include -#include #include #include "eckit/geo/iterator/Reduced.h" +#include "eckit/geo/iterator/Unstructured.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/utils/Translator.h" @@ -218,42 +218,6 @@ class Reorder { }; -class NestedIterator final : public geo::Iterator { -public: - explicit NestedIterator(const HEALPix& grid, size_t index = 0) : - points_(grid.to_points()), index_(index), index_size_(grid.size()) {} - - NestedIterator() : - index_(std::numeric_limits::max()), index_size_(std::numeric_limits::max()) {} - -private: - const std::vector points_; - - size_t index_; - const size_t index_size_; - - bool operator==(const Iterator& other) const override { - const auto* another = dynamic_cast(&other); - return another != nullptr && (operator bool() ? index_ == another->index_ : !another->operator bool()); - } - - bool operator++() override { - index_++; - return index_ < index_size_; - } - - bool operator+=(diff_t d) override { - index_ += d; - return index_ < index_size_; - } - - explicit operator bool() const override { return index_ < index_size_; } - Point operator*() const override { return points_.at(index_); } - - size_t index() const override { return index_; } -}; - - } // unnamed namespace @@ -297,14 +261,14 @@ Renumber HEALPix::reorder(Ordering ordering) const { Grid::iterator HEALPix::cbegin() const { - return ordering_ == Ordering::healpix_ring ? iterator{new geo::iterator::Reduced(*this)} - : iterator{new NestedIterator(*this)}; + return ordering_ == Ordering::healpix_ring ? iterator{new geo::iterator::Reduced(*this, 0)} + : iterator{new geo::iterator::Unstructured(*this, 0, to_points())}; } Grid::iterator HEALPix::cend() const { return ordering_ == Ordering::healpix_ring ? iterator{new geo::iterator::Reduced(*this, size())} - : iterator{new NestedIterator()}; + : iterator{new geo::iterator::Unstructured(*this)}; } diff --git a/src/eckit/geo/iterator/Unstructured.cc b/src/eckit/geo/iterator/Unstructured.cc index d16f62867..f571714b5 100644 --- a/src/eckit/geo/iterator/Unstructured.cc +++ b/src/eckit/geo/iterator/Unstructured.cc @@ -12,6 +12,9 @@ #include "eckit/geo/iterator/Unstructured.h" +#include + +#include "eckit/exception/Exceptions.h" #include "eckit/geo/Grid.h" #include "eckit/geo/grid/Unstructured.h" @@ -19,17 +22,73 @@ namespace eckit::geo::iterator { -Unstructured::Unstructured(const Grid& grid, size_t index) : - index_(index), - index_size_(grid.size()), - longitudes_(dynamic_cast(grid).longitudes()), - latitudes_(dynamic_cast(grid).latitudes()), - uid_(dynamic_cast(grid).uid()) { - ASSERT(index_size_ == longitudes_.size()); - ASSERT(index_size_ == latitudes_.size()); +namespace { + + +struct LonLatReference : Unstructured::Container { + explicit LonLatReference(const std::vector& longitudes, const std::vector& latitudes) : + longitudes(longitudes), latitudes(latitudes) { + ASSERT(longitudes.size() == latitudes.size()); + } + + Point get(size_t index) const override { return PointLonLat{longitudes.at(index), latitudes.at(index)}; } + size_t size() const override { return longitudes.size(); } + + const std::vector& longitudes; + const std::vector& latitudes; +}; + + +struct PointsReference : Unstructured::Container { + explicit PointsReference(const std::vector& points) : + points(points) {} + + Point get(size_t index) const override { return points.at(index); } + size_t size() const override { return points.size(); } + + const std::vector& points; +}; + + +struct PointsMove : Unstructured::Container { + explicit PointsMove(std::vector&& points) : + points(points) {} + + Point get(size_t index) const override { return points.at(index); } + size_t size() const override { return points.size(); } + + const std::vector points; +}; + + +} // namespace + + +Unstructured::Unstructured(const Grid& grid, + size_t index, + const std::vector& longitudes, + const std::vector& latitudes) : + container_(new LonLatReference(longitudes, latitudes)), index_(index), size_(container_->size()), uid_(grid.uid()) { + ASSERT(container_->size() == grid.size()); } +Unstructured::Unstructured(const Grid& grid, size_t index, const std::vector& points) : + container_(new PointsReference(points)), index_(index), size_(container_->size()), uid_(grid.uid()) { + ASSERT(container_->size() == grid.size()); +} + + +Unstructured::Unstructured(const Grid& grid, size_t index, std::vector&& points) : + container_(new PointsMove(std::move(points))), index_(index), size_(container_->size()), uid_(grid.uid()) { + ASSERT(container_->size() == grid.size()); +} + + +Unstructured::Unstructured(const Grid& grid) : + index_(grid.size()), size_(grid.size()), uid_(grid.uid()) {} + + bool Unstructured::operator==(const geo::Iterator& other) const { const auto* another = dynamic_cast(&other); return another != nullptr && index_ == another->index_ && uid_ == another->uid_; @@ -37,33 +96,34 @@ bool Unstructured::operator==(const geo::Iterator& other) const { bool Unstructured::operator++() { - if (index_++; index_ < index_size_) { + if (index_++; index_ < size_) { return true; } - index_ = index_size_; // ensure it's invalid + index_ = size_; // ensure it's invalid return false; } bool Unstructured::operator+=(difference_type d) { - if (auto di = static_cast(index_); 0 <= di + d && di + d < static_cast(index_size_)) { + if (auto di = static_cast(index_); 0 <= di + d && di + d < static_cast(size_)) { index_ = static_cast(di + d); return true; } - index_ = index_size_; // ensure it's invalid + index_ = size_; // ensure it's invalid return false; } Unstructured::operator bool() const { - return index_ < index_size_; + return index_ < size_; } Point Unstructured::operator*() const { - return PointLonLat{longitudes_.at(index_), latitudes_.at(index_)}; + ASSERT(container_); + return container_->get(index_); } diff --git a/src/eckit/geo/iterator/Unstructured.h b/src/eckit/geo/iterator/Unstructured.h index f066db1b9..2856927c7 100644 --- a/src/eckit/geo/iterator/Unstructured.h +++ b/src/eckit/geo/iterator/Unstructured.h @@ -12,6 +12,9 @@ #pragma once +#include +#include + #include "eckit/geo/Iterator.h" @@ -21,14 +24,26 @@ namespace eckit::geo::iterator { class Unstructured final : public Iterator { public: // -- Types - // None + + struct Container { + virtual ~Container() = default; + virtual Point get(size_t index) const = 0; + virtual size_t size() const = 0; + }; // -- Exceptions // None // -- Constructors - explicit Unstructured(const Grid&, size_t index = 0); + explicit Unstructured(const Grid&, + size_t index, + const std::vector& longitudes, + const std::vector& latitudes); + explicit Unstructured(const Grid&, size_t index, const std::vector&); + explicit Unstructured(const Grid&, size_t index, std::vector&&); + + explicit Unstructured(const Grid&); // -- Destructor // None @@ -57,11 +72,9 @@ class Unstructured final : public Iterator { private: // -- Members + std::unique_ptr container_; size_t index_; - const size_t index_size_; - - const std::vector& longitudes_; - const std::vector& latitudes_; + const size_t size_; const std::string uid_; // -- Methods From 39580d6b70084b0fc46f618b9310975a2c9ee5d0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 00:58:19 +0100 Subject: [PATCH 584/737] eckit::geo::Grid --- src/eckit/geo/Grid.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index c96f52a7e..8bd0e5d53 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -24,6 +24,7 @@ #include "eckit/geo/util/mutex.h" #include "eckit/log/Log.h" #include "eckit/parser/YAMLParser.h" +#include "eckit/utils/MD5.h" namespace eckit::geo { @@ -58,7 +59,7 @@ size_t Grid::size() const { Grid::uid_t Grid::uid() const { - throw NotImplemented("Grid::uid", Here()); + return MD5(spec()); } From 9fd7db094311bd3aac68e7204562049fe777e432 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 01:13:02 +0100 Subject: [PATCH 585/737] eckit::geo::Grid --- src/eckit/geo/grid/Unstructured.cc | 12 ---- src/eckit/geo/grid/Unstructured.h | 69 ------------------- .../grid/unstructured/UnstructuredFromGrid.cc | 45 ++---------- .../grid/unstructured/UnstructuredFromGrid.h | 14 ++-- 4 files changed, 8 insertions(+), 132 deletions(-) diff --git a/src/eckit/geo/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc index d25d15328..2169c54f9 100644 --- a/src/eckit/geo/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -12,22 +12,10 @@ #include "eckit/geo/grid/Unstructured.h" -#include "eckit/geo/iterator/Unstructured.h" - namespace eckit::geo::grid { -Grid::iterator Unstructured::cbegin() const { - return iterator{new geo::iterator::Unstructured(*this)}; -} - - -Grid::iterator Unstructured::cend() const { - return iterator{new geo::iterator::Unstructured(*this, size())}; -} - - Unstructured::Unstructured(const Spec& spec) : Grid(spec) {} diff --git a/src/eckit/geo/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h index 9aa38ec01..2f3125f19 100644 --- a/src/eckit/geo/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -24,80 +24,11 @@ namespace eckit::geo::grid { class Unstructured : public Grid { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - // None - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - - iterator cbegin() const override; - iterator cend() const override; - - // -- Class members - // None - - // -- Class methods - // None - protected: - // -- Constructors - explicit Unstructured(const Spec&); explicit Unstructured(const area::BoundingBox&); - // -- Members - // None - - // -- Methods - - virtual const std::vector& longitudes() const = 0; - virtual const std::vector& latitudes() const = 0; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - friend class geo::iterator::Unstructured; }; diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc index b842a989d..3775e0b45 100644 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc @@ -20,54 +20,17 @@ namespace eckit::geo::grid::unstructured { -namespace { - - -std::vector points_lat(const std::vector& points) { - std::vector l(points.size()); - std::transform(points.begin(), points.end(), l.begin(), [](const Point& p) { - return std::get(p).lat; - }); - return l; -} - - -std::vector points_lon(const std::vector& points) { - std::vector l(points.size()); - std::transform(points.begin(), points.end(), l.begin(), [](const Point& p) { - return std::get(p).lon; - }); - return l; -} - - -} // namespace - - -UnstructuredFromGrid::UnstructuredFromGrid(const std::vector& points) : - Unstructured(area::BoundingBox::make_global_prime()), - latitudes_(points_lat(points)), - longitudes_(points_lon(points)) { - ASSERT(size() > 0); -} +UnstructuredFromGrid::UnstructuredFromGrid(std::vector&& points) : + Unstructured(area::BoundingBox::make_global_prime()), points_(points) {} Grid::iterator UnstructuredFromGrid::cbegin() const { - return iterator{new geo::iterator::Unstructured(*this, 0)}; + return iterator{new geo::iterator::Unstructured(*this, 0, points_)}; } Grid::iterator UnstructuredFromGrid::cend() const { - return iterator{new geo::iterator::Unstructured(*this, size())}; -} - - -std::vector UnstructuredFromGrid::to_points() const { - std::vector p; - for (size_t i = 0; i < size(); ++i) { - p[i] = PointLonLat{longitudes_[i], latitudes_[i]}; - } - return p; + return iterator{new geo::iterator::Unstructured(*this)}; } diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h index 569db4435..702a7f4c3 100644 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h @@ -13,7 +13,6 @@ #pragma once #include -#include #include "eckit/geo/grid/Unstructured.h" @@ -36,7 +35,7 @@ class UnstructuredFromGrid final : public Unstructured { // -- Constructors - explicit UnstructuredFromGrid(const std::vector&); + explicit UnstructuredFromGrid(std::vector&&); // -- Destructor // None @@ -55,18 +54,14 @@ class UnstructuredFromGrid final : public Unstructured { iterator cbegin() const override; iterator cend() const override; - size_t size() const override { return latitudes_.size(); } + size_t size() const override { return points_.size(); } uid_t uid() const override; bool includesNorthPole() const override { return true; } bool includesSouthPole() const override { return true; } bool isPeriodicWestEast() const override { return true; } - std::vector to_points() const override; - std::pair, std::vector> to_latlon() const override { return {latitudes_, longitudes_}; } - - const std::vector& longitudes() const override { return longitudes_; } - const std::vector& latitudes() const override { return latitudes_; } + std::vector to_points() const override { return points_; } // -- Class members // None @@ -78,8 +73,7 @@ class UnstructuredFromGrid final : public Unstructured { private: // -- Members - mutable std::vector latitudes_; - mutable std::vector longitudes_; + const std::vector points_; // -- Methods // None From a4ef42bb311b9adee5b8a3807e780214c5cc35f1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 01:24:24 +0100 Subject: [PATCH 586/737] eckit::geo::Grid --- src/eckit/geo/CMakeLists.txt | 2 +- .../geo/grid/{unstructured => regular}/ORCA.cc | 8 ++++---- .../geo/grid/{unstructured => regular}/ORCA.h | 16 +++++++++------- 3 files changed, 14 insertions(+), 12 deletions(-) rename src/eckit/geo/grid/{unstructured => regular}/ORCA.cc (98%) rename src/eckit/geo/grid/{unstructured => regular}/ORCA.h (86%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index feed21e88..128f62ee8 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -145,7 +145,7 @@ if(eckit_HAVE_PROJ) endif() if(eckit_HAVE_ECKIT_CODEC) - list(APPEND eckit_geo_srcs grid/unstructured/ORCA.cc grid/unstructured/ORCA.h) + list(APPEND eckit_geo_srcs grid/regular/ORCA.cc grid/regular/ORCA.h) list(APPEND eckit_geo_libs eckit_codec) endif() diff --git a/src/eckit/geo/grid/unstructured/ORCA.cc b/src/eckit/geo/grid/regular/ORCA.cc similarity index 98% rename from src/eckit/geo/grid/unstructured/ORCA.cc rename to src/eckit/geo/grid/regular/ORCA.cc index cd991e09e..d3ef81ecd 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.cc +++ b/src/eckit/geo/grid/regular/ORCA.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/unstructured/ORCA.h" +#include "eckit/geo/grid/regular/ORCA.h" #include @@ -37,7 +37,7 @@ #endif -namespace eckit::geo::grid::unstructured { +namespace eckit::geo::grid::regular { namespace { @@ -137,7 +137,7 @@ const ORCA::ORCARecord& orca_record(const PathName& p, const Spec& spec) { ORCA::ORCA(const Spec& spec) : - Unstructured(spec), + Regular(spec), name_(spec.get_string("orca_name")), uid_(spec.get_string("orca_uid")), arrangement_(arrangement_from_string(spec.get_string("orca_arrangement"))), @@ -337,4 +337,4 @@ static const GridRegisterType __grid_type("ORCA"); static const GridRegisterName __grid_pattern(GridRegisterName::uid_pattern); -} // namespace eckit::geo::grid::unstructured +} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/grid/unstructured/ORCA.h b/src/eckit/geo/grid/regular/ORCA.h similarity index 86% rename from src/eckit/geo/grid/unstructured/ORCA.h rename to src/eckit/geo/grid/regular/ORCA.h index a08fbd40b..ca8e40fa0 100644 --- a/src/eckit/geo/grid/unstructured/ORCA.h +++ b/src/eckit/geo/grid/regular/ORCA.h @@ -16,7 +16,7 @@ #include #include -#include "eckit/geo/grid/Unstructured.h" +#include "eckit/geo/grid/Regular.h" namespace eckit { @@ -24,10 +24,10 @@ class PathName; } -namespace eckit::geo::grid::unstructured { +namespace eckit::geo::grid::regular { -class ORCA final : public Unstructured { +class ORCA final : public Regular { public: // -- Types @@ -82,8 +82,8 @@ class ORCA final : public Unstructured { // -- Methods - size_t ni() const { return record_.ni(); } - size_t nj() const { return record_.nj(); } + size_t ni() const override { return record_.ni(); } + size_t nj() const override { return record_.nj(); } std::string name() const { return name_; } std::string arrangement() const; @@ -97,7 +97,6 @@ class ORCA final : public Unstructured { area::BoundingBox boundingBox() const override; - size_t size() const override { return ni() * nj(); } uid_t uid() const override { return uid_; } bool includesNorthPole() const override { return true; } @@ -107,6 +106,9 @@ class ORCA final : public Unstructured { std::vector to_points() const override; std::pair, std::vector> to_latlon() const override; + const std::vector& longitudes() const override { return record_.longitudes_; } + const std::vector& latitudes() const override { return record_.latitudes_; } + // -- Class members // None @@ -140,4 +142,4 @@ class ORCA final : public Unstructured { }; -} // namespace eckit::geo::grid::unstructured +} // namespace eckit::geo::grid::regular From b40ad79572dfee4863038c6233b310a19417dfc9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 01:49:09 +0100 Subject: [PATCH 587/737] eckit::geo::Grid --- src/eckit/geo/CMakeLists.txt | 2 - src/eckit/geo/grid/Unstructured.cc | 34 ++++++- src/eckit/geo/grid/Unstructured.h | 71 +++++++++++++- .../grid/unstructured/UnstructuredFromGrid.cc | 53 ---------- .../grid/unstructured/UnstructuredFromGrid.h | 96 ------------------- 5 files changed, 96 insertions(+), 160 deletions(-) delete mode 100644 src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc delete mode 100644 src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 128f62ee8..af81e60ea 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -77,8 +77,6 @@ list(APPEND eckit_geo_srcs grid/regular/RegularLL.h grid/regular/XYToLonLat.cc grid/regular/XYToLonLat.h - grid/unstructured/UnstructuredFromGrid.cc - grid/unstructured/UnstructuredFromGrid.h iterator/Reduced.cc iterator/Reduced.h iterator/Regular.cc diff --git a/src/eckit/geo/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc index 2169c54f9..9d5cea3b8 100644 --- a/src/eckit/geo/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -12,16 +12,42 @@ #include "eckit/geo/grid/Unstructured.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/iterator/Unstructured.h" +#include "eckit/geo/spec/Custom.h" + namespace eckit::geo::grid { -Unstructured::Unstructured(const Spec& spec) : - Grid(spec) {} +Unstructured::Unstructured(std::vector&& points) : + Grid(area::BoundingBox::make_global_prime()), points_(points) {} + + +Grid::iterator Unstructured::cbegin() const { + return iterator{new geo::iterator::Unstructured(*this, 0, points_)}; +} + + +Grid::iterator Unstructured::cend() const { + return iterator{new geo::iterator::Unstructured(*this)}; +} + + +Spec* Unstructured::spec(const std::string& name) { + return SpecByUID::instance().get(name).spec(); +} + + +void Unstructured::spec(spec::Custom& custom) const { + custom.set("type", "unstructured"); + custom.set("uid", uid()); +} -Unstructured::Unstructured(const area::BoundingBox& bbox) : - Grid(bbox) {} +Grid::uid_t Unstructured::uid() const { + NOTIMP; +} } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h index 2f3125f19..e7a04b1f0 100644 --- a/src/eckit/geo/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -1,4 +1,4 @@ -/* +/* * (C) Copyright 1996- ECMWF. * * This software is licensed under the terms of the Apache Licence Version 2.0 @@ -12,6 +12,8 @@ #pragma once +#include + #include "eckit/geo/Grid.h" @@ -23,12 +25,71 @@ class Unstructured; namespace eckit::geo::grid { -class Unstructured : public Grid { -protected: - explicit Unstructured(const Spec&); - explicit Unstructured(const area::BoundingBox&); +class Unstructured final : public Grid { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit Unstructured(std::vector&&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + iterator cbegin() const override; + iterator cend() const override; + + size_t size() const override { return points_.size(); } + uid_t uid() const override; + + bool includesNorthPole() const override { return true; } + bool includesSouthPole() const override { return true; } + bool isPeriodicWestEast() const override { return true; } + + std::vector to_points() const override { return points_; } + + // -- Class members + // None + + // -- Class methods + + static Spec* spec(const std::string& name); private: + // -- Members + + const std::vector points_; + + // -- Methods + // None + + // -- Overridden methods + + void spec(spec::Custom&) const override; + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + friend class geo::iterator::Unstructured; }; diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc deleted file mode 100644 index 3775e0b45..000000000 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc +++ /dev/null @@ -1,53 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/unstructured/UnstructuredFromGrid.h" - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/iterator/Unstructured.h" -#include "eckit/geo/spec/Custom.h" - - -namespace eckit::geo::grid::unstructured { - - -UnstructuredFromGrid::UnstructuredFromGrid(std::vector&& points) : - Unstructured(area::BoundingBox::make_global_prime()), points_(points) {} - - -Grid::iterator UnstructuredFromGrid::cbegin() const { - return iterator{new geo::iterator::Unstructured(*this, 0, points_)}; -} - - -Grid::iterator UnstructuredFromGrid::cend() const { - return iterator{new geo::iterator::Unstructured(*this)}; -} - - -Spec* UnstructuredFromGrid::spec(const std::string& name) { - return SpecByUID::instance().get(name).spec(); -} - - -void UnstructuredFromGrid::spec(spec::Custom& custom) const { - custom.set("type", "unstructured"); - custom.set("uid", uid()); -} - - -Grid::uid_t UnstructuredFromGrid::uid() const { - NOTIMP; -} - - -} // namespace eckit::geo::grid::unstructured diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h deleted file mode 100644 index 702a7f4c3..000000000 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include - -#include "eckit/geo/grid/Unstructured.h" - - -namespace eckit { -class PathName; -} - - -namespace eckit::geo::grid::unstructured { - - -class UnstructuredFromGrid final : public Unstructured { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit UnstructuredFromGrid(std::vector&&); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - - iterator cbegin() const override; - iterator cend() const override; - - size_t size() const override { return points_.size(); } - uid_t uid() const override; - - bool includesNorthPole() const override { return true; } - bool includesSouthPole() const override { return true; } - bool isPeriodicWestEast() const override { return true; } - - std::vector to_points() const override { return points_; } - - // -- Class members - // None - - // -- Class methods - - static Spec* spec(const std::string& name); - -private: - // -- Members - - const std::vector points_; - - // -- Methods - // None - - // -- Overridden methods - - void spec(spec::Custom&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid::unstructured From 9c8eec72df76c004bb2af7c933c932fbf7de6915 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 01:49:26 +0100 Subject: [PATCH 588/737] Cleanup --- .../geo/grid/reduced-global/ReducedGaussian.cc | 2 +- src/eckit/geo/grid/regular/RegularGaussian.cc | 2 +- src/eckit/geo/iterator/Reduced.cc | 17 ++++++++--------- src/eckit/geo/iterator/Reduced.h | 2 +- src/eckit/geo/iterator/Regular.cc | 8 ++++---- src/eckit/geo/iterator/Regular.h | 2 +- src/eckit/geo/iterator/Unstructured.h | 10 +++++++++- 7 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc b/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc index e138dd376..64e20761b 100644 --- a/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc +++ b/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc @@ -128,7 +128,7 @@ Grid* ReducedGaussian::make_grid_cropped(const area::BoundingBox& crop) const { return new ReducedGaussian(pl_, bbox); } - throw eckit::Exception("RegularGaussian: cannot crop grid (empty intersection)"); + throw Exception("ReducedGaussian: cannot crop grid (empty intersection)"); } diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/regular/RegularGaussian.cc index c5a876d74..c80d507b3 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/regular/RegularGaussian.cc @@ -74,7 +74,7 @@ Grid* RegularGaussian::make_grid_cropped(const area::BoundingBox& crop) const { return new RegularGaussian(N_, bbox); } - throw eckit::Exception("RegularGaussian: cannot crop grid (empty intersection)"); + throw Exception("RegularGaussian: cannot crop grid (empty intersection)"); } diff --git a/src/eckit/geo/iterator/Reduced.cc b/src/eckit/geo/iterator/Reduced.cc index 1e9e685a8..cb5d5dc14 100644 --- a/src/eckit/geo/iterator/Reduced.cc +++ b/src/eckit/geo/iterator/Reduced.cc @@ -27,8 +27,8 @@ Reduced::Reduced(const Grid& grid, size_t index) : latitudes_(grid_.latitudes()), niacc_(grid_.niacc()), index_(index), - index_size_(grid.size()) { - if (index_ < index_size_) { + size_(grid.size()) { + if (index_ < size_) { longitudes_j_ = grid_.longitudes(j_ = j(index_)); ASSERT(niacc_[j_] <= index && index_ < niacc_[j_ + 1]); ASSERT(latitudes_.size() == grid_.nj()); @@ -43,7 +43,7 @@ bool Reduced::operator==(const Iterator& other) const { bool Reduced::operator++() { - if (index_++; index_ < index_size_) { + if (index_++; index_ < size_) { if (!(index_ < niacc_[j_ + 1])) { longitudes_j_ = grid_.longitudes(++j_); } @@ -52,14 +52,13 @@ bool Reduced::operator++() { return true; } - index_ = index_size_; // ensure it's invalid + index_ = size_; // ensure it's invalid return false; } bool Reduced::operator+=(difference_type d) { - if (auto di = static_cast(index_); - 0 <= di + d && di + d < static_cast(index_size_)) { + if (auto di = static_cast(index_); 0 <= di + d && di + d < static_cast(size_)) { if (index_ = static_cast(di + d); !(niacc_[j_] <= index_ && index_ < niacc_[j_ + 1])) { longitudes_j_ = grid_.longitudes(j_ = j(index_)); } @@ -68,13 +67,13 @@ bool Reduced::operator+=(difference_type d) { return true; } - index_ = index_size_; // ensure it's invalid + index_ = size_; // ensure it's invalid return false; } Reduced::operator bool() const { - return index_ < index_size_; + return index_ < size_; } @@ -84,7 +83,7 @@ Point Reduced::operator*() const { size_t Reduced::j(size_t idx) const { - ASSERT(idx < index_size_); + ASSERT(idx < size_); auto dist = std::distance(niacc_.begin(), std::upper_bound(niacc_.begin(), niacc_.end(), idx)); ASSERT(1 <= dist && dist <= niacc_.size() - 1); diff --git a/src/eckit/geo/iterator/Reduced.h b/src/eckit/geo/iterator/Reduced.h index 1c125c9c6..1712a7b15 100644 --- a/src/eckit/geo/iterator/Reduced.h +++ b/src/eckit/geo/iterator/Reduced.h @@ -67,7 +67,7 @@ class Reduced final : public geo::Iterator { const std::vector& niacc_; size_t j_; size_t index_; - const size_t index_size_; + const size_t size_; // -- Methods // None diff --git a/src/eckit/geo/iterator/Regular.cc b/src/eckit/geo/iterator/Regular.cc index 7140b1505..eab916b3a 100644 --- a/src/eckit/geo/iterator/Regular.cc +++ b/src/eckit/geo/iterator/Regular.cc @@ -28,7 +28,7 @@ Regular::Regular(const Grid& grid, size_t index) : index_(index), ni_(longitudes_.size()), nj_(latitudes_.size()), - index_size_(ni_ * nj_) { + size_(ni_ * nj_) { ASSERT(longitudes_.size() == grid_.ni()); ASSERT(latitudes_.size() == grid_.nj()); } @@ -41,7 +41,7 @@ bool Regular::operator==(const Iterator& other) const { bool Regular::operator++() { - if (index_++, i_++; index_ < index_size_) { + if (index_++, i_++; index_ < size_) { if (i_ >= ni_) { i_ = 0; j_++; @@ -50,7 +50,7 @@ bool Regular::operator++() { return true; } - index_ = index_size_; // ensure it's invalid + index_ = size_; // ensure it's invalid return false; } @@ -61,7 +61,7 @@ bool Regular::operator+=(difference_type d) { Regular::operator bool() const { - return index_ < index_size_; + return index_ < size_; } diff --git a/src/eckit/geo/iterator/Regular.h b/src/eckit/geo/iterator/Regular.h index 6756d207c..1bb3f5417 100644 --- a/src/eckit/geo/iterator/Regular.h +++ b/src/eckit/geo/iterator/Regular.h @@ -67,7 +67,7 @@ class Regular final : public Iterator { size_t index_; const size_t ni_; const size_t nj_; - const size_t index_size_; + const size_t size_; // -- Methods // None diff --git a/src/eckit/geo/iterator/Unstructured.h b/src/eckit/geo/iterator/Unstructured.h index 2856927c7..ff1a9f790 100644 --- a/src/eckit/geo/iterator/Unstructured.h +++ b/src/eckit/geo/iterator/Unstructured.h @@ -26,7 +26,15 @@ class Unstructured final : public Iterator { // -- Types struct Container { - virtual ~Container() = default; + Container() = default; + virtual ~Container() = default; + + Container(const Container&) = delete; + Container(Container&&) = delete; + + Container& operator=(const Container&) = delete; + Container& operator=(Container&&) = delete; + virtual Point get(size_t index) const = 0; virtual size_t size() const = 0; }; From 07b4c6d0a04433a27e2f16c815bab10451b7e675 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 01:51:54 +0100 Subject: [PATCH 589/737] eckit::geo::Grid --- src/eckit/geo/grid/regular/ORCA.cc | 1 + tests/geo/grid_orca.cc | 10 ++++++---- tests/geo/spec.cc | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/eckit/geo/grid/regular/ORCA.cc b/src/eckit/geo/grid/regular/ORCA.cc index d3ef81ecd..a0309f224 100644 --- a/src/eckit/geo/grid/regular/ORCA.cc +++ b/src/eckit/geo/grid/regular/ORCA.cc @@ -329,6 +329,7 @@ Spec* ORCA::spec(const std::string& name) { void ORCA::spec(spec::Custom& custom) const { + custom.set("type", "ORCA"); custom.set("uid", uid_); } diff --git a/tests/geo/grid_orca.cc b/tests/geo/grid_orca.cc index 6820daf84..0f7bd5b09 100644 --- a/tests/geo/grid_orca.cc +++ b/tests/geo/grid_orca.cc @@ -51,7 +51,7 @@ CASE("ORCA") { EXPECT(grid3.uid() == uid); EXPECT(grid3.calculate_uid() == uid); - EXPECT(static_cast(grid3).spec() == R"({"uid":")" + uid + R"("})"); + EXPECT(static_cast(grid3).spec() == R"({"type":"ORCA","uid":")" + uid + R"("})"); EXPECT(grid1->spec() == grid2->spec()); } @@ -60,11 +60,13 @@ CASE("ORCA") { SECTION("equals") { std::unique_ptr grid1(GridFactory::make_from_string("{uid:" + uid + "}")); std::unique_ptr grid2(GridFactory::build(spec::Custom({{"uid", uid}}))); - ORCA grid3(uid); + std::unique_ptr grid3(GridFactory::build(spec::Custom({{"grid", uid}}))); + ORCA grid4(uid); EXPECT(*grid1 == *grid2); - EXPECT(*grid2 == grid3); - EXPECT(grid3 == *grid1); + EXPECT(*grid2 == *grid3); + EXPECT(*grid3 == grid4); + EXPECT(grid4 == *grid1); } } diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 9d8396732..4476c9424 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -365,7 +365,7 @@ CASE("spec") { std::unique_ptr o1(GridFactory::build(spec::Custom({{"grid", "ORCA2_T"}}))); - EXPECT(o1->spec() == R"({"uid":")" + uid + R"("})"); + EXPECT(o1->spec() == R"({"type":"ORCA","uid":")" + uid + R"("})"); std::unique_ptr o2(GridFactory::build(spec::Custom({{"uid", uid}}))); From ba8bde52e4b9aba81416f6ce2442ed9a9843993d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 10:19:50 +0100 Subject: [PATCH 590/737] eckit::geo::Grid --- src/eckit/geo/LibEcKitGeo.cc | 9 ++++++--- src/eckit/geo/LibEcKitGeo.h | 4 +++- src/eckit/geo/etc/Grid.cc | 18 +++++++++++++++++- src/eckit/geo/etc/Grid.h | 6 ++++-- 4 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/eckit/geo/LibEcKitGeo.cc b/src/eckit/geo/LibEcKitGeo.cc index 0c2f06038..a5b541693 100644 --- a/src/eckit/geo/LibEcKitGeo.cc +++ b/src/eckit/geo/LibEcKitGeo.cc @@ -16,6 +16,7 @@ #include "eckit/eckit_version.h" #include "eckit/filesystem/PathName.h" #include "eckit/geo/eckit_geo_config.h" +#include "eckit/utils/StringTools.h" namespace eckit { @@ -34,9 +35,11 @@ LibEcKitGeo& LibEcKitGeo::instance() { } -PathName LibEcKitGeo::etcGrid() { - static const PathName path{ - LibResource("eckit-geo-grid;$ECKIT_GEO_GRID", "~eckit/etc/eckit/geo/grid.yaml")}; +std::vector LibEcKitGeo::etcGrid() { + static const auto paths = [](const std::string& s) -> std::vector { + const auto ss = StringTools::split(":", s); + return {ss.begin(), ss.end()}; + }(LibResource("eckit-geo-grid;$ECKIT_GEO_GRID", "~eckit/etc/eckit/geo/grid.yaml")}; return path; } diff --git a/src/eckit/geo/LibEcKitGeo.h b/src/eckit/geo/LibEcKitGeo.h index c1ad1b9d9..1ee3897fa 100644 --- a/src/eckit/geo/LibEcKitGeo.h +++ b/src/eckit/geo/LibEcKitGeo.h @@ -12,6 +12,8 @@ #pragma once +#include + #include "eckit/system/Library.h" @@ -47,7 +49,7 @@ class LibEcKitGeo final : public system::Library { static LibEcKitGeo& instance(); - static eckit::PathName etcGrid(); + static std::vector etcGrid(); static bool caching(); static std::string cacheDir(); diff --git a/src/eckit/geo/etc/Grid.cc b/src/eckit/geo/etc/Grid.cc index aa56c7f2a..5471faf54 100644 --- a/src/eckit/geo/etc/Grid.cc +++ b/src/eckit/geo/etc/Grid.cc @@ -75,10 +75,26 @@ const Grid& Grid::instance() { } -Grid::Grid(const PathName& path) { +Grid::Grid(const std::vector& paths) { auto* custom = new spec::Custom; spec_.reset(custom); + for (const auto& path : paths) { + if (path.exists()) { + load(path); + } + } +} + + +void Grid::load(const PathName& path) { + if (!spec_) { + spec_.reset(new spec::Custom); + } + + auto* custom = dynamic_cast(spec_.get()); + ASSERT(custom != nullptr); + struct SpecByUIDGenerator final : SpecByUID::generator_t { explicit SpecByUIDGenerator(spec::Custom* spec) : spec_(spec) {} diff --git a/src/eckit/geo/etc/Grid.h b/src/eckit/geo/etc/Grid.h index a85aebd15..17bf396dd 100644 --- a/src/eckit/geo/etc/Grid.h +++ b/src/eckit/geo/etc/Grid.h @@ -13,6 +13,7 @@ #pragma once #include +#include namespace eckit { @@ -64,14 +65,15 @@ class Grid final { private: // -- Constructors - explicit Grid(const PathName&); + explicit Grid(const std::vector&); // -- Members std::unique_ptr spec_; // -- Methods - // None + + void load(const PathName&); // -- Overridden methods // None From 6e976615be486f556e099e2d13948d50ed8a979e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 10:20:07 +0100 Subject: [PATCH 591/737] eckit::geo::Grid --- etc/eckit/geo/ORCA.yaml | 359 +++++++++++++++++++++++++++++++++++ etc/eckit/geo/grid.yaml | 356 ---------------------------------- src/eckit/geo/LibEcKitGeo.cc | 6 +- 3 files changed, 363 insertions(+), 358 deletions(-) create mode 100644 etc/eckit/geo/ORCA.yaml diff --git a/etc/eckit/geo/ORCA.yaml b/etc/eckit/geo/ORCA.yaml new file mode 100644 index 000000000..a94395f12 --- /dev/null +++ b/etc/eckit/geo/ORCA.yaml @@ -0,0 +1,359 @@ +--- + +orca_url_prefix: &orca_url_prefix https://get.ecmwf.int/repository/atlas/grids/orca/v0/ +orca_validate_uid: false # Validates UID upon grid creation +orca_compute_uid: false # Recompute UID and ignore encoded UID + +grid_names: + - ORCA2_F: &ORCA2_F + type: ORCA + orca_arrangement: F + orca_name: ORCA2 + dimensions: [182, 149] + orca_uid: "174487fbace54b00d959d971e88b71e7" + url_prefix: *orca_url_prefix + url: ORCA2_F.atlas + + - ORCA2_T: &ORCA2_T + type: ORCA + orca_arrangement: T + orca_name: ORCA2 + dimensions: [182, 149] + orca_uid: "d5bde4f52ff3a9bea5629cd9ac514410" + url_prefix: *orca_url_prefix + url: ORCA2_T.atlas + + - ORCA2_U: &ORCA2_U + type: ORCA + orca_arrangement: U + orca_name: ORCA2 + dimensions: [182, 149] + orca_uid: "857f7affa3a381e3882d38d321384e49" + url_prefix: *orca_url_prefix + url: ORCA2_U.atlas + + - ORCA2_V: &ORCA2_V + type: ORCA + orca_arrangement: V + orca_name: ORCA2 + dimensions: [182, 149] + orca_uid: "ca637bc5dc9a54e2ea4b9750e1b79e6e" + url_prefix: *orca_url_prefix + url: ORCA2_V.atlas + + - ORCA2_W: &ORCA2_W + type: ORCA + orca_arrangement: W + orca_name: ORCA2 + dimensions: [182, 149] + orca_uid: "edea6f71eb558dc056b5f576d5b904f7" + url_prefix: *orca_url_prefix + url: ORCA2_T.atlas + + - ORCA1_F: &ORCA1_F + type: ORCA + orca_arrangement: F + orca_name: ORCA1 + dimensions: [362, 292] + orca_uid: "a832a12030c73928133553ec3a8d2a7e" + url_prefix: *orca_url_prefix + url: ORCA1_F.atlas + + - ORCA1_T: &ORCA1_T + type: ORCA + orca_arrangement: T + orca_name: ORCA1 + dimensions: [362, 292] + orca_uid: "f4c91b6233fe55dec992160ec12b38df" + url_prefix: *orca_url_prefix + url: ORCA1_T.atlas + + - ORCA1_U: &ORCA1_U + type: ORCA + orca_arrangement: U + orca_name: ORCA1 + dimensions: [362, 292] + orca_uid: "1b0f8d234753f910197c975c906b4da5" + url_prefix: *orca_url_prefix + url: ORCA1_U.atlas + + - ORCA1_V: &ORCA1_V + type: ORCA + orca_arrangement: V + orca_name: ORCA1 + dimensions: [362, 292] + orca_uid: "c637340454795b395f982851b840943d" + url_prefix: *orca_url_prefix + url: ORCA1_V.atlas + + - ORCA1_W: &ORCA1_W + type: ORCA + orca_arrangement: W + orca_name: ORCA1 + dimensions: [362, 292] + orca_uid: "d50061c43e83c46c3810002591ea21e1" + url_prefix: *orca_url_prefix + url: ORCA1_T.atlas + + - eORCA1_F: &eORCA1_F + type: ORCA + orca_arrangement: F + orca_name: eORCA1 + dimensions: [362, 332] + orca_uid: "3c6d95561710c6f39b394809ff6c588c" + url_prefix: *orca_url_prefix + url: eORCA1_F.atlas + + - eORCA1_T: &eORCA1_T + type: ORCA + orca_arrangement: T + orca_name: eORCA1 + dimensions: [362, 332] + orca_uid: "ba65665a9e68d1a8fa0352ecfcf8e496" + url_prefix: *orca_url_prefix + url: eORCA1_T.atlas + + - eORCA1_U: &eORCA1_U + type: ORCA + orca_arrangement: U + orca_name: eORCA1 + dimensions: [362, 332] + orca_uid: "4eb1054957dcae914e219faf9a4068e3" + url_prefix: *orca_url_prefix + url: eORCA1_U.atlas + + - eORCA1_V: &eORCA1_V + type: ORCA + orca_arrangement: V + orca_name: eORCA1 + dimensions: [362, 332] + orca_uid: "09131429766e7737c087d3a8d7073dc9" + url_prefix: *orca_url_prefix + url: eORCA1_V.atlas + + - eORCA1_W: &eORCA1_W + type: ORCA + orca_arrangement: W + orca_name: eORCA1 + dimensions: [362, 332] + orca_uid: "5c678d8f9aa2edfbf57246d11d9c1278" + url_prefix: *orca_url_prefix + url: eORCA1_T.atlas + + - ORCA025_F: &ORCA025_F + type: ORCA + orca_arrangement: F + orca_name: ORCA025 + dimensions: [1442, 1021] + orca_uid: "efbc280d8d4b6048797880da2605bacb" + url_prefix: *orca_url_prefix + url: ORCA025_F.atlas + + - ORCA025_T: &ORCA025_T + type: ORCA + orca_arrangement: T + orca_name: ORCA025 + dimensions: [1442, 1021] + orca_uid: "15c961c269ac182ca226d7195f3921ba" + url_prefix: *orca_url_prefix + url: ORCA025_T.atlas + + - ORCA025_U: &ORCA025_U + type: ORCA + orca_arrangement: U + orca_name: ORCA025 + dimensions: [1442, 1021] + orca_uid: "3f4a68bc5b54c9f867fbcc12aacc723d" + url_prefix: *orca_url_prefix + url: ORCA025_U.atlas + + - ORCA025_V: &ORCA025_V + type: ORCA + orca_arrangement: V + orca_name: ORCA025 + dimensions: [1442, 1021] + orca_uid: "9c87699ee2026c0feee07d2a972eaccd" + url_prefix: *orca_url_prefix + url: ORCA025_V.atlas + + - ORCA025_W: &ORCA025_W + type: ORCA + orca_arrangement: W + orca_name: ORCA025 + dimensions: [1442, 1021] + orca_uid: "74ca68f1c8524811f3d3aad99536adc2" + url_prefix: *orca_url_prefix + url: ORCA025_T.atlas + + - eORCA025_F: &eORCA025_F + type: ORCA + orca_arrangement: F + orca_name: eORCA025 + dimensions: [1442, 1207] + orca_uid: "770e5bbb667a253d55db8a98a3b2d3a9" + url_prefix: *orca_url_prefix + url: eORCA025_F.atlas + + - eORCA025_T: &eORCA025_T + type: ORCA + orca_arrangement: T + orca_name: eORCA025 + dimensions: [1442, 1207] + orca_uid: "983412216c9768bc794c18dc92082895" + url_prefix: *orca_url_prefix + url: eORCA025_T.atlas + + - eORCA025_U: &eORCA025_U + type: ORCA + orca_arrangement: U + orca_name: eORCA025 + dimensions: [1442, 1207] + orca_uid: "b1b2922e9b57ee9c6eeddad218b6e4f3" + url_prefix: *orca_url_prefix + url: eORCA025_U.atlas + + - eORCA025_V: &eORCA025_V + type: ORCA + orca_arrangement: V + orca_name: eORCA025 + dimensions: [1442, 1207] + orca_uid: "9b06bf73a8f14e927bd9b0f1f0c04f74" + url_prefix: *orca_url_prefix + url: eORCA025_V.atlas + + - eORCA025_W: &eORCA025_W + type: ORCA + orca_arrangement: W + orca_name: eORCA025 + dimensions: [1442, 1207] + orca_uid: "4a1ba3b11b8888aefc96992b6b1cab62" + url_prefix: *orca_url_prefix + url: eORCA025_T.atlas + + - ORCA12_F: &ORCA12_F + type: ORCA + orca_arrangement: F + orca_name: ORCA12 + dimensions: [4322, 3059] + orca_uid: "29693ad8a7af3ae3ee0f02d090f0ec7b" + url_prefix: *orca_url_prefix + url: ORCA12_F.atlas + + - ORCA12_T: &ORCA12_T + type: ORCA + orca_arrangement: T + orca_name: ORCA12 + dimensions: [4322, 3059] + orca_uid: "b117d01170ac77bca68560ab10e559de" + url_prefix: *orca_url_prefix + url: ORCA12_T.atlas + + - ORCA12_U: &ORCA12_U + type: ORCA + orca_arrangement: U + orca_name: ORCA12 + dimensions: [4322, 3059] + orca_uid: "fff193b92d94d03e847ff2fa62b493f4" + url_prefix: *orca_url_prefix + url: ORCA12_U.atlas + + - ORCA12_V: &ORCA12_V + type: ORCA + orca_arrangement: V + orca_name: ORCA12 + dimensions: [4322, 3059] + orca_uid: "986e3450774b716f6e75c1987e370b10" + url_prefix: *orca_url_prefix + url: ORCA12_V.atlas + + - ORCA12_W: &ORCA12_W + type: ORCA + orca_arrangement: W + orca_name: ORCA12 + dimensions: [4322, 3059] + orca_uid: "ccfe953619a8dd49a7f765923882a274" + url_prefix: *orca_url_prefix + url: ORCA12_T.atlas + + - eORCA12_F: &eORCA12_F + type: ORCA + orca_arrangement: F + orca_name: eORCA12 + dimensions: [4322, 3606] + orca_uid: "25da53ed581b3931fa310840fa9aefd9" + url_prefix: *orca_url_prefix + url: eORCA12_F.atlas + + - eORCA12_T: &eORCA12_T + type: ORCA + orca_arrangement: T + orca_name: eORCA12 + dimensions: [4322, 3606] + orca_uid: "1553b66f5885cf5f83ad4b4fdf25f460" + url_prefix: *orca_url_prefix + url: eORCA12_T.atlas + + - eORCA12_U: &eORCA12_U + type: ORCA + orca_arrangement: U + orca_name: eORCA12 + dimensions: [4322, 3606] + orca_uid: "3e87c826643da440b4e9d9f67588a576" + url_prefix: *orca_url_prefix + url: eORCA12_U.atlas + + - eORCA12_V: &eORCA12_V + type: ORCA + orca_arrangement: V + orca_name: eORCA12 + dimensions: [4322, 3606] + orca_uid: "cc1e3fc06a2cd18c0653e557510b8a71" + url_prefix: *orca_url_prefix + url: eORCA12_V.atlas + + - eORCA12_W: &eORCA12_W + type: ORCA + orca_arrangement: W + orca_name: eORCA12 + dimensions: [4322, 3606] + orca_uid: "462469edbd0e0586a0cf17424cc58c89" + url_prefix: *orca_url_prefix + url: eORCA12_T.atlas + +grid_uids: + - 174487fbace54b00d959d971e88b71e7: *ORCA2_F + - d5bde4f52ff3a9bea5629cd9ac514410: *ORCA2_T + - 857f7affa3a381e3882d38d321384e49: *ORCA2_U + - ca637bc5dc9a54e2ea4b9750e1b79e6e: *ORCA2_V + - edea6f71eb558dc056b5f576d5b904f7: *ORCA2_W + - a832a12030c73928133553ec3a8d2a7e: *ORCA1_F + - f4c91b6233fe55dec992160ec12b38df: *ORCA1_T + - 1b0f8d234753f910197c975c906b4da5: *ORCA1_U + - c637340454795b395f982851b840943d: *ORCA1_V + - d50061c43e83c46c3810002591ea21e1: *ORCA1_W + - 3c6d95561710c6f39b394809ff6c588c: *eORCA1_F + - ba65665a9e68d1a8fa0352ecfcf8e496: *eORCA1_T + - 4eb1054957dcae914e219faf9a4068e3: *eORCA1_U + - 09131429766e7737c087d3a8d7073dc9: *eORCA1_V + - 5c678d8f9aa2edfbf57246d11d9c1278: *eORCA1_W + - efbc280d8d4b6048797880da2605bacb: *ORCA025_F + - 15c961c269ac182ca226d7195f3921ba: *ORCA025_T + - 3f4a68bc5b54c9f867fbcc12aacc723d: *ORCA025_U + - 9c87699ee2026c0feee07d2a972eaccd: *ORCA025_V + - 74ca68f1c8524811f3d3aad99536adc2: *ORCA025_W + - 770e5bbb667a253d55db8a98a3b2d3a9: *eORCA025_F + - 983412216c9768bc794c18dc92082895: *eORCA025_T + - b1b2922e9b57ee9c6eeddad218b6e4f3: *eORCA025_U + - 9b06bf73a8f14e927bd9b0f1f0c04f74: *eORCA025_V + - 4a1ba3b11b8888aefc96992b6b1cab62: *eORCA025_W + - 29693ad8a7af3ae3ee0f02d090f0ec7b: *ORCA12_F + - b117d01170ac77bca68560ab10e559de: *ORCA12_T + - fff193b92d94d03e847ff2fa62b493f4: *ORCA12_U + - 986e3450774b716f6e75c1987e370b10: *ORCA12_V + - ccfe953619a8dd49a7f765923882a274: *ORCA12_W + - 25da53ed581b3931fa310840fa9aefd9: *eORCA12_F + - 1553b66f5885cf5f83ad4b4fdf25f460: *eORCA12_T + - 3e87c826643da440b4e9d9f67588a576: *eORCA12_U + - cc1e3fc06a2cd18c0653e557510b8a71: *eORCA12_V + - 462469edbd0e0586a0cf17424cc58c89: *eORCA12_W + diff --git a/etc/eckit/geo/grid.yaml b/etc/eckit/geo/grid.yaml index 150d9fd19..8e2b0e4f2 100644 --- a/etc/eckit/geo/grid.yaml +++ b/etc/eckit/geo/grid.yaml @@ -1,9 +1,5 @@ --- -orca_url_prefix: &orca_url_prefix https://get.ecmwf.int/repository/atlas/grids/orca/v0/ -orca_validate_uid: false # Validates UID upon grid creation -orca_compute_uid: false # Recompute UID and ignore encoded UID - grid_names: - LAEA-EFAS-5km: type: lambert_azimuthal_equal_area @@ -27,355 +23,3 @@ grid_names: longitudeOfFirstGridPointInDegrees: -39.535385563614 shape: [1900, 2200] - - ORCA2_F: &ORCA2_F - type: ORCA - orca_arrangement: F - orca_name: ORCA2 - dimensions: [182, 149] - orca_uid: "174487fbace54b00d959d971e88b71e7" - url_prefix: *orca_url_prefix - url: ORCA2_F.atlas - - - ORCA2_T: &ORCA2_T - type: ORCA - orca_arrangement: T - orca_name: ORCA2 - dimensions: [182, 149] - orca_uid: "d5bde4f52ff3a9bea5629cd9ac514410" - url_prefix: *orca_url_prefix - url: ORCA2_T.atlas - - - ORCA2_U: &ORCA2_U - type: ORCA - orca_arrangement: U - orca_name: ORCA2 - dimensions: [182, 149] - orca_uid: "857f7affa3a381e3882d38d321384e49" - url_prefix: *orca_url_prefix - url: ORCA2_U.atlas - - - ORCA2_V: &ORCA2_V - type: ORCA - orca_arrangement: V - orca_name: ORCA2 - dimensions: [182, 149] - orca_uid: "ca637bc5dc9a54e2ea4b9750e1b79e6e" - url_prefix: *orca_url_prefix - url: ORCA2_V.atlas - - - ORCA2_W: &ORCA2_W - type: ORCA - orca_arrangement: W - orca_name: ORCA2 - dimensions: [182, 149] - orca_uid: "edea6f71eb558dc056b5f576d5b904f7" - url_prefix: *orca_url_prefix - url: ORCA2_T.atlas - - - ORCA1_F: &ORCA1_F - type: ORCA - orca_arrangement: F - orca_name: ORCA1 - dimensions: [362, 292] - orca_uid: "a832a12030c73928133553ec3a8d2a7e" - url_prefix: *orca_url_prefix - url: ORCA1_F.atlas - - - ORCA1_T: &ORCA1_T - type: ORCA - orca_arrangement: T - orca_name: ORCA1 - dimensions: [362, 292] - orca_uid: "f4c91b6233fe55dec992160ec12b38df" - url_prefix: *orca_url_prefix - url: ORCA1_T.atlas - - - ORCA1_U: &ORCA1_U - type: ORCA - orca_arrangement: U - orca_name: ORCA1 - dimensions: [362, 292] - orca_uid: "1b0f8d234753f910197c975c906b4da5" - url_prefix: *orca_url_prefix - url: ORCA1_U.atlas - - - ORCA1_V: &ORCA1_V - type: ORCA - orca_arrangement: V - orca_name: ORCA1 - dimensions: [362, 292] - orca_uid: "c637340454795b395f982851b840943d" - url_prefix: *orca_url_prefix - url: ORCA1_V.atlas - - - ORCA1_W: &ORCA1_W - type: ORCA - orca_arrangement: W - orca_name: ORCA1 - dimensions: [362, 292] - orca_uid: "d50061c43e83c46c3810002591ea21e1" - url_prefix: *orca_url_prefix - url: ORCA1_T.atlas - - - eORCA1_F: &eORCA1_F - type: ORCA - orca_arrangement: F - orca_name: eORCA1 - dimensions: [362, 332] - orca_uid: "3c6d95561710c6f39b394809ff6c588c" - url_prefix: *orca_url_prefix - url: eORCA1_F.atlas - - - eORCA1_T: &eORCA1_T - type: ORCA - orca_arrangement: T - orca_name: eORCA1 - dimensions: [362, 332] - orca_uid: "ba65665a9e68d1a8fa0352ecfcf8e496" - url_prefix: *orca_url_prefix - url: eORCA1_T.atlas - - - eORCA1_U: &eORCA1_U - type: ORCA - orca_arrangement: U - orca_name: eORCA1 - dimensions: [362, 332] - orca_uid: "4eb1054957dcae914e219faf9a4068e3" - url_prefix: *orca_url_prefix - url: eORCA1_U.atlas - - - eORCA1_V: &eORCA1_V - type: ORCA - orca_arrangement: V - orca_name: eORCA1 - dimensions: [362, 332] - orca_uid: "09131429766e7737c087d3a8d7073dc9" - url_prefix: *orca_url_prefix - url: eORCA1_V.atlas - - - eORCA1_W: &eORCA1_W - type: ORCA - orca_arrangement: W - orca_name: eORCA1 - dimensions: [362, 332] - orca_uid: "5c678d8f9aa2edfbf57246d11d9c1278" - url_prefix: *orca_url_prefix - url: eORCA1_T.atlas - - - ORCA025_F: &ORCA025_F - type: ORCA - orca_arrangement: F - orca_name: ORCA025 - dimensions: [1442, 1021] - orca_uid: "efbc280d8d4b6048797880da2605bacb" - url_prefix: *orca_url_prefix - url: ORCA025_F.atlas - - - ORCA025_T: &ORCA025_T - type: ORCA - orca_arrangement: T - orca_name: ORCA025 - dimensions: [1442, 1021] - orca_uid: "15c961c269ac182ca226d7195f3921ba" - url_prefix: *orca_url_prefix - url: ORCA025_T.atlas - - - ORCA025_U: &ORCA025_U - type: ORCA - orca_arrangement: U - orca_name: ORCA025 - dimensions: [1442, 1021] - orca_uid: "3f4a68bc5b54c9f867fbcc12aacc723d" - url_prefix: *orca_url_prefix - url: ORCA025_U.atlas - - - ORCA025_V: &ORCA025_V - type: ORCA - orca_arrangement: V - orca_name: ORCA025 - dimensions: [1442, 1021] - orca_uid: "9c87699ee2026c0feee07d2a972eaccd" - url_prefix: *orca_url_prefix - url: ORCA025_V.atlas - - - ORCA025_W: &ORCA025_W - type: ORCA - orca_arrangement: W - orca_name: ORCA025 - dimensions: [1442, 1021] - orca_uid: "74ca68f1c8524811f3d3aad99536adc2" - url_prefix: *orca_url_prefix - url: ORCA025_T.atlas - - - eORCA025_F: &eORCA025_F - type: ORCA - orca_arrangement: F - orca_name: eORCA025 - dimensions: [1442, 1207] - orca_uid: "770e5bbb667a253d55db8a98a3b2d3a9" - url_prefix: *orca_url_prefix - url: eORCA025_F.atlas - - - eORCA025_T: &eORCA025_T - type: ORCA - orca_arrangement: T - orca_name: eORCA025 - dimensions: [1442, 1207] - orca_uid: "983412216c9768bc794c18dc92082895" - url_prefix: *orca_url_prefix - url: eORCA025_T.atlas - - - eORCA025_U: &eORCA025_U - type: ORCA - orca_arrangement: U - orca_name: eORCA025 - dimensions: [1442, 1207] - orca_uid: "b1b2922e9b57ee9c6eeddad218b6e4f3" - url_prefix: *orca_url_prefix - url: eORCA025_U.atlas - - - eORCA025_V: &eORCA025_V - type: ORCA - orca_arrangement: V - orca_name: eORCA025 - dimensions: [1442, 1207] - orca_uid: "9b06bf73a8f14e927bd9b0f1f0c04f74" - url_prefix: *orca_url_prefix - url: eORCA025_V.atlas - - - eORCA025_W: &eORCA025_W - type: ORCA - orca_arrangement: W - orca_name: eORCA025 - dimensions: [1442, 1207] - orca_uid: "4a1ba3b11b8888aefc96992b6b1cab62" - url_prefix: *orca_url_prefix - url: eORCA025_T.atlas - - - ORCA12_F: &ORCA12_F - type: ORCA - orca_arrangement: F - orca_name: ORCA12 - dimensions: [4322, 3059] - orca_uid: "29693ad8a7af3ae3ee0f02d090f0ec7b" - url_prefix: *orca_url_prefix - url: ORCA12_F.atlas - - - ORCA12_T: &ORCA12_T - type: ORCA - orca_arrangement: T - orca_name: ORCA12 - dimensions: [4322, 3059] - orca_uid: "b117d01170ac77bca68560ab10e559de" - url_prefix: *orca_url_prefix - url: ORCA12_T.atlas - - - ORCA12_U: &ORCA12_U - type: ORCA - orca_arrangement: U - orca_name: ORCA12 - dimensions: [4322, 3059] - orca_uid: "fff193b92d94d03e847ff2fa62b493f4" - url_prefix: *orca_url_prefix - url: ORCA12_U.atlas - - - ORCA12_V: &ORCA12_V - type: ORCA - orca_arrangement: V - orca_name: ORCA12 - dimensions: [4322, 3059] - orca_uid: "986e3450774b716f6e75c1987e370b10" - url_prefix: *orca_url_prefix - url: ORCA12_V.atlas - - - ORCA12_W: &ORCA12_W - type: ORCA - orca_arrangement: W - orca_name: ORCA12 - dimensions: [4322, 3059] - orca_uid: "ccfe953619a8dd49a7f765923882a274" - url_prefix: *orca_url_prefix - url: ORCA12_T.atlas - - - eORCA12_F: &eORCA12_F - type: ORCA - orca_arrangement: F - orca_name: eORCA12 - dimensions: [4322, 3606] - orca_uid: "25da53ed581b3931fa310840fa9aefd9" - url_prefix: *orca_url_prefix - url: eORCA12_F.atlas - - - eORCA12_T: &eORCA12_T - type: ORCA - orca_arrangement: T - orca_name: eORCA12 - dimensions: [4322, 3606] - orca_uid: "1553b66f5885cf5f83ad4b4fdf25f460" - url_prefix: *orca_url_prefix - url: eORCA12_T.atlas - - - eORCA12_U: &eORCA12_U - type: ORCA - orca_arrangement: U - orca_name: eORCA12 - dimensions: [4322, 3606] - orca_uid: "3e87c826643da440b4e9d9f67588a576" - url_prefix: *orca_url_prefix - url: eORCA12_U.atlas - - - eORCA12_V: &eORCA12_V - type: ORCA - orca_arrangement: V - orca_name: eORCA12 - dimensions: [4322, 3606] - orca_uid: "cc1e3fc06a2cd18c0653e557510b8a71" - url_prefix: *orca_url_prefix - url: eORCA12_V.atlas - - - eORCA12_W: &eORCA12_W - type: ORCA - orca_arrangement: W - orca_name: eORCA12 - dimensions: [4322, 3606] - orca_uid: "462469edbd0e0586a0cf17424cc58c89" - url_prefix: *orca_url_prefix - url: eORCA12_T.atlas - -grid_uids: - - 174487fbace54b00d959d971e88b71e7: *ORCA2_F - - d5bde4f52ff3a9bea5629cd9ac514410: *ORCA2_T - - 857f7affa3a381e3882d38d321384e49: *ORCA2_U - - ca637bc5dc9a54e2ea4b9750e1b79e6e: *ORCA2_V - - edea6f71eb558dc056b5f576d5b904f7: *ORCA2_W - - a832a12030c73928133553ec3a8d2a7e: *ORCA1_F - - f4c91b6233fe55dec992160ec12b38df: *ORCA1_T - - 1b0f8d234753f910197c975c906b4da5: *ORCA1_U - - c637340454795b395f982851b840943d: *ORCA1_V - - d50061c43e83c46c3810002591ea21e1: *ORCA1_W - - 3c6d95561710c6f39b394809ff6c588c: *eORCA1_F - - ba65665a9e68d1a8fa0352ecfcf8e496: *eORCA1_T - - 4eb1054957dcae914e219faf9a4068e3: *eORCA1_U - - 09131429766e7737c087d3a8d7073dc9: *eORCA1_V - - 5c678d8f9aa2edfbf57246d11d9c1278: *eORCA1_W - - efbc280d8d4b6048797880da2605bacb: *ORCA025_F - - 15c961c269ac182ca226d7195f3921ba: *ORCA025_T - - 3f4a68bc5b54c9f867fbcc12aacc723d: *ORCA025_U - - 9c87699ee2026c0feee07d2a972eaccd: *ORCA025_V - - 74ca68f1c8524811f3d3aad99536adc2: *ORCA025_W - - 770e5bbb667a253d55db8a98a3b2d3a9: *eORCA025_F - - 983412216c9768bc794c18dc92082895: *eORCA025_T - - b1b2922e9b57ee9c6eeddad218b6e4f3: *eORCA025_U - - 9b06bf73a8f14e927bd9b0f1f0c04f74: *eORCA025_V - - 4a1ba3b11b8888aefc96992b6b1cab62: *eORCA025_W - - 29693ad8a7af3ae3ee0f02d090f0ec7b: *ORCA12_F - - b117d01170ac77bca68560ab10e559de: *ORCA12_T - - fff193b92d94d03e847ff2fa62b493f4: *ORCA12_U - - 986e3450774b716f6e75c1987e370b10: *ORCA12_V - - ccfe953619a8dd49a7f765923882a274: *ORCA12_W - - 25da53ed581b3931fa310840fa9aefd9: *eORCA12_F - - 1553b66f5885cf5f83ad4b4fdf25f460: *eORCA12_T - - 3e87c826643da440b4e9d9f67588a576: *eORCA12_U - - cc1e3fc06a2cd18c0653e557510b8a71: *eORCA12_V - - 462469edbd0e0586a0cf17424cc58c89: *eORCA12_W - diff --git a/src/eckit/geo/LibEcKitGeo.cc b/src/eckit/geo/LibEcKitGeo.cc index a5b541693..8429ffd1d 100644 --- a/src/eckit/geo/LibEcKitGeo.cc +++ b/src/eckit/geo/LibEcKitGeo.cc @@ -39,8 +39,10 @@ std::vector LibEcKitGeo::etcGrid() { static const auto paths = [](const std::string& s) -> std::vector { const auto ss = StringTools::split(":", s); return {ss.begin(), ss.end()}; - }(LibResource("eckit-geo-grid;$ECKIT_GEO_GRID", "~eckit/etc/eckit/geo/grid.yaml")}; - return path; + }(LibResource("eckit-geo-grid;$ECKIT_GEO_GRID", + "~eckit/etc/eckit/geo/grid.yaml:" + "~eckit/etc/eckit/geo/ORCA.yaml:")); + return paths; } From 741acfa8f485b5546f58fd09192747e3325aae51 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 12:46:36 +0100 Subject: [PATCH 592/737] Cleanup --- src/eckit/geo/CMakeLists.txt | 20 ++++---- src/eckit/geo/Cache.h | 2 +- src/eckit/geo/LibEcKitGeo.cc | 8 ++-- src/eckit/geo/eckit_geo_config.h.in | 1 + src/eckit/geo/etc/Grid.cc | 61 ++++--------------------- src/eckit/geo/etc/Grid.h | 2 - src/eckit/geo/grid/regular/RegularLL.cc | 16 +++---- src/eckit/geo/spec/Custom.cc | 27 +++++++++++ src/eckit/geo/spec/Custom.h | 2 + src/eckit/geo/util/regex.cc | 55 ---------------------- src/eckit/geo/util/regex.h | 30 ------------ 11 files changed, 62 insertions(+), 162 deletions(-) delete mode 100644 src/eckit/geo/util/regex.cc delete mode 100644 src/eckit/geo/util/regex.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index af81e60ea..d816c5b69 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -1,12 +1,5 @@ -configure_file(eckit_geo_config.h.in eckit_geo_config.h @ONLY) -install( - FILES ${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_config.h - DESTINATION ${INSTALL_INCLUDE_DIR}/eckit -) - list(APPEND eckit_geo_srcs - ${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_config.h Area.cc Area.h Cache.cc @@ -126,8 +119,6 @@ list(APPEND eckit_geo_srcs util/mutex.h util/reduced_classical_pl.cc util/reduced_octahedral_pl.cc - util/regex.cc - util/regex.h ) set(eckit_geo_include_dirs @@ -136,6 +127,7 @@ set(eckit_geo_include_dirs ) set(eckit_geo_libs eckit_maths) +set(eckit_GEO_ETC_GRID "~eckit/etc/eckit/geo/grid.yaml") if(eckit_HAVE_PROJ) list(APPEND eckit_geo_srcs projection/PROJ.cc projection/PROJ.h) @@ -145,8 +137,18 @@ endif() if(eckit_HAVE_ECKIT_CODEC) list(APPEND eckit_geo_srcs grid/regular/ORCA.cc grid/regular/ORCA.h) list(APPEND eckit_geo_libs eckit_codec) + list(APPEND eckit_GEO_ETC_GRID "~eckit/etc/eckit/geo/ORCA.yaml") endif() +string(REPLACE ";" ":" eckit_GEO_ETC_GRID "${eckit_GEO_ETC_GRID}") +configure_file(eckit_geo_config.h.in eckit_geo_config.h @ONLY) + +list(APPEND eckit_geo_srcs ${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_config.h) +install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_config.h + DESTINATION ${INSTALL_INCLUDE_DIR}/eckit +) + ecbuild_add_library( TARGET eckit_geo TYPE SHARED diff --git a/src/eckit/geo/Cache.h b/src/eckit/geo/Cache.h index 5dc8c0493..6ec1cca5a 100644 --- a/src/eckit/geo/Cache.h +++ b/src/eckit/geo/Cache.h @@ -92,7 +92,7 @@ class CacheT final : private Cache { void purge() final { container_.clear(); } private: - mutable std::map container_; + mutable std::map container_; util::recursive_mutex* mutex_; }; diff --git a/src/eckit/geo/LibEcKitGeo.cc b/src/eckit/geo/LibEcKitGeo.cc index 8429ffd1d..e84f98cfb 100644 --- a/src/eckit/geo/LibEcKitGeo.cc +++ b/src/eckit/geo/LibEcKitGeo.cc @@ -39,16 +39,14 @@ std::vector LibEcKitGeo::etcGrid() { static const auto paths = [](const std::string& s) -> std::vector { const auto ss = StringTools::split(":", s); return {ss.begin(), ss.end()}; - }(LibResource("eckit-geo-grid;$ECKIT_GEO_GRID", - "~eckit/etc/eckit/geo/grid.yaml:" - "~eckit/etc/eckit/geo/ORCA.yaml:")); + }(LibResource("eckit-geo-etc-grid;$ECKIT_GEO_ETC_GRID", eckit_GEO_ETC_GRID)); return paths; } bool LibEcKitGeo::caching() { - static const bool yes{LibResource("eckit-geo-caching;$ECKIT_GEO_CACHING", - eckit_HAVE_GEO_CACHING != 0 ? true : false)}; + static const bool yes{ + LibResource("eckit-geo-caching;$ECKIT_GEO_CACHING", eckit_HAVE_GEO_CACHING != 0)}; return yes; } diff --git a/src/eckit/geo/eckit_geo_config.h.in b/src/eckit/geo/eckit_geo_config.h.in index 8ba4211c8..036cba383 100644 --- a/src/eckit/geo/eckit_geo_config.h.in +++ b/src/eckit/geo/eckit_geo_config.h.in @@ -17,4 +17,5 @@ #cmakedefine01 eckit_HAVE_GEO_CACHING #cmakedefine01 eckit_HAVE_GEO_CONVEX_HULL #cmakedefine eckit_GEO_CACHE_PATH "@eckit_GEO_CACHE_PATH@" +#cmakedefine eckit_GEO_ETC_GRID "@eckit_GEO_ETC_GRID@" diff --git a/src/eckit/geo/etc/Grid.cc b/src/eckit/geo/etc/Grid.cc index 5471faf54..1e67fbcf0 100644 --- a/src/eckit/geo/etc/Grid.cc +++ b/src/eckit/geo/etc/Grid.cc @@ -12,15 +12,11 @@ #include "eckit/geo/etc/Grid.h" -#include -#include - #include "eckit/exception/Exceptions.h" #include "eckit/filesystem/PathName.h" #include "eckit/geo/Grid.h" #include "eckit/geo/LibEcKitGeo.h" #include "eckit/geo/spec/Custom.h" -#include "eckit/geo/util.h" #include "eckit/parser/YAMLParser.h" #include "eckit/value/Value.h" @@ -28,47 +24,6 @@ namespace eckit::geo::etc { -namespace { - - -template -spec::Custom::value_type __from_value(const Value& value) { - T to; - fromValue(to, value); - return {to}; -} - - -void set_custom_value(spec::Custom& custom, const std::string& key, const Value& value) { - using number_type = pl_type::value_type; - - auto list_of = [](const ValueList& list, auto pred) { return std::all_of(list.begin(), list.end(), pred); }; - - auto val = value.isList() && list_of(value, [](const Value& v) { return v.isDouble(); }) - ? __from_value>(value) - : value.isList() && list_of(value, [](const Value& v) { return v.isNumber(); }) - ? __from_value>(value) - : value.isList() ? __from_value>(value) - : value.isDouble() ? __from_value(value) - : value.isNumber() ? __from_value(value) - : __from_value(value); - - std::visit([&](const auto& val) { custom.set(key, val); }, val); -} - - -spec::Custom* spec_from_value_map(const ValueMap& map) { - auto* spec = new spec::Custom; - for (const auto& kv : map) { - set_custom_value(*spec, kv.first, kv.second); - } - return spec; -} - - -} // namespace - - const Grid& Grid::instance() { static const Grid __instance(LibEcKitGeo::etcGrid()); return __instance; @@ -88,13 +43,17 @@ Grid::Grid(const std::vector& paths) { void Grid::load(const PathName& path) { - if (!spec_) { - spec_.reset(new spec::Custom); - } - - auto* custom = dynamic_cast(spec_.get()); + auto* custom = dynamic_cast((spec_ ? spec_ : (spec_ = std::make_unique())).get()); ASSERT(custom != nullptr); + auto spec_from_value_map = [](const ValueMap& map) { + auto* custom = new spec::Custom; + for (const auto& kv : map) { + custom->set(kv.first, kv.second); + } + return custom; + }; + struct SpecByUIDGenerator final : SpecByUID::generator_t { explicit SpecByUIDGenerator(spec::Custom* spec) : spec_(spec) {} @@ -135,7 +94,7 @@ void Grid::load(const PathName& path) { continue; } - set_custom_value(*custom, key, kv.second); + custom->set(key, kv.second); } } } diff --git a/src/eckit/geo/etc/Grid.h b/src/eckit/geo/etc/Grid.h index 17bf396dd..acaf84e37 100644 --- a/src/eckit/geo/etc/Grid.h +++ b/src/eckit/geo/etc/Grid.h @@ -51,8 +51,6 @@ class Grid final { static const Grid& instance(); - const Spec& spec() const { return *spec_; } - // -- Overridden methods // None diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/regular/RegularLL.cc index 0a004d707..d10cd2f2d 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/regular/RegularLL.cc @@ -12,13 +12,12 @@ #include "eckit/geo/grid/regular/RegularLL.h" +#include + #include "eckit/exception/Exceptions.h" #include "eckit/geo/Increments.h" #include "eckit/geo/iterator/Regular.h" -#include "eckit/geo/range/RegularLatitude.h" -#include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" -#include "eckit/geo/util/regex.h" #include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" @@ -68,15 +67,14 @@ void RegularLL::spec(spec::Custom& custom) const { #define POSITIVE_REAL "[+]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][-+][0-9]+)?" -static const std::string __pattern("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); +static const std::string PATTERN("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); #undef POSITIVE_REAL Spec* RegularLL::spec(const std::string& name) { - - auto match = util::regex_match(__pattern, name); - ASSERT(match); - ASSERT(match.size() == 9); // because of sub-matches + std::smatch match; + std::regex_match(name, match, std::regex(PATTERN)); + ASSERT(match.size() == 9); auto d = Translator{}; @@ -85,7 +83,7 @@ Spec* RegularLL::spec(const std::string& name) { static const GridRegisterType __grid_type("regular_ll"); -static const GridRegisterName __grid_pattern(__pattern); +static const GridRegisterName __grid_pattern(PATTERN); } // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 8563beb37..20b617842 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -16,6 +16,7 @@ #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/util.h" #include "eckit/log/JSON.h" #include "eckit/value/Content.h" // for ValueList, ValueMap #include "eckit/value/Value.h" @@ -125,6 +126,14 @@ bool __get_v_real(const Custom::container_type& map, const std::string& name, T& } +template +Custom::value_type __from_value(const Value& value) { + T to; + fromValue(to, value); + return {to}; +} + + JSON& operator<<(JSON& out, const Custom::value_type& value) { std::visit([&](const auto& arg) { out << arg; }, value); return out; @@ -285,6 +294,24 @@ void Custom::set(const std::string& name, const std::vector& value) } +void Custom::set(const std::string& key, const Value& value) { + using number_type = pl_type::value_type; + + auto list_of = [](const ValueList& list, auto pred) { return std::all_of(list.begin(), list.end(), pred); }; + + auto val = value.isList() && list_of(value, [](const Value& v) { return v.isDouble(); }) + ? __from_value>(value) + : value.isList() && list_of(value, [](const Value& v) { return v.isNumber(); }) + ? __from_value>(value) + : value.isList() ? __from_value>(value) + : value.isDouble() ? __from_value(value) + : value.isNumber() ? __from_value(value) + : __from_value(value); + + std::visit([&](const auto& val) { set(key, val); }, val); +} + + bool Custom::has(const std::string& name) const { return map_.find(name) != map_.cend(); } diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 229fd4d4a..1fa7ce09a 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -99,6 +99,8 @@ class Custom final : public Spec { void set(const std::string& name, const std::vector& value); void set(const std::string& name, const std::vector& value); + void set(const std::string& name, const Value& value); + // -- Overridden methods bool has(const std::string& name) const override; diff --git a/src/eckit/geo/util/regex.cc b/src/eckit/geo/util/regex.cc deleted file mode 100644 index 900d3ca38..000000000 --- a/src/eckit/geo/util/regex.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/util/regex.h" - -#include - -#include "eckit/log/Log.h" - - -namespace eckit::geo::util { - - -regex_match_type regex_match(const std::string& pattern, const std::string& s) { - static const std::map __regex_code{ - {std::regex_constants::error_backref, "error_backref"}, - {std::regex_constants::error_badbrace, "error_badbrace"}, - {std::regex_constants::error_badrepeat, "error_badrepeat"}, - {std::regex_constants::error_brace, "error_brace"}, - {std::regex_constants::error_brack, "error_brack"}, - {std::regex_constants::error_collate, "error_collate"}, - {std::regex_constants::error_complexity, "error_complexity"}, - {std::regex_constants::error_ctype, "error_ctype"}, - {std::regex_constants::error_escape, "error_escape"}, - {std::regex_constants::error_paren, "error_paren"}, - {std::regex_constants::error_range, "error_range"}, - {std::regex_constants::error_space, "error_space"}, - {std::regex_constants::error_stack, "error_stack"}, - }; - - std::regex regex; - try { - regex.assign(std::regex(pattern, std::regex_constants::extended)); - } - catch (const std::regex_error& e) { - Log::error() << "regex_error caught: " << e.what() << ", code: " << __regex_code.at(e.code()) << std::endl; - throw; - } - - regex_match_type m; - std::regex_match(s, m, regex); - return m; -} - - -} // namespace eckit::geo::util diff --git a/src/eckit/geo/util/regex.h b/src/eckit/geo/util/regex.h deleted file mode 100644 index 5ffba6261..000000000 --- a/src/eckit/geo/util/regex.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include -#include - - -namespace eckit::geo::util { - - -struct regex_match_type : std::smatch { - explicit operator bool() const { return !std::smatch::empty(); } -}; - - -regex_match_type regex_match(const std::string& pattern, const std::string&); - - -} // namespace eckit::geo::util From 3c4053d49800281d2806c016ccf15f31515a27d2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 10 Apr 2024 16:47:43 +0100 Subject: [PATCH 593/737] eckit::geo::Grid --- src/eckit/geo/CMakeLists.txt | 28 +++---- .../geo/grid/{reduced-global => }/HEALPix.cc | 6 +- .../geo/grid/{reduced-global => }/HEALPix.h | 4 +- src/eckit/geo/grid/{regular => }/ORCA.cc | 6 +- src/eckit/geo/grid/{regular => }/ORCA.h | 4 +- .../{reduced-global => }/ReducedGaussian.cc | 6 +- .../{reduced-global => }/ReducedGaussian.h | 4 +- .../geo/grid/{reduced-local => }/ReducedLL.cc | 6 +- .../geo/grid/{reduced-local => }/ReducedLL.h | 4 +- .../geo/grid/{regular => }/RegularGaussian.cc | 6 +- .../geo/grid/{regular => }/RegularGaussian.h | 4 +- src/eckit/geo/grid/{regular => }/RegularLL.cc | 6 +- src/eckit/geo/grid/{regular => }/RegularLL.h | 4 +- .../geo/grid/{regular => }/XYToLonLat.cc | 6 +- src/eckit/geo/grid/{regular => }/XYToLonLat.h | 4 +- src/eckit/geo/grid/regular/IrregularLL.cc | 55 ------------- src/eckit/geo/grid/regular/IrregularLL.h | 82 ------------------- tests/geo/grid_healpix.cc | 16 ++-- tests/geo/grid_orca.cc | 8 +- tests/geo/grid_reduced_gg.cc | 14 ++-- tests/geo/grid_regular_gg.cc | 8 +- tests/geo/grid_regular_ll.cc | 12 +-- tests/geo/grid_to_points.cc | 4 +- 23 files changed, 74 insertions(+), 223 deletions(-) rename src/eckit/geo/grid/{reduced-global => }/HEALPix.cc (98%) rename src/eckit/geo/grid/{reduced-global => }/HEALPix.h (96%) rename src/eckit/geo/grid/{regular => }/ORCA.cc (98%) rename src/eckit/geo/grid/{regular => }/ORCA.h (97%) rename src/eckit/geo/grid/{reduced-global => }/ReducedGaussian.cc (96%) rename src/eckit/geo/grid/{reduced-global => }/ReducedGaussian.h (95%) rename src/eckit/geo/grid/{reduced-local => }/ReducedLL.cc (92%) rename src/eckit/geo/grid/{reduced-local => }/ReducedLL.h (94%) rename src/eckit/geo/grid/{regular => }/RegularGaussian.cc (94%) rename src/eckit/geo/grid/{regular => }/RegularGaussian.h (95%) rename src/eckit/geo/grid/{regular => }/RegularLL.cc (95%) rename src/eckit/geo/grid/{regular => }/RegularLL.h (95%) rename src/eckit/geo/grid/{regular => }/XYToLonLat.cc (96%) rename src/eckit/geo/grid/{regular => }/XYToLonLat.h (97%) delete mode 100644 src/eckit/geo/grid/regular/IrregularLL.cc delete mode 100644 src/eckit/geo/grid/regular/IrregularLL.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index d816c5b69..88e6bbfba 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -48,28 +48,26 @@ list(APPEND eckit_geo_srcs figure/OblateSpheroid.h figure/Sphere.cc figure/Sphere.h + grid/HEALPix.cc + grid/HEALPix.h + grid/ReducedGaussian.cc + grid/ReducedGaussian.h grid/ReducedGlobal.cc grid/ReducedGlobal.h + grid/ReducedLL.cc + grid/ReducedLL.h grid/ReducedLocal.cc grid/ReducedLocal.h grid/Regular.cc grid/Regular.h + grid/RegularGaussian.cc + grid/RegularGaussian.h + grid/RegularLL.cc + grid/RegularLL.h grid/Unstructured.cc grid/Unstructured.h - grid/reduced-global/HEALPix.cc - grid/reduced-global/HEALPix.h - grid/reduced-global/ReducedGaussian.cc - grid/reduced-global/ReducedGaussian.h - grid/reduced-local/ReducedLL.cc - grid/reduced-local/ReducedLL.h - grid/regular/IrregularLL.cc - grid/regular/IrregularLL.h - grid/regular/RegularGaussian.cc - grid/regular/RegularGaussian.h - grid/regular/RegularLL.cc - grid/regular/RegularLL.h - grid/regular/XYToLonLat.cc - grid/regular/XYToLonLat.h + grid/XYToLonLat.cc + grid/XYToLonLat.h iterator/Reduced.cc iterator/Reduced.h iterator/Regular.cc @@ -135,7 +133,7 @@ if(eckit_HAVE_PROJ) endif() if(eckit_HAVE_ECKIT_CODEC) - list(APPEND eckit_geo_srcs grid/regular/ORCA.cc grid/regular/ORCA.h) + list(APPEND eckit_geo_srcs grid/ORCA.cc grid/ORCA.h) list(APPEND eckit_geo_libs eckit_codec) list(APPEND eckit_GEO_ETC_GRID "~eckit/etc/eckit/geo/ORCA.yaml") endif() diff --git a/src/eckit/geo/grid/reduced-global/HEALPix.cc b/src/eckit/geo/grid/HEALPix.cc similarity index 98% rename from src/eckit/geo/grid/reduced-global/HEALPix.cc rename to src/eckit/geo/grid/HEALPix.cc index affcb97e6..3b2044eaf 100644 --- a/src/eckit/geo/grid/reduced-global/HEALPix.cc +++ b/src/eckit/geo/grid/HEALPix.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/reduced-global/HEALPix.h" +#include "eckit/geo/grid/HEALPix.h" #include #include @@ -25,7 +25,7 @@ #include "eckit/utils/Translator.h" -namespace eckit::geo::grid::reducedglobal { +namespace eckit::geo::grid { namespace { @@ -383,4 +383,4 @@ static const GridRegisterType __grid_type_2("healpix"); static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); -} // namespace eckit::geo::grid::reducedglobal +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/reduced-global/HEALPix.h b/src/eckit/geo/grid/HEALPix.h similarity index 96% rename from src/eckit/geo/grid/reduced-global/HEALPix.h rename to src/eckit/geo/grid/HEALPix.h index b68c6fd2e..89087800f 100644 --- a/src/eckit/geo/grid/reduced-global/HEALPix.h +++ b/src/eckit/geo/grid/HEALPix.h @@ -15,7 +15,7 @@ #include "eckit/geo/grid/ReducedGlobal.h" -namespace eckit::geo::grid::reducedglobal { +namespace eckit::geo::grid { class HEALPix final : public ReducedGlobal { @@ -104,4 +104,4 @@ class HEALPix final : public ReducedGlobal { }; -} // namespace eckit::geo::grid::reducedglobal +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/regular/ORCA.cc b/src/eckit/geo/grid/ORCA.cc similarity index 98% rename from src/eckit/geo/grid/regular/ORCA.cc rename to src/eckit/geo/grid/ORCA.cc index a0309f224..ee9cc1610 100644 --- a/src/eckit/geo/grid/regular/ORCA.cc +++ b/src/eckit/geo/grid/ORCA.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/regular/ORCA.h" +#include "eckit/geo/grid/ORCA.h" #include @@ -37,7 +37,7 @@ #endif -namespace eckit::geo::grid::regular { +namespace eckit::geo::grid { namespace { @@ -338,4 +338,4 @@ static const GridRegisterType __grid_type("ORCA"); static const GridRegisterName __grid_pattern(GridRegisterName::uid_pattern); -} // namespace eckit::geo::grid::regular +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/regular/ORCA.h b/src/eckit/geo/grid/ORCA.h similarity index 97% rename from src/eckit/geo/grid/regular/ORCA.h rename to src/eckit/geo/grid/ORCA.h index ca8e40fa0..cc7297e91 100644 --- a/src/eckit/geo/grid/regular/ORCA.h +++ b/src/eckit/geo/grid/ORCA.h @@ -24,7 +24,7 @@ class PathName; } -namespace eckit::geo::grid::regular { +namespace eckit::geo::grid { class ORCA final : public Regular { @@ -142,4 +142,4 @@ class ORCA final : public Regular { }; -} // namespace eckit::geo::grid::regular +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc similarity index 96% rename from src/eckit/geo/grid/reduced-global/ReducedGaussian.cc rename to src/eckit/geo/grid/ReducedGaussian.cc index 64e20761b..9668ed358 100644 --- a/src/eckit/geo/grid/reduced-global/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/reduced-global/ReducedGaussian.h" +#include "eckit/geo/grid/ReducedGaussian.h" #include @@ -23,7 +23,7 @@ #include "eckit/utils/Translator.h" -namespace eckit::geo::grid::reducedglobal { +namespace eckit::geo::grid { static size_t N(const pl_type& pl) { @@ -153,4 +153,4 @@ static const GridRegisterName __grid_pattern_1("[nN][1 static const GridRegisterName __grid_pattern_2("[oO][1-9][0-9]*"); -} // namespace eckit::geo::grid::reducedglobal +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/reduced-global/ReducedGaussian.h b/src/eckit/geo/grid/ReducedGaussian.h similarity index 95% rename from src/eckit/geo/grid/reduced-global/ReducedGaussian.h rename to src/eckit/geo/grid/ReducedGaussian.h index 2e7d7d973..bd669f39f 100644 --- a/src/eckit/geo/grid/reduced-global/ReducedGaussian.h +++ b/src/eckit/geo/grid/ReducedGaussian.h @@ -20,7 +20,7 @@ #include "eckit/geo/util.h" -namespace eckit::geo::grid::reducedglobal { +namespace eckit::geo::grid { class ReducedGaussian : public ReducedGlobal { @@ -98,4 +98,4 @@ class ReducedGaussian : public ReducedGlobal { }; -} // namespace eckit::geo::grid::reducedglobal +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/reduced-local/ReducedLL.cc b/src/eckit/geo/grid/ReducedLL.cc similarity index 92% rename from src/eckit/geo/grid/reduced-local/ReducedLL.cc rename to src/eckit/geo/grid/ReducedLL.cc index e9dc04f33..30db04a60 100644 --- a/src/eckit/geo/grid/reduced-local/ReducedLL.cc +++ b/src/eckit/geo/grid/ReducedLL.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/reduced-local/ReducedLL.h" +#include "eckit/geo/grid/ReducedLL.h" #include "eckit/geo/iterator/Reduced.h" #include "eckit/geo/range/RegularLatitude.h" @@ -18,7 +18,7 @@ #include "eckit/geo/spec/Custom.h" -namespace eckit::geo::grid::reducedlocal { +namespace eckit::geo::grid { ReducedLL::ReducedLL(const Spec& spec) : @@ -74,4 +74,4 @@ void ReducedLL::spec(spec::Custom& custom) const { } -} // namespace eckit::geo::grid::reducedlocal +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/reduced-local/ReducedLL.h b/src/eckit/geo/grid/ReducedLL.h similarity index 94% rename from src/eckit/geo/grid/reduced-local/ReducedLL.h rename to src/eckit/geo/grid/ReducedLL.h index c7e5de28c..9fc4eb530 100644 --- a/src/eckit/geo/grid/reduced-local/ReducedLL.h +++ b/src/eckit/geo/grid/ReducedLL.h @@ -19,7 +19,7 @@ #include "eckit/geo/util.h" -namespace eckit::geo::grid::reducedlocal { +namespace eckit::geo::grid { class ReducedLL : public ReducedLocal { @@ -90,4 +90,4 @@ class ReducedLL : public ReducedLocal { }; -} // namespace eckit::geo::grid::reducedlocal +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/regular/RegularGaussian.cc b/src/eckit/geo/grid/RegularGaussian.cc similarity index 94% rename from src/eckit/geo/grid/regular/RegularGaussian.cc rename to src/eckit/geo/grid/RegularGaussian.cc index c80d507b3..f73d096fd 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.cc +++ b/src/eckit/geo/grid/RegularGaussian.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/regular/RegularGaussian.h" +#include "eckit/geo/grid/RegularGaussian.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/iterator/Regular.h" @@ -20,7 +20,7 @@ #include "eckit/utils/Translator.h" -namespace eckit::geo::grid::regular { +namespace eckit::geo::grid { RegularGaussian::RegularGaussian(const Spec& spec) : @@ -82,4 +82,4 @@ static const GridRegisterType __grid_type("regular_gg"); static const GridRegisterName __grid_pattern("[fF][1-9][0-9]*"); -} // namespace eckit::geo::grid::regular +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/regular/RegularGaussian.h b/src/eckit/geo/grid/RegularGaussian.h similarity index 95% rename from src/eckit/geo/grid/regular/RegularGaussian.h rename to src/eckit/geo/grid/RegularGaussian.h index 166318964..da999615c 100644 --- a/src/eckit/geo/grid/regular/RegularGaussian.h +++ b/src/eckit/geo/grid/RegularGaussian.h @@ -18,7 +18,7 @@ #include "eckit/geo/grid/Regular.h" -namespace eckit::geo::grid::regular { +namespace eckit::geo::grid { class RegularGaussian final : public Regular { @@ -92,4 +92,4 @@ class RegularGaussian final : public Regular { }; -} // namespace eckit::geo::grid::regular +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/regular/RegularLL.cc b/src/eckit/geo/grid/RegularLL.cc similarity index 95% rename from src/eckit/geo/grid/regular/RegularLL.cc rename to src/eckit/geo/grid/RegularLL.cc index d10cd2f2d..06745a439 100644 --- a/src/eckit/geo/grid/regular/RegularLL.cc +++ b/src/eckit/geo/grid/RegularLL.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/regular/RegularLL.h" +#include "eckit/geo/grid/RegularLL.h" #include @@ -22,7 +22,7 @@ #include "eckit/utils/Translator.h" -namespace eckit::geo::grid::regular { +namespace eckit::geo::grid { RegularLL::RegularLL(const Spec& spec) : @@ -86,4 +86,4 @@ static const GridRegisterType __grid_type("regular_ll"); static const GridRegisterName __grid_pattern(PATTERN); -} // namespace eckit::geo::grid::regular +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/regular/RegularLL.h b/src/eckit/geo/grid/RegularLL.h similarity index 95% rename from src/eckit/geo/grid/regular/RegularLL.h rename to src/eckit/geo/grid/RegularLL.h index c850c7855..782467019 100644 --- a/src/eckit/geo/grid/regular/RegularLL.h +++ b/src/eckit/geo/grid/RegularLL.h @@ -22,7 +22,7 @@ class Increments; } // namespace eckit::geo -namespace eckit::geo::grid::regular { +namespace eckit::geo::grid { class RegularLL final : public Regular { @@ -93,4 +93,4 @@ class RegularLL final : public Regular { }; -} // namespace eckit::geo::grid::regular +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/regular/XYToLonLat.cc b/src/eckit/geo/grid/XYToLonLat.cc similarity index 96% rename from src/eckit/geo/grid/regular/XYToLonLat.cc rename to src/eckit/geo/grid/XYToLonLat.cc index f22e6e83c..8511d6878 100644 --- a/src/eckit/geo/grid/regular/XYToLonLat.cc +++ b/src/eckit/geo/grid/XYToLonLat.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/regular/XYToLonLat.h" +#include "eckit/geo/grid/XYToLonLat.h" #include "eckit/exception/Exceptions.h" #include "eckit/geo/Spec.h" @@ -19,7 +19,7 @@ #include "eckit/geo/spec/Custom.h" -namespace eckit::geo::grid::regular { +namespace eckit::geo::grid { XYToLonLat::XYToLonLat(const Spec& spec) : @@ -121,4 +121,4 @@ void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { } -} // namespace eckit::geo::grid::regular +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/regular/XYToLonLat.h b/src/eckit/geo/grid/XYToLonLat.h similarity index 97% rename from src/eckit/geo/grid/regular/XYToLonLat.h rename to src/eckit/geo/grid/XYToLonLat.h index d82a3b95a..1acd1e893 100644 --- a/src/eckit/geo/grid/regular/XYToLonLat.h +++ b/src/eckit/geo/grid/XYToLonLat.h @@ -17,7 +17,7 @@ #include "eckit/geo/grid/Regular.h" -namespace eckit::geo::grid::regular { +namespace eckit::geo::grid { class XYToLonLat : public Regular { @@ -137,4 +137,4 @@ struct LambertAzimuthalEqualArea final : public XYToLonLat { }; -} // namespace eckit::geo::grid::regular +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/regular/IrregularLL.cc b/src/eckit/geo/grid/regular/IrregularLL.cc deleted file mode 100644 index 3ee5d9d39..000000000 --- a/src/eckit/geo/grid/regular/IrregularLL.cc +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/regular/IrregularLL.h" - -// #include <> - - -namespace eckit::geo::grid::regular { - - -IrregularLL::IrregularLL(const Spec& spec) : - Regular(spec) {} - - -Grid::iterator IrregularLL::cbegin() const { - NOTIMP; -} - - -Grid::iterator IrregularLL::cend() const { - NOTIMP; -} - - -size_t IrregularLL::ni() const { - NOTIMP; -} - - -size_t IrregularLL::nj() const { - NOTIMP; -} - - -const std::vector& IrregularLL::longitudes() const { - NOTIMP; -} - - -const std::vector& IrregularLL::latitudes() const { - NOTIMP; -} - - -} // namespace eckit::geo::grid::regular diff --git a/src/eckit/geo/grid/regular/IrregularLL.h b/src/eckit/geo/grid/regular/IrregularLL.h deleted file mode 100644 index 828ccd63b..000000000 --- a/src/eckit/geo/grid/regular/IrregularLL.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/Regular.h" - - -namespace eckit::geo::grid::regular { - - -class IrregularLL final : public Regular { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit IrregularLL(const Spec&); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - - iterator cbegin() const override; - iterator cend() const override; - - size_t ni() const override; - size_t nj() const override; - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - - const std::vector& longitudes() const override; - const std::vector& latitudes() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid::regular diff --git a/tests/geo/grid_healpix.cc b/tests/geo/grid_healpix.cc index 5206e313b..cbb08b00c 100644 --- a/tests/geo/grid_healpix.cc +++ b/tests/geo/grid_healpix.cc @@ -12,8 +12,7 @@ #include -#include "eckit/geo/Grid.h" -#include "eckit/geo/grid/reduced-global/HEALPix.h" +#include "eckit/geo/grid/HEALPix.h" #include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" @@ -22,9 +21,6 @@ namespace eckit::geo::test { CASE("HEALPix") { - using grid::reducedglobal::HEALPix; - - SECTION("gridspec") { spec::Custom spec({{"grid", "h2"}}); std::unique_ptr grid1(GridFactory::build(spec)); @@ -47,7 +43,7 @@ CASE("HEALPix") { GridFactory::build(spec::Custom({{"grid", "h" + std::to_string(test.N)}}))); std::unique_ptr grid2( GridFactory::build(spec::Custom({{"type", "HEALPix"}, {"Nside", test.N}}))); - HEALPix grid3(test.N); + grid::HEALPix grid3(test.N); EXPECT(grid1->size() == test.size); EXPECT(grid2->size() == test.size); @@ -58,12 +54,12 @@ CASE("HEALPix") { SECTION("points") { - std::unique_ptr ring(new HEALPix(2)); + std::unique_ptr ring(new grid::HEALPix(2)); EXPECT(ring->order() == Ordering::healpix_ring); - std::unique_ptr nested(new HEALPix(2, Ordering::healpix_nested)); + std::unique_ptr nested(new grid::HEALPix(2, Ordering::healpix_nested)); EXPECT(nested->order() == Ordering::healpix_nested); @@ -169,7 +165,7 @@ CASE("HEALPix") { SECTION("equals") { std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "h2"}}))); std::unique_ptr grid2(GridFactory::make_from_string("{type: HEALPix, Nside: 2}")); - std::unique_ptr grid3(new HEALPix(2)); + std::unique_ptr grid3(new grid::HEALPix(2)); EXPECT(*grid1 == *grid2); EXPECT(*grid2 == *grid3); @@ -177,7 +173,7 @@ CASE("HEALPix") { std::unique_ptr grid4(GridFactory::build(spec::Custom({{"grid", "h2"}, {"ordering", "nested"}}))); std::unique_ptr grid5(GridFactory::make_from_string("{type: HEALPix, Nside: 2, ordering: nested}")); - std::unique_ptr grid6(new HEALPix(2, Ordering::healpix_nested)); + std::unique_ptr grid6(new grid::HEALPix(2, Ordering::healpix_nested)); EXPECT(*grid4 != *grid1); diff --git a/tests/geo/grid_orca.cc b/tests/geo/grid_orca.cc index 0f7bd5b09..3e4284e6f 100644 --- a/tests/geo/grid_orca.cc +++ b/tests/geo/grid_orca.cc @@ -12,7 +12,7 @@ #include -#include "eckit/geo/grid/regular/ORCA.h" +#include "eckit/geo/grid/ORCA.h" #include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" @@ -21,8 +21,6 @@ namespace eckit::geo::test { CASE("ORCA") { - using grid::regular::ORCA; - const Grid::uid_t uid = "d5bde4f52ff3a9bea5629cd9ac514410"; const std::vector dimensions{182, 149}; @@ -47,7 +45,7 @@ CASE("ORCA") { EXPECT(grid2->size() == dimensions[0] * dimensions[1]); EXPECT(grid2->uid() == uid); - ORCA grid3(uid); + grid::ORCA grid3(uid); EXPECT(grid3.uid() == uid); EXPECT(grid3.calculate_uid() == uid); @@ -61,7 +59,7 @@ CASE("ORCA") { std::unique_ptr grid1(GridFactory::make_from_string("{uid:" + uid + "}")); std::unique_ptr grid2(GridFactory::build(spec::Custom({{"uid", uid}}))); std::unique_ptr grid3(GridFactory::build(spec::Custom({{"grid", uid}}))); - ORCA grid4(uid); + grid::ORCA grid4(uid); EXPECT(*grid1 == *grid2); EXPECT(*grid2 == *grid3); diff --git a/tests/geo/grid_reduced_gg.cc b/tests/geo/grid_reduced_gg.cc index b2bfb8607..ace1b839a 100644 --- a/tests/geo/grid_reduced_gg.cc +++ b/tests/geo/grid_reduced_gg.cc @@ -12,8 +12,7 @@ #include -#include "eckit/geo/Grid.h" -#include "eckit/geo/grid/reduced-global/ReducedGaussian.h" +#include "eckit/geo/grid/ReducedGaussian.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/testing/Test.h" @@ -23,9 +22,6 @@ namespace eckit::geo::test { CASE("ReducedGaussianOctahedral") { - using grid::reducedglobal::ReducedGaussian; - - SECTION("gridspec") { // different ways to instantiate the same grid (O2) for (auto spec : { @@ -60,7 +56,7 @@ CASE("ReducedGaussianOctahedral") { GridFactory::build(spec::Custom({{"grid", "o" + std::to_string(test.N)}}))); std::unique_ptr grid2( GridFactory::build(spec::Custom({{"type", "reduced_gg"}, {"N", test.N}}))); - ReducedGaussian grid3(test.N); + grid::ReducedGaussian grid3(test.N); EXPECT(grid1->size() == test.size); EXPECT(grid2->size() == test.size); @@ -70,7 +66,7 @@ CASE("ReducedGaussianOctahedral") { SECTION("points") { - ReducedGaussian grid(1); + grid::ReducedGaussian grid(1); const std::vector ref{ {0., 35.264389683}, {18., 35.264389683}, {36., 35.264389683}, {54., 35.264389683}, @@ -167,8 +163,8 @@ CASE("ReducedGaussianOctahedral") { SECTION("equals") { std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "o3"}}))); std::unique_ptr grid2(GridFactory::make_from_string("N: 3")); - std::unique_ptr grid3(new ReducedGaussian(3)); - std::unique_ptr grid4(new ReducedGaussian(pl_type{20, 24, 28, 28, 24, 20})); + std::unique_ptr grid3(new grid::ReducedGaussian(3)); + std::unique_ptr grid4(new grid::ReducedGaussian(pl_type{20, 24, 28, 28, 24, 20})); EXPECT(*grid1 == *grid2); EXPECT(*grid2 == *grid3); diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index 0efaac91c..7109fda30 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -13,7 +13,7 @@ #include #include "eckit/geo/Grid.h" -#include "eckit/geo/grid/regular/RegularGaussian.h" +#include "eckit/geo/grid/RegularGaussian.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/testing/Test.h" @@ -36,7 +36,7 @@ CASE("RegularGaussian") { GridFactory::build(spec::Custom({{"grid", "f" + std::to_string(test.N)}}))); std::unique_ptr grid2( GridFactory::build(spec::Custom({{"type", "regular_gg"}, {"N", test.N}}))); - grid::regular::RegularGaussian grid3(test.N); + grid::RegularGaussian grid3(test.N); EXPECT(grid1->size() == test.size); EXPECT(grid2->size() == test.size); @@ -46,7 +46,7 @@ CASE("RegularGaussian") { SECTION("points") { - grid::regular::RegularGaussian grid(1); + grid::RegularGaussian grid(1); const std::vector ref{ {0., 35.264389683}, @@ -160,7 +160,7 @@ CASE("RegularGaussian") { SECTION("equals") { std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "f3"}}))); - std::unique_ptr grid2(new grid::regular::RegularGaussian(3)); + std::unique_ptr grid2(new grid::RegularGaussian(3)); EXPECT(*grid1 == *grid2); } diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index 0ec4ef096..744e85f88 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -12,7 +12,7 @@ #include -#include "eckit/geo/grid/regular/RegularLL.h" +#include "eckit/geo/grid/RegularLL.h" #include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" @@ -21,17 +21,17 @@ namespace eckit::geo::test { CASE("global") { - std::unique_ptr grid1(new grid::regular::RegularLL(spec::Custom{{{"grid", std::vector{1, 1}}}})); + std::unique_ptr grid1(new grid::RegularLL(spec::Custom{{{"grid", std::vector{1, 1}}}})); EXPECT(grid1->size() == 360 * 181); - std::unique_ptr grid2(new grid::regular::RegularLL( + std::unique_ptr grid2(new grid::RegularLL( spec::Custom{{{"grid", std::vector{2, 1}}, {"area", std::vector{10, 1, 1, 10}}}})); EXPECT(grid2->size() == 5 * 10); - for (const auto& grid : {grid::regular::RegularLL({1., 1.}, {89.5, 0.5, -89.5, 359.5}), - grid::regular::RegularLL({1., 1.}, {90., 0., -90, 360.}, {0.5, 0.5})}) { + for (const auto& grid : {grid::RegularLL({1., 1.}, {89.5, 0.5, -89.5, 359.5}), + grid::RegularLL({1., 1.}, {90., 0., -90, 360.}, {0.5, 0.5})}) { EXPECT(grid.ni() == 360); EXPECT(grid.nj() == 180); EXPECT(grid.size() == 360 * 180); @@ -46,7 +46,7 @@ CASE("non-global") { * -1 . . . . * -1 0 1 2 */ - grid::regular::RegularLL grid({1, 2}, {1, -1, -1, 2}); + grid::RegularLL grid({1, 2}, {1, -1, -1, 2}); const std::vector ref{ {-1., 1.}, diff --git a/tests/geo/grid_to_points.cc b/tests/geo/grid_to_points.cc index 646098333..62600c912 100644 --- a/tests/geo/grid_to_points.cc +++ b/tests/geo/grid_to_points.cc @@ -13,7 +13,7 @@ #include #include -#include "eckit/geo/grid/reduced-global/HEALPix.h" +#include "eckit/geo/grid/HEALPix.h" #include "eckit/testing/Test.h" @@ -22,7 +22,7 @@ namespace eckit::geo::test { CASE("HEALPix") { SECTION("HEALPix::to_points") { - std::unique_ptr grid(new grid::reducedglobal::HEALPix(2, Ordering::healpix_ring)); + std::unique_ptr grid(new grid::HEALPix(2, Ordering::healpix_ring)); static const std::vector expected_points_ring{ {45, 66.443535691}, From 1bc30a04b12277cff193fd70ee39599768dd27a1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 11 Apr 2024 15:01:20 +0100 Subject: [PATCH 594/737] eckit::geo::Grid --- src/eckit/geo/grid/ORCA.h | 4 +- src/eckit/geo/grid/Regular.h | 6 +-- src/eckit/geo/grid/RegularGaussian.h | 4 +- src/eckit/geo/grid/RegularLL.h | 4 +- src/eckit/geo/grid/XYToLonLat.cc | 61 ++++++++++++++-------------- src/eckit/geo/grid/XYToLonLat.h | 35 +++------------- src/eckit/geo/iterator/Regular.cc | 4 +- tests/geo/grid_regular_ll.cc | 4 +- 8 files changed, 50 insertions(+), 72 deletions(-) diff --git a/src/eckit/geo/grid/ORCA.h b/src/eckit/geo/grid/ORCA.h index cc7297e91..fe04613ab 100644 --- a/src/eckit/geo/grid/ORCA.h +++ b/src/eckit/geo/grid/ORCA.h @@ -82,8 +82,8 @@ class ORCA final : public Regular { // -- Methods - size_t ni() const override { return record_.ni(); } - size_t nj() const override { return record_.nj(); } + size_t nx() const override { return record_.nj(); } + size_t ny() const override { return record_.ni(); } std::string name() const { return name_; } std::string arrangement() const; diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index 0deb33b5b..2364040e8 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -45,12 +45,12 @@ class Regular : public Grid { // -- Methods - virtual size_t ni() const = 0; - virtual size_t nj() const = 0; + virtual size_t nx() const = 0; + virtual size_t ny() const = 0; // -- Overridden methods - size_t size() const override { return ni() * nj(); } + size_t size() const final { return nx() * ny(); } // -- Class members // None diff --git a/src/eckit/geo/grid/RegularGaussian.h b/src/eckit/geo/grid/RegularGaussian.h index da999615c..9995ecf60 100644 --- a/src/eckit/geo/grid/RegularGaussian.h +++ b/src/eckit/geo/grid/RegularGaussian.h @@ -51,8 +51,8 @@ class RegularGaussian final : public Regular { iterator cbegin() const override; iterator cend() const override; - size_t ni() const override { return x_->size(); } - size_t nj() const override { return y_->size(); } + size_t nx() const override { return x_->size(); } + size_t ny() const override { return y_->size(); } // -- Class members // None diff --git a/src/eckit/geo/grid/RegularLL.h b/src/eckit/geo/grid/RegularLL.h index 782467019..b5c807a8a 100644 --- a/src/eckit/geo/grid/RegularLL.h +++ b/src/eckit/geo/grid/RegularLL.h @@ -56,8 +56,8 @@ class RegularLL final : public Regular { iterator cbegin() const override; iterator cend() const override; - size_t ni() const override { return lon_.size(); } - size_t nj() const override { return lat_.size(); } + size_t nx() const override { return lon_.size(); } + size_t ny() const override { return lat_.size(); } // -- Class members // None diff --git a/src/eckit/geo/grid/XYToLonLat.cc b/src/eckit/geo/grid/XYToLonLat.cc index 8511d6878..14e08f16e 100644 --- a/src/eckit/geo/grid/XYToLonLat.cc +++ b/src/eckit/geo/grid/XYToLonLat.cc @@ -22,49 +22,50 @@ namespace eckit::geo::grid { -XYToLonLat::XYToLonLat(const Spec& spec) : - XYToLonLat(Internal(spec)) {} +namespace { -XYToLonLat::XYToLonLat(Internal&& internal) : - internal_(internal) {} +std::array grid_from_spec(const Spec& spec) { + std::array grid{0, 0}; + if (std::vector value; spec.get("grid", value) && value.size() == 2) { + grid[0] = value[0]; + grid[1] = value[1]; + } + else if (!spec.get("dx", grid[0]) || !spec.get("dy", grid[1])) { + throw SpecNotFound("'grid' = ['dx', 'dy'] expected"); + } + if (!(grid[0] > 0) || !(grid[1] > 0)) { + throw BadValue("'grid' = ['dx', 'dy'] > 0 expected"); + } -XYToLonLat::XYToLonLat(double dx, double dy, size_t nx, size_t ny) : - XYToLonLat(Internal{dx, dy, nx, ny}) {} + return grid; +} -XYToLonLat::Internal::Internal(const Spec& spec) : - grid{0., 0.}, shape{0, 0} { +std::array shape_from_spec(const Spec& spec) { + std::array shape{0, 0}; if (std::vector value; spec.get("shape", value) && value.size() == 2) { - shape = {value[0], value[1]}; + shape[0] = value[0]; + shape[1] = value[1]; } else if (!spec.get("nx", shape[0]) || !spec.get("ny", shape[1])) { - throw SpecNotFound("'shape': ['nx', 'ny'] expected"); + throw SpecNotFound("'shape' = ['nx', 'ny'] expected"); } - if (std::vector value; spec.get("grid", value) && value.size() == 2) { - grid = {value[0], value[1]}; - } - else if (!spec.get("dx", grid[0]) || !spec.get("dy", grid[1])) { - throw SpecNotFound("'grid': ['dx', 'dy'] expected"); + if (!(shape[0] > 0) || !(shape[1] > 0)) { + throw BadValue("'shape' = ['nx', 'ny'] > 0 expected"); } - check(); + return shape; } -XYToLonLat::Internal::Internal(double dx, double dy, size_t nx, size_t ny) : - grid{dx, dy}, shape{nx, ny} { - check(); -} +} // namespace -void XYToLonLat::Internal::check() const { - ASSERT_MSG(grid[0] > 0 && grid[1] > 0, - "'grid' > 0 failed, got grid: [" + std::to_string(grid[0]) + ", " + std::to_string(grid[0]) + "]"); - ASSERT_MSG(shape[0] > 0 && shape[1] > 0, - "'shape' > 0 failed, got shape: [" + std::to_string(shape[0]) + ", " + std::to_string(shape[0]) + "]"); -} + +XYToLonLat::XYToLonLat(const Spec& spec) : + Regular(spec), grid_(grid_from_spec(spec)), shape_(shape_from_spec(spec)) {} Grid::iterator XYToLonLat::cbegin() const { @@ -93,8 +94,8 @@ static const GridRegisterType __grid_type2("mercator"); void Mercator::spec(spec::Custom& custom) const { custom.set("type", "mercator"); - custom.set("grid", std::vector{dj(), di()}); - custom.set("shape", std::vector{static_cast(nj()), static_cast(ni())}); + custom.set("grid", std::vector{dy(), dx()}); + custom.set("shape", std::vector{static_cast(ny()), static_cast(nx())}); // FIXME a lot more stuff to add here! //... @@ -108,8 +109,8 @@ void Mercator::spec(spec::Custom& custom) const { void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { custom.set("type", "lambert_azimuthal_equal_area"); - custom.set("grid", std::vector{dj(), di()}); - custom.set("shape", std::vector{static_cast(nj()), static_cast(ni())}); + custom.set("grid", std::vector{dy(), dx()}); + custom.set("shape", std::vector{static_cast(ny()), static_cast(nx())}); // FIXME a lot more stuff to add here! //... diff --git a/src/eckit/geo/grid/XYToLonLat.h b/src/eckit/geo/grid/XYToLonLat.h index 1acd1e893..5a6cd1c87 100644 --- a/src/eckit/geo/grid/XYToLonLat.h +++ b/src/eckit/geo/grid/XYToLonLat.h @@ -43,23 +43,17 @@ class XYToLonLat : public Regular { // -- Methods - double dx() const { return internal_.grid[0]; }; - double dy() const { return internal_.grid[1]; }; + double dx() const { return grid_[0]; }; + double dy() const { return grid_[1]; }; - size_t nx() const { return internal_.shape[0]; } - size_t ny() const { return internal_.shape[1]; } - - double di() const { return dy(); }; - double dj() const { return dx(); }; + size_t nx() const override { return shape_[1]; } + size_t ny() const override { return shape_[0]; } // -- Overridden methods iterator cbegin() const override; iterator cend() const override; - size_t ni() const override { return ny(); } - size_t nj() const override { return nx(); } - // -- Class members // None @@ -67,24 +61,6 @@ class XYToLonLat : public Regular { // None protected: - // -- Types - - struct Internal { - explicit Internal(const Spec&); - Internal(double dx, double dy, size_t nx, size_t ny); - - void check() const; - - std::array grid; - std::array shape; - }; - - // -- Constructors - - explicit XYToLonLat(Internal&&); - - XYToLonLat(double dx, double dy, size_t nx, size_t ny); - // -- Members // None @@ -103,7 +79,8 @@ class XYToLonLat : public Regular { private: // -- Members - const Internal internal_; + std::array grid_; + std::array shape_; // -- Methods // None diff --git a/src/eckit/geo/iterator/Regular.cc b/src/eckit/geo/iterator/Regular.cc index eab916b3a..7866e2835 100644 --- a/src/eckit/geo/iterator/Regular.cc +++ b/src/eckit/geo/iterator/Regular.cc @@ -29,8 +29,8 @@ Regular::Regular(const Grid& grid, size_t index) : ni_(longitudes_.size()), nj_(latitudes_.size()), size_(ni_ * nj_) { - ASSERT(longitudes_.size() == grid_.ni()); - ASSERT(latitudes_.size() == grid_.nj()); + ASSERT(longitudes_.size() == grid_.nx()); + ASSERT(latitudes_.size() == grid_.ny()); } diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index 744e85f88..ce113eba4 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -32,8 +32,8 @@ CASE("global") { for (const auto& grid : {grid::RegularLL({1., 1.}, {89.5, 0.5, -89.5, 359.5}), grid::RegularLL({1., 1.}, {90., 0., -90, 360.}, {0.5, 0.5})}) { - EXPECT(grid.ni() == 360); - EXPECT(grid.nj() == 180); + EXPECT(grid.nx() == 360); + EXPECT(grid.ny() == 180); EXPECT(grid.size() == 360 * 180); } } From 9af1836f9fd8a9d4a33d25349f13333946bda060 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 11 Apr 2024 19:25:57 +0100 Subject: [PATCH 595/737] eckit::geo::Grid --- src/eckit/geo/CMakeLists.txt | 8 +- src/eckit/geo/Increments.cc | 30 ++-- src/eckit/geo/Increments.h | 48 ++---- src/eckit/geo/Range.h | 6 + src/eckit/geo/Shape.cc | 45 ++++++ src/eckit/geo/Shape.h | 87 +++++++++++ src/eckit/geo/grid/ORCA.h | 3 - src/eckit/geo/grid/Regular.cc | 193 +++++++++++++++++++++++- src/eckit/geo/grid/Regular.h | 98 ++++++------ src/eckit/geo/grid/RegularGaussian.cc | 85 ----------- src/eckit/geo/grid/RegularGaussian.h | 95 ------------ src/eckit/geo/grid/RegularLL.cc | 89 ----------- src/eckit/geo/grid/RegularLL.h | 96 ------------ src/eckit/geo/grid/XYToLonLat.cc | 125 --------------- src/eckit/geo/grid/XYToLonLat.h | 117 -------------- src/eckit/geo/iterator/Regular.cc | 21 ++- src/eckit/geo/iterator/Regular.h | 17 ++- src/eckit/geo/range/GaussianLatitude.cc | 6 + src/eckit/geo/range/GaussianLatitude.h | 1 + src/eckit/geo/range/Regular.h | 13 +- src/eckit/geo/range/RegularCartesian.h | 2 + tests/geo/grid_regular_gg.cc | 2 +- tests/geo/grid_regular_ll.cc | 2 +- tests/geo/increments.cc | 24 +-- 24 files changed, 451 insertions(+), 762 deletions(-) create mode 100644 src/eckit/geo/Shape.cc create mode 100644 src/eckit/geo/Shape.h delete mode 100644 src/eckit/geo/grid/RegularGaussian.cc delete mode 100644 src/eckit/geo/grid/RegularGaussian.h delete mode 100644 src/eckit/geo/grid/RegularLL.cc delete mode 100644 src/eckit/geo/grid/RegularLL.h delete mode 100644 src/eckit/geo/grid/XYToLonLat.cc delete mode 100644 src/eckit/geo/grid/XYToLonLat.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 88e6bbfba..3bcf048d1 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -34,6 +34,8 @@ list(APPEND eckit_geo_srcs Range.h Renumber.h Search.h + Shape.cc + Shape.h Spec.cc Spec.h Sphere.cc @@ -60,14 +62,8 @@ list(APPEND eckit_geo_srcs grid/ReducedLocal.h grid/Regular.cc grid/Regular.h - grid/RegularGaussian.cc - grid/RegularGaussian.h - grid/RegularLL.cc - grid/RegularLL.h grid/Unstructured.cc grid/Unstructured.h - grid/XYToLonLat.cc - grid/XYToLonLat.h iterator/Reduced.cc iterator/Reduced.h iterator/Regular.cc diff --git a/src/eckit/geo/Increments.cc b/src/eckit/geo/Increments.cc index bd54fddfc..aed5c4ed7 100644 --- a/src/eckit/geo/Increments.cc +++ b/src/eckit/geo/Increments.cc @@ -20,29 +20,31 @@ namespace eckit::geo { -static Increments make_from_spec(const Spec& spec) { - if (std::vector grid; spec.get("grid", grid) && grid.size() == 2) { - return {grid[0], grid[1]}; +Increments Increments::make_from_spec(const Spec& spec) { + value_type x = 0; + value_type y = 0; + if (std::vector value; spec.get("increments", value) || spec.get("grid", value) && value.size() == 2) { + x = value[0]; + y = value[1]; + } + else if (!spec.get("dx", x) || !spec.get("dy", y)) { + throw SpecNotFound("'increments' = ['dx', 'dy'] expected"); } - throw BadParameter("Increments: expected list of size 2"); + return {x, y}; } -Increments::Increments(double west_east, double south_north) : - array{west_east, south_north} { - ASSERT(!types::is_equal(operator[](0), 0.)); - ASSERT(!types::is_equal(operator[](1), 0.)); +Increments::Increments(value_type dx, value_type dy) : + array{dx, dy} { + if (!(dx != 0) || !(dy != 0)) { + throw BadValue("'shape' = ['dx', 'dy'] != 0 expected"); + } } -Increments::Increments(const Spec& spec) : - Increments(make_from_spec(spec)) {} - - bool Increments::operator==(const Increments& other) const { - return west_east == other.west_east && south_north == other.south_north; + return types::is_approximately_equal(dx, other.dx) && types::is_approximately_equal(dy, other.dy); } - } // namespace eckit::geo diff --git a/src/eckit/geo/Increments.h b/src/eckit/geo/Increments.h index 66439a11e..c6b86052f 100644 --- a/src/eckit/geo/Increments.h +++ b/src/eckit/geo/Increments.h @@ -24,19 +24,14 @@ class Spec; namespace eckit::geo { -class Increments : protected std::array { +class Increments : public std::array { public: - // -- Exceptions - // None - // -- Constructors - explicit Increments(const Spec&); - - Increments(double west_east, double south_north); + explicit Increments(const Spec& spec) : + Increments(make_from_spec(spec)) {} - Increments() : - Increments(0, 0) {} + Increments(value_type dx, value_type dy); Increments(const Increments& other) : array(other) {} @@ -48,9 +43,6 @@ class Increments : protected std::array { ~Increments() = default; - // -- Convertors - // None - // -- Operators bool operator==(const Increments& other) const; @@ -68,42 +60,22 @@ class Increments : protected std::array { // Members - double& west_east = array::operator[](0); - double& south_north = array::operator[](1); + value_type& dx = array::operator[](0); + value_type& dy = array::operator[](1); // -- Methods - std::array deconstruct() const { return {west_east, south_north}; } - - // -- Overridden methods - // None - - // -- Class members - // None + std::array deconstruct() const { return {dx, dy}; } // -- Class methods - // None -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None + static Increments make_from_spec(const Spec&); +private: // -- Friends friend std::ostream& operator<<(std::ostream& os, const Increments& inc) { - return os << "[" << inc.west_east << "," << inc.south_north << "]"; + return os << "[" << inc.dx << "," << inc.dy << "]"; } }; diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 844ef97b8..0207eecbb 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -15,6 +15,11 @@ #include +namespace eckit { +class Fraction; +} + + namespace eckit::geo { @@ -45,6 +50,7 @@ class Range { virtual Range* flip() const = 0; virtual Range* crop(double crop_a, double crop_b) const = 0; + virtual Fraction increment() const = 0; virtual const std::vector& values() const = 0; protected: diff --git a/src/eckit/geo/Shape.cc b/src/eckit/geo/Shape.cc new file mode 100644 index 000000000..0f6ea8bc0 --- /dev/null +++ b/src/eckit/geo/Shape.cc @@ -0,0 +1,45 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Shape.h" + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/Spec.h" + + +namespace eckit::geo { + + +Shape Shape::make_from_spec(const Spec& spec) { + value_type x = 0; + value_type y = 0; + if (std::vector value; spec.get("shape", value) && value.size() == 2) { + x = value[0]; + y = value[1]; + } + else if (!spec.get("nx", x) || !spec.get("ny", y)) { + throw SpecNotFound("'shape' = ['nx', 'ny'] expected"); + } + + return {x, y}; +} + + +Shape::Shape(value_type nx, value_type ny) : + array{nx, ny} { + if (!(nx > 0) || !(ny > 0)) { + throw BadValue("'shape' = ['nx', 'ny'] > 0 expected"); + } +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Shape.h b/src/eckit/geo/Shape.h new file mode 100644 index 000000000..b777f303a --- /dev/null +++ b/src/eckit/geo/Shape.h @@ -0,0 +1,87 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + + +namespace eckit::geo { +class Spec; +} + + +namespace eckit::geo { + + +class Shape final : public std::array { +public: + // -- Constructors + + explicit Shape(const Spec& spec) : + Shape(make_from_spec(spec)) {} + + Shape(value_type nx, value_type ny); + + Shape() : + Shape(0, 0) {} + + Shape(const Shape& other) : + array(other) {} + + Shape(Shape&& other) : + array(other) {} + + // -- Destructor + + ~Shape() = default; + + // -- Operators + + bool operator==(const Shape& other) const { return nx == other.nx && ny == other.ny; } + + bool operator!=(const Shape& other) const { return !operator==(other); } + + Shape& operator=(const Shape& other) { + array::operator=(other); + return *this; + } + + Shape& operator=(Shape&& other) { + array::operator=(other); + return *this; + } + + // Members + + value_type& nx = array::operator[](0); + value_type& ny = array::operator[](1); + + // -- Methods + + std::array deconstruct() const { return {nx, ny}; } + + // -- Class methods + + static Shape make_from_spec(const Spec&); + +private: + // -- Friends + + friend std::ostream& operator<<(std::ostream& os, const Shape& inc) { + return os << "[" << inc.nx << "," << inc.ny << "]"; + } +}; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/grid/ORCA.h b/src/eckit/geo/grid/ORCA.h index fe04613ab..ecbadc93d 100644 --- a/src/eckit/geo/grid/ORCA.h +++ b/src/eckit/geo/grid/ORCA.h @@ -106,9 +106,6 @@ class ORCA final : public Regular { std::vector to_points() const override; std::pair, std::vector> to_latlon() const override; - const std::vector& longitudes() const override { return record_.longitudes_; } - const std::vector& latitudes() const override { return record_.latitudes_; } - // -- Class members // None diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index 366ba9a7d..fa4e6b584 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -12,16 +12,201 @@ #include "eckit/geo/grid/Regular.h" +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/Increments.h" +#include "eckit/geo/Spec.h" +#include "eckit/geo/etc/Grid.h" +#include "eckit/geo/iterator/Regular.h" +#include "eckit/geo/range/GaussianLatitude.h" +#include "eckit/geo/range/RegularCartesian.h" +#include "eckit/geo/range/RegularLatitude.h" +#include "eckit/geo/range/RegularLongitude.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/types/Fraction.h" +#include "eckit/utils/Translator.h" + namespace eckit::geo::grid { -Regular::Regular(const Spec& spec) : - Grid(spec) {} +double Regular::dx() const { + return x().increment(); +} + + +double Regular::dy() const { + return y().increment(); +} + + +Grid::iterator Regular::cbegin() const { + return iterator{new geo::iterator::Regular(*this, 0)}; +} + + +Grid::iterator Regular::cend() const { + return iterator{new geo::iterator::Regular(*this, size())}; +} + + +const Range& Regular::x() const { + ASSERT(x_ && x_->size() > 0); + return *x_; +} + + +const Range& Regular::y() const { + ASSERT(y_ && y_->size() > 0); + return *y_; +} + + +Regular::Regular(std::pair xy, const area::BoundingBox& bbox) : + Grid(bbox), x_(xy.first), y_(xy.second) { + ASSERT(x_ && x_->size() > 0); + ASSERT(y_ && y_->size() > 0); +} + + +std::pair Regular::make_cartesian_ranges_from_spec(const Spec& spec) { + Increments inc(spec); + Shape shape(spec); + + // FIXME This is a hack, we should not be using these keys + Point2 a{spec.get_double("longitudeOfFirstGridPointInDegrees"), + spec.get_double("latitudeOfFirstGridPointInDegrees")}; + Point2 b{a.X + inc.dx * (shape.nx - 1), a.Y - inc.dy * (shape.ny - 1)}; + + return {new range::RegularCartesian(shape.nx, a.X, b.X), new range::RegularCartesian(shape.ny, a.Y, b.Y)}; +} + + +#define POSITIVE_REAL "[+]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][-+][0-9]+)?" +static const std::string REGULAR_LL_PATTERN("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); +#undef POSITIVE_REAL + + +RegularLL::RegularLL(const Spec& spec) : + RegularLL(Increments{spec}, area::BoundingBox{spec}, [&spec]() -> PointLonLat { + if (double lon = 0., lat = 0.; spec.get("reference_lon", lon) && spec.get("reference_lat", lat)) { + return {lon, lat}; + } + + area::BoundingBox area{spec}; + return {area.west, area.south}; + }()) { + ASSERT(size() > 0); +} + + +RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : + RegularLL(inc, bbox, {bbox.south, bbox.west}) {} + + +RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& ref) : + Regular({new range::RegularLongitude(inc.dx, bbox.west, bbox.east, ref.lon, 0.), + new range::RegularLatitude(inc.dy, bbox.north, bbox.south, ref.lat, 0.)}, + bbox) { + ASSERT(size() > 0); +} + + +Spec* RegularLL::spec(const std::string& name) { + std::smatch match; + std::regex_match(name, match, std::regex(REGULAR_LL_PATTERN)); + ASSERT(match.size() == 9); + + auto d = Translator{}; + + return new spec::Custom({{"type", "regular_ll"}, {"grid", std::vector{d(match[1]), d(match[5])}}}); +} + + +void RegularLL::spec(spec::Custom& custom) const { + custom.set("grid", std::vector{dx(), dy()}); + boundingBox().spec(custom); +} + + +RegularGaussian::RegularGaussian(const Spec& spec) : + RegularGaussian(spec.get_unsigned("N"), area::BoundingBox(spec)) {} + + +RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : + Regular({range::RegularLongitude(4 * N, 0., 360.).crop(bbox.west, bbox.east), + range::GaussianLatitude(N, false).crop(bbox.north, bbox.south)}, + bbox), + N_(N) { + ASSERT(size() > 0); +} + + +Grid* RegularGaussian::make_grid_cropped(const area::BoundingBox& crop) const { + if (auto bbox(boundingBox()); crop.intersects(bbox)) { + return new RegularGaussian(N_, bbox); + } + + throw Exception("RegularGaussian: cannot crop grid (empty intersection)"); +} + + +Spec* RegularGaussian::spec(const std::string& name) { + auto N = Translator{}(name.substr(1)); + return new spec::Custom({{"type", "regular_gg"}, {"N", N}}); +} + + +void RegularGaussian::spec(spec::Custom& custom) const { + custom.set("grid", "F" + std::to_string(N_)); + boundingBox().spec(custom); +} + + +struct Mercator final : public Regular { + explicit Mercator(const Spec& spec) : + Regular(Regular::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} + void spec(spec::Custom& custom) const override { + custom.set("type", "mercator"); + custom.set("grid", std::vector{dx(), dy()}); + custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); + + // FIXME a lot more stuff to add here! + //... + + if (std::string name; SpecByName::instance().match(custom, name)) { + custom.clear(); + custom.set("grid", name); + } + } +}; + + +struct LambertAzimuthalEqualArea final : public Regular { + explicit LambertAzimuthalEqualArea(const Spec& spec) : + Regular(Regular::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} + void spec(spec::Custom& custom) const override { + custom.set("type", "lambert_azimuthal_equal_area"); + custom.set("grid", std::vector{dx(), dy()}); + custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); + + // FIXME a lot more stuff to add here! + //... + + if (std::string name; SpecByName::instance().match(custom, name)) { + custom.clear(); + custom.set("grid", name); + } + } +}; + +static const GridRegisterName __grid_pattern1(REGULAR_LL_PATTERN); +static const GridRegisterName __grid_pattern2("[fF][1-9][0-9]*"); -Regular::Regular(const area::BoundingBox& bbox) : - Grid(bbox) {} +static const GridRegisterType __grid_type1("regular_ll"); +static const GridRegisterType __grid_type2("regular_gg"); +static const GridRegisterType __grid_type3("mercator"); +static const GridRegisterType __grid_type4("lambert_azimuthal_equal_area"); } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index 2364040e8..c25aed272 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -12,12 +12,21 @@ #pragma once +#include +#include + #include "eckit/geo/Grid.h" +#include "eckit/geo/PointLonLat.h" +#include "eckit/geo/Range.h" +#include "eckit/geo/Shape.h" -namespace eckit::geo::iterator { +namespace eckit::geo { +class Increments; +namespace iterator { class Regular; } +} // namespace eckit::geo namespace eckit::geo::grid { @@ -25,81 +34,72 @@ namespace eckit::geo::grid { class Regular : public Grid { public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors - // None - - // -- Destructor - // None - // -- Convertors - // None - - // -- Operators - // None + explicit Regular(const Spec& spec) : + Grid(spec) {} // -- Methods - virtual size_t nx() const = 0; - virtual size_t ny() const = 0; + virtual double dx() const; + virtual double dy() const; + + virtual size_t nx() const { return x_->size(); } + virtual size_t ny() const { return y_->size(); } // -- Overridden methods - size_t size() const final { return nx() * ny(); } + iterator cbegin() const override; + iterator cend() const override; - // -- Class members - // None + size_t size() const final { return nx() * ny(); } - // -- Class methods - // None + const Range& x() const; + const Range& y() const; protected: // -- Constructors - explicit Regular(const Spec&); - explicit Regular(const area::BoundingBox& = area::BoundingBox::make_global_prime()); - - // -- Members - // None + Regular(std::pair xy, const area::BoundingBox&); // -- Methods - virtual const std::vector& longitudes() const = 0; - virtual const std::vector& latitudes() const = 0; + static std::pair make_cartesian_ranges_from_spec(const Spec& spec); - // -- Overridden methods - // None +private: + // -- Members - // -- Class members - // None + std::unique_ptr x_; + std::unique_ptr y_; - // -- Class methods - // None + // -- Friends -private: - // -- Members - // None + friend class geo::iterator::Regular; +}; - // -- Methods - // None - // -- Overridden methods - // None +struct RegularLL final : public Regular { + explicit RegularLL(const Spec&); + explicit RegularLL(const Increments&, const area::BoundingBox& = {}); + RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); - // -- Class members - // None + static Spec* spec(const std::string& name); + void spec(spec::Custom&) const override; +}; - // -- Class methods - // None - // -- Friends +struct RegularGaussian final : public Regular { + explicit RegularGaussian(const Spec&); + explicit RegularGaussian(size_t N, const area::BoundingBox& = area::BoundingBox::make_global_prime()); - friend class geo::iterator::Regular; + Grid* make_grid_cropped(const area::BoundingBox& crop) const override; + static Spec* spec(const std::string& name); + void spec(spec::Custom&) const override; + + size_t N() const { return N_; } + +private: + const size_t N_; }; diff --git a/src/eckit/geo/grid/RegularGaussian.cc b/src/eckit/geo/grid/RegularGaussian.cc deleted file mode 100644 index f73d096fd..000000000 --- a/src/eckit/geo/grid/RegularGaussian.cc +++ /dev/null @@ -1,85 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/RegularGaussian.h" - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/iterator/Regular.h" -#include "eckit/geo/range/GaussianLatitude.h" -#include "eckit/geo/range/RegularLongitude.h" -#include "eckit/geo/spec/Custom.h" -#include "eckit/utils/Translator.h" - - -namespace eckit::geo::grid { - - -RegularGaussian::RegularGaussian(const Spec& spec) : - RegularGaussian(spec.get_unsigned("N"), area::BoundingBox(spec)) {} - - -RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : - Regular(bbox), - N_(N), - x_(range::RegularLongitude(4 * N, 0., 360.).crop(bbox.west, bbox.east)), - y_(range::GaussianLatitude(N, false).crop(bbox.north, bbox.south)) { - ASSERT(x_->size() > 0); - ASSERT(y_->size() > 0); -} - - -Grid::iterator RegularGaussian::cbegin() const { - return iterator{new geo::iterator::Regular(*this, 0)}; -} - - -Grid::iterator RegularGaussian::cend() const { - return iterator{new geo::iterator::Regular(*this, size())}; -} - - -Spec* RegularGaussian::spec(const std::string& name) { - auto N = Translator{}(name.substr(1)); - return new spec::Custom({{"type", "regular_gg"}, {"N", N}}); -} - - -const std::vector& RegularGaussian::longitudes() const { - return x_->values(); -} - - -const std::vector& RegularGaussian::latitudes() const { - return y_->values(); -} - - -void RegularGaussian::spec(spec::Custom& custom) const { - custom.set("grid", "F" + std::to_string(N_)); - boundingBox().spec(custom); -} - - -Grid* RegularGaussian::make_grid_cropped(const area::BoundingBox& crop) const { - if (auto bbox(boundingBox()); crop.intersects(bbox)) { - return new RegularGaussian(N_, bbox); - } - - throw Exception("RegularGaussian: cannot crop grid (empty intersection)"); -} - - -static const GridRegisterType __grid_type("regular_gg"); -static const GridRegisterName __grid_pattern("[fF][1-9][0-9]*"); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularGaussian.h b/src/eckit/geo/grid/RegularGaussian.h deleted file mode 100644 index 9995ecf60..000000000 --- a/src/eckit/geo/grid/RegularGaussian.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include - -#include "eckit/geo/Range.h" -#include "eckit/geo/grid/Regular.h" - - -namespace eckit::geo::grid { - - -class RegularGaussian final : public Regular { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit RegularGaussian(const Spec&); - explicit RegularGaussian(size_t N, const area::BoundingBox& = area::BoundingBox::make_global_prime()); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - - iterator cbegin() const override; - iterator cend() const override; - - size_t nx() const override { return x_->size(); } - size_t ny() const override { return y_->size(); } - - // -- Class members - // None - - // -- Class methods - - static Spec* spec(const std::string& name); - -private: - // -- Members - - const size_t N_; - - std::unique_ptr x_; - std::unique_ptr y_; - - // -- Methods - // None - - // -- Overridden methods - - const std::vector& longitudes() const override; - const std::vector& latitudes() const override; - - void spec(spec::Custom&) const override; - - Grid* make_grid_cropped(const area::BoundingBox&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularLL.cc b/src/eckit/geo/grid/RegularLL.cc deleted file mode 100644 index 06745a439..000000000 --- a/src/eckit/geo/grid/RegularLL.cc +++ /dev/null @@ -1,89 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/RegularLL.h" - -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/Increments.h" -#include "eckit/geo/iterator/Regular.h" -#include "eckit/geo/spec/Custom.h" -#include "eckit/types/Fraction.h" -#include "eckit/utils/Translator.h" - - -namespace eckit::geo::grid { - - -RegularLL::RegularLL(const Spec& spec) : - RegularLL(Increments{spec}, area::BoundingBox{spec}, [&spec]() -> PointLonLat { - if (double lon = 0., lat = 0.; spec.get("reference_lon", lon) && spec.get("reference_lat", lat)) { - return {lon, lat}; - } - - area::BoundingBox area{spec}; - return {area.west, area.south}; - }()) { - ASSERT(size() > 0); -} - - -RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : - RegularLL(inc, bbox, {bbox.south, bbox.west}) {} - - -RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& ref) : - Regular(bbox), - lon_(inc.west_east, bbox.west, bbox.east, ref.lon, 0.), - lat_(inc.south_north, bbox.north, bbox.south, ref.lat, 0.) { - ASSERT(size() > 0); -} - - -Grid::iterator RegularLL::cbegin() const { - return iterator{new geo::iterator::Regular(*this, 0)}; -} - - -Grid::iterator RegularLL::cend() const { - return iterator{new geo::iterator::Regular(*this, size())}; -} - - -void RegularLL::spec(spec::Custom& custom) const { - custom.set("grid", std::vector{lon_.increment(), lat_.increment()}); - boundingBox().spec(custom); -} - - -#define POSITIVE_REAL "[+]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][-+][0-9]+)?" -static const std::string PATTERN("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); -#undef POSITIVE_REAL - - -Spec* RegularLL::spec(const std::string& name) { - std::smatch match; - std::regex_match(name, match, std::regex(PATTERN)); - ASSERT(match.size() == 9); - - auto d = Translator{}; - - return new spec::Custom({{"type", "regular_ll"}, {"grid", std::vector{d(match[1]), d(match[5])}}}); -} - - -static const GridRegisterType __grid_type("regular_ll"); -static const GridRegisterName __grid_pattern(PATTERN); - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularLL.h b/src/eckit/geo/grid/RegularLL.h deleted file mode 100644 index b5c807a8a..000000000 --- a/src/eckit/geo/grid/RegularLL.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/grid/Regular.h" -#include "eckit/geo/range/RegularLatitude.h" -#include "eckit/geo/range/RegularLongitude.h" - - -namespace eckit::geo { -class Increments; -} // namespace eckit::geo - - -namespace eckit::geo::grid { - - -class RegularLL final : public Regular { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit RegularLL(const Spec&); - explicit RegularLL(const Increments&, const area::BoundingBox& = {}); - RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - - iterator cbegin() const override; - iterator cend() const override; - - size_t nx() const override { return lon_.size(); } - size_t ny() const override { return lat_.size(); } - - // -- Class members - // None - - // -- Class methods - - static Spec* spec(const std::string& name); - -private: - // -- Members - - const range::RegularLongitude lon_; - const range::RegularLatitude lat_; - - // -- Methods - // None - - // -- Overridden methods - - const std::vector& longitudes() const override { return lon_.values(); } - const std::vector& latitudes() const override { return lat_.values(); } - - void spec(spec::Custom&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/XYToLonLat.cc b/src/eckit/geo/grid/XYToLonLat.cc deleted file mode 100644 index 14e08f16e..000000000 --- a/src/eckit/geo/grid/XYToLonLat.cc +++ /dev/null @@ -1,125 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/XYToLonLat.h" - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/Spec.h" -#include "eckit/geo/etc/Grid.h" -#include "eckit/geo/iterator/Regular.h" -#include "eckit/geo/spec/Custom.h" - - -namespace eckit::geo::grid { - - -namespace { - - -std::array grid_from_spec(const Spec& spec) { - std::array grid{0, 0}; - if (std::vector value; spec.get("grid", value) && value.size() == 2) { - grid[0] = value[0]; - grid[1] = value[1]; - } - else if (!spec.get("dx", grid[0]) || !spec.get("dy", grid[1])) { - throw SpecNotFound("'grid' = ['dx', 'dy'] expected"); - } - - if (!(grid[0] > 0) || !(grid[1] > 0)) { - throw BadValue("'grid' = ['dx', 'dy'] > 0 expected"); - } - - return grid; -} - - -std::array shape_from_spec(const Spec& spec) { - std::array shape{0, 0}; - if (std::vector value; spec.get("shape", value) && value.size() == 2) { - shape[0] = value[0]; - shape[1] = value[1]; - } - else if (!spec.get("nx", shape[0]) || !spec.get("ny", shape[1])) { - throw SpecNotFound("'shape' = ['nx', 'ny'] expected"); - } - - if (!(shape[0] > 0) || !(shape[1] > 0)) { - throw BadValue("'shape' = ['nx', 'ny'] > 0 expected"); - } - - return shape; -} - - -} // namespace - - -XYToLonLat::XYToLonLat(const Spec& spec) : - Regular(spec), grid_(grid_from_spec(spec)), shape_(shape_from_spec(spec)) {} - - -Grid::iterator XYToLonLat::cbegin() const { - return iterator{new geo::iterator::Regular(*this, 0)}; -} - - -Grid::iterator XYToLonLat::cend() const { - return iterator{new geo::iterator::Regular(*this, size())}; -} - - -const std::vector& XYToLonLat::longitudes() const { - NOTIMP; -} - - -const std::vector& XYToLonLat::latitudes() const { - NOTIMP; -} - - -static const GridRegisterType __grid_type1("lambert_azimuthal_equal_area"); -static const GridRegisterType __grid_type2("mercator"); - - -void Mercator::spec(spec::Custom& custom) const { - custom.set("type", "mercator"); - custom.set("grid", std::vector{dy(), dx()}); - custom.set("shape", std::vector{static_cast(ny()), static_cast(nx())}); - - // FIXME a lot more stuff to add here! - //... - - if (std::string name; SpecByName::instance().match(custom, name)) { - custom.clear(); - custom.set("grid", name); - } -} - - -void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { - custom.set("type", "lambert_azimuthal_equal_area"); - custom.set("grid", std::vector{dy(), dx()}); - custom.set("shape", std::vector{static_cast(ny()), static_cast(nx())}); - - // FIXME a lot more stuff to add here! - //... - - if (std::string name; SpecByName::instance().match(custom, name)) { - custom.clear(); - custom.set("grid", name); - } -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/XYToLonLat.h b/src/eckit/geo/grid/XYToLonLat.h deleted file mode 100644 index 5a6cd1c87..000000000 --- a/src/eckit/geo/grid/XYToLonLat.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include - -#include "eckit/geo/grid/Regular.h" - - -namespace eckit::geo::grid { - - -class XYToLonLat : public Regular { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - - explicit XYToLonLat(const Spec&); - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - - double dx() const { return grid_[0]; }; - double dy() const { return grid_[1]; }; - - size_t nx() const override { return shape_[1]; } - size_t ny() const override { return shape_[0]; } - - // -- Overridden methods - - iterator cbegin() const override; - iterator cend() const override; - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - std::array grid_; - std::array shape_; - - // -- Methods - // None - - // -- Overridden methods - - const std::vector& longitudes() const override; - const std::vector& latitudes() const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -struct Mercator final : public XYToLonLat { - explicit Mercator(const Spec& spec) : - XYToLonLat(spec) {} - void spec(spec::Custom&) const override; -}; - -struct LambertAzimuthalEqualArea final : public XYToLonLat { - explicit LambertAzimuthalEqualArea(const Spec& spec) : - XYToLonLat(spec) {} - void spec(spec::Custom&) const override; -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/iterator/Regular.cc b/src/eckit/geo/iterator/Regular.cc index 7866e2835..c1bbadf29 100644 --- a/src/eckit/geo/iterator/Regular.cc +++ b/src/eckit/geo/iterator/Regular.cc @@ -19,19 +19,16 @@ namespace eckit::geo::iterator { -Regular::Regular(const Grid& grid, size_t index) : - grid_(dynamic_cast(grid)), - longitudes_(grid_.longitudes()), - latitudes_(grid_.latitudes()), +Regular::Regular(const grid::Regular& grid, size_t index) : + grid_(grid), + x_(grid.x().values()), + y_(grid.y().values()), i_(0), j_(0), index_(index), - ni_(longitudes_.size()), - nj_(latitudes_.size()), - size_(ni_ * nj_) { - ASSERT(longitudes_.size() == grid_.nx()); - ASSERT(latitudes_.size() == grid_.ny()); -} + nx_(x_.size()), + ny_(y_.size()), + size_(nx_ * nx_) {} bool Regular::operator==(const Iterator& other) const { @@ -42,7 +39,7 @@ bool Regular::operator==(const Iterator& other) const { bool Regular::operator++() { if (index_++, i_++; index_ < size_) { - if (i_ >= ni_) { + if (i_ >= nx_) { i_ = 0; j_++; } @@ -66,7 +63,7 @@ Regular::operator bool() const { Point Regular::operator*() const { - return PointLonLat{longitudes_.at(i_), latitudes_.at(j_)}; + return PointLonLat{x_.at(i_), y_.at(j_)}; } diff --git a/src/eckit/geo/iterator/Regular.h b/src/eckit/geo/iterator/Regular.h index 1bb3f5417..00dabc1bf 100644 --- a/src/eckit/geo/iterator/Regular.h +++ b/src/eckit/geo/iterator/Regular.h @@ -12,12 +12,17 @@ #pragma once +#include + #include "eckit/geo/Iterator.h" -namespace eckit::geo::grid { +namespace eckit::geo { +class Range; +namespace grid { class Regular; } +} // namespace eckit::geo namespace eckit::geo::iterator { @@ -33,7 +38,7 @@ class Regular final : public Iterator { // -- Constructors - explicit Regular(const Grid&, size_t index = 0); + explicit Regular(const grid::Regular&, size_t index = 0); // -- Destructor // None @@ -60,13 +65,13 @@ class Regular final : public Iterator { // -- Members const grid::Regular& grid_; - const std::vector& longitudes_; - const std::vector& latitudes_; + const std::vector& x_; + const std::vector& y_; size_t i_; size_t j_; size_t index_; - const size_t ni_; - const size_t nj_; + const size_t nx_; + const size_t ny_; const size_t size_; // -- Methods diff --git a/src/eckit/geo/range/GaussianLatitude.cc b/src/eckit/geo/range/GaussianLatitude.cc index 7404b05f1..2386b90ba 100644 --- a/src/eckit/geo/range/GaussianLatitude.cc +++ b/src/eckit/geo/range/GaussianLatitude.cc @@ -18,6 +18,7 @@ #include "eckit/geo/util.h" #include "eckit/geo/util/mutex.h" #include "eckit/types/FloatCompare.h" +#include "eckit/types/Fraction.h" namespace eckit::geo::range { @@ -60,6 +61,11 @@ Range* GaussianLatitude::crop(double crop_a, double crop_b) const { } +Fraction GaussianLatitude::increment() const { + NOTIMP; +} + + const std::vector& GaussianLatitude::values() const { util::lock_guard lock(MUTEX); return values_.empty() ? util::gaussian_latitudes(N_, a() < b()) : values_; diff --git a/src/eckit/geo/range/GaussianLatitude.h b/src/eckit/geo/range/GaussianLatitude.h index d2178105f..9eb2c98f7 100644 --- a/src/eckit/geo/range/GaussianLatitude.h +++ b/src/eckit/geo/range/GaussianLatitude.h @@ -32,6 +32,7 @@ class GaussianLatitude final : public Range { Range* flip() const override; Range* crop(double crop_a, double crop_b) const override; + Fraction increment() const override; const std::vector& values() const override; private: diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h index 6ded7488e..b6d6d8f0c 100644 --- a/src/eckit/geo/range/Regular.h +++ b/src/eckit/geo/range/Regular.h @@ -15,11 +15,6 @@ #include "eckit/geo/Range.h" -namespace eckit { -class Fraction; -} - - namespace eckit::geo::range { @@ -27,7 +22,7 @@ class Regular : public Range { public: // -- Methods - Fraction increment() const; + Fraction increment() const override; // -- Overridden methods @@ -36,12 +31,12 @@ class Regular : public Range { protected: // -- Constructors - explicit Regular(double inc, double a, double b, double ref, double eps); + Regular(double inc, double a, double b, double ref, double eps); - explicit Regular(size_t n, double a, double b, bool periodic, double eps) : + Regular(size_t n, double a, double b, bool periodic, double eps) : Range(n, a, b, eps), periodic_(periodic) {} - explicit Regular(size_t n, double a, double b, std::vector&& values, bool periodic, double eps) : + Regular(size_t n, double a, double b, std::vector&& values, bool periodic, double eps) : Range(n, a, b, eps), values_(values), periodic_(periodic) {} // -- Methods diff --git a/src/eckit/geo/range/RegularCartesian.h b/src/eckit/geo/range/RegularCartesian.h index b790d0f57..f55403034 100644 --- a/src/eckit/geo/range/RegularCartesian.h +++ b/src/eckit/geo/range/RegularCartesian.h @@ -22,6 +22,8 @@ class RegularCartesian final : public Regular { public: // -- Constructors + using Regular::Regular; + RegularCartesian(size_t n, double a, double b, double eps = 0.) : Regular(n, a, b, false, eps) {} diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index 7109fda30..d31022232 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -13,7 +13,7 @@ #include #include "eckit/geo/Grid.h" -#include "eckit/geo/grid/RegularGaussian.h" +#include "eckit/geo/grid/Regular.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/testing/Test.h" diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index ce113eba4..1c8eecaa6 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -12,7 +12,7 @@ #include -#include "eckit/geo/grid/RegularLL.h" +#include "eckit/geo/grid/Regular.h" #include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" diff --git a/tests/geo/increments.cc b/tests/geo/increments.cc index 4db8a1ce6..24f7f21d3 100644 --- a/tests/geo/increments.cc +++ b/tests/geo/increments.cc @@ -35,30 +35,30 @@ CASE("assignment") { Increments a(10, 1); Increments b(20, 2); - EXPECT_NOT_EQUAL(a.west_east, b.west_east); + EXPECT_NOT_EQUAL(a.dx, b.dx); EXPECT_NOT_EQUAL(a, b); b = a; - EXPECT_EQUAL(a.west_east, b.west_east); + EXPECT_EQUAL(a.dx, b.dx); EXPECT_EQUAL(a, b); - b.west_east = 30; - EXPECT_EQUAL(b.west_east, 30); - EXPECT_EQUAL(a.west_east, 10); + b.dx = 30; + EXPECT_EQUAL(b.dx, 30); + EXPECT_EQUAL(a.dx, 10); Increments c(a); - EXPECT_EQUAL(a.west_east, c.west_east); + EXPECT_EQUAL(a.dx, c.dx); EXPECT_EQUAL(a, c); - c.west_east = 40; - EXPECT_EQUAL(c.west_east, 40); - EXPECT_EQUAL(a.west_east, 10); + c.dx = 40; + EXPECT_EQUAL(c.dx, 40); + EXPECT_EQUAL(a.dx, 10); auto d(std::move(a)); - EXPECT_EQUAL(d.west_east, 10); + EXPECT_EQUAL(d.dx, 10); - d.west_east = 50; - EXPECT_EQUAL(d.west_east, 50); + d.dx = 50; + EXPECT_EQUAL(d.dx, 50); } From 906c803894b95d014e794fbce2cfbc77a2f542a7 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 12 Apr 2024 00:01:14 +0100 Subject: [PATCH 596/737] eckit::geo::Grid --- src/eckit/geo/CMakeLists.txt | 6 +- src/eckit/geo/grid/HEALPix.cc | 4 +- src/eckit/geo/grid/HEALPix.h | 15 ++- .../geo/grid/{ReducedGlobal.cc => Reduced.cc} | 16 +-- .../geo/grid/{ReducedGlobal.h => Reduced.h} | 62 ++-------- src/eckit/geo/grid/ReducedGaussian.cc | 2 +- src/eckit/geo/grid/ReducedGaussian.h | 10 +- src/eckit/geo/grid/ReducedLL.cc | 2 +- src/eckit/geo/grid/ReducedLL.h | 4 +- src/eckit/geo/grid/ReducedLocal.cc | 96 --------------- src/eckit/geo/grid/ReducedLocal.h | 112 ------------------ src/eckit/geo/iterator/Reduced.cc | 4 +- src/eckit/geo/iterator/Reduced.h | 4 +- 13 files changed, 38 insertions(+), 299 deletions(-) rename src/eckit/geo/grid/{ReducedGlobal.cc => Reduced.cc} (81%) rename src/eckit/geo/grid/{ReducedGlobal.h => Reduced.h} (62%) delete mode 100644 src/eckit/geo/grid/ReducedLocal.cc delete mode 100644 src/eckit/geo/grid/ReducedLocal.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 3bcf048d1..ece5754d7 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -52,14 +52,12 @@ list(APPEND eckit_geo_srcs figure/Sphere.h grid/HEALPix.cc grid/HEALPix.h + grid/Reduced.cc + grid/Reduced.h grid/ReducedGaussian.cc grid/ReducedGaussian.h - grid/ReducedGlobal.cc - grid/ReducedGlobal.h grid/ReducedLL.cc grid/ReducedLL.h - grid/ReducedLocal.cc - grid/ReducedLocal.h grid/Regular.cc grid/Regular.h grid/Unstructured.cc diff --git a/src/eckit/geo/grid/HEALPix.cc b/src/eckit/geo/grid/HEALPix.cc index 3b2044eaf..c396412e1 100644 --- a/src/eckit/geo/grid/HEALPix.cc +++ b/src/eckit/geo/grid/HEALPix.cc @@ -230,7 +230,7 @@ HEALPix::HEALPix(const Spec& spec) : HEALPix::HEALPix(size_t Nside, Ordering ordering) : - ReducedGlobal(area::BoundingBox::make_global_prime()), Nside_(Nside), ordering_(ordering) { + Reduced(area::BoundingBox::make_global_prime()), Nside_(Nside), ordering_(ordering) { ASSERT(Nside_ > 0); ASSERT_MSG(ordering == Ordering::healpix_ring || ordering == Ordering::healpix_nested, "HEALPix: supported orderings: ring, nested"); @@ -301,7 +301,7 @@ size_t HEALPix::size() const { std::vector HEALPix::to_points() const { - const auto points = ReducedGlobal::to_points(); + const auto points = Reduced::to_points(); if (ordering_ == Ordering::healpix_ring) { return points; diff --git a/src/eckit/geo/grid/HEALPix.h b/src/eckit/geo/grid/HEALPix.h index 89087800f..840ab7aa1 100644 --- a/src/eckit/geo/grid/HEALPix.h +++ b/src/eckit/geo/grid/HEALPix.h @@ -12,13 +12,13 @@ #pragma once -#include "eckit/geo/grid/ReducedGlobal.h" +#include "eckit/geo/grid/Reduced.h" namespace eckit::geo::grid { -class HEALPix final : public ReducedGlobal { +class HEALPix final : public Reduced { public: // -- Types // None @@ -51,11 +51,12 @@ class HEALPix final : public ReducedGlobal { size_t size() const override; - std::vector to_points() const override; - size_t ni(size_t j) const override; size_t nj() const override; + std::vector to_points() const override; + std::pair, std::vector> to_latlon() const override; + Ordering order() const override { return ordering_; } Renumber reorder(Ordering) const override; Grid* make_grid_reordered(Ordering ordering) const override { return new HEALPix(Nside_, ordering); } @@ -86,12 +87,10 @@ class HEALPix final : public ReducedGlobal { bool includesSouthPole() const override { return true; } bool isPeriodicWestEast() const override { return true; } - std::pair, std::vector> to_latlon() const override; + void spec(spec::Custom&) const override; const std::vector& latitudes() const override; - std::vector longitudes(size_t j) const override; - - void spec(spec::Custom&) const override; + std::vector longitudes(size_t i) const override; // -- Class members // None diff --git a/src/eckit/geo/grid/ReducedGlobal.cc b/src/eckit/geo/grid/Reduced.cc similarity index 81% rename from src/eckit/geo/grid/ReducedGlobal.cc rename to src/eckit/geo/grid/Reduced.cc index 1c87f380c..ea08fd8cc 100644 --- a/src/eckit/geo/grid/ReducedGlobal.cc +++ b/src/eckit/geo/grid/Reduced.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/ReducedGlobal.h" +#include "eckit/geo/grid/Reduced.h" #include "eckit/exception/Exceptions.h" @@ -18,7 +18,7 @@ namespace eckit::geo::grid { -std::vector ReducedGlobal::to_points() const { +std::vector Reduced::to_points() const { std::vector points; points.reserve(size()); @@ -39,7 +39,7 @@ std::vector ReducedGlobal::to_points() const { } -std::pair, std::vector> ReducedGlobal::to_latlon() const { +std::pair, std::vector> Reduced::to_latlon() const { const auto N = size(); std::pair, std::vector> latlon; @@ -63,15 +63,7 @@ std::pair, std::vector> ReducedGlobal::to_latlon() c } -ReducedGlobal::ReducedGlobal(const Spec& spec) : - Grid(spec) {} - - -ReducedGlobal::ReducedGlobal(const area::BoundingBox& bbox) : - Grid(bbox) {} - - -const std::vector& ReducedGlobal::niacc() const { +const std::vector& Reduced::niacc() const { if (niacc_.empty()) { niacc_.resize(1 + nj()); niacc_.front() = 0; diff --git a/src/eckit/geo/grid/ReducedGlobal.h b/src/eckit/geo/grid/Reduced.h similarity index 62% rename from src/eckit/geo/grid/ReducedGlobal.h rename to src/eckit/geo/grid/Reduced.h index 7bece248e..12b78dfd0 100644 --- a/src/eckit/geo/grid/ReducedGlobal.h +++ b/src/eckit/geo/grid/Reduced.h @@ -23,48 +23,25 @@ class Reduced; namespace eckit::geo::grid { -class ReducedGlobal : public Grid { +class Reduced : public Grid { public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - // None - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - // -- Methods - // None + + size_t size() const override { return niacc().back(); } // -- Overridden methods std::vector to_points() const override; std::pair, std::vector> to_latlon() const override; - // -- Class members - // None - - // -- Class methods - // None - protected: // -- Constructors - explicit ReducedGlobal(const Spec&); - explicit ReducedGlobal(const area::BoundingBox&); + explicit Reduced(const Spec& spec) : + Grid(spec) {} - // -- Members - // None + explicit Reduced(const area::BoundingBox& bbox) : + Grid(bbox) {} // -- Methods @@ -73,34 +50,15 @@ class ReducedGlobal : public Grid { virtual size_t ni(size_t j) const = 0; virtual size_t nj() const = 0; - virtual const std::vector& latitudes() const = 0; - virtual std::vector longitudes(size_t i) const = 0; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members mutable std::vector niacc_; - // -- Methods - // None - - // -- Overridden methods - // None + // Methods - // -- Class members - // None - - // -- Class methods - // None + virtual const std::vector& latitudes() const = 0; + virtual std::vector longitudes(size_t i) const = 0; // -- Friends diff --git a/src/eckit/geo/grid/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc index 9668ed358..f93b6231e 100644 --- a/src/eckit/geo/grid/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -37,7 +37,7 @@ ReducedGaussian::ReducedGaussian(const Spec& spec) : ReducedGaussian::ReducedGaussian(const pl_type& pl, const area::BoundingBox& bbox) : - ReducedGlobal(bbox), + Reduced(bbox), N_(N(pl)), pl_(pl), j_(0), diff --git a/src/eckit/geo/grid/ReducedGaussian.h b/src/eckit/geo/grid/ReducedGaussian.h index bd669f39f..cc3746fb8 100644 --- a/src/eckit/geo/grid/ReducedGaussian.h +++ b/src/eckit/geo/grid/ReducedGaussian.h @@ -16,14 +16,14 @@ #include #include "eckit/geo/Range.h" -#include "eckit/geo/grid/ReducedGlobal.h" +#include "eckit/geo/grid/Reduced.h" #include "eckit/geo/util.h" namespace eckit::geo::grid { -class ReducedGaussian : public ReducedGlobal { +class ReducedGaussian : public Reduced { public: // -- Types // None @@ -80,11 +80,11 @@ class ReducedGaussian : public ReducedGlobal { // -- Overridden methods - const std::vector& latitudes() const override; - std::vector longitudes(size_t j) const override; - void spec(spec::Custom&) const override; + const std::vector& latitudes() const override; + std::vector longitudes(size_t i) const override; + Grid* make_grid_cropped(const area::BoundingBox&) const override; // -- Class members diff --git a/src/eckit/geo/grid/ReducedLL.cc b/src/eckit/geo/grid/ReducedLL.cc index 30db04a60..173c49941 100644 --- a/src/eckit/geo/grid/ReducedLL.cc +++ b/src/eckit/geo/grid/ReducedLL.cc @@ -26,7 +26,7 @@ ReducedLL::ReducedLL(const Spec& spec) : ReducedLL::ReducedLL(const pl_type& pl, const area::BoundingBox& bbox) : - ReducedLocal(bbox), pl_(pl), y_(new range::RegularLatitude(pl_.size(), bbox.north, bbox.south)) { + Reduced(bbox), pl_(pl), y_(new range::RegularLatitude(pl_.size(), bbox.north, bbox.south)) { ASSERT(y_); } diff --git a/src/eckit/geo/grid/ReducedLL.h b/src/eckit/geo/grid/ReducedLL.h index 9fc4eb530..36985e949 100644 --- a/src/eckit/geo/grid/ReducedLL.h +++ b/src/eckit/geo/grid/ReducedLL.h @@ -15,14 +15,14 @@ #include #include "eckit/geo/Range.h" -#include "eckit/geo/grid/ReducedLocal.h" +#include "eckit/geo/grid/Reduced.h" #include "eckit/geo/util.h" namespace eckit::geo::grid { -class ReducedLL : public ReducedLocal { +class ReducedLL : public Reduced { public: // -- Types // None diff --git a/src/eckit/geo/grid/ReducedLocal.cc b/src/eckit/geo/grid/ReducedLocal.cc deleted file mode 100644 index a1bc93ae2..000000000 --- a/src/eckit/geo/grid/ReducedLocal.cc +++ /dev/null @@ -1,96 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/ReducedLocal.h" - -#include "eckit/exception/Exceptions.h" - - -namespace eckit::geo::grid { - - -size_t ReducedLocal::size() const { - return niacc().back(); -} - - -std::vector ReducedLocal::to_points() const { - std::vector points; - points.reserve(size()); - - const auto& lats = latitudes(); - ASSERT(lats.size() == nj()); - - for (size_t j = 0; j < nj(); ++j) { - const auto lons = longitudes(j); - ASSERT(lons.size() == ni(j)); - - const auto lat = lats.at(j); - for (auto lon : lons) { - points.emplace_back(PointLonLat{lon, lat}); - } - } - - return points; -} - - -std::pair, std::vector> ReducedLocal::to_latlon() const { - const auto N = size(); - - std::pair, std::vector> latlon; - auto& lat = latlon.first; - auto& lon = latlon.second; - lat.reserve(N); - lon.reserve(N); - - const auto& lats = latitudes(); - ASSERT(lats.size() == nj()); - - for (size_t j = 0; j < nj(); ++j) { - const auto lons = longitudes(j); - - lat.insert(lat.end(), lons.size(), lats.at(j)); - lon.insert(lon.end(), lons.begin(), lons.end()); - } - - ASSERT(lat.size() == N && lon.size() == N); - return latlon; -} - - -ReducedLocal::ReducedLocal(const Spec& spec) : - Grid(spec) {} - - -ReducedLocal::ReducedLocal(const area::BoundingBox& bbox) : - Grid(bbox) {} - - -const std::vector& ReducedLocal::niacc() const { - if (niacc_.empty()) { - niacc_.resize(1 + nj()); - niacc_.front() = 0; - - size_t j = 0; - for (auto a = niacc_.begin(), b = a + 1; b != niacc_.end(); ++j, ++a, ++b) { - *b = *a + ni(j); - } - - ASSERT(niacc_.back() == size()); - } - - return niacc_; -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedLocal.h b/src/eckit/geo/grid/ReducedLocal.h deleted file mode 100644 index a81eee461..000000000 --- a/src/eckit/geo/grid/ReducedLocal.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Grid.h" - - -namespace eckit::geo::iterator { -class Reduced; -} - - -namespace eckit::geo::grid { - - -class ReducedLocal : public Grid { -public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - // None - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - - size_t size() const override; - std::vector to_points() const override; - std::pair, std::vector> to_latlon() const override; - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Constructors - - explicit ReducedLocal(const Spec&); - explicit ReducedLocal(const area::BoundingBox&); - - // -- Members - // None - - // -- Methods - - const std::vector& niacc() const; - - virtual size_t ni(size_t j) const = 0; - virtual size_t nj() const = 0; - - virtual const std::vector& latitudes() const = 0; - virtual std::vector longitudes(size_t i) const = 0; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - - mutable std::vector niacc_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - - friend class geo::iterator::Reduced; -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/iterator/Reduced.cc b/src/eckit/geo/iterator/Reduced.cc index cb5d5dc14..3e0348893 100644 --- a/src/eckit/geo/iterator/Reduced.cc +++ b/src/eckit/geo/iterator/Reduced.cc @@ -16,14 +16,14 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/grid/ReducedGlobal.h" +#include "eckit/geo/grid/Reduced.h" namespace eckit::geo::iterator { Reduced::Reduced(const Grid& grid, size_t index) : - grid_(dynamic_cast(grid)), + grid_(dynamic_cast(grid)), latitudes_(grid_.latitudes()), niacc_(grid_.niacc()), index_(index), diff --git a/src/eckit/geo/iterator/Reduced.h b/src/eckit/geo/iterator/Reduced.h index 1712a7b15..b12851893 100644 --- a/src/eckit/geo/iterator/Reduced.h +++ b/src/eckit/geo/iterator/Reduced.h @@ -18,7 +18,7 @@ namespace eckit::geo::grid { -class ReducedGlobal; +class Reduced; } @@ -61,7 +61,7 @@ class Reduced final : public geo::Iterator { private: // -- Members - const grid::ReducedGlobal& grid_; + const grid::Reduced& grid_; std::vector longitudes_j_; const std::vector& latitudes_; const std::vector& niacc_; From 7800bee8e39e9672940999879af21e81e810b482 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 12 Apr 2024 02:05:30 +0100 Subject: [PATCH 597/737] eckit::geo::Grid --- src/eckit/geo/Grid.cc | 15 +++++++++------ src/eckit/geo/Grid.h | 10 ++++++---- src/eckit/geo/area/BoundingBox.cc | 25 +++++++++++++++---------- src/eckit/geo/area/BoundingBox.h | 14 +++++++------- src/eckit/geo/grid/HEALPix.cc | 8 +------- src/eckit/geo/grid/HEALPix.h | 2 -- src/eckit/geo/grid/ORCA.cc | 6 ------ src/eckit/geo/grid/ORCA.h | 2 -- src/eckit/geo/grid/ReducedGaussian.h | 4 ++-- src/eckit/geo/grid/ReducedLL.h | 2 +- src/eckit/geo/grid/Regular.h | 3 ++- src/eckit/geo/grid/Unstructured.cc | 2 +- 12 files changed, 44 insertions(+), 49 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 8bd0e5d53..69f9612e0 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -13,7 +13,6 @@ #include "eckit/geo/Grid.h" #include -#include #include #include @@ -39,11 +38,11 @@ class lock_type { Grid::Grid(const Spec& spec) : - bbox_(spec) {} + bbox_(area::BoundingBox::make_from_spec(spec)) {} Grid::Grid(const area::BoundingBox& bbox) : - bbox_(bbox) {} + bbox_(new area::BoundingBox(bbox)) {} std::string Grid::spec() const { @@ -119,7 +118,7 @@ Grid* Grid::make_grid_reordered(Ordering) const { Area* Grid::area() const { - return new area::BoundingBox(bbox_); + return new area::BoundingBox(*bbox_); } @@ -133,8 +132,12 @@ Grid* Grid::make_grid_cropped(const Area&) const { } -area::BoundingBox Grid::boundingBox() const { - return bbox_; +const area::BoundingBox& Grid::boundingBox() const { + if (!bbox_) { + bbox_.reset(calculate_bbox()); + ASSERT(bbox_); + } + return *bbox_; } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index d57a91cb7..19d4ca40c 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -23,6 +23,7 @@ #include "eckit/geo/Iterator.h" #include "eckit/geo/Ordering.h" #include "eckit/geo/Point.h" +#include "eckit/geo/Projection.h" #include "eckit/geo/Renumber.h" #include "eckit/geo/area/BoundingBox.h" #include "eckit/geo/spec/Generator.h" @@ -136,7 +137,7 @@ class Grid { virtual Renumber crop(const Area&) const; virtual Grid* make_grid_cropped(const Area&) const; - virtual area::BoundingBox boundingBox() const; + virtual const area::BoundingBox& boundingBox() const; virtual Renumber crop(const area::BoundingBox&) const; virtual Grid* make_grid_cropped(const area::BoundingBox&) const; @@ -157,8 +158,6 @@ class Grid { // -- Methods - void bbox(const area::BoundingBox& bbox) { bbox_ = bbox; } - static Renumber no_reorder(size_t size); // -- Overridden methods @@ -173,12 +172,15 @@ class Grid { private: // -- Members - area::BoundingBox bbox_; + mutable std::unique_ptr bbox_; + std::unique_ptr projection_; // -- Methods virtual void spec(spec::Custom&) const; + virtual area::BoundingBox* calculate_bbox() const { return new area::BoundingBox{}; } + // -- Overridden methods // None diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 7532ef35c..8d4cf3cd3 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -14,6 +14,7 @@ #include #include +#include #include #include "eckit/exception/Exceptions.h" @@ -31,13 +32,13 @@ static const BoundingBox GLOBE_PRIME{90., 0., -90., 360.}; static const BoundingBox GLOBE_ANTIPRIME{90., -180., -90., 180.}; -BoundingBox BoundingBox::make_global_prime() { - return GLOBE_PRIME; +BoundingBox* BoundingBox::make_global_prime() { + return new BoundingBox(GLOBE_PRIME); } -BoundingBox BoundingBox::make_global_antiprime() { - return GLOBE_ANTIPRIME; +BoundingBox* BoundingBox::make_global_antiprime() { + return new BoundingBox(GLOBE_ANTIPRIME); } @@ -48,12 +49,12 @@ void BoundingBox::spec(spec::Custom& custom) const { } -static BoundingBox make_from_spec(const Spec& spec) { - const auto [n, w, s, e] = BoundingBox::make_global_prime().deconstruct(); +BoundingBox* BoundingBox::make_from_spec(const Spec& spec) { + const auto [n, w, s, e] = GLOBE_PRIME.deconstruct(); if (std::vector area{n, w, s, e}; spec.get("area", area)) { ASSERT_MSG(area.size() == 4, "BoundingBox: 'area' expected list of size 4"); - return {area[0], area[1], area[2], area[3]}; + return new BoundingBox{area[0], area[1], area[2], area[3]}; } std::array area{n, w, s, e}; @@ -64,12 +65,12 @@ static BoundingBox make_from_spec(const Spec& spec) { auto new_west = spec.get("east", area[3]) && !spec.has("west"); ASSERT(!new_east || !new_west); - return {area[0], new_west ? area[3] - 360. : area[1], area[2], new_east ? area[1] + 360. : area[3]}; + return new BoundingBox{area[0], new_west ? area[3] - 360. : area[1], area[2], new_east ? area[1] + 360. : area[3]}; } BoundingBox::BoundingBox(const Spec& spec) : - BoundingBox(make_from_spec(spec)) {} + BoundingBox(*std::unique_ptr(make_from_spec(spec))) {} BoundingBox::BoundingBox(double n, double w, double s, double e) : @@ -89,6 +90,10 @@ BoundingBox::BoundingBox(double n, double w, double s, double e) : } +BoundingBox::BoundingBox() : + BoundingBox(GLOBE_PRIME) {} + + bool BoundingBox::operator==(const BoundingBox& other) const { return types::is_approximately_equal(north, other.north, PointLonLat::EPS) && types::is_approximately_equal(south, other.south, PointLonLat::EPS) && @@ -203,7 +208,7 @@ double BoundingBox::area(double radius) const { } -BoundingBox BoundingBox::make(const BoundingBox&, const Projection&) { +BoundingBox BoundingBox::calculate(const BoundingBox&, const Projection&) { NOTIMP; } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index bf1e589ca..4cead209a 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -37,8 +37,7 @@ class BoundingBox : public Area, protected std::array { BoundingBox(double north, double west, double south, double east); - BoundingBox() : - BoundingBox(make_global_prime()) {} + BoundingBox(); BoundingBox(const BoundingBox& other) : array(other) {} @@ -83,10 +82,6 @@ class BoundingBox : public Area, protected std::array { bool empty() const; double area(double radius) const; - static BoundingBox make(const BoundingBox&, const Projection&); - static BoundingBox make_global_prime(); - static BoundingBox make_global_antiprime(); - // -- Overridden methods void spec(spec::Custom&) const override; @@ -95,7 +90,12 @@ class BoundingBox : public Area, protected std::array { // None // -- Class methods - // None + + static BoundingBox calculate(const BoundingBox&, const Projection&); + + static BoundingBox* make_global_prime(); + static BoundingBox* make_global_antiprime(); + static BoundingBox* make_from_spec(const Spec&); // -- Members diff --git a/src/eckit/geo/grid/HEALPix.cc b/src/eckit/geo/grid/HEALPix.cc index c396412e1..4d38bd016 100644 --- a/src/eckit/geo/grid/HEALPix.cc +++ b/src/eckit/geo/grid/HEALPix.cc @@ -230,7 +230,7 @@ HEALPix::HEALPix(const Spec& spec) : HEALPix::HEALPix(size_t Nside, Ordering ordering) : - Reduced(area::BoundingBox::make_global_prime()), Nside_(Nside), ordering_(ordering) { + Reduced(area::BoundingBox{}), Nside_(Nside), ordering_(ordering) { ASSERT(Nside_ > 0); ASSERT_MSG(ordering == Ordering::healpix_ring || ordering == Ordering::healpix_nested, "HEALPix: supported orderings: ring, nested"); @@ -289,12 +289,6 @@ Spec* HEALPix::spec(const std::string& name) { } -area::BoundingBox HEALPix::boundingBox() const { - static const auto __bbox(area::BoundingBox::make_global_prime()); - return __bbox; -} - - size_t HEALPix::size() const { return 12 * Nside_ * Nside_; } diff --git a/src/eckit/geo/grid/HEALPix.h b/src/eckit/geo/grid/HEALPix.h index 840ab7aa1..8bc7da717 100644 --- a/src/eckit/geo/grid/HEALPix.h +++ b/src/eckit/geo/grid/HEALPix.h @@ -81,8 +81,6 @@ class HEALPix final : public Reduced { // -- Overridden methods - area::BoundingBox boundingBox() const override; - bool includesNorthPole() const override { return true; } bool includesSouthPole() const override { return true; } bool isPeriodicWestEast() const override { return true; } diff --git a/src/eckit/geo/grid/ORCA.cc b/src/eckit/geo/grid/ORCA.cc index ee9cc1610..0e886e450 100644 --- a/src/eckit/geo/grid/ORCA.cc +++ b/src/eckit/geo/grid/ORCA.cc @@ -281,12 +281,6 @@ Grid::iterator ORCA::cend() const { } -area::BoundingBox ORCA::boundingBox() const { - static const auto __bbox(area::BoundingBox::make_global_prime()); - return __bbox; -} - - Grid::uid_t ORCA::calculate_uid() const { MD5 hash(arrangement_to_string(arrangement_)); diff --git a/src/eckit/geo/grid/ORCA.h b/src/eckit/geo/grid/ORCA.h index ecbadc93d..7a33931a8 100644 --- a/src/eckit/geo/grid/ORCA.h +++ b/src/eckit/geo/grid/ORCA.h @@ -95,8 +95,6 @@ class ORCA final : public Regular { iterator cbegin() const override; iterator cend() const override; - area::BoundingBox boundingBox() const override; - uid_t uid() const override { return uid_; } bool includesNorthPole() const override { return true; } diff --git a/src/eckit/geo/grid/ReducedGaussian.h b/src/eckit/geo/grid/ReducedGaussian.h index cc3746fb8..6e8ec8b90 100644 --- a/src/eckit/geo/grid/ReducedGaussian.h +++ b/src/eckit/geo/grid/ReducedGaussian.h @@ -34,8 +34,8 @@ class ReducedGaussian : public Reduced { // -- Constructors explicit ReducedGaussian(const Spec&); - explicit ReducedGaussian(const pl_type&, const area::BoundingBox& = area::BoundingBox::make_global_prime()); - explicit ReducedGaussian(size_t N, const area::BoundingBox& = area::BoundingBox::make_global_prime()); + explicit ReducedGaussian(const pl_type&, const area::BoundingBox& = {}); + explicit ReducedGaussian(size_t N, const area::BoundingBox& = {}); // -- Destructor // None diff --git a/src/eckit/geo/grid/ReducedLL.h b/src/eckit/geo/grid/ReducedLL.h index 36985e949..1643f0fc6 100644 --- a/src/eckit/geo/grid/ReducedLL.h +++ b/src/eckit/geo/grid/ReducedLL.h @@ -33,7 +33,7 @@ class ReducedLL : public Reduced { // -- Constructors explicit ReducedLL(const Spec&); - explicit ReducedLL(const pl_type&, const area::BoundingBox& = area::BoundingBox::make_global_prime()); + explicit ReducedLL(const pl_type&, const area::BoundingBox& = {}); // -- Destructor // None diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index c25aed272..c180938ae 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -90,9 +90,10 @@ struct RegularLL final : public Regular { struct RegularGaussian final : public Regular { explicit RegularGaussian(const Spec&); - explicit RegularGaussian(size_t N, const area::BoundingBox& = area::BoundingBox::make_global_prime()); + explicit RegularGaussian(size_t N, const area::BoundingBox& = {}); Grid* make_grid_cropped(const area::BoundingBox& crop) const override; + static Spec* spec(const std::string& name); void spec(spec::Custom&) const override; diff --git a/src/eckit/geo/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc index 9d5cea3b8..c66a0c8e4 100644 --- a/src/eckit/geo/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -21,7 +21,7 @@ namespace eckit::geo::grid { Unstructured::Unstructured(std::vector&& points) : - Grid(area::BoundingBox::make_global_prime()), points_(points) {} + Grid(area::BoundingBox{}), points_(points) {} Grid::iterator Unstructured::cbegin() const { From e528a3011a99f073f174ff6e4a1d3798248bfda8 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 17 Apr 2024 20:23:24 +0100 Subject: [PATCH 598/737] Clean up CMakeLists.txt --- CMakeLists.txt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 81717d600..bd7a4e7b0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,8 +155,8 @@ set( eckit_CODEC_STATIC_ASSERT ON CACHE BOOL "eckit::codec static assertions" ) ecbuild_add_option( FEATURE CONVEX_HULL DEFAULT OFF - DESCRIPTION "eckit::maths library convex hull/Delaunay triangulation" - REQUIRED_PACKAGES "Qhull COMPONENTS C CXX" ) + DESCRIPTION "eckit::maths library convex hull/Delaunay triangulation" ) + # REQUIRED_PACKAGES "Qhull COMPONENTS C CXX" if( eckit_HAVE_CONVEX_HULL ) find_package( Qhull REQUIRED CONFIG ) @@ -213,7 +213,7 @@ endif() ecbuild_add_option( FEATURE CURL DESCRIPTION "Curl library for transfering data with URLs" - REQUIRED_PACKAGES "CURL VERSION 7.20" ) + REQUIRED_PACKAGES "CURL 7.20" ) if(HAVE_CURL) ecbuild_info("Curl version ${CURL_VERSION_STRING} -- libs [${CURL_LIBRARIES}] incs [${CURL_INCLUDE_DIRS}]") @@ -229,6 +229,7 @@ ecbuild_add_option( FEATURE JEMALLOC #### CUDA ecbuild_add_option( FEATURE CUDA + DEFAULT OFF CONDITION HAVE_EXPERIMENTAL DESCRIPTION "CUDA GPU linear algebra operations" REQUIRED_PACKAGES CUDA ) @@ -287,10 +288,7 @@ ecbuild_add_option( FEATURE AIO ecbuild_add_option( FEATURE PROJ DEFAULT OFF DESCRIPTION "support PROJ-based projections" - REQUIRED_PACKAGES "PROJ VERSION 9.2" ) - -### ecCodes -ecbuild_add_option( FEATURE ECCODES REQUIRED_PACKAGES eccodes DESCRIPTION "FIXME: remove" ) + REQUIRED_PACKAGES "PROJ 9.2" ) ### c math library, needed when including "math.h" From 44451c842685ea1b9d0e4b96bea8e0897d6ee216 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 19 Apr 2024 10:13:16 +0100 Subject: [PATCH 599/737] eckit::geo::Grid (correct code, note that it will be removed) --- .../grid/unstructured/UnstructuredFromGrid.cc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc index b842a989d..111cf621a 100644 --- a/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc +++ b/src/eckit/geo/grid/unstructured/UnstructuredFromGrid.cc @@ -25,18 +25,16 @@ namespace { std::vector points_lat(const std::vector& points) { std::vector l(points.size()); - std::transform(points.begin(), points.end(), l.begin(), [](const Point& p) { - return std::get(p).lat; - }); + std::transform(points.begin(), points.end(), l.begin(), + [](const Point& p) { return std::get(p).lat; }); return l; } std::vector points_lon(const std::vector& points) { std::vector l(points.size()); - std::transform(points.begin(), points.end(), l.begin(), [](const Point& p) { - return std::get(p).lon; - }); + std::transform(points.begin(), points.end(), l.begin(), + [](const Point& p) { return std::get(p).lon; }); return l; } @@ -63,11 +61,14 @@ Grid::iterator UnstructuredFromGrid::cend() const { std::vector UnstructuredFromGrid::to_points() const { - std::vector p; + std::vector points; + points.reserve(size()); + for (size_t i = 0; i < size(); ++i) { - p[i] = PointLonLat{longitudes_[i], latitudes_[i]}; + points.emplace_back(PointLonLat{longitudes_[i], latitudes_[i]}); } - return p; + + return points; } From 6fe3054d58363f014fea23a1b11abeb9068d1dc9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 19 Apr 2024 10:59:06 +0100 Subject: [PATCH 600/737] eckit::geo::Domain --- src/eckit/geo/CMakeLists.txt | 2 - src/eckit/geo/Domain.cc | 104 -------------------------------- src/eckit/geo/Domain.h | 114 ----------------------------------- 3 files changed, 220 deletions(-) delete mode 100644 src/eckit/geo/Domain.cc delete mode 100644 src/eckit/geo/Domain.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 0706d235b..2d485d819 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -11,8 +11,6 @@ list(APPEND eckit_geo_srcs Area.h Cache.cc Cache.h - Domain.cc - Domain.h Earth.h EllipsoidOfRevolution.cc EllipsoidOfRevolution.h diff --git a/src/eckit/geo/Domain.cc b/src/eckit/geo/Domain.cc deleted file mode 100644 index bb04ed914..000000000 --- a/src/eckit/geo/Domain.cc +++ /dev/null @@ -1,104 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/Domain.h" - -#include -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/Point.h" -#include "eckit/geo/Sphere.h" -#include "eckit/geo/util.h" -#include "eckit/types/FloatCompare.h" - - -namespace eckit::geo { - - -Domain::Domain(double north, double west, double south, double east) : - north_(north), west_(west), south_(south), east_(east) { - if (west_ != east_) { - auto e = PointLonLat::normalise_angle_to_minimum(east, west); - east_ = e == west_ ? (e + 360.) : e; - } - - ASSERT_MSG(west_ <= east_ && east_ <= west_ + 360., "Domain: longitude range"); - ASSERT_MSG(-90. <= south_ && south_ <= north_ && north_ <= 90., "Domain: latitude range"); -} - - -Domain::Domain() : - Domain(90., 0., -90., 360.) {} - - -bool Domain::operator==(const Domain& other) const { - return north_ == other.north_ && south_ == other.south_ && west_ == other.west_ && east_ == other.east_; -} - - -bool Domain::includesNorthPole() const { - return north_ == NORTH_POLE; -} - - -bool Domain::includesSouthPole() const { - return south_ == SOUTH_POLE; -} - - -bool Domain::isPeriodicWestEast() const { - return west_ != east_ && west_ == PointLonLat::normalise_angle_to_minimum(east_, west_); -} - - -bool Domain::contains(double lat, double lon) const { - return lat <= north_ && lat >= south_ && PointLonLat::normalise_angle_to_minimum(lon, west_) <= east_; -} - - -bool Domain::contains(const Domain& other) const { - if (other.empty()) { - return contains(other.south_, other.west_); - } - - // check for West/East range (if non-periodic), then other's corners - if (east_ - west_ < other.east_ - other.west_ || - east_ < PointLonLat::normalise_angle_to_minimum(other.east_, west_)) { - return false; - } - - return contains(other.north_, other.west_) && contains(other.north_, other.east_) && - contains(other.south_, other.west_) && contains(other.south_, other.east_); -} - - -bool Domain::empty() const { - return types::is_approximately_equal(north_, south_) || types::is_approximately_equal(west_, east_); -} - - -double Domain::area(double radius) const { - double lonf = isPeriodicWestEast() ? 1. : ((east_ - west_) / 360.); - ASSERT(0. <= lonf && lonf <= 1.); - - const auto sn = std::sin(north_ * util::DEGREE_TO_RADIAN); - const auto ss = std::sin(south_ * util::DEGREE_TO_RADIAN); - - double latf = 0.5 * (sn - ss); - ASSERT(0. <= latf && latf <= 1.); - - return Sphere::area(radius) * latf * lonf; -} - - -} // namespace eckit::geo diff --git a/src/eckit/geo/Domain.h b/src/eckit/geo/Domain.h deleted file mode 100644 index e920bb9af..000000000 --- a/src/eckit/geo/Domain.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - - -namespace eckit::geo { - - -class Domain { -public: - // -- Exceptions - // None - - // -- Constructors - - Domain(double north, double west, double south, double east); - Domain(); - Domain(const Domain&) = default; - Domain(Domain&&) = default; - - // -- Destructor - - virtual ~Domain() = default; - - // -- Convertors - // None - - // -- Operators - - Domain& operator=(const Domain&) = default; - Domain& operator=(Domain&&) = default; - bool operator==(const Domain&) const; - bool operator!=(const Domain& other) const { return !operator==(other); } - - // -- Methods - - double north() const { return north_; } - double west() const { return west_; } - double south() const { return south_; } - double east() const { return east_; } - - bool includesNorthPole() const; - bool includesSouthPole() const; - bool isPeriodicWestEast() const; - - bool contains(double lat, double lon) const; - bool contains(const Domain&) const; - bool empty() const; - double area(double radius) const; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None - -private: - // -- Members - - double north_; - double west_; - double south_; - double east_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None -}; - - -} // namespace eckit::geo From b6aa3b6ab8738f24d6783f00a8645546e9911649 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 19 Apr 2024 19:34:34 +0100 Subject: [PATCH 601/737] eckit::geo::Point allow default-constructible Point --- src/eckit/geo/Point.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eckit/geo/Point.h b/src/eckit/geo/Point.h index 331eb5d4f..3745a7721 100644 --- a/src/eckit/geo/Point.h +++ b/src/eckit/geo/Point.h @@ -23,7 +23,7 @@ namespace eckit::geo { -using Point = std::variant; +using Point = std::variant; bool points_equal(const Point&, const Point&); bool points_equal(const Point&, const Point&, double eps); From cc2a091d685e2856ed5c413f07dcafa1a4518502 Mon Sep 17 00:00:00 2001 From: Shahram Najm Date: Thu, 2 May 2024 10:25:11 +0000 Subject: [PATCH 602/737] ECC-1818: GRIB Geoiterator issues for Lambert azimuthal equal area --- ...b_iterator_class_lambert_azimuthal_equal_area.cc | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.cc b/src/grib_iterator_class_lambert_azimuthal_equal_area.cc index a945ee1d2..24dba1877 100644 --- a/src/grib_iterator_class_lambert_azimuthal_equal_area.cc +++ b/src/grib_iterator_class_lambert_azimuthal_equal_area.cc @@ -209,7 +209,11 @@ static int init_oblate(grib_handle* h, sinphi_ = sin(standardParallelInRadians); /* (P->phi0); */ Q__sinb1 = pj_qsfn(sinphi_, e, one_es) / Q__qp; Q__cosb1 = sqrt(1.0 - Q__sinb1 * Q__sinb1); - Q__dd = cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); + if (Q__cosb1 == 0) { + Q__dd = 1.0; + } else { + Q__dd = cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); + } Q__ymf = (Q__xmf = Q__rq) / Q__dd; Q__xmf *= Q__dd; @@ -253,7 +257,12 @@ static int init_oblate(grib_handle* h, xy_y *= Q__dd; rho = hypot(xy_x, xy_y); Assert(rho >= EPS10); /* TODO(masn): check */ - sCe = 2. * asin(.5 * rho / Q__rq); + const double asin_arg = (0.5 * rho / Q__rq); + if (asin_arg < -1.0 || asin_arg > 1.0) { + grib_context_log(h->context, GRIB_LOG_ERROR, "Invalid value: arcsin argument=%g", asin_arg); + return GRIB_GEOCALCULUS_PROBLEM; + } + sCe = 2. * asin(asin_arg); cCe = cos(sCe); sCe = sin(sCe); xy_x *= sCe; From 5ef14cffd13a064349e1d0e108fe58b81d0d23bb Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 2 May 2024 14:20:16 +0000 Subject: [PATCH 603/737] Compilation improvements --- src/eckit/geo/Cache.cc | 6 +++--- src/eckit/geo/Figure.cc | 2 ++ src/eckit/geo/util.h | 10 ++++------ src/eckit/geo/util/arange.cc | 10 +++++----- src/eckit/geo/util/bounding_box.cc | 14 +++++++------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/eckit/geo/Cache.cc b/src/eckit/geo/Cache.cc index f3fe3e619..84708c435 100644 --- a/src/eckit/geo/Cache.cc +++ b/src/eckit/geo/Cache.cc @@ -12,6 +12,7 @@ #include "eckit/geo/Cache.h" +#include #include @@ -24,9 +25,8 @@ static std::vector CACHES; Cache::bytes_t Cache::total_footprint() { util::lock_guard lock(MUTEX); - return std::accumulate(CACHES.begin(), CACHES.end(), static_cast(0), [](bytes_t sum, const auto* cache) { - return sum + cache->footprint(); - }); + return std::accumulate(CACHES.begin(), CACHES.end(), static_cast(0), + [](bytes_t sum, const auto* cache) { return sum + cache->footprint(); }); } diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc index 497c0923b..b5a7748e8 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/geo/Figure.cc @@ -12,6 +12,8 @@ #include "eckit/geo/Figure.h" +#include + #include "eckit/exception/Exceptions.h" diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index 00c937249..e409edc91 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -13,6 +13,7 @@ #pragma once #include +#include #include #include #include @@ -39,9 +40,8 @@ pl_type pl_convert(const T& pl) { ASSERT(!pl.empty()); pl_type _pl(pl.size()); - std::transform(pl.begin(), pl.end(), _pl.begin(), [](typename T::value_type p) { - return static_cast(p); - }); + std::transform(pl.begin(), pl.end(), _pl.begin(), + [](typename T::value_type p) { return static_cast(p); }); return _pl; } @@ -59,9 +59,7 @@ const std::vector& gaussian_latitudes(size_t N, bool increasing); std::vector linspace(double start, double stop, size_t num, bool endpoint); -std::pair monotonic_crop(const std::vector&, - double min, - double max, +std::pair monotonic_crop(const std::vector&, double min, double max, double eps); diff --git a/src/eckit/geo/util/arange.cc b/src/eckit/geo/util/arange.cc index f83ee9201..4065acf03 100644 --- a/src/eckit/geo/util/arange.cc +++ b/src/eckit/geo/util/arange.cc @@ -10,6 +10,7 @@ */ +#include #include #include "eckit/types/FloatCompare.h" @@ -19,8 +20,8 @@ namespace eckit::geo::util { std::vector arange(double start, double stop, double step) { - if (types::is_approximately_equal(step, 0.) || types::is_approximately_equal(start, stop) || - (stop - start) * step < 0.) { + if (types::is_approximately_equal(step, 0.) || types::is_approximately_equal(start, stop) + || (stop - start) * step < 0.) { std::vector l(1, start); return l; } @@ -28,9 +29,8 @@ std::vector arange(double start, double stop, double step) { const auto num = static_cast((stop - start) / step) + 1; std::vector l(num); - std::generate_n(l.begin(), num, [start, step, n = 0ULL]() mutable { - return start + static_cast(n++) * step; - }); + std::generate_n(l.begin(), num, + [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); return l; } diff --git a/src/eckit/geo/util/bounding_box.cc b/src/eckit/geo/util/bounding_box.cc index f7739b8a0..fcc0725fc 100644 --- a/src/eckit/geo/util/bounding_box.cc +++ b/src/eckit/geo/util/bounding_box.cc @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -38,8 +39,7 @@ void longitude_in_range(double reference, double& lon) { struct BoundLonLat { - BoundLonLat(PointLonLat min, PointLonLat max) : - min_(min), max_(max) {} + BoundLonLat(PointLonLat min, PointLonLat max) : min_(min), max_(max) {} explicit operator area::BoundingBox() const { return {max_.lat, min_.lon, min_.lat, max_.lon}; } @@ -150,8 +150,8 @@ struct DerivateCentral final : Derivate { struct DerivateFactory { - static const Derivate* build( - const std::string& type, const Projection& p, Point2 A, Point2 B, double h, double refLongitude = 0.) { + static const Derivate* build(const std::string& type, const Projection& p, Point2 A, Point2 B, double h, + double refLongitude = 0.) { ASSERT(0. < h); if (A.distance2(B) < h * h) { @@ -177,8 +177,8 @@ struct DerivateFactory { } // This is 'const' as Grid should always be immutable - const Derivate* build_( - const std::string& type, const Projection& p, Point2 A, Point2 B, double h, double refLongitude) const; + const Derivate* build_(const std::string& type, const Projection& p, Point2 A, Point2 B, double h, + double refLongitude) const; void list_(std::ostream&) const; }; @@ -306,7 +306,7 @@ area::BoundingBox bounding_box(Point2 min, Point2 max, Projection& projection) { // 4. return bounding box - return {bounds}; + return area::BoundingBox{bounds}; } From 41099e31f94d8c851845bbeb6ece23f33ce39940 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 2 May 2024 21:42:52 +0100 Subject: [PATCH 604/737] Rename variables/functions starting with double underscore __ Co-authored-by: Simon Smart --- src/eckit/geo/etc/Grid.cc | 10 +-- src/eckit/geo/grid/HEALPix.cc | 50 +++++------- src/eckit/geo/grid/ORCA.cc | 10 +-- src/eckit/geo/grid/ReducedGaussian.cc | 6 +- src/eckit/geo/grid/Regular.cc | 17 ++-- src/eckit/geo/projection/LonLatToXY.cc | 2 +- src/eckit/geo/projection/LonLatToXYZ.cc | 11 +-- src/eckit/geo/projection/Mercator.cc | 10 +-- src/eckit/geo/projection/None.cc | 2 +- src/eckit/geo/projection/PROJ.cc | 5 +- src/eckit/geo/projection/Rotation.cc | 34 +++----- src/eckit/geo/projection/XYToLonLat.cc | 4 +- src/eckit/geo/spec/Custom.cc | 103 +++++++++++------------- src/eckit/geo/spec/Layered.h | 59 +++++++------- 14 files changed, 145 insertions(+), 178 deletions(-) diff --git a/src/eckit/geo/etc/Grid.cc b/src/eckit/geo/etc/Grid.cc index 1e67fbcf0..406ec9b54 100644 --- a/src/eckit/geo/etc/Grid.cc +++ b/src/eckit/geo/etc/Grid.cc @@ -25,8 +25,8 @@ namespace eckit::geo::etc { const Grid& Grid::instance() { - static const Grid __instance(LibEcKitGeo::etcGrid()); - return __instance; + static const Grid INSTANCE(LibEcKitGeo::etcGrid()); + return INSTANCE; } @@ -55,16 +55,14 @@ void Grid::load(const PathName& path) { }; struct SpecByUIDGenerator final : SpecByUID::generator_t { - explicit SpecByUIDGenerator(spec::Custom* spec) : - spec_(spec) {} + explicit SpecByUIDGenerator(spec::Custom* spec) : spec_(spec) {} Spec* spec() const override { return new spec::Custom(*spec_); } bool match(const spec::Custom& other) const override { return other == *spec_; } std::unique_ptr spec_; }; struct SpecByNameGenerator final : SpecByName::generator_t { - explicit SpecByNameGenerator(spec::Custom* spec) : - spec_(spec) {} + explicit SpecByNameGenerator(spec::Custom* spec) : spec_(spec) {} Spec* spec(SpecByName::generator_t::arg1_t) const override { return new spec::Custom(*spec_); } bool match(const spec::Custom& other) const override { return other == *spec_; } std::unique_ptr spec_; diff --git a/src/eckit/geo/grid/HEALPix.cc b/src/eckit/geo/grid/HEALPix.cc index 4d38bd016..9bf0d0108 100644 --- a/src/eckit/geo/grid/HEALPix.cc +++ b/src/eckit/geo/grid/HEALPix.cc @@ -32,30 +32,26 @@ namespace { struct CodecFijNest { - static constexpr uint64_t __masks[] = {0x00000000ffffffff, - 0x0000ffff0000ffff, - 0x00ff00ff00ff00ff, - 0x0f0f0f0f0f0f0f0f, - 0x3333333333333333, - 0x5555555555555555}; + static constexpr uint64_t MASKS[] = {0x00000000ffffffff, 0x0000ffff0000ffff, 0x00ff00ff00ff00ff, + 0x0f0f0f0f0f0f0f0f, 0x3333333333333333, 0x5555555555555555}; inline static int nest_encode_bits(int n) { - auto b = static_cast(n) & __masks[0]; - b = (b ^ (b << 16)) & __masks[1]; - b = (b ^ (b << 8)) & __masks[2]; - b = (b ^ (b << 4)) & __masks[3]; - b = (b ^ (b << 2)) & __masks[4]; - b = (b ^ (b << 1)) & __masks[5]; + auto b = static_cast(n) & MASKS[0]; + b = (b ^ (b << 16)) & MASKS[1]; + b = (b ^ (b << 8)) & MASKS[2]; + b = (b ^ (b << 4)) & MASKS[3]; + b = (b ^ (b << 2)) & MASKS[4]; + b = (b ^ (b << 1)) & MASKS[5]; return static_cast(b); } inline static int nest_decode_bits(int n) { - auto b = static_cast(n) & __masks[5]; - b = (b ^ (b >> 1)) & __masks[4]; - b = (b ^ (b >> 2)) & __masks[3]; - b = (b ^ (b >> 4)) & __masks[2]; - b = (b ^ (b >> 8)) & __masks[1]; - b = (b ^ (b >> 16)) & __masks[0]; + auto b = static_cast(n) & MASKS[5]; + b = (b ^ (b >> 1)) & MASKS[4]; + b = (b ^ (b >> 2)) & MASKS[3]; + b = (b ^ (b >> 4)) & MASKS[2]; + b = (b ^ (b >> 8)) & MASKS[1]; + b = (b ^ (b >> 16)) & MASKS[0]; return static_cast(b); } @@ -171,9 +167,7 @@ class Reorder { auto [f, i, j] = CodecFijNest::nest_to_fij(n, k_); ASSERT(f < 12 && i < Nside_ && j < Nside_); - auto to_ring_local = [&](int f, - int i, - int j, + auto to_ring_local = [&](int f, int i, int j, int Nring, //!< number of pixels in ring int shift //!< if ring's first pixel is/is not at phi=0 ) -> int { @@ -229,8 +223,7 @@ HEALPix::HEALPix(const Spec& spec) : }(spec.get_string("ordering", "ring"))) {} -HEALPix::HEALPix(size_t Nside, Ordering ordering) : - Reduced(area::BoundingBox{}), Nside_(Nside), ordering_(ordering) { +HEALPix::HEALPix(size_t Nside, Ordering ordering) : Reduced(area::BoundingBox{}), Nside_(Nside), ordering_(ordering) { ASSERT(Nside_ > 0); ASSERT_MSG(ordering == Ordering::healpix_ring || ordering == Ordering::healpix_nested, "HEALPix: supported orderings: ring, nested"); @@ -358,9 +351,8 @@ std::vector HEALPix::longitudes(size_t j) const { const auto start = j < Nside_ || 3 * Nside_ - 1 < j || static_cast((j + Nside_) % 2) ? step / 2. : 0.; std::vector lons(Ni); - std::generate_n(lons.begin(), Ni, [start, step, n = 0ULL]() mutable { - return start + static_cast(n++) * step; - }); + std::generate_n(lons.begin(), Ni, + [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); return lons; } @@ -372,9 +364,9 @@ void HEALPix::spec(spec::Custom& custom) const { } -static const GridRegisterType __grid_type_1("HEALPix"); -static const GridRegisterType __grid_type_2("healpix"); -static const GridRegisterName __grid_pattern("[hH][1-9][0-9]*"); +static const GridRegisterType GRIDTYPE1("HEALPix"); +static const GridRegisterType GRIDTYPE2("healpix"); +static const GridRegisterName GRIDNAME("[hH][1-9][0-9]*"); } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ORCA.cc b/src/eckit/geo/grid/ORCA.cc index 0e886e450..6774b2e89 100644 --- a/src/eckit/geo/grid/ORCA.cc +++ b/src/eckit/geo/grid/ORCA.cc @@ -183,9 +183,9 @@ Grid::uid_t ORCA::ORCARecord::calculate_uid(Arrangement arrangement) const { ORCA::ORCARecord::bytes_t ORCA::ORCARecord::footprint() const { - return sizeof(dimensions_.front()) * dimensions_.size() + sizeof(halo_.front()) * halo_.size() + - sizeof(pivot_.front()) * pivot_.size() + sizeof(longitudes_.front()) * longitudes_.size() + - sizeof(latitudes_.front()) * latitudes_.size() + sizeof(flags_.front()) * flags_.size(); + return sizeof(dimensions_.front()) * dimensions_.size() + sizeof(halo_.front()) * halo_.size() + + sizeof(pivot_.front()) * pivot_.size() + sizeof(longitudes_.front()) * longitudes_.size() + + sizeof(latitudes_.front()) * latitudes_.size() + sizeof(flags_.front()) * flags_.size(); } @@ -328,8 +328,8 @@ void ORCA::spec(spec::Custom& custom) const { } -static const GridRegisterType __grid_type("ORCA"); -static const GridRegisterName __grid_pattern(GridRegisterName::uid_pattern); +static const GridRegisterType GRIDTYPE("ORCA"); +static const GridRegisterName GRIDNAME(GridRegisterName::uid_pattern); } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc index f93b6231e..d97e524f3 100644 --- a/src/eckit/geo/grid/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -148,9 +148,9 @@ struct ReducedGaussianOctahedral { }; -static const GridRegisterType __grid_type("reduced_gg"); -static const GridRegisterName __grid_pattern_1("[nN][1-9][0-9]*"); -static const GridRegisterName __grid_pattern_2("[oO][1-9][0-9]*"); +static const GridRegisterType GRIDTYPE("reduced_gg"); +static const GridRegisterName GRIDNAME1("[nN][1-9][0-9]*"); +static const GridRegisterName GRIDNAME2("[oO][1-9][0-9]*"); } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index fa4e6b584..71d164faa 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -12,6 +12,8 @@ #include "eckit/geo/grid/Regular.h" +#include + #include "eckit/exception/Exceptions.h" #include "eckit/geo/Increments.h" #include "eckit/geo/Spec.h" @@ -128,8 +130,7 @@ void RegularLL::spec(spec::Custom& custom) const { } -RegularGaussian::RegularGaussian(const Spec& spec) : - RegularGaussian(spec.get_unsigned("N"), area::BoundingBox(spec)) {} +RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian(spec.get_unsigned("N"), area::BoundingBox(spec)) {} RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : @@ -200,13 +201,13 @@ struct LambertAzimuthalEqualArea final : public Regular { }; -static const GridRegisterName __grid_pattern1(REGULAR_LL_PATTERN); -static const GridRegisterName __grid_pattern2("[fF][1-9][0-9]*"); +static const GridRegisterName GRIDNAME1(REGULAR_LL_PATTERN); +static const GridRegisterName GRIDNAME2("[fF][1-9][0-9]*"); -static const GridRegisterType __grid_type1("regular_ll"); -static const GridRegisterType __grid_type2("regular_gg"); -static const GridRegisterType __grid_type3("mercator"); -static const GridRegisterType __grid_type4("lambert_azimuthal_equal_area"); +static const GridRegisterType GRIDTYPE1("regular_ll"); +static const GridRegisterType GRIDTYPE2("regular_gg"); +static const GridRegisterType GRIDTYPE3("mercator"); +static const GridRegisterType GRIDTYPE4("lambert_azimuthal_equal_area"); } // namespace eckit::geo::grid diff --git a/src/eckit/geo/projection/LonLatToXY.cc b/src/eckit/geo/projection/LonLatToXY.cc index 0dfd1435d..2be295d56 100644 --- a/src/eckit/geo/projection/LonLatToXY.cc +++ b/src/eckit/geo/projection/LonLatToXY.cc @@ -18,7 +18,7 @@ namespace eckit::geo::projection { -static ProjectionBuilder __projection("ll_to_xy"); +static ProjectionBuilder PROJECTION("ll_to_xy"); Spec* LonLatToXY::spec() const { diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc index 320c8a3a0..1be20ce19 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -21,7 +21,7 @@ namespace eckit::geo::projection { -static ProjectionBuilder __projection("ll_to_xyz"); +static ProjectionBuilder PROJECTION("ll_to_xyz"); LonLatToXYZ::LonLatToXYZ(double a, double b) { @@ -31,8 +31,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { using S = Sphere; const double R_; - explicit LonLatToSphereXYZ(double R) : - R_(R) {} + explicit LonLatToSphereXYZ(double R) : R_(R) {} Point3 operator()(const PointLonLat& p) const override { return S::convertSphericalToCartesian(R_, p, 0.); } PointLonLat operator()(const Point3& q) const override { return S::convertCartesianToSpherical(R_, q); } Spec* spec() const override { return new spec::Custom{{{"R", R_}}}; } @@ -43,8 +42,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { const double a_; const double b_; - explicit LonLatToSpheroidXYZ(double a, double b) : - a_(a), b_(b) {} + explicit LonLatToSpheroidXYZ(double a, double b) : a_(a), b_(b) {} Point3 operator()(const PointLonLat& p) const override { return S::convertSphericalToCartesian(a_, b_, p, 0.); } PointLonLat operator()(const Point3& q) const override { NOTIMP; } Spec* spec() const override { return new spec::Custom{{{"a", a_}, {"b", b_}}}; } @@ -55,8 +53,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { } -LonLatToXYZ::LonLatToXYZ(double R) : - LonLatToXYZ(R, R) {} +LonLatToXYZ::LonLatToXYZ(double R) : LonLatToXYZ(R, R) {} LonLatToXYZ::LonLatToXYZ(const Spec& spec) : diff --git a/src/eckit/geo/projection/Mercator.cc b/src/eckit/geo/projection/Mercator.cc index 1e1c2b12d..74ab51959 100644 --- a/src/eckit/geo/projection/Mercator.cc +++ b/src/eckit/geo/projection/Mercator.cc @@ -23,7 +23,7 @@ namespace eckit::geo::projection { -static ProjectionBuilder __projection("mercator"); +static ProjectionBuilder PROJECTION("mercator"); Mercator::Mercator(double meridian, double parallel, Figure* figure, PointLonLat first) : @@ -53,16 +53,16 @@ Mercator::Mercator(double meridian, double parallel, Figure* figure, PointLonLat w_ = 1. / m_; x0_ = m_ * (lam0_ - lam1); - y0_ = m_ * std::log(std::tan(M_PI_4 - 0.5 * phi1) / - std::pow(((1. - e_ * std::sin(phi1)) / (1. + e_ * std::sin(phi1))), 0.5 * e_)); + y0_ = m_ + * std::log(std::tan(M_PI_4 - 0.5 * phi1) + / std::pow(((1. - e_ * std::sin(phi1)) / (1. + e_ * std::sin(phi1))), 0.5 * e_)); ASSERT(types::is_approximately_equal(phi1, calculate_phi(std::exp(y0_ * w_)), eps_)); } Mercator::Mercator(const Spec& spec) : - Mercator(spec.get_double("meridian"), - spec.get_double("parallel"), + Mercator(spec.get_double("meridian"), spec.get_double("parallel"), FigureFactory::instance().get(spec.get_string("figure")).create(spec), PointLonLat{spec.get_double("lon0"), spec.get_double("lat0")}) {} diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index cb2cceb43..8caf3932f 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -18,7 +18,7 @@ namespace eckit::geo::projection { -static ProjectionBuilder __projection("none"); +static ProjectionBuilder PROJECTION("none"); Spec* None::spec() const { diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 8b0c3bfe2..205dcf35d 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -19,7 +19,7 @@ namespace eckit::geo::projection { -static ProjectionBuilder __projection("proj"); +static ProjectionBuilder PROJECTION("proj"); PROJ::PROJ(const std::string& source, const std::string& target, double lon_minimum) : @@ -41,8 +41,7 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini Point convert(const PJ_COORD& c) const final { return PointLonLat::make(c.enu.e, c.enu.n, lon_minimum_); } - explicit LonLat(double lon_minimum) : - lon_minimum_(lon_minimum) {} + explicit LonLat(double lon_minimum) : lon_minimum_(lon_minimum) {} const double lon_minimum_; }; diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index bd2c6c6b3..1539e8bb3 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -25,15 +25,13 @@ namespace eckit::geo::projection { -static ProjectionBuilder __projection("rotation"); +static ProjectionBuilder PROJECTION("rotation"); -Rotation::Rotation() : - Rotation(-90., 0., 0.) {} +Rotation::Rotation() : Rotation(-90., 0., 0.) {} -Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : - rotated_(true) { +Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : rotated_(true) { using M = maths::Matrix3; struct NonRotated final : Implementation { @@ -42,16 +40,14 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : }; struct RotationAngle final : Implementation { - explicit RotationAngle(double angle) : - angle_(angle) {} + explicit RotationAngle(double angle) : angle_(angle) {} PointLonLat operator()(const PointLonLat& p) const override { return {p.lon + angle_, p.lat}; } Spec* spec() const override { return new spec::Custom{{{"angle", angle_}}}; } const double angle_; }; struct RotationMatrix final : Implementation { - explicit RotationMatrix(M&& R) : - RotationMatrix(std::move(R), 0, 0, 0) {} + explicit RotationMatrix(M&& R) : RotationMatrix(std::move(R), 0, 0, 0) {} RotationMatrix(M&& R, double south_pole_lon, double south_pole_lat, double angle) : R_(R), south_pole_lon_(south_pole_lon), south_pole_lat_(south_pole_lat), angle_(angle) {} PointLonLat operator()(const PointLonLat& p) const override { @@ -95,29 +91,21 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : // q = Rz Ry Ra p = [ cosφ sinφ ] [ cosϑ sinϑ ] [ cosα sinα ] p // [ -sinφ cosφ ] [ 1 ] [ -sinα cosα ] // [ 1 ] [ -sinϑ cosϑ ] [ 1 ] - fwd_ = std::make_unique(M{ca * cp * ct - sa * sp, - sa * cp * ct + ca * sp, + fwd_ = std::make_unique(M{ca * cp * ct - sa * sp, sa * cp * ct + ca * sp, cp * st, // - -sa * cp - ca * ct * sp, - ca * cp - sa * ct * sp, + -sa * cp - ca * ct * sp, ca * cp - sa * ct * sp, -sp * st, // - -ca * st, - -sa * st, - ct}); + -ca * st, -sa * st, ct}); // Un-rotate (rotate by -φ, -ϑ, -α): // p = Ra Ry Rz q = [ cosα -sinα ] [ cosϑ -sinϑ ] [ cosφ -sinφ ] q // [ sinα cosα ] [ 1 ] [ sinφ cosφ ] // [ 1 ] [ sinϑ cosϑ ] [ 1 ] - inv_ = std::make_unique(M{ca * cp * ct - sa * sp, - -sa * cp - ca * ct * sp, + inv_ = std::make_unique(M{ca * cp * ct - sa * sp, -sa * cp - ca * ct * sp, -ca * st, // - sa * cp * ct + ca * sp, - ca * cp - sa * ct * sp, + sa * cp * ct + ca * sp, ca * cp - sa * ct * sp, -sa * st, // - cp * st, - -sp * st, - ct}); + cp * st, -sp * st, ct}); } diff --git a/src/eckit/geo/projection/XYToLonLat.cc b/src/eckit/geo/projection/XYToLonLat.cc index d536c6208..04c2c40b7 100644 --- a/src/eckit/geo/projection/XYToLonLat.cc +++ b/src/eckit/geo/projection/XYToLonLat.cc @@ -18,8 +18,8 @@ namespace eckit::geo::projection { -static ProjectionBuilder __projection1("xy_to_ll"); -static ProjectionBuilder __projection2("plate-carree"); +static ProjectionBuilder PROJECTION1("xy_to_ll"); +static ProjectionBuilder PROJECTION2("plate-carree"); Spec* XYToLonLat::spec() const { diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 20b617842..b16489329 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -29,28 +29,28 @@ namespace { template -bool __get_s(const From& from, To& to) { +bool get_t_s(const From& from, To& to) { to = static_cast(from); return true; } template -bool __get_s(const From& from, std::string& to) { +bool get_t_s(const From& from, std::string& to) { to = std::to_string(from); return true; } template -bool __get_s(const From& from, From& to) { +bool get_t_s(const From& from, From& to) { to = from; return true; } template -bool __get_v(const std::vector& from, std::vector& to) { +bool get_t_v(const std::vector& from, std::vector& to) { to.clear(); for (const auto& f : from) { to.emplace_back(static_cast(f)); @@ -60,20 +60,20 @@ bool __get_v(const std::vector& from, std::vector& to) { template -bool __get_v(const std::vector& from, std::vector& to) { +bool get_t_v(const std::vector& from, std::vector& to) { to = from; return true; } template -bool __get_s_integral(const Custom::container_type& map, const std::string& name, T& value) { +bool get_t_s_integral(const Custom::container_type& map, const std::string& name, T& value) { if (auto it = map.find(name); it != map.cend()) { const auto& v = it->second; - return std::holds_alternative(v) ? __get_s(std::get(v), value) - : std::holds_alternative(v) ? __get_s(std::get(v), value) - : std::holds_alternative(v) ? __get_s(std::get(v), value) - : std::holds_alternative(v) ? __get_s(std::get(v), value) + return std::holds_alternative(v) ? get_t_s(std::get(v), value) + : std::holds_alternative(v) ? get_t_s(std::get(v), value) + : std::holds_alternative(v) ? get_t_s(std::get(v), value) + : std::holds_alternative(v) ? get_t_s(std::get(v), value) : false; } return false; @@ -81,15 +81,15 @@ bool __get_s_integral(const Custom::container_type& map, const std::string& name template -bool __get_s_real(const Custom::container_type& map, const std::string& name, T& value) { - if (__get_s_integral(map, name, value)) { +bool get_t_s_real(const Custom::container_type& map, const std::string& name, T& value) { + if (get_t_s_integral(map, name, value)) { return true; } if (auto it = map.find(name); it != map.cend()) { const auto& v = it->second; - return std::holds_alternative(v) ? __get_s(std::get(v), value) - : std::holds_alternative(v) ? __get_s(std::get(v), value) + return std::holds_alternative(v) ? get_t_s(std::get(v), value) + : std::holds_alternative(v) ? get_t_s(std::get(v), value) : false; } return false; @@ -97,13 +97,13 @@ bool __get_s_real(const Custom::container_type& map, const std::string& name, T& template -bool __get_v_integral(const Custom::container_type& map, const std::string& name, T& value) { +bool get_t_v_integral(const Custom::container_type& map, const std::string& name, T& value) { if (auto it = map.find(name); it != map.cend()) { const auto& v = it->second; - return std::holds_alternative>(v) ? __get_v(std::get>(v), value) - : std::holds_alternative>(v) ? __get_v(std::get>(v), value) - : std::holds_alternative>(v) ? __get_v(std::get>(v), value) - : std::holds_alternative>(v) ? __get_v(std::get>(v), value) + return std::holds_alternative>(v) ? get_t_v(std::get>(v), value) + : std::holds_alternative>(v) ? get_t_v(std::get>(v), value) + : std::holds_alternative>(v) ? get_t_v(std::get>(v), value) + : std::holds_alternative>(v) ? get_t_v(std::get>(v), value) : false; } return false; @@ -111,15 +111,15 @@ bool __get_v_integral(const Custom::container_type& map, const std::string& name template -bool __get_v_real(const Custom::container_type& map, const std::string& name, T& value) { - if (__get_v_integral(map, name, value)) { +bool get_t_v_real(const Custom::container_type& map, const std::string& name, T& value) { + if (get_t_v_integral(map, name, value)) { return true; } if (auto it = map.find(name); it != map.cend()) { const auto& v = it->second; - return std::holds_alternative>(v) ? __get_v(std::get>(v), value) - : std::holds_alternative>(v) ? __get_v(std::get>(v), value) + return std::holds_alternative>(v) ? get_t_v(std::get>(v), value) + : std::holds_alternative>(v) ? get_t_v(std::get>(v), value) : false; } return false; @@ -127,7 +127,7 @@ bool __get_v_real(const Custom::container_type& map, const std::string& name, T& template -Custom::value_type __from_value(const Value& value) { +Custom::value_type from_value_t(const Value& value) { T to; fromValue(to, value); return {to}; @@ -143,18 +143,15 @@ JSON& operator<<(JSON& out, const Custom::value_type& value) { } // namespace -Custom::key_type::key_type(const std::string& s) : - std::string{s} { +Custom::key_type::key_type(const std::string& s) : std::string{s} { std::transform(begin(), end(), begin(), [](unsigned char c) -> unsigned char { return std::tolower(c); }); } -Custom::Custom(const Custom::container_type& map) : - map_(map) {} +Custom::Custom(const Custom::container_type& map) : map_(map) {} -Custom::Custom(Custom::container_type&& map) : - map_(map) {} +Custom::Custom(Custom::container_type&& map) : map_(map) {} Custom::Custom(const Value& value) { @@ -182,12 +179,10 @@ Custom::Custom(const Value& value) { } -Custom::Custom(const Custom& custom) : - Custom(custom.map_) {} +Custom::Custom(const Custom& custom) : Custom(custom.map_) {} -Custom::Custom(Custom&& custom) : - Custom(custom.map_) {} +Custom::Custom(Custom&& custom) : Custom(custom.map_) {} Custom& Custom::operator=(Custom&& custom) { @@ -300,13 +295,13 @@ void Custom::set(const std::string& key, const Value& value) { auto list_of = [](const ValueList& list, auto pred) { return std::all_of(list.begin(), list.end(), pred); }; auto val = value.isList() && list_of(value, [](const Value& v) { return v.isDouble(); }) - ? __from_value>(value) + ? from_value_t>(value) : value.isList() && list_of(value, [](const Value& v) { return v.isNumber(); }) - ? __from_value>(value) - : value.isList() ? __from_value>(value) - : value.isDouble() ? __from_value(value) - : value.isNumber() ? __from_value(value) - : __from_value(value); + ? from_value_t>(value) + : value.isList() ? from_value_t>(value) + : value.isDouble() ? from_value_t(value) + : value.isNumber() ? from_value_t(value) + : from_value_t(value); std::visit([&](const auto& val) { set(key, val); }, val); } @@ -324,7 +319,7 @@ bool Custom::get(const std::string& name, std::string& value) const { return true; } - return __get_s_real(map_, name, value); + return get_t_s_real(map_, name, value); } return false; } @@ -337,7 +332,7 @@ bool Custom::get(const std::string& name, bool& value) const { return true; } - if (int i = 0; __get_s_integral(map_, name, i)) { + if (int i = 0; get_t_s_integral(map_, name, i)) { value = i != 0; return true; } @@ -347,62 +342,62 @@ bool Custom::get(const std::string& name, bool& value) const { bool Custom::get(const std::string& name, int& value) const { - return __get_s_integral(map_, name, value); + return get_t_s_integral(map_, name, value); } bool Custom::get(const std::string& name, long& value) const { - return __get_s_integral(map_, name, value); + return get_t_s_integral(map_, name, value); } bool Custom::get(const std::string& name, long long& value) const { - return __get_s_integral(map_, name, value); + return get_t_s_integral(map_, name, value); } bool Custom::get(const std::string& name, size_t& value) const { - return __get_s_integral(map_, name, value); + return get_t_s_integral(map_, name, value); } bool Custom::get(const std::string& name, float& value) const { - return __get_s_real(map_, name, value); + return get_t_s_real(map_, name, value); } bool Custom::get(const std::string& name, double& value) const { - return __get_s_real(map_, name, value); + return get_t_s_real(map_, name, value); } bool Custom::get(const std::string& name, std::vector& value) const { - return __get_v_integral(map_, name, value); + return get_t_v_integral(map_, name, value); } bool Custom::get(const std::string& name, std::vector& value) const { - return __get_v_integral(map_, name, value); + return get_t_v_integral(map_, name, value); } bool Custom::get(const std::string& name, std::vector& value) const { - return __get_v_integral(map_, name, value); + return get_t_v_integral(map_, name, value); } bool Custom::get(const std::string& name, std::vector& value) const { - return __get_v_integral(map_, name, value); + return get_t_v_integral(map_, name, value); } bool Custom::get(const std::string& name, std::vector& value) const { - return __get_v_real(map_, name, value); + return get_t_v_real(map_, name, value); } bool Custom::get(const std::string& name, std::vector& value) const { - return __get_v_real(map_, name, value); + return get_t_v_real(map_, name, value); } diff --git a/src/eckit/geo/spec/Layered.h b/src/eckit/geo/spec/Layered.h index 7a49522d5..a0fb3c3a2 100644 --- a/src/eckit/geo/spec/Layered.h +++ b/src/eckit/geo/spec/Layered.h @@ -38,30 +38,29 @@ class Layered final : public Spec { // -- Overridden methods bool has(const std::string& name) const override { - return !hide_.contains(name) && - (std::any_of(front_.begin(), - front_.end(), - [&](const decltype(front_)::value_type& c) { return c->has(name); }) || - spec_.has(name) || std::any_of(back_.begin(), back_.end(), [&](const decltype(back_)::value_type& c) { - return c->has(name); - })); + return !hide_.contains(name) + && (std::any_of(front_.begin(), front_.end(), + [&](const decltype(front_)::value_type& c) { return c->has(name); }) + || spec_.has(name) + || std::any_of(back_.begin(), back_.end(), + [&](const decltype(back_)::value_type& c) { return c->has(name); })); } - bool get(const std::string& name, std::string& value) const override { return __get(name, value); } - bool get(const std::string& name, bool& value) const override { return __get(name, value); } - bool get(const std::string& name, int& value) const override { return __get(name, value); } - bool get(const std::string& name, long& value) const override { return __get(name, value); } - bool get(const std::string& name, long long& value) const override { return __get(name, value); } - bool get(const std::string& name, size_t& value) const override { return __get(name, value); } - bool get(const std::string& name, float& value) const override { return __get(name, value); } - bool get(const std::string& name, double& value) const override { return __get(name, value); } - bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } - bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } - bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } - bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } - bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } - bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } - bool get(const std::string& name, std::vector& value) const override { return __get(name, value); } + bool get(const std::string& name, std::string& value) const override { return get_t(name, value); } + bool get(const std::string& name, bool& value) const override { return get_t(name, value); } + bool get(const std::string& name, int& value) const override { return get_t(name, value); } + bool get(const std::string& name, long& value) const override { return get_t(name, value); } + bool get(const std::string& name, long long& value) const override { return get_t(name, value); } + bool get(const std::string& name, size_t& value) const override { return get_t(name, value); } + bool get(const std::string& name, float& value) const override { return get_t(name, value); } + bool get(const std::string& name, double& value) const override { return get_t(name, value); } + bool get(const std::string& name, std::vector& value) const override { return get_t(name, value); } + bool get(const std::string& name, std::vector& value) const override { return get_t(name, value); } + bool get(const std::string& name, std::vector& value) const override { return get_t(name, value); } + bool get(const std::string& name, std::vector& value) const override { return get_t(name, value); } + bool get(const std::string& name, std::vector& value) const override { return get_t(name, value); } + bool get(const std::string& name, std::vector& value) const override { return get_t(name, value); } + bool get(const std::string& name, std::vector& value) const override { return get_t(name, value); } private: // -- Members @@ -77,15 +76,13 @@ class Layered final : public Spec { // -- Methods template - bool __get(const std::string& name, T& value) const { - return !hide_.contains(name) && - (std::any_of(front_.rbegin(), - front_.rend(), - [&](const decltype(front_)::value_type& c) { return c->get(name, value); }) || - spec_.get(name, value) || - std::any_of(back_.begin(), back_.end(), [&](const decltype(back_)::value_type& c) { - return c->get(name, value); - })); + bool get_t(const std::string& name, T& value) const { + return !hide_.contains(name) + && (std::any_of(front_.rbegin(), front_.rend(), + [&](const decltype(front_)::value_type& c) { return c->get(name, value); }) + || spec_.get(name, value) + || std::any_of(back_.begin(), back_.end(), + [&](const decltype(back_)::value_type& c) { return c->get(name, value); })); } // -- Overridden methods From 32e0e889019c65d866ae22bab4b05c259989bf4a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 3 May 2024 15:21:06 +0100 Subject: [PATCH 605/737] PROJ improvements --- src/eckit/geo/projection/PROJ.cc | 48 ++++++++++++++++++++++++++++---- src/eckit/geo/projection/PROJ.h | 39 ++++---------------------- 2 files changed, 48 insertions(+), 39 deletions(-) diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 205dcf35d..770908f3d 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -12,6 +12,8 @@ #include "eckit/geo/projection/PROJ.h" +#include + #include "eckit/exception/Exceptions.h" #include "eckit/geo/spec/Custom.h" @@ -22,16 +24,50 @@ namespace eckit::geo::projection { static ProjectionBuilder PROJECTION("proj"); +template +struct proj_ptr_container_t : std::unique_ptr { + using t = std::unique_ptr; + explicit proj_ptr_container_t(T* ptr) : t(ptr, D()) {} + explicit operator T*() const { return t::get(); } +}; + + +using pj_t = proj_ptr_container_t; +using ctx_t = proj_ptr_container_t; + + +struct PROJ::Implementation { + explicit Implementation(PJ* pj_ptr, PJ_CONTEXT* pjc_ptr = PJ_DEFAULT_CTX) : proj(pj_ptr), ctx(pjc_ptr) {} + pj_t proj; + ctx_t ctx; +}; + + +struct PROJ::Convert { + Convert() = default; + virtual ~Convert() = default; + + Convert(const Convert&) = delete; + Convert(Convert&&) = delete; + void operator=(const Convert&) = delete; + void operator=(Convert&&) = delete; + + virtual PJ_COORD convert(const Point&) const = 0; + virtual Point convert(const PJ_COORD&) const = 0; +}; + + PROJ::PROJ(const std::string& source, const std::string& target, double lon_minimum) : - proj_(nullptr), ctx_(PJ_DEFAULT_CTX), source_(source), target_(target) { + implementation_(nullptr), source_(source), target_(target) { + ASSERT(implementation_); ASSERT(!source.empty()); // projection, normalised - pj_t p(proj_create_crs_to_crs(ctx_.get(), source_.c_str(), target_.c_str(), nullptr)); + pj_t p(proj_create_crs_to_crs(implementation_->ctx.get(), source_.c_str(), target_.c_str(), nullptr)); ASSERT(p); - proj_.reset(proj_normalize_for_visualization(ctx_.get(), p.get())); - ASSERT(proj_); + implementation_->proj.reset(proj_normalize_for_visualization(implementation_->ctx.get(), p.get())); + ASSERT(implementation_->proj); struct LonLat final : Convert { PJ_COORD convert(const Point& p) const final { @@ -113,12 +149,12 @@ std::string PROJ::ellipsoid(const std::string& string) { Point PROJ::fwd(const Point& p) const { - return to_->convert(proj_trans(proj_.get(), PJ_FWD, from_->convert(p))); + return to_->convert(proj_trans(implementation_->proj.get(), PJ_FWD, from_->convert(p))); } Point PROJ::inv(const Point& q) const { - return from_->convert(proj_trans(proj_.get(), PJ_INV, to_->convert(q))); + return from_->convert(proj_trans(implementation_->proj.get(), PJ_INV, to_->convert(q))); } diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index 1970793af..3ab6f2778 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -14,8 +14,6 @@ #include -#include - #include "eckit/geo/Projection.h" @@ -25,35 +23,6 @@ namespace eckit::geo::projection { /// Calculate coordinates using PROJ class PROJ final : public Projection { public: - // -- Types - - struct pj_t : std::unique_ptr { - using t = std::unique_ptr; - explicit pj_t(PJ* ptr) : - t(ptr, &proj_destroy) {} - explicit operator PJ*() const { return t::get(); } - }; - - struct ctx_t : std::unique_ptr { - using t = std::unique_ptr; - explicit ctx_t(PJ_CONTEXT* ptr) : - t(ptr, &proj_context_destroy) {} - explicit operator PJ_CONTEXT*() const { return t::get(); } - }; - - struct Convert { - Convert() = default; - virtual ~Convert() = default; - - Convert(const Convert&) = delete; - Convert(Convert&&) = delete; - void operator=(const Convert&) = delete; - void operator=(Convert&&) = delete; - - virtual PJ_COORD convert(const Point&) const = 0; - virtual Point convert(const PJ_COORD&) const = 0; - }; - // -- Exceptions // None @@ -92,10 +61,14 @@ class PROJ final : public Projection { // None private: + // -- Types + + struct Implementation; + struct Convert; + // -- Members - pj_t proj_; - ctx_t ctx_; + std::unique_ptr implementation_; const std::string source_; const std::string target_; From 57bc993f93f66ff45f0ad599116c305f1740031b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 3 May 2024 15:22:48 +0100 Subject: [PATCH 606/737] PROJ improvements --- src/eckit/geo/projection/PROJ.cc | 151 +++++++++++++++++-------------- src/eckit/geo/projection/PROJ.h | 4 - 2 files changed, 84 insertions(+), 71 deletions(-) diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 770908f3d..2e0dfb24d 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -24,26 +24,23 @@ namespace eckit::geo::projection { static ProjectionBuilder PROJECTION("proj"); -template -struct proj_ptr_container_t : std::unique_ptr { - using t = std::unique_ptr; - explicit proj_ptr_container_t(T* ptr) : t(ptr, D()) {} - explicit operator T*() const { return t::get(); } -}; +namespace { -using pj_t = proj_ptr_container_t; -using ctx_t = proj_ptr_container_t; +constexpr auto CTX = PJ_DEFAULT_CTX; -struct PROJ::Implementation { - explicit Implementation(PJ* pj_ptr, PJ_CONTEXT* pjc_ptr = PJ_DEFAULT_CTX) : proj(pj_ptr), ctx(pjc_ptr) {} - pj_t proj; - ctx_t ctx; +struct pj_t : std::unique_ptr { + explicit pj_t(element_type* ptr) : unique_ptr(ptr, &proj_destroy) {} }; -struct PROJ::Convert { +struct ctx_t : std::unique_ptr { + explicit ctx_t(element_type* ptr) : unique_ptr(ptr, &proj_context_destroy) {} +}; + + +struct Convert { Convert() = default; virtual ~Convert() = default; @@ -52,63 +49,83 @@ struct PROJ::Convert { void operator=(const Convert&) = delete; void operator=(Convert&&) = delete; - virtual PJ_COORD convert(const Point&) const = 0; - virtual Point convert(const PJ_COORD&) const = 0; + virtual PJ_COORD to_coord(const Point&) const = 0; + virtual Point to_point(const PJ_COORD&) const = 0; }; -PROJ::PROJ(const std::string& source, const std::string& target, double lon_minimum) : - implementation_(nullptr), source_(source), target_(target) { - ASSERT(implementation_); - ASSERT(!source.empty()); +struct LonLat final : Convert { + PJ_COORD to_coord(const Point& p) const final { + const auto& q = std::get(p); + return proj_coord(q.lon, q.lat, 0, 0); + } - // projection, normalised - pj_t p(proj_create_crs_to_crs(implementation_->ctx.get(), source_.c_str(), target_.c_str(), nullptr)); - ASSERT(p); + Point to_point(const PJ_COORD& c) const final { return PointLonLat::make(c.enu.e, c.enu.n, lon_minimum_); } - implementation_->proj.reset(proj_normalize_for_visualization(implementation_->ctx.get(), p.get())); - ASSERT(implementation_->proj); + explicit LonLat(double lon_minimum) : lon_minimum_(lon_minimum) {} + const double lon_minimum_; +}; - struct LonLat final : Convert { - PJ_COORD convert(const Point& p) const final { - const auto& q = std::get(p); - return proj_coord(q.lon, q.lat, 0, 0); - } - Point convert(const PJ_COORD& c) const final { return PointLonLat::make(c.enu.e, c.enu.n, lon_minimum_); } +struct XY final : Convert { + PJ_COORD to_coord(const Point& p) const final { + const auto& q = std::get(p); + return proj_coord(q.X, q.Y, 0, 0); + } - explicit LonLat(double lon_minimum) : lon_minimum_(lon_minimum) {} - const double lon_minimum_; - }; + Point to_point(const PJ_COORD& c) const final { return Point2{c.xy.x, c.xy.y}; } +}; - struct XY final : Convert { - PJ_COORD convert(const Point& p) const final { - const auto& q = std::get(p); - return proj_coord(q.X, q.Y, 0, 0); - } - Point convert(const PJ_COORD& c) const final { return Point2{c.xy.x, c.xy.y}; } - }; +struct XYZ final : Convert { + PJ_COORD to_coord(const Point& p) const final { + const auto& q = std::get(p); + return proj_coord(q.X, q.Y, q.Z, 0); + } - struct XYZ final : Convert { - PJ_COORD convert(const Point& p) const final { - const auto& q = std::get(p); - return proj_coord(q.X, q.Y, q.Z, 0); - } + Point to_point(const PJ_COORD& c) const final { return Point3{c.xy.x, c.xy.y, c.xyz.z}; } +}; - Point convert(const PJ_COORD& c) const final { return Point3{c.xy.x, c.xy.y, c.xyz.z}; } - }; - auto convert_ptr = [lon_minimum](const std::string& string) -> Convert* { - constexpr auto ctx = PJ_DEFAULT_CTX; +} // namespace + + +struct PROJ::Implementation { + Implementation(PJ* pj_ptr, PJ_CONTEXT* pjc_ptr, Convert* source_ptr, Convert* target_ptr) : + proj_(pj_ptr), ctx_(pjc_ptr), source_(source_ptr), target_(target_ptr) { + ASSERT(proj_); + ASSERT(source_); + ASSERT(target_); + } + + inline Point fwd(const Point& p) const { + return target_->to_point(proj_trans(proj_.get(), PJ_FWD, source_->to_coord(p))); + } + + inline Point inv(const Point& p) const { + return source_->to_point(proj_trans(proj_.get(), PJ_INV, target_->to_coord(p))); + } + +private: + const pj_t proj_; + const ctx_t ctx_; + const std::unique_ptr source_; + const std::unique_ptr target_; +}; + - pj_t identity(proj_create_crs_to_crs(ctx, string.c_str(), string.c_str(), nullptr)); - pj_t crs(proj_get_target_crs(ctx, identity.get())); - pj_t cs(proj_crs_get_coordinate_system(ctx, crs.get())); +PROJ::PROJ(const std::string& source, const std::string& target, double lon_minimum) : + source_(source), target_(target) { + ASSERT(!source.empty()); + + auto make_convert = [lon_minimum](const std::string& string) -> Convert* { + pj_t identity(proj_create_crs_to_crs(CTX, string.c_str(), string.c_str(), nullptr)); + pj_t crs(proj_get_target_crs(CTX, identity.get())); + pj_t cs(proj_crs_get_coordinate_system(CTX, crs.get())); ASSERT(cs); - auto type = proj_cs_get_type(ctx, cs.get()); - auto dim = proj_cs_get_axis_count(ctx, cs.get()); + auto type = proj_cs_get_type(CTX, cs.get()); + auto dim = proj_cs_get_axis_count(CTX, cs.get()); return type == PJ_CS_TYPE_CARTESIAN && dim == 3 ? static_cast(new XYZ) : type == PJ_CS_TYPE_CARTESIAN && dim == 2 ? static_cast(new XY) @@ -117,11 +134,13 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini : NOTIMP; }; - from_.reset(convert_ptr(source_)); - ASSERT(from_); + // projection, normalised + auto ctx = PJ_DEFAULT_CTX; - to_.reset(convert_ptr(target_)); - ASSERT(to_); + implementation_ = std::make_unique( + proj_normalize_for_visualization(ctx, proj_create_crs_to_crs(ctx, source_.c_str(), target_.c_str(), nullptr)), + ctx, make_convert(source_), make_convert(target_)); + ASSERT(implementation_); } @@ -132,16 +151,14 @@ PROJ::PROJ(const Spec& spec) : std::string PROJ::ellipsoid(const std::string& string) { - constexpr auto ctx = PJ_DEFAULT_CTX; - - pj_t identity(proj_create_crs_to_crs(ctx, string.c_str(), string.c_str(), nullptr)); - pj_t crs(proj_get_target_crs(ctx, identity.get())); - pj_t ellipsoid(proj_get_ellipsoid(ctx, crs.get())); + pj_t identity(proj_create_crs_to_crs(CTX, string.c_str(), string.c_str(), nullptr)); + pj_t crs(proj_get_target_crs(CTX, identity.get())); + pj_t ellipsoid(proj_get_ellipsoid(CTX, crs.get())); ASSERT(ellipsoid); double a = 0; double b = 0; - ASSERT(proj_ellipsoid_get_parameters(ctx, ellipsoid.get(), &a, &b, nullptr, nullptr)); + ASSERT(proj_ellipsoid_get_parameters(CTX, ellipsoid.get(), &a, &b, nullptr, nullptr)); ASSERT(0 < b && b <= a); return b < a ? "+a=" + std::to_string(a) + " +b=" + std::to_string(b) : "+R=" + std::to_string(a); @@ -149,17 +166,17 @@ std::string PROJ::ellipsoid(const std::string& string) { Point PROJ::fwd(const Point& p) const { - return to_->convert(proj_trans(implementation_->proj.get(), PJ_FWD, from_->convert(p))); + return implementation_->fwd(p); } Point PROJ::inv(const Point& q) const { - return from_->convert(proj_trans(implementation_->proj.get(), PJ_INV, to_->convert(q))); + return implementation_->inv(q); } Spec* PROJ::spec() const { - return new spec::Custom{{{"source", source_}, {"target", target_}}}; + return new spec::Custom{{{"projection", "proj"}, {"source", source_}, {"target", target_}}}; } diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index 3ab6f2778..e7faf613a 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -64,7 +64,6 @@ class PROJ final : public Projection { // -- Types struct Implementation; - struct Convert; // -- Members @@ -73,9 +72,6 @@ class PROJ final : public Projection { const std::string source_; const std::string target_; - std::unique_ptr from_; - std::unique_ptr to_; - // -- Methods // None From b3d9a9e2323e878c20240acc4c7c41beb3660e0d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 14:36:47 +0100 Subject: [PATCH 607/737] clang-format version 19 --- src/eckit/geo/Cache.h | 7 ++----- src/eckit/geo/GreatCircle.cc | 7 +++---- src/eckit/geo/Grid.cc | 6 ++---- src/eckit/geo/Grid.h | 5 +---- src/eckit/geo/Increments.cc | 3 +-- src/eckit/geo/Increments.h | 9 +++------ src/eckit/geo/LibEcKitGeo.cc | 3 +-- src/eckit/geo/Range.cc | 3 +-- src/eckit/geo/Shape.cc | 3 +-- src/eckit/geo/Shape.h | 12 ++++-------- src/eckit/geo/Sphere.cc | 8 ++++---- src/eckit/geo/Sphere.h | 4 ++-- src/eckit/geo/SphereT.h | 4 ++-- src/eckit/geo/area/BoundingBox.cc | 22 ++++++++++------------ src/eckit/geo/area/BoundingBox.h | 6 ++---- src/eckit/geo/figure/OblateSpheroid.cc | 6 ++---- src/eckit/geo/figure/Sphere.cc | 6 ++---- src/eckit/geo/grid/Reduced.h | 6 ++---- src/eckit/geo/grid/ReducedLL.cc | 3 +-- src/eckit/geo/grid/Regular.h | 3 +-- src/eckit/geo/grid/Unstructured.cc | 3 +-- src/eckit/geo/iterator/Unstructured.cc | 13 ++++--------- src/eckit/geo/iterator/Unstructured.h | 4 +--- src/eckit/geo/polygon/LonLatPolygon.cc | 15 +++++++-------- src/eckit/geo/polygon/Polygon.h | 3 +-- src/eckit/geo/range/GaussianLatitude.cc | 4 ++-- src/eckit/geo/range/Regular.cc | 3 +-- src/eckit/geo/range/Regular.h | 3 +-- src/eckit/geo/range/RegularCartesian.cc | 4 ++-- src/eckit/geo/range/RegularCartesian.h | 3 +-- src/eckit/geo/range/RegularLatitude.cc | 7 +++---- src/eckit/geo/range/RegularLongitude.h | 3 +-- src/eckit/geo/spec/Custom.h | 21 ++++----------------- src/eckit/geo/spec/Generator.h | 14 +++++--------- src/eckit/geo/spec/Layered.cc | 6 ++---- src/eckit/geo/util/gaussian_latitudes.cc | 8 ++++---- src/eckit/geo/util/linspace.cc | 5 ++--- src/eckit/geo/util/monotonic_crop.cc | 9 +++------ 38 files changed, 92 insertions(+), 162 deletions(-) diff --git a/src/eckit/geo/Cache.h b/src/eckit/geo/Cache.h index 6ec1cca5a..7b364576d 100644 --- a/src/eckit/geo/Cache.h +++ b/src/eckit/geo/Cache.h @@ -48,7 +48,7 @@ class CacheT final : private Cache { struct has_footprint : std::false_type {}; template - struct has_footprint>> : std::true_type {}; + struct has_footprint>> : std::true_type{}; template static inline constexpr bool has_footprint_v = has_footprint::value; @@ -57,10 +57,7 @@ class CacheT final : private Cache { using key_type = Key; using value_type = Value; - CacheT() : - mutex_(new util::recursive_mutex) { - ASSERT(mutex_ != nullptr); - } + CacheT() : mutex_(new util::recursive_mutex) { ASSERT(mutex_ != nullptr); } bool contains(const key_type& key) const { util::lock_guard lock(*mutex_); diff --git a/src/eckit/geo/GreatCircle.cc b/src/eckit/geo/GreatCircle.cc index bb615fec0..0689b7451 100644 --- a/src/eckit/geo/GreatCircle.cc +++ b/src/eckit/geo/GreatCircle.cc @@ -32,8 +32,7 @@ static bool pole(const double lat) { //---------------------------------------------------------------------------------------------------------------------- -GreatCircle::GreatCircle(const PointLonLat& Alonlat, const PointLonLat& Blonlat) : - A_(Alonlat), B_(Blonlat) { +GreatCircle::GreatCircle(const PointLonLat& Alonlat, const PointLonLat& Blonlat) : A_(Alonlat), B_(Blonlat) { const bool Apole = pole(A_.lat); const bool Bpole = pole(B_.lat); const double lon12_deg = PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); @@ -64,8 +63,8 @@ std::vector GreatCircle::latitude(double lon) const { const double lambda2p = util::DEGREE_TO_RADIAN * (lon - B_.lon); const double lambda = util::DEGREE_TO_RADIAN * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, -180.); - double lat = - std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); + double lat + = std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); return {util::RADIAN_TO_DEGREE * lat}; } diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 69f9612e0..3e62f47ba 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -37,12 +37,10 @@ class lock_type { }; -Grid::Grid(const Spec& spec) : - bbox_(area::BoundingBox::make_from_spec(spec)) {} +Grid::Grid(const Spec& spec) : bbox_(area::BoundingBox::make_from_spec(spec)) {} -Grid::Grid(const area::BoundingBox& bbox) : - bbox_(new area::BoundingBox(bbox)) {} +Grid::Grid(const area::BoundingBox& bbox) : bbox_(new area::BoundingBox(bbox)) {} std::string Grid::spec() const { diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 19d4ca40c..765d1ca6a 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -55,10 +55,7 @@ class Grid { using ARG1 = const Spec&; struct Iterator final : std::unique_ptr { - explicit Iterator(geo::Iterator* it) : - unique_ptr(it) { - ASSERT(unique_ptr::operator bool()); - } + explicit Iterator(geo::Iterator* it) : unique_ptr(it) { ASSERT(unique_ptr::operator bool()); } using difference_type = unique_ptr::element_type::difference_type; diff --git a/src/eckit/geo/Increments.cc b/src/eckit/geo/Increments.cc index aed5c4ed7..94dd79c0c 100644 --- a/src/eckit/geo/Increments.cc +++ b/src/eckit/geo/Increments.cc @@ -35,8 +35,7 @@ Increments Increments::make_from_spec(const Spec& spec) { } -Increments::Increments(value_type dx, value_type dy) : - array{dx, dy} { +Increments::Increments(value_type dx, value_type dy) : array{dx, dy} { if (!(dx != 0) || !(dy != 0)) { throw BadValue("'shape' = ['dx', 'dy'] != 0 expected"); } diff --git a/src/eckit/geo/Increments.h b/src/eckit/geo/Increments.h index c6b86052f..e718bbade 100644 --- a/src/eckit/geo/Increments.h +++ b/src/eckit/geo/Increments.h @@ -28,16 +28,13 @@ class Increments : public std::array { public: // -- Constructors - explicit Increments(const Spec& spec) : - Increments(make_from_spec(spec)) {} + explicit Increments(const Spec& spec) : Increments(make_from_spec(spec)) {} Increments(value_type dx, value_type dy); - Increments(const Increments& other) : - array(other) {} + Increments(const Increments& other) : array(other) {} - Increments(Increments&& other) : - array(other) {} + Increments(Increments&& other) : array(other) {} // -- Destructor diff --git a/src/eckit/geo/LibEcKitGeo.cc b/src/eckit/geo/LibEcKitGeo.cc index e84f98cfb..5854ef749 100644 --- a/src/eckit/geo/LibEcKitGeo.cc +++ b/src/eckit/geo/LibEcKitGeo.cc @@ -25,8 +25,7 @@ namespace eckit { REGISTER_LIBRARY(LibEcKitGeo); -LibEcKitGeo::LibEcKitGeo() : - Library("eckit_geo") {} +LibEcKitGeo::LibEcKitGeo() : Library("eckit_geo") {} LibEcKitGeo& LibEcKitGeo::instance() { diff --git a/src/eckit/geo/Range.cc b/src/eckit/geo/Range.cc index 263d1fd97..18ab57d95 100644 --- a/src/eckit/geo/Range.cc +++ b/src/eckit/geo/Range.cc @@ -19,8 +19,7 @@ namespace eckit::geo { -Range::Range(size_t n, double _a, double _b, double _eps) : - n_(n), a_(_a), b_(_b), eps_(_eps) { +Range::Range(size_t n, double _a, double _b, double _eps) : n_(n), a_(_a), b_(_b), eps_(_eps) { ASSERT(0 < n); ASSERT(0. <= eps_); if (types::is_approximately_equal(_a, _b)) { diff --git a/src/eckit/geo/Shape.cc b/src/eckit/geo/Shape.cc index 0f6ea8bc0..2f403c00d 100644 --- a/src/eckit/geo/Shape.cc +++ b/src/eckit/geo/Shape.cc @@ -34,8 +34,7 @@ Shape Shape::make_from_spec(const Spec& spec) { } -Shape::Shape(value_type nx, value_type ny) : - array{nx, ny} { +Shape::Shape(value_type nx, value_type ny) : array{nx, ny} { if (!(nx > 0) || !(ny > 0)) { throw BadValue("'shape' = ['nx', 'ny'] > 0 expected"); } diff --git a/src/eckit/geo/Shape.h b/src/eckit/geo/Shape.h index b777f303a..d78bd5070 100644 --- a/src/eckit/geo/Shape.h +++ b/src/eckit/geo/Shape.h @@ -28,19 +28,15 @@ class Shape final : public std::array { public: // -- Constructors - explicit Shape(const Spec& spec) : - Shape(make_from_spec(spec)) {} + explicit Shape(const Spec& spec) : Shape(make_from_spec(spec)) {} Shape(value_type nx, value_type ny); - Shape() : - Shape(0, 0) {} + Shape() : Shape(0, 0) {} - Shape(const Shape& other) : - array(other) {} + Shape(const Shape& other) : array(other) {} - Shape(Shape&& other) : - array(other) {} + Shape(Shape&& other) : array(other) {} // -- Destructor diff --git a/src/eckit/geo/Sphere.cc b/src/eckit/geo/Sphere.cc index 6ff38060f..75834e321 100644 --- a/src/eckit/geo/Sphere.cc +++ b/src/eckit/geo/Sphere.cc @@ -61,8 +61,8 @@ double Sphere::centralAngle(const PointLonLat& P1, const PointLonLat& P2) { auto squared = [](double x) { return x * x; }; - const auto angle = - std::atan2(std::sqrt(squared(cp2 * sl) + squared(cp1 * sp2 - sp1 * cp2 * cl)), sp1 * sp2 + cp1 * cp2 * cl); + const auto angle + = std::atan2(std::sqrt(squared(cp2 * sl) + squared(cp1 * sp2 - sp1 * cp2 * cl)), sp1 * sp2 + cp1 * cp2 * cl); if (is_approximately_equal(angle, 0.)) { return 0.; @@ -139,8 +139,8 @@ double Sphere::greatCircleLatitudeGivenLongitude(const PointLonLat& P1, const Po } -void Sphere::greatCircleLongitudeGivenLatitude( - const PointLonLat& P1, const PointLonLat& P2, double Clat, double& Clon1, double& Clon2) { +void Sphere::greatCircleLongitudeGivenLatitude(const PointLonLat& P1, const PointLonLat& P2, double Clat, double& Clon1, + double& Clon2) { GreatCircle gc(P1, P2); auto lon = gc.longitude(Clat); diff --git a/src/eckit/geo/Sphere.h b/src/eckit/geo/Sphere.h index 048108668..3c6eac4aa 100644 --- a/src/eckit/geo/Sphere.h +++ b/src/eckit/geo/Sphere.h @@ -42,8 +42,8 @@ struct Sphere { static double greatCircleLatitudeGivenLongitude(const PointLonLat&, const PointLonLat&, double lon); // Great-circle intermediate longitude(s) provided two circle points and intermediate latitude in degrees - static void greatCircleLongitudeGivenLatitude( - const PointLonLat&, const PointLonLat&, double lat, double& lon1, double& lon2); + static void greatCircleLongitudeGivenLatitude(const PointLonLat&, const PointLonLat&, double lat, double& lon1, + double& lon2); /// Convert spherical to Cartesian coordinates static Point3 convertSphericalToCartesian(double radius, const PointLonLat&, double height = 0.); diff --git a/src/eckit/geo/SphereT.h b/src/eckit/geo/SphereT.h index 17d3ff74c..cbd2f13cb 100644 --- a/src/eckit/geo/SphereT.h +++ b/src/eckit/geo/SphereT.h @@ -62,8 +62,8 @@ struct SphereT { } // Great-circle intermediate longitude(s) provided two circle points and intermediate latitude in degrees - inline static void greatCircleLongitudeGivenLatitude( - const PointLonLat& A, const PointLonLat& B, double lat, double& lon1, double& lon2) { + inline static void greatCircleLongitudeGivenLatitude(const PointLonLat& A, const PointLonLat& B, double lat, + double& lon1, double& lon2) { return Sphere::greatCircleLongitudeGivenLatitude(A, B, lat, lon1, lon2); } diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 8d4cf3cd3..c5164c544 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -69,12 +69,10 @@ BoundingBox* BoundingBox::make_from_spec(const Spec& spec) { } -BoundingBox::BoundingBox(const Spec& spec) : - BoundingBox(*std::unique_ptr(make_from_spec(spec))) {} +BoundingBox::BoundingBox(const Spec& spec) : BoundingBox(*std::unique_ptr(make_from_spec(spec))) {} -BoundingBox::BoundingBox(double n, double w, double s, double e) : - array{n, w, s, e} { +BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s, e} { ASSERT_MSG(types::is_approximately_lesser_or_equal(-90., south), "BoundingBox: latitude range (-90 <= south)"); ASSERT_MSG(types::is_approximately_lesser_or_equal(south, north), "BoundingBox: latitude range (south <= north)"); ASSERT_MSG(types::is_approximately_lesser_or_equal(north, 90.), "BoundingBox: latitude range (north <= 90)"); @@ -90,22 +88,22 @@ BoundingBox::BoundingBox(double n, double w, double s, double e) : } -BoundingBox::BoundingBox() : - BoundingBox(GLOBE_PRIME) {} +BoundingBox::BoundingBox() : BoundingBox(GLOBE_PRIME) {} bool BoundingBox::operator==(const BoundingBox& other) const { - return types::is_approximately_equal(north, other.north, PointLonLat::EPS) && - types::is_approximately_equal(south, other.south, PointLonLat::EPS) && - types::is_approximately_equal(west, other.west, PointLonLat::EPS) && - types::is_approximately_equal(east, other.east, PointLonLat::EPS); + return types::is_approximately_equal(north, other.north, PointLonLat::EPS) + && types::is_approximately_equal(south, other.south, PointLonLat::EPS) + && types::is_approximately_equal(west, other.west, PointLonLat::EPS) + && types::is_approximately_equal(east, other.east, PointLonLat::EPS); } bool BoundingBox::isPeriodicWestEast() const { - return west != east && - types::is_approximately_equal(west, PointLonLat::normalise_angle_to_minimum(east, west), PointLonLat::EPS); + return west != east + && types::is_approximately_equal(west, PointLonLat::normalise_angle_to_minimum(east, west), + PointLonLat::EPS); } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 4cead209a..d5dbc1ba7 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -39,11 +39,9 @@ class BoundingBox : public Area, protected std::array { BoundingBox(); - BoundingBox(const BoundingBox& other) : - array(other) {} + BoundingBox(const BoundingBox& other) : array(other) {} - BoundingBox(BoundingBox&& other) : - array(other) {} + BoundingBox(BoundingBox&& other) : array(other) {} // -- Destructor diff --git a/src/eckit/geo/figure/OblateSpheroid.cc b/src/eckit/geo/figure/OblateSpheroid.cc index d2618ddf8..ccac007ae 100644 --- a/src/eckit/geo/figure/OblateSpheroid.cc +++ b/src/eckit/geo/figure/OblateSpheroid.cc @@ -20,14 +20,12 @@ namespace eckit::geo::figure { -OblateSpheroid::OblateSpheroid(double a, double b) : - a_(a), b_(b) { +OblateSpheroid::OblateSpheroid(double a, double b) : a_(a), b_(b) { ASSERT_MSG(types::is_strictly_greater(b_, 0.) && b_ <= a_, "OblateSpheroid requires 0 < b <= a"); } -OblateSpheroid::OblateSpheroid(const Spec& spec) : - OblateSpheroid(spec.get_double("a"), spec.get_double("b")) {} +OblateSpheroid::OblateSpheroid(const Spec& spec) : OblateSpheroid(spec.get_double("a"), spec.get_double("b")) {} double OblateSpheroid::R() const { diff --git a/src/eckit/geo/figure/Sphere.cc b/src/eckit/geo/figure/Sphere.cc index 0e980287e..99f1eddd5 100644 --- a/src/eckit/geo/figure/Sphere.cc +++ b/src/eckit/geo/figure/Sphere.cc @@ -20,14 +20,12 @@ namespace eckit::geo::figure { -Sphere::Sphere(double R) : - R_(R) { +Sphere::Sphere(double R) : R_(R) { ASSERT_MSG(types::is_strictly_greater(R_, 0.), "Sphere requires R > 0"); } -Sphere::Sphere(const Spec& spec) : - Sphere(spec.get_double("R")) {} +Sphere::Sphere(const Spec& spec) : Sphere(spec.get_double("R")) {} } // namespace eckit::geo::figure diff --git a/src/eckit/geo/grid/Reduced.h b/src/eckit/geo/grid/Reduced.h index 12b78dfd0..b1c41faee 100644 --- a/src/eckit/geo/grid/Reduced.h +++ b/src/eckit/geo/grid/Reduced.h @@ -37,11 +37,9 @@ class Reduced : public Grid { protected: // -- Constructors - explicit Reduced(const Spec& spec) : - Grid(spec) {} + explicit Reduced(const Spec& spec) : Grid(spec) {} - explicit Reduced(const area::BoundingBox& bbox) : - Grid(bbox) {} + explicit Reduced(const area::BoundingBox& bbox) : Grid(bbox) {} // -- Methods diff --git a/src/eckit/geo/grid/ReducedLL.cc b/src/eckit/geo/grid/ReducedLL.cc index 173c49941..f98c2e7be 100644 --- a/src/eckit/geo/grid/ReducedLL.cc +++ b/src/eckit/geo/grid/ReducedLL.cc @@ -21,8 +21,7 @@ namespace eckit::geo::grid { -ReducedLL::ReducedLL(const Spec& spec) : - ReducedLL(spec.get_long_vector("pl"), area::BoundingBox(spec)) {} +ReducedLL::ReducedLL(const Spec& spec) : ReducedLL(spec.get_long_vector("pl"), area::BoundingBox(spec)) {} ReducedLL::ReducedLL(const pl_type& pl, const area::BoundingBox& bbox) : diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index c180938ae..2085ae72d 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -36,8 +36,7 @@ class Regular : public Grid { public: // -- Constructors - explicit Regular(const Spec& spec) : - Grid(spec) {} + explicit Regular(const Spec& spec) : Grid(spec) {} // -- Methods diff --git a/src/eckit/geo/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc index c66a0c8e4..c79846299 100644 --- a/src/eckit/geo/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -20,8 +20,7 @@ namespace eckit::geo::grid { -Unstructured::Unstructured(std::vector&& points) : - Grid(area::BoundingBox{}), points_(points) {} +Unstructured::Unstructured(std::vector&& points) : Grid(area::BoundingBox{}), points_(points) {} Grid::iterator Unstructured::cbegin() const { diff --git a/src/eckit/geo/iterator/Unstructured.cc b/src/eckit/geo/iterator/Unstructured.cc index f571714b5..70ab4c3be 100644 --- a/src/eckit/geo/iterator/Unstructured.cc +++ b/src/eckit/geo/iterator/Unstructured.cc @@ -40,8 +40,7 @@ struct LonLatReference : Unstructured::Container { struct PointsReference : Unstructured::Container { - explicit PointsReference(const std::vector& points) : - points(points) {} + explicit PointsReference(const std::vector& points) : points(points) {} Point get(size_t index) const override { return points.at(index); } size_t size() const override { return points.size(); } @@ -51,8 +50,7 @@ struct PointsReference : Unstructured::Container { struct PointsMove : Unstructured::Container { - explicit PointsMove(std::vector&& points) : - points(points) {} + explicit PointsMove(std::vector&& points) : points(points) {} Point get(size_t index) const override { return points.at(index); } size_t size() const override { return points.size(); } @@ -64,9 +62,7 @@ struct PointsMove : Unstructured::Container { } // namespace -Unstructured::Unstructured(const Grid& grid, - size_t index, - const std::vector& longitudes, +Unstructured::Unstructured(const Grid& grid, size_t index, const std::vector& longitudes, const std::vector& latitudes) : container_(new LonLatReference(longitudes, latitudes)), index_(index), size_(container_->size()), uid_(grid.uid()) { ASSERT(container_->size() == grid.size()); @@ -85,8 +81,7 @@ Unstructured::Unstructured(const Grid& grid, size_t index, std::vector&& } -Unstructured::Unstructured(const Grid& grid) : - index_(grid.size()), size_(grid.size()), uid_(grid.uid()) {} +Unstructured::Unstructured(const Grid& grid) : index_(grid.size()), size_(grid.size()), uid_(grid.uid()) {} bool Unstructured::operator==(const geo::Iterator& other) const { diff --git a/src/eckit/geo/iterator/Unstructured.h b/src/eckit/geo/iterator/Unstructured.h index ff1a9f790..b12a73992 100644 --- a/src/eckit/geo/iterator/Unstructured.h +++ b/src/eckit/geo/iterator/Unstructured.h @@ -44,9 +44,7 @@ class Unstructured final : public Iterator { // -- Constructors - explicit Unstructured(const Grid&, - size_t index, - const std::vector& longitudes, + explicit Unstructured(const Grid&, size_t index, const std::vector& longitudes, const std::vector& latitudes); explicit Unstructured(const Grid&, size_t index, const std::vector&); explicit Unstructured(const Grid&, size_t index, std::vector&&); diff --git a/src/eckit/geo/polygon/LonLatPolygon.cc b/src/eckit/geo/polygon/LonLatPolygon.cc index 102e326d9..533009d8c 100644 --- a/src/eckit/geo/polygon/LonLatPolygon.cc +++ b/src/eckit/geo/polygon/LonLatPolygon.cc @@ -61,11 +61,10 @@ inline Point2 componentsMax(const Point2& A, const Point2& B) { //---------------------------------------------------------------------------------------------------------------------- -LonLatPolygon::LonLatPolygon(const std::vector& points, bool includePoles) : - container_type(points) { +LonLatPolygon::LonLatPolygon(const std::vector& points, bool includePoles) : container_type(points) { ASSERT(points.size() > 1); - ASSERT(is_approximately_equal(points.front()[LON], points.back()[LON]) && - is_approximately_equal(points.front()[LAT], points.back()[LAT])); + ASSERT(is_approximately_equal(points.front()[LON], points.back()[LON]) + && is_approximately_equal(points.front()[LAT], points.back()[LAT])); if (points.size() > 2) { clear(); // assumes reserved size is kept @@ -132,13 +131,13 @@ bool LonLatPolygon::contains(const Point2& Plonlat, bool normalise_angle) const } // check bounding box - if (!is_approximately_greater_or_equal(Q[LAT], min_[LAT]) || - !is_approximately_greater_or_equal(max_[LAT], Q[LAT])) { + if (!is_approximately_greater_or_equal(Q[LAT], min_[LAT]) + || !is_approximately_greater_or_equal(max_[LAT], Q[LAT])) { return false; } if (quickCheckLongitude_) { - if (!is_approximately_greater_or_equal(Q[LON], min_[LON]) || - !is_approximately_greater_or_equal(max_[LON], Q[LON])) { + if (!is_approximately_greater_or_equal(Q[LON], min_[LON]) + || !is_approximately_greater_or_equal(max_[LON], Q[LON])) { return false; } } diff --git a/src/eckit/geo/polygon/Polygon.h b/src/eckit/geo/polygon/Polygon.h index 4664be43e..d3fa50b39 100644 --- a/src/eckit/geo/polygon/Polygon.h +++ b/src/eckit/geo/polygon/Polygon.h @@ -28,8 +28,7 @@ class Polygon : protected std::deque { Polygon() = default; - Polygon(std::initializer_list l) : - container_type(l) {} + Polygon(std::initializer_list l) : container_type(l) {} using container_type::push_back; using container_type::push_front; diff --git a/src/eckit/geo/range/GaussianLatitude.cc b/src/eckit/geo/range/GaussianLatitude.cc index 2386b90ba..7951617b8 100644 --- a/src/eckit/geo/range/GaussianLatitude.cc +++ b/src/eckit/geo/range/GaussianLatitude.cc @@ -41,8 +41,8 @@ Range* GaussianLatitude::flip() const { Range* GaussianLatitude::crop(double crop_a, double crop_b) const { - ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || - (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); + ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) + || (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); auto v = values(); diff --git a/src/eckit/geo/range/Regular.cc b/src/eckit/geo/range/Regular.cc index 932c1ec13..bd909ac07 100644 --- a/src/eckit/geo/range/Regular.cc +++ b/src/eckit/geo/range/Regular.cc @@ -24,8 +24,7 @@ namespace eckit::geo::range { -Regular::Regular(double _inc, double _a, double _b, double _ref, double eps) : - Range(2, _a, _b, eps), periodic_(false) { +Regular::Regular(double _inc, double _a, double _b, double _ref, double eps) : Range(2, _a, _b, eps), periodic_(false) { ASSERT(0. <= _inc); Fraction inc(_inc); diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h index b6d6d8f0c..36e4c4728 100644 --- a/src/eckit/geo/range/Regular.h +++ b/src/eckit/geo/range/Regular.h @@ -33,8 +33,7 @@ class Regular : public Range { Regular(double inc, double a, double b, double ref, double eps); - Regular(size_t n, double a, double b, bool periodic, double eps) : - Range(n, a, b, eps), periodic_(periodic) {} + Regular(size_t n, double a, double b, bool periodic, double eps) : Range(n, a, b, eps), periodic_(periodic) {} Regular(size_t n, double a, double b, std::vector&& values, bool periodic, double eps) : Range(n, a, b, eps), values_(values), periodic_(periodic) {} diff --git a/src/eckit/geo/range/RegularCartesian.cc b/src/eckit/geo/range/RegularCartesian.cc index 64cfd9af6..136df3c6e 100644 --- a/src/eckit/geo/range/RegularCartesian.cc +++ b/src/eckit/geo/range/RegularCartesian.cc @@ -36,8 +36,8 @@ static Fraction regular_adjust(const Fraction& target, const Fraction& inc, bool Range* RegularCartesian::crop(double crop_a, double crop_b) const { - ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || - (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); + ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) + || (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); if (types::is_approximately_equal(crop_a, crop_b, eps())) { NOTIMP; // FIXME diff --git a/src/eckit/geo/range/RegularCartesian.h b/src/eckit/geo/range/RegularCartesian.h index f55403034..dccef9049 100644 --- a/src/eckit/geo/range/RegularCartesian.h +++ b/src/eckit/geo/range/RegularCartesian.h @@ -24,8 +24,7 @@ class RegularCartesian final : public Regular { using Regular::Regular; - RegularCartesian(size_t n, double a, double b, double eps = 0.) : - Regular(n, a, b, false, eps) {} + RegularCartesian(size_t n, double a, double b, double eps = 0.) : Regular(n, a, b, false, eps) {} // -- Overridden methods diff --git a/src/eckit/geo/range/RegularLatitude.cc b/src/eckit/geo/range/RegularLatitude.cc index 4890962c8..fbeaac942 100644 --- a/src/eckit/geo/range/RegularLatitude.cc +++ b/src/eckit/geo/range/RegularLatitude.cc @@ -24,16 +24,15 @@ RegularLatitude::RegularLatitude(double _inc, double _a, double _b, double _ref, Regular(_inc, _a, _b, _ref, _eps) {} -RegularLatitude::RegularLatitude(size_t n, double _a, double _b, double _eps) : - Regular(n, _a, _b, false, _eps) { +RegularLatitude::RegularLatitude(size_t n, double _a, double _b, double _eps) : Regular(n, _a, _b, false, _eps) { ASSERT(-90. <= a() && a() <= 90.); ASSERT(-90. <= b() && b() <= 90.); } Range* RegularLatitude::crop(double crop_a, double crop_b) const { - ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || - (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); + ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) + || (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); if (types::is_approximately_equal(crop_a, crop_b, eps())) { NOTIMP; // FIXME diff --git a/src/eckit/geo/range/RegularLongitude.h b/src/eckit/geo/range/RegularLongitude.h index 2bf97b079..184968675 100644 --- a/src/eckit/geo/range/RegularLongitude.h +++ b/src/eckit/geo/range/RegularLongitude.h @@ -25,8 +25,7 @@ class RegularLongitude final : public Regular { // -- Constructors explicit RegularLongitude(double inc, double a, double b, double ref, double eps = 0.); - explicit RegularLongitude(double inc, double a, double b, double eps = 0.) : - RegularLongitude(inc, a, b, a, eps) {} + explicit RegularLongitude(double inc, double a, double b, double eps = 0.) : RegularLongitude(inc, a, b, a, eps) {} explicit RegularLongitude(size_t n, double a, double b, double eps = 0.); diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 1fa7ce09a..46c7a2ca6 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -31,25 +31,12 @@ class Custom final : public Spec { struct key_type : std::string { key_type(const std::string&); - key_type(const char* s) : - key_type(std::string{s}) {}; + key_type(const char* s) : key_type(std::string{s}) {}; }; - using value_type = std::variant, - std::vector, - std::vector, - std::vector, - std::vector, - std::vector, - std::vector>; + using value_type = std::variant, + std::vector, std::vector, std::vector, std::vector, + std::vector, std::vector>; using container_type = std::map; diff --git a/src/eckit/geo/spec/Generator.h b/src/eckit/geo/spec/Generator.h index 038c8a389..f99ab1eea 100644 --- a/src/eckit/geo/spec/Generator.h +++ b/src/eckit/geo/spec/Generator.h @@ -140,9 +140,8 @@ bool GeneratorT::exists(const key_t& k) const { template bool GeneratorT::matches(const std::string& k) const { lock_type lock; - return std::any_of(store_.begin(), store_.end(), [&](const auto& p) -> bool { - return std::regex_match(k, std::regex(p.first)); - }); + return std::any_of(store_.begin(), store_.end(), + [&](const auto& p) -> bool { return std::regex_match(k, std::regex(p.first)); }); } template @@ -286,8 +285,7 @@ class ConcreteSpecGeneratorT0 final : public SpecGeneratorT0 { public: // -- Constructors - explicit ConcreteSpecGeneratorT0(const SpecGeneratorT0::key_t& k) : - key_(k) { + explicit ConcreteSpecGeneratorT0(const SpecGeneratorT0::key_t& k) : key_(k) { GeneratorT::instance().regist(key_, this); } @@ -320,8 +318,7 @@ class ConcreteSpecGeneratorT1 final : public SpecGeneratorT1 { public: // -- Constructors - explicit ConcreteSpecGeneratorT1(const typename SpecGeneratorT1::key_t& k) : - key_(k) { + explicit ConcreteSpecGeneratorT1(const typename SpecGeneratorT1::key_t& k) : key_(k) { GeneratorT>::instance().regist(key_, this); } @@ -354,8 +351,7 @@ class ConcreteSpecGeneratorT2 final : public SpecGeneratorT2 { public: // -- Constructors - explicit ConcreteSpecGeneratorT2(const typename SpecGeneratorT2::key_t& k) : - key_(k) { + explicit ConcreteSpecGeneratorT2(const typename SpecGeneratorT2::key_t& k) : key_(k) { GeneratorT>::instance().regist(key_, this); } diff --git a/src/eckit/geo/spec/Layered.cc b/src/eckit/geo/spec/Layered.cc index 4fc9afb9d..c31b05c5b 100644 --- a/src/eckit/geo/spec/Layered.cc +++ b/src/eckit/geo/spec/Layered.cc @@ -22,12 +22,10 @@ namespace eckit::geo::spec { static const Custom EMPTY; -Layered::Layered() : - Layered(EMPTY) {} +Layered::Layered() : Layered(EMPTY) {} -Layered::Layered(const Spec& spec) : - spec_(spec) {} +Layered::Layered(const Spec& spec) : spec_(spec) {} void Layered::hide(const std::string& name) { diff --git a/src/eckit/geo/util/gaussian_latitudes.cc b/src/eckit/geo/util/gaussian_latitudes.cc index cebdfee0e..c51f4e19d 100644 --- a/src/eckit/geo/util/gaussian_latitudes.cc +++ b/src/eckit/geo/util/gaussian_latitudes.cc @@ -51,8 +51,8 @@ const std::vector& gaussian_latitudes(size_t N, bool increasing) { } for (size_t j = 2; j <= i - (i % 2); j += 2) { - zfn[i - j] = zfn[i - j + 2] * static_cast((j - 1) * (2 * i - j + 2)) / - static_cast(j * (2 * i - j + 1)); + zfn[i - j] = zfn[i - j + 2] * static_cast((j - 1) * (2 * i - j + 2)) + / static_cast(j * (2 * i - j + 1)); } } @@ -94,8 +94,8 @@ const std::vector& gaussian_latitudes(size_t N, bool increasing) { } if (!converged) { - throw BadValue("Could not calculate latitude within accuracy/iterations: " + std::to_string(eps) + "/" + - std::to_string(Nmax)); + throw BadValue("Could not calculate latitude within accuracy/iterations: " + std::to_string(eps) + "/" + + std::to_string(Nmax)); } // Convert colatitude [rad] to latitude [degree], symmetry diff --git a/src/eckit/geo/util/linspace.cc b/src/eckit/geo/util/linspace.cc index 16fdabe51..5f8948a67 100644 --- a/src/eckit/geo/util/linspace.cc +++ b/src/eckit/geo/util/linspace.cc @@ -25,9 +25,8 @@ std::vector linspace(double start, double stop, size_t num, bool endpoin const auto step = num > 1 ? (stop - start) / static_cast(endpoint ? (num - 1) : num) : 0; std::vector l(num); - std::generate_n(l.begin(), num, [start, step, n = 0ULL]() mutable { - return start + static_cast(n++) * step; - }); + std::generate_n(l.begin(), num, + [start, step, n = 0ULL]() mutable { return start + static_cast(n++) * step; }); return l; } diff --git a/src/eckit/geo/util/monotonic_crop.cc b/src/eckit/geo/util/monotonic_crop.cc index d45995424..a6f30c5d3 100644 --- a/src/eckit/geo/util/monotonic_crop.cc +++ b/src/eckit/geo/util/monotonic_crop.cc @@ -26,9 +26,7 @@ namespace eckit::geo::util { using difference_type = std::make_signed_t; -std::pair monotonic_crop(const std::vector& values, - double min, - double max, +std::pair monotonic_crop(const std::vector& values, double min, double max, double eps) { if (values.empty() || min > max) { return {}; @@ -42,9 +40,8 @@ std::pair monotonic_crop(const std::vector Date: Thu, 9 May 2024 14:37:02 +0100 Subject: [PATCH 608/737] Documentation --- src/eckit/geo/Figure.h | 3 +++ src/eckit/geo/range/Regular.h | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index d4852fcd9..31f05b571 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -26,6 +26,9 @@ class Spec; namespace eckit::geo { +/** + * @brief Figure: describe a combination of "shape" (sphere, ellipsoid, geoid) and "size" (radius, a, b, elevation) + */ class Figure { public: // -- Types diff --git a/src/eckit/geo/range/Regular.h b/src/eckit/geo/range/Regular.h index 36e4c4728..a43532ba4 100644 --- a/src/eckit/geo/range/Regular.h +++ b/src/eckit/geo/range/Regular.h @@ -31,6 +31,15 @@ class Regular : public Range { protected: // -- Constructors + /** + * @brief Regular + * @param inc regular increment + * @param a range start + * @param b range end + * @param ref User-defined coordinate reachable with (multiples of) integer increment; Can be defined out of the [a, + * b] range. Support both "shifted" and "non-shifted" ranges, for the same definition of [a, b] range and increment + * @param eps tolerace to check range start/end against + */ Regular(double inc, double a, double b, double ref, double eps); Regular(size_t n, double a, double b, bool periodic, double eps) : Range(n, a, b, eps), periodic_(periodic) {} From 7c4d717ebd61ba4fea4ac254e73c81ece1c66947 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 14:37:46 +0100 Subject: [PATCH 609/737] eckit::geo::Point (PointLonLat, Point2, Point3) immutability --- src/eckit/geo/Point2.cc | 10 +++---- src/eckit/geo/Point2.h | 47 +++++++++++++----------------- src/eckit/geo/Point3.cc | 12 ++++---- src/eckit/geo/Point3.h | 45 +++++++++++++--------------- src/eckit/geo/PointLonLat.cc | 14 ++++----- src/eckit/geo/PointLonLat.h | 30 +++++++++---------- src/eckit/geo/area/BoundingBox.cc | 10 +++---- src/eckit/geo/area/BoundingBox.h | 3 +- src/eckit/geo/util/bounding_box.cc | 22 +++++++------- 9 files changed, 89 insertions(+), 104 deletions(-) diff --git a/src/eckit/geo/Point2.cc b/src/eckit/geo/Point2.cc index f3b375b3a..ce0a4f7f8 100644 --- a/src/eckit/geo/Point2.cc +++ b/src/eckit/geo/Point2.cc @@ -22,7 +22,7 @@ namespace eckit::geo { static const Point2 ZERO; -double Point2::norm() const { +Point2::value_type Point2::norm() const { return distance(ZERO); } @@ -38,22 +38,22 @@ Point2 Point2::middle(const Point2& p) const { } -double Point2::distance(const Point2& p, size_t axis) const { +Point2::value_type Point2::distance(const Point2& p, size_t axis) const { return std::abs(x(axis) - p.x(axis)); } -double Point2::distance(const Point2& p) const { +Point2::value_type Point2::distance(const Point2& p) const { return std::sqrt(distance2(p)); } -double Point2::distance2(const Point2& p) const { +Point2::value_type Point2::distance2(const Point2& p) const { return (X - p.X) * (X - p.X) + (Y - p.Y) * (Y - p.Y); } -bool points_equal(const Point2& a, const Point2& b, double eps) { +bool points_equal(const Point2& a, const Point2& b, Point2::value_type eps) { return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps); } diff --git a/src/eckit/geo/Point2.h b/src/eckit/geo/Point2.h index 1becef155..466443749 100644 --- a/src/eckit/geo/Point2.h +++ b/src/eckit/geo/Point2.h @@ -19,26 +19,21 @@ namespace eckit::geo { class Point2 final : protected std::array { -private: +public: // -- Types - using container_type = std::array; + using container_type = array; using container_type::value_type; -public: // -- Constructors - Point2() : - Point2(0., 0.) {} + Point2() : Point2(0., 0.) {} - Point2(double x, double y) : - container_type{x, y} {} + Point2(value_type x, value_type y) : container_type{x, y} {} - Point2(const Point2& other) : - container_type(other) {} + Point2(const Point2& other) : container_type(other) {} - Point2(Point2&& other) : - container_type(other) {} + Point2(Point2&& other) : container_type(other) {} // -- Destructor @@ -60,33 +55,33 @@ class Point2 final : protected std::array { // -- Members - double& X = container_type::operator[](0); - double& Y = container_type::operator[](1); + const value_type& X = container_type::operator[](0); + const value_type& Y = container_type::operator[](1); // -- Methods static size_t dimensions() { return DIMS; } - static double norm(const Point2& p) { return p.norm(); } + static value_type norm(const Point2& p) { return p.norm(); } static Point2 normalize(const Point2& p) { return p.normalize(); } static Point2 middle(const Point2& p, const Point2& q) { return p.middle(q); } - static double distance(const Point2& p, const Point2& q, size_t axis) { return p.distance(q, axis); } - static double distance(const Point2& p, const Point2& q) { return p.distance(q); } - static double distance2(const Point2& p, const Point2& q) { return p.distance2(q); } + static value_type distance(const Point2& p, const Point2& q, size_t axis) { return p.distance(q, axis); } + static value_type distance(const Point2& p, const Point2& q) { return p.distance(q); } + static value_type distance2(const Point2& p, const Point2& q) { return p.distance2(q); } - double norm() const; + value_type norm() const; Point2 normalize() const; Point2 middle(const Point2&) const; - double distance(const Point2&, size_t axis) const; - double distance(const Point2&) const; - double distance2(const Point2&) const; + value_type distance(const Point2&, size_t axis) const; + value_type distance(const Point2&) const; + value_type distance2(const Point2&) const; - double x(size_t axis) const { return container_type::operator[](axis); } + value_type x(size_t axis) const { return container_type::operator[](axis); } // -- Class members - static constexpr size_t DIMS = 2; - static constexpr double EPS = 1e-9; + static constexpr size_t DIMS = 2; + static constexpr value_type EPS = 1e-9; // -- Friends @@ -96,14 +91,14 @@ class Point2 final : protected std::array { friend Point2 operator-(const Point2& p, const Point2& q) { return {p.X - q.X, p.Y - q.Y}; } friend Point2 operator+(const Point2& p, const Point2& q) { return {p.X + q.X, p.Y + q.Y}; } - friend Point2 operator*(const Point2& p, double d) { return {p.X * d, p.Y * d}; } + friend Point2 operator*(const Point2& p, value_type d) { return {p.X * d, p.Y * d}; } friend bool operator==(const Point2& p, const Point2& q) { return p.X == q.X && p.Y == q.Y; } friend bool operator!=(const Point2& p, const Point2& q) { return !operator==(p, q); } }; -bool points_equal(const Point2&, const Point2&, double eps = Point2::EPS); +bool points_equal(const Point2&, const Point2&, Point2::value_type eps = Point2::EPS); } // namespace eckit::geo diff --git a/src/eckit/geo/Point3.cc b/src/eckit/geo/Point3.cc index c33f69475..037b76d9c 100644 --- a/src/eckit/geo/Point3.cc +++ b/src/eckit/geo/Point3.cc @@ -19,24 +19,24 @@ namespace eckit::geo { -double Point3::distance(const Point3& p, size_t axis) const { +Point3::value_type Point3::distance(const Point3& p, size_t axis) const { return std::abs(x(axis) - p.x(axis)); } -double Point3::distance(const Point3& p) const { +Point3::value_type Point3::distance(const Point3& p) const { return std::sqrt(distance2(p)); } -double Point3::distance2(const Point3& p) const { +Point3::value_type Point3::distance2(const Point3& p) const { return (X - p.X) * (X - p.X) + (Y - p.Y) * (Y - p.Y) + (Z - p.Z) * (Z - p.Z); } -bool points_equal(const Point3& a, const Point3& b, double eps) { - return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps) && - types::is_approximately_equal(a.Z, b.Z, eps); +bool points_equal(const Point3& a, const Point3& b, Point3::value_type eps) { + return types::is_approximately_equal(a.X, b.X, eps) && types::is_approximately_equal(a.Y, b.Y, eps) + && types::is_approximately_equal(a.Z, b.Z, eps); } diff --git a/src/eckit/geo/Point3.h b/src/eckit/geo/Point3.h index ebeb3d965..4db3871c5 100644 --- a/src/eckit/geo/Point3.h +++ b/src/eckit/geo/Point3.h @@ -19,26 +19,21 @@ namespace eckit::geo { class Point3 final : protected std::array { -private: +public: // -- Types - using container_type = std::array; + using container_type = array; using container_type::value_type; -public: // -- Constructors - Point3() : - Point3(0., 0., 0.) {} + Point3() : Point3(0., 0., 0.) {} - Point3(double x, double y, double z) : - container_type{x, y, z} {} + Point3(value_type x, value_type y, value_type z) : container_type{x, y, z} {} - Point3(const Point3& other) : - container_type(other) {} + Point3(const Point3& other) : container_type(other) {} - Point3(Point3&& other) : - container_type(other) {} + Point3(Point3&& other) : container_type(other) {} // -- Destructor @@ -60,26 +55,26 @@ class Point3 final : protected std::array { // -- Members - double& X = container_type::operator[](0); - double& Y = container_type::operator[](1); - double& Z = container_type::operator[](2); + const value_type& X = container_type::operator[](0); + const value_type& Y = container_type::operator[](1); + const value_type& Z = container_type::operator[](2); // -- Methods - static double distance(const Point3& p, const Point3& q, size_t axis) { return p.distance(q, axis); } - static double distance(const Point3& p, const Point3& q) { return p.distance(q); } - static double distance2(const Point3& p, const Point3& q) { return p.distance2(q); } + static value_type distance(const Point3& p, const Point3& q, size_t axis) { return p.distance(q, axis); } + static value_type distance(const Point3& p, const Point3& q) { return p.distance(q); } + static value_type distance2(const Point3& p, const Point3& q) { return p.distance2(q); } - double distance(const Point3&, size_t axis) const; - double distance(const Point3&) const; - double distance2(const Point3&) const; + value_type distance(const Point3&, size_t axis) const; + value_type distance(const Point3&) const; + value_type distance2(const Point3&) const; - double x(size_t axis) const { return container_type::operator[](axis); } + value_type x(size_t axis) const { return container_type::operator[](axis); } // -- Class members - static constexpr size_t DIMS = 3; - static constexpr double EPS = 1e-9; + static constexpr size_t DIMS = 3; + static constexpr value_type EPS = 1e-9; // -- Friends @@ -89,14 +84,14 @@ class Point3 final : protected std::array { friend Point3 operator-(const Point3& p, const Point3& q) { return {p.X - q.X, p.Y - q.Y, p.Z - q.Z}; } friend Point3 operator+(const Point3& p, const Point3& q) { return {p.X + q.X, p.Y + q.Y, p.Z + q.Z}; } - friend Point3 operator*(const Point3& p, double d) { return {p.X * d, p.Y * d, p.Z * d}; } + friend Point3 operator*(const Point3& p, value_type d) { return {p.X * d, p.Y * d, p.Z * d}; } friend bool operator==(const Point3& p, const Point3& q) { return p.X == q.X && p.Y == q.Y && p.Z == q.Z; } friend bool operator!=(const Point3& p, const Point3& q) { return !operator==(p, q); } }; -bool points_equal(const Point3&, const Point3&, double eps = Point3::EPS); +bool points_equal(const Point3&, const Point3&, Point3::value_type eps = Point3::EPS); } // namespace eckit::geo diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index 3ca7f83c0..53842f5c0 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -23,16 +23,16 @@ namespace eckit::geo { -double PointLonLat::normalise_angle_to_minimum(double a, double minimum) { - auto modulo_360 = [](double a) { return a - 360. * std::floor(a / 360.); }; +PointLonLat::value_type PointLonLat::normalise_angle_to_minimum(value_type a, value_type minimum) { + auto modulo_360 = [](auto a) { return a - 360. * std::floor(a / 360.); }; auto diff = a - minimum; return 0. <= diff && diff < 360. ? a : modulo_360(diff) + minimum; } -double PointLonLat::normalise_angle_to_maximum(double a, double maximum) { - auto modulo_360 = [](double a) { return a - 360. * std::ceil(a / 360.); }; +PointLonLat::value_type PointLonLat::normalise_angle_to_maximum(value_type a, value_type maximum) { + auto modulo_360 = [](auto a) { return a - 360. * std::ceil(a / 360.); }; auto diff = a - maximum; return -360. < diff && diff <= 0. ? a : modulo_360(a - maximum) + maximum; @@ -42,14 +42,14 @@ double PointLonLat::normalise_angle_to_maximum(double a, double maximum) { void PointLonLat::assert_latitude_range(const PointLonLat& P) { if (!(-90. <= P.lat && P.lat <= 90.)) { std::ostringstream oss; - oss.precision(std::numeric_limits::max_digits10); + oss.precision(std::numeric_limits::max_digits10); oss << "Invalid latitude " << P.lat; throw BadValue(oss.str(), Here()); } } -PointLonLat PointLonLat::make(double lon, double lat, double lon_minimum, double eps) { +PointLonLat PointLonLat::make(value_type lon, value_type lat, value_type lon_minimum, value_type eps) { lat = normalise_angle_to_minimum(lat, -90.); if (types::is_strictly_greater(lat, 90., eps)) { @@ -64,7 +64,7 @@ PointLonLat PointLonLat::make(double lon, double lat, double lon_minimum, double } -bool points_equal(const PointLonLat& a, const PointLonLat& b, double eps) { +bool points_equal(const PointLonLat& a, const PointLonLat& b, PointLonLat::value_type eps) { auto c = PointLonLat::make(a.lon, a.lat, 0., eps); auto d = PointLonLat::make(b.lon, b.lat, 0., eps); return types::is_approximately_equal(c.lon, d.lon, eps) && types::is_approximately_equal(c.lat, d.lat, eps); diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index 2357281c5..db266da0c 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -21,23 +21,19 @@ namespace eckit::geo { class PointLonLat final : protected std::array { -private: +public: // -- Types - using container_type = std::array; + using container_type = array; using container_type::value_type; -public: // -- Constructors - PointLonLat(double lon, double lat) : - container_type{lon, lat} {} + PointLonLat(value_type lon, value_type lat) : container_type{lon, lat} {} - PointLonLat(const PointLonLat& other) : - container_type(other) {} + PointLonLat(const PointLonLat& other) : container_type(other) {} - PointLonLat(PointLonLat&& other) : - container_type(other) {} + PointLonLat(PointLonLat&& other) : container_type(other) {} // -- Destructor @@ -57,24 +53,24 @@ class PointLonLat final : protected std::array { // -- Members - value_type& lon = container_type::operator[](0); - value_type& lat = container_type::operator[](1); + const value_type& lon = container_type::operator[](0); + const value_type& lat = container_type::operator[](1); // -- Methods - static double normalise_angle_to_minimum(double, double minimum); + static value_type normalise_angle_to_minimum(value_type, value_type minimum); - static double normalise_angle_to_maximum(double, double maximum); + static value_type normalise_angle_to_maximum(value_type, value_type maximum); static void assert_latitude_range(const PointLonLat&); - static PointLonLat make(double lon, double lat, double lon_minimum = 0, double eps = EPS); + static PointLonLat make(value_type lon, value_type lat, value_type lon_minimum = 0, value_type eps = EPS); PointLonLat antipode() const { return make(lon, lat + 180.); } // -- Class members - static constexpr double EPS = 1e-9; + static constexpr value_type EPS = 1e-9; // -- Class methods @@ -94,7 +90,7 @@ class PointLonLat final : protected std::array { friend PointLonLat operator-(const PointLonLat& p, const PointLonLat& q) { return {p.lon - q.lon, p.lat - q.lat}; } friend PointLonLat operator+(const PointLonLat& p, const PointLonLat& q) { return {p.lon + q.lon, p.lat + q.lat}; } - friend PointLonLat operator*(const PointLonLat& p, double d) { return {p.lon * d, p.lat * d}; } + friend PointLonLat operator*(const PointLonLat& p, value_type d) { return {p.lon * d, p.lat * d}; } friend bool operator<(const PointLonLat& p, const PointLonLat& q) { return static_cast(p) < static_cast(q); @@ -102,7 +98,7 @@ class PointLonLat final : protected std::array { }; -bool points_equal(const PointLonLat&, const PointLonLat&, double eps = PointLonLat::EPS); +bool points_equal(const PointLonLat&, const PointLonLat&, PointLonLat::value_type eps = PointLonLat::EPS); } // namespace eckit::geo diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index c5164c544..bc86197ff 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -119,14 +119,14 @@ bool BoundingBox::containsSouthPole() const { } -bool BoundingBox::contains(double lat, double lon) const { - return lat <= north && lat >= south && PointLonLat::normalise_angle_to_minimum(lon, west) <= east; +bool BoundingBox::contains(const PointLonLat& p) const { + return p.lat <= north && p.lat >= south && PointLonLat::normalise_angle_to_minimum(p.lon, west) <= east; } bool BoundingBox::contains(const BoundingBox& other) const { if (other.empty()) { - return contains(other.south, other.west); + return contains({other.south, other.west}); } // check for West/East range (if non-periodic), then other's corners @@ -134,8 +134,8 @@ bool BoundingBox::contains(const BoundingBox& other) const { return false; } - return contains(other.north, other.west) && contains(other.north, other.east) && - contains(other.south, other.west) && contains(other.south, other.east); + return contains({other.north, other.west}) && contains({other.north, other.east}) + && contains({other.south, other.west}) && contains({other.south, other.east}); } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index d5dbc1ba7..683fbae3a 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -16,6 +16,7 @@ #include #include "eckit/geo/Area.h" +#include "eckit/geo/Point.h" namespace eckit::geo { @@ -75,7 +76,7 @@ class BoundingBox : public Area, protected std::array { bool intersects(BoundingBox&) const; - bool contains(double lat, double lon) const; + bool contains(const PointLonLat&) const; bool contains(const BoundingBox&) const; bool empty() const; double area(double radius) const; diff --git a/src/eckit/geo/util/bounding_box.cc b/src/eckit/geo/util/bounding_box.cc index fcc0725fc..eb5388c0d 100644 --- a/src/eckit/geo/util/bounding_box.cc +++ b/src/eckit/geo/util/bounding_box.cc @@ -27,14 +27,16 @@ namespace eckit::geo::util { -void longitude_in_range(double reference, double& lon) { +PointLonLat longitude_in_range(double reference, const PointLonLat& p) { // keep longitude difference (to reference) range below +-180 degree + auto lon = p.lon; while (lon > reference + 180.) { lon -= 360.; } while (lon <= reference - 180.) { lon += 360.; } + return {lon, p.lat}; } @@ -52,9 +54,8 @@ struct BoundLonLat { max_ = first_ ? add : PointLonLat::componentsMax(max_, add); first_ = false; - min_.lat = std::max(min_.lat, -90.); - max_.lat = std::min(max_.lat, 90.); - max_.lon = std::min(max_.lon, min_.lon + 360.); + min_ = {min_.lon, std::max(min_.lat, -90.)}; + max_ = {std::min(max_.lon, min_.lon + 360.), std::min(max_.lat, 90.)}; ASSERT(min_.lon <= max_.lon && min_.lat <= max_.lat); includesSouthPole(types::is_approximately_equal(min_.lat, -90.)); @@ -64,14 +65,14 @@ struct BoundLonLat { bool crossesDateLine(bool yes) { if ((crossesDateLine_ = crossesDateLine_ || yes)) { - max_.lon = min_.lon + 360.; + max_ = {min_.lon + 360., max_.lat}; } return crossesDateLine_; } bool includesNorthPole(bool yes) { if ((includesNorthPole_ = includesNorthPole_ || yes)) { - max_.lat = 90.; + max_ = {max_.lon, 90.}; } crossesDateLine(includesNorthPole_); return includesNorthPole_; @@ -79,7 +80,7 @@ struct BoundLonLat { bool includesSouthPole(bool yes) { if ((includesSouthPole_ = includesSouthPole_ || yes)) { - min_.lat = -90.; + min_ = {min_.lon, -90.}; } crossesDateLine(includesSouthPole_); return includesSouthPole_; @@ -113,9 +114,7 @@ struct Derivate { virtual PointLonLat d(Point2) const = 0; PointLonLat f(const Point2& p) const { - auto q = std::get(projection_.inv(p)); - longitude_in_range(refLongitude_, q.lon); - return q; + return longitude_in_range(refLongitude_, std::get(projection_.inv(p))); } inline const Point2& H() const { return H_; } @@ -217,8 +216,7 @@ area::BoundingBox bounding_box(Point2 min, Point2 max, Projection& projection) { BoundLonLat bounds(centre_ll, centre_ll); for (const auto& [A, dummy] : segments) { - auto q = std::get(projection.inv(A)); - longitude_in_range(centre_lon, q.lon); + auto q = longitude_in_range(centre_lon, std::get(projection.inv(A))); bounds.extend(q, PointLonLat{h_ll, h_ll}); } From 859ac2c81b8c013ca67167ad7462d30fc1159de9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 14:50:02 +0100 Subject: [PATCH 610/737] eckit::geo::PointLonLat refactor --- src/eckit/geo/Point.h | 13 ------------- src/eckit/geo/PointLonLat.cc | 28 ++++++++++++++-------------- src/eckit/geo/PointLonLat.h | 12 ++++++++++-- src/eckit/geo/area/BoundingBox.cc | 9 ++++----- 4 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/eckit/geo/Point.h b/src/eckit/geo/Point.h index 3745a7721..227d32d1a 100644 --- a/src/eckit/geo/Point.h +++ b/src/eckit/geo/Point.h @@ -31,17 +31,4 @@ bool points_equal(const Point&, const Point&, double eps); std::ostream& operator<<(std::ostream&, const Point&); -constexpr double GLOBE = 360.; -constexpr double GREENWICH = 0.; -constexpr double ANTIMERIDIAN = -180.; -constexpr double EQUATOR = 0.; -constexpr double NORTH_POLE = 90.; -constexpr double SOUTH_POLE = -90.; - - -// FIXME remove -using Longitude = double; -using Latitude = double; - - } // namespace eckit::geo diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index 53842f5c0..bc2360a3e 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -24,23 +24,23 @@ namespace eckit::geo { PointLonLat::value_type PointLonLat::normalise_angle_to_minimum(value_type a, value_type minimum) { - auto modulo_360 = [](auto a) { return a - 360. * std::floor(a / 360.); }; + static const auto modulo_globe = [](auto a) { return a - GLOBE * std::floor(a / GLOBE); }; auto diff = a - minimum; - return 0. <= diff && diff < 360. ? a : modulo_360(diff) + minimum; + return 0. <= diff && diff < GLOBE ? a : modulo_globe(diff) + minimum; } PointLonLat::value_type PointLonLat::normalise_angle_to_maximum(value_type a, value_type maximum) { - auto modulo_360 = [](auto a) { return a - 360. * std::ceil(a / 360.); }; + auto modulo_360 = [](auto a) { return a - GLOBE * std::ceil(a / GLOBE); }; auto diff = a - maximum; - return -360. < diff && diff <= 0. ? a : modulo_360(a - maximum) + maximum; + return -GLOBE < diff && diff <= 0. ? a : modulo_360(a - maximum) + maximum; } void PointLonLat::assert_latitude_range(const PointLonLat& P) { - if (!(-90. <= P.lat && P.lat <= 90.)) { + if (!(SOUTH_POLE <= P.lat && P.lat <= NORTH_POLE)) { std::ostringstream oss; oss.precision(std::numeric_limits::max_digits10); oss << "Invalid latitude " << P.lat; @@ -50,23 +50,23 @@ void PointLonLat::assert_latitude_range(const PointLonLat& P) { PointLonLat PointLonLat::make(value_type lon, value_type lat, value_type lon_minimum, value_type eps) { - lat = normalise_angle_to_minimum(lat, -90.); + lat = normalise_angle_to_minimum(lat, SOUTH_POLE); - if (types::is_strictly_greater(lat, 90., eps)) { - lat = 180. - lat; - lon += 180.; + if (types::is_strictly_greater(lat, NORTH_POLE, eps)) { + lat = GLOBE / 2. - lat; + lon += GLOBE / 2.; } - return types::is_approximately_equal(lat, 90., eps) ? PointLonLat{0., 90.} - : types::is_approximately_equal(lat, -90., eps) - ? PointLonLat{0., -90.} + return types::is_approximately_equal(lat, NORTH_POLE, eps) ? PointLonLat{0., NORTH_POLE} + : types::is_approximately_equal(lat, SOUTH_POLE, eps) + ? PointLonLat{EQUATOR, SOUTH_POLE} : PointLonLat{normalise_angle_to_minimum(lon, lon_minimum), lat}; } bool points_equal(const PointLonLat& a, const PointLonLat& b, PointLonLat::value_type eps) { - auto c = PointLonLat::make(a.lon, a.lat, 0., eps); - auto d = PointLonLat::make(b.lon, b.lat, 0., eps); + const auto c = PointLonLat::make(a.lon, a.lat, PointLonLat::EQUATOR, eps); + const auto d = PointLonLat::make(b.lon, b.lat, PointLonLat::EQUATOR, eps); return types::is_approximately_equal(c.lon, d.lon, eps) && types::is_approximately_equal(c.lat, d.lat, eps); } diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index db266da0c..351939ee7 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -22,6 +22,14 @@ namespace eckit::geo { class PointLonLat final : protected std::array { public: + // FIXME move into PointLonLat + static constexpr double GLOBE = 360.; + static constexpr double GREENWICH = 0.; + static constexpr double ANTIMERIDIAN = -180.; + static constexpr double EQUATOR = 0.; + static constexpr double NORTH_POLE = 90.; + static constexpr double SOUTH_POLE = -90.; + // -- Types using container_type = array; @@ -64,9 +72,9 @@ class PointLonLat final : protected std::array { static void assert_latitude_range(const PointLonLat&); - static PointLonLat make(value_type lon, value_type lat, value_type lon_minimum = 0, value_type eps = EPS); + static PointLonLat make(value_type lon, value_type lat, value_type lon_minimum = EQUATOR, value_type eps = EPS); - PointLonLat antipode() const { return make(lon, lat + 180.); } + PointLonLat antipode() const { return make(lon, lat + GLOBE / 2.); } // -- Class members diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index bc86197ff..11d8084aa 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -100,7 +100,6 @@ bool BoundingBox::operator==(const BoundingBox& other) const { bool BoundingBox::isPeriodicWestEast() const { - return west != east && types::is_approximately_equal(west, PointLonLat::normalise_angle_to_minimum(east, west), PointLonLat::EPS); @@ -108,14 +107,14 @@ bool BoundingBox::isPeriodicWestEast() const { bool BoundingBox::containsNorthPole() const { - static const auto NORTH_POLE = PointLonLat::make(0., 90.); - return points_equal({0., north}, NORTH_POLE); + static const auto POLE = PointLonLat::make(PointLonLat::EQUATOR, PointLonLat::NORTH_POLE); + return points_equal({PointLonLat::EQUATOR, north}, POLE); } bool BoundingBox::containsSouthPole() const { - static const auto SOUTH_POLE = PointLonLat::make(0., -90.); - return points_equal({0., south}, SOUTH_POLE); + static const auto POLE = PointLonLat::make(PointLonLat::EQUATOR, PointLonLat::SOUTH_POLE); + return points_equal({PointLonLat::EQUATOR, south}, POLE); } From 0dca50c6c86f2251c118be9243147f72183da98d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 15:10:03 +0100 Subject: [PATCH 611/737] CMakeLists.txt avoid file(GLOB...) --- etc/eckit/geo/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/etc/eckit/geo/CMakeLists.txt b/etc/eckit/geo/CMakeLists.txt index c4b764e98..cb36257fe 100644 --- a/etc/eckit/geo/CMakeLists.txt +++ b/etc/eckit/geo/CMakeLists.txt @@ -1,4 +1,7 @@ -file(GLOB _files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.yaml") +set(_files) +list(APPEND _files "grid.yaml") +list(APPEND _files "ORCA.yaml") + set(_destination "etc/eckit/geo") install(FILES ${_files} DESTINATION ${_destination} PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ) From 1d482d53b3ff98467f535af4ef51b7e48c17de43 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 15:11:23 +0100 Subject: [PATCH 612/737] eckit::geo::Figure::area, eckit::geo::area::BoundingBox::area --- src/eckit/geo/Figure.cc | 5 +++++ src/eckit/geo/Figure.h | 8 +++++++- src/eckit/geo/area/BoundingBox.cc | 16 +++------------- src/eckit/geo/area/BoundingBox.h | 7 +++++-- src/eckit/geo/figure/Sphere.cc | 18 ++++++++++++++++++ src/eckit/geo/figure/Sphere.h | 1 + 6 files changed, 39 insertions(+), 16 deletions(-) diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc index b5a7748e8..9487634e4 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/geo/Figure.cc @@ -35,6 +35,11 @@ double Figure::b() const { } +double Figure::area(const area::BoundingBox&) const { + throw NotImplemented("Figure::area", Here()); +} + + double Figure::eccentricity() const { return std::sqrt(1. - (b() * b()) / (a() * a())); } diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index 31f05b571..b557fc9f0 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -19,8 +19,11 @@ namespace eckit::geo { -class Spec; +namespace area { +class BoundingBox; } +class Spec; +} // namespace eckit::geo namespace eckit::geo { @@ -67,6 +70,9 @@ class Figure { virtual double a() const; virtual double b() const; + /// @brief Calculate the bounding box prescribed area ([[R]**2]) + virtual double area(const area::BoundingBox&) const; + double eccentricity() const; // -- Overridden methods diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 11d8084aa..a7eea6090 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -13,15 +13,14 @@ #include "eckit/geo/area/BoundingBox.h" #include -#include #include #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Figure.h" #include "eckit/geo/PointLonLat.h" #include "eckit/geo/Sphere.h" #include "eckit/geo/spec/Custom.h" -#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -191,17 +190,8 @@ bool BoundingBox::empty() const { } -double BoundingBox::area(double radius) const { - double lonf = isPeriodicWestEast() ? 1. : ((east - west) / 360.); - ASSERT(0. <= lonf && lonf <= 1.); - - const auto sn = std::sin(north * util::DEGREE_TO_RADIAN); - const auto ss = std::sin(south * util::DEGREE_TO_RADIAN); - - double latf = 0.5 * (sn - ss); - ASSERT(0. <= latf && latf <= 1.); - - return Sphere::area(radius) * latf * lonf; +double BoundingBox::area(const Figure& figure) const { + return figure.area(*this); } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 683fbae3a..96911cdd7 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -20,8 +20,9 @@ namespace eckit::geo { +class Figure; class Projection; -} +} // namespace eckit::geo namespace eckit::geo::area { @@ -79,7 +80,9 @@ class BoundingBox : public Area, protected std::array { bool contains(const PointLonLat&) const; bool contains(const BoundingBox&) const; bool empty() const; - double area(double radius) const; + + /// @brief Calculate the bounding box prescribed area ([[R]**2]) + double area(const Figure&) const; // -- Overridden methods diff --git a/src/eckit/geo/figure/Sphere.cc b/src/eckit/geo/figure/Sphere.cc index 99f1eddd5..75d7ff02c 100644 --- a/src/eckit/geo/figure/Sphere.cc +++ b/src/eckit/geo/figure/Sphere.cc @@ -12,8 +12,12 @@ #include "eckit/geo/figure/Sphere.h" +#include + #include "eckit/exception/Exceptions.h" #include "eckit/geo/Spec.h" +#include "eckit/geo/area/BoundingBox.h" +#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -28,4 +32,18 @@ Sphere::Sphere(double R) : R_(R) { Sphere::Sphere(const Spec& spec) : Sphere(spec.get_double("R")) {} +double Sphere::area(const area::BoundingBox& bbox) const { + auto lonf = bbox.isPeriodicWestEast() ? 1. : ((bbox.east - bbox.west) / PointLonLat::GLOBE); + ASSERT(0. <= lonf && lonf <= 1.); + + const auto sn = std::sin(bbox.north * util::DEGREE_TO_RADIAN); + const auto ss = std::sin(bbox.south * util::DEGREE_TO_RADIAN); + + auto latf = 0.5 * (sn - ss); + ASSERT(0. <= latf && latf <= 1.); + + return 4. * M_PI * R_ * R_ * latf * lonf; +} + + } // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/Sphere.h b/src/eckit/geo/figure/Sphere.h index fee30bfb6..2eff12081 100644 --- a/src/eckit/geo/figure/Sphere.h +++ b/src/eckit/geo/figure/Sphere.h @@ -49,6 +49,7 @@ class Sphere final : public Figure { double a() const override { return R_; } double b() const override { return R_; } + double area(const area::BoundingBox&) const override; // -- Class members // None From 4f9e3a048df354b053c1161abb27f61682dd22a0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 15:13:10 +0100 Subject: [PATCH 613/737] throw NotImplemented replaced by NOTIMP; --- src/eckit/geo/Area.cc | 2 +- src/eckit/geo/Figure.cc | 8 ++++---- src/eckit/geo/Grid.cc | 20 ++++++++++---------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/eckit/geo/Area.cc b/src/eckit/geo/Area.cc index 612352723..742452b4b 100644 --- a/src/eckit/geo/Area.cc +++ b/src/eckit/geo/Area.cc @@ -19,7 +19,7 @@ namespace eckit::geo { void Area::spec(spec::Custom&) const { - throw NotImplemented("Area::spec"); + NOTIMP; } diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc index 9487634e4..86a7fc36f 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/geo/Figure.cc @@ -21,22 +21,22 @@ namespace eckit::geo { double Figure::R() const { - throw NotImplemented("Figure::R", Here()); + NOTIMP; } double Figure::a() const { - throw NotImplemented("Figure::a", Here()); + NOTIMP; } double Figure::b() const { - throw NotImplemented("Figure::b", Here()); + NOTIMP; } double Figure::area(const area::BoundingBox&) const { - throw NotImplemented("Figure::area", Here()); + NOTIMP; } diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 3e62f47ba..473e89e1e 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -51,7 +51,7 @@ std::string Grid::spec() const { size_t Grid::size() const { - throw NotImplemented("Grid::size", Here()); + NOTIMP; } @@ -61,17 +61,17 @@ Grid::uid_t Grid::uid() const { bool Grid::includesNorthPole() const { - throw NotImplemented("Grid::includesNorthPole", Here()); + NOTIMP; } bool Grid::includesSouthPole() const { - throw NotImplemented("Grid::includesSouthPole", Here()); + NOTIMP; } bool Grid::isPeriodicWestEast() const { - throw NotImplemented("Grid::isPeriodicWestEast", Here()); + NOTIMP; } @@ -101,17 +101,17 @@ std::pair, std::vector > Grid::to_latlon() const { Ordering Grid::order() const { - throw NotImplemented("Grid::order"); + NOTIMP; } Renumber Grid::reorder(Ordering) const { - throw NotImplemented("Grid::reorder"); + NOTIMP; } Grid* Grid::make_grid_reordered(Ordering) const { - throw NotImplemented("Grid::make_grid_reordered"); + NOTIMP; } @@ -121,12 +121,12 @@ Area* Grid::area() const { Renumber Grid::crop(const Area&) const { - throw NotImplemented("Grid::crop"); + NOTIMP; } Grid* Grid::make_grid_cropped(const Area&) const { - throw NotImplemented("Grid::make_grid_cropped"); + NOTIMP; } @@ -157,7 +157,7 @@ Renumber Grid::no_reorder(size_t size) { void Grid::spec(spec::Custom&) const { - throw NotImplemented("Grid::spec"); + NOTIMP; } From 57d2952ae2e0b64453b74186b1a2ff3a67ad682f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 15:26:13 +0100 Subject: [PATCH 614/737] eckit:Exception use Here() --- src/eckit/geo/Grid.cc | 2 +- src/eckit/geo/Increments.cc | 4 ++-- src/eckit/geo/Shape.cc | 4 ++-- src/eckit/geo/Spec.cc | 6 +++--- src/eckit/geo/Spec.h | 2 +- src/eckit/geo/grid/ORCA.cc | 4 ++-- src/eckit/geo/grid/ReducedGaussian.cc | 2 +- src/eckit/geo/grid/Regular.cc | 2 +- src/eckit/geo/projection/Mercator.cc | 2 +- src/eckit/geo/spec/Custom.cc | 4 ++-- src/eckit/geo/spec/Generator.h | 5 +++-- src/eckit/geo/util/bounding_box.cc | 2 +- src/eckit/geo/util/gaussian_latitudes.cc | 3 ++- src/eckit/geo/util/reduced_classical_pl.cc | 2 +- 14 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 473e89e1e..a292fab74 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -183,7 +183,7 @@ const Grid* GridFactory::make_from_spec_(const Spec& spec) const { } list(Log::error() << "Grid: cannot build grid without 'type', choices are: "); - throw SpecNotFound("Grid: cannot build grid without 'type'"); + throw SpecNotFound("Grid: cannot build grid without 'type'", Here()); } diff --git a/src/eckit/geo/Increments.cc b/src/eckit/geo/Increments.cc index 94dd79c0c..a33a0b767 100644 --- a/src/eckit/geo/Increments.cc +++ b/src/eckit/geo/Increments.cc @@ -28,7 +28,7 @@ Increments Increments::make_from_spec(const Spec& spec) { y = value[1]; } else if (!spec.get("dx", x) || !spec.get("dy", y)) { - throw SpecNotFound("'increments' = ['dx', 'dy'] expected"); + throw SpecNotFound("'increments' = ['dx', 'dy'] expected", Here()); } return {x, y}; @@ -37,7 +37,7 @@ Increments Increments::make_from_spec(const Spec& spec) { Increments::Increments(value_type dx, value_type dy) : array{dx, dy} { if (!(dx != 0) || !(dy != 0)) { - throw BadValue("'shape' = ['dx', 'dy'] != 0 expected"); + throw BadValue("'shape' = ['dx', 'dy'] != 0 expected", Here()); } } diff --git a/src/eckit/geo/Shape.cc b/src/eckit/geo/Shape.cc index 2f403c00d..70ab10bbe 100644 --- a/src/eckit/geo/Shape.cc +++ b/src/eckit/geo/Shape.cc @@ -27,7 +27,7 @@ Shape Shape::make_from_spec(const Spec& spec) { y = value[1]; } else if (!spec.get("nx", x) || !spec.get("ny", y)) { - throw SpecNotFound("'shape' = ['nx', 'ny'] expected"); + throw SpecNotFound("'shape' = ['nx', 'ny'] expected", Here()); } return {x, y}; @@ -36,7 +36,7 @@ Shape Shape::make_from_spec(const Spec& spec) { Shape::Shape(value_type nx, value_type ny) : array{nx, ny} { if (!(nx > 0) || !(ny > 0)) { - throw BadValue("'shape' = ['nx', 'ny'] > 0 expected"); + throw BadValue("'shape' = ['nx', 'ny'] > 0 expected", Here()); } } diff --git a/src/eckit/geo/Spec.cc b/src/eckit/geo/Spec.cc index df32f1e5f..f12d3d707 100644 --- a/src/eckit/geo/Spec.cc +++ b/src/eckit/geo/Spec.cc @@ -30,13 +30,13 @@ static T _get_d(const Spec& spec, const std::string& name, const T& _default) { template static T _get_t(const Spec& spec, const std::string& name) { T value{}; - return spec.get(name, value) ? value : throw SpecNotFound(name); + return spec.get(name, value) ? value : throw SpecNotFound(name, Here()); } -SpecNotFound::SpecNotFound(const std::string& name) { +SpecNotFound::SpecNotFound(const std::string& name, const CodeLocation& loc) : Exception(loc) { std::ostringstream s; - s << "SpecNotFound: [" << name << "]"; + s << "SpecNotFound: [" << name << "], in " << loc; reason(s.str()); } diff --git a/src/eckit/geo/Spec.h b/src/eckit/geo/Spec.h index aa022ff8f..ef52b6562 100644 --- a/src/eckit/geo/Spec.h +++ b/src/eckit/geo/Spec.h @@ -27,7 +27,7 @@ namespace eckit::geo { class SpecNotFound : public Exception { public: - explicit SpecNotFound(const std::string&); + explicit SpecNotFound(const std::string&, const CodeLocation&); }; diff --git a/src/eckit/geo/grid/ORCA.cc b/src/eckit/geo/grid/ORCA.cc index 6774b2e89..0301f70ae 100644 --- a/src/eckit/geo/grid/ORCA.cc +++ b/src/eckit/geo/grid/ORCA.cc @@ -102,7 +102,7 @@ PathName orca_path(const PathName& path, const std::string& url) { tmp.unlink(true); } - throw UserError("ORCA: download error"); + throw UserError("ORCA: download error", Here()); } PathName::rename(tmp, path); @@ -218,7 +218,7 @@ void ORCA::ORCARecord::read(const PathName& p) { return; } - throw SeriousBug("ORCA::read: unsupported version"); + throw SeriousBug("ORCA::read: unsupported version", Here()); } diff --git a/src/eckit/geo/grid/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc index d97e524f3..d57f999c3 100644 --- a/src/eckit/geo/grid/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -128,7 +128,7 @@ Grid* ReducedGaussian::make_grid_cropped(const area::BoundingBox& crop) const { return new ReducedGaussian(pl_, bbox); } - throw Exception("ReducedGaussian: cannot crop grid (empty intersection)"); + throw UserError("ReducedGaussian: cannot crop grid (empty intersection)", Here()); } diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index 71d164faa..c0bf32a66 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -147,7 +147,7 @@ Grid* RegularGaussian::make_grid_cropped(const area::BoundingBox& crop) const { return new RegularGaussian(N_, bbox); } - throw Exception("RegularGaussian: cannot crop grid (empty intersection)"); + throw UserError("RegularGaussian: cannot crop grid (empty intersection)", Here()); } diff --git a/src/eckit/geo/projection/Mercator.cc b/src/eckit/geo/projection/Mercator.cc index 74ab51959..95abe8d62 100644 --- a/src/eckit/geo/projection/Mercator.cc +++ b/src/eckit/geo/projection/Mercator.cc @@ -79,7 +79,7 @@ double Mercator::calculate_phi(double t) const { } } - throw SeriousBug("Mercator: phi calculation failed to converge"); + throw SeriousBug("Mercator: phi calculation failed to converge", Here()); } diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index b16489329..13dcc9183 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -159,7 +159,7 @@ Custom::Custom(const Value& value) { return value.isNumber() ? value_type(static_cast(value)) : value.isDouble() ? value_type(static_cast(value)) : value.isString() ? static_cast(value) - : throw BadValue(value); + : throw BadValue(value, Here()); }; auto vector = [](const Value& value) -> value_type { @@ -168,7 +168,7 @@ Custom::Custom(const Value& value) { return list.front().isNumber() ? value_type(std::vector(list.begin(), list.end())) : list.front().isDouble() ? value_type(std::vector(list.begin(), list.end())) : list.front().isString() ? std::vector(list.begin(), list.end()) - : throw BadValue(value); + : throw BadValue(value, Here()); }; ASSERT(value.isMap()); diff --git a/src/eckit/geo/spec/Generator.h b/src/eckit/geo/spec/Generator.h index f99ab1eea..795c231d6 100644 --- a/src/eckit/geo/spec/Generator.h +++ b/src/eckit/geo/spec/Generator.h @@ -74,7 +74,7 @@ class GeneratorT { for (auto j = store_.cbegin(); j != end; ++j) { if (!(j->first.empty()) && j->second->match(spec)) { if (i != end) { - throw SeriousBug("Generator matches names '" + i->first + "' and '" + j->first + "'"); + throw SeriousBug("Generator matches names '" + i->first + "' and '" + j->first + "'", Here()); } i = j; } @@ -182,7 +182,8 @@ const typename GeneratorT::generator_t& GeneratorT::match(const std::strin for (auto j = store_.cbegin(); j != end; ++j) { if (std::regex_match(k, std::regex(j->first))) { if (i != end) { - throw SeriousBug("Generator name '" + k + "' matches '" + i->first + "' and '" + j->first + "'"); + throw SeriousBug("Generator name '" + k + "' matches '" + i->first + "' and '" + j->first + "'", + Here()); } i = j; } diff --git a/src/eckit/geo/util/bounding_box.cc b/src/eckit/geo/util/bounding_box.cc index eb5388c0d..c4c835e41 100644 --- a/src/eckit/geo/util/bounding_box.cc +++ b/src/eckit/geo/util/bounding_box.cc @@ -164,7 +164,7 @@ struct DerivateFactory { return type == "forwards" ? static_cast(new DerivateForwards(p, A, B, h, refLongitude)) : type == "backwards" ? static_cast(new DerivateBackwards(p, A, B, h, refLongitude)) : type == "central" ? static_cast(new DerivateCentral(p, A, B, h, refLongitude)) - : throw; + : throw BadValue("DerivateFactory: unknown method", Here()); } static void list(std::ostream& out) { return instance().list_(out); } diff --git a/src/eckit/geo/util/gaussian_latitudes.cc b/src/eckit/geo/util/gaussian_latitudes.cc index c51f4e19d..09a565758 100644 --- a/src/eckit/geo/util/gaussian_latitudes.cc +++ b/src/eckit/geo/util/gaussian_latitudes.cc @@ -95,7 +95,8 @@ const std::vector& gaussian_latitudes(size_t N, bool increasing) { if (!converged) { throw BadValue("Could not calculate latitude within accuracy/iterations: " + std::to_string(eps) + "/" - + std::to_string(Nmax)); + + std::to_string(Nmax), + Here()); } // Convert colatitude [rad] to latitude [degree], symmetry diff --git a/src/eckit/geo/util/reduced_classical_pl.cc b/src/eckit/geo/util/reduced_classical_pl.cc index c43518488..c19a6cd7e 100644 --- a/src/eckit/geo/util/reduced_classical_pl.cc +++ b/src/eckit/geo/util/reduced_classical_pl.cc @@ -1347,7 +1347,7 @@ const pl_type& reduced_classical_pl(size_t N) { auto pl_half = CLASSICAL_PLS.find(N); if (pl_half == CLASSICAL_PLS.end()) { - throw BadValue("reduced_classical_pl: unknown N=" + std::to_string(N)); + throw BadValue("reduced_classical_pl: unknown N=" + std::to_string(N), Here()); } ASSERT(pl_half->second.size() == N); From 63791a1fd3bf6560b3627a283081d2489c6d8e51 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 15:36:00 +0100 Subject: [PATCH 615/737] Cleanup class descriptions with sections // None --- src/eckit/geo/Area.h | 50 -------------------------- src/eckit/geo/Figure.h | 50 -------------------------- src/eckit/geo/Grid.h | 30 ---------------- src/eckit/geo/Iterator.h | 49 ------------------------- src/eckit/geo/LibEcKitGeo.h | 42 ---------------------- src/eckit/geo/Projection.h | 50 -------------------------- src/eckit/geo/area/BoundingBox.h | 29 +++------------ src/eckit/geo/etc/Grid.h | 41 --------------------- src/eckit/geo/figure/OblateSpheroid.h | 40 --------------------- src/eckit/geo/figure/Sphere.h | 39 -------------------- src/eckit/geo/grid/HEALPix.h | 30 ---------------- src/eckit/geo/grid/ORCA.h | 27 -------------- src/eckit/geo/grid/ReducedGaussian.h | 36 ------------------- src/eckit/geo/grid/ReducedLL.h | 36 ------------------- src/eckit/geo/grid/Unstructured.h | 30 ---------------- src/eckit/geo/iterator/Reduced.h | 39 -------------------- src/eckit/geo/iterator/Regular.h | 39 -------------------- src/eckit/geo/iterator/Unstructured.h | 39 -------------------- src/eckit/geo/projection/LonLatToXY.h | 36 ------------------- src/eckit/geo/projection/LonLatToXYZ.h | 30 ---------------- src/eckit/geo/projection/Mercator.h | 27 -------------- src/eckit/geo/projection/None.h | 46 ------------------------ src/eckit/geo/projection/PROJ.h | 33 ----------------- src/eckit/geo/projection/Rotation.h | 30 ---------------- src/eckit/geo/projection/XYToLonLat.h | 36 ------------------- 25 files changed, 4 insertions(+), 930 deletions(-) diff --git a/src/eckit/geo/Area.h b/src/eckit/geo/Area.h index 3f76efc43..6d43cff32 100644 --- a/src/eckit/geo/Area.h +++ b/src/eckit/geo/Area.h @@ -36,9 +36,6 @@ class Area { using builder_t = BuilderT1; using ARG1 = const Spec&; - // -- Exceptions - // None - // -- Constructors Area() noexcept = default; @@ -49,9 +46,6 @@ class Area { virtual ~Area() = default; - // -- Convertors - // None - // -- Operators Area& operator=(const Area&) = default; @@ -62,50 +56,6 @@ class Area { static std::string className() { return "area"; } virtual void spec(spec::Custom&) const; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index b557fc9f0..bf8afe662 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -39,9 +39,6 @@ class Figure { using builder_t = BuilderT1
; using ARG1 = const Spec&; - // -- Exceptions - // None - // -- Constructors Figure() noexcept = default; @@ -54,9 +51,6 @@ class Figure { virtual ~Figure() = default; - // -- Convertors - // None - // -- Operators Figure& operator=(const Figure&) = default; @@ -74,50 +68,6 @@ class Figure { virtual double area(const area::BoundingBox&) const; double eccentricity() const; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 765d1ca6a..96be84bab 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -84,9 +84,6 @@ class Grid { using iterator = Iterator; - // -- Exceptions - // None - // -- Constructors explicit Grid(const Spec&); @@ -98,9 +95,6 @@ class Grid { virtual ~Grid() = default; - // -- Convertors - // None - // -- Operators Grid& operator=(const Grid&) = delete; @@ -138,12 +132,6 @@ class Grid { virtual Renumber crop(const area::BoundingBox&) const; virtual Grid* make_grid_cropped(const area::BoundingBox&) const; - // -- Overridden methods - // None - - // -- Class members - // None - // -- Class methods static std::string className() { return "grid"; } @@ -157,15 +145,6 @@ class Grid { static Renumber no_reorder(size_t size); - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members @@ -178,15 +157,6 @@ class Grid { virtual area::BoundingBox* calculate_bbox() const { return new area::BoundingBox{}; } - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - // -- Friends friend bool operator==(const Grid& a, const Grid& b) { return a.spec() == b.spec(); } diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index a075c8b15..4149db8aa 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -31,9 +31,6 @@ class Iterator { using difference_type = std::ptrdiff_t; - // -- Exceptions - // None - // -- Constructors Iterator(const Iterator&) = delete; @@ -43,9 +40,6 @@ class Iterator { virtual ~Iterator() = default; - // -- Convertors - // None - // -- Operators void operator=(const Iterator&) = delete; @@ -67,53 +61,10 @@ class Iterator { virtual size_t index() const = 0; - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - protected: // -- Constructors Iterator() = default; - - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/LibEcKitGeo.h b/src/eckit/geo/LibEcKitGeo.h index 1ee3897fa..4a8c73060 100644 --- a/src/eckit/geo/LibEcKitGeo.h +++ b/src/eckit/geo/LibEcKitGeo.h @@ -27,24 +27,6 @@ namespace eckit { class LibEcKitGeo final : public system::Library { public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - // None - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - // -- Methods static LibEcKitGeo& instance(); @@ -54,40 +36,16 @@ class LibEcKitGeo final : public system::Library { static bool caching(); static std::string cacheDir(); - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Constructors LibEcKitGeo(); - // -- Members - // None - - // -- Methods - // None - // -- Overridden methods const void* addr() const override; std::string version() const override; std::string gitsha1(unsigned int count) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 816c470c5..7b81386b6 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -37,9 +37,6 @@ class Projection { using builder_t = BuilderT1; using ARG1 = const Spec&; - // -- Exceptions - // None - // -- Constructors Projection() noexcept = default; @@ -50,9 +47,6 @@ class Projection { virtual ~Projection() = default; - // -- Convertors - // None - // -- Operators Projection& operator=(const Projection&) = default; @@ -66,50 +60,6 @@ class Projection { virtual Point inv(const Point&) const = 0; virtual Spec* spec() const = 0; - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -protected: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 96911cdd7..d33d9d9a6 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -30,9 +30,6 @@ namespace eckit::geo::area { class BoundingBox : public Area, protected std::array { public: - // -- Exceptions - // None - // -- Constructors explicit BoundingBox(const Spec&); @@ -49,9 +46,6 @@ class BoundingBox : public Area, protected std::array { ~BoundingBox() override = default; - // -- Convertors - // None - // -- Operators bool operator==(const BoundingBox&) const; @@ -88,9 +82,6 @@ class BoundingBox : public Area, protected std::array { void spec(spec::Custom&) const override; - // -- Class members - // None - // -- Class methods static BoundingBox calculate(const BoundingBox&, const Projection&); @@ -101,22 +92,10 @@ class BoundingBox : public Area, protected std::array { // -- Members - double& north = operator[](0); - double& west = operator[](1); - double& south = operator[](2); - double& east = operator[](3); - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None + const double& north = operator[](0); + const double& west = operator[](1); + const double& south = operator[](2); + const double& east = operator[](3); // -- Friends diff --git a/src/eckit/geo/etc/Grid.h b/src/eckit/geo/etc/Grid.h index acaf84e37..0bc4c7319 100644 --- a/src/eckit/geo/etc/Grid.h +++ b/src/eckit/geo/etc/Grid.h @@ -29,37 +29,8 @@ namespace eckit::geo::etc { class Grid final { public: - // -- Types - // None - - // -- Exceptions - // None - - // -- Constructors - // None - - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - static const Grid& instance(); - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Constructors @@ -72,18 +43,6 @@ class Grid final { // -- Methods void load(const PathName&); - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/figure/OblateSpheroid.h b/src/eckit/geo/figure/OblateSpheroid.h index 67be8f4fc..8876c37e1 100644 --- a/src/eckit/geo/figure/OblateSpheroid.h +++ b/src/eckit/geo/figure/OblateSpheroid.h @@ -20,62 +20,22 @@ namespace eckit::geo::figure { class OblateSpheroid final : public Figure { public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors OblateSpheroid(double a, double b); explicit OblateSpheroid(const Spec&); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - // -- Overridden methods double R() const override; double a() const override { return a_; } double b() const override { return b_; } - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members const double a_; const double b_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/figure/Sphere.h b/src/eckit/geo/figure/Sphere.h index 2eff12081..f5cdb39b2 100644 --- a/src/eckit/geo/figure/Sphere.h +++ b/src/eckit/geo/figure/Sphere.h @@ -20,29 +20,11 @@ namespace eckit::geo::figure { class Sphere final : public Figure { public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors explicit Sphere(double R); explicit Sphere(const Spec&); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - // -- Overridden methods double R() const override { return R_; } @@ -51,31 +33,10 @@ class Sphere final : public Figure { double area(const area::BoundingBox&) const override; - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members const double R_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/grid/HEALPix.h b/src/eckit/geo/grid/HEALPix.h index 8bc7da717..81921b33b 100644 --- a/src/eckit/geo/grid/HEALPix.h +++ b/src/eckit/geo/grid/HEALPix.h @@ -20,26 +20,11 @@ namespace eckit::geo::grid { class HEALPix final : public Reduced { public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors explicit HEALPix(const Spec&); explicit HEALPix(size_t Nside, Ordering = Ordering::healpix_ring); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - // -- Methods size_t Nside() const { return Nside_; } @@ -65,9 +50,6 @@ class HEALPix final : public Reduced { static Spec* spec(const std::string& name); - // -- Class methods - // None - private: // -- Members @@ -76,9 +58,6 @@ class HEALPix final : public Reduced { mutable std::vector latitudes_; - // -- Methods - // None - // -- Overridden methods bool includesNorthPole() const override { return true; } @@ -89,15 +68,6 @@ class HEALPix final : public Reduced { const std::vector& latitudes() const override; std::vector longitudes(size_t i) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/grid/ORCA.h b/src/eckit/geo/grid/ORCA.h index 7a33931a8..f4484f54e 100644 --- a/src/eckit/geo/grid/ORCA.h +++ b/src/eckit/geo/grid/ORCA.h @@ -63,23 +63,11 @@ class ORCA final : public Regular { std::vector flags_; }; - // -- Exceptions - // None - // -- Constructors explicit ORCA(const Spec&); explicit ORCA(uid_t); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - // -- Methods size_t nx() const override { return record_.nj(); } @@ -104,9 +92,6 @@ class ORCA final : public Regular { std::vector to_points() const override; std::pair, std::vector> to_latlon() const override; - // -- Class members - // None - // -- Class methods static Spec* spec(const std::string& name); @@ -119,21 +104,9 @@ class ORCA final : public Regular { Arrangement arrangement_; const ORCARecord& record_; - // -- Methods - // None - // -- Overridden methods void spec(spec::Custom&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/grid/ReducedGaussian.h b/src/eckit/geo/grid/ReducedGaussian.h index 6e8ec8b90..03ce86a97 100644 --- a/src/eckit/geo/grid/ReducedGaussian.h +++ b/src/eckit/geo/grid/ReducedGaussian.h @@ -25,30 +25,12 @@ namespace eckit::geo::grid { class ReducedGaussian : public Reduced { public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors explicit ReducedGaussian(const Spec&); explicit ReducedGaussian(const pl_type&, const area::BoundingBox& = {}); explicit ReducedGaussian(size_t N, const area::BoundingBox& = {}); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - // -- Overridden methods iterator cbegin() const override; @@ -58,12 +40,6 @@ class ReducedGaussian : public Reduced { size_t ni(size_t j) const override; size_t nj() const override; - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members @@ -75,9 +51,6 @@ class ReducedGaussian : public Reduced { std::vector> x_; std::unique_ptr y_; - // -- Methods - // None - // -- Overridden methods void spec(spec::Custom&) const override; @@ -86,15 +59,6 @@ class ReducedGaussian : public Reduced { std::vector longitudes(size_t i) const override; Grid* make_grid_cropped(const area::BoundingBox&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/grid/ReducedLL.h b/src/eckit/geo/grid/ReducedLL.h index 1643f0fc6..114e7d055 100644 --- a/src/eckit/geo/grid/ReducedLL.h +++ b/src/eckit/geo/grid/ReducedLL.h @@ -24,29 +24,11 @@ namespace eckit::geo::grid { class ReducedLL : public Reduced { public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors explicit ReducedLL(const Spec&); explicit ReducedLL(const pl_type&, const area::BoundingBox& = {}); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - // -- Overridden methods iterator cbegin() const override; @@ -55,12 +37,6 @@ class ReducedLL : public Reduced { size_t ni(size_t j) const override; size_t nj() const override; - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members @@ -69,24 +45,12 @@ class ReducedLL : public Reduced { std::unique_ptr x_; std::unique_ptr y_; - // -- Methods - // None - // -- Overridden methods const std::vector& latitudes() const override; std::vector longitudes(size_t j) const override; void spec(spec::Custom&) const override; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h index e7a04b1f0..52fd90c60 100644 --- a/src/eckit/geo/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -27,28 +27,10 @@ namespace eckit::geo::grid { class Unstructured final : public Grid { public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors explicit Unstructured(std::vector&&); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - // -- Overridden methods iterator cbegin() const override; @@ -63,9 +45,6 @@ class Unstructured final : public Grid { std::vector to_points() const override { return points_; } - // -- Class members - // None - // -- Class methods static Spec* spec(const std::string& name); @@ -75,19 +54,10 @@ class Unstructured final : public Grid { const std::vector points_; - // -- Methods - // None - // -- Overridden methods void spec(spec::Custom&) const override; - // -- Class members - // None - - // -- Class methods - // None - // -- Friends friend class geo::iterator::Unstructured; diff --git a/src/eckit/geo/iterator/Reduced.h b/src/eckit/geo/iterator/Reduced.h index b12851893..b886feaad 100644 --- a/src/eckit/geo/iterator/Reduced.h +++ b/src/eckit/geo/iterator/Reduced.h @@ -27,37 +27,10 @@ namespace eckit::geo::iterator { class Reduced final : public geo::Iterator { public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors explicit Reduced(const Grid&, size_t index = 0); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members @@ -69,9 +42,6 @@ class Reduced final : public geo::Iterator { size_t index_; const size_t size_; - // -- Methods - // None - // -- Overridden operators bool operator==(const Iterator&) const override; @@ -84,15 +54,6 @@ class Reduced final : public geo::Iterator { size_t index() const override { return index_; } size_t j(size_t idx) const; - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/iterator/Regular.h b/src/eckit/geo/iterator/Regular.h index 00dabc1bf..389b40662 100644 --- a/src/eckit/geo/iterator/Regular.h +++ b/src/eckit/geo/iterator/Regular.h @@ -30,37 +30,10 @@ namespace eckit::geo::iterator { class Regular final : public Iterator { public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors explicit Regular(const grid::Regular&, size_t index = 0); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members @@ -74,9 +47,6 @@ class Regular final : public Iterator { const size_t ny_; const size_t size_; - // -- Methods - // None - // -- Overridden methods bool operator==(const Iterator&) const override; @@ -86,15 +56,6 @@ class Regular final : public Iterator { Point operator*() const override; size_t index() const override { return index_; } - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/iterator/Unstructured.h b/src/eckit/geo/iterator/Unstructured.h index b12a73992..4636c8e34 100644 --- a/src/eckit/geo/iterator/Unstructured.h +++ b/src/eckit/geo/iterator/Unstructured.h @@ -39,9 +39,6 @@ class Unstructured final : public Iterator { virtual size_t size() const = 0; }; - // -- Exceptions - // None - // -- Constructors explicit Unstructured(const Grid&, size_t index, const std::vector& longitudes, @@ -51,30 +48,6 @@ class Unstructured final : public Iterator { explicit Unstructured(const Grid&); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - - // -- Overridden operators - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members @@ -83,9 +56,6 @@ class Unstructured final : public Iterator { const size_t size_; const std::string uid_; - // -- Methods - // None - // -- Overridden methods bool operator==(const geo::Iterator&) const override; @@ -96,15 +66,6 @@ class Unstructured final : public Iterator { Point operator*() const override; size_t index() const override { return index_; } - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/projection/LonLatToXY.h b/src/eckit/geo/projection/LonLatToXY.h index 8ebdb8fdd..efc7fd525 100644 --- a/src/eckit/geo/projection/LonLatToXY.h +++ b/src/eckit/geo/projection/LonLatToXY.h @@ -20,23 +20,11 @@ namespace eckit::geo::projection { class LonLatToXY final : public Projection { public: - // -- Exceptions - // None - // -- Constructors explicit LonLatToXY() = default; explicit LonLatToXY(const Spec&) {} - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - // -- Methods inline Point2 fwd(const PointLonLat& p) const { return {p.lon, p.lat}; } @@ -46,35 +34,11 @@ class LonLatToXY final : public Projection { Spec* spec() const override; - // -- Class members - // None - - // -- Class methods - // None - private: - // -- Types - // None - - // -- Members - // None - - // -- Methods - // None - // -- Overridden methods inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } inline Point inv(const Point& q) const override { return inv(std::get(q)); } - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/projection/LonLatToXYZ.h b/src/eckit/geo/projection/LonLatToXYZ.h index bb979acd6..fd15b6ed7 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.h +++ b/src/eckit/geo/projection/LonLatToXYZ.h @@ -23,24 +23,12 @@ namespace eckit::geo::projection { /// Calculate coordinates of a point on a sphere or spheroid, in [x, y, z] class LonLatToXYZ final : public Projection { public: - // -- Exceptions - // None - // -- Constructors LonLatToXYZ(double a, double b); explicit LonLatToXYZ(double R); explicit LonLatToXYZ(const Spec&); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - // -- Methods Point3 fwd(const PointLonLat& p) const { return (*impl_)(p); } @@ -50,12 +38,6 @@ class LonLatToXYZ final : public Projection { Spec* spec() const override; - // -- Class members - // None - - // -- Class methods - // None - private: // -- Types @@ -77,22 +59,10 @@ class LonLatToXYZ final : public Projection { std::unique_ptr impl_; - // -- Methods - // None - // -- Overridden methods Point fwd(const Point& p) const override { return (*impl_)(std::get(p)); } Point inv(const Point& q) const override { return (*impl_)(std::get(q)); } - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/projection/Mercator.h b/src/eckit/geo/projection/Mercator.h index 7f9bb2e9e..901ba0249 100644 --- a/src/eckit/geo/projection/Mercator.h +++ b/src/eckit/geo/projection/Mercator.h @@ -24,24 +24,12 @@ namespace eckit::geo::projection { /// Calculate coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle class Mercator final : public Projection { public: - // -- Exceptions - // None - // -- Constructors Mercator(double meridian, double parallel, Figure*, PointLonLat first = {0, 0}); explicit Mercator(const Spec&); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - // -- Methods Point2 fwd(const PointLonLat& p) const; @@ -51,12 +39,6 @@ class Mercator final : public Projection { Spec* spec() const override; - // -- Class members - // None - - // -- Class methods - // None - private: // -- Members @@ -84,15 +66,6 @@ class Mercator final : public Projection { Point fwd(const Point& p) const override { return fwd(std::get(p)); } Point inv(const Point& q) const override { return inv(std::get(q)); } - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index b96962b31..73a62e347 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -20,63 +20,17 @@ namespace eckit::geo::projection { class None final : public Projection { public: - // -- Types - // None - - // -- Exceptions - // None - // -- Constructors explicit None() = default; explicit None(const Spec&) {} - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - - // -- Methods - // None - // -- Overridden methods Spec* spec() const override; inline Point fwd(const Point& p) const override { return p; } inline Point inv(const Point& q) const override { return q; } - - // -- Class members - // None - - // -- Class methods - // None - -private: - // -- Types - // None - - // -- Members - // None - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index e7faf613a..def5c650f 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -23,23 +23,11 @@ namespace eckit::geo::projection { /// Calculate coordinates using PROJ class PROJ final : public Projection { public: - // -- Exceptions - // None - // -- Constructors PROJ(const std::string& source, const std::string& target, double lon_minimum = 0.); explicit PROJ(const Spec&); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - // -- Methods const std::string& source() const { return source_; } @@ -54,12 +42,6 @@ class PROJ final : public Projection { Spec* spec() const override; - // -- Class members - // None - - // -- Class methods - // None - private: // -- Types @@ -71,21 +53,6 @@ class PROJ final : public Projection { const std::string source_; const std::string target_; - - // -- Methods - // None - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index f67f100e6..09347704d 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -23,24 +23,12 @@ namespace eckit::geo::projection { /// Calculate coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle class Rotation final : public Projection { public: - // -- Exceptions - // None - // -- Constructors Rotation(); Rotation(double south_pole_lon, double south_pole_lat, double angle); explicit Rotation(const Spec&); - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - // -- Methods bool rotated() const { return rotated_; } @@ -51,12 +39,6 @@ class Rotation final : public Projection { Spec* spec() const override; - // -- Class members - // None - - // -- Class methods - // None - private: // -- Types @@ -79,22 +61,10 @@ class Rotation final : public Projection { std::unique_ptr inv_; bool rotated_; - // -- Methods - // None - // -- Overridden methods Point fwd(const Point& p) const override { return (*fwd_)(std::get(p)); } Point inv(const Point& q) const override { return (*inv_)(std::get(q)); } - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; diff --git a/src/eckit/geo/projection/XYToLonLat.h b/src/eckit/geo/projection/XYToLonLat.h index e9d436cb7..5c07d5571 100644 --- a/src/eckit/geo/projection/XYToLonLat.h +++ b/src/eckit/geo/projection/XYToLonLat.h @@ -20,23 +20,11 @@ namespace eckit::geo::projection { class XYToLonLat final : public Projection { public: - // -- Exceptions - // None - // -- Constructors explicit XYToLonLat() = default; explicit XYToLonLat(const Spec&) {} - // -- Destructor - // None - - // -- Convertors - // None - - // -- Operators - // None - // -- Methods inline PointLonLat fwd(const Point2& p) const { return {p.X, p.Y}; } @@ -46,35 +34,11 @@ class XYToLonLat final : public Projection { Spec* spec() const override; - // -- Class members - // None - - // -- Class methods - // None - private: - // -- Types - // None - - // -- Members - // None - - // -- Methods - // None - // -- Overridden methods inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } inline Point inv(const Point& q) const override { return inv(std::get(q)); } - - // -- Class members - // None - - // -- Class methods - // None - - // -- Friends - // None }; From e04de415d67fc6cc1c3256bffa0fcd8dd3f3076b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 16:20:44 +0100 Subject: [PATCH 616/737] eckit::geo::area::BoundingBox immutability --- src/eckit/geo/area/BoundingBox.cc | 2 +- tests/geo/area_boundingbox.cc | 6 +++--- tests/geo/grid_regular_gg.cc | 35 +++++++------------------------ 3 files changed, 12 insertions(+), 31 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index a7eea6090..35f297755 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -78,7 +78,7 @@ BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s if (!types::is_approximately_equal(west, east)) { auto e = PointLonLat::normalise_angle_to_minimum(east, west); - east = types::is_approximately_equal(e, west) ? (e + 360.) : e; + operator=({north, west, south, types::is_approximately_equal(e, west) ? (e + 360.) : e}); } ASSERT_MSG(types::is_approximately_lesser_or_equal(west, east), "BoundingBox: longitude range (west <= east)"); diff --git a/tests/geo/area_boundingbox.cc b/tests/geo/area_boundingbox.cc index 76c381c19..0148c4fb0 100644 --- a/tests/geo/area_boundingbox.cc +++ b/tests/geo/area_boundingbox.cc @@ -53,7 +53,7 @@ CASE("assignment") { EXPECT_EQUAL(a.north, b.north); EXPECT_EQUAL(a, b); - b.north = 30; + b = {30., b.west, b.south, b.east}; EXPECT_EQUAL(b.north, 30); EXPECT_EQUAL(a.north, 10); @@ -61,14 +61,14 @@ CASE("assignment") { EXPECT_EQUAL(a.north, c.north); EXPECT_EQUAL(a, c); - c.north = 40; + c = {40., c.west, c.south, c.east}; EXPECT_EQUAL(c.north, 40); EXPECT_EQUAL(a.north, 10); auto d(std::move(a)); EXPECT_EQUAL(d.north, 10); - d.north = 50; + d = {50., d.west, d.south, d.east}; EXPECT_EQUAL(d.north, 50); } diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index d31022232..fc9a37295 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -25,8 +25,7 @@ namespace eckit::geo::test { CASE("RegularGaussian") { SECTION("sizes") { struct test_t { - explicit test_t(size_t N) : - N(N), size(4 * N * 2 * N) {} + explicit test_t(size_t N) : N(N), size(4 * N * 2 * N) {} size_t N; size_t size; } tests[]{test_t{2}, test_t{3}, test_t{64}}; @@ -49,14 +48,8 @@ CASE("RegularGaussian") { grid::RegularGaussian grid(1); const std::vector ref{ - {0., 35.264389683}, - {90., 35.264389683}, - {180., 35.264389683}, - {270., 35.264389683}, - {0., -35.264389683}, - {90., -35.264389683}, - {180., -35.264389683}, - {270., -35.264389683}, + {0., 35.264389683}, {90., 35.264389683}, {180., 35.264389683}, {270., 35.264389683}, + {0., -35.264389683}, {90., -35.264389683}, {180., -35.264389683}, {270., -35.264389683}, }; auto points = grid.to_points(); @@ -103,7 +96,7 @@ CASE("RegularGaussian") { EXPECT(bbox3.isPeriodicWestEast()); - bbox3.east = 0.; + bbox3 = {bbox3.north, bbox3.west, bbox3.south, 0.}; EXPECT_NOT(bbox3.isPeriodicWestEast()); @@ -119,22 +112,10 @@ CASE("RegularGaussian") { EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj const std::vector ref{ - {-180., 59.444408289}, - {-135., 59.444408289}, - {-90., 59.444408289}, - {-45., 59.444408289}, - {-180., 19.875719147}, - {-135., 19.875719147}, - {-90., 19.875719147}, - {-45., 19.875719147}, - {-180., -19.875719147}, - {-135., -19.875719147}, - {-90., -19.875719147}, - {-45., -19.875719147}, - {-180., -59.444408289}, - {-135., -59.444408289}, - {-90., -59.444408289}, - {-45., -59.444408289}, + {-180., 59.444408289}, {-135., 59.444408289}, {-90., 59.444408289}, {-45., 59.444408289}, + {-180., 19.875719147}, {-135., 19.875719147}, {-90., 19.875719147}, {-45., 19.875719147}, + {-180., -19.875719147}, {-135., -19.875719147}, {-90., -19.875719147}, {-45., -19.875719147}, + {-180., -59.444408289}, {-135., -59.444408289}, {-90., -59.444408289}, {-45., -59.444408289}, }; auto points5 = grid5->to_points(); From 1cef5b2f7296786985874aa51359e5bf81cfb2dc Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 16:40:57 +0100 Subject: [PATCH 617/737] eckit::geo::Figure area refactor --- src/eckit/geo/Figure.cc | 5 +++++ src/eckit/geo/Figure.h | 3 +++ src/eckit/geo/figure/OblateSpheroid.cc | 13 +++++++++++++ src/eckit/geo/figure/OblateSpheroid.h | 2 ++ src/eckit/geo/figure/Sphere.cc | 7 ++++++- src/eckit/geo/figure/Sphere.h | 1 + 6 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc index 86a7fc36f..4e1df6c16 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/geo/Figure.cc @@ -35,6 +35,11 @@ double Figure::b() const { } +double Figure::area() const { + NOTIMP; +} + + double Figure::area(const area::BoundingBox&) const { NOTIMP; } diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index bf8afe662..04b4343be 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -64,6 +64,9 @@ class Figure { virtual double a() const; virtual double b() const; + /// @brief Calculate surface area ([[R]**2]) + virtual double area() const; + /// @brief Calculate the bounding box prescribed area ([[R]**2]) virtual double area(const area::BoundingBox&) const; diff --git a/src/eckit/geo/figure/OblateSpheroid.cc b/src/eckit/geo/figure/OblateSpheroid.cc index ccac007ae..d21ec335e 100644 --- a/src/eckit/geo/figure/OblateSpheroid.cc +++ b/src/eckit/geo/figure/OblateSpheroid.cc @@ -12,6 +12,8 @@ #include "eckit/geo/figure/OblateSpheroid.h" +#include + #include "eckit/exception/Exceptions.h" #include "eckit/geo/Spec.h" #include "eckit/types/FloatCompare.h" @@ -34,4 +36,15 @@ double OblateSpheroid::R() const { } +double OblateSpheroid::area() const { + auto e = eccentricity(); + if (types::is_approximately_equal(e, 1.)) { + return 2. * M_PI * a_ * a_; + } + + ASSERT(types::is_strictly_greater(e, 0.)); + return 2. * M_PI * a_ * a_ * (1. + (1 - e * e) / e * std::atan2(e, 1 - e * e)); +} + + } // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/OblateSpheroid.h b/src/eckit/geo/figure/OblateSpheroid.h index 8876c37e1..f3bdadc59 100644 --- a/src/eckit/geo/figure/OblateSpheroid.h +++ b/src/eckit/geo/figure/OblateSpheroid.h @@ -31,6 +31,8 @@ class OblateSpheroid final : public Figure { double a() const override { return a_; } double b() const override { return b_; } + double area() const override; + private: // -- Members diff --git a/src/eckit/geo/figure/Sphere.cc b/src/eckit/geo/figure/Sphere.cc index 75d7ff02c..5bd1aaaae 100644 --- a/src/eckit/geo/figure/Sphere.cc +++ b/src/eckit/geo/figure/Sphere.cc @@ -32,6 +32,11 @@ Sphere::Sphere(double R) : R_(R) { Sphere::Sphere(const Spec& spec) : Sphere(spec.get_double("R")) {} +double Sphere::area() const { + return 4. * M_PI * R_ * R_; +} + + double Sphere::area(const area::BoundingBox& bbox) const { auto lonf = bbox.isPeriodicWestEast() ? 1. : ((bbox.east - bbox.west) / PointLonLat::GLOBE); ASSERT(0. <= lonf && lonf <= 1.); @@ -42,7 +47,7 @@ double Sphere::area(const area::BoundingBox& bbox) const { auto latf = 0.5 * (sn - ss); ASSERT(0. <= latf && latf <= 1.); - return 4. * M_PI * R_ * R_ * latf * lonf; + return area() * latf * lonf; } diff --git a/src/eckit/geo/figure/Sphere.h b/src/eckit/geo/figure/Sphere.h index f5cdb39b2..109c7df0d 100644 --- a/src/eckit/geo/figure/Sphere.h +++ b/src/eckit/geo/figure/Sphere.h @@ -31,6 +31,7 @@ class Sphere final : public Figure { double a() const override { return R_; } double b() const override { return R_; } + double area() const override; double area(const area::BoundingBox&) const override; private: From 16556fb670534b7be0254989e7d8e31b65218161 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 16:44:38 +0100 Subject: [PATCH 618/737] tests/maths/CMakeLists.txt revert removal of convex hull test --- tests/maths/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/maths/CMakeLists.txt b/tests/maths/CMakeLists.txt index 329dbe54b..90a0b4de3 100644 --- a/tests/maths/CMakeLists.txt +++ b/tests/maths/CMakeLists.txt @@ -13,3 +13,10 @@ foreach( _test matrix matrix3 ) ) endforeach() +ecbuild_add_test( + TARGET eckit_test_maths_convex_hull + SOURCES test_convex_hull.cc + CONDITION HAVE_CONVEX_HULL + LIBS eckit_maths eckit +) + From 37725142463d6c46a373bab64ae07d3d9ae0c969 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 16:47:18 +0100 Subject: [PATCH 619/737] src/eckit/maths/CMakeLists.txt revert removal of convex hull interface sources, update to latest develop --- src/eckit/maths/CMakeLists.txt | 31 ++++++++------- src/eckit/maths/Matrix3.h | 70 ++++++++++++++-------------------- 2 files changed, 45 insertions(+), 56 deletions(-) diff --git a/src/eckit/maths/CMakeLists.txt b/src/eckit/maths/CMakeLists.txt index 560cad0fb..bc4cac86c 100644 --- a/src/eckit/maths/CMakeLists.txt +++ b/src/eckit/maths/CMakeLists.txt @@ -1,28 +1,31 @@ -list( APPEND eckit_maths_lib_srcs +list(APPEND eckit_maths_private_libs "${LAPACK_LIBRARIES}" "${BLAS_LIBRARIES}") +list(APPEND eckit_maths_sources Eigen.h Lapack.cc Lapack.h Matrix.h + Matrix3.h MatrixEigen.h MatrixLapack.h ) -if( eckit_HAVE_ECKIT_GEO ) - # for eckit::geo - list( APPEND eckit_maths_lib_srcs - Matrix3.h - ) +if(eckit_HAVE_CONVEX_HULL) + list(APPEND eckit_maths_sources ConvexHull.h ConvexHullN.h Qhull.cc Qhull.h) + list(APPEND eckit_maths_private_libs Qhull::Qhull) endif() -ecbuild_add_library( TARGET eckit_maths - TYPE SHARED - INSTALL_HEADERS ALL - HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/maths - SOURCES ${eckit_maths_lib_srcs} - PUBLIC_LIBS eckit - PRIVATE_LIBS "${LAPACK_LIBRARIES}" "${BLAS_LIBRARIES}" ) +ecbuild_add_library( + TARGET eckit_maths + TYPE SHARED + INSTALL_HEADERS ALL + HEADER_DESTINATION ${INSTALL_INCLUDE_DIR}/eckit/maths + SOURCES ${eckit_maths_sources} + PRIVATE_LIBS ${eckit_maths_private_libs} + PUBLIC_LIBS eckit +) -if( HAVE_EIGEN ) +if(HAVE_EIGEN) # Add include directories with "SYSTEM" to avoid warnings from within Eigen headers target_include_directories(eckit_maths SYSTEM PUBLIC ${EIGEN3_INCLUDE_DIRS}) endif() + diff --git a/src/eckit/maths/Matrix3.h b/src/eckit/maths/Matrix3.h index f48860297..669345d06 100644 --- a/src/eckit/maths/Matrix3.h +++ b/src/eckit/maths/Matrix3.h @@ -18,47 +18,39 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Point3.h" + namespace eckit::maths { + template class Matrix3 final : protected std::array { -private: - // -- Types - - using P = std::array; - public: // -- Types - // None - // -- Exceptions - // None + using container_type = std::array; +public: // -- Constructors Matrix3(T xx, T xy, T xz, T yx, T yy, T yz, T zx, T zy, T zz) : - P{xx, xy, xz, yx, yy, yz, zx, zy, zz} {} - Matrix3(const Matrix3& other) : - P(other) {} - Matrix3(Matrix3&& other) : - P(other) {} + container_type{xx, xy, xz, yx, yy, yz, zx, zy, zz} {} + + Matrix3(const Matrix3& other) : container_type(other) {} + Matrix3(Matrix3&& other) : container_type(other) {} // -- Destructor ~Matrix3() = default; - // -- Convertors - // None - // -- Operators Matrix3& operator=(const Matrix3& other) { - P::operator=(other); + container_type::operator=(other); return *this; } Matrix3& operator=(Matrix3&& other) { - P::operator=(other); + container_type::operator=(other); return *this; } @@ -75,23 +67,23 @@ class Matrix3 final : protected std::array { // -- Members - T& XX = P::operator[](0); - T& XY = P::operator[](1); - T& XZ = P::operator[](2); - T& YX = P::operator[](3); - T& YY = P::operator[](4); - T& YZ = P::operator[](5); - T& ZX = P::operator[](6); - T& ZY = P::operator[](7); - T& ZZ = P::operator[](8); + const T& XX = container_type::operator[](0); + const T& XY = container_type::operator[](1); + const T& XZ = container_type::operator[](2); + const T& YX = container_type::operator[](3); + const T& YY = container_type::operator[](4); + const T& YZ = container_type::operator[](5); + const T& ZX = container_type::operator[](6); + const T& ZY = container_type::operator[](7); + const T& ZZ = container_type::operator[](8); // -- Methods - using P::size; - using P::begin; - using P::end; - using P::cbegin; - using P::cend; + using container_type::begin; + using container_type::cbegin; + using container_type::cend; + using container_type::end; + using container_type::size; static Matrix3 identity() { return {1, 0, 0, 0, 1, 0, 0, 0, 1}; } @@ -104,16 +96,9 @@ class Matrix3 final : protected std::array { (YX * ZY - YY * ZX) / det, (XY * ZX - XX * ZY) / det, (XX * YY - XY * YX) / det}; } - T determinant() const { return XX*YY*ZZ-XZ*YY*ZX+XY*YZ*ZX+XZ*YX*ZY-XX*YZ*ZY-XY*YX*ZZ; } - - // -- Overridden methods - // None - - // -- Class members - // None - - // -- Class methods - // None + T determinant() const { + return XX * YY * ZZ - XZ * YY * ZX + XY * YZ * ZX + XZ * YX * ZY - XX * YZ * ZY - XY * YX * ZZ; + } // -- Friends @@ -123,4 +108,5 @@ class Matrix3 final : protected std::array { } }; + } // namespace eckit::maths From e5f95bc9e87740e44af653f0438c2bc4019c3acc Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 17:24:58 +0100 Subject: [PATCH 620/737] eckit::geo::Cache::bytes_size_t instead of bytes_t --- src/eckit/geo/Cache.cc | 6 +++--- src/eckit/geo/Cache.h | 12 ++++++------ tests/geo/cache.cc | 30 +++++++++++++++--------------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/eckit/geo/Cache.cc b/src/eckit/geo/Cache.cc index 84708c435..44272d1b1 100644 --- a/src/eckit/geo/Cache.cc +++ b/src/eckit/geo/Cache.cc @@ -23,10 +23,10 @@ static util::recursive_mutex MUTEX; static std::vector CACHES; -Cache::bytes_t Cache::total_footprint() { +Cache::bytes_size_t Cache::total_footprint() { util::lock_guard lock(MUTEX); - return std::accumulate(CACHES.begin(), CACHES.end(), static_cast(0), - [](bytes_t sum, const auto* cache) { return sum + cache->footprint(); }); + return std::accumulate(CACHES.begin(), CACHES.end(), static_cast(0), + [](bytes_size_t sum, const auto* cache) { return sum + cache->footprint(); }); } diff --git a/src/eckit/geo/Cache.h b/src/eckit/geo/Cache.h index 7b364576d..05cc72928 100644 --- a/src/eckit/geo/Cache.h +++ b/src/eckit/geo/Cache.h @@ -24,17 +24,17 @@ namespace eckit::geo { class Cache { public: - using bytes_t = decltype(sizeof(int)); + using bytes_size_t = decltype(sizeof(int)); - static bytes_t total_footprint(); + static bytes_size_t total_footprint(); static void total_purge(); protected: Cache(); private: - virtual bytes_t footprint() const = 0; - virtual void purge() = 0; + virtual bytes_size_t footprint() const = 0; + virtual void purge() = 0; }; @@ -74,9 +74,9 @@ class CacheT final : private Cache { return container_[key]; } - bytes_t footprint() const final { + bytes_size_t footprint() const final { util::lock_guard lock(*mutex_); - return std::accumulate(container_.begin(), container_.end(), 0, [](bytes_t sum, const auto& kv) { + return std::accumulate(container_.begin(), container_.end(), 0, [](bytes_size_t sum, const auto& kv) { if constexpr (has_footprint_v) { return sum + kv.second.footprint(); } diff --git a/tests/geo/cache.cc b/tests/geo/cache.cc index 3aba24123..082f2758e 100644 --- a/tests/geo/cache.cc +++ b/tests/geo/cache.cc @@ -22,23 +22,23 @@ CASE("eckit::geo::util") { struct test_t { size_t N; bool increasing; - Cache::bytes_t pl_footprint; - Cache::bytes_t pl_footprint_acc; - Cache::bytes_t gl_footprint; - Cache::bytes_t gl_footprint_acc; + Cache::bytes_size_t pl_footprint; + Cache::bytes_size_t pl_footprint_acc; + Cache::bytes_size_t gl_footprint; + Cache::bytes_size_t gl_footprint_acc; } tests[] = { - {16, false, 256, 256, 256, 256}, - {24, false, 384, 640, 384, 640}, - {24, false, 384, 640, 384, 640}, // (repeated for a cache hit) - {32, false, 512, 1152, 512, 1152}, + {16, false, 256, 256, 256, 256}, // + {24, false, 384, 640, 384, 640}, // + {24, false, 384, 640, 384, 640}, // (repeated for a cache hit) + {32, false, 512, 1152, 512, 1152}, // {16, false, 256, 1152, 256, 1152}, // (repeated for another cache hit) - {48, false, 768, 1920, 768, 1920}, - {16, true, 256, 1920, 256, 2176}, // (repeated except for 'increasing') - {24, true, 384, 1920, 384, 2560}, // ... - {24, true, 384, 1920, 384, 2560}, - {32, true, 512, 1920, 512, 3072}, - {16, true, 256, 1920, 256, 3072}, - {48, true, 768, 1920, 768, 3840}, + {48, false, 768, 1920, 768, 1920}, // + {16, true, 256, 1920, 256, 2176}, // (repeated except for 'increasing') + {24, true, 384, 1920, 384, 2560}, // ... + {24, true, 384, 1920, 384, 2560}, // + {32, true, 512, 1920, 512, 3072}, // + {16, true, 256, 1920, 256, 3072}, // + {48, true, 768, 1920, 768, 3840}, // }; From 3441e7404b0b2a353f469645b3d068af8d61b009 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 19:28:57 +0100 Subject: [PATCH 621/737] eckit::geo apply [[nodiscard]] to factories, generator and spec() methods --- src/eckit/geo/Grid.h | 19 ++++++++++--------- src/eckit/geo/LibEcKitGeo.h | 2 +- src/eckit/geo/Projection.h | 2 +- src/eckit/geo/Range.h | 8 ++++---- src/eckit/geo/area/BoundingBox.h | 6 +++--- src/eckit/geo/grid/HEALPix.h | 4 ++-- src/eckit/geo/grid/ORCA.h | 2 +- src/eckit/geo/grid/ReducedGaussian.h | 2 +- src/eckit/geo/grid/Regular.h | 6 +++--- src/eckit/geo/grid/Unstructured.h | 2 +- src/eckit/geo/projection/Composer.h | 6 +++--- src/eckit/geo/projection/LonLatToXY.h | 2 +- src/eckit/geo/projection/LonLatToXYZ.h | 2 +- src/eckit/geo/projection/Mercator.h | 2 +- src/eckit/geo/projection/None.h | 2 +- src/eckit/geo/projection/PROJ.h | 2 +- src/eckit/geo/projection/Rotation.h | 2 +- src/eckit/geo/projection/XYToLonLat.h | 2 +- src/eckit/geo/range/GaussianLatitude.h | 5 +++-- src/eckit/geo/range/RegularCartesian.h | 4 ++-- src/eckit/geo/range/RegularLatitude.h | 4 ++-- src/eckit/geo/range/RegularLongitude.h | 4 ++-- src/eckit/geo/spec/Generator.h | 13 +++++++------ 23 files changed, 53 insertions(+), 50 deletions(-) diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 96be84bab..86998fef3 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -122,15 +122,16 @@ class Grid { virtual Ordering order() const; virtual Renumber reorder(Ordering) const; - virtual Grid* make_grid_reordered(Ordering) const; virtual Area* area() const; virtual Renumber crop(const Area&) const; - virtual Grid* make_grid_cropped(const Area&) const; virtual const area::BoundingBox& boundingBox() const; virtual Renumber crop(const area::BoundingBox&) const; - virtual Grid* make_grid_cropped(const area::BoundingBox&) const; + + [[nodiscard]] virtual Grid* make_grid_reordered(Ordering) const; + [[nodiscard]] virtual Grid* make_grid_cropped(const Area&) const; + [[nodiscard]] virtual Grid* make_grid_cropped(const area::BoundingBox&) const; // -- Class methods @@ -155,7 +156,7 @@ class Grid { virtual void spec(spec::Custom&) const; - virtual area::BoundingBox* calculate_bbox() const { return new area::BoundingBox{}; } + [[nodiscard]] virtual area::BoundingBox* calculate_bbox() const { return new area::BoundingBox{}; } // -- Friends @@ -181,21 +182,21 @@ using GridRegisterName = spec::ConcreteSpecGeneratorT1; struct GridFactory { // This is 'const' as Grid should always be immutable - static const Grid* build(const Spec& spec) { return instance().make_from_spec_(spec); } + [[nodiscard]] static const Grid* build(const Spec& spec) { return instance().make_from_spec_(spec); } // This is 'const' as Grid should always be immutable - static const Grid* make_from_string(const std::string&); + [[nodiscard]] static const Grid* make_from_string(const std::string&); - static Spec* make_spec(const Spec& spec) { return instance().make_spec_(spec); } + [[nodiscard]] static Spec* make_spec(const Spec& spec) { return instance().make_spec_(spec); } static void list(std::ostream& out) { return instance().list_(out); } private: static GridFactory& instance(); // This is 'const' as Grid should always be immutable - const Grid* make_from_spec_(const Spec&) const; + [[nodiscard]] const Grid* make_from_spec_(const Spec&) const; - Spec* make_spec_(const Spec&) const; + [[nodiscard]] Spec* make_spec_(const Spec&) const; void list_(std::ostream&) const; }; diff --git a/src/eckit/geo/LibEcKitGeo.h b/src/eckit/geo/LibEcKitGeo.h index 4a8c73060..ec0c40f48 100644 --- a/src/eckit/geo/LibEcKitGeo.h +++ b/src/eckit/geo/LibEcKitGeo.h @@ -43,7 +43,7 @@ class LibEcKitGeo final : public system::Library { // -- Overridden methods - const void* addr() const override; + [[nodiscard]] const void* addr() const override; std::string version() const override; std::string gitsha1(unsigned int count) const override; }; diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 7b81386b6..6e0174dab 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -59,7 +59,7 @@ class Projection { virtual Point fwd(const Point&) const = 0; virtual Point inv(const Point&) const = 0; - virtual Spec* spec() const = 0; + [[nodiscard]] virtual Spec* spec() const = 0; }; diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 0207eecbb..99d26181a 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -48,10 +48,10 @@ class Range { virtual bool periodic() const { return false; } - virtual Range* flip() const = 0; - virtual Range* crop(double crop_a, double crop_b) const = 0; - virtual Fraction increment() const = 0; - virtual const std::vector& values() const = 0; + [[nodiscard]] virtual Range* flip() const = 0; + [[nodiscard]] virtual Range* crop(double crop_a, double crop_b) const = 0; + virtual Fraction increment() const = 0; + virtual const std::vector& values() const = 0; protected: // -- Constructors diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index d33d9d9a6..f64f185dc 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -86,9 +86,9 @@ class BoundingBox : public Area, protected std::array { static BoundingBox calculate(const BoundingBox&, const Projection&); - static BoundingBox* make_global_prime(); - static BoundingBox* make_global_antiprime(); - static BoundingBox* make_from_spec(const Spec&); + [[nodiscard]] static BoundingBox* make_global_prime(); + [[nodiscard]] static BoundingBox* make_global_antiprime(); + [[nodiscard]] static BoundingBox* make_from_spec(const Spec&); // -- Members diff --git a/src/eckit/geo/grid/HEALPix.h b/src/eckit/geo/grid/HEALPix.h index 81921b33b..55a547125 100644 --- a/src/eckit/geo/grid/HEALPix.h +++ b/src/eckit/geo/grid/HEALPix.h @@ -44,11 +44,11 @@ class HEALPix final : public Reduced { Ordering order() const override { return ordering_; } Renumber reorder(Ordering) const override; - Grid* make_grid_reordered(Ordering ordering) const override { return new HEALPix(Nside_, ordering); } + [[nodiscard]] Grid* make_grid_reordered(Ordering ordering) const override { return new HEALPix(Nside_, ordering); } // -- Class members - static Spec* spec(const std::string& name); + [[nodiscard]] static Spec* spec(const std::string& name); private: // -- Members diff --git a/src/eckit/geo/grid/ORCA.h b/src/eckit/geo/grid/ORCA.h index f4484f54e..8b21ad635 100644 --- a/src/eckit/geo/grid/ORCA.h +++ b/src/eckit/geo/grid/ORCA.h @@ -94,7 +94,7 @@ class ORCA final : public Regular { // -- Class methods - static Spec* spec(const std::string& name); + [[nodiscard]] static Spec* spec(const std::string& name); private: // -- Members diff --git a/src/eckit/geo/grid/ReducedGaussian.h b/src/eckit/geo/grid/ReducedGaussian.h index 03ce86a97..781f3b7af 100644 --- a/src/eckit/geo/grid/ReducedGaussian.h +++ b/src/eckit/geo/grid/ReducedGaussian.h @@ -58,7 +58,7 @@ class ReducedGaussian : public Reduced { const std::vector& latitudes() const override; std::vector longitudes(size_t i) const override; - Grid* make_grid_cropped(const area::BoundingBox&) const override; + [[nodiscard]] Grid* make_grid_cropped(const area::BoundingBox&) const override; }; diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index 2085ae72d..d4accce1a 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -82,7 +82,7 @@ struct RegularLL final : public Regular { explicit RegularLL(const Increments&, const area::BoundingBox& = {}); RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); - static Spec* spec(const std::string& name); + [[nodiscard]] static Spec* spec(const std::string& name); void spec(spec::Custom&) const override; }; @@ -91,9 +91,9 @@ struct RegularGaussian final : public Regular { explicit RegularGaussian(const Spec&); explicit RegularGaussian(size_t N, const area::BoundingBox& = {}); - Grid* make_grid_cropped(const area::BoundingBox& crop) const override; + [[nodiscard]] Grid* make_grid_cropped(const area::BoundingBox& crop) const override; - static Spec* spec(const std::string& name); + [[nodiscard]] static Spec* spec(const std::string& name); void spec(spec::Custom&) const override; size_t N() const { return N_; } diff --git a/src/eckit/geo/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h index 52fd90c60..e247966cd 100644 --- a/src/eckit/geo/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -47,7 +47,7 @@ class Unstructured final : public Grid { // -- Class methods - static Spec* spec(const std::string& name); + [[nodiscard]] static Spec* spec(const std::string& name); private: // -- Members diff --git a/src/eckit/geo/projection/Composer.h b/src/eckit/geo/projection/Composer.h index 458e91308..6f276b9bf 100644 --- a/src/eckit/geo/projection/Composer.h +++ b/src/eckit/geo/projection/Composer.h @@ -42,15 +42,15 @@ class Composer final : public Projection, private std::deque { // -- Overridden methods - Spec* spec() const override; + [[nodiscard]] Spec* spec() const override; Point fwd(const Point&) const override; Point inv(const Point&) const override; // -- Class methods - static Projection* compose_back(Projection*, const Spec&); - static Projection* compose_front(const Spec&, Projection*); + [[nodiscard]] static Projection* compose_back(Projection*, const Spec&); + [[nodiscard]] static Projection* compose_front(const Spec&, Projection*); }; diff --git a/src/eckit/geo/projection/LonLatToXY.h b/src/eckit/geo/projection/LonLatToXY.h index efc7fd525..2f47fd1c6 100644 --- a/src/eckit/geo/projection/LonLatToXY.h +++ b/src/eckit/geo/projection/LonLatToXY.h @@ -32,7 +32,7 @@ class LonLatToXY final : public Projection { // -- Overridden methods - Spec* spec() const override; + [[nodiscard]] Spec* spec() const override; private: // -- Overridden methods diff --git a/src/eckit/geo/projection/LonLatToXYZ.h b/src/eckit/geo/projection/LonLatToXYZ.h index fd15b6ed7..92eb16460 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.h +++ b/src/eckit/geo/projection/LonLatToXYZ.h @@ -52,7 +52,7 @@ class LonLatToXYZ final : public Projection { virtual Point3 operator()(const PointLonLat&) const = 0; virtual PointLonLat operator()(const Point3&) const = 0; - virtual Spec* spec() const = 0; + [[nodiscard]] virtual Spec* spec() const = 0; }; // -- Members diff --git a/src/eckit/geo/projection/Mercator.h b/src/eckit/geo/projection/Mercator.h index 901ba0249..84b22e883 100644 --- a/src/eckit/geo/projection/Mercator.h +++ b/src/eckit/geo/projection/Mercator.h @@ -37,7 +37,7 @@ class Mercator final : public Projection { // -- Overridden methods - Spec* spec() const override; + [[nodiscard]] Spec* spec() const override; private: // -- Members diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index 73a62e347..48f4cd08e 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -27,7 +27,7 @@ class None final : public Projection { // -- Overridden methods - Spec* spec() const override; + [[nodiscard]] Spec* spec() const override; inline Point fwd(const Point& p) const override { return p; } inline Point inv(const Point& q) const override { return q; } diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index def5c650f..fbe057ba5 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -40,7 +40,7 @@ class PROJ final : public Projection { Point fwd(const Point&) const override; Point inv(const Point&) const override; - Spec* spec() const override; + [[nodiscard]] Spec* spec() const override; private: // -- Types diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index 09347704d..3012f146e 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -37,7 +37,7 @@ class Rotation final : public Projection { // -- Overridden methods - Spec* spec() const override; + [[nodiscard]] Spec* spec() const override; private: // -- Types diff --git a/src/eckit/geo/projection/XYToLonLat.h b/src/eckit/geo/projection/XYToLonLat.h index 5c07d5571..061b4cb60 100644 --- a/src/eckit/geo/projection/XYToLonLat.h +++ b/src/eckit/geo/projection/XYToLonLat.h @@ -32,7 +32,7 @@ class XYToLonLat final : public Projection { // -- Overridden methods - Spec* spec() const override; + [[nodiscard]] Spec* spec() const override; private: // -- Overridden methods diff --git a/src/eckit/geo/range/GaussianLatitude.h b/src/eckit/geo/range/GaussianLatitude.h index 9eb2c98f7..3d3b9204d 100644 --- a/src/eckit/geo/range/GaussianLatitude.h +++ b/src/eckit/geo/range/GaussianLatitude.h @@ -30,8 +30,9 @@ class GaussianLatitude final : public Range { // -- Overridden methods - Range* flip() const override; - Range* crop(double crop_a, double crop_b) const override; + [[nodiscard]] Range* flip() const override; + [[nodiscard]] Range* crop(double crop_a, double crop_b) const override; + Fraction increment() const override; const std::vector& values() const override; diff --git a/src/eckit/geo/range/RegularCartesian.h b/src/eckit/geo/range/RegularCartesian.h index dccef9049..3c1b95b3c 100644 --- a/src/eckit/geo/range/RegularCartesian.h +++ b/src/eckit/geo/range/RegularCartesian.h @@ -28,8 +28,8 @@ class RegularCartesian final : public Regular { // -- Overridden methods - Range* crop(double crop_a, double crop_b) const override; - Range* flip() const override; + [[nodiscard]] Range* crop(double crop_a, double crop_b) const override; + [[nodiscard]] Range* flip() const override; }; diff --git a/src/eckit/geo/range/RegularLatitude.h b/src/eckit/geo/range/RegularLatitude.h index 7c608f0b5..6371ec963 100644 --- a/src/eckit/geo/range/RegularLatitude.h +++ b/src/eckit/geo/range/RegularLatitude.h @@ -27,8 +27,8 @@ class RegularLatitude final : public Regular { // -- Overridden methods - Range* crop(double crop_a, double crop_b) const override; - Range* flip() const override { return new RegularLatitude(size(), b(), a(), eps()); } + [[nodiscard]] Range* crop(double crop_a, double crop_b) const override; + [[nodiscard]] Range* flip() const override { return new RegularLatitude(size(), b(), a(), eps()); } }; diff --git a/src/eckit/geo/range/RegularLongitude.h b/src/eckit/geo/range/RegularLongitude.h index 184968675..ef29dc660 100644 --- a/src/eckit/geo/range/RegularLongitude.h +++ b/src/eckit/geo/range/RegularLongitude.h @@ -31,8 +31,8 @@ class RegularLongitude final : public Regular { // -- Overridden methods - Range* crop(double crop_a, double crop_b) const override; - Range* flip() const override; + [[nodiscard]] Range* crop(double crop_a, double crop_b) const override; + [[nodiscard]] Range* flip() const override; bool periodic() const override { return getPeriodic(); } diff --git a/src/eckit/geo/spec/Generator.h b/src/eckit/geo/spec/Generator.h index 795c231d6..2827ed336 100644 --- a/src/eckit/geo/spec/Generator.h +++ b/src/eckit/geo/spec/Generator.h @@ -247,7 +247,7 @@ class SpecGeneratorT0 : public SpecGenerator { public: // -- Methods - virtual Spec* spec() const = 0; + [[nodiscard]] virtual Spec* spec() const = 0; }; //------------------------------------------------------------------------------------------------------ @@ -261,7 +261,7 @@ class SpecGeneratorT1 : public SpecGenerator { // -- Methods - virtual Spec* spec(arg1_t) const = 0; + [[nodiscard]] virtual Spec* spec(arg1_t) const = 0; }; //------------------------------------------------------------------------------------------------------ @@ -276,7 +276,7 @@ class SpecGeneratorT2 : public SpecGenerator { // -- Methods - virtual Spec* spec(arg1_t, arg2_t) const = 0; + [[nodiscard]] virtual Spec* spec(arg1_t, arg2_t) const = 0; }; //------------------------------------------------------------------------------------------------------ @@ -304,7 +304,7 @@ class ConcreteSpecGeneratorT0 final : public SpecGeneratorT0 { // -- Overridden methods - Spec* spec() const override { return T::spec(); } + [[nodiscard]] Spec* spec() const override { return T::spec(); } private: // -- Members @@ -337,7 +337,7 @@ class ConcreteSpecGeneratorT1 final : public SpecGeneratorT1 { // -- Overridden methods - Spec* spec(typename SpecGeneratorT1::arg1_t p1) const override { return T::spec(p1); } + [[nodiscard]] Spec* spec(typename SpecGeneratorT1::arg1_t p1) const override { return T::spec(p1); } private: // -- Members @@ -370,7 +370,8 @@ class ConcreteSpecGeneratorT2 final : public SpecGeneratorT2 { // -- Overridden methods - Spec* spec(typename SpecGeneratorT1::arg1_t p1, typename SpecGeneratorT1::arg2_t p2) const override { + [[nodiscard]] Spec* spec(typename SpecGeneratorT1::arg1_t p1, + typename SpecGeneratorT1::arg2_t p2) const override { return T::spec(p1, p2); } From 7e71f7c41ba999db65020e5263122501fd292db1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 19:33:40 +0100 Subject: [PATCH 622/737] eckit::geo tests: remove nested SECTION --- tests/geo/grid.cc | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index 7aeebe283..159a047c6 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -64,33 +64,31 @@ CASE("GridFactory::build") { } - SECTION("Grid::build_from_increments") { - SECTION("global") { - std::unique_ptr global(GridFactory::build(spec::Custom({ - {"type", "regular_ll"}, - {"west_east_increment", 1}, - {"south_north_increment", 1}, - }))); - - auto size = global->size(); - EXPECT_EQUAL(size, 360 * 181); - } + SECTION("Grid::build_from_increments (global)") { + std::unique_ptr global(GridFactory::build(spec::Custom({ + {"type", "regular_ll"}, + {"west_east_increment", 1}, + {"south_north_increment", 1}, + }))); + + auto size = global->size(); + EXPECT_EQUAL(size, 360 * 181); + } - SECTION("non-global") { - std::unique_ptr grid(GridFactory::build(spec::Custom({ - {"type", "regular_ll"}, - {"west_east_increment", 1}, - {"south_north_increment", 1}, - {"north", 10}, - {"west", 1}, - {"south", 1}, - {"east", 10}, - }))); + SECTION("Grid::build_from_increments (non-global)") { + std::unique_ptr grid(GridFactory::build(spec::Custom({ + {"type", "regular_ll"}, + {"west_east_increment", 1}, + {"south_north_increment", 1}, + {"north", 10}, + {"west", 1}, + {"south", 1}, + {"east", 10}, + }))); - auto size = grid->size(); - EXPECT_EQUAL(size, 100); - } + auto size = grid->size(); + EXPECT_EQUAL(size, 100); } } From b4d2fa010b294fd2f769aecc0ad5d3218f7dd49a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 19:33:53 +0100 Subject: [PATCH 623/737] clang-format version 19 --- tests/geo/area_polygon.cc | 14 +- tests/geo/great_circle.cc | 70 +++------- tests/geo/grid_healpix.cc | 3 +- tests/geo/grid_reduced_gg.cc | 3 +- tests/geo/grid_regular_ll.cc | 9 +- tests/geo/kdtree.cc | 8 +- tests/geo/pointlonlat.cc | 216 +++++++----------------------- tests/geo/projection_ll_to_xyz.cc | 10 +- tests/geo/projection_rotation.cc | 3 +- tests/geo/spec.cc | 4 +- 10 files changed, 80 insertions(+), 260 deletions(-) diff --git a/tests/geo/area_polygon.cc b/tests/geo/area_polygon.cc index ad860ab26..e944f37e9 100644 --- a/tests/geo/area_polygon.cc +++ b/tests/geo/area_polygon.cc @@ -100,8 +100,8 @@ CASE("LonLatPolygon") { SECTION("Construction") { const std::vector points1{{0, 0}, {1, 1}, {2, 2}, {0, 0}}; - const std::vector - points2{{0, 0}, {1, 0}, {2, 0}, {2, 1}, {2, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 0}}; + const std::vector points2{{0, 0}, {1, 0}, {2, 0}, {2, 1}, {2, 2}, + {1, 2}, {0, 2}, {0, 1}, {0, 0}}; EXPECT_EQUAL(Polygon(points1).size(), 2); EXPECT_EQUAL(Polygon(points1.begin(), points1.end()).size(), 2); @@ -367,14 +367,8 @@ CASE("LonLatPolygon") { std::vector points; - const std::vector list_lons{lon[0], - mid(lon[0], lon[1]), - lon[1], - mid(lon[1], lon[2]), - lon[2], - mid(lon[2], lon[3]), - lon[3], - mid(lon[3], lon[4])}; + const std::vector list_lons{lon[0], mid(lon[0], lon[1]), lon[1], mid(lon[1], lon[2]), + lon[2], mid(lon[2], lon[3]), lon[3], mid(lon[3], lon[4])}; const std::vector list_lats{lat[0], mid(lat[0], lat[1]), lat[1], mid(lat[1], lat[2]), lat[2]}; for (double lon : list_lons) { diff --git a/tests/geo/great_circle.cc b/tests/geo/great_circle.cc index 9f1818bfe..6da020776 100644 --- a/tests/geo/great_circle.cc +++ b/tests/geo/great_circle.cc @@ -29,8 +29,8 @@ CASE("great circle intersections") { using types::is_approximately_equal; using types::is_approximately_greater_or_equal; - auto is_approximately_equal_longitude = - [](double lon1, double lon2, double epsilon = std::numeric_limits::epsilon()) -> bool { + auto is_approximately_equal_longitude + = [](double lon1, double lon2, double epsilon = std::numeric_limits::epsilon()) -> bool { while (lon2 < lon1) { lon2 += 360; } @@ -49,50 +49,16 @@ CASE("great circle intersections") { }; const std::vector latitudes{ - 90, - 60, - 45, - 30, - 0, - -30, - -45, - -60, - -90, + 90, 60, 45, 30, 0, -30, -45, -60, -90, }; const std::vector longitudes{ - -181, - -180, - -135, - -90, - -45, - 0, - 45, - 90, - 135, - 180, - 225, - 270, - 315, - 360, - 361, + -181, -180, -135, -90, -45, 0, 45, 90, 135, 180, 225, 270, 315, 360, 361, }; const std::vector antipodes{ - {0, 0}, - {180, 0}, - {-180, 0}, - {0, 0}, - {-90, 0}, - {90, 0}, - {90, 0}, - {-90, 0}, - {0, 90}, - {0, -90}, - {0, -90}, - {0, 90}, - {45, 45}, - {225, -45}, + {0, 0}, {180, 0}, {-180, 0}, {0, 0}, {-90, 0}, {90, 0}, {90, 0}, + {-90, 0}, {0, 90}, {0, -90}, {0, -90}, {0, 90}, {45, 45}, {225, -45}, }; SECTION("example intersection with meridian and parallel") { @@ -108,8 +74,8 @@ CASE("great circle intersections") { auto lons = gc.longitude(mid.lat); EXPECT(lons.size() == 2); - EXPECT(is_approximately_equal_longitude(lons[0], mid.lon, 0.01) || - is_approximately_equal_longitude(lons[1], mid.lon, 0.01)); + EXPECT(is_approximately_equal_longitude(lons[0], mid.lon, 0.01) + || is_approximately_equal_longitude(lons[1], mid.lon, 0.01)); } SECTION("mal-formed great circle") { @@ -143,17 +109,17 @@ CASE("great circle intersections") { auto lon_at_equator = gc.longitude(0); EXPECT(lon_at_equator.size() == 2); - EXPECT((is_approximately_equal_longitude(lon_gc + 90, lon_at_equator[0]) && - is_approximately_equal_longitude(lon_gc - 90, lon_at_equator[1])) || - (is_approximately_equal_longitude(lon_gc - 90, lon_at_equator[0]) && - is_approximately_equal_longitude(lon_gc + 90, lon_at_equator[1]))); + EXPECT((is_approximately_equal_longitude(lon_gc + 90, lon_at_equator[0]) + && is_approximately_equal_longitude(lon_gc - 90, lon_at_equator[1])) + || (is_approximately_equal_longitude(lon_gc - 90, lon_at_equator[0]) + && is_approximately_equal_longitude(lon_gc + 90, lon_at_equator[1]))); auto lon_extrema1 = gc.longitude(lat_gc); EXPECT(lon_extrema1.size() == 1 && is_approximately_equal_longitude(lon_extrema1[0], lon_gc, 0.01)); auto lon_extrema2 = gc.longitude(-lat_gc); - EXPECT(lon_extrema2.size() == 1 && - is_approximately_equal_longitude(lon_extrema2[0], lon_gc + 180, 0.01)); + EXPECT(lon_extrema2.size() == 1 + && is_approximately_equal_longitude(lon_extrema2[0], lon_gc + 180, 0.01)); } } } @@ -176,8 +142,8 @@ CASE("great circle intersections") { } else { EXPECT(is_approximately_equal_longitude(lons[0] + 180, lons[1])); - EXPECT(is_approximately_equal_longitude(lons[0], lon) || - is_approximately_equal_longitude(lons[1], lon)); + EXPECT(is_approximately_equal_longitude(lons[0], lon) + || is_approximately_equal_longitude(lons[1], lon)); } } @@ -189,8 +155,8 @@ CASE("great circle intersections") { EXPECT(lons.size() == 2); EXPECT(is_approximately_equal_longitude(lons[0] + 180, lons[1])); - EXPECT(is_approximately_equal_longitude(lons[0], lon) || - is_approximately_equal_longitude(lons[1], lon)); + EXPECT(is_approximately_equal_longitude(lons[0], lon) + || is_approximately_equal_longitude(lons[1], lon)); } } } diff --git a/tests/geo/grid_healpix.cc b/tests/geo/grid_healpix.cc index cbb08b00c..c91d08b38 100644 --- a/tests/geo/grid_healpix.cc +++ b/tests/geo/grid_healpix.cc @@ -32,8 +32,7 @@ CASE("HEALPix") { SECTION("sizes") { struct test_t { - explicit test_t(size_t N) : - N(N), size(12 * N * N) {} + explicit test_t(size_t N) : N(N), size(12 * N * N) {} size_t N; size_t size; } tests[]{test_t{2}, test_t{3}, test_t{64}}; diff --git a/tests/geo/grid_reduced_gg.cc b/tests/geo/grid_reduced_gg.cc index ace1b839a..e1ef8ca10 100644 --- a/tests/geo/grid_reduced_gg.cc +++ b/tests/geo/grid_reduced_gg.cc @@ -45,8 +45,7 @@ CASE("ReducedGaussianOctahedral") { SECTION("sizes") { struct test_t { - explicit test_t(size_t N) : - N(N), size(4 * N * (N + 9)) {} + explicit test_t(size_t N) : N(N), size(4 * N * (N + 9)) {} size_t N; size_t size; } tests[]{test_t{2}, test_t{3}, test_t{64}}; diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index 1c8eecaa6..188526cd9 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -49,14 +49,7 @@ CASE("non-global") { grid::RegularLL grid({1, 2}, {1, -1, -1, 2}); const std::vector ref{ - {-1., 1.}, - {0., 1.}, - {1., 1.}, - {2., 1.}, - {-1., -1.}, - {0., -1.}, - {1., -1.}, - {2., -1.}, + {-1., 1.}, {0., 1.}, {1., 1.}, {2., 1.}, {-1., -1.}, {0., -1.}, {1., -1.}, {2., -1.}, }; auto points = grid.to_points(); diff --git a/tests/geo/kdtree.cc b/tests/geo/kdtree.cc index 2e66d2983..f1a86930e 100644 --- a/tests/geo/kdtree.cc +++ b/tests/geo/kdtree.cc @@ -76,8 +76,9 @@ struct PointInBoxInteriorFinder { const size_t axis = node->axis(); - return (lbound.x(axis) < point.x(axis) && isAnyPointInBoxInterior(node->left(alloc), alloc, lbound, ubound)) || - (ubound.x(axis) > point.x(axis) && isAnyPointInBoxInterior(node->right(alloc), alloc, lbound, ubound)); + return (lbound.x(axis) < point.x(axis) && isAnyPointInBoxInterior(node->left(alloc), alloc, lbound, ubound)) + || (ubound.x(axis) > point.x(axis) + && isAnyPointInBoxInterior(node->right(alloc), alloc, lbound, ubound)); } /// \brief Returns true if \p point is in the interior of the axis-aligned box @@ -97,8 +98,7 @@ struct PointInBoxInteriorFinder { /// \brief Returns true if any point in \p tree is in the interior of the axis-aligned box /// with bottom-left and top-right corners at \p lbound and \p ubound. template -bool isAnyPointInBoxInterior(const KDTreeX& tree, - const typename KDTreeX::Point& lbound, +bool isAnyPointInBoxInterior(const KDTreeX& tree, const typename KDTreeX::Point& lbound, const typename KDTreeX::Point& ubound) { return PointInBoxInteriorFinder::isAnyPointInBoxInterior(tree, lbound, ubound); } diff --git a/tests/geo/pointlonlat.cc b/tests/geo/pointlonlat.cc index c88fd75a8..8fcfd0dd4 100644 --- a/tests/geo/pointlonlat.cc +++ b/tests/geo/pointlonlat.cc @@ -41,9 +41,8 @@ CASE("PointLonLat normalise_angle_to_*") { {360., 0., 0.}, {100000., 99960., 100000.}, }) { - EXPECT(types::is_approximately_equal(test.ref, - PointLonLat::normalise_angle_to_minimum(test.angle, test.lim), - PointLonLat::EPS)); + EXPECT(types::is_approximately_equal( + test.ref, PointLonLat::normalise_angle_to_minimum(test.angle, test.lim), PointLonLat::EPS)); } } @@ -61,9 +60,8 @@ CASE("PointLonLat normalise_angle_to_*") { {720., 360., 360.}, {100040., 100080., 100040.}, }) { - EXPECT(types::is_approximately_equal(test.ref, - PointLonLat::normalise_angle_to_maximum(test.angle, test.lim), - PointLonLat::EPS)); + EXPECT(types::is_approximately_equal( + test.ref, PointLonLat::normalise_angle_to_maximum(test.angle, test.lim), PointLonLat::EPS)); } } @@ -85,206 +83,86 @@ CASE("PointLonLat normalise_angle_to_*") { }; for (const auto& test : { - test_t{0x1.a99999999999fp+3, - 0x1.a9999999999ap+3, - 0x1.a99999999998p+3, - 0x1.a99999999998p+3, + test_t{0x1.a99999999999fp+3, 0x1.a9999999999ap+3, 0x1.a99999999998p+3, 0x1.a99999999998p+3, 0x1.a99999999998p+3}, // 13.30000000000001 - {0x1.7599999999999p+5, - 0x1.7599999999998p+5, - 0x1.75999999999ap+5, - 0x1.75999999999ap+5, + {0x1.7599999999999p+5, 0x1.7599999999998p+5, 0x1.75999999999ap+5, 0x1.75999999999ap+5, 0x1.75999999999ap+5}, // 46.699999999999996 - {-0x1.37823af2187f7p+4, - -0x1.37823af2187fp+4, - -0x1.37823af2188p+4, - -0x1.37823af2188p+4, + {-0x1.37823af2187f7p+4, -0x1.37823af2187fp+4, -0x1.37823af2188p+4, -0x1.37823af2188p+4, -0x1.37823af2188p+4}, //-19.469294496237094 - {0x1.14f26c8adc252p+3, - 0x1.14f26c8adc26p+3, - 0x1.14f26c8adc24p+3, - 0x1.14f26c8adc28p+3, + {0x1.14f26c8adc252p+3, 0x1.14f26c8adc26p+3, 0x1.14f26c8adc24p+3, 0x1.14f26c8adc28p+3, 0x1.14f26c8adc24p+3}, // 8.6545927726848824 - {0x1.237e9f537dd2dp+5, - 0x1.237e9f537dd3p+5, - 0x1.237e9f537dd3p+5, - 0x1.237e9f537dd3p+5, + {0x1.237e9f537dd2dp+5, 0x1.237e9f537dd3p+5, 0x1.237e9f537dd3p+5, 0x1.237e9f537dd3p+5, 0x1.237e9f537dd3p+5}, // 36.436827327992752 - {0x1.eb74b977e1e89p+5, - 0x1.eb74b977e1e88p+5, - 0x1.eb74b977e1e9p+5, - 0x1.eb74b977e1e8p+5, + {0x1.eb74b977e1e89p+5, 0x1.eb74b977e1e88p+5, 0x1.eb74b977e1e9p+5, 0x1.eb74b977e1e8p+5, 0x1.eb74b977e1e9p+5}, // 61.431994377690962 - {0x1.1008717af4f67p+6, - 0x1.1008717af4f68p+6, - 0x1.1008717af4f68p+6, - 0x1.1008717af4f68p+6, + {0x1.1008717af4f67p+6, 0x1.1008717af4f68p+6, 0x1.1008717af4f68p+6, 0x1.1008717af4f68p+6, 0x1.1008717af4f68p+6}, // 68.008245392991384 - {-0x1.b4f88656270d9p+4, - -0x1.b4f88656270ep+4, - -0x1.b4f88656270ep+4, - -0x1.b4f88656270ep+4, + {-0x1.b4f88656270d9p+4, -0x1.b4f88656270ep+4, -0x1.b4f88656270ep+4, -0x1.b4f88656270ep+4, -0x1.b4f88656270ep+4}, //-27.31067498830166 - {-0x1.eb22f87f6ac12p+1, - -0x1.eb22f87f6acp+1, - -0x1.eb22f87f6acp+1, - -0x1.eb22f87f6acp+1, + {-0x1.eb22f87f6ac12p+1, -0x1.eb22f87f6acp+1, -0x1.eb22f87f6acp+1, -0x1.eb22f87f6acp+1, -0x1.eb22f87f6acp+1}, //-3.8370047208932272 - {0x1.40de11e0c3e99p+4, - 0x1.40de11e0c3eap+4, - 0x1.40de11e0c3eap+4, - 0x1.40de11e0c3eap+4, + {0x1.40de11e0c3e99p+4, 0x1.40de11e0c3eap+4, 0x1.40de11e0c3eap+4, 0x1.40de11e0c3eap+4, 0x1.40de11e0c3eap+4}, // 20.054216268529306 - {0x1.4aeba99be1331p+5, - 0x1.4aeba99be133p+5, - 0x1.4aeba99be133p+5, - 0x1.4aeba99be133p+5, + {0x1.4aeba99be1331p+5, 0x1.4aeba99be133p+5, 0x1.4aeba99be133p+5, 0x1.4aeba99be133p+5, 0x1.4aeba99be133p+5}, // 41.365069597063105 - {0x1.aa5c50f727ae6p+5, - 0x1.aa5c50f727ae8p+5, - 0x1.aa5c50f727aep+5, - 0x1.aa5c50f727aep+5, + {0x1.aa5c50f727ae6p+5, 0x1.aa5c50f727ae8p+5, 0x1.aa5c50f727aep+5, 0x1.aa5c50f727aep+5, 0x1.aa5c50f727aep+5}, // 53.295076304338906 - {-0x1.556ccf04ef1bbp+4, - -0x1.556ccf04ef1cp+4, - -0x1.556ccf04ef1cp+4, - -0x1.556ccf04ef1cp+4, + {-0x1.556ccf04ef1bbp+4, -0x1.556ccf04ef1cp+4, -0x1.556ccf04ef1cp+4, -0x1.556ccf04ef1cp+4, -0x1.556ccf04ef1cp+4}, //-21.339064616464139 - {0x1.556ccf04ef1bbp+4, - 0x1.556ccf04ef1cp+4, - 0x1.556ccf04ef1cp+4, - 0x1.556ccf04ef1cp+4, + {0x1.556ccf04ef1bbp+4, 0x1.556ccf04ef1cp+4, 0x1.556ccf04ef1cp+4, 0x1.556ccf04ef1cp+4, 0x1.556ccf04ef1cp+4}, // 21.339064616464139 - {0x1.388f683df92bbp+5, - 0x1.388f683df92b8p+5, - 0x1.388f683df92cp+5, - 0x1.388f683df92cp+5, + {0x1.388f683df92bbp+5, 0x1.388f683df92b8p+5, 0x1.388f683df92cp+5, 0x1.388f683df92cp+5, 0x1.388f683df92cp+5}, // 39.070023044745049 - {-0x1.40de11e0c3e9dp+4, - -0x1.40de11e0c3eap+4, - -0x1.40de11e0c3eap+4, - -0x1.40de11e0c3eap+4, + {-0x1.40de11e0c3e9dp+4, -0x1.40de11e0c3eap+4, -0x1.40de11e0c3eap+4, -0x1.40de11e0c3eap+4, -0x1.40de11e0c3eap+4}, //-20.05421626852932 - {0x1.eb22f87f6abf5p+1, - 0x1.eb22f87f6acp+1, - 0x1.eb22f87f6acp+1, - 0x1.eb22f87f6acp+1, + {0x1.eb22f87f6abf5p+1, 0x1.eb22f87f6acp+1, 0x1.eb22f87f6acp+1, 0x1.eb22f87f6acp+1, 0x1.eb22f87f6acp+1}, // 3.8370047208932143 - {0x1.b4f88656270d7p+4, - 0x1.b4f88656270dp+4, - 0x1.b4f88656270ep+4, - 0x1.b4f88656270cp+4, + {0x1.b4f88656270d7p+4, 0x1.b4f88656270dp+4, 0x1.b4f88656270ep+4, 0x1.b4f88656270cp+4, 0x1.b4f88656270ep+4}, // 27.310674988301653 - {-0x1.3f0f4411db559p+5, - -0x1.3f0f4411db558p+5, - -0x1.3f0f4411db56p+5, - -0x1.3f0f4411db558p+5, + {-0x1.3f0f4411db559p+5, -0x1.3f0f4411db558p+5, -0x1.3f0f4411db56p+5, -0x1.3f0f4411db558p+5, -0x1.3f0f4411db56p+5}, //-39.882454051500368 - {-0x1.63664f7d2181dp+5, - -0x1.63664f7d2182p+5, - -0x1.63664f7d2182p+5, - -0x1.63664f7d2182p+5, + {-0x1.63664f7d2181dp+5, -0x1.63664f7d2182p+5, -0x1.63664f7d2182p+5, -0x1.63664f7d2182p+5, -0x1.63664f7d2182p+5}, //-44.424956300339751 - {-0x1.75e470fd085aap+5, - -0x1.75e470fd085a8p+5, - -0x1.75e470fd085bp+5, - -0x1.75e470fd085a8p+5, + {-0x1.75e470fd085aap+5, -0x1.75e470fd085a8p+5, -0x1.75e470fd085bp+5, -0x1.75e470fd085a8p+5, -0x1.75e470fd085bp+5}, //-46.7365436332869 - {-0x1.b2a6314996231p+4, - -0x1.b2a631499623p+4, - -0x1.b2a631499624p+4, - -0x1.b2a631499624p+4, + {-0x1.b2a6314996231p+4, -0x1.b2a631499623p+4, -0x1.b2a631499624p+4, -0x1.b2a631499624p+4, -0x1.b2a631499624p+4}, //-27.165574347922476 - {-0x1.f720e2a9525edp+5, - -0x1.f720e2a9525fp+5, - -0x1.f720e2a9525fp+5, - -0x1.f720e2a9525fp+5, + {-0x1.f720e2a9525edp+5, -0x1.f720e2a9525fp+5, -0x1.f720e2a9525fp+5, -0x1.f720e2a9525fp+5, -0x1.f720e2a9525fp+5}, //-62.89105732233643 - {-0x1.236723c039272p+5, - -0x1.236723c03927p+5, - -0x1.236723c03927p+5, - -0x1.236723c03927p+5, + {-0x1.236723c039272p+5, -0x1.236723c03927p+5, -0x1.236723c03927p+5, -0x1.236723c03927p+5, -0x1.236723c03927p+5}, //-36.425361158126989 - {-0x1.7f9f1a40a5d1fp+4, - -0x1.7f9f1a40a5d2p+4, - -0x1.7f9f1a40a5d2p+4, - -0x1.7f9f1a40a5d2p+4, + {-0x1.7f9f1a40a5d1fp+4, -0x1.7f9f1a40a5d2p+4, -0x1.7f9f1a40a5d2p+4, -0x1.7f9f1a40a5d2p+4, -0x1.7f9f1a40a5d2p+4}, //-23.976343395738805 {0x1.ffffffffffffep+0, 0x1p+1, 0x1p+1, 0x1p+1, 0x1p+1}, // 1.9999999999999996 - {0x1.0b907154a92f7p+6, - 0x1.0b907154a92f8p+6, - 0x1.0b907154a92f8p+6, - 0x1.0b907154a92f8p+6, + {0x1.0b907154a92f7p+6, 0x1.0b907154a92f8p+6, 0x1.0b907154a92f8p+6, 0x1.0b907154a92f8p+6, 0x1.0b907154a92f8p+6}, // 66.891057322336437 - {0x1.436723c039272p+5, - 0x1.436723c03927p+5, - 0x1.436723c03927p+5, - 0x1.436723c03927p+5, + {0x1.436723c039272p+5, 0x1.436723c03927p+5, 0x1.436723c03927p+5, 0x1.436723c03927p+5, 0x1.436723c03927p+5}, // 40.425361158126989 - {0x1.bf9f1a40a5d1fp+4, - 0x1.bf9f1a40a5d2p+4, - 0x1.bf9f1a40a5d2p+4, - 0x1.bf9f1a40a5d2p+4, + {0x1.bf9f1a40a5d1fp+4, 0x1.bf9f1a40a5d2p+4, 0x1.bf9f1a40a5d2p+4, 0x1.bf9f1a40a5d2p+4, 0x1.bf9f1a40a5d2p+4}, // 27.976343395738805 - {0x1.0f266c20b79f9p+7, - 0x1.0f266c20b79f8p+7, - 0x1.0f266c20b79f8p+7, - 0x1.0f266c20b79f8p+7, + {0x1.0f266c20b79f9p+7, 0x1.0f266c20b79f8p+7, 0x1.0f266c20b79f8p+7, 0x1.0f266c20b79f8p+7, 0x1.0f266c20b79f8p+7}, // 135.57504369966026 - {0x1.787bbbb54c676p+6, - 0x1.787bbbb54c678p+6, - 0x1.787bbbb54c678p+6, - 0x1.787bbbb54c678p+6, + {0x1.787bbbb54c676p+6, 0x1.787bbbb54c678p+6, 0x1.787bbbb54c678p+6, 0x1.787bbbb54c678p+6, 0x1.787bbbb54c678p+6}, // 94.120833237446135 - {0x1.95e470fd085aap+5, - 0x1.95e470fd085a8p+5, - 0x1.95e470fd085bp+5, - 0x1.95e470fd085ap+5, + {0x1.95e470fd085aap+5, 0x1.95e470fd085a8p+5, 0x1.95e470fd085bp+5, 0x1.95e470fd085ap+5, 0x1.95e470fd085bp+5}, // 50.7365436332869 - {0x1.1bd0dd7b42b69p+7, - 0x1.1bd0dd7b42b68p+7, - 0x1.1bd0dd7b42b68p+7, - 0x1.1bd0dd7b42b68p+7, + {0x1.1bd0dd7b42b69p+7, 0x1.1bd0dd7b42b68p+7, 0x1.1bd0dd7b42b68p+7, 0x1.1bd0dd7b42b68p+7, 0x1.1bd0dd7b42b68p+7}, // 141.90793976964349 - {0x1.19981bd70b549p+6, - 0x1.19981bd70b548p+6, - 0x1.19981bd70b548p+6, - 0x1.19981bd70b548p+6, + {0x1.19981bd70b549p+6, 0x1.19981bd70b548p+6, 0x1.19981bd70b548p+6, 0x1.19981bd70b548p+6, 0x1.19981bd70b548p+6}, // 70.39854370123534 - {0x1.50bc8a12f525bp+5, - 0x1.50bc8a12f5258p+5, - 0x1.50bc8a12f526p+5, - 0x1.50bc8a12f526p+5, + {0x1.50bc8a12f525bp+5, 0x1.50bc8a12f5258p+5, 0x1.50bc8a12f526p+5, 0x1.50bc8a12f526p+5, 0x1.50bc8a12f526p+5}, // 42.092060230356502 - {0x1.cb2a2664f7bbdp+6, - 0x1.cb2a2664f7bbcp+6, - 0x1.cb2a2664f7bcp+6, - 0x1.cb2a2664f7bcp+6, + {0x1.cb2a2664f7bbdp+6, 0x1.cb2a2664f7bbcp+6, 0x1.cb2a2664f7bcp+6, 0x1.cb2a2664f7bcp+6, 0x1.cb2a2664f7bcp+6}, // 114.79116208803221 - {0x1.6784444ab398ap+6, - 0x1.6784444ab3988p+6, - 0x1.6784444ab3988p+6, - 0x1.6784444ab3988p+6, + {0x1.6784444ab398ap+6, 0x1.6784444ab3988p+6, 0x1.6784444ab3988p+6, 0x1.6784444ab3988p+6, 0x1.6784444ab3988p+6}, // 89.879166762553865 - {0x1.83664f7d2181ep+5, - 0x1.83664f7d2182p+5, - 0x1.83664f7d2182p+5, - 0x1.83664f7d2182p+5, + {0x1.83664f7d2181ep+5, 0x1.83664f7d2182p+5, 0x1.83664f7d2182p+5, 0x1.83664f7d2182p+5, 0x1.83664f7d2182p+5}, // 48.424956300339758 - {0x1.380c1cb7eb45dp+7, - 0x1.380c1cb7eb45cp+7, - 0x1.380c1cb7eb45cp+7, - 0x1.380c1cb7eb45cp+7, + {0x1.380c1cb7eb45dp+7, 0x1.380c1cb7eb45cp+7, 0x1.380c1cb7eb45cp+7, 0x1.380c1cb7eb45cp+7, 0x1.380c1cb7eb46p+7}, // 156.02365660426122 - {0x1.d46f8eab56d0bp+6, - 0x1.d46f8eab56d0cp+6, - 0x1.d46f8eab56d08p+6, - 0x1.d46f8eab56d1p+6, + {0x1.d46f8eab56d0bp+6, 0x1.d46f8eab56d0cp+6, 0x1.d46f8eab56d08p+6, 0x1.d46f8eab56d1p+6, 0x1.d46f8eab56d08p+6}, // 117.10894267766359 - {0x1.5f0f4411db559p+5, - 0x1.5f0f4411db558p+5, - 0x1.5f0f4411db56p+5, - 0x1.5f0f4411db56p+5, + {0x1.5f0f4411db559p+5, 0x1.5f0f4411db558p+5, 0x1.5f0f4411db56p+5, 0x1.5f0f4411db56p+5, 0x1.5f0f4411db56p+5}, // 43.882454051500368 }) { EXPECT(test.angle == normalise(test.angle, -180.)); @@ -305,11 +183,9 @@ CASE("PointLonLat normalisation") { EXPECT(types::is_approximately_equal(a, PointLonLat::normalise_angle_to_minimum(a, a), PointLonLat::EPS)); EXPECT(types::is_approximately_equal(a, PointLonLat::normalise_angle_to_maximum(a, a), PointLonLat::EPS)); - EXPECT(types::is_approximately_equal(a + 360., - PointLonLat::normalise_angle_to_minimum(a - da, a) + da, + EXPECT(types::is_approximately_equal(a + 360., PointLonLat::normalise_angle_to_minimum(a - da, a) + da, PointLonLat::EPS)); - EXPECT(types::is_approximately_equal(a - 360., - PointLonLat::normalise_angle_to_maximum(a + da, a) - da, + EXPECT(types::is_approximately_equal(a - 360., PointLonLat::normalise_angle_to_maximum(a + da, a) - da, PointLonLat::EPS)); } diff --git a/tests/geo/projection_ll_to_xyz.cc b/tests/geo/projection_ll_to_xyz.cc index 2f9b6dd90..0245c4726 100644 --- a/tests/geo/projection_ll_to_xyz.cc +++ b/tests/geo/projection_ll_to_xyz.cc @@ -42,14 +42,8 @@ CASE("projection: ll_to_xyz") { PointLonLat a; Point3 b; } tests[] = { - {{0, 0}, {1, 0, 0}}, - {{90, 0}, {0, 1, 0}}, - {{180, 0}, {-1, 0, 0}}, - {{270, 0}, {0, -1, 0}}, - {{0, -90}, {0, 0, -0.5}}, - {{42, -90}, {0, 0, -0.5}}, - {{0, 90}, {0, 0, 0.5}}, - {{42, 90}, {0, 0, 0.5}}, + {{0, 0}, {1, 0, 0}}, {{90, 0}, {0, 1, 0}}, {{180, 0}, {-1, 0, 0}}, {{270, 0}, {0, -1, 0}}, + {{0, -90}, {0, 0, -0.5}}, {{42, -90}, {0, 0, -0.5}}, {{0, 90}, {0, 0, 0.5}}, {{42, 90}, {0, 0, 0.5}}, }; for (const auto& test : tests) { diff --git a/tests/geo/projection_rotation.cc b/tests/geo/projection_rotation.cc index 871ab42d2..77de9cd14 100644 --- a/tests/geo/projection_rotation.cc +++ b/tests/geo/projection_rotation.cc @@ -49,8 +49,7 @@ CASE("rotation (2)") { for (auto a : delta) { for (auto b : delta) { for (auto c : delta) { - projection::Rotation rot(0. + static_cast(b), - -90. + static_cast(a), + projection::Rotation rot(0. + static_cast(b), -90. + static_cast(a), static_cast(c)); EXPECT(rot.rotated() == (a % 360 != 0 || (b - c) % 360 != 0)); diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 4476c9424..5b0d72ea8 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -203,8 +203,8 @@ CASE("Spec <- Custom") { {"vector", std::vector{"string", "string"}}})); const std::string b_str = b->str(); - const std::string b_ref = - R"({"bool":true,"double":6,"float":5,"int":1,"long":2,"long long":3,"size_t":4,"string":"string","vector":[6,6],"vector":[5,5],"vector":[1,1],"vector":[3,3],"vector":[2,2],"vector":[4,4],"vector":["string","string"]})"; + const std::string b_ref + = R"({"bool":true,"double":6,"float":5,"int":1,"long":2,"long long":3,"size_t":4,"string":"string","vector":[6,6],"vector":[5,5],"vector":[1,1],"vector":[3,3],"vector":[2,2],"vector":[4,4],"vector":["string","string"]})"; EXPECT_EQUAL(b_str, b_ref); } } From d1077adebf32aeb8dc8395df111e5c5d5e711a69 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 20:26:56 +0100 Subject: [PATCH 624/737] eckit::geo::area::BoundingBox fix --- src/eckit/geo/area/BoundingBox.cc | 4 ++-- src/eckit/geo/area/BoundingBox.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 35f297755..84ea5f349 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -77,8 +77,8 @@ BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s ASSERT_MSG(types::is_approximately_lesser_or_equal(north, 90.), "BoundingBox: latitude range (north <= 90)"); if (!types::is_approximately_equal(west, east)) { - auto e = PointLonLat::normalise_angle_to_minimum(east, west); - operator=({north, west, south, types::is_approximately_equal(e, west) ? (e + 360.) : e}); + auto e = PointLonLat::normalise_angle_to_minimum(east, west); + operator[](3) = types::is_approximately_equal(e, west) ? (e + 360.) : e; } ASSERT_MSG(types::is_approximately_lesser_or_equal(west, east), "BoundingBox: longitude range (west <= east)"); diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index f64f185dc..9383c4e11 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -97,6 +97,7 @@ class BoundingBox : public Area, protected std::array { const double& south = operator[](2); const double& east = operator[](3); +private: // -- Friends friend std::ostream& operator<<(std::ostream& os, const BoundingBox& bbox) { From eda6a19072690da46c39417415f555ec03337e95 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 9 May 2024 20:38:00 +0100 Subject: [PATCH 625/737] eckit::geo::Increments fix --- src/eckit/geo/Increments.cc | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/eckit/geo/Increments.cc b/src/eckit/geo/Increments.cc index a33a0b767..317cd37a2 100644 --- a/src/eckit/geo/Increments.cc +++ b/src/eckit/geo/Increments.cc @@ -21,17 +21,24 @@ namespace eckit::geo { Increments Increments::make_from_spec(const Spec& spec) { - value_type x = 0; - value_type y = 0; - if (std::vector value; spec.get("increments", value) || spec.get("grid", value) && value.size() == 2) { - x = value[0]; - y = value[1]; + if (std::vector value; spec.get("increments", value) && value.size() == 2) { + return {value[0], value[1]}; } - else if (!spec.get("dx", x) || !spec.get("dy", y)) { - throw SpecNotFound("'increments' = ['dx', 'dy'] expected", Here()); + + if (std::vector value; spec.get("grid", value) && value.size() == 2) { + return {value[0], value[1]}; + } + + if (value_type x = 0, y = 0; spec.get("dx", x) && spec.get("dy", y)) { + return {x, y}; + } + + if (value_type x = 0, y = 0; spec.get("west_east_increment", x) && spec.get("south_north_increment", y)) { + return {x, y}; } - return {x, y}; + throw SpecNotFound( + "'increments' = 'grid' = ['dx', 'dy'] = ['west_east_increment', 'south_north_increment'] expected", Here()); } From 0d0bdbc66a3af1776c9b731af7713240519641d8 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 10 May 2024 07:53:00 +0100 Subject: [PATCH 626/737] eckit::geo::Increments, BoundingBox, Shape immutability --- src/eckit/geo/Increments.h | 18 +++++++++++------- src/eckit/geo/Shape.h | 18 +++++++++++------- src/eckit/geo/area/BoundingBox.h | 14 +++++++++----- src/eckit/geo/grid/Regular.cc | 3 ++- src/eckit/geo/grid/Regular.h | 1 - tests/geo/increments.cc | 6 +++--- 6 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/eckit/geo/Increments.h b/src/eckit/geo/Increments.h index e718bbade..c606091bf 100644 --- a/src/eckit/geo/Increments.h +++ b/src/eckit/geo/Increments.h @@ -26,15 +26,19 @@ namespace eckit::geo { class Increments : public std::array { public: + // -- Types + + using container_type = array; + // -- Constructors explicit Increments(const Spec& spec) : Increments(make_from_spec(spec)) {} Increments(value_type dx, value_type dy); - Increments(const Increments& other) : array(other) {} + Increments(const Increments& other) : container_type(other) {} - Increments(Increments&& other) : array(other) {} + Increments(Increments&& other) : container_type(other) {} // -- Destructor @@ -46,23 +50,23 @@ class Increments : public std::array { bool operator!=(const Increments& other) const { return !operator==(other); } Increments& operator=(const Increments& other) { - array::operator=(other); + container_type::operator=(other); return *this; } Increments& operator=(Increments&& other) { - array::operator=(other); + container_type::operator=(other); return *this; } // Members - value_type& dx = array::operator[](0); - value_type& dy = array::operator[](1); + const value_type& dx = container_type::operator[](0); + const value_type& dy = container_type::operator[](1); // -- Methods - std::array deconstruct() const { return {dx, dy}; } + container_type deconstruct() const { return {dx, dy}; } // -- Class methods diff --git a/src/eckit/geo/Shape.h b/src/eckit/geo/Shape.h index d78bd5070..dfc2d59f2 100644 --- a/src/eckit/geo/Shape.h +++ b/src/eckit/geo/Shape.h @@ -26,6 +26,10 @@ namespace eckit::geo { class Shape final : public std::array { public: + // -- Types + + using container_type = array; + // -- Constructors explicit Shape(const Spec& spec) : Shape(make_from_spec(spec)) {} @@ -34,9 +38,9 @@ class Shape final : public std::array { Shape() : Shape(0, 0) {} - Shape(const Shape& other) : array(other) {} + Shape(const Shape& other) : container_type(other) {} - Shape(Shape&& other) : array(other) {} + Shape(Shape&& other) : container_type(other) {} // -- Destructor @@ -49,23 +53,23 @@ class Shape final : public std::array { bool operator!=(const Shape& other) const { return !operator==(other); } Shape& operator=(const Shape& other) { - array::operator=(other); + container_type::operator=(other); return *this; } Shape& operator=(Shape&& other) { - array::operator=(other); + container_type::operator=(other); return *this; } // Members - value_type& nx = array::operator[](0); - value_type& ny = array::operator[](1); + const value_type& nx = container_type::operator[](0); + const value_type& ny = container_type::operator[](1); // -- Methods - std::array deconstruct() const { return {nx, ny}; } + container_type deconstruct() const { return {nx, ny}; } // -- Class methods diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 9383c4e11..887307acb 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -30,6 +30,10 @@ namespace eckit::geo::area { class BoundingBox : public Area, protected std::array { public: + // -- Types + + using container_type = array; + // -- Constructors explicit BoundingBox(const Spec&); @@ -38,9 +42,9 @@ class BoundingBox : public Area, protected std::array { BoundingBox(); - BoundingBox(const BoundingBox& other) : array(other) {} + BoundingBox(const BoundingBox& other) : container_type(other) {} - BoundingBox(BoundingBox&& other) : array(other) {} + BoundingBox(BoundingBox&& other) : container_type(other) {} // -- Destructor @@ -52,18 +56,18 @@ class BoundingBox : public Area, protected std::array { bool operator!=(const BoundingBox& other) const { return !operator==(other); } BoundingBox& operator=(const BoundingBox& other) { - array::operator=(other); + container_type::operator=(other); return *this; } BoundingBox& operator=(BoundingBox&& other) { - array::operator=(other); + container_type::operator=(other); return *this; } // -- Methods - std::array deconstruct() const { return {north, west, south, east}; } + container_type deconstruct() const { return {north, west, south, east}; } bool isPeriodicWestEast() const; bool containsNorthPole() const; diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index c0bf32a66..ef87fc103 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -16,6 +16,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Increments.h" +#include "eckit/geo/Shape.h" #include "eckit/geo/Spec.h" #include "eckit/geo/etc/Grid.h" #include "eckit/geo/iterator/Regular.h" @@ -77,7 +78,7 @@ std::pair Regular::make_cartesian_ranges_from_spec(const Spec& s // FIXME This is a hack, we should not be using these keys Point2 a{spec.get_double("longitudeOfFirstGridPointInDegrees"), spec.get_double("latitudeOfFirstGridPointInDegrees")}; - Point2 b{a.X + inc.dx * (shape.nx - 1), a.Y - inc.dy * (shape.ny - 1)}; + Point2 b{a.X + inc.dx * static_cast(shape.nx - 1), a.Y - inc.dy * static_cast(shape.ny - 1)}; return {new range::RegularCartesian(shape.nx, a.X, b.X), new range::RegularCartesian(shape.ny, a.Y, b.Y)}; } diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index d4accce1a..037f88d66 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -18,7 +18,6 @@ #include "eckit/geo/Grid.h" #include "eckit/geo/PointLonLat.h" #include "eckit/geo/Range.h" -#include "eckit/geo/Shape.h" namespace eckit::geo { diff --git a/tests/geo/increments.cc b/tests/geo/increments.cc index 24f7f21d3..e33e0c88c 100644 --- a/tests/geo/increments.cc +++ b/tests/geo/increments.cc @@ -42,7 +42,7 @@ CASE("assignment") { EXPECT_EQUAL(a.dx, b.dx); EXPECT_EQUAL(a, b); - b.dx = 30; + b = {30, b.dy}; EXPECT_EQUAL(b.dx, 30); EXPECT_EQUAL(a.dx, 10); @@ -50,14 +50,14 @@ CASE("assignment") { EXPECT_EQUAL(a.dx, c.dx); EXPECT_EQUAL(a, c); - c.dx = 40; + c = {40, c.dy}; EXPECT_EQUAL(c.dx, 40); EXPECT_EQUAL(a.dx, 10); auto d(std::move(a)); EXPECT_EQUAL(d.dx, 10); - d.dx = 50; + d = {50, d.dy}; EXPECT_EQUAL(d.dx, 50); } From ffa9bdbf215be1e917a8493a55441a400141b68b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 10 May 2024 09:27:34 +0100 Subject: [PATCH 627/737] eckit::geo rearranged eccodes projections for merging --- .../geo/projection/LambertAzimuthalEqualArea.cc} | 0 .../geo/projection/LambertConformalConic.cc} | 0 .../geo/projection/PolarStereographic.cc} | 0 .../geo/projection/SpaceView.cc} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/{grib_iterator_class_lambert_azimuthal_equal_area.cc => eckit/geo/projection/LambertAzimuthalEqualArea.cc} (100%) rename src/{grib_iterator_class_lambert_conformal.cc => eckit/geo/projection/LambertConformalConic.cc} (100%) rename src/{grib_iterator_class_polar_stereographic.cc => eckit/geo/projection/PolarStereographic.cc} (100%) rename src/{grib_iterator_class_space_view.cc => eckit/geo/projection/SpaceView.cc} (100%) diff --git a/src/grib_iterator_class_lambert_azimuthal_equal_area.cc b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc similarity index 100% rename from src/grib_iterator_class_lambert_azimuthal_equal_area.cc rename to src/eckit/geo/projection/LambertAzimuthalEqualArea.cc diff --git a/src/grib_iterator_class_lambert_conformal.cc b/src/eckit/geo/projection/LambertConformalConic.cc similarity index 100% rename from src/grib_iterator_class_lambert_conformal.cc rename to src/eckit/geo/projection/LambertConformalConic.cc diff --git a/src/grib_iterator_class_polar_stereographic.cc b/src/eckit/geo/projection/PolarStereographic.cc similarity index 100% rename from src/grib_iterator_class_polar_stereographic.cc rename to src/eckit/geo/projection/PolarStereographic.cc diff --git a/src/grib_iterator_class_space_view.cc b/src/eckit/geo/projection/SpaceView.cc similarity index 100% rename from src/grib_iterator_class_space_view.cc rename to src/eckit/geo/projection/SpaceView.cc From 7e2010e4f6357ffd34ed90126a15cf651a8d4456 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 10 May 2024 09:43:03 +0100 Subject: [PATCH 628/737] eckit::geo rearranged eccodes projections --- src/eckit/geo/CMakeLists.txt | 8 + .../projection/LambertAzimuthalEqualArea.cc | 136 +++++---- .../projection/LambertAzimuthalEqualArea.h | 79 ++++++ .../geo/projection/LambertConformalConic.cc | 265 +++++++++--------- .../geo/projection/LambertConformalConic.h | 80 ++++++ .../geo/projection/PolarStereographic.cc | 193 +++++++------ src/eckit/geo/projection/PolarStereographic.h | 80 ++++++ src/eckit/geo/projection/SpaceView.cc | 84 +++--- src/eckit/geo/projection/SpaceView.h | 80 ++++++ 9 files changed, 654 insertions(+), 351 deletions(-) create mode 100644 src/eckit/geo/projection/LambertAzimuthalEqualArea.h create mode 100644 src/eckit/geo/projection/LambertConformalConic.h create mode 100644 src/eckit/geo/projection/PolarStereographic.h create mode 100644 src/eckit/geo/projection/SpaceView.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 3390bb1f3..1ae519b09 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -72,6 +72,10 @@ list(APPEND eckit_geo_srcs polygon/Polygon.h projection/Composer.cc projection/Composer.h + projection/LambertAzimuthalEqualArea.cc + projection/LambertAzimuthalEqualArea.h + projection/LambertConformalConic.cc + projection/LambertConformalConic.h projection/LonLatToXY.cc projection/LonLatToXY.h projection/LonLatToXYZ.cc @@ -80,8 +84,12 @@ list(APPEND eckit_geo_srcs projection/Mercator.h projection/None.cc projection/None.h + projection/PolarStereographic.cc + projection/PolarStereographic.h projection/Rotation.cc projection/Rotation.h + projection/SpaceView.cc + projection/SpaceView.h projection/XYToLonLat.cc projection/XYToLonLat.h range/GaussianLatitude.cc diff --git a/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc index 24dba1877..d8302e279 100644 --- a/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc @@ -8,8 +8,8 @@ * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction. */ -#include "grib_api_internal.h" #include +#include "grib_api_internal.h" /* This is used by make_class.pl @@ -36,55 +36,54 @@ or edit "iterator.class" and rerun ./make_class.pl */ -static void init_class (grib_iterator_class*); +static void init_class(grib_iterator_class*); -static int init (grib_iterator* i,grib_handle*,grib_arguments*); -static int next (grib_iterator* i, double *lat, double *lon, double *val); -static int destroy (grib_iterator* i); +static int init(grib_iterator* i, grib_handle*, grib_arguments*); +static int next(grib_iterator* i, double* lat, double* lon, double* val); +static int destroy(grib_iterator* i); -typedef struct grib_iterator_lambert_azimuthal_equal_area{ - grib_iterator it; +typedef struct grib_iterator_lambert_azimuthal_equal_area { + grib_iterator it; /* Members defined in gen */ int carg; const char* missingValue; /* Members defined in lambert_azimuthal_equal_area */ - double *lats; - double *lons; + double* lats; + double* lons; long Nj; } grib_iterator_lambert_azimuthal_equal_area; extern grib_iterator_class* grib_iterator_class_gen; static grib_iterator_class _grib_iterator_class_lambert_azimuthal_equal_area = { - &grib_iterator_class_gen, /* super */ - "lambert_azimuthal_equal_area", /* name */ - sizeof(grib_iterator_lambert_azimuthal_equal_area),/* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ + &grib_iterator_class_gen, /* super */ + "lambert_azimuthal_equal_area", /* name */ + sizeof(grib_iterator_lambert_azimuthal_equal_area), /* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ }; -grib_iterator_class* grib_iterator_class_lambert_azimuthal_equal_area = &_grib_iterator_class_lambert_azimuthal_equal_area; +grib_iterator_class* grib_iterator_class_lambert_azimuthal_equal_area + = &_grib_iterator_class_lambert_azimuthal_equal_area; -static void init_class(grib_iterator_class* c) -{ - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; +static void init_class(grib_iterator_class* c) { + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; } /* END_CLASS_IMP */ #define ITER "Lambert azimuthal equal area Geoiterator" -static int next(grib_iterator* iter, double* lat, double* lon, double* val) -{ +static int next(grib_iterator* iter, double* lat, double* lon, double* val) { grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)iter; if ((long)iter->e >= (long)(iter->nv - 1)) @@ -121,8 +120,7 @@ static int next(grib_iterator* iter, double* lat, double* lon, double* val) #define P11 .06640211640211640212 /* 251 / 3780 */ #define P20 .01677689594356261023 /* 761 / 45360 */ -static void pj_authset(double es, double* APA) -{ +static void pj_authset(double es, double* APA) { double t; APA[0] = es * P00; t = es * es; @@ -133,14 +131,12 @@ static void pj_authset(double es, double* APA) APA[1] += t * P11; APA[2] = t * P20; } -static double pj_authlat(double beta, const double* APA) -{ +static double pj_authlat(double beta, const double* APA) { double t = beta + beta; return (beta + APA[0] * sin(t) + APA[1] * sin(t + t) + APA[2] * sin(t + t + t)); } -static double pj_qsfn(double sinphi, double e, double one_es) -{ +static double pj_qsfn(double sinphi, double e, double one_es) { double con, div1, div2; const double EPSILON = 1.0e-7; @@ -160,14 +156,11 @@ static double pj_qsfn(double sinphi, double e, double one_es) } #define EPS10 1.e-10 -static int init_oblate(grib_handle* h, - grib_iterator_lambert_azimuthal_equal_area* self, - size_t nv, long nx, long ny, +static int init_oblate(grib_handle* h, grib_iterator_lambert_azimuthal_equal_area* self, size_t nv, long nx, long ny, double Dx, double Dy, double earthMinorAxisInMetres, double earthMajorAxisInMetres, - double latFirstInRadians, double lonFirstInRadians, - double centralLongitudeInRadians, double standardParallelInRadians, - long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) -{ + double latFirstInRadians, double lonFirstInRadians, double centralLongitudeInRadians, + double standardParallelInRadians, long iScansNegatively, long jScansPositively, + long jPointsAreConsecutive) { double *lats, *lons; long i, j; double x0, y0, x, y; @@ -175,7 +168,9 @@ static int init_oblate(grib_handle* h, double Q__qp = 0, Q__rq = 0, Q__cosb1, Q__sinb1, Q__dd, Q__xmf, Q__ymf, t; /* double Q__mmf = 0; */ double e, es, temp, one_es; - double APA[3] = {0,}; + double APA[3] = { + 0, + }; double xFirst, yFirst; Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; @@ -202,7 +197,7 @@ static int init_oblate(grib_handle* h, else Q->mode = OBLIQ; */ - Q__qp = pj_qsfn(1.0, e, one_es); + Q__qp = pj_qsfn(1.0, e, one_es); /* Q__mmf = 0.5 / one_es; ---- TODO(masn): do I need this? */ pj_authset(es, APA); /* sets up APA array */ Q__rq = sqrt(0.5 * Q__qp); @@ -211,10 +206,11 @@ static int init_oblate(grib_handle* h, Q__cosb1 = sqrt(1.0 - Q__sinb1 * Q__sinb1); if (Q__cosb1 == 0) { Q__dd = 1.0; - } else { + } + else { Q__dd = cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); } - Q__ymf = (Q__xmf = Q__rq) / Q__dd; + Q__ymf = (Q__xmf = Q__rq) / Q__dd; Q__xmf *= Q__dd; sinb = q / Q__qp; @@ -291,14 +287,10 @@ static int init_oblate(grib_handle* h, return GRIB_SUCCESS; } -static int init_sphere(grib_handle* h, - grib_iterator_lambert_azimuthal_equal_area* self, - size_t nv, long nx, long ny, - double Dx, double Dy, double radius, - double latFirstInRadians, double lonFirstInRadians, - double centralLongitudeInRadians, double standardParallelInRadians, - long iScansNegatively, long jScansPositively, long jPointsAreConsecutive) -{ +static int init_sphere(grib_handle* h, grib_iterator_lambert_azimuthal_equal_area* self, size_t nv, long nx, long ny, + double Dx, double Dy, double radius, double latFirstInRadians, double lonFirstInRadians, + double centralLongitudeInRadians, double standardParallelInRadians, long iScansNegatively, + long jScansPositively, long jPointsAreConsecutive) { double *lats, *lons; double phi1, lambda0, xFirst, yFirst, x, y; double kp, sinphi1, cosphi1; @@ -398,8 +390,7 @@ static int init_sphere(grib_handle* h, return GRIB_SUCCESS; } -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) -{ +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { int err = 0; int is_oblate = 0; double lonFirstInDegrees, latFirstInDegrees, lonFirstInRadians, latFirstInRadians, radius = 0; @@ -411,8 +402,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) long jScansPositively, jPointsAreConsecutive; double earthMajorAxisInMetres = 0, earthMinorAxisInMetres = 0; - grib_iterator_lambert_azimuthal_equal_area* self = - (grib_iterator_lambert_azimuthal_equal_area*)iter; + grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)iter; const char* sradius = grib_arguments_get_name(h, args, self->carg++); const char* snx = grib_arguments_get_name(h, args, self->carg++); @@ -431,11 +421,14 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) is_oblate = grib_is_earth_oblate(h); if (is_oblate) { - if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; - if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; + if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) + return err; } else { - if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) return err; + if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) + return err; } if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) @@ -444,7 +437,8 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return err; if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, ny); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, + ny); return GRIB_WRONG_GRID; } if ((err = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) @@ -474,28 +468,24 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) standardParallelInRadians = standardParallelInDegrees * d2r; if (is_oblate) { - err = init_oblate(h, self, iter->nv, nx, ny, - Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, - latFirstInRadians, lonFirstInRadians, - centralLongitudeInRadians, standardParallelInRadians, + err = init_oblate(h, self, iter->nv, nx, ny, Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, + latFirstInRadians, lonFirstInRadians, centralLongitudeInRadians, standardParallelInRadians, iScansNegatively, jScansPositively, jPointsAreConsecutive); } else { - err = init_sphere(h, self, iter->nv, nx, ny, - Dx, Dy, radius, - latFirstInRadians, lonFirstInRadians, - centralLongitudeInRadians, standardParallelInRadians, - iScansNegatively, jScansPositively, jPointsAreConsecutive); + err = init_sphere(h, self, iter->nv, nx, ny, Dx, Dy, radius, latFirstInRadians, lonFirstInRadians, + centralLongitudeInRadians, standardParallelInRadians, iScansNegatively, jScansPositively, + jPointsAreConsecutive); } - if (err) return err; + if (err) + return err; iter->e = -1; return GRIB_SUCCESS; } -static int destroy(grib_iterator* iter) -{ +static int destroy(grib_iterator* iter) { grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)iter; const grib_context* c = iter->h->context; diff --git a/src/eckit/geo/projection/LambertAzimuthalEqualArea.h b/src/eckit/geo/projection/LambertAzimuthalEqualArea.h new file mode 100644 index 000000000..5044a147a --- /dev/null +++ b/src/eckit/geo/projection/LambertAzimuthalEqualArea.h @@ -0,0 +1,79 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Projection.h" + + +namespace eckit::geo::projection { + + +class LambertAzimuthalEqualArea final : public Projection { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + explicit LambertAzimuthalEqualArea(const Spec&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + Point fwd(const Point&) const override; + Point inv(const Point&) const override; + + [[nodiscard]] Spec* spec() const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LambertConformalConic.cc b/src/eckit/geo/projection/LambertConformalConic.cc index 5d15a67b6..72cb94c6a 100644 --- a/src/eckit/geo/projection/LambertConformalConic.cc +++ b/src/eckit/geo/projection/LambertConformalConic.cc @@ -8,8 +8,8 @@ * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction. */ -#include "grib_api_internal.h" #include +#include "grib_api_internal.h" /* This is used by make_class.pl @@ -36,48 +36,47 @@ or edit "iterator.class" and rerun ./make_class.pl */ -static void init_class (grib_iterator_class*); +static void init_class(grib_iterator_class*); -static int init (grib_iterator* i,grib_handle*,grib_arguments*); -static int next (grib_iterator* i, double *lat, double *lon, double *val); -static int destroy (grib_iterator* i); +static int init(grib_iterator* i, grib_handle*, grib_arguments*); +static int next(grib_iterator* i, double* lat, double* lon, double* val); +static int destroy(grib_iterator* i); -typedef struct grib_iterator_lambert_conformal{ - grib_iterator it; +typedef struct grib_iterator_lambert_conformal { + grib_iterator it; /* Members defined in gen */ int carg; const char* missingValue; /* Members defined in lambert_conformal */ - double *lats; - double *lons; + double* lats; + double* lons; long Nj; } grib_iterator_lambert_conformal; extern grib_iterator_class* grib_iterator_class_gen; static grib_iterator_class _grib_iterator_class_lambert_conformal = { - &grib_iterator_class_gen, /* super */ - "lambert_conformal", /* name */ - sizeof(grib_iterator_lambert_conformal),/* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ + &grib_iterator_class_gen, /* super */ + "lambert_conformal", /* name */ + sizeof(grib_iterator_lambert_conformal), /* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ }; grib_iterator_class* grib_iterator_class_lambert_conformal = &_grib_iterator_class_lambert_conformal; -static void init_class(grib_iterator_class* c) -{ - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; +static void init_class(grib_iterator_class* c) { + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; } /* END_CLASS_IMP */ @@ -85,25 +84,26 @@ static void init_class(grib_iterator_class* c) #define EPSILON 1.0e-10 #ifndef M_PI -#define M_PI 3.14159265358979323846 // Whole pie +#define M_PI 3.14159265358979323846 // Whole pie #endif #ifndef M_PI_2 -#define M_PI_2 1.57079632679489661923 // Half a pie +#define M_PI_2 1.57079632679489661923 // Half a pie #endif #ifndef M_PI_4 -#define M_PI_4 0.78539816339744830962 // Quarter of a pie +#define M_PI_4 0.78539816339744830962 // Quarter of a pie #endif -#define RAD2DEG 57.29577951308232087684 // 180 over pi -#define DEG2RAD 0.01745329251994329576 // pi over 180 +#define RAD2DEG 57.29577951308232087684 // 180 over pi +#define DEG2RAD 0.01745329251994329576 // pi over 180 // Adjust longitude (in radians) to range -180 to 180 -static double adjust_lon_radians(double lon) -{ - if (lon > M_PI) lon -= 2 * M_PI; - if (lon < -M_PI) lon += 2 * M_PI; +static double adjust_lon_radians(double lon) { + if (lon > M_PI) + lon -= 2 * M_PI; + if (lon < -M_PI) + lon += 2 * M_PI; return lon; } @@ -113,11 +113,9 @@ static double adjust_lon_radians(double lon) // Then, assuming an initial trial phi equal to (pi/2 - 2*arctan t) in the right side of equation (7-9), // calculate phi on the left side. Substitute the calculated phi) into the right side, // calculate a new phi, etc., until phi does not change significantly from the preceding trial value of phi -static double compute_phi( - double eccent, // Spheroid eccentricity - double ts, // Constant value t - int* error) -{ +static double compute_phi(double eccent, // Spheroid eccentricity + double ts, // Constant value t + int* error) { double eccnth, phi, con, dphi, sinpi; int i, MAX_ITER = 15; @@ -137,17 +135,15 @@ static double compute_phi( // Compute the constant small m which is the radius of // a parallel of latitude, phi, divided by the semimajor axis -static double compute_m(double eccent, double sinphi, double cosphi) -{ +static double compute_m(double eccent, double sinphi, double cosphi) { const double con = eccent * sinphi; return ((cosphi / (sqrt(1.0 - con * con)))); } // Compute the constant small t for use in the forward computations -static double compute_t( - double eccent, // Eccentricity of the spheroid - double phi, // Latitude phi - double sinphi) // Sine of the latitude +static double compute_t(double eccent, // Eccentricity of the spheroid + double phi, // Latitude phi + double sinphi) // Sine of the latitude { double con = eccent * sinphi; double com = 0.5 * eccent; @@ -155,32 +151,29 @@ static double compute_t( return (tan(0.5 * (M_PI_2 - phi)) / con); } -static double calculate_eccentricity(double minor, double major) -{ +static double calculate_eccentricity(double minor, double major) { const double temp = minor / major; return sqrt(1.0 - temp * temp); } -static void xy2lonlat(double radius, double n, double f, double rho0_bare, double LoVInRadians, - double x, double y, - double* lonDeg, double* latDeg) -{ +static void xy2lonlat(double radius, double n, double f, double rho0_bare, double LoVInRadians, double x, double y, + double* lonDeg, double* latDeg) { DEBUG_ASSERT(radius > 0); DEBUG_ASSERT(n != 0.0); x /= radius; y /= radius; - y = rho0_bare - y; + y = rho0_bare - y; double rho = hypot(x, y); if (rho != 0.0) { if (n < 0.0) { rho = -rho; - x = -x; - y = -y; + x = -x; + y = -y; } - double latRadians = 2. * atan(pow(f / rho, 1.0/n)) - M_PI_2; + double latRadians = 2. * atan(pow(f / rho, 1.0 / n)) - M_PI_2; double lonRadians = atan2(x, y) / n; - *lonDeg = (lonRadians + LoVInRadians) * RAD2DEG; - *latDeg = latRadians * RAD2DEG; + *lonDeg = (lonRadians + LoVInRadians) * RAD2DEG; + *latDeg = latRadians * RAD2DEG; } else { *lonDeg = 0.0; @@ -188,29 +181,25 @@ static void xy2lonlat(double radius, double n, double f, double rho0_bare, doubl } } -static int init_sphere(const grib_handle* h, - grib_iterator_lambert_conformal* self, - size_t nv, long nx, long ny, - double LoVInDegrees, - double Dx, double Dy, double radius, - double latFirstInRadians, double lonFirstInRadians, - double LoVInRadians, double Latin1InRadians, double Latin2InRadians, - double LaDInRadians) -{ +static int init_sphere(const grib_handle* h, grib_iterator_lambert_conformal* self, size_t nv, long nx, long ny, + double LoVInDegrees, double Dx, double Dy, double radius, double latFirstInRadians, + double lonFirstInRadians, double LoVInRadians, double Latin1InRadians, double Latin2InRadians, + double LaDInRadians) { double n, x, y; if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { n = sin(Latin1InRadians); - } else { - n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) / - log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); + } + else { + n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) + / log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); } - double f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; - double rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); + double f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; + double rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); double rho0_bare = f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); - double rho0 = radius * rho0_bare; // scaled - double lonDiff = lonFirstInRadians - LoVInRadians; + double rho0 = radius * rho0_bare; // scaled + double lonDiff = lonFirstInRadians - LoVInRadians; // Adjust longitude to range -180 to 180 if (lonDiff > M_PI) @@ -241,7 +230,7 @@ static int init_sphere(const grib_handle* h, y = y0 + j * Dy; for (long i = 0; i < nx; i++) { const long index = i + j * nx; - x = x0 + i * Dx; + x = x0 + i * Dx; xy2lonlat(radius, n, f, rho0_bare, LoVInRadians, x, y, &lonDeg, &latDeg); self->lons[index] = lonDeg; self->lats[index] = latDeg; @@ -277,32 +266,26 @@ static int init_sphere(const grib_handle* h, } // Oblate spheroid -static int init_oblate(const grib_handle* h, - grib_iterator_lambert_conformal* self, - size_t nv, long nx, long ny, - double LoVInDegrees, - double Dx, double Dy, - double earthMinorAxisInMetres, double earthMajorAxisInMetres, - double latFirstInRadians, double lonFirstInRadians, - double LoVInRadians, double Latin1InRadians, double Latin2InRadians, - double LaDInRadians) -{ +static int init_oblate(const grib_handle* h, grib_iterator_lambert_conformal* self, size_t nv, long nx, long ny, + double LoVInDegrees, double Dx, double Dy, double earthMinorAxisInMetres, + double earthMajorAxisInMetres, double latFirstInRadians, double lonFirstInRadians, + double LoVInRadians, double Latin1InRadians, double Latin2InRadians, double LaDInRadians) { int i, j, err = 0; double x0, y0, x, y, latRad, lonRad, latDeg, lonDeg, sinphi, ts, rh1, theta; - double false_easting; // x offset in meters - double false_northing; // y offset in meters - - double ns; // ratio of angle between meridian - double F; // flattening of ellipsoid - double rh; // height above ellipsoid - double sin_po; // sin value - double cos_po; // cos value - double con; // temporary variable - double ms1; // small m 1 - double ms2; // small m 2 - double ts0; // small t 0 - double ts1; // small t 1 - double ts2; // small t 2 + double false_easting; // x offset in meters + double false_northing; // y offset in meters + + double ns; // ratio of angle between meridian + double F; // flattening of ellipsoid + double rh; // height above ellipsoid + double sin_po; // sin value + double cos_po; // cos value + double con; // temporary variable + double ms1; // small m 1 + double ms2; // small m 2 + double ts0; // small t 0 + double ts1; // small t 1 + double ts2; // small t 2 double e = calculate_eccentricity(earthMinorAxisInMetres, earthMajorAxisInMetres); @@ -321,10 +304,11 @@ static int init_oblate(const grib_handle* h, if (fabs(Latin1InRadians - Latin2InRadians) > EPSILON) { ns = log(ms1 / ms2) / log(ts1 / ts2); - } else { + } + else { ns = con; } - F = ms1 / (ns * pow(ts1, ns)); + F = ms1 / (ns * pow(ts1, ns)); rh = earthMajorAxisInMetres * F * pow(ts0, ns); // Forward projection: convert lat,lon to x,y @@ -333,10 +317,12 @@ static int init_oblate(const grib_handle* h, sinphi = sin(latFirstInRadians); ts = compute_t(e, latFirstInRadians, sinphi); rh1 = earthMajorAxisInMetres * F * pow(ts, ns); - } else { + } + else { con = latFirstInRadians * ns; if (con <= 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Point cannot be projected: latFirstInRadians=%g", ITER, latFirstInRadians); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Point cannot be projected: latFirstInRadians=%g", ITER, + latFirstInRadians); return GRIB_GEOCALCULUS_PROBLEM; } rh1 = 0; @@ -369,8 +355,8 @@ static int init_oblate(const grib_handle* h, double _x, _y; x = i * Dx; // Inverse projection to convert from x,y to lat,lon - _x = x - false_easting; - _y = rh - y + false_northing; + _x = x - false_easting; + _y = rh - y + false_northing; rh1 = sqrt(_x * _x + _y * _y); con = 1.0; if (ns <= 0) { @@ -391,15 +377,16 @@ static int init_oblate(const grib_handle* h, grib_context_free(h->context, self->lons); return err; } - } else { + } + else { latRad = -M_PI_2; } lonRad = adjust_lon_radians(theta / ns + LoVInRadians); if (i == 0 && j == 0) { DEBUG_ASSERT(fabs(latFirstInRadians - latRad) <= EPSILON); } - latDeg = latRad * RAD2DEG; // Convert to degrees - lonDeg = normalise_longitude_in_degrees(lonRad * RAD2DEG); + latDeg = latRad * RAD2DEG; // Convert to degrees + lonDeg = normalise_longitude_in_degrees(lonRad * RAD2DEG); self->lons[index] = lonDeg; self->lats[index] = latDeg; } @@ -407,15 +394,13 @@ static int init_oblate(const grib_handle* h, return GRIB_SUCCESS; } -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) -{ +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { int err = 0, is_oblate = 0; long nx, ny, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning; - double LoVInDegrees, LaDInDegrees, Latin1InDegrees, Latin2InDegrees, latFirstInDegrees, - lonFirstInDegrees, Dx, Dy, radius = 0; - double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, - LaDInRadians; - double earthMajorAxisInMetres=0, earthMinorAxisInMetres=0; + double LoVInDegrees, LaDInDegrees, Latin1InDegrees, Latin2InDegrees, latFirstInDegrees, lonFirstInDegrees, Dx, Dy, + radius = 0; + double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians; + double earthMajorAxisInMetres = 0, earthMinorAxisInMetres = 0; grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; @@ -436,20 +421,27 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); - if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) return err; - if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) return err; + if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) + return err; is_oblate = grib_is_earth_oblate(h); if (is_oblate) { - if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) return err; - if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) return err; - } else { - if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) return err; + if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) + return err; + if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) + return err; + } + else { + if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) + return err; } if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, ny); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, + ny); return GRIB_WRONG_GRID; } @@ -496,32 +488,26 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) LoVInRadians = LoVInDegrees * DEG2RAD; if (is_oblate) { - err = init_oblate(h, self, iter->nv, nx, ny, - LoVInDegrees, - Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, - latFirstInRadians, lonFirstInRadians, - LoVInRadians, Latin1InRadians, Latin2InRadians, - LaDInRadians); - } else { - err = init_sphere(h, self, iter->nv, nx, ny, - LoVInDegrees, - Dx, Dy, radius, - latFirstInRadians, lonFirstInRadians, + err = init_oblate(h, self, iter->nv, nx, ny, LoVInDegrees, Dx, Dy, earthMinorAxisInMetres, + earthMajorAxisInMetres, latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, + Latin2InRadians, LaDInRadians); + } + else { + err = init_sphere(h, self, iter->nv, nx, ny, LoVInDegrees, Dx, Dy, radius, latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians); } - if (err) return err; + if (err) + return err; iter->e = -1; // Apply the scanning mode flags which may require data array to be transformed - err = transform_iterator_data(h->context, iter->data, - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, - iter->nv, nx, ny); + err = transform_iterator_data(h->context, iter->data, iScansNegatively, jScansPositively, jPointsAreConsecutive, + alternativeRowScanning, iter->nv, nx, ny); return err; } -static int next(grib_iterator* iter, double* lat, double* lon, double* val) -{ +static int next(grib_iterator* iter, double* lat, double* lon, double* val) { grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; if ((long)iter->e >= (long)(iter->nv - 1)) @@ -536,8 +522,7 @@ static int next(grib_iterator* iter, double* lat, double* lon, double* val) return 1; } -static int destroy(grib_iterator* i) -{ +static int destroy(grib_iterator* i) { grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; const grib_context* c = i->h->context; diff --git a/src/eckit/geo/projection/LambertConformalConic.h b/src/eckit/geo/projection/LambertConformalConic.h new file mode 100644 index 000000000..eeb124027 --- /dev/null +++ b/src/eckit/geo/projection/LambertConformalConic.h @@ -0,0 +1,80 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Projection.h" + + +namespace eckit::geo::projection { + + +class LambertConformalConic final : public Projection { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + LambertConformalConic(); + explicit LambertConformalConic(const Spec&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + Point fwd(const Point&) const override; + Point inv(const Point&) const override; + + [[nodiscard]] Spec* spec() const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/PolarStereographic.cc b/src/eckit/geo/projection/PolarStereographic.cc index 1f0c59d69..020feff1c 100644 --- a/src/eckit/geo/projection/PolarStereographic.cc +++ b/src/eckit/geo/projection/PolarStereographic.cc @@ -8,8 +8,8 @@ * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction. */ -#include "grib_api_internal.h" #include +#include "grib_api_internal.h" /* This is used by make_class.pl @@ -36,55 +36,53 @@ or edit "iterator.class" and rerun ./make_class.pl */ -static void init_class (grib_iterator_class*); +static void init_class(grib_iterator_class*); -static int init (grib_iterator* i,grib_handle*,grib_arguments*); -static int next (grib_iterator* i, double *lat, double *lon, double *val); -static int destroy (grib_iterator* i); +static int init(grib_iterator* i, grib_handle*, grib_arguments*); +static int next(grib_iterator* i, double* lat, double* lon, double* val); +static int destroy(grib_iterator* i); -typedef struct grib_iterator_polar_stereographic{ - grib_iterator it; +typedef struct grib_iterator_polar_stereographic { + grib_iterator it; /* Members defined in gen */ int carg; const char* missingValue; /* Members defined in polar_stereographic */ - double *lats; - double *lons; + double* lats; + double* lons; long Nj; } grib_iterator_polar_stereographic; extern grib_iterator_class* grib_iterator_class_gen; static grib_iterator_class _grib_iterator_class_polar_stereographic = { - &grib_iterator_class_gen, /* super */ - "polar_stereographic", /* name */ - sizeof(grib_iterator_polar_stereographic),/* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ + &grib_iterator_class_gen, /* super */ + "polar_stereographic", /* name */ + sizeof(grib_iterator_polar_stereographic), /* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ }; grib_iterator_class* grib_iterator_class_polar_stereographic = &_grib_iterator_class_polar_stereographic; -static void init_class(grib_iterator_class* c) -{ - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; +static void init_class(grib_iterator_class* c) { + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; } /* END_CLASS_IMP */ #define ITER "Polar stereographic Geoiterator" -static int next(grib_iterator* iter, double* lat, double* lon, double* val) -{ +static int next(grib_iterator* iter, double* lat, double* lon, double* val) { grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)iter; if ((long)iter->e >= (long)(iter->nv - 1)) @@ -100,8 +98,7 @@ static int next(grib_iterator* iter, double* lat, double* lon, double* val) } /* Data struct for Forward and Inverse Projections */ -typedef struct proj_data_t -{ +typedef struct proj_data_t { double centre_lon; /* central longitude */ double centre_lat; /* central latitude */ double sign; /* sign variable */ @@ -117,8 +114,7 @@ typedef struct proj_data_t #define PI_OVER_2 1.5707963267948966 /* half pi */ #define EPSILON 1.0e-10 -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) -{ +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { int ret = 0; double *lats, *lons; /* arrays for latitudes and longitudes */ double lonFirstInDegrees, latFirstInDegrees, radius; @@ -132,8 +128,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) double ts; /* value of small t */ double height; /* height above ellipsoid */ double x0, y0, lonFirst, latFirst; - proj_data_t fwd_proj_data = {0,}; - proj_data_t inv_proj_data = {0,}; + proj_data_t fwd_proj_data = { + 0, + }; + proj_data_t inv_proj_data = { + 0, + }; grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)iter; @@ -165,7 +165,8 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return ret; if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, ny); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, + ny); return GRIB_WRONG_GRID; } if ((ret = grib_get_double_internal(h, s_latFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) @@ -294,77 +295,75 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) y += Dy; } -// /*standardParallel = (southPoleOnPlane == 1) ? -90 : +90;*/ -// if (jPointsAreConsecutive) -// { -// x=xFirst; -// for (i=0;i360) *lons -= 360; -// lons++; -// lats++; -// y+=Dy; -// } -// x+=Dx; -// } -// } -// else -// { -// y=yFirst; -// for (j=0;j360) *lons -= 360; -// lons++; -// lats++; -// x+=Dx; -// } -// y+=Dy; -// } -// } + // /*standardParallel = (southPoleOnPlane == 1) ? -90 : +90;*/ + // if (jPointsAreConsecutive) + // { + // x=xFirst; + // for (i=0;i360) *lons -= 360; + // lons++; + // lats++; + // y+=Dy; + // } + // x+=Dx; + // } + // } + // else + // { + // y=yFirst; + // for (j=0;j360) *lons -= 360; + // lons++; + // lats++; + // x+=Dx; + // } + // y+=Dy; + // } + // } iter->e = -1; /* Apply the scanning mode flags which may require data array to be transformed */ - ret = transform_iterator_data(h->context, iter->data, - iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning, - iter->nv, nx, ny); + ret = transform_iterator_data(h->context, iter->data, iScansNegatively, jScansPositively, jPointsAreConsecutive, + alternativeRowScanning, iter->nv, nx, ny); return ret; } -static int destroy(grib_iterator* i) -{ +static int destroy(grib_iterator* i) { grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; const grib_context* c = i->h->context; diff --git a/src/eckit/geo/projection/PolarStereographic.h b/src/eckit/geo/projection/PolarStereographic.h new file mode 100644 index 000000000..71f28abc3 --- /dev/null +++ b/src/eckit/geo/projection/PolarStereographic.h @@ -0,0 +1,80 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Projection.h" + + +namespace eckit::geo::projection { + + +class PolarStereographic final : public Projection { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + PolarStereographic(); + explicit PolarStereographic(const Spec&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + Point fwd(const Point&) const override; + Point inv(const Point&) const override; + + [[nodiscard]] Spec* spec() const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/SpaceView.cc b/src/eckit/geo/projection/SpaceView.cc index 1622f94a5..66e7d4684 100644 --- a/src/eckit/geo/projection/SpaceView.cc +++ b/src/eckit/geo/projection/SpaceView.cc @@ -8,8 +8,8 @@ * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction. */ -#include "grib_api_internal.h" #include +#include "grib_api_internal.h" /* This is used by make_class.pl @@ -36,55 +36,53 @@ or edit "iterator.class" and rerun ./make_class.pl */ -static void init_class (grib_iterator_class*); +static void init_class(grib_iterator_class*); -static int init (grib_iterator* i,grib_handle*,grib_arguments*); -static int next (grib_iterator* i, double *lat, double *lon, double *val); -static int destroy (grib_iterator* i); +static int init(grib_iterator* i, grib_handle*, grib_arguments*); +static int next(grib_iterator* i, double* lat, double* lon, double* val); +static int destroy(grib_iterator* i); -typedef struct grib_iterator_space_view{ - grib_iterator it; +typedef struct grib_iterator_space_view { + grib_iterator it; /* Members defined in gen */ int carg; const char* missingValue; /* Members defined in space_view */ - double *lats; - double *lons; + double* lats; + double* lons; long Nj; } grib_iterator_space_view; extern grib_iterator_class* grib_iterator_class_gen; static grib_iterator_class _grib_iterator_class_space_view = { - &grib_iterator_class_gen, /* super */ - "space_view", /* name */ - sizeof(grib_iterator_space_view),/* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ + &grib_iterator_class_gen, /* super */ + "space_view", /* name */ + sizeof(grib_iterator_space_view), /* size of instance */ + 0, /* inited */ + &init_class, /* init_class */ + &init, /* constructor */ + &destroy, /* destructor */ + &next, /* Next Value */ + 0, /* Previous Value */ + 0, /* Reset the counter */ + 0, /* has next values */ }; grib_iterator_class* grib_iterator_class_space_view = &_grib_iterator_class_space_view; -static void init_class(grib_iterator_class* c) -{ - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; +static void init_class(grib_iterator_class* c) { + c->previous = (*(c->super))->previous; + c->reset = (*(c->super))->reset; + c->has_next = (*(c->super))->has_next; } /* END_CLASS_IMP */ #define ITER "Space view Geoiterator" -static int next(grib_iterator* iter, double* lat, double* lon, double* val) -{ +static int next(grib_iterator* iter, double* lat, double* lon, double* val) { grib_iterator_space_view* self = (grib_iterator_space_view*)iter; if ((long)iter->e >= (long)(iter->nv - 1)) @@ -127,11 +125,13 @@ static int next(grib_iterator* iter, double* lat, double* lon, double* val) // *dx = *dy = 1184; // *xp = *yp = 635; // } -// else if (satelliteIdentifier == 259 && channelNumber == 4 && *dx == 1185) { /* GOES-15 (West) channel 4 */ +// else if (satelliteIdentifier == 259 && channelNumber == 4 && *dx == 1185) { /* GOES-15 (West) channel 4 +// */ // *dx = *dy = 880; // *xp = *yp = 450; // } -// else if (satelliteIdentifier == 57 && *dx == 1732) { /* MSG (Meteosat second generation), non-HRV channels */ +// else if (satelliteIdentifier == 57 && *dx == 1732) { /* MSG (Meteosat second generation), non-HRV +// channels */ // *dx = *dy = 1811; // *xp = *yp = 928; // } @@ -142,11 +142,10 @@ static int next(grib_iterator* iter, double* lat, double* lon, double* val) #define RAD2DEG 57.29577951308232087684 /* 180 over pi */ #define DEG2RAD 0.01745329251994329576 /* pi over 180 */ -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) -{ +static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { /* REFERENCE: - * LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) - */ + * LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) + */ int ret = GRIB_SUCCESS; double *lats, *lons; /* arrays of latitudes and longitudes */ double latOfSubSatellitePointInDegrees, lonOfSubSatellitePointInDegrees; @@ -208,12 +207,15 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, ny); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, + ny); return GRIB_WRONG_GRID; } - if ((ret = grib_get_double_internal(h, sLatOfSubSatellitePointInDegrees, &latOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sLatOfSubSatellitePointInDegrees, &latOfSubSatellitePointInDegrees)) + != GRIB_SUCCESS) return ret; - if ((ret = grib_get_double_internal(h, sLonOfSubSatellitePointInDegrees, &lonOfSubSatellitePointInDegrees)) != GRIB_SUCCESS) + if ((ret = grib_get_double_internal(h, sLonOfSubSatellitePointInDegrees, &lonOfSubSatellitePointInDegrees)) + != GRIB_SUCCESS) return ret; if ((ret = grib_get_double_internal(h, sDx, &dx)) != GRIB_SUCCESS) return ret; @@ -256,7 +258,8 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) } if (nrInRadiusOfEarth == 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Key %s must be greater than zero", ITER, sNrInRadiusOfEarthScaled); + grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Key %s must be greater than zero", ITER, + sNrInRadiusOfEarthScaled); return GRIB_GEOCALCULUS_PROBLEM; } @@ -267,8 +270,8 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) lop = lonOfSubSatellitePointInDegrees; if (lap != 0.0) { grib_context_log(h->context, GRIB_LOG_ERROR, - "%s: Key %s must be 0 (satellite must be located in the equator plane)", - ITER, sLatOfSubSatellitePointInDegrees); + "%s: Key %s must be 0 (satellite must be located in the equator plane)", ITER, + sLatOfSubSatellitePointInDegrees); return GRIB_GEOCALCULUS_PROBLEM; } @@ -378,8 +381,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) return ret; } -static int destroy(grib_iterator* iter) -{ +static int destroy(grib_iterator* iter) { grib_iterator_space_view* self = (grib_iterator_space_view*)iter; const grib_context* c = iter->h->context; diff --git a/src/eckit/geo/projection/SpaceView.h b/src/eckit/geo/projection/SpaceView.h new file mode 100644 index 000000000..0d934ac69 --- /dev/null +++ b/src/eckit/geo/projection/SpaceView.h @@ -0,0 +1,80 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Projection.h" + + +namespace eckit::geo::projection { + + +class SpaceView final : public Projection { +public: + // -- Types + // None + + // -- Exceptions + // None + + // -- Constructors + + SpaceView(); + explicit SpaceView(const Spec&); + + // -- Destructor + // None + + // -- Convertors + // None + + // -- Operators + // None + + // -- Methods + // None + + // -- Overridden methods + + Point fwd(const Point&) const override; + Point inv(const Point&) const override; + + [[nodiscard]] Spec* spec() const override; + + // -- Class members + // None + + // -- Class methods + // None + +private: + // -- Members + // None + + // -- Methods + // None + + // -- Overridden methods + // None + + // -- Class members + // None + + // -- Class methods + // None + + // -- Friends + // None +}; + + +} // namespace eckit::geo::projection From 17fd6dc0285f98fe7ee6d00191166933f4705277 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 10 May 2024 10:48:40 +0100 Subject: [PATCH 629/737] eckit::geo rearranged eccodes projections --- .../projection/LambertAzimuthalEqualArea.cc | 153 ++++---------- .../geo/projection/LambertConformalConic.cc | 159 +++++---------- .../geo/projection/LambertConformalConic.h | 1 - .../geo/projection/PolarStereographic.cc | 190 ++++-------------- src/eckit/geo/projection/PolarStereographic.h | 1 - src/eckit/geo/projection/SpaceView.cc | 151 ++------------ src/eckit/geo/projection/SpaceView.h | 1 - 7 files changed, 143 insertions(+), 513 deletions(-) diff --git a/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc index d8302e279..2c65be1c9 100644 --- a/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc @@ -1,124 +1,54 @@ /* - * (C) Copyright 2005- ECMWF. + * (C) Copyright 1996- 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. + * 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 -#include "grib_api_internal.h" - -/* - This is used by make_class.pl - - START_CLASS_DEF - CLASS = iterator - SUPER = grib_iterator_class_gen - IMPLEMENTS = destroy - IMPLEMENTS = init;next - MEMBERS = double *lats - MEMBERS = double *lons - MEMBERS = long Nj - 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 "iterator.class" and rerun ./make_class.pl +#include "eckit/geo/projection/LambertAzimuthalEqualArea.h" -*/ - - -static void init_class(grib_iterator_class*); - -static int init(grib_iterator* i, grib_handle*, grib_arguments*); -static int next(grib_iterator* i, double* lat, double* lon, double* val); -static int destroy(grib_iterator* i); +#include +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/util.h" -typedef struct grib_iterator_lambert_azimuthal_equal_area { - grib_iterator it; - /* Members defined in gen */ - int carg; - const char* missingValue; - /* Members defined in lambert_azimuthal_equal_area */ - double* lats; - double* lons; - long Nj; -} grib_iterator_lambert_azimuthal_equal_area; -extern grib_iterator_class* grib_iterator_class_gen; +namespace eckit::geo::projection { -static grib_iterator_class _grib_iterator_class_lambert_azimuthal_equal_area = { - &grib_iterator_class_gen, /* super */ - "lambert_azimuthal_equal_area", /* name */ - sizeof(grib_iterator_lambert_azimuthal_equal_area), /* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ -}; -grib_iterator_class* grib_iterator_class_lambert_azimuthal_equal_area - = &_grib_iterator_class_lambert_azimuthal_equal_area; +LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Spec&) {} -static void init_class(grib_iterator_class* c) { - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; +Point LambertAzimuthalEqualArea::fwd(const Point&) const { + NOTIMP; } -/* END_CLASS_IMP */ -#define ITER "Lambert azimuthal equal area Geoiterator" -static int next(grib_iterator* iter, double* lat, double* lon, double* val) { - grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)iter; +Point LambertAzimuthalEqualArea::inv(const Point&) const { + NOTIMP; +} - if ((long)iter->e >= (long)(iter->nv - 1)) - return 0; - iter->e++; - *lat = self->lats[iter->e]; - *lon = self->lons[iter->e]; - if (val && iter->data) { - *val = iter->data[iter->e]; - } - return 1; +Spec* LambertAzimuthalEqualArea::spec() const { + NOTIMP; } -#ifndef M_PI -#define M_PI 3.14159265358979323846 /* Whole pie */ -#endif - -#ifndef M_PI_2 -#define M_PI_2 1.57079632679489661923 /* Half a pie */ -#endif -#ifndef M_PI_4 -#define M_PI_4 0.78539816339744830962 /* Quarter of a pie */ -#endif +#if 0 +static constexpr double EPSILON = 1e-10; -#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ -#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +static constexpr double P00 = .33333333333333333333; // 1 / 3 +static constexpr double P01 = .17222222222222222222; // 31 / 180 +static constexpr double P02 = .10257936507936507937; // 517 / 5040 +static constexpr double P10 = .06388888888888888888; // 23 / 360 +static constexpr double P11 = .06640211640211640212; // 251 / 3780 +static constexpr double P20 = .01677689594356261023; // 761 / 45360 -#define P00 .33333333333333333333 /* 1 / 3 */ -#define P01 .17222222222222222222 /* 31 / 180 */ -#define P02 .10257936507936507937 /* 517 / 5040 */ -#define P10 .06388888888888888888 /* 23 / 360 */ -#define P11 .06640211640211640212 /* 251 / 3780 */ -#define P20 .01677689594356261023 /* 761 / 45360 */ static void pj_authset(double es, double* APA) { double t; @@ -131,16 +61,18 @@ static void pj_authset(double es, double* APA) { APA[1] += t * P11; APA[2] = t * P20; } + + static double pj_authlat(double beta, const double* APA) { double t = beta + beta; return (beta + APA[0] * sin(t) + APA[1] * sin(t + t) + APA[2] * sin(t + t + t)); } + static double pj_qsfn(double sinphi, double e, double one_es) { double con, div1, div2; - const double EPSILON = 1.0e-7; - if (e >= EPSILON) { + if (e >= 1.0e-7) { con = e * sinphi; div1 = 1.0 - con * con; div2 = 1.0 + con; @@ -155,7 +87,7 @@ static double pj_qsfn(double sinphi, double e, double one_es) { return (sinphi + sinphi); } -#define EPS10 1.e-10 + static int init_oblate(grib_handle* h, grib_iterator_lambert_azimuthal_equal_area* self, size_t nv, long nx, long ny, double Dx, double Dy, double earthMinorAxisInMetres, double earthMajorAxisInMetres, double latFirstInRadians, double lonFirstInRadians, double centralLongitudeInRadians, @@ -187,12 +119,12 @@ static int init_oblate(grib_handle* h, grib_iterator_lambert_azimuthal_equal_are q = pj_qsfn(sinphi, e, one_es); t = fabs(standardParallelInRadians); - if (t > M_PI_2 + EPS10) { + if (t > M_PI_2 + EPSILON) { return GRIB_GEOCALCULUS_PROBLEM; } - /* if (fabs(t - M_HALFPI) < EPS10) + /* if (fabs(t - M_HALFPI) < EPSILON) Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; - else if (fabs(t) < EPS10) + else if (fabs(t) < EPSILON) Q->mode = EQUIT; else Q->mode = OBLIQ; @@ -217,7 +149,7 @@ static int init_oblate(grib_handle* h, grib_iterator_lambert_azimuthal_equal_are cosb2 = 1.0 - sinb * sinb; cosb = cosb2 > 0 ? sqrt(cosb2) : 0; b = 1. + Q__sinb1 * sinb + Q__cosb1 * cosb * coslam; - if (fabs(b) < EPS10) { + if (fabs(b) < EPSILON) { return GRIB_GEOCALCULUS_PROBLEM; } b = sqrt(2.0 / b); @@ -252,7 +184,7 @@ static int init_oblate(grib_handle* h, grib_iterator_lambert_azimuthal_equal_are xy_x /= Q__dd; xy_y *= Q__dd; rho = hypot(xy_x, xy_y); - Assert(rho >= EPS10); /* TODO(masn): check */ + ASSERT(rho >= EPSILON); /* TODO(masn): check */ const double asin_arg = (0.5 * rho / Q__rq); if (asin_arg < -1.0 || asin_arg > 1.0) { grib_context_log(h->context, GRIB_LOG_ERROR, "Invalid value: arcsin argument=%g", asin_arg); @@ -272,8 +204,8 @@ static int init_oblate(grib_handle* h, grib_iterator_lambert_azimuthal_equal_are lp__lam = atan2(xy_x, xy_y); /* longitude */ lp__phi = pj_authlat(asin(ab), APA); /* latitude */ - *lats = lp__phi * RAD2DEG; - *lons = (lp__lam + centralLongitudeInRadians) * RAD2DEG; + *lats = lp__phi * util::RADIAN_TO_DEGREE; + *lons = (lp__lam + centralLongitudeInRadians) * util::RADIAN_TO_DEGREE; lons++; lats++; @@ -287,6 +219,7 @@ static int init_oblate(grib_handle* h, grib_iterator_lambert_azimuthal_equal_are return GRIB_SUCCESS; } + static int init_sphere(grib_handle* h, grib_iterator_lambert_azimuthal_equal_area* self, size_t nv, long nx, long ny, double Dx, double Dy, double radius, double latFirstInRadians, double lonFirstInRadians, double centralLongitudeInRadians, double standardParallelInRadians, long iScansNegatively, @@ -390,6 +323,7 @@ static int init_sphere(grib_handle* h, grib_iterator_lambert_azimuthal_equal_are return GRIB_SUCCESS; } + static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { int err = 0; int is_oblate = 0; @@ -484,12 +418,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { return GRIB_SUCCESS; } +#endif -static int destroy(grib_iterator* iter) { - grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)iter; - const grib_context* c = iter->h->context; - grib_context_free(c, self->lats); - grib_context_free(c, self->lons); - return GRIB_SUCCESS; -} +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LambertConformalConic.cc b/src/eckit/geo/projection/LambertConformalConic.cc index 72cb94c6a..b00cb10ca 100644 --- a/src/eckit/geo/projection/LambertConformalConic.cc +++ b/src/eckit/geo/projection/LambertConformalConic.cc @@ -1,102 +1,47 @@ /* - * (C) Copyright 2005- ECMWF. + * (C) Copyright 1996- 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. + * 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 -#include "grib_api_internal.h" - -/* - This is used by make_class.pl - - START_CLASS_DEF - CLASS = iterator - SUPER = grib_iterator_class_gen - IMPLEMENTS = destroy - IMPLEMENTS = init;next - MEMBERS = double *lats - MEMBERS = double *lons - MEMBERS = long Nj - 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 "iterator.class" and rerun ./make_class.pl -*/ +#include "eckit/geo/projection/LambertConformalConic.h" +#include -static void init_class(grib_iterator_class*); +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/util.h" -static int init(grib_iterator* i, grib_handle*, grib_arguments*); -static int next(grib_iterator* i, double* lat, double* lon, double* val); -static int destroy(grib_iterator* i); +namespace eckit::geo::projection { -typedef struct grib_iterator_lambert_conformal { - grib_iterator it; - /* Members defined in gen */ - int carg; - const char* missingValue; - /* Members defined in lambert_conformal */ - double* lats; - double* lons; - long Nj; -} grib_iterator_lambert_conformal; -extern grib_iterator_class* grib_iterator_class_gen; +LambertConformalConic::LambertConformalConic(const Spec&) {} -static grib_iterator_class _grib_iterator_class_lambert_conformal = { - &grib_iterator_class_gen, /* super */ - "lambert_conformal", /* name */ - sizeof(grib_iterator_lambert_conformal), /* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ -}; -grib_iterator_class* grib_iterator_class_lambert_conformal = &_grib_iterator_class_lambert_conformal; +Point LambertConformalConic::fwd(const Point&) const { + NOTIMP; +} -static void init_class(grib_iterator_class* c) { - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; +Point LambertConformalConic::inv(const Point&) const { + NOTIMP; } -/* END_CLASS_IMP */ -#define ITER "Lambert conformal Geoiterator" -#define EPSILON 1.0e-10 -#ifndef M_PI -#define M_PI 3.14159265358979323846 // Whole pie -#endif +Spec* LambertConformalConic::spec() const { + NOTIMP; +} -#ifndef M_PI_2 -#define M_PI_2 1.57079632679489661923 // Half a pie -#endif -#ifndef M_PI_4 -#define M_PI_4 0.78539816339744830962 // Quarter of a pie -#endif +#if 0 +static constexpr double EPSILON = 1e-10; -#define RAD2DEG 57.29577951308232087684 // 180 over pi -#define DEG2RAD 0.01745329251994329576 // pi over 180 // Adjust longitude (in radians) to range -180 to 180 static double adjust_lon_radians(double lon) { @@ -107,6 +52,7 @@ static double adjust_lon_radians(double lon) { return lon; } + // Function to compute the latitude angle, phi2, for the inverse // From the book "Map Projections-A Working Manual-John P. Snyder (1987)" // Equation (7-9) involves rapidly converging iteration: Calculate t from (15-11) @@ -133,6 +79,7 @@ static double compute_phi(double eccent, // Spheroid eccentricity return 0; } + // Compute the constant small m which is the radius of // a parallel of latitude, phi, divided by the semimajor axis static double compute_m(double eccent, double sinphi, double cosphi) { @@ -140,6 +87,7 @@ static double compute_m(double eccent, double sinphi, double cosphi) { return ((cosphi / (sqrt(1.0 - con * con)))); } + // Compute the constant small t for use in the forward computations static double compute_t(double eccent, // Eccentricity of the spheroid double phi, // Latitude phi @@ -151,15 +99,17 @@ static double compute_t(double eccent, // Eccentricity of the spheroid return (tan(0.5 * (M_PI_2 - phi)) / con); } + static double calculate_eccentricity(double minor, double major) { const double temp = minor / major; return sqrt(1.0 - temp * temp); } + static void xy2lonlat(double radius, double n, double f, double rho0_bare, double LoVInRadians, double x, double y, double* lonDeg, double* latDeg) { - DEBUG_ASSERT(radius > 0); - DEBUG_ASSERT(n != 0.0); + ASSERT(radius > 0); + ASSERT(n != 0.0); x /= radius; y /= radius; y = rho0_bare - y; @@ -172,15 +122,16 @@ static void xy2lonlat(double radius, double n, double f, double rho0_bare, doubl } double latRadians = 2. * atan(pow(f / rho, 1.0 / n)) - M_PI_2; double lonRadians = atan2(x, y) / n; - *lonDeg = (lonRadians + LoVInRadians) * RAD2DEG; - *latDeg = latRadians * RAD2DEG; + *lonDeg = (lonRadians + LoVInRadians) * util::RADIAN_TO_DEGREE; + *latDeg = latRadians * util::RADIAN_TO_DEGREE; } else { *lonDeg = 0.0; - *latDeg = (n > 0.0 ? M_PI_2 : -M_PI_2) * RAD2DEG; + *latDeg = (n > 0.0 ? M_PI_2 : -M_PI_2) * util::RADIAN_TO_DEGREE; } } + static int init_sphere(const grib_handle* h, grib_iterator_lambert_conformal* self, size_t nv, long nx, long ny, double LoVInDegrees, double Dx, double Dy, double radius, double latFirstInRadians, double lonFirstInRadians, double LoVInRadians, double Latin1InRadians, double Latin2InRadians, @@ -254,8 +205,8 @@ static int init_sphere(const grib_handle* h, grib_iterator_lambert_conformal* se angle = atan2(x, tmp); /* See ECC-524 */ rho = sqrt(x * x + tmp2); if (n <= 0) rho = -rho; - lonDeg = LoVInDegrees + (angle / n) * RAD2DEG; - latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * RAD2DEG; + lonDeg = LoVInDegrees + (angle / n) * util::RADIAN_TO_DEGREE; + latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * util::RADIAN_TO_DEGREE; lonDeg = normalise_longitude_in_degrees(lonDeg); self->lons[index] = lonDeg; self->lats[index] = latDeg; @@ -265,6 +216,7 @@ static int init_sphere(const grib_handle* h, grib_iterator_lambert_conformal* se return GRIB_SUCCESS; } + // Oblate spheroid static int init_oblate(const grib_handle* h, grib_iterator_lambert_conformal* self, size_t nv, long nx, long ny, double LoVInDegrees, double Dx, double Dy, double earthMinorAxisInMetres, @@ -383,10 +335,10 @@ static int init_oblate(const grib_handle* h, grib_iterator_lambert_conformal* se } lonRad = adjust_lon_radians(theta / ns + LoVInRadians); if (i == 0 && j == 0) { - DEBUG_ASSERT(fabs(latFirstInRadians - latRad) <= EPSILON); + ASSERT(fabs(latFirstInRadians - latRad) <= EPSILON); } - latDeg = latRad * RAD2DEG; // Convert to degrees - lonDeg = normalise_longitude_in_degrees(lonRad * RAD2DEG); + latDeg = latRad * util::RADIAN_TO_DEGREE; // Convert to degrees + lonDeg = normalise_longitude_in_degrees(lonRad * util::RADIAN_TO_DEGREE); self->lons[index] = lonDeg; self->lats[index] = latDeg; } @@ -394,6 +346,7 @@ static int init_oblate(const grib_handle* h, grib_iterator_lambert_conformal* se return GRIB_SUCCESS; } + static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { int err = 0, is_oblate = 0; long nx, ny, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning; @@ -480,12 +433,12 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { // // See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html // - latFirstInRadians = latFirstInDegrees * DEG2RAD; - lonFirstInRadians = lonFirstInDegrees * DEG2RAD; - Latin1InRadians = Latin1InDegrees * DEG2RAD; - Latin2InRadians = Latin2InDegrees * DEG2RAD; - LaDInRadians = LaDInDegrees * DEG2RAD; - LoVInRadians = LoVInDegrees * DEG2RAD; + latFirstInRadians = latFirstInDegrees * util::DEGREE_TO_RADIAN; + lonFirstInRadians = lonFirstInDegrees * util::DEGREE_TO_RADIAN; + Latin1InRadians = Latin1InDegrees * util::DEGREE_TO_RADIAN; + Latin2InRadians = Latin2InDegrees * util::DEGREE_TO_RADIAN; + LaDInRadians = LaDInDegrees * util::DEGREE_TO_RADIAN; + LoVInRadians = LoVInDegrees * util::DEGREE_TO_RADIAN; if (is_oblate) { err = init_oblate(h, self, iter->nv, nx, ny, LoVInDegrees, Dx, Dy, earthMinorAxisInMetres, @@ -506,27 +459,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { alternativeRowScanning, iter->nv, nx, ny); return err; } +#endif -static int next(grib_iterator* iter, double* lat, double* lon, double* val) { - grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; - - if ((long)iter->e >= (long)(iter->nv - 1)) - return 0; - iter->e++; - - *lat = self->lats[iter->e]; - *lon = self->lons[iter->e]; - if (val && iter->data) { - *val = iter->data[iter->e]; - } - return 1; -} - -static int destroy(grib_iterator* i) { - grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)i; - const grib_context* c = i->h->context; - grib_context_free(c, self->lats); - grib_context_free(c, self->lons); - return GRIB_SUCCESS; -} +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LambertConformalConic.h b/src/eckit/geo/projection/LambertConformalConic.h index eeb124027..07abda721 100644 --- a/src/eckit/geo/projection/LambertConformalConic.h +++ b/src/eckit/geo/projection/LambertConformalConic.h @@ -28,7 +28,6 @@ class LambertConformalConic final : public Projection { // -- Constructors - LambertConformalConic(); explicit LambertConformalConic(const Spec&); // -- Destructor diff --git a/src/eckit/geo/projection/PolarStereographic.cc b/src/eckit/geo/projection/PolarStereographic.cc index 020feff1c..c6b503b8b 100644 --- a/src/eckit/geo/projection/PolarStereographic.cc +++ b/src/eckit/geo/projection/PolarStereographic.cc @@ -1,101 +1,47 @@ /* - * (C) Copyright 2005- ECMWF. + * (C) Copyright 1996- 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. + * 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 -#include "grib_api_internal.h" - -/* - This is used by make_class.pl - - START_CLASS_DEF - CLASS = iterator - SUPER = grib_iterator_class_gen - IMPLEMENTS = destroy - IMPLEMENTS = init;next - MEMBERS = double *lats - MEMBERS = double *lons - MEMBERS = long Nj - END_CLASS_DEF -*/ -/* START_CLASS_IMP */ +#include "eckit/geo/projection/PolarStereographic.h" -/* - -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 "iterator.class" and rerun ./make_class.pl +#include -*/ +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/util.h" -static void init_class(grib_iterator_class*); +namespace eckit::geo::projection { -static int init(grib_iterator* i, grib_handle*, grib_arguments*); -static int next(grib_iterator* i, double* lat, double* lon, double* val); -static int destroy(grib_iterator* i); +PolarStereographic::PolarStereographic(const Spec&) {} -typedef struct grib_iterator_polar_stereographic { - grib_iterator it; - /* Members defined in gen */ - int carg; - const char* missingValue; - /* Members defined in polar_stereographic */ - double* lats; - double* lons; - long Nj; -} grib_iterator_polar_stereographic; -extern grib_iterator_class* grib_iterator_class_gen; +Point PolarStereographic::fwd(const Point&) const { + NOTIMP; +} -static grib_iterator_class _grib_iterator_class_polar_stereographic = { - &grib_iterator_class_gen, /* super */ - "polar_stereographic", /* name */ - sizeof(grib_iterator_polar_stereographic), /* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ -}; -grib_iterator_class* grib_iterator_class_polar_stereographic = &_grib_iterator_class_polar_stereographic; +Point PolarStereographic::inv(const Point&) const { + NOTIMP; +} -static void init_class(grib_iterator_class* c) { - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; +Spec* PolarStereographic::spec() const { + NOTIMP; } -/* END_CLASS_IMP */ -#define ITER "Polar stereographic Geoiterator" -static int next(grib_iterator* iter, double* lat, double* lon, double* val) { - grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)iter; +#if 0 +static constexpr double EPSILON = 1e-10; - if ((long)iter->e >= (long)(iter->nv - 1)) - return 0; - iter->e++; - - *lat = self->lats[iter->e]; - *lon = self->lons[iter->e]; - if (val && iter->data) { - *val = iter->data[iter->e]; - } - return 1; -} /* Data struct for Forward and Inverse Projections */ typedef struct proj_data_t { @@ -109,10 +55,6 @@ typedef struct proj_data_t { double false_easting; /* x offset in meters */ } proj_data_t; -#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ -#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ -#define PI_OVER_2 1.5707963267948966 /* half pi */ -#define EPSILON 1.0e-10 static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { int ret = 0; @@ -192,10 +134,10 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { if ((ret = grib_get_long_internal(h, s_alternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) return ret; - centralLongitude = centralLongitudeInDegrees * DEG2RAD; - centralLatitude = centralLatitudeInDegrees * DEG2RAD; - lonFirst = lonFirstInDegrees * DEG2RAD; - latFirst = latFirstInDegrees * DEG2RAD; + centralLongitude = centralLongitudeInDegrees * util::DEGREE_TO_RADIAN; + centralLatitude = centralLatitudeInDegrees * util::DEGREE_TO_RADIAN; + lonFirst = lonFirstInDegrees * util::DEGREE_TO_RADIAN; + latFirst = latFirstInDegrees * util::DEGREE_TO_RADIAN; /* Forward projection initialisation */ fwd_proj_data.false_northing = 0; @@ -207,17 +149,17 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { else fwd_proj_data.sign = +1.0; fwd_proj_data.ind = 0; - if (fabs(fabs(centralLatitude) - PI_OVER_2) > EPSILON) { + if (fabs(fabs(centralLatitude) - M_PI_2) > EPSILON) { /* central latitude different from 90 i.e. not north/south polar */ fwd_proj_data.ind = 1; con1 = fwd_proj_data.sign * centralLatitude; fwd_proj_data.mcs = cos(con1); - fwd_proj_data.tcs = tan(0.5 * (PI_OVER_2 - con1)); + fwd_proj_data.tcs = tan(0.5 * (M_PI_2 - con1)); } /* Forward projection from initial lat,lon to initial x,y */ con1 = fwd_proj_data.sign * (lonFirst - fwd_proj_data.centre_lon); - ts = tan(0.5 * (PI_OVER_2 - fwd_proj_data.sign * latFirst)); + ts = tan(0.5 * (M_PI_2 - fwd_proj_data.sign * latFirst)); if (fwd_proj_data.ind) height = radius * fwd_proj_data.mcs * ts / fwd_proj_data.tcs; else @@ -238,11 +180,11 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { else inv_proj_data.sign = +1.0; inv_proj_data.ind = 0; - if (fabs(fabs(centralLatitude) - PI_OVER_2) > EPSILON) { + if (fabs(fabs(centralLatitude) - M_PI_2) > EPSILON) { inv_proj_data.ind = 1; con1 = inv_proj_data.sign * inv_proj_data.centre_lat; inv_proj_data.mcs = cos(con1); - inv_proj_data.tcs = tan(0.5 * (PI_OVER_2 - con1)); + inv_proj_data.tcs = tan(0.5 * (M_PI_2 - con1)); } self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); if (!self->lats) { @@ -273,7 +215,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { ts = rh * inv_proj_data.tcs / (radius * inv_proj_data.mcs); else ts = rh / (radius * 2.0); - *lats = inv_proj_data.sign * (PI_OVER_2 - 2 * atan(ts)); + *lats = inv_proj_data.sign * (M_PI_2 - 2 * atan(ts)); if (rh == 0) { *lons = inv_proj_data.sign * inv_proj_data.centre_lon; } @@ -281,8 +223,8 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { double temp = atan2(_x, -_y); *lons = inv_proj_data.sign * temp + inv_proj_data.centre_lon; } - *lats = *lats * RAD2DEG; - *lons = *lons * RAD2DEG; + *lats = *lats * util::RADIAN_TO_DEGREE; + *lons = *lons * util::RADIAN_TO_DEGREE; while (*lons < 0) *lons += 360; while (*lons > 360) @@ -295,65 +237,6 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { y += Dy; } - // /*standardParallel = (southPoleOnPlane == 1) ? -90 : +90;*/ - // if (jPointsAreConsecutive) - // { - // x=xFirst; - // for (i=0;i360) *lons -= 360; - // lons++; - // lats++; - // y+=Dy; - // } - // x+=Dx; - // } - // } - // else - // { - // y=yFirst; - // for (j=0;j360) *lons -= 360; - // lons++; - // lats++; - // x+=Dx; - // } - // y+=Dy; - // } - // } - iter->e = -1; /* Apply the scanning mode flags which may require data array to be transformed */ @@ -362,12 +245,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { return ret; } +#endif -static int destroy(grib_iterator* i) { - grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)i; - const grib_context* c = i->h->context; - grib_context_free(c, self->lats); - grib_context_free(c, self->lons); - return GRIB_SUCCESS; -} +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/PolarStereographic.h b/src/eckit/geo/projection/PolarStereographic.h index 71f28abc3..fdb703e89 100644 --- a/src/eckit/geo/projection/PolarStereographic.h +++ b/src/eckit/geo/projection/PolarStereographic.h @@ -28,7 +28,6 @@ class PolarStereographic final : public Projection { // -- Constructors - PolarStereographic(); explicit PolarStereographic(const Spec&); // -- Destructor diff --git a/src/eckit/geo/projection/SpaceView.cc b/src/eckit/geo/projection/SpaceView.cc index 66e7d4684..d03d76b02 100644 --- a/src/eckit/geo/projection/SpaceView.cc +++ b/src/eckit/geo/projection/SpaceView.cc @@ -1,147 +1,45 @@ /* - * (C) Copyright 2005- ECMWF. + * (C) Copyright 1996- 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. + * 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 -#include "grib_api_internal.h" - -/* - This is used by make_class.pl - - START_CLASS_DEF - CLASS = iterator - SUPER = grib_iterator_class_gen - IMPLEMENTS = destroy - IMPLEMENTS = init;next - MEMBERS = double *lats - MEMBERS = double *lons - MEMBERS = long Nj - 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 "iterator.class" and rerun ./make_class.pl -*/ +#include "eckit/geo/projection/SpaceView.h" +#include -static void init_class(grib_iterator_class*); - -static int init(grib_iterator* i, grib_handle*, grib_arguments*); -static int next(grib_iterator* i, double* lat, double* lon, double* val); -static int destroy(grib_iterator* i); - +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/util.h" -typedef struct grib_iterator_space_view { - grib_iterator it; - /* Members defined in gen */ - int carg; - const char* missingValue; - /* Members defined in space_view */ - double* lats; - double* lons; - long Nj; -} grib_iterator_space_view; -extern grib_iterator_class* grib_iterator_class_gen; +namespace eckit::geo::projection { -static grib_iterator_class _grib_iterator_class_space_view = { - &grib_iterator_class_gen, /* super */ - "space_view", /* name */ - sizeof(grib_iterator_space_view), /* size of instance */ - 0, /* inited */ - &init_class, /* init_class */ - &init, /* constructor */ - &destroy, /* destructor */ - &next, /* Next Value */ - 0, /* Previous Value */ - 0, /* Reset the counter */ - 0, /* has next values */ -}; -grib_iterator_class* grib_iterator_class_space_view = &_grib_iterator_class_space_view; +SpaceView::SpaceView(const Spec&) {} -static void init_class(grib_iterator_class* c) { - c->previous = (*(c->super))->previous; - c->reset = (*(c->super))->reset; - c->has_next = (*(c->super))->has_next; +Point SpaceView::fwd(const Point&) const { + NOTIMP; } -/* END_CLASS_IMP */ -#define ITER "Space view Geoiterator" -static int next(grib_iterator* iter, double* lat, double* lon, double* val) { - grib_iterator_space_view* self = (grib_iterator_space_view*)iter; +Point SpaceView::inv(const Point&) const { + NOTIMP; +} - if ((long)iter->e >= (long)(iter->nv - 1)) - return 0; - iter->e++; - *lat = self->lats[iter->e]; - *lon = self->lons[iter->e]; - if (val && iter->data) { - *val = iter->data[iter->e]; - } - return 1; +Spec* SpaceView::spec() const { + NOTIMP; } -// static void adjustBadlyEncodedEcmwfGribs(grib_handle* h, -// long* nx, long* ny, double* dx, double* dy, double* xp, double* yp) -// { -// /* Correct the information provided in the headers of certain satellite imagery that -// * we have available. This is specific to ECMWF. -// * Obtained through trial-and-error to get the best match with the coastlines. -// * -// * Copied from Magics GribSatelliteInterpretor::AdjustBadlyEncodedGribs() -// */ -// long centre = 0; -// int err = grib_get_long(h, "centre", ¢re); -// if (!err && centre == 98) { -// int err1 = 0, err2 = 0, err3 = 0; -// long satelliteIdentifier, channelNumber, functionCode; -// /* These keys are defined in the ECMWF local definition 24 - Satellite image simulation */ -// err1 = grib_get_long(h, "satelliteIdentifier", &satelliteIdentifier); -// err2 = grib_get_long(h, "channelNumber", &channelNumber); -// err3 = grib_get_long(h, "functionCode", &functionCode); -// if (!err1 && !err2 && !err3) { -// if (satelliteIdentifier == 54 && channelNumber == 2 && *dx == 1179) { /* Meteosat 7, channel 2 */ -// *nx = *ny = 900; -// *dx = *dy = 853; -// *xp = *yp = 450; -// } -// else if (satelliteIdentifier == 54 && channelNumber == 3 && *dx == 1179) { /* Meteosat 7, channel 3 */ -// *dx = *dy = 1184; -// *xp = *yp = 635; -// } -// else if (satelliteIdentifier == 259 && channelNumber == 4 && *dx == 1185) { /* GOES-15 (West) channel 4 -// */ -// *dx = *dy = 880; -// *xp = *yp = 450; -// } -// else if (satelliteIdentifier == 57 && *dx == 1732) { /* MSG (Meteosat second generation), non-HRV -// channels */ -// *dx = *dy = 1811; -// *xp = *yp = 928; -// } -// } -// } -// } - -#define RAD2DEG 57.29577951308232087684 /* 180 over pi */ -#define DEG2RAD 0.01745329251994329576 /* pi over 180 */ +#if 0 static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { /* REFERENCE: * LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) @@ -364,8 +262,8 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { S2 = Sn * sin_x * cos_y; S3 = Sn * sin_y; Sxy = sqrt(S1 * S1 + S2 * S2); - lons[i] = atan(S2 / S1) * (RAD2DEG) + lop; - lats[i] = atan(factor_2 * S3 / Sxy) * (RAD2DEG); + lons[i] = atan(S2 / S1) * (util::RADIAN_TO_DEGREE) + lop; + lats[i] = atan(factor_2 * S3 / Sxy) * (util::RADIAN_TO_DEGREE); /*fprintf(stderr, "lat=%g lon=%g\n", lats[i], lons[i]);*/ } while (lons[i] < 0) @@ -380,12 +278,7 @@ static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { return ret; } +#endif -static int destroy(grib_iterator* iter) { - grib_iterator_space_view* self = (grib_iterator_space_view*)iter; - const grib_context* c = iter->h->context; - grib_context_free(c, self->lats); - grib_context_free(c, self->lons); - return GRIB_SUCCESS; -} +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/SpaceView.h b/src/eckit/geo/projection/SpaceView.h index 0d934ac69..676a6c880 100644 --- a/src/eckit/geo/projection/SpaceView.h +++ b/src/eckit/geo/projection/SpaceView.h @@ -28,7 +28,6 @@ class SpaceView final : public Projection { // -- Constructors - SpaceView(); explicit SpaceView(const Spec&); // -- Destructor From d1b33903abe2ebd180dcf6b0425650882baec12b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 10 May 2024 14:00:57 +0100 Subject: [PATCH 630/737] eckit::geo rearranged eccodes projections --- src/eckit/geo/PointLonLat.h | 20 +- .../projection/LambertAzimuthalEqualArea.cc | 436 ++++----------- .../geo/projection/LambertConformalConic.cc | 515 ++++++------------ .../geo/projection/LambertConformalConic.h | 5 + .../geo/projection/PolarStereographic.cc | 243 ++------- src/eckit/geo/projection/SpaceView.cc | 281 ++-------- src/eckit/geo/projection/SpaceView.h | 4 + 7 files changed, 379 insertions(+), 1125 deletions(-) diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index 351939ee7..548b344d9 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -22,14 +22,6 @@ namespace eckit::geo { class PointLonLat final : protected std::array { public: - // FIXME move into PointLonLat - static constexpr double GLOBE = 360.; - static constexpr double GREENWICH = 0.; - static constexpr double ANTIMERIDIAN = -180.; - static constexpr double EQUATOR = 0.; - static constexpr double NORTH_POLE = 90.; - static constexpr double SOUTH_POLE = -90.; - // -- Types using container_type = array; @@ -37,6 +29,8 @@ class PointLonLat final : protected std::array { // -- Constructors + PointLonLat() : PointLonLat(0., 0.) {} + PointLonLat(value_type lon, value_type lat) : container_type{lon, lat} {} PointLonLat(const PointLonLat& other) : container_type(other) {} @@ -72,12 +66,20 @@ class PointLonLat final : protected std::array { static void assert_latitude_range(const PointLonLat&); - static PointLonLat make(value_type lon, value_type lat, value_type lon_minimum = EQUATOR, value_type eps = EPS); + [[nodiscard]] static PointLonLat make(value_type lon, value_type lat, value_type lon_minimum = EQUATOR, + value_type eps = EPS); PointLonLat antipode() const { return make(lon, lat + GLOBE / 2.); } // -- Class members + static constexpr double GLOBE = 360.; + static constexpr double GREENWICH = 0.; + static constexpr double ANTIMERIDIAN = -180.; + static constexpr double EQUATOR = 0.; + static constexpr double NORTH_POLE = 90.; + static constexpr double SOUTH_POLE = -90.; + static constexpr value_type EPS = 1e-9; // -- Class methods diff --git a/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc index 2c65be1c9..647b676dd 100644 --- a/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc @@ -39,7 +39,6 @@ Spec* LambertAzimuthalEqualArea::spec() const { } -#if 0 static constexpr double EPSILON = 1e-10; static constexpr double P00 = .33333333333333333333; // 1 / 3 @@ -50,19 +49,6 @@ static constexpr double P11 = .06640211640211640212; // 251 / 3780 static constexpr double P20 = .01677689594356261023; // 761 / 45360 -static void pj_authset(double es, double* APA) { - double t; - APA[0] = es * P00; - t = es * es; - APA[0] += t * P01; - APA[1] = t * P10; - t *= es; - APA[0] += t * P02; - APA[1] += t * P11; - APA[2] = t * P20; -} - - static double pj_authlat(double beta, const double* APA) { double t = beta + beta; return (beta + APA[0] * sin(t) + APA[1] * sin(t + t) + APA[2] * sin(t + t + t)); @@ -70,355 +56,133 @@ static double pj_authlat(double beta, const double* APA) { static double pj_qsfn(double sinphi, double e, double one_es) { - double con, div1, div2; - - if (e >= 1.0e-7) { - con = e * sinphi; - div1 = 1.0 - con * con; - div2 = 1.0 + con; + if (e < 1.e-7) { + return sinphi + sinphi; + } - /* avoid zero division, fail gracefully */ - if (div1 == 0.0 || div2 == 0.0) - return HUGE_VAL; + double con = e * sinphi; + double div1 = 1.0 - con * con; + double div2 = 1.0 + con; - return (one_es * (sinphi / div1 - (.5 / e) * log((1. - con) / div2))); - } - else - return (sinphi + sinphi); + /* avoid zero division, fail gracefully */ + return div1 == 0.0 || div2 == 0.0 ? HUGE_VAL : (one_es * (sinphi / div1 - (.5 / e) * log((1. - con) / div2))); } -static int init_oblate(grib_handle* h, grib_iterator_lambert_azimuthal_equal_area* self, size_t nv, long nx, long ny, - double Dx, double Dy, double earthMinorAxisInMetres, double earthMajorAxisInMetres, - double latFirstInRadians, double lonFirstInRadians, double centralLongitudeInRadians, - double standardParallelInRadians, long iScansNegatively, long jScansPositively, - long jPointsAreConsecutive) { - double *lats, *lons; - long i, j; - double x0, y0, x, y; - double coslam, sinlam, sinphi, sinphi_, q, sinb = 0.0, cosb = 0.0, b = 0.0, cosb2; - double Q__qp = 0, Q__rq = 0, Q__cosb1, Q__sinb1, Q__dd, Q__xmf, Q__ymf, t; - /* double Q__mmf = 0; */ - double e, es, temp, one_es; - double APA[3] = { - 0, - }; - double xFirst, yFirst; - - Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; - Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; - - temp = (earthMajorAxisInMetres - earthMinorAxisInMetres) / earthMajorAxisInMetres; - es = 2 * temp - temp * temp; - one_es = 1.0 - es; - e = sqrt(es); - - coslam = cos(lonFirstInRadians - centralLongitudeInRadians); /* cos(lp.lam) */ - sinlam = sin(lonFirstInRadians - centralLongitudeInRadians); - sinphi = sin(latFirstInRadians); /* sin(lp.phi) */ - q = pj_qsfn(sinphi, e, one_es); - - t = fabs(standardParallelInRadians); +static void init_oblate() { + double earthMinorAxisInMetres = 0; + double earthMajorAxisInMetres = 0; + double latFirstInRadians = 0; + double lonFirstInRadians = 0; + double centralLongitudeInRadians = 0; + double standardParallelInRadians = 0; + + const double temp = (earthMajorAxisInMetres - earthMinorAxisInMetres) / earthMajorAxisInMetres; + const double es = 2 * temp - temp * temp; + const double one_es = 1.0 - es; + const double e = sqrt(es); + + const double coslam = cos(lonFirstInRadians - centralLongitudeInRadians); /* cos(lp.lam) */ + const double sinlam = sin(lonFirstInRadians - centralLongitudeInRadians); + const double sinphi = sin(latFirstInRadians); /* sin(lp.phi) */ + const double q = pj_qsfn(sinphi, e, one_es); + + const double t = fabs(standardParallelInRadians); if (t > M_PI_2 + EPSILON) { - return GRIB_GEOCALCULUS_PROBLEM; + throw; // GRIB_GEOCALCULUS_PROBLEM; } - /* if (fabs(t - M_HALFPI) < EPSILON) - Q->mode = P->phi0 < 0. ? S_POLE : N_POLE; - else if (fabs(t) < EPSILON) - Q->mode = EQUIT; - else - Q->mode = OBLIQ; - */ - Q__qp = pj_qsfn(1.0, e, one_es); - /* Q__mmf = 0.5 / one_es; ---- TODO(masn): do I need this? */ - pj_authset(es, APA); /* sets up APA array */ - Q__rq = sqrt(0.5 * Q__qp); - sinphi_ = sin(standardParallelInRadians); /* (P->phi0); */ - Q__sinb1 = pj_qsfn(sinphi_, e, one_es) / Q__qp; - Q__cosb1 = sqrt(1.0 - Q__sinb1 * Q__sinb1); - if (Q__cosb1 == 0) { - Q__dd = 1.0; - } - else { - Q__dd = cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); - } - Q__ymf = (Q__xmf = Q__rq) / Q__dd; - Q__xmf *= Q__dd; - sinb = q / Q__qp; - cosb2 = 1.0 - sinb * sinb; - cosb = cosb2 > 0 ? sqrt(cosb2) : 0; - b = 1. + Q__sinb1 * sinb + Q__cosb1 * cosb * coslam; + const double Q__qp = pj_qsfn(1.0, e, one_es); + + const double APA[3] + = {es * P00 + es * es * P01 + es * es * es * P02, es * es * P10 + es * es * es * P11, es * es * es * P20}; + + const double Q__rq = sqrt(0.5 * Q__qp); + const double sinphi_ = sin(standardParallelInRadians); /* (P->phi0); */ + const double Q__sinb1 = pj_qsfn(sinphi_, e, one_es) / Q__qp; + const double Q__cosb1 = sqrt(1.0 - Q__sinb1 * Q__sinb1); + const double Q__dd + = Q__cosb1 == 0 ? 1. : cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); + const double Q__xmf = Q__rq * Q__dd; + const double Q__ymf = Q__rq / Q__dd; + + const double sinb = q / Q__qp; + const double cosb2 = 1.0 - sinb * sinb; + const double cosb = cosb2 > 0 ? sqrt(cosb2) : 0; + + double b = 1. + Q__sinb1 * sinb + Q__cosb1 * cosb * coslam; if (fabs(b) < EPSILON) { - return GRIB_GEOCALCULUS_PROBLEM; + throw; // GRIB_GEOCALCULUS_PROBLEM; } b = sqrt(2.0 / b); /* OBLIQUE */ - y0 = Q__ymf * b * (Q__cosb1 * sinb - Q__sinb1 * cosb * coslam); - x0 = Q__xmf * b * cosb * sinlam; - - /* Allocate latitude and longitude arrays */ - self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - lats = self->lats; - lons = self->lons; - - /* Populate the lat and lon arrays */ - { - xFirst = x0; - yFirst = y0; - y = yFirst; - for (j = 0; j < ny; j++) { - x = xFirst; - for (i = 0; i < nx; i++) { - double cCe, sCe, rho, ab = 0.0, lp__lam, lp__phi, xy_x = x, xy_y = y; - xy_x /= Q__dd; - xy_y *= Q__dd; - rho = hypot(xy_x, xy_y); - ASSERT(rho >= EPSILON); /* TODO(masn): check */ - const double asin_arg = (0.5 * rho / Q__rq); - if (asin_arg < -1.0 || asin_arg > 1.0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "Invalid value: arcsin argument=%g", asin_arg); - return GRIB_GEOCALCULUS_PROBLEM; - } - sCe = 2. * asin(asin_arg); - cCe = cos(sCe); - sCe = sin(sCe); - xy_x *= sCe; - /* if oblique */ - ab = cCe * Q__sinb1 + xy_y * sCe * Q__cosb1 / rho; - xy_y = rho * Q__cosb1 * cCe - xy_y * Q__sinb1 * sCe; - /* else - ab = xy.y * sCe / rho; - xy.y = rho * cCe; - */ - lp__lam = atan2(xy_x, xy_y); /* longitude */ - lp__phi = pj_authlat(asin(ab), APA); /* latitude */ - - *lats = lp__phi * util::RADIAN_TO_DEGREE; - *lons = (lp__lam + centralLongitudeInRadians) * util::RADIAN_TO_DEGREE; - - lons++; - lats++; - - x += Dx / earthMajorAxisInMetres; - } - y += Dy / earthMajorAxisInMetres; - } + const double y0 = Q__ymf * b * (Q__cosb1 * sinb - Q__sinb1 * cosb * coslam); + const double x0 = Q__xmf * b * cosb * sinlam; + + double x = x0; + double y = y0; + + double xy_x = x / Q__dd; + double xy_y = y * Q__dd; + double rho = hypot(xy_x, xy_y); + ASSERT(rho >= EPSILON); + + const double asin_arg = (0.5 * rho / Q__rq); + if (asin_arg < -1.0 || asin_arg > 1.0) { + // Invalid value: arcsin argument={asin_arg} + throw; // GRIB_GEOCALCULUS_PROBLEM; } - return GRIB_SUCCESS; + double cCe = cos(2. * asin(asin_arg)); + double sCe = sin(2. * asin(asin_arg)); + xy_x *= sCe; + + double ab = cCe * Q__sinb1 + xy_y * sCe * Q__cosb1 / rho; + xy_y = rho * Q__cosb1 * cCe - xy_y * Q__sinb1 * sCe; + + double latr = pj_authlat(asin(ab), APA); + double lonr = atan2(xy_x, xy_y) + centralLongitudeInRadians; + + PointLonLat::make(lonr * util::RADIAN_TO_DEGREE, latr * util::RADIAN_TO_DEGREE); } -static int init_sphere(grib_handle* h, grib_iterator_lambert_azimuthal_equal_area* self, size_t nv, long nx, long ny, - double Dx, double Dy, double radius, double latFirstInRadians, double lonFirstInRadians, - double centralLongitudeInRadians, double standardParallelInRadians, long iScansNegatively, - long jScansPositively, long jPointsAreConsecutive) { - double *lats, *lons; - double phi1, lambda0, xFirst, yFirst, x, y; - double kp, sinphi1, cosphi1; - double sinphi, cosphi, cosdlambda, sindlambda; - double cosc, sinc; - long i, j; - double c, rho; - const double epsilon = 1.0e-20; - const double d2r = acos(0.0) / 90.0; - - lambda0 = centralLongitudeInRadians; - phi1 = standardParallelInRadians; - - cosphi1 = cos(phi1); - sinphi1 = sin(phi1); - - Dx = iScansNegatively == 0 ? Dx / 1000 : -Dx / 1000; - Dy = jScansPositively == 1 ? Dy / 1000 : -Dy / 1000; - self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - lats = self->lats; - lons = self->lons; +void init_sphere() { + double latFirstInRadians = 0.; + double lonFirstInRadians = 0.; + double radius = 1.; + + double lambda0 = 0.; // centralLongitudeInRadians; + double phi1 = 0.; // standardParallelInRadians; /* compute xFirst,yFirst in metres */ - sinphi = sin(latFirstInRadians); - cosphi = cos(latFirstInRadians); - cosdlambda = cos(lonFirstInRadians - lambda0); - sindlambda = sin(lonFirstInRadians - lambda0); - kp = radius * sqrt(2.0 / (1 + sinphi1 * sinphi + cosphi1 * cosphi * cosdlambda)); - xFirst = kp * cosphi * sindlambda; - yFirst = kp * (cosphi1 * sinphi - sinphi1 * cosphi * cosdlambda); - - if (jPointsAreConsecutive) { - x = xFirst; - for (i = 0; i < nx; i++) { - double xsq = x * x; - y = yFirst; - for (j = 0; j < ny; j++) { - rho = sqrt(xsq + y * y); - if (rho > epsilon) { - c = 2 * asin(rho / (2.0 * radius)); - cosc = cos(c); - sinc = sin(c); - *lats = asin(cosc * sinphi1 + y * sinc * cosphi1 / rho) / d2r; - *lons = (lambda0 + atan2(x * sinc, rho * cosphi1 * cosc - y * sinphi1 * sinc)) / d2r; - } - else { - *lats = phi1 / d2r; - *lons = lambda0 / d2r; - } - if (*lons < 0) - *lons += 360; - lons++; - lats++; - - y += Dy; - } - x += Dx; - } - } - else { - y = yFirst; - for (j = 0; j < ny; j++) { - double ysq = y * y; - x = xFirst; - for (i = 0; i < nx; i++) { - rho = sqrt(x * x + ysq); - if (rho > epsilon) { - c = 2 * asin(rho / (2.0 * radius)); - cosc = cos(c); - sinc = sin(c); - *lats = asin(cosc * sinphi1 + y * sinc * cosphi1 / rho) / d2r; - *lons = (lambda0 + atan2(x * sinc, rho * cosphi1 * cosc - y * sinphi1 * sinc)) / d2r; - } - else { - *lats = phi1 / d2r; - *lons = lambda0 / d2r; - } - if (*lons < 0) - *lons += 360; - lons++; - lats++; - - x += Dx; - } - y += Dy; - } - } - return GRIB_SUCCESS; -} + auto cosphi1 = cos(phi1); + auto sinphi1 = sin(phi1); + auto sinphi = sin(latFirstInRadians); + auto cosphi = cos(latFirstInRadians); + auto cosdlambda = cos(lonFirstInRadians - lambda0); + auto sindlambda = sin(lonFirstInRadians - lambda0); + auto kp = radius * sqrt(2.0 / (1 + sinphi1 * sinphi + cosphi1 * cosphi * cosdlambda)); + auto xFirst = kp * cosphi * sindlambda; + auto yFirst = kp * (cosphi1 * sinphi - sinphi1 * cosphi * cosdlambda); -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { - int err = 0; - int is_oblate = 0; - double lonFirstInDegrees, latFirstInDegrees, lonFirstInRadians, latFirstInRadians, radius = 0; - long nx, ny; - double standardParallelInDegrees, centralLongitudeInDegrees; - double standardParallelInRadians, centralLongitudeInRadians; - double Dx, Dy; - long alternativeRowScanning, iScansNegatively; - long jScansPositively, jPointsAreConsecutive; - double earthMajorAxisInMetres = 0, earthMinorAxisInMetres = 0; - - grib_iterator_lambert_azimuthal_equal_area* self = (grib_iterator_lambert_azimuthal_equal_area*)iter; - - const char* sradius = grib_arguments_get_name(h, args, self->carg++); - const char* snx = grib_arguments_get_name(h, args, self->carg++); - const char* sny = grib_arguments_get_name(h, args, self->carg++); - const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sstandardParallel = grib_arguments_get_name(h, args, self->carg++); - const char* scentralLongitude = grib_arguments_get_name(h, args, self->carg++); - const char* sDx = grib_arguments_get_name(h, args, self->carg++); - const char* sDy = grib_arguments_get_name(h, args, self->carg++); - const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); - const double d2r = acos(0.0) / 90.0; - - is_oblate = grib_is_earth_oblate(h); - if (is_oblate) { - if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) - return err; - } - else { - if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) - return err; - } + Point2 p; - if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) - return err; + double lonr = phi1; + double latr = lambda0; - if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, - ny); - return GRIB_WRONG_GRID; - } - if ((err = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, slonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sstandardParallel, &standardParallelInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, scentralLongitude, ¢ralLongitudeInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sDx, &Dx)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sDy, &Dy)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) - return err; - - latFirstInRadians = latFirstInDegrees * d2r; - lonFirstInRadians = lonFirstInDegrees * d2r; - centralLongitudeInRadians = centralLongitudeInDegrees * d2r; - standardParallelInRadians = standardParallelInDegrees * d2r; - - if (is_oblate) { - err = init_oblate(h, self, iter->nv, nx, ny, Dx, Dy, earthMinorAxisInMetres, earthMajorAxisInMetres, - latFirstInRadians, lonFirstInRadians, centralLongitudeInRadians, standardParallelInRadians, - iScansNegatively, jScansPositively, jPointsAreConsecutive); + if (auto x = p.X, y = p.Y, rho = sqrt(x * x + y * y); rho > EPSILON) { + double c = 2 * asin(rho / (2.0 * radius)); + double cosc = cos(c); + double sinc = sin(c); + latr = asin(cosc * sinphi1 + y * sinc * cosphi1 / rho); + lonr = (lambda0 + atan2(x * sinc, rho * cosphi1 * cosc - y * sinphi1 * sinc)); } - else { - err = init_sphere(h, self, iter->nv, nx, ny, Dx, Dy, radius, latFirstInRadians, lonFirstInRadians, - centralLongitudeInRadians, standardParallelInRadians, iScansNegatively, jScansPositively, - jPointsAreConsecutive); - } - if (err) - return err; - - iter->e = -1; - return GRIB_SUCCESS; + PointLonLat::make(lonr * util::RADIAN_TO_DEGREE, latr * util::RADIAN_TO_DEGREE); } -#endif } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LambertConformalConic.cc b/src/eckit/geo/projection/LambertConformalConic.cc index b00cb10ca..eb87492dc 100644 --- a/src/eckit/geo/projection/LambertConformalConic.cc +++ b/src/eckit/geo/projection/LambertConformalConic.cc @@ -21,7 +21,14 @@ namespace eckit::geo::projection { -LambertConformalConic::LambertConformalConic(const Spec&) {} +LambertConformalConic::LambertConformalConic(const Spec&) { + // if (fabs(Latin1InDegrees + Latin2InDegrees) < EPSILON) { + // grib_context_log(h->context, GRIB_LOG_ERROR, + // "%s: Cannot have equal latitudes for standard parallels on opposite sides of equator", + // ITER); + // return GRIB_WRONG_GRID; + // } +} Point LambertConformalConic::fwd(const Point&) const { @@ -39,205 +46,172 @@ Spec* LambertConformalConic::spec() const { } -#if 0 -static constexpr double EPSILON = 1e-10; +namespace { -// Adjust longitude (in radians) to range -180 to 180 -static double adjust_lon_radians(double lon) { - if (lon > M_PI) +double adjust_lon_radians(double lon) { + while (lon > M_PI) { lon -= 2 * M_PI; - if (lon < -M_PI) + } + while (lon < -M_PI) { lon += 2 * M_PI; + } return lon; -} - + ß +}; + + +void init_sphere() { + size_t nv; + long nx; + long ny; + double LoVInDegrees; + double Dx; + double Dy; + double radius = 1.; + double latFirstInRadians = 0.; + double lonFirstInRadians = 0.; + double LoVInRadians = 0.; + double Latin1InRadians = 0.; + double Latin2InRadians = 0.; + double LaDInRadians = 0.; + + double n; -// Function to compute the latitude angle, phi2, for the inverse -// From the book "Map Projections-A Working Manual-John P. Snyder (1987)" -// Equation (7-9) involves rapidly converging iteration: Calculate t from (15-11) -// Then, assuming an initial trial phi equal to (pi/2 - 2*arctan t) in the right side of equation (7-9), -// calculate phi on the left side. Substitute the calculated phi) into the right side, -// calculate a new phi, etc., until phi does not change significantly from the preceding trial value of phi -static double compute_phi(double eccent, // Spheroid eccentricity - double ts, // Constant value t - int* error) { - double eccnth, phi, con, dphi, sinpi; - int i, MAX_ITER = 15; - - eccnth = 0.5 * eccent; - phi = M_PI_2 - 2 * atan(ts); - for (i = 0; i <= MAX_ITER; i++) { - sinpi = sin(phi); - con = eccent * sinpi; - dphi = M_PI_2 - 2 * atan(ts * (pow(((1.0 - con) / (1.0 + con)), eccnth))) - phi; - phi += dphi; - if (fabs(dphi) <= 0.0000000001) - return (phi); + if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { + n = sin(Latin1InRadians); + } + else { + n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) + / log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); } - *error = GRIB_INTERNAL_ERROR; - return 0; -} - - -// Compute the constant small m which is the radius of -// a parallel of latitude, phi, divided by the semimajor axis -static double compute_m(double eccent, double sinphi, double cosphi) { - const double con = eccent * sinphi; - return ((cosphi / (sqrt(1.0 - con * con)))); -} + double f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; + double rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); + double rho0_bare = f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); + double rho0 = radius * rho0_bare; // scaled + double lonDiff = adjust_lon_radians(lonFirstInRadians - LoVInRadians); -// Compute the constant small t for use in the forward computations -static double compute_t(double eccent, // Eccentricity of the spheroid - double phi, // Latitude phi - double sinphi) // Sine of the latitude -{ - double con = eccent * sinphi; - double com = 0.5 * eccent; - con = pow(((1.0 - con) / (1.0 + con)), com); - return (tan(0.5 * (M_PI_2 - phi)) / con); -} + double angle = n * lonDiff; + double x0 = rho * sin(angle); + double y0 = rho0 - rho * cos(angle); + double latDeg = 0; + double lonDeg = 0; -static double calculate_eccentricity(double minor, double major) { - const double temp = minor / major; - return sqrt(1.0 - temp * temp); -} + Point2 p; -static void xy2lonlat(double radius, double n, double f, double rho0_bare, double LoVInRadians, double x, double y, - double* lonDeg, double* latDeg) { ASSERT(radius > 0); ASSERT(n != 0.0); - x /= radius; - y /= radius; - y = rho0_bare - y; - double rho = hypot(x, y); - if (rho != 0.0) { + + double x = p.X / radius; + double y = rho0_bare - p.Y / radius; + + if (double rho = hypot(x, y); rho != 0.0) { if (n < 0.0) { rho = -rho; x = -x; y = -y; } double latRadians = 2. * atan(pow(f / rho, 1.0 / n)) - M_PI_2; - double lonRadians = atan2(x, y) / n; - *lonDeg = (lonRadians + LoVInRadians) * util::RADIAN_TO_DEGREE; - *latDeg = latRadians * util::RADIAN_TO_DEGREE; + double lonRadians = atan2(x, y) / n + LoVInRadians; + + auto q = PointLonLat::make(lonRadians * util::RADIAN_TO_DEGREE, latRadians * util::RADIAN_TO_DEGREE); } else { - *lonDeg = 0.0; - *latDeg = (n > 0.0 ? M_PI_2 : -M_PI_2) * util::RADIAN_TO_DEGREE; + auto q = PointLonLat::make(0.0, n > 0 ? PointLonLat::NORTH_POLE : PointLonLat::SOUTH_POLE); } } -static int init_sphere(const grib_handle* h, grib_iterator_lambert_conformal* self, size_t nv, long nx, long ny, - double LoVInDegrees, double Dx, double Dy, double radius, double latFirstInRadians, - double lonFirstInRadians, double LoVInRadians, double Latin1InRadians, double Latin2InRadians, - double LaDInRadians) { - double n, x, y; +void init_oblate() { + static constexpr double EPSILON = 1e-10; - if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { - n = sin(Latin1InRadians); - } - else { - n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) - / log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); - } + double LoVInDegrees = 0.; + double LoVInRadians = 0.; + double LaDInRadians = 0.; + double LaDInDegrees = 0.; + double latFirstInRadians = 0.; + double lonFirstInRadians = 0.; + double Latin1InRadians = 0.; + double Latin2InRadians = 0.; + double earthMajorAxisInMetres = 1.; + double earthMinorAxisInMetres = 1.; - double f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; - double rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); - double rho0_bare = f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); - double rho0 = radius * rho0_bare; // scaled - double lonDiff = lonFirstInRadians - LoVInRadians; + double x0; + double y0; - // Adjust longitude to range -180 to 180 - if (lonDiff > M_PI) - lonDiff -= 2 * M_PI; - if (lonDiff < -M_PI) - lonDiff += 2 * M_PI; - double angle = n * lonDiff; - double x0 = rho * sin(angle); - double y0 = rho0 - rho * cos(angle); - // Dx = iScansNegatively == 0 ? Dx : -Dx; - // GRIB-405: Don't change sign of Dy. Latitudes ALWAYS increase from latitudeOfFirstGridPoint - // Dy = jScansPositively == 1 ? Dy : -Dy; - - // Allocate latitude and longitude arrays - self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } + double sinphi; + double ts; + double rh1; - double latDeg = 0, lonDeg = 0; - for (long j = 0; j < ny; j++) { - y = y0 + j * Dy; - for (long i = 0; i < nx; i++) { - const long index = i + j * nx; - x = x0 + i * Dx; - xy2lonlat(radius, n, f, rho0_bare, LoVInRadians, x, y, &lonDeg, &latDeg); - self->lons[index] = lonDeg; - self->lats[index] = latDeg; - } - } + double ns; // ratio of angle between meridian + double F; // flattening of ellipsoid + double rh; // height above ellipsoid -#if 0 - for (j = 0; j < ny; j++) { - y = y0 + j * Dy; - //if (n < 0) { /* adjustment for southern hemisphere */ - // y = -y; - //} - tmp = rho0 - y; - tmp2 = tmp * tmp; - for (i = 0; i < nx; i++) { - int index = i + j * nx; - x = x0 + i * Dx; - //if (n < 0) { /* adjustment for southern hemisphere */ - // x = -x; - //} - angle = atan2(x, tmp); /* See ECC-524 */ - rho = sqrt(x * x + tmp2); - if (n <= 0) rho = -rho; - lonDeg = LoVInDegrees + (angle / n) * util::RADIAN_TO_DEGREE; - latDeg = (2.0 * atan(pow(radius * f / rho, 1.0 / n)) - M_PI_2) * util::RADIAN_TO_DEGREE; - lonDeg = normalise_longitude_in_degrees(lonDeg); - self->lons[index] = lonDeg; - self->lats[index] = latDeg; - } - } -#endif - return GRIB_SUCCESS; -} + double sin_po; // temporary sin value + double cos_po; // temporary cos value + double con; // temporary variable + double ms1; // small m 1 + double ms2; // small m 2 + double ts0; // small t 0 + double ts1; // small t 1 + double ts2; // small t 2 + + auto calculate_eccentricity = [](double minor, double major) { + const double temp = minor / major; + return sqrt(1.0 - temp * temp); + }; + + // Compute the constant small m which is the radius of + // a parallel of latitude, phi, divided by the semimajor axis + auto compute_m = [](double eccent, double sinphi, double cosphi) { + const double con = eccent * sinphi; + return ((cosphi / (sqrt(1.0 - con * con)))); + }; + + // Compute the constant small t for use in the forward computations + auto compute_t = [](double eccent, // Eccentricity of the spheroid + double phi, // Latitude phi + double sinphi) // Sine of the latitude + { + double con = eccent * sinphi; + con = pow(((1.0 - con) / (1.0 + con)), 0.5 * eccent); + return (tan(0.5 * (M_PI_2 - phi)) / con); + }; + + // Function to compute the latitude angle, phi2, for the inverse + // From the book "Map Projections-A Working Manual-John P. Snyder (1987)" + // Equation (7-9) involves rapidly converging iteration: Calculate t from (15-11) + // Then, assuming an initial trial phi equal to (pi/2 - 2*arctan t) in the right side of equation (7-9), + // calculate phi on the left side. Substitute the calculated phi) into the right side, + // calculate a new phi, etc., until phi does not change significantly from the preceding trial value of phi + auto compute_phi = [](double eccent, // Spheroid eccentricity + double ts // Constant value t + ) -> double { + double eccnth; + double phi; + double con; + double dphi; + double sinpi; + + eccnth = 0.5 * eccent; + phi = M_PI_2 - 2 * atan(ts); + + constexpr int MAX_ITER = 15; + for (int i = 0; i <= MAX_ITER; i++) { + sinpi = sin(phi); + con = eccent * sinpi; + dphi = M_PI_2 - 2 * atan(ts * (pow(((1.0 - con) / (1.0 + con)), eccnth))) - phi; + phi += dphi; + if (fabs(dphi) <= 0.0000000001) + return (phi); + } -// Oblate spheroid -static int init_oblate(const grib_handle* h, grib_iterator_lambert_conformal* self, size_t nv, long nx, long ny, - double LoVInDegrees, double Dx, double Dy, double earthMinorAxisInMetres, - double earthMajorAxisInMetres, double latFirstInRadians, double lonFirstInRadians, - double LoVInRadians, double Latin1InRadians, double Latin2InRadians, double LaDInRadians) { - int i, j, err = 0; - double x0, y0, x, y, latRad, lonRad, latDeg, lonDeg, sinphi, ts, rh1, theta; - double false_easting; // x offset in meters - double false_northing; // y offset in meters - - double ns; // ratio of angle between meridian - double F; // flattening of ellipsoid - double rh; // height above ellipsoid - double sin_po; // sin value - double cos_po; // cos value - double con; // temporary variable - double ms1; // small m 1 - double ms2; // small m 2 - double ts0; // small t 0 - double ts1; // small t 1 - double ts2; // small t 2 + throw eckit::SeriousBug("Failed to compute the latitude angle, phi2, for the inverse", Here()); + }; double e = calculate_eccentricity(earthMinorAxisInMetres, earthMajorAxisInMetres); @@ -251,215 +225,56 @@ static int init_oblate(const grib_handle* h, grib_iterator_lambert_conformal* se cos_po = cos(Latin2InRadians); ms2 = compute_m(e, sin_po, cos_po); ts2 = compute_t(e, Latin2InRadians, sin_po); + sin_po = sin(LaDInRadians); ts0 = compute_t(e, LaDInRadians, sin_po); - if (fabs(Latin1InRadians - Latin2InRadians) > EPSILON) { - ns = log(ms1 / ms2) / log(ts1 / ts2); - } - else { - ns = con; - } + ns = fabs(Latin1InRadians - Latin2InRadians) > EPSILON ? log(ms1 / ms2) / log(ts1 / ts2) : con; F = ms1 / (ns * pow(ts1, ns)); rh = earthMajorAxisInMetres * F * pow(ts0, ns); // Forward projection: convert lat,lon to x,y - con = fabs(fabs(latFirstInRadians) - M_PI_2); - if (con > EPSILON) { + if (fabs(fabs(latFirstInRadians) - M_PI_2) > EPSILON) { sinphi = sin(latFirstInRadians); ts = compute_t(e, latFirstInRadians, sinphi); rh1 = earthMajorAxisInMetres * F * pow(ts, ns); } else { - con = latFirstInRadians * ns; - if (con <= 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Point cannot be projected: latFirstInRadians=%g", ITER, - latFirstInRadians); - return GRIB_GEOCALCULUS_PROBLEM; + if (latFirstInRadians * ns <= 0) { + throw; // GRIB_GEOCALCULUS_PROBLEM Point cannot be projected: {latFirstInRadians}; } rh1 = 0; } - theta = ns * adjust_lon_radians(lonFirstInRadians - LoVInRadians); - x0 = rh1 * sin(theta); - y0 = rh - rh1 * cos(theta); - x0 = -x0; - y0 = -y0; - - // Allocate latitude and longitude arrays - self->lats = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - // Populate our arrays - false_easting = x0; - false_northing = y0; - for (j = 0; j < ny; j++) { - y = j * Dy; - for (i = 0; i < nx; i++) { - const int index = i + j * nx; - double _x, _y; - x = i * Dx; - // Inverse projection to convert from x,y to lat,lon - _x = x - false_easting; - _y = rh - y + false_northing; - rh1 = sqrt(_x * _x + _y * _y); - con = 1.0; - if (ns <= 0) { - rh1 = -rh1; - con = -con; - } - theta = 0.0; - if (rh1 != 0) - theta = atan2((con * _x), (con * _y)); - if ((rh1 != 0) || (ns > 0.0)) { - con = 1.0 / ns; - ts = pow((rh1 / (earthMajorAxisInMetres * F)), con); - latRad = compute_phi(e, ts, &err); - if (err) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "%s: Failed to compute the latitude angle, phi2, for the inverse", ITER); - grib_context_free(h->context, self->lats); - grib_context_free(h->context, self->lons); - return err; - } - } - else { - latRad = -M_PI_2; - } - lonRad = adjust_lon_radians(theta / ns + LoVInRadians); - if (i == 0 && j == 0) { - ASSERT(fabs(latFirstInRadians - latRad) <= EPSILON); - } - latDeg = latRad * util::RADIAN_TO_DEGREE; // Convert to degrees - lonDeg = normalise_longitude_in_degrees(lonRad * util::RADIAN_TO_DEGREE); - self->lons[index] = lonDeg; - self->lats[index] = latDeg; - } - } - return GRIB_SUCCESS; -} + double theta0 = ns * adjust_lon_radians(lonFirstInRadians - LoVInRadians); + x0 = -rh1 * sin(theta0); + y0 = rh1 * cos(theta0) - rh; -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { - int err = 0, is_oblate = 0; - long nx, ny, iScansNegatively, jScansPositively, jPointsAreConsecutive, alternativeRowScanning; - double LoVInDegrees, LaDInDegrees, Latin1InDegrees, Latin2InDegrees, latFirstInDegrees, lonFirstInDegrees, Dx, Dy, - radius = 0; - double latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians; - double earthMajorAxisInMetres = 0, earthMinorAxisInMetres = 0; - - grib_iterator_lambert_conformal* self = (grib_iterator_lambert_conformal*)iter; - - const char* sradius = grib_arguments_get_name(h, args, self->carg++); - const char* snx = grib_arguments_get_name(h, args, self->carg++); - const char* sny = grib_arguments_get_name(h, args, self->carg++); - const char* sLoVInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sLaDInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sLatin1InDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sLatin2InDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* slatFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* slonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - // Dx and Dy are in Metres - const char* sDx = grib_arguments_get_name(h, args, self->carg++); - const char* sDy = grib_arguments_get_name(h, args, self->carg++); - const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); - const char* salternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); - - if ((err = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) - return err; - - is_oblate = grib_is_earth_oblate(h); - - if (is_oblate) { - if ((err = grib_get_double_internal(h, "earthMinorAxisInMetres", &earthMinorAxisInMetres)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, "earthMajorAxisInMetres", &earthMajorAxisInMetres)) != GRIB_SUCCESS) - return err; - } - else { - if ((err = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) - return err; - } + // Inverse projection to convert from x,y to lat,lon + double x = 0.; + double y = 0.; - if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, - ny); - return GRIB_WRONG_GRID; - } + Point2 p{x - x0, rh - y + y0}; - if ((err = grib_get_double_internal(h, sLoVInDegrees, &LoVInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sLaDInDegrees, &LaDInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sLatin1InDegrees, &Latin1InDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sLatin2InDegrees, &Latin2InDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, slatFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, slonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sDx, &Dx)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_double_internal(h, sDy, &Dy)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) - return err; - if ((err = grib_get_long_internal(h, salternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) - return err; - - // Standard Parallels cannot be equal and on opposite sides of the equator - if (fabs(Latin1InDegrees + Latin2InDegrees) < EPSILON) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "%s: Cannot have equal latitudes for standard parallels on opposite sides of equator", ITER); - return GRIB_WRONG_GRID; + rh1 = sqrt(p.X * p.X + p.Y * p.Y); + con = 1.0; + if (ns <= 0) { + rh1 = -rh1; + con = -con; } - // - // See Wolfram MathWorld: http://mathworld.wolfram.com/LambertConformalConicProjection.html - // - latFirstInRadians = latFirstInDegrees * util::DEGREE_TO_RADIAN; - lonFirstInRadians = lonFirstInDegrees * util::DEGREE_TO_RADIAN; - Latin1InRadians = Latin1InDegrees * util::DEGREE_TO_RADIAN; - Latin2InRadians = Latin2InDegrees * util::DEGREE_TO_RADIAN; - LaDInRadians = LaDInDegrees * util::DEGREE_TO_RADIAN; - LoVInRadians = LoVInDegrees * util::DEGREE_TO_RADIAN; - - if (is_oblate) { - err = init_oblate(h, self, iter->nv, nx, ny, LoVInDegrees, Dx, Dy, earthMinorAxisInMetres, - earthMajorAxisInMetres, latFirstInRadians, lonFirstInRadians, LoVInRadians, Latin1InRadians, - Latin2InRadians, LaDInRadians); - } - else { - err = init_sphere(h, self, iter->nv, nx, ny, LoVInDegrees, Dx, Dy, radius, latFirstInRadians, lonFirstInRadians, - LoVInRadians, Latin1InRadians, Latin2InRadians, LaDInRadians); - } - if (err) - return err; + double theta = rh1 != 0 ? atan2((con * p.X), (con * p.Y)) : 0.0; - iter->e = -1; + double latRad + = rh1 != 0 || ns > 0.0 ? compute_phi(e, pow((rh1 / (earthMajorAxisInMetres * F)), 1.0 / ns)) : -M_PI_2; + double lonRad = adjust_lon_radians(theta / ns + LoVInRadians); - // Apply the scanning mode flags which may require data array to be transformed - err = transform_iterator_data(h->context, iter->data, iScansNegatively, jScansPositively, jPointsAreConsecutive, - alternativeRowScanning, iter->nv, nx, ny); - return err; + auto q = PointLonLat::make(lonRad * util::RADIAN_TO_DEGREE, latRad * util::RADIAN_TO_DEGREE); } -#endif + + +} // namespace } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LambertConformalConic.h b/src/eckit/geo/projection/LambertConformalConic.h index 07abda721..d92fc213b 100644 --- a/src/eckit/geo/projection/LambertConformalConic.h +++ b/src/eckit/geo/projection/LambertConformalConic.h @@ -18,6 +18,11 @@ namespace eckit::geo::projection { +/** + * @brief LambertConformalConic projection + * @ref Map Projections: A Working Manual, John P. Snyder (1987) + * @ref Wolfram MathWorld (http://mathworld.wolfram.com/LambertConformalConicProjection.html) + */ class LambertConformalConic final : public Projection { public: // -- Types diff --git a/src/eckit/geo/projection/PolarStereographic.cc b/src/eckit/geo/projection/PolarStereographic.cc index c6b503b8b..e35429469 100644 --- a/src/eckit/geo/projection/PolarStereographic.cc +++ b/src/eckit/geo/projection/PolarStereographic.cc @@ -39,213 +39,48 @@ Spec* PolarStereographic::spec() const { } -#if 0 -static constexpr double EPSILON = 1e-10; - - -/* Data struct for Forward and Inverse Projections */ -typedef struct proj_data_t { - double centre_lon; /* central longitude */ - double centre_lat; /* central latitude */ - double sign; /* sign variable */ - double ind; /* flag variable */ - double mcs; /* small m */ - double tcs; /* small t */ - double false_northing; /* y offset in meters */ - double false_easting; /* x offset in meters */ -} proj_data_t; - - -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { - int ret = 0; - double *lats, *lons; /* arrays for latitudes and longitudes */ - double lonFirstInDegrees, latFirstInDegrees, radius; - double x, y, Dx, Dy; - long nx, ny; - double centralLongitudeInDegrees, centralLatitudeInDegrees; - long alternativeRowScanning, iScansNegatively, i, j; - long jScansPositively, jPointsAreConsecutive, southPoleOnPlane; - double centralLongitude, centralLatitude; /* in radians */ - double con1; /* temporary angle */ - double ts; /* value of small t */ - double height; /* height above ellipsoid */ - double x0, y0, lonFirst, latFirst; - proj_data_t fwd_proj_data = { - 0, - }; - proj_data_t inv_proj_data = { - 0, - }; - - grib_iterator_polar_stereographic* self = (grib_iterator_polar_stereographic*)iter; - - const char* s_radius = grib_arguments_get_name(h, args, self->carg++); - const char* s_nx = grib_arguments_get_name(h, args, self->carg++); - const char* s_ny = grib_arguments_get_name(h, args, self->carg++); - const char* s_latFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* s_lonFirstInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* s_southPoleOnPlane = grib_arguments_get_name(h, args, self->carg++); - const char* s_centralLongitude = grib_arguments_get_name(h, args, self->carg++); - const char* s_centralLatitude = grib_arguments_get_name(h, args, self->carg++); - const char* s_Dx = grib_arguments_get_name(h, args, self->carg++); - const char* s_Dy = grib_arguments_get_name(h, args, self->carg++); - const char* s_iScansNegatively = grib_arguments_get_name(h, args, self->carg++); - const char* s_jScansPositively = grib_arguments_get_name(h, args, self->carg++); - const char* s_jPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); - const char* s_alternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); - - if (grib_is_earth_oblate(h)) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Only supported for spherical earth.", ITER); - return GRIB_GEOCALCULUS_PROBLEM; - } - - if ((ret = grib_get_double_internal(h, s_radius, &radius)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_nx, &nx)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_ny, &ny)) != GRIB_SUCCESS) - return ret; - - if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, - ny); - return GRIB_WRONG_GRID; - } - if ((ret = grib_get_double_internal(h, s_latFirstInDegrees, &latFirstInDegrees)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, s_lonFirstInDegrees, &lonFirstInDegrees)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_southPoleOnPlane, &southPoleOnPlane)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, s_centralLongitude, ¢ralLongitudeInDegrees)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, s_centralLatitude, ¢ralLatitudeInDegrees)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, s_Dx, &Dx)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, s_Dy, &Dy)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_jPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_jScansPositively, &jScansPositively)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_iScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, s_alternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) - return ret; - - centralLongitude = centralLongitudeInDegrees * util::DEGREE_TO_RADIAN; - centralLatitude = centralLatitudeInDegrees * util::DEGREE_TO_RADIAN; - lonFirst = lonFirstInDegrees * util::DEGREE_TO_RADIAN; - latFirst = latFirstInDegrees * util::DEGREE_TO_RADIAN; - - /* Forward projection initialisation */ - fwd_proj_data.false_northing = 0; - fwd_proj_data.false_easting = 0; - fwd_proj_data.centre_lon = centralLongitude; - fwd_proj_data.centre_lat = centralLatitude; - if (centralLatitude < 0) - fwd_proj_data.sign = -1.0; - else - fwd_proj_data.sign = +1.0; - fwd_proj_data.ind = 0; - if (fabs(fabs(centralLatitude) - M_PI_2) > EPSILON) { - /* central latitude different from 90 i.e. not north/south polar */ - fwd_proj_data.ind = 1; - con1 = fwd_proj_data.sign * centralLatitude; - fwd_proj_data.mcs = cos(con1); - fwd_proj_data.tcs = tan(0.5 * (M_PI_2 - con1)); - } +namespace { + + +void init() { + static constexpr double EPSILON = 1e-10; + + const double radius = 1.; + const double centralLongitude = util::DEGREE_TO_RADIAN * 0. /*centralLongitudeInDegrees*/; + const double centralLatitude = util::DEGREE_TO_RADIAN * 0. /*centralLatitudeInDegrees*/; + const double lonFirst = util::DEGREE_TO_RADIAN * 0. /*lonFirstInDegrees*/; + const double latFirst = util::DEGREE_TO_RADIAN * 0. /*latFirstInDegrees*/; + + const double sign = centralLatitude < 0 ? -1. : 1.; + const bool ind = fabs(fabs(centralLatitude) - M_PI_2) > EPSILON; + + const double mcs = ind ? cos(sign * centralLatitude) : 0.; + const double tcs = ind ? tan(0.5 * (M_PI_2 - sign * centralLatitude)) : 0.; /* Forward projection from initial lat,lon to initial x,y */ - con1 = fwd_proj_data.sign * (lonFirst - fwd_proj_data.centre_lon); - ts = tan(0.5 * (M_PI_2 - fwd_proj_data.sign * latFirst)); - if (fwd_proj_data.ind) - height = radius * fwd_proj_data.mcs * ts / fwd_proj_data.tcs; - else - height = 2.0 * radius * ts; - x0 = fwd_proj_data.sign * height * sin(con1) + fwd_proj_data.false_easting; - y0 = -fwd_proj_data.sign * height * cos(con1) + fwd_proj_data.false_northing; - - x0 = -x0; - y0 = -y0; - - /* Inverse projection initialisation */ - inv_proj_data.false_easting = x0; - inv_proj_data.false_northing = y0; - inv_proj_data.centre_lon = centralLongitude; - inv_proj_data.centre_lat = centralLatitude; - if (centralLatitude < 0) - inv_proj_data.sign = -1.0; - else - inv_proj_data.sign = +1.0; - inv_proj_data.ind = 0; - if (fabs(fabs(centralLatitude) - M_PI_2) > EPSILON) { - inv_proj_data.ind = 1; - con1 = inv_proj_data.sign * inv_proj_data.centre_lat; - inv_proj_data.mcs = cos(con1); - inv_proj_data.tcs = tan(0.5 * (M_PI_2 - con1)); - } - self->lats = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, iter->nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, iter->nv * sizeof(double)); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, iter->nv * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - lats = self->lats; - lons = self->lons; - /* These will be processed later in transform_iterator_data() */ - /* Dx = iScansNegatively == 0 ? Dx : -Dx; */ - /* Dy = jScansPositively == 1 ? Dy : -Dy; */ - - y = 0; - for (j = 0; j < ny; j++) { - x = 0; - for (i = 0; i < nx; i++) { - /* Inverse projection from x,y to lat,lon */ - /* int index =i+j*nx; */ - double _x = (x - inv_proj_data.false_easting) * inv_proj_data.sign; - double _y = (y - inv_proj_data.false_northing) * inv_proj_data.sign; - double rh = sqrt(_x * _x + _y * _y); - if (inv_proj_data.ind) - ts = rh * inv_proj_data.tcs / (radius * inv_proj_data.mcs); - else - ts = rh / (radius * 2.0); - *lats = inv_proj_data.sign * (M_PI_2 - 2 * atan(ts)); - if (rh == 0) { - *lons = inv_proj_data.sign * inv_proj_data.centre_lon; - } - else { - double temp = atan2(_x, -_y); - *lons = inv_proj_data.sign * temp + inv_proj_data.centre_lon; - } - *lats = *lats * util::RADIAN_TO_DEGREE; - *lons = *lons * util::RADIAN_TO_DEGREE; - while (*lons < 0) - *lons += 360; - while (*lons > 360) - *lons -= 360; - lons++; - lats++; - - x += Dx; - } - y += Dy; - } - - iter->e = -1; - - /* Apply the scanning mode flags which may require data array to be transformed */ - ret = transform_iterator_data(h->context, iter->data, iScansNegatively, jScansPositively, jPointsAreConsecutive, - alternativeRowScanning, iter->nv, nx, ny); - - return ret; + double tsf = tan(0.5 * (M_PI_2 - sign * latFirst)); + double height = ind ? radius * mcs * tsf / tcs : 2.0 * radius * tsf; + + double a = sign * (lonFirst - centralLongitude); + double x0 = -sign * height * sin(a); + double y0 = sign * height * cos(a); + + /* Inverse projection from x,y to lat,lon */ + double x = 0; + double y = 0; + Point2 p{(x - x0) * sign, (y - y0) * sign}; + + double rh = sqrt(p.X * p.X + p.Y * p.Y); + double tsi = ind ? rh * tcs / (radius * mcs) : rh / (radius * 2.0); + + double latr = sign * (M_PI_2 - 2 * atan(tsi)); + double lonr = rh == 0 ? sign * centralLongitude : sign * atan2(p.X, -p.Y) + centralLongitude; + + PointLonLat::make(lonr * util::RADIAN_TO_DEGREE, latr * util::RADIAN_TO_DEGREE); } -#endif + + +} // namespace } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/SpaceView.cc b/src/eckit/geo/projection/SpaceView.cc index d03d76b02..3a716b27b 100644 --- a/src/eckit/geo/projection/SpaceView.cc +++ b/src/eckit/geo/projection/SpaceView.cc @@ -21,7 +21,18 @@ namespace eckit::geo::projection { -SpaceView::SpaceView(const Spec&) {} +SpaceView::SpaceView(const Spec&) { + // Orthographic not supported. This happens when Nr (camera altitude) is missing + + // if (latOfSubSatellitePointInDegrees != 0.0) { + // grib_context_log(h->context, GRIB_LOG_ERROR, + // "%s: Key %s must be 0 (satellite must be located in the equator plane)", ITER, + // sLatOfSubSatellitePointInDegrees); + // return GRIB_GEOCALCULUS_PROBLEM; + // } + + // (orientationInDegrees != 0.0) not spported +} Point SpaceView::fwd(const Point&) const { @@ -39,246 +50,64 @@ Spec* SpaceView::spec() const { } -#if 0 -static int init(grib_iterator* iter, grib_handle* h, grib_arguments* args) { - /* REFERENCE: - * LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) - */ - int ret = GRIB_SUCCESS; - double *lats, *lons; /* arrays of latitudes and longitudes */ - double latOfSubSatellitePointInDegrees, lonOfSubSatellitePointInDegrees; - double orientationInDegrees, nrInRadiusOfEarth; - double radius = 0, xpInGridLengths = 0, ypInGridLengths = 0; - long nx, ny, earthIsOblate = 0; - long alternativeRowScanning, iScansNegatively; - long Xo, Yo, jScansPositively, jPointsAreConsecutive, i; - - double major = 0, minor = 0, r_eq, r_pol, height; - double lap, lop, angular_size; - double xp, yp, dx, dy, rx, ry, x, y; - double cos_x, cos_y, sin_x, sin_y; - double factor_1, factor_2, tmp1, Sd, Sn, Sxy, S1, S2, S3; - int x0, y0, ix, iy; - double *s_x, *c_x; /* arrays storing sin and cos values */ - size_t array_size = (iter->nv * sizeof(double)); - - grib_iterator_space_view* self = (grib_iterator_space_view*)iter; - - const char* sradius = grib_arguments_get_name(h, args, self->carg++); - const char* sEarthIsOblate = grib_arguments_get_name(h, args, self->carg++); - const char* sMajorAxisInMetres = grib_arguments_get_name(h, args, self->carg++); - const char* sMinorAxisInMetres = grib_arguments_get_name(h, args, self->carg++); - const char* snx = grib_arguments_get_name(h, args, self->carg++); - const char* sny = grib_arguments_get_name(h, args, self->carg++); - const char* sLatOfSubSatellitePointInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sLonOfSubSatellitePointInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sDx = grib_arguments_get_name(h, args, self->carg++); - const char* sDy = grib_arguments_get_name(h, args, self->carg++); - const char* sXpInGridLengths = grib_arguments_get_name(h, args, self->carg++); - const char* sYpInGridLengths = grib_arguments_get_name(h, args, self->carg++); - const char* sOrientationInDegrees = grib_arguments_get_name(h, args, self->carg++); - const char* sNrInRadiusOfEarthScaled = grib_arguments_get_name(h, args, self->carg++); - const char* sXo = grib_arguments_get_name(h, args, self->carg++); - const char* sYo = grib_arguments_get_name(h, args, self->carg++); - - const char* siScansNegatively = grib_arguments_get_name(h, args, self->carg++); - const char* sjScansPositively = grib_arguments_get_name(h, args, self->carg++); - const char* sjPointsAreConsecutive = grib_arguments_get_name(h, args, self->carg++); - const char* sAlternativeRowScanning = grib_arguments_get_name(h, args, self->carg++); - - if ((ret = grib_get_long_internal(h, snx, &nx)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sny, &ny)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sEarthIsOblate, &earthIsOblate)) != GRIB_SUCCESS) - return ret; - - if (earthIsOblate) { - if ((ret = grib_get_double_internal(h, sMajorAxisInMetres, &major)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sMinorAxisInMetres, &minor)) != GRIB_SUCCESS) - return ret; - } - else { - if ((ret = grib_get_double_internal(h, sradius, &radius)) != GRIB_SUCCESS) - return ret; - } +namespace { - if (iter->nv != nx * ny) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Wrong number of points (%zu!=%ldx%ld)", ITER, iter->nv, nx, - ny); - return GRIB_WRONG_GRID; - } - if ((ret = grib_get_double_internal(h, sLatOfSubSatellitePointInDegrees, &latOfSubSatellitePointInDegrees)) - != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sLonOfSubSatellitePointInDegrees, &lonOfSubSatellitePointInDegrees)) - != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sDx, &dx)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sDy, &dy)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sXpInGridLengths, &xpInGridLengths)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sYpInGridLengths, &ypInGridLengths)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_double_internal(h, sOrientationInDegrees, &orientationInDegrees)) != GRIB_SUCCESS) - return ret; - - /* Orthographic not supported. This happens when Nr (camera altitude) is missing */ - if (grib_is_missing(h, "Nr", &ret)) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Orthographic view (Nr missing) not supported", ITER); - return GRIB_GEOCALCULUS_PROBLEM; - } - if ((ret = grib_get_double_internal(h, sNrInRadiusOfEarthScaled, &nrInRadiusOfEarth)) != GRIB_SUCCESS) - return ret; - - if ((ret = grib_get_long_internal(h, sXo, &Xo)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sYo, &Yo)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sjPointsAreConsecutive, &jPointsAreConsecutive)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sjScansPositively, &jScansPositively)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, siScansNegatively, &iScansNegatively)) != GRIB_SUCCESS) - return ret; - if ((ret = grib_get_long_internal(h, sAlternativeRowScanning, &alternativeRowScanning)) != GRIB_SUCCESS) - return ret; - - if (earthIsOblate) { - r_eq = major; /* In km */ - r_pol = minor; - } - else { - r_eq = r_pol = radius * 0.001; /*conv to km*/ - } - if (nrInRadiusOfEarth == 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Key %s must be greater than zero", ITER, - sNrInRadiusOfEarthScaled); - return GRIB_GEOCALCULUS_PROBLEM; - } +void init() { + double lonOfSubSatellitePointInDegrees = 0.; + double nrInRadiusOfEarth = 1.; + double xpInGridLengths = 0.; + double ypInGridLengths = 0.; + long Xo = 0; + long Yo = 0; - angular_size = 2.0 * asin(1.0 / nrInRadiusOfEarth); - height = nrInRadiusOfEarth * r_eq; + double earthMajorAxis = 1. / 1000.; // [km] + double earthMinorAxis = 1. / 1000.; - lap = latOfSubSatellitePointInDegrees; - lop = lonOfSubSatellitePointInDegrees; - if (lap != 0.0) { - grib_context_log(h->context, GRIB_LOG_ERROR, - "%s: Key %s must be 0 (satellite must be located in the equator plane)", ITER, - sLatOfSubSatellitePointInDegrees); - return GRIB_GEOCALCULUS_PROBLEM; - } + double angular_size = 2.0 * asin(1.0 / nrInRadiusOfEarth); + double height = nrInRadiusOfEarth * earthMajorAxis; - /*orient_angle = orientationInDegrees;*/ - /* if (orient_angle != 0.0) return GRIB_NOT_IMPLEMENTED; */ + double lop = lonOfSubSatellitePointInDegrees; - xp = xpInGridLengths; - yp = ypInGridLengths; - x0 = Xo; - y0 = Yo; + double dx = 1.; + double dy = 1.; - /* adjustBadlyEncodedEcmwfGribs(h, &nx, &ny, &dx, &dy, &xp, &yp); */ - if (dx == 0 || dy == 0) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Keys %s and %s must be greater than zero", ITER, sDx, sDy); - return GRIB_GEOCALCULUS_PROBLEM; - } - rx = angular_size / dx; - ry = (r_pol / r_eq) * angular_size / dy; + auto x0 = static_cast(Xo); + auto y0 = static_cast(Yo); - self->lats = (double*)grib_context_malloc(h->context, array_size); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, array_size); - return GRIB_OUT_OF_MEMORY; - } - self->lons = (double*)grib_context_malloc(h->context, array_size); - if (!self->lats) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, array_size); - return GRIB_OUT_OF_MEMORY; - } - lats = self->lats; - lons = self->lons; + double xp = xpInGridLengths - x0; + double yp = ypInGridLengths - y0; - if (!iScansNegatively) { - xp = xp - x0; - } - else { - xp = (nx - 1) - (xp - x0); - } - if (jScansPositively) { - yp = yp - y0; + double rx = angular_size / dx; + double ry = (earthMinorAxis / earthMajorAxis) * angular_size / dy; + + Point2 p; + Point2 q{(p.X - xp) * rx, (p.Y - yp) * ry}; + + double factor_1 = height * height - earthMajorAxis * earthMajorAxis; + double factor_2 = (earthMajorAxis / earthMinorAxis) * (earthMajorAxis / earthMinorAxis); + double factor_3 = (1 + (factor_2 - 1.0) * sin(q.Y) * sin(q.Y)); + + double Sd = height * cos(q.X) * cos(q.Y); + Sd = sqrt(Sd * Sd - factor_3 * factor_1); + if (Sd <= 0.0) { + Point q; } else { - yp = (ny - 1) - (yp - y0); - } - i = 0; - factor_2 = (r_eq / r_pol) * (r_eq / r_pol); - factor_1 = height * height - r_eq * r_eq; - - /* Store array of sin and cosine values to avoid recalculation */ - s_x = (double*)grib_context_malloc(h->context, nx * sizeof(double)); - if (!s_x) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nx * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } - c_x = (double*)grib_context_malloc(h->context, nx * sizeof(double)); - if (!c_x) { - grib_context_log(h->context, GRIB_LOG_ERROR, "%s: Error allocating %zu bytes", ITER, nx * sizeof(double)); - return GRIB_OUT_OF_MEMORY; - } + double Sn = (height * cos(q.X) * cos(q.Y) - Sd) / factor_3; + double S1 = height - Sn * cos(q.X) * cos(q.Y); + double S2 = Sn * sin(q.X) * cos(q.Y); + double S3 = Sn * sin(q.Y); + double Sxy = sqrt(S1 * S1 + S2 * S2); - for (ix = 0; ix < nx; ix++) { - x = (ix - xp) * rx; - s_x[ix] = sin(x); - c_x[ix] = sqrt(1.0 - s_x[ix] * s_x[ix]); + auto lonr = atan(S2 / S1) + lop; + auto latr = atan(factor_2 * S3 / Sxy); + PointLonLat::make(util::RADIAN_TO_DEGREE * lonr, util::RADIAN_TO_DEGREE * latr); } +} - /*for (iy = 0; iy < ny; iy++) {*/ - for (iy = ny - 1; iy >= 0; --iy) { - y = (iy - yp) * ry; - sin_y = sin(y); - cos_y = sqrt(1.0 - sin_y * sin_y); - - tmp1 = (1 + (factor_2 - 1.0) * sin_y * sin_y); - - for (ix = 0; ix < nx; ix++, i++) { - /*x = (ix - xp) * rx;*/ - /* Use sin/cos previously computed */ - sin_x = s_x[ix]; - cos_x = c_x[ix]; - - Sd = height * cos_x * cos_y; - Sd = Sd * Sd - tmp1 * factor_1; - if (Sd <= 0.0) { /* outside of view */ - lats[i] = lons[i] = 0; /* TODO: error? */ - } - else { - Sd = sqrt(Sd); - Sn = (height * cos_x * cos_y - Sd) / tmp1; - S1 = height - Sn * cos_x * cos_y; - S2 = Sn * sin_x * cos_y; - S3 = Sn * sin_y; - Sxy = sqrt(S1 * S1 + S2 * S2); - lons[i] = atan(S2 / S1) * (util::RADIAN_TO_DEGREE) + lop; - lats[i] = atan(factor_2 * S3 / Sxy) * (util::RADIAN_TO_DEGREE); - /*fprintf(stderr, "lat=%g lon=%g\n", lats[i], lons[i]);*/ - } - while (lons[i] < 0) - lons[i] += 360; - while (lons[i] > 360) - lons[i] -= 360; - } - } - grib_context_free(h->context, s_x); - grib_context_free(h->context, c_x); - iter->e = -1; - return ret; -} -#endif +} // namespace } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/SpaceView.h b/src/eckit/geo/projection/SpaceView.h index 676a6c880..bbd916949 100644 --- a/src/eckit/geo/projection/SpaceView.h +++ b/src/eckit/geo/projection/SpaceView.h @@ -18,6 +18,10 @@ namespace eckit::geo::projection { +/** + * @brief SpaceView projection + * @ref LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) + */ class SpaceView final : public Projection { public: // -- Types From 80e32224e167937355be7da2746be4254976b461 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 10 May 2024 14:16:08 +0100 Subject: [PATCH 631/737] eckit::geo rearranged eccodes projections --- src/eckit/geo/projection/LambertAzimuthalEqualArea.cc | 4 ++-- src/eckit/geo/projection/LambertAzimuthalEqualArea.h | 11 ++++++----- src/eckit/geo/projection/LambertConformalConic.cc | 4 ++-- src/eckit/geo/projection/LambertConformalConic.h | 11 ++++++----- src/eckit/geo/projection/PolarStereographic.cc | 4 ++-- src/eckit/geo/projection/PolarStereographic.h | 11 ++++++----- src/eckit/geo/projection/SpaceView.cc | 4 ++-- src/eckit/geo/projection/SpaceView.h | 11 ++++++----- 8 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc index 647b676dd..8c7da656d 100644 --- a/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc @@ -24,12 +24,12 @@ namespace eckit::geo::projection { LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Spec&) {} -Point LambertAzimuthalEqualArea::fwd(const Point&) const { +Point2 LambertAzimuthalEqualArea::fwd(const PointLonLat&) const { NOTIMP; } -Point LambertAzimuthalEqualArea::inv(const Point&) const { +PointLonLat LambertAzimuthalEqualArea::inv(const Point2&) const { NOTIMP; } diff --git a/src/eckit/geo/projection/LambertAzimuthalEqualArea.h b/src/eckit/geo/projection/LambertAzimuthalEqualArea.h index 5044a147a..f54e028bf 100644 --- a/src/eckit/geo/projection/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/projection/LambertAzimuthalEqualArea.h @@ -40,12 +40,11 @@ class LambertAzimuthalEqualArea final : public Projection { // None // -- Methods - // None - // -- Overridden methods + Point2 fwd(const PointLonLat& p) const; + PointLonLat inv(const Point2& q) const; - Point fwd(const Point&) const override; - Point inv(const Point&) const override; + // -- Overridden methods [[nodiscard]] Spec* spec() const override; @@ -63,7 +62,9 @@ class LambertAzimuthalEqualArea final : public Projection { // None // -- Overridden methods - // None + + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } // -- Class members // None diff --git a/src/eckit/geo/projection/LambertConformalConic.cc b/src/eckit/geo/projection/LambertConformalConic.cc index eb87492dc..3cd780f1d 100644 --- a/src/eckit/geo/projection/LambertConformalConic.cc +++ b/src/eckit/geo/projection/LambertConformalConic.cc @@ -31,12 +31,12 @@ LambertConformalConic::LambertConformalConic(const Spec&) { } -Point LambertConformalConic::fwd(const Point&) const { +Point2 LambertConformalConic::fwd(const PointLonLat&) const { NOTIMP; } -Point LambertConformalConic::inv(const Point&) const { +PointLonLat LambertConformalConic::inv(const Point2&) const { NOTIMP; } diff --git a/src/eckit/geo/projection/LambertConformalConic.h b/src/eckit/geo/projection/LambertConformalConic.h index d92fc213b..adfd0a533 100644 --- a/src/eckit/geo/projection/LambertConformalConic.h +++ b/src/eckit/geo/projection/LambertConformalConic.h @@ -45,12 +45,11 @@ class LambertConformalConic final : public Projection { // None // -- Methods - // None - // -- Overridden methods + Point2 fwd(const PointLonLat& p) const; + PointLonLat inv(const Point2& q) const; - Point fwd(const Point&) const override; - Point inv(const Point&) const override; + // -- Overridden methods [[nodiscard]] Spec* spec() const override; @@ -68,7 +67,9 @@ class LambertConformalConic final : public Projection { // None // -- Overridden methods - // None + + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } // -- Class members // None diff --git a/src/eckit/geo/projection/PolarStereographic.cc b/src/eckit/geo/projection/PolarStereographic.cc index e35429469..031f36747 100644 --- a/src/eckit/geo/projection/PolarStereographic.cc +++ b/src/eckit/geo/projection/PolarStereographic.cc @@ -24,12 +24,12 @@ namespace eckit::geo::projection { PolarStereographic::PolarStereographic(const Spec&) {} -Point PolarStereographic::fwd(const Point&) const { +Point2 PolarStereographic::fwd(const PointLonLat&) const { NOTIMP; } -Point PolarStereographic::inv(const Point&) const { +PointLonLat PolarStereographic::inv(const Point2&) const { NOTIMP; } diff --git a/src/eckit/geo/projection/PolarStereographic.h b/src/eckit/geo/projection/PolarStereographic.h index fdb703e89..90d67a473 100644 --- a/src/eckit/geo/projection/PolarStereographic.h +++ b/src/eckit/geo/projection/PolarStereographic.h @@ -40,12 +40,11 @@ class PolarStereographic final : public Projection { // None // -- Methods - // None - // -- Overridden methods + Point2 fwd(const PointLonLat& p) const; + PointLonLat inv(const Point2& q) const; - Point fwd(const Point&) const override; - Point inv(const Point&) const override; + // -- Overridden methods [[nodiscard]] Spec* spec() const override; @@ -63,7 +62,9 @@ class PolarStereographic final : public Projection { // None // -- Overridden methods - // None + + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } // -- Class members // None diff --git a/src/eckit/geo/projection/SpaceView.cc b/src/eckit/geo/projection/SpaceView.cc index 3a716b27b..f2ae81f54 100644 --- a/src/eckit/geo/projection/SpaceView.cc +++ b/src/eckit/geo/projection/SpaceView.cc @@ -35,12 +35,12 @@ SpaceView::SpaceView(const Spec&) { } -Point SpaceView::fwd(const Point&) const { +Point2 SpaceView::fwd(const PointLonLat&) const { NOTIMP; } -Point SpaceView::inv(const Point&) const { +PointLonLat SpaceView::inv(const Point2&) const { NOTIMP; } diff --git a/src/eckit/geo/projection/SpaceView.h b/src/eckit/geo/projection/SpaceView.h index bbd916949..d31e3a85d 100644 --- a/src/eckit/geo/projection/SpaceView.h +++ b/src/eckit/geo/projection/SpaceView.h @@ -44,12 +44,11 @@ class SpaceView final : public Projection { // None // -- Methods - // None - // -- Overridden methods + Point2 fwd(const PointLonLat& p) const; + PointLonLat inv(const Point2& q) const; - Point fwd(const Point&) const override; - Point inv(const Point&) const override; + // -- Overridden methods [[nodiscard]] Spec* spec() const override; @@ -67,7 +66,9 @@ class SpaceView final : public Projection { // None // -- Overridden methods - // None + + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } // -- Class members // None From 895541c8981cdc0a1c77dee4f0ed06ec382e81b5 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 10 May 2024 15:37:09 +0100 Subject: [PATCH 632/737] eckit::geo::ProjectionProblem --- src/eckit/geo/CMakeLists.txt | 1 + src/eckit/geo/PointLonLat.cc | 6 +++--- src/eckit/geo/Projection.cc | 28 ++++++++++++++++++++++++++++ src/eckit/geo/Projection.h | 7 +++++++ 4 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 src/eckit/geo/Projection.cc diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 1ae519b09..297a121f2 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -27,6 +27,7 @@ list(APPEND eckit_geo_srcs Point3.h PointLonLat.cc PointLonLat.h + Projection.cc Projection.h Range.cc Range.h diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index bc2360a3e..dcb1c542f 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -32,10 +32,10 @@ PointLonLat::value_type PointLonLat::normalise_angle_to_minimum(value_type a, va PointLonLat::value_type PointLonLat::normalise_angle_to_maximum(value_type a, value_type maximum) { - auto modulo_360 = [](auto a) { return a - GLOBE * std::ceil(a / GLOBE); }; + auto modulo_globe = [](auto a) { return a - GLOBE * std::ceil(a / GLOBE); }; auto diff = a - maximum; - return -GLOBE < diff && diff <= 0. ? a : modulo_360(a - maximum) + maximum; + return -GLOBE < diff && diff <= 0. ? a : modulo_globe(a - maximum) + maximum; } @@ -43,7 +43,7 @@ void PointLonLat::assert_latitude_range(const PointLonLat& P) { if (!(SOUTH_POLE <= P.lat && P.lat <= NORTH_POLE)) { std::ostringstream oss; oss.precision(std::numeric_limits::max_digits10); - oss << "Invalid latitude " << P.lat; + oss << "Invalid latitude [degree] " << P.lat; throw BadValue(oss.str(), Here()); } } diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc new file mode 100644 index 000000000..29080179b --- /dev/null +++ b/src/eckit/geo/Projection.cc @@ -0,0 +1,28 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Projection.h" + +#include + + +namespace eckit::geo { + + +ProjectionProblem::ProjectionProblem(const std::string& what, const CodeLocation& loc) : Exception(loc) { + std::ostringstream s; + s << "ProjectionProblem: [" << what << "], in " << loc; + reason(s.str()); +}; + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 6e0174dab..2d50dc81f 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -14,6 +14,7 @@ #include +#include "eckit/exception/Exceptions.h" #include "eckit/geo/Point.h" #include "eckit/memory/Builder.h" #include "eckit/memory/Factory.h" @@ -30,6 +31,12 @@ class Custom; namespace eckit::geo { +class ProjectionProblem : public Exception { +public: + explicit ProjectionProblem(const std::string&, const CodeLocation&); +}; + + class Projection { public: // -- Types From 845a427fc6fb6abbac3d6770c7877f774f776a54 Mon Sep 17 00:00:00 2001 From: Iain Russell <40060766+iainrussell@users.noreply.github.com> Date: Fri, 10 May 2024 15:41:00 +0100 Subject: [PATCH 633/737] eckit::geo enable geo module in downstream-ci --- .github/ci-config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ci-config.yml b/.github/ci-config.yml index 52a3c0a16..90f642a2d 100644 --- a/.github/ci-config.yml +++ b/.github/ci-config.yml @@ -1,3 +1,4 @@ +cmake_options: -DENABLE_ECKIT_GEO=ON -DENABLE_PROJ=ON dependencies: | ecmwf/ecbuild dependency_branch: develop From 48f36ee3e37e92651f8890eae7ad679738ed2f69 Mon Sep 17 00:00:00 2001 From: Iain Russell <40060766+iainrussell@users.noreply.github.com> Date: Fri, 10 May 2024 16:39:47 +0100 Subject: [PATCH 634/737] eckit::geo remove proj testing in downstream-ci for now --- .github/ci-config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ci-config.yml b/.github/ci-config.yml index 90f642a2d..c1c0c52bf 100644 --- a/.github/ci-config.yml +++ b/.github/ci-config.yml @@ -1,4 +1,4 @@ -cmake_options: -DENABLE_ECKIT_GEO=ON -DENABLE_PROJ=ON +cmake_options: -DENABLE_ECKIT_GEO=ON dependencies: | ecmwf/ecbuild dependency_branch: develop From bcba07ac49c03dde89a36155c718f80a052185bf Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 10 May 2024 17:30:59 +0100 Subject: [PATCH 635/737] eckit::geo::Projection --- .../projection/LambertAzimuthalEqualArea.cc | 177 ++++-------------- .../projection/LambertAzimuthalEqualArea.h | 32 +++- 2 files changed, 70 insertions(+), 139 deletions(-) diff --git a/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc index 8c7da656d..5fd68f837 100644 --- a/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc @@ -14,174 +14,75 @@ #include -#include "eckit/exception/Exceptions.h" +#include "eckit/geo/Earth.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo::projection { -LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Spec&) {} +static ProjectionBuilder PROJECTION_1("lambert_azimuthal_equal_area"); +static ProjectionBuilder PROJECTION_2("laea"); -Point2 LambertAzimuthalEqualArea::fwd(const PointLonLat&) const { - NOTIMP; -} - +LambertAzimuthalEqualArea::sincos_t::sincos_t(value_type r) : array{std::sin(r), std::cos(r)} {} -PointLonLat LambertAzimuthalEqualArea::inv(const Point2&) const { - NOTIMP; -} +LambertAzimuthalEqualArea::PointLonLatR::PointLonLatR(value_type lonr, value_type latr) : array{lonr, latr} {} -Spec* LambertAzimuthalEqualArea::spec() const { - NOTIMP; -} +LambertAzimuthalEqualArea::PointLonLatR::PointLonLatR(const PointLonLat& p) : + PointLonLatR{p.lon * util::DEGREE_TO_RADIAN, p.lat * util::DEGREE_TO_RADIAN} {} -static constexpr double EPSILON = 1e-10; -static constexpr double P00 = .33333333333333333333; // 1 / 3 -static constexpr double P01 = .17222222222222222222; // 31 / 180 -static constexpr double P02 = .10257936507936507937; // 517 / 5040 -static constexpr double P10 = .06388888888888888888; // 23 / 360 -static constexpr double P11 = .06640211640211640212; // 251 / 3780 -static constexpr double P20 = .01677689594356261023; // 761 / 45360 +LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Spec& spec) : + LambertAzimuthalEqualArea({spec.get_double("lon_0"), spec.get_double("lat_0")}, + {spec.get_double("lon_first"), spec.get_double("lat_first")}) {} -static double pj_authlat(double beta, const double* APA) { - double t = beta + beta; - return (beta + APA[0] * sin(t) + APA[1] * sin(t + t) + APA[2] * sin(t + t + t)); -} +LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(PointLonLat centre, PointLonLat first) : + centre_(centre), + centre_r_(centre), + first_(first), + first_r_(first), + phi0_(centre_r_.latr), + phi_(first_r_.latr), + dlam_(first_r_.lonr - centre_r_.lonr), + R_(Earth::radius()) {} -static double pj_qsfn(double sinphi, double e, double one_es) { - if (e < 1.e-7) { - return sinphi + sinphi; - } +Point2 LambertAzimuthalEqualArea::fwd(const PointLonLat& p) const { + const auto kp = R_ * std::sqrt(2. / (1. + phi0_.sin * phi_.sin + phi0_.cos * phi_.cos * dlam_.cos)); - double con = e * sinphi; - double div1 = 1.0 - con * con; - double div2 = 1.0 + con; + auto x = kp * phi_.cos * dlam_.sin; + auto y = kp * (phi0_.cos * phi_.sin - phi0_.sin * phi_.cos * dlam_.cos); - /* avoid zero division, fail gracefully */ - return div1 == 0.0 || div2 == 0.0 ? HUGE_VAL : (one_es * (sinphi / div1 - (.5 / e) * log((1. - con) / div2))); + return {x, y}; } -static void init_oblate() { - double earthMinorAxisInMetres = 0; - double earthMajorAxisInMetres = 0; - double latFirstInRadians = 0; - double lonFirstInRadians = 0; - double centralLongitudeInRadians = 0; - double standardParallelInRadians = 0; - - const double temp = (earthMajorAxisInMetres - earthMinorAxisInMetres) / earthMajorAxisInMetres; - const double es = 2 * temp - temp * temp; - const double one_es = 1.0 - es; - const double e = sqrt(es); +PointLonLat LambertAzimuthalEqualArea::inv(const Point2& p) const { + if (auto x = p.X, y = p.Y, rho = std::sqrt(x * x + y * y); !types::is_approximately_equal(rho, 0.)) { + const sincos_t c(2. * std::asin(rho / (2. * R_))); - const double coslam = cos(lonFirstInRadians - centralLongitudeInRadians); /* cos(lp.lam) */ - const double sinlam = sin(lonFirstInRadians - centralLongitudeInRadians); - const double sinphi = sin(latFirstInRadians); /* sin(lp.phi) */ - const double q = pj_qsfn(sinphi, e, one_es); + const auto lonr = centre_r_.lonr + std::atan2(x * c.sin, rho * phi0_.cos * c.cos - y * phi0_.sin * c.sin); + const auto latr = std::asin(c.cos * phi0_.sin + y * c.sin * phi0_.cos / rho); - const double t = fabs(standardParallelInRadians); - if (t > M_PI_2 + EPSILON) { - throw; // GRIB_GEOCALCULUS_PROBLEM; + return PointLonLat::make(util::RADIAN_TO_DEGREE * lonr, util::RADIAN_TO_DEGREE * latr); } - const double Q__qp = pj_qsfn(1.0, e, one_es); - - const double APA[3] - = {es * P00 + es * es * P01 + es * es * es * P02, es * es * P10 + es * es * es * P11, es * es * es * P20}; - - const double Q__rq = sqrt(0.5 * Q__qp); - const double sinphi_ = sin(standardParallelInRadians); /* (P->phi0); */ - const double Q__sinb1 = pj_qsfn(sinphi_, e, one_es) / Q__qp; - const double Q__cosb1 = sqrt(1.0 - Q__sinb1 * Q__sinb1); - const double Q__dd - = Q__cosb1 == 0 ? 1. : cos(standardParallelInRadians) / (sqrt(1. - es * sinphi_ * sinphi_) * Q__rq * Q__cosb1); - const double Q__xmf = Q__rq * Q__dd; - const double Q__ymf = Q__rq / Q__dd; - - const double sinb = q / Q__qp; - const double cosb2 = 1.0 - sinb * sinb; - const double cosb = cosb2 > 0 ? sqrt(cosb2) : 0; - - double b = 1. + Q__sinb1 * sinb + Q__cosb1 * cosb * coslam; - if (fabs(b) < EPSILON) { - throw; // GRIB_GEOCALCULUS_PROBLEM; - } - b = sqrt(2.0 / b); - - /* OBLIQUE */ - const double y0 = Q__ymf * b * (Q__cosb1 * sinb - Q__sinb1 * cosb * coslam); - const double x0 = Q__xmf * b * cosb * sinlam; - - double x = x0; - double y = y0; - - double xy_x = x / Q__dd; - double xy_y = y * Q__dd; - double rho = hypot(xy_x, xy_y); - ASSERT(rho >= EPSILON); - - const double asin_arg = (0.5 * rho / Q__rq); - if (asin_arg < -1.0 || asin_arg > 1.0) { - // Invalid value: arcsin argument={asin_arg} - throw; // GRIB_GEOCALCULUS_PROBLEM; - } - - double cCe = cos(2. * asin(asin_arg)); - double sCe = sin(2. * asin(asin_arg)); - xy_x *= sCe; - - double ab = cCe * Q__sinb1 + xy_y * sCe * Q__cosb1 / rho; - xy_y = rho * Q__cosb1 * cCe - xy_y * Q__sinb1 * sCe; - - double latr = pj_authlat(asin(ab), APA); - double lonr = atan2(xy_x, xy_y) + centralLongitudeInRadians; - - PointLonLat::make(lonr * util::RADIAN_TO_DEGREE, latr * util::RADIAN_TO_DEGREE); + return PointLonLat::make(centre_.lon, centre_.lat); } -void init_sphere() { - double latFirstInRadians = 0.; - double lonFirstInRadians = 0.; - double radius = 1.; - - double lambda0 = 0.; // centralLongitudeInRadians; - double phi1 = 0.; // standardParallelInRadians; - - /* compute xFirst,yFirst in metres */ - auto cosphi1 = cos(phi1); - auto sinphi1 = sin(phi1); - auto sinphi = sin(latFirstInRadians); - auto cosphi = cos(latFirstInRadians); - auto cosdlambda = cos(lonFirstInRadians - lambda0); - auto sindlambda = sin(lonFirstInRadians - lambda0); - - auto kp = radius * sqrt(2.0 / (1 + sinphi1 * sinphi + cosphi1 * cosphi * cosdlambda)); - auto xFirst = kp * cosphi * sindlambda; - auto yFirst = kp * (cosphi1 * sinphi - sinphi1 * cosphi * cosdlambda); - - Point2 p; - - double lonr = phi1; - double latr = lambda0; - - if (auto x = p.X, y = p.Y, rho = sqrt(x * x + y * y); rho > EPSILON) { - double c = 2 * asin(rho / (2.0 * radius)); - double cosc = cos(c); - double sinc = sin(c); - latr = asin(cosc * sinphi1 + y * sinc * cosphi1 / rho); - lonr = (lambda0 + atan2(x * sinc, rho * cosphi1 * cosc - y * sinphi1 * sinc)); - } - - PointLonLat::make(lonr * util::RADIAN_TO_DEGREE, latr * util::RADIAN_TO_DEGREE); +Spec* LambertAzimuthalEqualArea::spec() const { + return new spec::Custom({{"projection", "laea"}, + {"lon_0", centre_.lon}, + {"lat_0", centre_.lat}, + {"lon_first", first_.lon}, + {"lat_first", first_.lat}}); } diff --git a/src/eckit/geo/projection/LambertAzimuthalEqualArea.h b/src/eckit/geo/projection/LambertAzimuthalEqualArea.h index f54e028bf..e8e2ff31a 100644 --- a/src/eckit/geo/projection/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/projection/LambertAzimuthalEqualArea.h @@ -12,6 +12,8 @@ #pragma once +#include + #include "eckit/geo/Projection.h" @@ -29,6 +31,7 @@ class LambertAzimuthalEqualArea final : public Projection { // -- Constructors explicit LambertAzimuthalEqualArea(const Spec&); + LambertAzimuthalEqualArea(PointLonLat centre, PointLonLat first); // -- Destructor // None @@ -55,8 +58,35 @@ class LambertAzimuthalEqualArea final : public Projection { // None private: + // -- Types + + struct PointLonLatR final : protected std::array { + PointLonLatR(value_type lonr, value_type latr); + explicit PointLonLatR(const PointLonLat&); + + const value_type& lonr = array::operator[](0); + const value_type& latr = array::operator[](1); + }; + + struct sincos_t final : std::array { + explicit sincos_t(value_type r); + + const value_type& sin = array::operator[](0); + const value_type& cos = array::operator[](1); + }; + // -- Members - // None + + const PointLonLat centre_; // central longitude/standard parallel [degree] + const PointLonLatR centre_r_; // central_longitude/standard parallel [radian] + + const PointLonLat first_; // first point [degree] + const PointLonLatR first_r_; // first point [radian] + + const sincos_t phi0_; + const sincos_t phi_; + const sincos_t dlam_; + const double R_; // -- Methods // None From c8ca24fc76e2e55547b8f760b6822882d800ebb2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 10 May 2024 17:31:24 +0100 Subject: [PATCH 636/737] eckit::geo::Projection --- src/eckit/geo/projection/Mercator.cc | 5 +++-- src/eckit/geo/projection/Rotation.cc | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/projection/Mercator.cc b/src/eckit/geo/projection/Mercator.cc index 95abe8d62..9e02e7455 100644 --- a/src/eckit/geo/projection/Mercator.cc +++ b/src/eckit/geo/projection/Mercator.cc @@ -23,7 +23,8 @@ namespace eckit::geo::projection { -static ProjectionBuilder PROJECTION("mercator"); +static ProjectionBuilder PROJECTION_1("mercator"); +static ProjectionBuilder PROJECTION_2("merc"); Mercator::Mercator(double meridian, double parallel, Figure* figure, PointLonLat first) : @@ -104,7 +105,7 @@ PointLonLat Mercator::inv(const Point2& q) const { Spec* Mercator::spec() const { - return new spec::Custom{{{"lad", parallel_}, {"orientation", meridian_}}}; + return new spec::Custom{{{"projection", "mercator"}, {"lad", parallel_}, {"orientation", meridian_}}}; } diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 1539e8bb3..75e703f43 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -36,13 +36,13 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : struct NonRotated final : Implementation { PointLonLat operator()(const PointLonLat& p) const override { return p; } - Spec* spec() const override { return new spec::Custom{}; } + Spec* spec() const override { return nullptr; } }; struct RotationAngle final : Implementation { explicit RotationAngle(double angle) : angle_(angle) {} PointLonLat operator()(const PointLonLat& p) const override { return {p.lon + angle_, p.lat}; } - Spec* spec() const override { return new spec::Custom{{{"angle", angle_}}}; } + Spec* spec() const override { return new spec::Custom{{{"projection", "rotation"}, {"angle", angle_}}}; } const double angle_; }; @@ -54,8 +54,10 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : return UnitSphere::convertCartesianToSpherical(R_ * UnitSphere::convertSphericalToCartesian(p)); } Spec* spec() const override { - return new spec::Custom{ - {{"south_pole_lon", south_pole_lon_}, {"south_pole_lat", south_pole_lat_}, {"angle", angle_}}}; + return new spec::Custom{{{"projection", "rotation"}, + {"south_pole_lon", south_pole_lon_}, + {"south_pole_lat", south_pole_lat_}, + {"angle", angle_}}}; } const M R_; const double south_pole_lon_; From 3264d176d285df55ac0fb7a6e930cbc5a6a73579 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 11 May 2024 00:28:45 +0100 Subject: [PATCH 637/737] eckit::geo::Figure --- src/eckit/geo/CMakeLists.txt | 14 +++---- src/eckit/geo/Figure.cc | 13 +----- src/eckit/geo/Figure.h | 6 --- src/eckit/geo/Search.h | 4 +- src/eckit/geo/area/BoundingBox.cc | 7 +--- src/eckit/geo/area/BoundingBox.h | 3 -- src/eckit/geo/figure/OblateSpheroid.cc | 15 +------ src/eckit/geo/figure/OblateSpheroid.h | 2 - src/eckit/geo/figure/Sphere.cc | 26 +----------- src/eckit/geo/figure/Sphere.h | 3 -- src/eckit/geo/{ => geometry}/Earth.h | 6 +-- .../OblateSpheroid.cc} | 18 ++++++--- .../OblateSpheroid.h} | 18 ++++++--- src/eckit/geo/{ => geometry}/Sphere.cc | 34 ++++++---------- src/eckit/geo/{ => geometry}/Sphere.h | 30 ++++++++------ src/eckit/geo/{ => geometry}/SphereT.h | 40 +++++++++---------- src/eckit/geo/{ => geometry}/UnitSphere.h | 16 +++----- src/eckit/geo/projection/LonLatToXYZ.cc | 8 ++-- src/eckit/geo/projection/Rotation.cc | 5 ++- tests/geo/figure_sphere.cc | 20 ++++++---- 20 files changed, 116 insertions(+), 172 deletions(-) rename src/eckit/geo/{ => geometry}/Earth.h (86%) rename src/eckit/geo/{EllipsoidOfRevolution.cc => geometry/OblateSpheroid.cc} (76%) rename src/eckit/geo/{EllipsoidOfRevolution.h => geometry/OblateSpheroid.h} (66%) rename src/eckit/geo/{ => geometry}/Sphere.cc (84%) rename src/eckit/geo/{ => geometry}/Sphere.h (70%) rename src/eckit/geo/{ => geometry}/SphereT.h (60%) rename src/eckit/geo/{ => geometry}/UnitSphere.h (51%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 297a121f2..008e925a8 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -4,9 +4,6 @@ list(APPEND eckit_geo_srcs Area.h Cache.cc Cache.h - Earth.h - EllipsoidOfRevolution.cc - EllipsoidOfRevolution.h Figure.cc Figure.h GreatCircle.cc @@ -37,10 +34,6 @@ list(APPEND eckit_geo_srcs Shape.h Spec.cc Spec.h - Sphere.cc - Sphere.h - SphereT.h - UnitSphere.h area/BoundingBox.cc area/BoundingBox.h etc/Grid.cc @@ -49,6 +42,13 @@ list(APPEND eckit_geo_srcs figure/OblateSpheroid.h figure/Sphere.cc figure/Sphere.h + geometry/Earth.h + geometry/OblateSpheroid.cc + geometry/OblateSpheroid.h + geometry/Sphere.cc + geometry/Sphere.h + geometry/SphereT.h + geometry/UnitSphere.h grid/HEALPix.cc grid/HEALPix.h grid/Reduced.cc diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc index 4e1df6c16..846ad4045 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/geo/Figure.cc @@ -15,6 +15,7 @@ #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/geometry/OblateSpheroid.h" namespace eckit::geo { @@ -35,18 +36,8 @@ double Figure::b() const { } -double Figure::area() const { - NOTIMP; -} - - -double Figure::area(const area::BoundingBox&) const { - NOTIMP; -} - - double Figure::eccentricity() const { - return std::sqrt(1. - (b() * b()) / (a() * a())); + return geometry::OblateSpheroid::eccentricity(a(), b()); } diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index 04b4343be..833062964 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -64,12 +64,6 @@ class Figure { virtual double a() const; virtual double b() const; - /// @brief Calculate surface area ([[R]**2]) - virtual double area() const; - - /// @brief Calculate the bounding box prescribed area ([[R]**2]) - virtual double area(const area::BoundingBox&) const; - double eccentricity() const; }; diff --git a/src/eckit/geo/Search.h b/src/eckit/geo/Search.h index e30434fd1..7225488fc 100644 --- a/src/eckit/geo/Search.h +++ b/src/eckit/geo/Search.h @@ -17,7 +17,7 @@ #include "eckit/container/KDTree.h" #include "eckit/container/sptree/SPValue.h" #include "eckit/geo/Point.h" -#include "eckit/geo/UnitSphere.h" +#include "eckit/geo/geometry/UnitSphere.h" namespace eckit::geo { @@ -76,7 +76,7 @@ struct SearchLonLat : Search3 { } private: - static Search3::Point to_cartesian(const Point& p) { return UnitSphere::convertSphericalToCartesian(p); } + static Search3::Point to_cartesian(const Point& p) { return geometry::UnitSphere::convertSphericalToCartesian(p); } }; diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 84ea5f349..9eeb13bc2 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -19,7 +19,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Figure.h" #include "eckit/geo/PointLonLat.h" -#include "eckit/geo/Sphere.h" +#include "eckit/geo/geometry/Sphere.h" #include "eckit/geo/spec/Custom.h" #include "eckit/types/FloatCompare.h" @@ -190,11 +190,6 @@ bool BoundingBox::empty() const { } -double BoundingBox::area(const Figure& figure) const { - return figure.area(*this); -} - - BoundingBox BoundingBox::calculate(const BoundingBox&, const Projection&) { NOTIMP; } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 887307acb..0a55490bd 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -79,9 +79,6 @@ class BoundingBox : public Area, protected std::array { bool contains(const BoundingBox&) const; bool empty() const; - /// @brief Calculate the bounding box prescribed area ([[R]**2]) - double area(const Figure&) const; - // -- Overridden methods void spec(spec::Custom&) const override; diff --git a/src/eckit/geo/figure/OblateSpheroid.cc b/src/eckit/geo/figure/OblateSpheroid.cc index d21ec335e..e14e9a39b 100644 --- a/src/eckit/geo/figure/OblateSpheroid.cc +++ b/src/eckit/geo/figure/OblateSpheroid.cc @@ -12,8 +12,6 @@ #include "eckit/geo/figure/OblateSpheroid.h" -#include - #include "eckit/exception/Exceptions.h" #include "eckit/geo/Spec.h" #include "eckit/types/FloatCompare.h" @@ -23,7 +21,7 @@ namespace eckit::geo::figure { OblateSpheroid::OblateSpheroid(double a, double b) : a_(a), b_(b) { - ASSERT_MSG(types::is_strictly_greater(b_, 0.) && b_ <= a_, "OblateSpheroid requires 0 < b <= a"); + ASSERT_MSG(0. < b && b_ <= a_, "OblateSpheroid requires 0 < b <= a"); } @@ -36,15 +34,4 @@ double OblateSpheroid::R() const { } -double OblateSpheroid::area() const { - auto e = eccentricity(); - if (types::is_approximately_equal(e, 1.)) { - return 2. * M_PI * a_ * a_; - } - - ASSERT(types::is_strictly_greater(e, 0.)); - return 2. * M_PI * a_ * a_ * (1. + (1 - e * e) / e * std::atan2(e, 1 - e * e)); -} - - } // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/OblateSpheroid.h b/src/eckit/geo/figure/OblateSpheroid.h index f3bdadc59..8876c37e1 100644 --- a/src/eckit/geo/figure/OblateSpheroid.h +++ b/src/eckit/geo/figure/OblateSpheroid.h @@ -31,8 +31,6 @@ class OblateSpheroid final : public Figure { double a() const override { return a_; } double b() const override { return b_; } - double area() const override; - private: // -- Members diff --git a/src/eckit/geo/figure/Sphere.cc b/src/eckit/geo/figure/Sphere.cc index 5bd1aaaae..b85cd6f41 100644 --- a/src/eckit/geo/figure/Sphere.cc +++ b/src/eckit/geo/figure/Sphere.cc @@ -12,43 +12,19 @@ #include "eckit/geo/figure/Sphere.h" -#include - #include "eckit/exception/Exceptions.h" #include "eckit/geo/Spec.h" -#include "eckit/geo/area/BoundingBox.h" -#include "eckit/geo/util.h" -#include "eckit/types/FloatCompare.h" namespace eckit::geo::figure { Sphere::Sphere(double R) : R_(R) { - ASSERT_MSG(types::is_strictly_greater(R_, 0.), "Sphere requires R > 0"); + ASSERT_MSG(R_ > 0., "Sphere requires R > 0"); } Sphere::Sphere(const Spec& spec) : Sphere(spec.get_double("R")) {} -double Sphere::area() const { - return 4. * M_PI * R_ * R_; -} - - -double Sphere::area(const area::BoundingBox& bbox) const { - auto lonf = bbox.isPeriodicWestEast() ? 1. : ((bbox.east - bbox.west) / PointLonLat::GLOBE); - ASSERT(0. <= lonf && lonf <= 1.); - - const auto sn = std::sin(bbox.north * util::DEGREE_TO_RADIAN); - const auto ss = std::sin(bbox.south * util::DEGREE_TO_RADIAN); - - auto latf = 0.5 * (sn - ss); - ASSERT(0. <= latf && latf <= 1.); - - return area() * latf * lonf; -} - - } // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/Sphere.h b/src/eckit/geo/figure/Sphere.h index 109c7df0d..fc165d110 100644 --- a/src/eckit/geo/figure/Sphere.h +++ b/src/eckit/geo/figure/Sphere.h @@ -31,9 +31,6 @@ class Sphere final : public Figure { double a() const override { return R_; } double b() const override { return R_; } - double area() const override; - double area(const area::BoundingBox&) const override; - private: // -- Members diff --git a/src/eckit/geo/Earth.h b/src/eckit/geo/geometry/Earth.h similarity index 86% rename from src/eckit/geo/Earth.h rename to src/eckit/geo/geometry/Earth.h index 25e8b0d74..2b08c332c 100644 --- a/src/eckit/geo/Earth.h +++ b/src/eckit/geo/geometry/Earth.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geo/SphereT.h" +#include "eckit/geo/geometry/SphereT.h" -namespace eckit::geo { +namespace eckit::geo::geometry { struct DatumIFS { @@ -36,4 +36,4 @@ struct DatumWGS84SemiMajorAxis { using Earth = SphereT; -} // namespace eckit::geo +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/EllipsoidOfRevolution.cc b/src/eckit/geo/geometry/OblateSpheroid.cc similarity index 76% rename from src/eckit/geo/EllipsoidOfRevolution.cc rename to src/eckit/geo/geometry/OblateSpheroid.cc index eb82ef9d8..3f72715ce 100644 --- a/src/eckit/geo/EllipsoidOfRevolution.cc +++ b/src/eckit/geo/geometry/OblateSpheroid.cc @@ -8,7 +8,8 @@ * does it submit to any jurisdiction. */ -#include "eckit/geo/EllipsoidOfRevolution.h" + +#include "eckit/geo/geometry/OblateSpheroid.h" #include @@ -18,12 +19,17 @@ #include "eckit/geo/util.h" -namespace eckit::geo { +namespace eckit::geo::geometry { + + +double OblateSpheroid::eccentricity(double a, double b) { + ASSERT(0. < b && b <= a); + return std::sqrt(1. - b * b / (a * a)); +} -Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, double b, const PointLonLat& P, double height) { - ASSERT(a > 0.); - ASSERT(b > 0.); +Point3 OblateSpheroid::convertSphericalToCartesian(double a, double b, const PointLonLat& P, double height) { + ASSERT(0. < b && 0. < a); // See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates // numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line) @@ -43,4 +49,4 @@ Point3 EllipsoidOfRevolution::convertSphericalToCartesian(double a, double b, co } -} // namespace eckit::geo +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/EllipsoidOfRevolution.h b/src/eckit/geo/geometry/OblateSpheroid.h similarity index 66% rename from src/eckit/geo/EllipsoidOfRevolution.h rename to src/eckit/geo/geometry/OblateSpheroid.h index c427d9723..8db515444 100644 --- a/src/eckit/geo/EllipsoidOfRevolution.h +++ b/src/eckit/geo/geometry/OblateSpheroid.h @@ -13,16 +13,24 @@ namespace eckit::geo { - - class Point3; class PointLonLat; +} // namespace eckit::geo + +namespace eckit::geo::geometry { -struct EllipsoidOfRevolution { - // Convert elliptic coordinates to Cartesian + +struct OblateSpheroid { + /// Elliptic eccentricity + static double eccentricity(double a, double b); + + /// Surface area [m ** 2] + static double area(double a, double b); + + /// Convert geocentric coordinates to Cartesian static Point3 convertSphericalToCartesian(double a, double b, const PointLonLat&, double height = 0.); }; -} // namespace eckit::geo +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/Sphere.cc b/src/eckit/geo/geometry/Sphere.cc similarity index 84% rename from src/eckit/geo/Sphere.cc rename to src/eckit/geo/geometry/Sphere.cc index 75834e321..016dc09b5 100644 --- a/src/eckit/geo/Sphere.cc +++ b/src/eckit/geo/geometry/Sphere.cc @@ -8,7 +8,8 @@ * does it submit to any jurisdiction. */ -#include "eckit/geo/Sphere.h" + +#include "eckit/geo/geometry/Sphere.h" #include #include @@ -18,11 +19,12 @@ #include "eckit/geo/GreatCircle.h" #include "eckit/geo/Point3.h" #include "eckit/geo/PointLonLat.h" +#include "eckit/geo/area/BoundingBox.h" #include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geo { +namespace eckit::geo::geometry { using types::is_approximately_equal; @@ -106,29 +108,19 @@ double Sphere::area(double radius) { } -double Sphere::area(double radius, const PointLonLat& WestNorth, const PointLonLat& EastSouth) { +double Sphere::area(double radius, const area::BoundingBox& bbox) { ASSERT(radius > 0.); - PointLonLat::assert_latitude_range(WestNorth); - PointLonLat::assert_latitude_range(EastSouth); - - // Set longitude fraction - auto W = WestNorth.lon; - auto E = PointLonLat::normalise_angle_to_minimum(EastSouth.lon, W); - auto longitude_range(is_approximately_equal(W, E) && !is_approximately_equal(EastSouth.lon, WestNorth.lon) ? 360. - : E - W); - ASSERT(longitude_range <= 360.); - - auto longitude_fraction = longitude_range / 360.; - // Set latitude fraction - auto N = WestNorth.lat; - auto S = EastSouth.lat; - ASSERT(S <= N); + // Set longitude and latitude fractions + auto lonf = bbox.isPeriodicWestEast() ? 1. : (bbox.west - bbox.east) / PointLonLat::GLOBE; + ASSERT(0. <= lonf && lonf <= 1.); - auto latitude_fraction = 0.5 * (std::sin(util::DEGREE_TO_RADIAN * N) - std::sin(util::DEGREE_TO_RADIAN * S)); + auto sn = std::sin(util::DEGREE_TO_RADIAN * bbox.north); + auto ss = std::sin(util::DEGREE_TO_RADIAN * bbox.south); + auto latf = 0.5 * (sn - ss); // Calculate area - return area(radius) * latitude_fraction * longitude_fraction; + return area(radius) * latf * lonf; } @@ -191,4 +183,4 @@ PointLonLat Sphere::convertCartesianToSpherical(double radius, const Point3& A) } -} // namespace eckit::geo +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/Sphere.h b/src/eckit/geo/geometry/Sphere.h similarity index 70% rename from src/eckit/geo/Sphere.h rename to src/eckit/geo/geometry/Sphere.h index 3c6eac4aa..2668afd18 100644 --- a/src/eckit/geo/Sphere.h +++ b/src/eckit/geo/geometry/Sphere.h @@ -13,35 +13,41 @@ namespace eckit::geo { - - class Point3; class PointLonLat; +namespace area { +class BoundingBox; +} +} // namespace eckit::geo +namespace eckit::geo::geometry { + + +/// Spherical geometry struct Sphere { - /// Great-circle central angle between two points in radians + /// Great-circle central angle between two points [radian] static double centralAngle(const PointLonLat&, const PointLonLat&); - /// Great-circle central angle between two points (Cartesian coordinates) in radians + /// Great-circle central angle between two points (Cartesian coordinates) [m] static double centralAngle(double radius, const Point3&, const Point3&); - /// Great-circle distance between two points in metres + /// Great-circle distance between two points [m] static double distance(double radius, const PointLonLat&, const PointLonLat&); - /// Great-circle distance between two points (Cartesian coordinates) in metres + /// Great-circle distance between two points (Cartesian coordinates) [m] static double distance(double radius, const Point3&, const Point3&); - /// Surface area in square metres + /// Surface area [m ** 2] static double area(double radius); - /// Surface area between parallels and meridians defined by two points in square metres - static double area(double radius, const PointLonLat&, const PointLonLat&); + /// Surface area between parallels and meridians [m ** 2] + static double area(double radius, const area::BoundingBox&); - // Great-circle intermediate latitude provided two circle points and intermediate longitude in degrees + /// Great-circle intermediate latitude provided two circle points and intermediate longitude [degree] static double greatCircleLatitudeGivenLongitude(const PointLonLat&, const PointLonLat&, double lon); - // Great-circle intermediate longitude(s) provided two circle points and intermediate latitude in degrees + /// Great-circle intermediate longitude(s) provided two circle points and intermediate latitude [degree] static void greatCircleLongitudeGivenLatitude(const PointLonLat&, const PointLonLat&, double lat, double& lon1, double& lon2); @@ -53,4 +59,4 @@ struct Sphere { }; -} // namespace eckit::geo +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/SphereT.h b/src/eckit/geo/geometry/SphereT.h similarity index 60% rename from src/eckit/geo/SphereT.h rename to src/eckit/geo/geometry/SphereT.h index cbd2f13cb..828012517 100644 --- a/src/eckit/geo/SphereT.h +++ b/src/eckit/geo/geometry/SphereT.h @@ -8,31 +8,30 @@ * does it submit to any jurisdiction. */ + #pragma once #include "eckit/geo/Point3.h" #include "eckit/geo/PointLonLat.h" -#include "eckit/geo/Sphere.h" +#include "eckit/geo/geometry/Sphere.h" -//---------------------------------------------------------------------------------------------------------------------- -namespace eckit::geo { +namespace eckit::geo::area { +class BoundingBox; +} -//---------------------------------------------------------------------------------------------------------------------- -class Point3; -class PointLonLat; +namespace eckit::geo::geometry { -//---------------------------------------------------------------------------------------------------------------------- -/// Definition of a sphere parametrised with a geodetic datum +/// Sphere parametrised with a geodetic datum template struct SphereT { /// Sphere radius in metres inline static double radius() { return DATUM::radius(); } - /// Great-circle central angle between two points in radians + /// Great-circle central angle between two points [radian] inline static double centralAngle(const PointLonLat& A, const PointLonLat& B) { return Sphere::centralAngle(A, B); } /// Great-circle central angle between two points (Cartesian coordinates) in radians @@ -40,44 +39,41 @@ struct SphereT { return Sphere::centralAngle(DATUM::radius(), A, B); } - /// Great-circle distance between two points in metres + /// Great-circle distance between two points [m] inline static double distance(const PointLonLat& A, const PointLonLat& B) { return Sphere::distance(DATUM::radius(), A, B); } - /// Great-circle distance between two points (Cartesian coordinates) in metres + /// Great-circle distance between two points (Cartesian coordinates) [m] inline static double distance(const Point3& A, const Point3& B) { return Sphere::distance(DATUM::radius(), A, B); } - /// Surface area in square metres + /// Surface area [m ** 2] inline static double area() { return Sphere::area(DATUM::radius()); } - /// Surface area between parallels and meridians defined by two points in square metres - inline static double area(const PointLonLat& WestNorth, const PointLonLat& EastSouth) { - return Sphere::area(DATUM::radius(), WestNorth, EastSouth); - } + /// Surface area between parallels and meridians [m ** 2] + inline static double area(const area::BoundingBox& bbox) { return Sphere::area(DATUM::radius(), bbox); } - // Great-circle intermediate latitude provided two circle points and intermediate longitude in degrees + /// Great-circle intermediate latitude provided two circle points and intermediate longitude [degree] inline static double greatCircleLatitudeGivenLongitude(const PointLonLat& A, const PointLonLat& B, double lon) { return Sphere::greatCircleLatitudeGivenLongitude(A, B, lon); } - // Great-circle intermediate longitude(s) provided two circle points and intermediate latitude in degrees + /// Great-circle intermediate longitude(s) provided two circle points and intermediate latitude [degree] inline static void greatCircleLongitudeGivenLatitude(const PointLonLat& A, const PointLonLat& B, double lat, double& lon1, double& lon2) { return Sphere::greatCircleLongitudeGivenLatitude(A, B, lat, lon1, lon2); } - // Convert spherical to Cartesian coordinates + /// Convert spherical to Cartesian coordinates inline static Point3 convertSphericalToCartesian(const PointLonLat& P, double height = 0.) { return Sphere::convertSphericalToCartesian(DATUM::radius(), P, height); } - // Convert Cartesian to spherical coordinates + /// Convert Cartesian to spherical coordinates inline static PointLonLat convertCartesianToSpherical(const Point3& P) { return Sphere::convertCartesianToSpherical(DATUM::radius(), P); } }; -//---------------------------------------------------------------------------------------------------------------------- -} // namespace eckit::geo +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/UnitSphere.h b/src/eckit/geo/geometry/UnitSphere.h similarity index 51% rename from src/eckit/geo/UnitSphere.h rename to src/eckit/geo/geometry/UnitSphere.h index 380a981cc..8acb2a1a0 100644 --- a/src/eckit/geo/UnitSphere.h +++ b/src/eckit/geo/geometry/UnitSphere.h @@ -8,29 +8,23 @@ * does it submit to any jurisdiction. */ -#ifndef UnitSphere_H -#define UnitSphere_H -#include "eckit/geo/SphereT.h" +#pragma once -//------------------------------------------------------------------------------------------------------ +#include "eckit/geo/geometry/SphereT.h" -namespace eckit::geo { -//------------------------------------------------------------------------------------------------------ +namespace eckit::geo::geometry { + /// Definition of a unit datum struct DatumUnit { static constexpr double radius() { return 1.; } }; -//------------------------------------------------------------------------------------------------------ /// Definition of a unit sphere using UnitSphere = SphereT; -//------------------------------------------------------------------------------------------------------ - -} // namespace eckit::geo -#endif +} // namespace eckit::geo::geometry diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc index 1be20ce19..24b7ed537 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -12,8 +12,8 @@ #include "eckit/geo/projection/LonLatToXYZ.h" -#include "eckit/geo/EllipsoidOfRevolution.h" -#include "eckit/geo/Sphere.h" +#include "eckit/geo/geometry/OblateSpheroid.h" +#include "eckit/geo/geometry/Sphere.h" #include "eckit/geo/spec/Custom.h" #include "eckit/types/FloatCompare.h" @@ -28,7 +28,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { ASSERT_MSG(types::is_strictly_greater(b, 0.) && b <= a, "LonLatToXYZ requires 0 < b <= a"); struct LonLatToSphereXYZ final : Implementation { - using S = Sphere; + using S = geometry::Sphere; const double R_; explicit LonLatToSphereXYZ(double R) : R_(R) {} @@ -38,7 +38,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { }; struct LonLatToSpheroidXYZ final : Implementation { - using S = EllipsoidOfRevolution; + using S = geometry::OblateSpheroid; const double a_; const double b_; diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 75e703f43..2ee42124b 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -15,7 +15,7 @@ #include #include -#include "eckit/geo/UnitSphere.h" +#include "eckit/geo/geometry/UnitSphere.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/maths/Matrix3.h" @@ -51,7 +51,8 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : RotationMatrix(M&& R, double south_pole_lon, double south_pole_lat, double angle) : R_(R), south_pole_lon_(south_pole_lon), south_pole_lat_(south_pole_lat), angle_(angle) {} PointLonLat operator()(const PointLonLat& p) const override { - return UnitSphere::convertCartesianToSpherical(R_ * UnitSphere::convertSphericalToCartesian(p)); + return geometry::UnitSphere::convertCartesianToSpherical( + R_ * geometry::UnitSphere::convertSphericalToCartesian(p)); } Spec* spec() const override { return new spec::Custom{{{"projection", "rotation"}, diff --git a/tests/geo/figure_sphere.cc b/tests/geo/figure_sphere.cc index 43057ff59..d03a070cb 100644 --- a/tests/geo/figure_sphere.cc +++ b/tests/geo/figure_sphere.cc @@ -14,8 +14,9 @@ #include "eckit/geo/Point3.h" #include "eckit/geo/PointLonLat.h" -#include "eckit/geo/SphereT.h" -#include "eckit/geo/UnitSphere.h" +#include "eckit/geo/area/BoundingBox.h" +#include "eckit/geo/geometry/SphereT.h" +#include "eckit/geo/geometry/UnitSphere.h" #include "eckit/testing/Test.h" @@ -23,6 +24,8 @@ namespace eckit::geo::test { CASE("unit sphere") { + using geometry::UnitSphere; + const auto R = UnitSphere::radius(); const auto L = R * std::sqrt(2) / 2.; @@ -76,8 +79,8 @@ CASE("unit sphere") { SECTION("area hemispheres") { - auto area_hemisphere_north = UnitSphere::area({-180., 90.}, {180., 0.}); - auto area_hemisphere_south = UnitSphere::area({-180., 0.}, {180., -90.}); + auto area_hemisphere_north = UnitSphere::area({90., -180., 0., 180.}); + auto area_hemisphere_south = UnitSphere::area({0., -180., -90., 180.}); EXPECT(area_hemisphere_north == 0.5 * UnitSphere::area()); EXPECT(area_hemisphere_north == area_hemisphere_south); @@ -228,7 +231,8 @@ CASE("two-unit sphere") { static double radius() { return 2.; } }; - using TwoUnitsSphere = SphereT; + using geometry::UnitSphere; + using TwoUnitsSphere = geometry::SphereT; const PointLonLat P1(-71.6, -33.); // Valparaíso const PointLonLat P2(121.8, 31.4); // Shanghai @@ -254,8 +258,10 @@ CASE("two-unit sphere") { SECTION("sub areas") { - auto area_1 = UnitSphere::area(P2, P1); - auto area_2 = TwoUnitsSphere::area(P2, P1); + area::BoundingBox bbox({P2.lat, P1.lon, P1.lat, P2.lon}); + + auto area_1 = UnitSphere::area(bbox); + auto area_2 = TwoUnitsSphere::area(bbox); EXPECT(4. * area_1 == area_2); } } From 6a546ac505cc390a66c076f29ec8670fc6df5cd7 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 11 May 2024 00:29:24 +0100 Subject: [PATCH 638/737] eckit::geo::Projection --- src/eckit/geo/CMakeLists.txt | 22 +- .../geo/projection/LambertConformalConic.cc | 280 ------------------ .../geo/projection/ProjectionOnFigure.cc | 50 ++++ src/eckit/geo/projection/ProjectionOnFigure.h | 61 ++++ .../{ => figure}/LambertAzimuthalEqualArea.cc | 27 +- .../{ => figure}/LambertAzimuthalEqualArea.h | 28 +- .../figure/LambertConformalConic.cc | 105 +++++++ .../{ => figure}/LambertConformalConic.h | 20 +- .../geo/projection/{ => figure}/Mercator.cc | 6 +- .../geo/projection/{ => figure}/Mercator.h | 8 +- .../{ => figure}/PolarStereographic.cc | 6 +- .../{ => figure}/PolarStereographic.h | 8 +- .../geo/projection/{ => figure}/SpaceView.cc | 6 +- .../geo/projection/{ => figure}/SpaceView.h | 8 +- tests/geo/projection_mercator.cc | 8 +- 15 files changed, 282 insertions(+), 361 deletions(-) delete mode 100644 src/eckit/geo/projection/LambertConformalConic.cc create mode 100644 src/eckit/geo/projection/ProjectionOnFigure.cc create mode 100644 src/eckit/geo/projection/ProjectionOnFigure.h rename src/eckit/geo/projection/{ => figure}/LambertAzimuthalEqualArea.cc (71%) rename src/eckit/geo/projection/{ => figure}/LambertAzimuthalEqualArea.h (65%) create mode 100644 src/eckit/geo/projection/figure/LambertConformalConic.cc rename src/eckit/geo/projection/{ => figure}/LambertConformalConic.h (69%) rename src/eckit/geo/projection/{ => figure}/Mercator.cc (96%) rename src/eckit/geo/projection/{ => figure}/Mercator.h (89%) rename src/eckit/geo/projection/{ => figure}/PolarStereographic.cc (93%) rename src/eckit/geo/projection/{ => figure}/PolarStereographic.h (86%) rename src/eckit/geo/projection/{ => figure}/SpaceView.cc (95%) rename src/eckit/geo/projection/{ => figure}/SpaceView.h (87%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 008e925a8..69843776b 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -73,26 +73,28 @@ list(APPEND eckit_geo_srcs polygon/Polygon.h projection/Composer.cc projection/Composer.h - projection/LambertAzimuthalEqualArea.cc - projection/LambertAzimuthalEqualArea.h - projection/LambertConformalConic.cc - projection/LambertConformalConic.h projection/LonLatToXY.cc projection/LonLatToXY.h projection/LonLatToXYZ.cc projection/LonLatToXYZ.h - projection/Mercator.cc - projection/Mercator.h projection/None.cc projection/None.h - projection/PolarStereographic.cc - projection/PolarStereographic.h + projection/ProjectionOnFigure.cc + projection/ProjectionOnFigure.h projection/Rotation.cc projection/Rotation.h - projection/SpaceView.cc - projection/SpaceView.h projection/XYToLonLat.cc projection/XYToLonLat.h + projection/figure/LambertAzimuthalEqualArea.cc + projection/figure/LambertAzimuthalEqualArea.h + projection/figure/LambertConformalConic.cc + projection/figure/LambertConformalConic.h + projection/figure/Mercator.cc + projection/figure/Mercator.h + projection/figure/PolarStereographic.cc + projection/figure/PolarStereographic.h + projection/figure/SpaceView.cc + projection/figure/SpaceView.h range/GaussianLatitude.cc range/GaussianLatitude.h range/Regular.cc diff --git a/src/eckit/geo/projection/LambertConformalConic.cc b/src/eckit/geo/projection/LambertConformalConic.cc deleted file mode 100644 index 3cd780f1d..000000000 --- a/src/eckit/geo/projection/LambertConformalConic.cc +++ /dev/null @@ -1,280 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/projection/LambertConformalConic.h" - -#include - -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/util.h" - - -namespace eckit::geo::projection { - - -LambertConformalConic::LambertConformalConic(const Spec&) { - // if (fabs(Latin1InDegrees + Latin2InDegrees) < EPSILON) { - // grib_context_log(h->context, GRIB_LOG_ERROR, - // "%s: Cannot have equal latitudes for standard parallels on opposite sides of equator", - // ITER); - // return GRIB_WRONG_GRID; - // } -} - - -Point2 LambertConformalConic::fwd(const PointLonLat&) const { - NOTIMP; -} - - -PointLonLat LambertConformalConic::inv(const Point2&) const { - NOTIMP; -} - - -Spec* LambertConformalConic::spec() const { - NOTIMP; -} - - -namespace { - - -double adjust_lon_radians(double lon) { - while (lon > M_PI) { - lon -= 2 * M_PI; - } - while (lon < -M_PI) { - lon += 2 * M_PI; - } - return lon; - ß -}; - - -void init_sphere() { - size_t nv; - long nx; - long ny; - double LoVInDegrees; - double Dx; - double Dy; - double radius = 1.; - double latFirstInRadians = 0.; - double lonFirstInRadians = 0.; - double LoVInRadians = 0.; - double Latin1InRadians = 0.; - double Latin2InRadians = 0.; - double LaDInRadians = 0.; - - double n; - - if (fabs(Latin1InRadians - Latin2InRadians) < 1E-09) { - n = sin(Latin1InRadians); - } - else { - n = log(cos(Latin1InRadians) / cos(Latin2InRadians)) - / log(tan(M_PI_4 + Latin2InRadians / 2.0) / tan(M_PI_4 + Latin1InRadians / 2.0)); - } - - double f = (cos(Latin1InRadians) * pow(tan(M_PI_4 + Latin1InRadians / 2.0), n)) / n; - double rho = radius * f * pow(tan(M_PI_4 + latFirstInRadians / 2.0), -n); - double rho0_bare = f * pow(tan(M_PI_4 + LaDInRadians / 2.0), -n); - double rho0 = radius * rho0_bare; // scaled - double lonDiff = adjust_lon_radians(lonFirstInRadians - LoVInRadians); - - double angle = n * lonDiff; - double x0 = rho * sin(angle); - double y0 = rho0 - rho * cos(angle); - - double latDeg = 0; - double lonDeg = 0; - - Point2 p; - - - ASSERT(radius > 0); - ASSERT(n != 0.0); - - double x = p.X / radius; - double y = rho0_bare - p.Y / radius; - - if (double rho = hypot(x, y); rho != 0.0) { - if (n < 0.0) { - rho = -rho; - x = -x; - y = -y; - } - double latRadians = 2. * atan(pow(f / rho, 1.0 / n)) - M_PI_2; - double lonRadians = atan2(x, y) / n + LoVInRadians; - - auto q = PointLonLat::make(lonRadians * util::RADIAN_TO_DEGREE, latRadians * util::RADIAN_TO_DEGREE); - } - else { - auto q = PointLonLat::make(0.0, n > 0 ? PointLonLat::NORTH_POLE : PointLonLat::SOUTH_POLE); - } -} - - -void init_oblate() { - static constexpr double EPSILON = 1e-10; - - double LoVInDegrees = 0.; - double LoVInRadians = 0.; - double LaDInRadians = 0.; - double LaDInDegrees = 0.; - double latFirstInRadians = 0.; - double lonFirstInRadians = 0.; - double Latin1InRadians = 0.; - double Latin2InRadians = 0.; - double earthMajorAxisInMetres = 1.; - double earthMinorAxisInMetres = 1.; - - double x0; - double y0; - - double sinphi; - double ts; - double rh1; - - double ns; // ratio of angle between meridian - double F; // flattening of ellipsoid - double rh; // height above ellipsoid - - double sin_po; // temporary sin value - double cos_po; // temporary cos value - double con; // temporary variable - - double ms1; // small m 1 - double ms2; // small m 2 - double ts0; // small t 0 - double ts1; // small t 1 - double ts2; // small t 2 - - auto calculate_eccentricity = [](double minor, double major) { - const double temp = minor / major; - return sqrt(1.0 - temp * temp); - }; - - // Compute the constant small m which is the radius of - // a parallel of latitude, phi, divided by the semimajor axis - auto compute_m = [](double eccent, double sinphi, double cosphi) { - const double con = eccent * sinphi; - return ((cosphi / (sqrt(1.0 - con * con)))); - }; - - // Compute the constant small t for use in the forward computations - auto compute_t = [](double eccent, // Eccentricity of the spheroid - double phi, // Latitude phi - double sinphi) // Sine of the latitude - { - double con = eccent * sinphi; - con = pow(((1.0 - con) / (1.0 + con)), 0.5 * eccent); - return (tan(0.5 * (M_PI_2 - phi)) / con); - }; - - // Function to compute the latitude angle, phi2, for the inverse - // From the book "Map Projections-A Working Manual-John P. Snyder (1987)" - // Equation (7-9) involves rapidly converging iteration: Calculate t from (15-11) - // Then, assuming an initial trial phi equal to (pi/2 - 2*arctan t) in the right side of equation (7-9), - // calculate phi on the left side. Substitute the calculated phi) into the right side, - // calculate a new phi, etc., until phi does not change significantly from the preceding trial value of phi - auto compute_phi = [](double eccent, // Spheroid eccentricity - double ts // Constant value t - ) -> double { - double eccnth; - double phi; - double con; - double dphi; - double sinpi; - - eccnth = 0.5 * eccent; - phi = M_PI_2 - 2 * atan(ts); - - constexpr int MAX_ITER = 15; - for (int i = 0; i <= MAX_ITER; i++) { - sinpi = sin(phi); - con = eccent * sinpi; - dphi = M_PI_2 - 2 * atan(ts * (pow(((1.0 - con) / (1.0 + con)), eccnth))) - phi; - phi += dphi; - if (fabs(dphi) <= 0.0000000001) - return (phi); - } - - throw eckit::SeriousBug("Failed to compute the latitude angle, phi2, for the inverse", Here()); - }; - - double e = calculate_eccentricity(earthMinorAxisInMetres, earthMajorAxisInMetres); - - sin_po = sin(Latin1InRadians); - cos_po = cos(Latin1InRadians); - con = sin_po; - ms1 = compute_m(e, sin_po, cos_po); - ts1 = compute_t(e, Latin1InRadians, sin_po); - - sin_po = sin(Latin2InRadians); - cos_po = cos(Latin2InRadians); - ms2 = compute_m(e, sin_po, cos_po); - ts2 = compute_t(e, Latin2InRadians, sin_po); - - sin_po = sin(LaDInRadians); - ts0 = compute_t(e, LaDInRadians, sin_po); - - ns = fabs(Latin1InRadians - Latin2InRadians) > EPSILON ? log(ms1 / ms2) / log(ts1 / ts2) : con; - F = ms1 / (ns * pow(ts1, ns)); - rh = earthMajorAxisInMetres * F * pow(ts0, ns); - - // Forward projection: convert lat,lon to x,y - if (fabs(fabs(latFirstInRadians) - M_PI_2) > EPSILON) { - sinphi = sin(latFirstInRadians); - ts = compute_t(e, latFirstInRadians, sinphi); - rh1 = earthMajorAxisInMetres * F * pow(ts, ns); - } - else { - if (latFirstInRadians * ns <= 0) { - throw; // GRIB_GEOCALCULUS_PROBLEM Point cannot be projected: {latFirstInRadians}; - } - rh1 = 0; - } - - double theta0 = ns * adjust_lon_radians(lonFirstInRadians - LoVInRadians); - x0 = -rh1 * sin(theta0); - y0 = rh1 * cos(theta0) - rh; - - - // Inverse projection to convert from x,y to lat,lon - double x = 0.; - double y = 0.; - - Point2 p{x - x0, rh - y + y0}; - - rh1 = sqrt(p.X * p.X + p.Y * p.Y); - con = 1.0; - if (ns <= 0) { - rh1 = -rh1; - con = -con; - } - - double theta = rh1 != 0 ? atan2((con * p.X), (con * p.Y)) : 0.0; - - double latRad - = rh1 != 0 || ns > 0.0 ? compute_phi(e, pow((rh1 / (earthMajorAxisInMetres * F)), 1.0 / ns)) : -M_PI_2; - double lonRad = adjust_lon_radians(theta / ns + LoVInRadians); - - auto q = PointLonLat::make(lonRad * util::RADIAN_TO_DEGREE, latRad * util::RADIAN_TO_DEGREE); -} - - -} // namespace - - -} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/ProjectionOnFigure.cc b/src/eckit/geo/projection/ProjectionOnFigure.cc new file mode 100644 index 000000000..6a4a0c64f --- /dev/null +++ b/src/eckit/geo/projection/ProjectionOnFigure.cc @@ -0,0 +1,50 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/projection/ProjectionOnFigure.h" + +#include + +#include "eckit/geo/geometry/Earth.h" +#include "eckit/geo/util.h" + + +namespace eckit::geo::projection { + + +ProjectionOnFigure::sincos_t::sincos_t(value_type r) : array{std::sin(r), std::sqrt(1. - std::sin(r) * std::sin(r))} {} + + +ProjectionOnFigure::PointLonLatR::PointLonLatR(value_type lonr, value_type latr) : array{lonr, latr} {} + + +ProjectionOnFigure::PointLonLatR::PointLonLatR(const PointLonLat& p) : + PointLonLatR{p.lon * util::DEGREE_TO_RADIAN, p.lat * util::DEGREE_TO_RADIAN} {} + + +// FIXME refactor figures into a single hierarchy +struct Earth final : Figure { + Earth() = default; + + double R() const override { return geometry::Earth::radius(); } + double a() const override { return geometry::Earth::radius(); } + double b() const override { return geometry::Earth::radius(); } +}; + + +ProjectionOnFigure::ProjectionOnFigure(const Spec&) : ProjectionOnFigure() {} + + +ProjectionOnFigure::ProjectionOnFigure(Figure* figure_ptr) : figure_(figure_ptr != nullptr ? figure_ptr : new Earth) {} + + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/ProjectionOnFigure.h b/src/eckit/geo/projection/ProjectionOnFigure.h new file mode 100644 index 000000000..e60623875 --- /dev/null +++ b/src/eckit/geo/projection/ProjectionOnFigure.h @@ -0,0 +1,61 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + +#include "eckit/geo/Figure.h" +#include "eckit/geo/PointLonLat.h" +#include "eckit/geo/Projection.h" + + +namespace eckit::geo::projection { + + +class ProjectionOnFigure : public Projection { +protected: + // -- Types + + struct PointLonLatR final : protected std::array { + PointLonLatR(value_type lonr, value_type latr); + explicit PointLonLatR(const PointLonLat&); + + const value_type& lonr = array::operator[](0); + const value_type& latr = array::operator[](1); + }; + + struct sincos_t final : std::array { + explicit sincos_t(value_type r); + + const value_type& sin = array::operator[](0); + const value_type& cos = array::operator[](1); + }; + + // -- Constructors + + explicit ProjectionOnFigure(const Spec&); + explicit ProjectionOnFigure(Figure* = nullptr); + + // -- Methods + + const Figure& figure() const { return *figure_; } + +private: + // -- Members + + const std::unique_ptr
figure_; +}; + + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc similarity index 71% rename from src/eckit/geo/projection/LambertAzimuthalEqualArea.cc rename to src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc index 5fd68f837..3f0c5b601 100644 --- a/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc @@ -10,36 +10,26 @@ */ -#include "eckit/geo/projection/LambertAzimuthalEqualArea.h" +#include "eckit/geo/projection/figure/LambertAzimuthalEqualArea.h" #include -#include "eckit/geo/Earth.h" +#include "eckit/geo/geometry/Earth.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" -namespace eckit::geo::projection { +namespace eckit::geo::projection::figure { static ProjectionBuilder PROJECTION_1("lambert_azimuthal_equal_area"); static ProjectionBuilder PROJECTION_2("laea"); -LambertAzimuthalEqualArea::sincos_t::sincos_t(value_type r) : array{std::sin(r), std::cos(r)} {} - - -LambertAzimuthalEqualArea::PointLonLatR::PointLonLatR(value_type lonr, value_type latr) : array{lonr, latr} {} - - -LambertAzimuthalEqualArea::PointLonLatR::PointLonLatR(const PointLonLat& p) : - PointLonLatR{p.lon * util::DEGREE_TO_RADIAN, p.lat * util::DEGREE_TO_RADIAN} {} - - LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Spec& spec) : LambertAzimuthalEqualArea({spec.get_double("lon_0"), spec.get_double("lat_0")}, - {spec.get_double("lon_first"), spec.get_double("lat_first")}) {} + {spec.get_double("first_lon"), spec.get_double("first_lat")}) {} LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(PointLonLat centre, PointLonLat first) : @@ -49,12 +39,11 @@ LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(PointLonLat centre, PointLo first_r_(first), phi0_(centre_r_.latr), phi_(first_r_.latr), - dlam_(first_r_.lonr - centre_r_.lonr), - R_(Earth::radius()) {} + dlam_(first_r_.lonr - centre_r_.lonr) {} Point2 LambertAzimuthalEqualArea::fwd(const PointLonLat& p) const { - const auto kp = R_ * std::sqrt(2. / (1. + phi0_.sin * phi_.sin + phi0_.cos * phi_.cos * dlam_.cos)); + const auto kp = figure().R() * std::sqrt(2. / (1. + phi0_.sin * phi_.sin + phi0_.cos * phi_.cos * dlam_.cos)); auto x = kp * phi_.cos * dlam_.sin; auto y = kp * (phi0_.cos * phi_.sin - phi0_.sin * phi_.cos * dlam_.cos); @@ -65,7 +54,7 @@ Point2 LambertAzimuthalEqualArea::fwd(const PointLonLat& p) const { PointLonLat LambertAzimuthalEqualArea::inv(const Point2& p) const { if (auto x = p.X, y = p.Y, rho = std::sqrt(x * x + y * y); !types::is_approximately_equal(rho, 0.)) { - const sincos_t c(2. * std::asin(rho / (2. * R_))); + const sincos_t c(2. * std::asin(rho / (2. * figure().R()))); const auto lonr = centre_r_.lonr + std::atan2(x * c.sin, rho * phi0_.cos * c.cos - y * phi0_.sin * c.sin); const auto latr = std::asin(c.cos * phi0_.sin + y * c.sin * phi0_.cos / rho); @@ -86,4 +75,4 @@ Spec* LambertAzimuthalEqualArea::spec() const { } -} // namespace eckit::geo::projection +} // namespace eckit::geo::projection::figure diff --git a/src/eckit/geo/projection/LambertAzimuthalEqualArea.h b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h similarity index 65% rename from src/eckit/geo/projection/LambertAzimuthalEqualArea.h rename to src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h index e8e2ff31a..9d20d6479 100644 --- a/src/eckit/geo/projection/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h @@ -14,13 +14,13 @@ #include -#include "eckit/geo/Projection.h" +#include "eckit/geo/projection/ProjectionOnFigure.h" -namespace eckit::geo::projection { +namespace eckit::geo::projection::figure { -class LambertAzimuthalEqualArea final : public Projection { +class LambertAzimuthalEqualArea final : public ProjectionOnFigure { public: // -- Types // None @@ -60,25 +60,10 @@ class LambertAzimuthalEqualArea final : public Projection { private: // -- Types - struct PointLonLatR final : protected std::array { - PointLonLatR(value_type lonr, value_type latr); - explicit PointLonLatR(const PointLonLat&); - - const value_type& lonr = array::operator[](0); - const value_type& latr = array::operator[](1); - }; - - struct sincos_t final : std::array { - explicit sincos_t(value_type r); - - const value_type& sin = array::operator[](0); - const value_type& cos = array::operator[](1); - }; - // -- Members - const PointLonLat centre_; // central longitude/standard parallel [degree] - const PointLonLatR centre_r_; // central_longitude/standard parallel [radian] + const PointLonLat centre_; // central meridian/standard parallel [degree] + const PointLonLatR centre_r_; // central meridian/standard parallel [radian] const PointLonLat first_; // first point [degree] const PointLonLatR first_r_; // first point [radian] @@ -86,7 +71,6 @@ class LambertAzimuthalEqualArea final : public Projection { const sincos_t phi0_; const sincos_t phi_; const sincos_t dlam_; - const double R_; // -- Methods // None @@ -107,4 +91,4 @@ class LambertAzimuthalEqualArea final : public Projection { }; -} // namespace eckit::geo::projection +} // namespace eckit::geo::projection::figure diff --git a/src/eckit/geo/projection/figure/LambertConformalConic.cc b/src/eckit/geo/projection/figure/LambertConformalConic.cc new file mode 100644 index 000000000..8b961a8a3 --- /dev/null +++ b/src/eckit/geo/projection/figure/LambertConformalConic.cc @@ -0,0 +1,105 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/projection/figure/LambertConformalConic.h" + +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/geometry/Earth.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/geo/util.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::projection::figure { + + +LambertConformalConic::LambertConformalConic(const Spec& spec) : + LambertConformalConic({spec.get_double("lon_0"), spec.get_double("lat_0")}, spec.get_double("lat_1"), + spec.get_double("lat_2")) {} + + +LambertConformalConic::LambertConformalConic(PointLonLat centre, double lat_1, double lat_2) : + centre_(centre), + centre_r_(centre), + lat_1_(lat_1), + lat_2_(lat_2), + lat_1_r_(lat_1 * util::DEGREE_TO_RADIAN), + lat_2_r_(lat_2 * util::DEGREE_TO_RADIAN) { + ASSERT(!eckit::types::is_approximately_equal(figure().R(), 0.)); + + if (eckit::types::is_approximately_equal(lat_1, -lat_2)) { + throw ProjectionProblem( + "LambertConformalConic: cannot have equal latitudes for standard parallels on opposite sides of equator", + Here()); + } + + double latFirstInRadians = 0.; + double lonFirstInRadians = 0.; + double LaDInRadians = 0.; + double LoVInRadians = 0.; + + auto n = eckit::types::is_approximately_equal(lat_1, lat_2) + ? sin(lat_1_r_) + : log(cos(lat_1_r_) / cos(lat_2_r_)) / log(tan(M_PI_4 + lat_2_r_ / 2.) / tan(M_PI_4 + lat_1_r_ / 2.)); + + auto f = (cos(lat_1_r_) * pow(tan(M_PI_4 + lat_1_r_ / 2.), n)) / n; + auto rho0_bare = f * pow(tan(M_PI_4 + LaDInRadians / 2.), -n); + auto rho = figure().R() * f * pow(tan(M_PI_4 + latFirstInRadians / 2.), -n); + auto rho0 = figure().R() * rho0_bare; // scaled + + auto dlam = lonFirstInRadians - LoVInRadians; + + auto x0 = rho * sin(n * dlam); + auto y0 = rho0 - rho * cos(n * dlam); +} + + +Point2 LambertConformalConic::fwd(const PointLonLat&) const { + NOTIMP; +} + + +PointLonLat LambertConformalConic::inv(const Point2& p) const { + double n = 0.; + double f = 0; + double rho0_bare = 0; + double LoVInRadians = 0; + + ASSERT(n != 0.); + + double x = p.X / figure().R(); + double y = rho0_bare - p.Y / figure().R(); + + if (double rho = std::hypot(x, y); rho != 0.) { + if (n < 0.) { + rho = -rho; + x = -x; + y = -y; + } + double lonr = std::atan2(x, y) / n + LoVInRadians; + double latr = 2. * std::atan(pow(f / rho, 1. / n)) - M_PI_2; + + return PointLonLat::make(util::RADIAN_TO_DEGREE * lonr, util::RADIAN_TO_DEGREE * latr); + } + + return PointLonLat::make(0., n > 0 ? PointLonLat::NORTH_POLE : PointLonLat::SOUTH_POLE); +} + + +Spec* LambertConformalConic::spec() const { + NOTIMP; +} + + +} // namespace eckit::geo::projection::figure diff --git a/src/eckit/geo/projection/LambertConformalConic.h b/src/eckit/geo/projection/figure/LambertConformalConic.h similarity index 69% rename from src/eckit/geo/projection/LambertConformalConic.h rename to src/eckit/geo/projection/figure/LambertConformalConic.h index adfd0a533..ab236d18c 100644 --- a/src/eckit/geo/projection/LambertConformalConic.h +++ b/src/eckit/geo/projection/figure/LambertConformalConic.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geo/Projection.h" +#include "eckit/geo/projection/ProjectionOnFigure.h" -namespace eckit::geo::projection { +namespace eckit::geo::projection::figure { /** @@ -23,7 +23,7 @@ namespace eckit::geo::projection { * @ref Map Projections: A Working Manual, John P. Snyder (1987) * @ref Wolfram MathWorld (http://mathworld.wolfram.com/LambertConformalConicProjection.html) */ -class LambertConformalConic final : public Projection { +class LambertConformalConic final : public ProjectionOnFigure { public: // -- Types // None @@ -35,6 +35,9 @@ class LambertConformalConic final : public Projection { explicit LambertConformalConic(const Spec&); + LambertConformalConic(PointLonLat centre, double lat_1, double lat_2); + LambertConformalConic(PointLonLat centre, double lat_1) : LambertConformalConic(centre, lat_1, lat_1) {} + // -- Destructor // None @@ -61,7 +64,14 @@ class LambertConformalConic final : public Projection { private: // -- Members - // None + + const PointLonLat centre_; // central meridian/parallel [degree] + const PointLonLatR centre_r_; // central meridian/parallel [radian] + + const double lat_1_; + const double lat_2_; + const double lat_1_r_; + const double lat_2_r_; // -- Methods // None @@ -82,4 +92,4 @@ class LambertConformalConic final : public Projection { }; -} // namespace eckit::geo::projection +} // namespace eckit::geo::projection::figure diff --git a/src/eckit/geo/projection/Mercator.cc b/src/eckit/geo/projection/figure/Mercator.cc similarity index 96% rename from src/eckit/geo/projection/Mercator.cc rename to src/eckit/geo/projection/figure/Mercator.cc index 9e02e7455..a4d00e33f 100644 --- a/src/eckit/geo/projection/Mercator.cc +++ b/src/eckit/geo/projection/figure/Mercator.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/projection/Mercator.h" +#include "eckit/geo/projection/figure/Mercator.h" #include #include @@ -20,7 +20,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geo::projection { +namespace eckit::geo::projection::figure { static ProjectionBuilder PROJECTION_1("mercator"); @@ -109,4 +109,4 @@ Spec* Mercator::spec() const { } -} // namespace eckit::geo::projection +} // namespace eckit::geo::projection::figure diff --git a/src/eckit/geo/projection/Mercator.h b/src/eckit/geo/projection/figure/Mercator.h similarity index 89% rename from src/eckit/geo/projection/Mercator.h rename to src/eckit/geo/projection/figure/Mercator.h index 84b22e883..5af54c90f 100644 --- a/src/eckit/geo/projection/Mercator.h +++ b/src/eckit/geo/projection/figure/Mercator.h @@ -15,14 +15,14 @@ #include #include "eckit/geo/Figure.h" -#include "eckit/geo/Projection.h" +#include "eckit/geo/projection/ProjectionOnFigure.h" -namespace eckit::geo::projection { +namespace eckit::geo::projection::figure { /// Calculate coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle -class Mercator final : public Projection { +class Mercator final : public ProjectionOnFigure { public: // -- Constructors @@ -69,4 +69,4 @@ class Mercator final : public Projection { }; -} // namespace eckit::geo::projection +} // namespace eckit::geo::projection::figure diff --git a/src/eckit/geo/projection/PolarStereographic.cc b/src/eckit/geo/projection/figure/PolarStereographic.cc similarity index 93% rename from src/eckit/geo/projection/PolarStereographic.cc rename to src/eckit/geo/projection/figure/PolarStereographic.cc index 031f36747..74af31c46 100644 --- a/src/eckit/geo/projection/PolarStereographic.cc +++ b/src/eckit/geo/projection/figure/PolarStereographic.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/projection/PolarStereographic.h" +#include "eckit/geo/projection/figure/PolarStereographic.h" #include @@ -18,7 +18,7 @@ #include "eckit/geo/util.h" -namespace eckit::geo::projection { +namespace eckit::geo::projection::figure { PolarStereographic::PolarStereographic(const Spec&) {} @@ -83,4 +83,4 @@ void init() { } // namespace -} // namespace eckit::geo::projection +} // namespace eckit::geo::projection::figure diff --git a/src/eckit/geo/projection/PolarStereographic.h b/src/eckit/geo/projection/figure/PolarStereographic.h similarity index 86% rename from src/eckit/geo/projection/PolarStereographic.h rename to src/eckit/geo/projection/figure/PolarStereographic.h index 90d67a473..ca5764824 100644 --- a/src/eckit/geo/projection/PolarStereographic.h +++ b/src/eckit/geo/projection/figure/PolarStereographic.h @@ -12,13 +12,13 @@ #pragma once -#include "eckit/geo/Projection.h" +#include "eckit/geo/projection/ProjectionOnFigure.h" -namespace eckit::geo::projection { +namespace eckit::geo::projection::figure { -class PolarStereographic final : public Projection { +class PolarStereographic final : public ProjectionOnFigure { public: // -- Types // None @@ -77,4 +77,4 @@ class PolarStereographic final : public Projection { }; -} // namespace eckit::geo::projection +} // namespace eckit::geo::projection::figure diff --git a/src/eckit/geo/projection/SpaceView.cc b/src/eckit/geo/projection/figure/SpaceView.cc similarity index 95% rename from src/eckit/geo/projection/SpaceView.cc rename to src/eckit/geo/projection/figure/SpaceView.cc index f2ae81f54..3ae06afff 100644 --- a/src/eckit/geo/projection/SpaceView.cc +++ b/src/eckit/geo/projection/figure/SpaceView.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/projection/SpaceView.h" +#include "eckit/geo/projection/figure/SpaceView.h" #include @@ -18,7 +18,7 @@ #include "eckit/geo/util.h" -namespace eckit::geo::projection { +namespace eckit::geo::projection::figure { SpaceView::SpaceView(const Spec&) { @@ -110,4 +110,4 @@ void init() { } // namespace -} // namespace eckit::geo::projection +} // namespace eckit::geo::projection::figure diff --git a/src/eckit/geo/projection/SpaceView.h b/src/eckit/geo/projection/figure/SpaceView.h similarity index 87% rename from src/eckit/geo/projection/SpaceView.h rename to src/eckit/geo/projection/figure/SpaceView.h index d31e3a85d..99b40a707 100644 --- a/src/eckit/geo/projection/SpaceView.h +++ b/src/eckit/geo/projection/figure/SpaceView.h @@ -12,17 +12,17 @@ #pragma once -#include "eckit/geo/Projection.h" +#include "eckit/geo/projection/ProjectionOnFigure.h" -namespace eckit::geo::projection { +namespace eckit::geo::projection::figure { /** * @brief SpaceView projection * @ref LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) */ -class SpaceView final : public Projection { +class SpaceView final : public ProjectionOnFigure { public: // -- Types // None @@ -81,4 +81,4 @@ class SpaceView final : public Projection { }; -} // namespace eckit::geo::projection +} // namespace eckit::geo::projection::figure diff --git a/tests/geo/projection_mercator.cc b/tests/geo/projection_mercator.cc index 20a6ccefa..258a5d5e9 100644 --- a/tests/geo/projection_mercator.cc +++ b/tests/geo/projection_mercator.cc @@ -13,7 +13,7 @@ #include #include "eckit/geo/figure/Sphere.h" -#include "eckit/geo/projection/Mercator.h" +#include "eckit/geo/projection/figure/Mercator.h" #include "eckit/testing/Test.h" @@ -21,7 +21,7 @@ namespace eckit::geo::test { CASE("projection: mercator (poles)") { - projection::Mercator projection(0., 14., new figure::Sphere(1.), {0., 0.}); + projection::figure::Mercator projection(0., 14., new figure::Sphere(1.), {0., 0.}); auto a = projection.fwd(PointLonLat{0., 90.}); EXPECT(a.Y > std::numeric_limits::max()); @@ -32,7 +32,7 @@ CASE("projection: mercator (poles)") { CASE("projection: mercator (1)") { - projection::Mercator projection(0., 14., new figure::Sphere(6371229.), {262.036, 14.7365}); + projection::figure::Mercator projection(0., 14., new figure::Sphere(6371229.), {262.036, 14.7365}); Point2 a{0., 0.}; auto b = projection.inv(a); @@ -43,7 +43,7 @@ CASE("projection: mercator (1)") { CASE("projection: mercator (2)") { - projection::Mercator projection(-180., 0., new figure::Sphere(1.), {0., 0.}); + projection::figure::Mercator projection(-180., 0., new figure::Sphere(1.), {0., 0.}); PointLonLat a{-75., 35.}; auto b = projection.fwd(a); From 69fa89d820b27f9ac6b1b10d17129e78817da662 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 11 May 2024 01:03:28 +0100 Subject: [PATCH 639/737] eckit::geo::Projection --- .../figure/LambertConformalConic.cc | 64 +++++++++---------- .../projection/figure/LambertConformalConic.h | 15 ++++- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/src/eckit/geo/projection/figure/LambertConformalConic.cc b/src/eckit/geo/projection/figure/LambertConformalConic.cc index 8b961a8a3..8af0a9d02 100644 --- a/src/eckit/geo/projection/figure/LambertConformalConic.cc +++ b/src/eckit/geo/projection/figure/LambertConformalConic.cc @@ -15,7 +15,6 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/geometry/Earth.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -25,16 +24,19 @@ namespace eckit::geo::projection::figure { LambertConformalConic::LambertConformalConic(const Spec& spec) : - LambertConformalConic({spec.get_double("lon_0"), spec.get_double("lat_0")}, spec.get_double("lat_1"), + LambertConformalConic({spec.get_double("lon_0"), spec.get_double("lat_0")}, + {spec.get_double("first_lon"), spec.get_double("first_lat")}, spec.get_double("lat_1"), spec.get_double("lat_2")) {} -LambertConformalConic::LambertConformalConic(PointLonLat centre, double lat_1, double lat_2) : +LambertConformalConic::LambertConformalConic(PointLonLat centre, PointLonLat first, double lat_1, double lat_2) : centre_(centre), centre_r_(centre), + first_(first), + first_r_(first), lat_1_(lat_1), - lat_2_(lat_2), lat_1_r_(lat_1 * util::DEGREE_TO_RADIAN), + lat_2_(lat_2), lat_2_r_(lat_2 * util::DEGREE_TO_RADIAN) { ASSERT(!eckit::types::is_approximately_equal(figure().R(), 0.)); @@ -44,56 +46,48 @@ LambertConformalConic::LambertConformalConic(PointLonLat centre, double lat_1, d Here()); } - double latFirstInRadians = 0.; - double lonFirstInRadians = 0.; - double LaDInRadians = 0.; - double LoVInRadians = 0.; + n_ = eckit::types::is_approximately_equal(lat_1, lat_2) + ? std::sin(lat_1_r_) + : std::log(std::cos(lat_1_r_) / std::cos(lat_2_r_)) + / std::log(std::tan(M_PI_4 + lat_2_r_ / 2.) / std::tan(M_PI_4 + lat_1_r_ / 2.)); - auto n = eckit::types::is_approximately_equal(lat_1, lat_2) - ? sin(lat_1_r_) - : log(cos(lat_1_r_) / cos(lat_2_r_)) / log(tan(M_PI_4 + lat_2_r_ / 2.) / tan(M_PI_4 + lat_1_r_ / 2.)); + if (eckit::types::is_approximately_equal(n_, 0.)) { + throw ProjectionProblem("LambertConformalConic: cannot corretly calculate n_", Here()); + } - auto f = (cos(lat_1_r_) * pow(tan(M_PI_4 + lat_1_r_ / 2.), n)) / n; - auto rho0_bare = f * pow(tan(M_PI_4 + LaDInRadians / 2.), -n); - auto rho = figure().R() * f * pow(tan(M_PI_4 + latFirstInRadians / 2.), -n); - auto rho0 = figure().R() * rho0_bare; // scaled + f_ = (std::cos(lat_1_r_) * std::pow(std::tan(M_PI_4 + lat_1_r_ / 2.), n_)) / n_; + rho0_bare_ = f_ * std::pow(std::tan(M_PI_4 + centre_r_.latr / 2.), -n_); +} - auto dlam = lonFirstInRadians - LoVInRadians; - auto x0 = rho * sin(n * dlam); - auto y0 = rho0 - rho * cos(n * dlam); -} +Point2 LambertConformalConic::fwd(const PointLonLat& p) const { + PointLonLatR q(p); + auto rho = figure().R() * f_ * std::pow(std::tan(M_PI_4 + q.latr / 2.), -n_); + auto rho0 = figure().R() * rho0_bare_; // scaled + auto dlam = q.lonr - centre_r_.lonr; -Point2 LambertConformalConic::fwd(const PointLonLat&) const { - NOTIMP; + return {rho * std::sin(n_ * dlam), rho0 - rho * std::cos(n_ * dlam)}; } PointLonLat LambertConformalConic::inv(const Point2& p) const { - double n = 0.; - double f = 0; - double rho0_bare = 0; - double LoVInRadians = 0; - - ASSERT(n != 0.); - - double x = p.X / figure().R(); - double y = rho0_bare - p.Y / figure().R(); + auto x = p.X / figure().R(); + auto y = rho0_bare_ - p.Y / figure().R(); - if (double rho = std::hypot(x, y); rho != 0.) { - if (n < 0.) { + if (auto rho = std::hypot(x, y); rho != 0.) { + if (n_ < 0.) { rho = -rho; x = -x; y = -y; } - double lonr = std::atan2(x, y) / n + LoVInRadians; - double latr = 2. * std::atan(pow(f / rho, 1. / n)) - M_PI_2; + auto lonr = std::atan2(x, y) / n_ + centre_r_.lonr; + auto latr = 2. * std::atan(std::pow(f_ / rho, 1. / n_)) - M_PI_2; return PointLonLat::make(util::RADIAN_TO_DEGREE * lonr, util::RADIAN_TO_DEGREE * latr); } - return PointLonLat::make(0., n > 0 ? PointLonLat::NORTH_POLE : PointLonLat::SOUTH_POLE); + return PointLonLat::make(0., n_ > 0 ? PointLonLat::NORTH_POLE : PointLonLat::SOUTH_POLE); } diff --git a/src/eckit/geo/projection/figure/LambertConformalConic.h b/src/eckit/geo/projection/figure/LambertConformalConic.h index ab236d18c..fe1e678c0 100644 --- a/src/eckit/geo/projection/figure/LambertConformalConic.h +++ b/src/eckit/geo/projection/figure/LambertConformalConic.h @@ -35,8 +35,9 @@ class LambertConformalConic final : public ProjectionOnFigure { explicit LambertConformalConic(const Spec&); - LambertConformalConic(PointLonLat centre, double lat_1, double lat_2); - LambertConformalConic(PointLonLat centre, double lat_1) : LambertConformalConic(centre, lat_1, lat_1) {} + LambertConformalConic(PointLonLat centre, PointLonLat first, double lat_1, double lat_2); + LambertConformalConic(PointLonLat centre, PointLonLat first, double lat_1) : + LambertConformalConic(centre, first, lat_1, lat_1) {} // -- Destructor // None @@ -68,11 +69,19 @@ class LambertConformalConic final : public ProjectionOnFigure { const PointLonLat centre_; // central meridian/parallel [degree] const PointLonLatR centre_r_; // central meridian/parallel [radian] + const PointLonLat first_; // first point [degree] + const PointLonLatR first_r_; // first point [radian] + const double lat_1_; - const double lat_2_; const double lat_1_r_; + const double lat_2_; const double lat_2_r_; + double n_; + double f_; + double rho0_bare_; + + // -- Methods // None From 1eced01b67864a61d52323d4669a530f6dbba5e4 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 13 May 2024 09:34:47 +0100 Subject: [PATCH 640/737] eckit::geo::Projection --- .../figure/LambertConformalConic.cc | 10 +++--- src/eckit/geo/projection/figure/Mercator.cc | 31 ++++++++++--------- src/eckit/geo/projection/figure/Mercator.h | 13 +++----- 3 files changed, 25 insertions(+), 29 deletions(-) diff --git a/src/eckit/geo/projection/figure/LambertConformalConic.cc b/src/eckit/geo/projection/figure/LambertConformalConic.cc index 8af0a9d02..5bc522374 100644 --- a/src/eckit/geo/projection/figure/LambertConformalConic.cc +++ b/src/eckit/geo/projection/figure/LambertConformalConic.cc @@ -38,20 +38,20 @@ LambertConformalConic::LambertConformalConic(PointLonLat centre, PointLonLat fir lat_1_r_(lat_1 * util::DEGREE_TO_RADIAN), lat_2_(lat_2), lat_2_r_(lat_2 * util::DEGREE_TO_RADIAN) { - ASSERT(!eckit::types::is_approximately_equal(figure().R(), 0.)); + ASSERT(!types::is_approximately_equal(figure().R(), 0.)); - if (eckit::types::is_approximately_equal(lat_1, -lat_2)) { + if (types::is_approximately_equal(lat_1, -lat_2)) { throw ProjectionProblem( "LambertConformalConic: cannot have equal latitudes for standard parallels on opposite sides of equator", Here()); } - n_ = eckit::types::is_approximately_equal(lat_1, lat_2) + n_ = types::is_approximately_equal(lat_1, lat_2) ? std::sin(lat_1_r_) : std::log(std::cos(lat_1_r_) / std::cos(lat_2_r_)) / std::log(std::tan(M_PI_4 + lat_2_r_ / 2.) / std::tan(M_PI_4 + lat_1_r_ / 2.)); - if (eckit::types::is_approximately_equal(n_, 0.)) { + if (types::is_approximately_equal(n_, 0.)) { throw ProjectionProblem("LambertConformalConic: cannot corretly calculate n_", Here()); } @@ -75,7 +75,7 @@ PointLonLat LambertConformalConic::inv(const Point2& p) const { auto x = p.X / figure().R(); auto y = rho0_bare_ - p.Y / figure().R(); - if (auto rho = std::hypot(x, y); rho != 0.) { + if (auto rho = std::hypot(x, y); !types::is_approximately_equal(rho, 0.)) { if (n_ < 0.) { rho = -rho; x = -x; diff --git a/src/eckit/geo/projection/figure/Mercator.cc b/src/eckit/geo/projection/figure/Mercator.cc index a4d00e33f..fdc42486d 100644 --- a/src/eckit/geo/projection/figure/Mercator.cc +++ b/src/eckit/geo/projection/figure/Mercator.cc @@ -27,29 +27,29 @@ static ProjectionBuilder PROJECTION_1("mercator"); static ProjectionBuilder PROJECTION_2("merc"); -Mercator::Mercator(double meridian, double parallel, Figure* figure, PointLonLat first) : - meridian_(PointLonLat::normalise_angle_to_minimum(meridian, -180.)), - parallel_(parallel), - figure_(figure), +Mercator::Mercator(PointLonLat centre, PointLonLat first, Figure* figure_ptr) : + ProjectionOnFigure(figure_ptr), + centre_(PointLonLat::make(centre.lon, centre.lat, PointLonLat::ANTIMERIDIAN)), first_(first), eps_(1e-10), max_iter_(15) { // Map Projections: A Working Manual, John P. Snyder (1987) // - Equation (7-9) to calculate phi iteratively // - Equation (15-11) to calculate t - ASSERT(figure_); - ASSERT_MSG(!types::is_approximately_equal(first.lat, 90.) && !types::is_approximately_equal(first.lat, -90.), - "Mercator: projection cannot be calculated at the poles"); + if (types::is_approximately_equal(first.lat, PointLonLat::NORTH_POLE) + || types::is_approximately_equal(first.lat, PointLonLat::SOUTH_POLE)) { + throw ProjectionProblem("Mercator: projection cannot be calculated at the poles", Here()); + } - e_ = figure_->eccentricity(); - lam0_ = util::DEGREE_TO_RADIAN * meridian_; + e_ = figure().eccentricity(); + lam0_ = util::DEGREE_TO_RADIAN * centre_.lon; - auto phi0 = util::DEGREE_TO_RADIAN * parallel_; + auto phi0 = util::DEGREE_TO_RADIAN * centre_.lat; auto lam1 = util::DEGREE_TO_RADIAN * first.lon; auto phi1 = util::DEGREE_TO_RADIAN * first.lat; - m_ = figure_->a() * std::cos(phi0) / (std::sqrt(1. - e_ * e_ * std::sin(phi0) * std::sin(phi0))); + m_ = figure().a() * std::cos(phi0) / (std::sqrt(1. - e_ * e_ * std::sin(phi0) * std::sin(phi0))); ASSERT(!types::is_approximately_equal(m_, 0.)); w_ = 1. / m_; @@ -63,13 +63,14 @@ Mercator::Mercator(double meridian, double parallel, Figure* figure, PointLonLat Mercator::Mercator(const Spec& spec) : - Mercator(spec.get_double("meridian"), spec.get_double("parallel"), - FigureFactory::instance().get(spec.get_string("figure")).create(spec), - PointLonLat{spec.get_double("lon0"), spec.get_double("lat0")}) {} + Mercator({spec.get_double("lon_0"), spec.get_double("lat_ts")}, + {spec.get_double("first_lon"), spec.get_double("first_lat")}, + FigureFactory::instance().get(spec.get_string("figure")).create(spec)) {} double Mercator::calculate_phi(double t) const { auto phi = M_PI_2 - 2 * std::atan(t); + for (size_t i = 0; i <= max_iter_; i++) { auto es = e_ * std::sin(phi); auto dphi = M_PI_2 - 2 * std::atan(t * (std::pow(((1. - es * es) / (1. + es * es)), 0.5 * e_))) - phi; @@ -105,7 +106,7 @@ PointLonLat Mercator::inv(const Point2& q) const { Spec* Mercator::spec() const { - return new spec::Custom{{{"projection", "mercator"}, {"lad", parallel_}, {"orientation", meridian_}}}; + return new spec::Custom{{{"projection", "mercator"}, {"lat_ts", centre_.lat}, {"lon_0", centre_.lon}}}; } diff --git a/src/eckit/geo/projection/figure/Mercator.h b/src/eckit/geo/projection/figure/Mercator.h index 5af54c90f..b68dd337d 100644 --- a/src/eckit/geo/projection/figure/Mercator.h +++ b/src/eckit/geo/projection/figure/Mercator.h @@ -12,9 +12,6 @@ #pragma once -#include - -#include "eckit/geo/Figure.h" #include "eckit/geo/projection/ProjectionOnFigure.h" @@ -26,7 +23,7 @@ class Mercator final : public ProjectionOnFigure { public: // -- Constructors - Mercator(double meridian, double parallel, Figure*, PointLonLat first = {0, 0}); + explicit Mercator(PointLonLat centre, PointLonLat first = {0, 0}, Figure* = nullptr); explicit Mercator(const Spec&); @@ -42,11 +39,9 @@ class Mercator final : public ProjectionOnFigure { private: // -- Members - const double meridian_; // angle [degree] between Eastward direction and the Equator, range [0, 90] - const double parallel_; // latitude [degree] of projection intersecting ellipsoid - - const std::unique_ptr
figure_; - PointLonLat first_; + const PointLonLat centre_; // angle [degree] between Eastward direction and the Equator, range [0, 90], latitude + // [degree] of projection intersecting ellipsoid + const PointLonLat first_; const double eps_; const size_t max_iter_; From 6e4ca606c83b6bc3e74e05cf0df405af5261961a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 16 May 2024 13:53:59 +0100 Subject: [PATCH 641/737] eckit::geo::Projection --- tests/geo/projection_mercator.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/geo/projection_mercator.cc b/tests/geo/projection_mercator.cc index 258a5d5e9..beb90e2d1 100644 --- a/tests/geo/projection_mercator.cc +++ b/tests/geo/projection_mercator.cc @@ -21,7 +21,7 @@ namespace eckit::geo::test { CASE("projection: mercator (poles)") { - projection::figure::Mercator projection(0., 14., new figure::Sphere(1.), {0., 0.}); + projection::figure::Mercator projection({0., 14.}, {0., 0.}, new figure::Sphere(1.)); auto a = projection.fwd(PointLonLat{0., 90.}); EXPECT(a.Y > std::numeric_limits::max()); @@ -32,7 +32,7 @@ CASE("projection: mercator (poles)") { CASE("projection: mercator (1)") { - projection::figure::Mercator projection(0., 14., new figure::Sphere(6371229.), {262.036, 14.7365}); + projection::figure::Mercator projection({0., 14.}, {262.036, 14.7365}, new figure::Sphere(6371229.)); Point2 a{0., 0.}; auto b = projection.inv(a); @@ -43,7 +43,7 @@ CASE("projection: mercator (1)") { CASE("projection: mercator (2)") { - projection::figure::Mercator projection(-180., 0., new figure::Sphere(1.), {0., 0.}); + projection::figure::Mercator projection({-180., 0.}, {0., 0.}, new figure::Sphere(1.)); PointLonLat a{-75., 35.}; auto b = projection.fwd(a); From a8737a02f87991ab54f4d318b724c4f12712cf72 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 16 May 2024 16:53:44 +0100 Subject: [PATCH 642/737] eckit::geo::util --- src/eckit/geo/CMakeLists.txt | 1 + src/eckit/geo/GreatCircle.cc | 51 +++++++++---------- .../geo/projection/ProjectionOnFigure.cc | 6 +-- src/eckit/geo/projection/ProjectionOnFigure.h | 8 --- .../figure/LambertAzimuthalEqualArea.cc | 2 +- .../figure/LambertAzimuthalEqualArea.h | 9 ++-- src/eckit/geo/util/sincos.h | 30 +++++++++++ 7 files changed, 62 insertions(+), 45 deletions(-) create mode 100644 src/eckit/geo/util/sincos.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 69843776b..325a91546 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -120,6 +120,7 @@ list(APPEND eckit_geo_srcs util/mutex.h util/reduced_classical_pl.cc util/reduced_octahedral_pl.cc + util/sincos.h ) set(eckit_geo_include_dirs diff --git a/src/eckit/geo/GreatCircle.cc b/src/eckit/geo/GreatCircle.cc index 0689b7451..2f9a18fb1 100644 --- a/src/eckit/geo/GreatCircle.cc +++ b/src/eckit/geo/GreatCircle.cc @@ -16,26 +16,25 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/util.h" +#include "eckit/geo/util/sincos.h" #include "eckit/types/FloatCompare.h" -//---------------------------------------------------------------------------------------------------------------------- namespace eckit::geo { -//---------------------------------------------------------------------------------------------------------------------- using types::is_approximately_equal; -static bool pole(const double lat) { + +static bool is_pole(const double lat) { return is_approximately_equal(std::abs(lat), 90.); } -//---------------------------------------------------------------------------------------------------------------------- GreatCircle::GreatCircle(const PointLonLat& Alonlat, const PointLonLat& Blonlat) : A_(Alonlat), B_(Blonlat) { - const bool Apole = pole(A_.lat); - const bool Bpole = pole(B_.lat); - const double lon12_deg = PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); + const bool Apole = is_pole(A_.lat); + const bool Bpole = is_pole(B_.lat); + const double lon12_deg = PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, PointLonLat::ANTIMERIDIAN); const bool lon_same = Apole || Bpole || is_approximately_equal(lon12_deg, 0.); const bool lon_opposite = Apole || Bpole || is_approximately_equal(std::abs(lon12_deg), 180.); @@ -52,6 +51,7 @@ GreatCircle::GreatCircle(const PointLonLat& Alonlat, const PointLonLat& Blonlat) crossesPoles_ = lon_same || lon_opposite; } + std::vector GreatCircle::latitude(double lon) const { if (crossesPoles()) { return {}; @@ -61,28 +61,31 @@ std::vector GreatCircle::latitude(double lon) const { const double lat2 = util::DEGREE_TO_RADIAN * B_.lat; const double lambda1p = util::DEGREE_TO_RADIAN * (lon - A_.lon); const double lambda2p = util::DEGREE_TO_RADIAN * (lon - B_.lon); - const double lambda = util::DEGREE_TO_RADIAN * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, -180.); + const double lambda + = util::DEGREE_TO_RADIAN * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, PointLonLat::ANTIMERIDIAN); double lat = std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); return {util::RADIAN_TO_DEGREE * lat}; } + std::vector GreatCircle::longitude(double lat) const { if (crossesPoles()) { - const double lon = pole(A_.lat) ? B_.lon : A_.lon; - if (pole(lat)) { + const double lon = is_pole(A_.lat) ? B_.lon : A_.lon; + if (is_pole(lat)) { return {lon}; } return {lon, lon + 180.}; } - const double lon12 = util::DEGREE_TO_RADIAN * PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -180.); - const double lon1 = util::DEGREE_TO_RADIAN * A_.lon; - const double lat1 = util::DEGREE_TO_RADIAN * A_.lat; - const double lat2 = util::DEGREE_TO_RADIAN * B_.lat; - const double lat3 = util::DEGREE_TO_RADIAN * lat; + const double lon12 + = util::DEGREE_TO_RADIAN * PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, PointLonLat::ANTIMERIDIAN); + const double lon1 = util::DEGREE_TO_RADIAN * A_.lon; + const double lat1 = util::DEGREE_TO_RADIAN * A_.lat; + const double lat2 = util::DEGREE_TO_RADIAN * B_.lat; + const double lat3 = util::DEGREE_TO_RADIAN * lat; const double X = std::sin(lat1) * std::cos(lat2) * std::sin(lon12); const double Y = std::sin(lat1) * std::cos(lat2) * std::cos(lon12) - std::cos(lat1) * std::sin(lat2); @@ -110,24 +113,20 @@ std::vector GreatCircle::longitude(double lat) const { return {}; } + bool GreatCircle::crossesPoles() const { return crossesPoles_; } -std::pair GreatCircle::calculate_course(const PointLonLat& A, const PointLonLat& B) { - const auto sdl = std::sin(util::DEGREE_TO_RADIAN * (B.lon - A.lon)); - const auto cdl = std::cos(util::DEGREE_TO_RADIAN * (B.lon - A.lon)); - const auto spA = std::sin(util::DEGREE_TO_RADIAN * A.lat); - const auto cpA = std::cos(util::DEGREE_TO_RADIAN * A.lat); - const auto spB = std::sin(util::DEGREE_TO_RADIAN * B.lat); - const auto cpB = std::cos(util::DEGREE_TO_RADIAN * B.lat); - const auto alpha1 = util::RADIAN_TO_DEGREE * std::atan2(cpB * sdl, cpA * spB - spA * cpB * cdl); - const auto alpha2 = util::RADIAN_TO_DEGREE * std::atan2(cpA * sdl, -cpB * spA + spB * cpA * cdl); +std::pair GreatCircle::calculate_course(const PointLonLat& A, const PointLonLat& B) { + const util::sincos_t dl(util::DEGREE_TO_RADIAN * (A.lon - B.lon)); + const util::sincos_t scA(util::DEGREE_TO_RADIAN * A.lat); + const util::sincos_t scB(util::DEGREE_TO_RADIAN * B.lat); - return {alpha1, alpha2}; + return {util::RADIAN_TO_DEGREE * std::atan2(scB.cos * dl.sin, scA.cos * scB.sin - scA.sin * scB.cos * dl.cos), + util::RADIAN_TO_DEGREE * std::atan2(scA.cos * dl.sin, -scB.cos * scA.sin + scB.sin * scA.cos * dl.cos)}; } -//---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geo diff --git a/src/eckit/geo/projection/ProjectionOnFigure.cc b/src/eckit/geo/projection/ProjectionOnFigure.cc index 6a4a0c64f..33088a79d 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.cc +++ b/src/eckit/geo/projection/ProjectionOnFigure.cc @@ -12,8 +12,7 @@ #include "eckit/geo/projection/ProjectionOnFigure.h" -#include - +#include "eckit/geo/PointLonLat.h" #include "eckit/geo/geometry/Earth.h" #include "eckit/geo/util.h" @@ -21,9 +20,6 @@ namespace eckit::geo::projection { -ProjectionOnFigure::sincos_t::sincos_t(value_type r) : array{std::sin(r), std::sqrt(1. - std::sin(r) * std::sin(r))} {} - - ProjectionOnFigure::PointLonLatR::PointLonLatR(value_type lonr, value_type latr) : array{lonr, latr} {} diff --git a/src/eckit/geo/projection/ProjectionOnFigure.h b/src/eckit/geo/projection/ProjectionOnFigure.h index e60623875..2f3367dff 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.h +++ b/src/eckit/geo/projection/ProjectionOnFigure.h @@ -16,7 +16,6 @@ #include #include "eckit/geo/Figure.h" -#include "eckit/geo/PointLonLat.h" #include "eckit/geo/Projection.h" @@ -35,13 +34,6 @@ class ProjectionOnFigure : public Projection { const value_type& latr = array::operator[](1); }; - struct sincos_t final : std::array { - explicit sincos_t(value_type r); - - const value_type& sin = array::operator[](0); - const value_type& cos = array::operator[](1); - }; - // -- Constructors explicit ProjectionOnFigure(const Spec&); diff --git a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc index 3f0c5b601..06f188c30 100644 --- a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc @@ -54,7 +54,7 @@ Point2 LambertAzimuthalEqualArea::fwd(const PointLonLat& p) const { PointLonLat LambertAzimuthalEqualArea::inv(const Point2& p) const { if (auto x = p.X, y = p.Y, rho = std::sqrt(x * x + y * y); !types::is_approximately_equal(rho, 0.)) { - const sincos_t c(2. * std::asin(rho / (2. * figure().R()))); + const util::sincos_t c(2. * std::asin(rho / (2. * figure().R()))); const auto lonr = centre_r_.lonr + std::atan2(x * c.sin, rho * phi0_.cos * c.cos - y * phi0_.sin * c.sin); const auto latr = std::asin(c.cos * phi0_.sin + y * c.sin * phi0_.cos / rho); diff --git a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h index 9d20d6479..e6f53d213 100644 --- a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h @@ -12,9 +12,8 @@ #pragma once -#include - #include "eckit/geo/projection/ProjectionOnFigure.h" +#include "eckit/geo/util/sincos.h" namespace eckit::geo::projection::figure { @@ -68,9 +67,9 @@ class LambertAzimuthalEqualArea final : public ProjectionOnFigure { const PointLonLat first_; // first point [degree] const PointLonLatR first_r_; // first point [radian] - const sincos_t phi0_; - const sincos_t phi_; - const sincos_t dlam_; + const util::sincos_t phi0_; + const util::sincos_t phi_; + const util::sincos_t dlam_; // -- Methods // None diff --git a/src/eckit/geo/util/sincos.h b/src/eckit/geo/util/sincos.h new file mode 100644 index 000000000..6fe51cf6e --- /dev/null +++ b/src/eckit/geo/util/sincos.h @@ -0,0 +1,30 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include + + +namespace eckit::geo::util { + + +struct sincos_t final : std::array { + explicit sincos_t(value_type r) : array{std::sin(r), std::sqrt(1. - std::sin(r) * std::sin(r))} {} + + const value_type& sin = array::operator[](0); + const value_type& cos = array::operator[](1); +}; + + +} // namespace eckit::geo::util From c6c1cc980c98fc24b51bf240161d91713b355c12 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 16 May 2024 16:55:11 +0100 Subject: [PATCH 643/737] Cleanup --- src/eckit/geo/polygon/LonLatPolygon.cc | 5 +---- src/eckit/geo/polygon/LonLatPolygon.h | 5 ++--- src/eckit/geo/polygon/Polygon.cc | 4 +--- src/eckit/geo/polygon/Polygon.h | 4 +--- 4 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/eckit/geo/polygon/LonLatPolygon.cc b/src/eckit/geo/polygon/LonLatPolygon.cc index 533009d8c..53aae168f 100644 --- a/src/eckit/geo/polygon/LonLatPolygon.cc +++ b/src/eckit/geo/polygon/LonLatPolygon.cc @@ -8,6 +8,7 @@ * does it submit to any jurisdiction. */ + #include "eckit/geo/polygon/LonLatPolygon.h" #include @@ -17,11 +18,9 @@ #include "eckit/geo/PointLonLat.h" #include "eckit/types/FloatCompare.h" -//---------------------------------------------------------------------------------------------------------------------- namespace eckit::geo::polygon { -//---------------------------------------------------------------------------------------------------------------------- namespace { @@ -59,7 +58,6 @@ inline Point2 componentsMax(const Point2& A, const Point2& B) { } // namespace -//---------------------------------------------------------------------------------------------------------------------- LonLatPolygon::LonLatPolygon(const std::vector& points, bool includePoles) : container_type(points) { ASSERT(points.size() > 1); @@ -180,6 +178,5 @@ bool LonLatPolygon::contains(const Point2& Plonlat, bool normalise_angle) const return false; } -//---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geo::polygon diff --git a/src/eckit/geo/polygon/LonLatPolygon.h b/src/eckit/geo/polygon/LonLatPolygon.h index f82282f2d..5dd8cb5c4 100644 --- a/src/eckit/geo/polygon/LonLatPolygon.h +++ b/src/eckit/geo/polygon/LonLatPolygon.h @@ -8,6 +8,7 @@ * does it submit to any jurisdiction. */ + #pragma once #include @@ -15,15 +16,14 @@ #include "eckit/geo/Point2.h" -//---------------------------------------------------------------------------------------------------------------------- namespace eckit::geo::polygon { -//---------------------------------------------------------------------------------------------------------------------- class LonLatPolygon : protected std::vector { public: // -- Types + using container_type = std::vector; using container_type::value_type; @@ -77,6 +77,5 @@ class LonLatPolygon : protected std::vector { bool quickCheckLongitude_; }; -//---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geo::polygon diff --git a/src/eckit/geo/polygon/Polygon.cc b/src/eckit/geo/polygon/Polygon.cc index 6b5da73d2..9808f9406 100644 --- a/src/eckit/geo/polygon/Polygon.cc +++ b/src/eckit/geo/polygon/Polygon.cc @@ -8,15 +8,14 @@ * does it submit to any jurisdiction. */ + #include #include "eckit/geo/polygon/Polygon.h" -//---------------------------------------------------------------------------------------------------------------------- namespace eckit::geo::polygon { -//---------------------------------------------------------------------------------------------------------------------- bool Polygon::congruent(const Polygon& p) const { if (empty()) { @@ -61,6 +60,5 @@ void Polygon::print(std::ostream& s) const { s << ']'; } -//---------------------------------------------------------------------------------------------------------------------- } // namespace eckit::geo::polygon diff --git a/src/eckit/geo/polygon/Polygon.h b/src/eckit/geo/polygon/Polygon.h index d3fa50b39..1e2b19792 100644 --- a/src/eckit/geo/polygon/Polygon.h +++ b/src/eckit/geo/polygon/Polygon.h @@ -8,6 +8,7 @@ * does it submit to any jurisdiction. */ + #pragma once #include @@ -15,11 +16,9 @@ #include "eckit/geo/Point2.h" -//------------------------------------------------------------------------------------------------------ namespace eckit::geo::polygon { -//------------------------------------------------------------------------------------------------------ class Polygon : protected std::deque { public: @@ -49,6 +48,5 @@ class Polygon : protected std::deque { } }; -//------------------------------------------------------------------------------------------------------ } // namespace eckit::geo::polygon From 9515305c130075447b712892cfa67b6b30486ac0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 17 May 2024 00:56:17 +0100 Subject: [PATCH 644/737] eckit::geo::Point --- src/eckit/geo/CMakeLists.txt | 2 + src/eckit/geo/PointLonLat.cc | 4 +- src/eckit/geo/PointLonLatR.cc | 58 ++++++++++++++++ src/eckit/geo/PointLonLatR.h | 97 ++++++++++++++++++++++++++ tests/geo/CMakeLists.txt | 1 + tests/geo/pointlonlatr.cc | 127 ++++++++++++++++++++++++++++++++++ 6 files changed, 287 insertions(+), 2 deletions(-) create mode 100644 src/eckit/geo/PointLonLatR.cc create mode 100644 src/eckit/geo/PointLonLatR.h create mode 100644 tests/geo/pointlonlatr.cc diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 325a91546..56f066567 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -24,6 +24,8 @@ list(APPEND eckit_geo_srcs Point3.h PointLonLat.cc PointLonLat.h + PointLonLatR.cc + PointLonLatR.h Projection.cc Projection.h Range.cc diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index dcb1c542f..1393c6373 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -27,7 +27,7 @@ PointLonLat::value_type PointLonLat::normalise_angle_to_minimum(value_type a, va static const auto modulo_globe = [](auto a) { return a - GLOBE * std::floor(a / GLOBE); }; auto diff = a - minimum; - return 0. <= diff && diff < GLOBE ? a : modulo_globe(diff) + minimum; + return 0. <= diff && diff < GLOBE ? a : (modulo_globe(diff) + minimum); } @@ -35,7 +35,7 @@ PointLonLat::value_type PointLonLat::normalise_angle_to_maximum(value_type a, va auto modulo_globe = [](auto a) { return a - GLOBE * std::ceil(a / GLOBE); }; auto diff = a - maximum; - return -GLOBE < diff && diff <= 0. ? a : modulo_globe(a - maximum) + maximum; + return -GLOBE < diff && diff <= 0. ? a : (modulo_globe(diff) + maximum); } diff --git a/src/eckit/geo/PointLonLatR.cc b/src/eckit/geo/PointLonLatR.cc new file mode 100644 index 000000000..08125da51 --- /dev/null +++ b/src/eckit/geo/PointLonLatR.cc @@ -0,0 +1,58 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/PointLonLatR.h" + +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo { + + +PointLonLatR::value_type PointLonLatR::normalise_angle_to_minimum(value_type a, value_type minimum) { + static const auto modulo_globe = [](auto a) { return a - GLOBE * std::floor(a / GLOBE); }; + + auto diff = a - minimum; + return 0. <= diff && diff < GLOBE ? a : (modulo_globe(diff) + minimum); +} + + +PointLonLatR::value_type PointLonLatR::normalise_angle_to_maximum(value_type a, value_type maximum) { + auto modulo_globe = [](auto a) { return a - GLOBE * std::ceil(a / GLOBE); }; + + auto diff = a - maximum; + return -GLOBE < diff && diff <= 0. ? a : (modulo_globe(diff) + maximum); +} + + +PointLonLatR PointLonLatR::make(value_type lon, value_type lat, value_type lon_minimum, value_type eps) { + lat = normalise_angle_to_minimum(lat, SOUTH_POLE); + + if (types::is_strictly_greater(lat, NORTH_POLE, eps)) { + lat = GLOBE / 2. - lat; + lon += GLOBE / 2.; + } + + return types::is_approximately_equal(lat, NORTH_POLE, eps) ? PointLonLatR{0., NORTH_POLE} + : types::is_approximately_equal(lat, SOUTH_POLE, eps) + ? PointLonLatR{EQUATOR, SOUTH_POLE} + : PointLonLatR{normalise_angle_to_minimum(lon, lon_minimum), lat}; +} + + +bool points_equal(const PointLonLatR& a, const PointLonLatR& b, PointLonLatR::value_type eps) { + const auto c = PointLonLatR::make(a.lonr, a.latr, PointLonLatR::EQUATOR, eps); + const auto d = PointLonLatR::make(b.lonr, b.latr, PointLonLatR::EQUATOR, eps); + return types::is_approximately_equal(c.lonr, d.lonr, eps) && types::is_approximately_equal(c.latr, d.latr, eps); +} + +} // namespace eckit::geo diff --git a/src/eckit/geo/PointLonLatR.h b/src/eckit/geo/PointLonLatR.h new file mode 100644 index 000000000..f9b3b0af2 --- /dev/null +++ b/src/eckit/geo/PointLonLatR.h @@ -0,0 +1,97 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include +#include +#include + + +namespace eckit::geo { + + +class PointLonLatR final : protected std::array { +public: + // -- Types + + using container_type = array; + using container_type::value_type; + + // -- Constructors + + PointLonLatR() : PointLonLatR(0., 0.) {} + + PointLonLatR(value_type lon, value_type lat) : container_type{lon, lat} {} + + PointLonLatR(const PointLonLatR& other) : container_type(other) {} + + PointLonLatR(PointLonLatR&& other) : container_type(other) {} + + // -- Destructor + + ~PointLonLatR() = default; + + // -- Operators + + PointLonLatR& operator=(const PointLonLatR& other) { + container_type::operator=(other); + return *this; + } + + PointLonLatR& operator=(PointLonLatR&& other) { + container_type::operator=(other); + return *this; + } + + // -- Members + + const value_type& lonr = container_type::operator[](0); + const value_type& latr = container_type::operator[](1); + + // -- Methods + + static value_type normalise_angle_to_minimum(value_type, value_type minimum); + + static value_type normalise_angle_to_maximum(value_type, value_type maximum); + + [[nodiscard]] static PointLonLatR make(value_type lon, value_type lat, value_type lon_minimum = EQUATOR, + value_type eps = EPS); + + PointLonLatR antipode() const { return make(lonr, latr + GLOBE / 2.); } + + // -- Class members + + static constexpr double GLOBE = 2. * M_PI; + static constexpr double GREENWICH = 0.; + static constexpr double ANTIMERIDIAN = -M_PI; + static constexpr double EQUATOR = 0.; + static constexpr double NORTH_POLE = M_PI_2; + static constexpr double SOUTH_POLE = -M_PI_2; + + static constexpr value_type EPS = 1e-10; + + // -- Class methods + // None + + // -- Friends + + friend std::ostream& operator<<(std::ostream& out, const PointLonLatR& p) { + return out << '{' << p.lonr << ", " << p.latr << '}'; + } +}; + + +bool points_equal(const PointLonLatR&, const PointLonLatR&, PointLonLatR::value_type eps = PointLonLatR::EPS); + + +} // namespace eckit::geo diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index adf307441..030db62b8 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -18,6 +18,7 @@ foreach(_test point2 point3 pointlonlat + pointlonlatr projection projection_ll_to_xyz projection_mercator diff --git a/tests/geo/pointlonlatr.cc b/tests/geo/pointlonlatr.cc new file mode 100644 index 000000000..aaae2df21 --- /dev/null +++ b/tests/geo/pointlonlatr.cc @@ -0,0 +1,127 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/PointLonLatR.h" +#include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::test { + + +CASE("PointLonLatR normalise_angle_to_*") { + struct test_t { + double angle; + double lim; + double ref; + }; + + + SECTION("normalise_angle_to_minimum") { + for (const auto& test : { + test_t{1., 0., 1.}, + {1. + 42. * PointLonLatR::GLOBE, 0., 1.}, + {1. - 42. * PointLonLatR::GLOBE, 0., 1.}, + {1., 3. * PointLonLatR::GLOBE, 3. * PointLonLatR::GLOBE + 1.}, + {-1., 3. * PointLonLatR::GLOBE, 4. * PointLonLatR::GLOBE - 1.}, + }) { + EXPECT(types::is_approximately_equal( + test.ref, PointLonLatR::normalise_angle_to_minimum(test.angle, test.lim), PointLonLatR::EPS)); + } + } + + + SECTION("normalise_angle_to_maximum") { + for (const auto& test : { + test_t{1., 0., 1. - PointLonLatR::GLOBE}, + {1., 3. * PointLonLatR::GLOBE, 2. * PointLonLatR::GLOBE + 1.}, + {-1., 3. * PointLonLatR::GLOBE, 3. * PointLonLatR::GLOBE - 1.}, + }) { + EXPECT(types::is_approximately_equal( + test.ref, PointLonLatR::normalise_angle_to_maximum(test.angle, test.lim), PointLonLatR::EPS)); + } + } +} + + +CASE("PointLonLatR normalisation") { + PointLonLatR p(1, PointLonLatR::NORTH_POLE); + EXPECT_EQUAL(p.lonr, 1.); + EXPECT_EQUAL(p.latr, PointLonLatR::NORTH_POLE); + + auto p2 = PointLonLatR::make(p.lonr, p.latr); + EXPECT_EQUAL(p2.lonr, 0.); + EXPECT(points_equal(p, p2)); + + auto p3 = PointLonLatR(1. + 42. * PointLonLatR::GLOBE, PointLonLatR::NORTH_POLE); + EXPECT(points_equal(p, p3)); + + PointLonLatR q(1., PointLonLatR::SOUTH_POLE); + EXPECT_EQUAL(q.lonr, 1.); + EXPECT_EQUAL(q.latr, PointLonLatR::SOUTH_POLE); + + auto q2 = q.antipode(); + EXPECT_EQUAL(q2.lonr, 0.); + EXPECT(points_equal(q2, p)); + + auto q3 = q2.antipode(); + EXPECT(points_equal(q3, q)); +} + + +CASE("PointLonLatR comparison") { + auto r(PointLonLatR::make(-10., -91.)); + EXPECT(points_equal(r, r.antipode().antipode())); + + PointLonLatR a1{PointLonLatR::ANTIMERIDIAN, 0.}; + PointLonLatR a2{-PointLonLatR::ANTIMERIDIAN, 0.}; + EXPECT(points_equal(a1, a2)); + + PointLonLatR b1{0., PointLonLatR::SOUTH_POLE}; + auto b2 = PointLonLatR::make(1., PointLonLatR::SOUTH_POLE + PointLonLatR::GLOBE); + EXPECT(points_equal(b1, b2)); + + PointLonLatR c1{300., -30.}; + PointLonLatR c2{c1.lonr - PointLonLatR::GLOBE - PointLonLatR::EPS / 10., + c1.latr + PointLonLatR::GLOBE + PointLonLatR::EPS / 10.}; + EXPECT(points_equal(c1, c2)); + + PointLonLatR e1{PointLonLatR::GREENWICH, PointLonLatR::NORTH_POLE}; + PointLonLatR e2{PointLonLatR::ANTIMERIDIAN, PointLonLatR::NORTH_POLE}; + EXPECT(points_equal(e1, e2)); + + PointLonLatR f1{PointLonLatR::GREENWICH, PointLonLatR::SOUTH_POLE}; + PointLonLatR f2{-PointLonLatR::ANTIMERIDIAN, PointLonLatR::SOUTH_POLE}; + EXPECT(points_equal(f1, f2)); +} + + +CASE("PointLonLatR normalise angles") { + EXPECT(types::is_approximately_equal(0., PointLonLatR::normalise_angle_to_minimum(0. + PointLonLatR::GLOBE, 0.), + PointLonLatR::EPS)); + + EXPECT(types::is_approximately_equal( + 1., PointLonLatR::normalise_angle_to_minimum(1. + PointLonLatR::GLOBE * 11, 0.), PointLonLatR::EPS)); + + EXPECT(types::is_approximately_equal( + 2. + PointLonLatR::GLOBE * 11, + PointLonLatR::normalise_angle_to_minimum(2. + PointLonLatR::GLOBE * 11, PointLonLatR::GLOBE * 11), + PointLonLatR::EPS)); +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From 9d72419a9216f6f97ab988aab549b53e8356fad3 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 17 May 2024 01:35:21 +0100 Subject: [PATCH 645/737] eckit::geo::Point --- src/eckit/geo/Point.h | 3 ++- src/eckit/geo/PointLonLat.cc | 7 +++++++ src/eckit/geo/PointLonLat.h | 7 +++++++ src/eckit/geo/PointLonLatR.cc | 7 +++++++ src/eckit/geo/PointLonLatR.h | 7 +++++++ tests/geo/pointlonlatr.cc | 18 ++++++++++++++++++ 6 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/Point.h b/src/eckit/geo/Point.h index 227d32d1a..01059287c 100644 --- a/src/eckit/geo/Point.h +++ b/src/eckit/geo/Point.h @@ -18,12 +18,13 @@ #include "eckit/geo/Point2.h" #include "eckit/geo/Point3.h" #include "eckit/geo/PointLonLat.h" +#include "eckit/geo/PointLonLatR.h" namespace eckit::geo { -using Point = std::variant; +using Point = std::variant; bool points_equal(const Point&, const Point&); bool points_equal(const Point&, const Point&, double eps); diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index 1393c6373..edb80d884 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -17,6 +17,8 @@ #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/PointLonLatR.h" +#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -64,6 +66,11 @@ PointLonLat PointLonLat::make(value_type lon, value_type lat, value_type lon_min } +PointLonLat PointLonLat::make_from(const PointLonLatR& p) { + return make(util::RADIAN_TO_DEGREE * p.lonr, util::RADIAN_TO_DEGREE * p.latr); +} + + bool points_equal(const PointLonLat& a, const PointLonLat& b, PointLonLat::value_type eps) { const auto c = PointLonLat::make(a.lon, a.lat, PointLonLat::EQUATOR, eps); const auto d = PointLonLat::make(b.lon, b.lat, PointLonLat::EQUATOR, eps); diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index 548b344d9..db2dd7071 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -17,6 +17,11 @@ #include +namespace eckit::geo { +class PointLonLatR; +} + + namespace eckit::geo { @@ -69,6 +74,8 @@ class PointLonLat final : protected std::array { [[nodiscard]] static PointLonLat make(value_type lon, value_type lat, value_type lon_minimum = EQUATOR, value_type eps = EPS); + [[nodiscard]] static PointLonLat make_from(const PointLonLatR&); + PointLonLat antipode() const { return make(lon, lat + GLOBE / 2.); } // -- Class members diff --git a/src/eckit/geo/PointLonLatR.cc b/src/eckit/geo/PointLonLatR.cc index 08125da51..dcf6f1751 100644 --- a/src/eckit/geo/PointLonLatR.cc +++ b/src/eckit/geo/PointLonLatR.cc @@ -12,6 +12,8 @@ #include "eckit/geo/PointLonLatR.h" +#include "eckit/geo/PointLonLat.h" +#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -49,6 +51,11 @@ PointLonLatR PointLonLatR::make(value_type lon, value_type lat, value_type lon_m } +PointLonLatR PointLonLatR::make_from(const PointLonLat& p) { + return make(util::DEGREE_TO_RADIAN * p.lon, util::DEGREE_TO_RADIAN * p.lat); +} + + bool points_equal(const PointLonLatR& a, const PointLonLatR& b, PointLonLatR::value_type eps) { const auto c = PointLonLatR::make(a.lonr, a.latr, PointLonLatR::EQUATOR, eps); const auto d = PointLonLatR::make(b.lonr, b.latr, PointLonLatR::EQUATOR, eps); diff --git a/src/eckit/geo/PointLonLatR.h b/src/eckit/geo/PointLonLatR.h index f9b3b0af2..e2861c93e 100644 --- a/src/eckit/geo/PointLonLatR.h +++ b/src/eckit/geo/PointLonLatR.h @@ -17,6 +17,11 @@ #include +namespace eckit::geo { +class PointLonLat; +} + + namespace eckit::geo { @@ -67,6 +72,8 @@ class PointLonLatR final : protected std::array { [[nodiscard]] static PointLonLatR make(value_type lon, value_type lat, value_type lon_minimum = EQUATOR, value_type eps = EPS); + [[nodiscard]] static PointLonLatR make_from(const PointLonLat&); + PointLonLatR antipode() const { return make(lonr, latr + GLOBE / 2.); } // -- Class members diff --git a/tests/geo/pointlonlatr.cc b/tests/geo/pointlonlatr.cc index aaae2df21..a8dcbce70 100644 --- a/tests/geo/pointlonlatr.cc +++ b/tests/geo/pointlonlatr.cc @@ -11,6 +11,8 @@ #include "eckit/geo/PointLonLatR.h" +#include "eckit/geo/PointLonLat.h" +#include "eckit/geo/util.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" @@ -119,6 +121,22 @@ CASE("PointLonLatR normalise angles") { } +CASE("PointLonLatR conversion to/from PointLonLat") { + PointLonLatR p{0., 0.}; + EXPECT(points_equal(p, PointLonLatR::make_from(PointLonLat{0., 0.}))); + + PointLonLatR q{0., PointLonLatR::NORTH_POLE}; + EXPECT(points_equal(q, PointLonLatR::make_from(PointLonLat{1., PointLonLat::NORTH_POLE}))); + + PointLonLatR r{42. * PointLonLatR::GLOBE, PointLonLatR::SOUTH_POLE}; + EXPECT( + points_equal(r, PointLonLatR::make_from(PointLonLat{0., PointLonLat::SOUTH_POLE - 42. * PointLonLat::GLOBE}))); + + PointLonLatR s{10. * util::DEGREE_TO_RADIAN, 42. * PointLonLatR::GLOBE}; + EXPECT(points_equal(s, PointLonLatR::make_from(PointLonLat{10. - 42. * PointLonLat::GLOBE, 0.}))); +} + + } // namespace eckit::geo::test From 28d090a2fe6f317aa6bb7b4c976e0aa0badb8d98 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 17 May 2024 16:15:31 +0100 Subject: [PATCH 646/737] eckit::geo::Projection --- src/eckit/geo/PointLonLat.cc | 5 +- src/eckit/geo/PointLonLat.h | 2 +- src/eckit/geo/PointLonLatR.cc | 5 +- src/eckit/geo/PointLonLatR.h | 2 +- src/eckit/geo/Projection.h | 2 +- src/eckit/geo/projection/Composer.cc | 2 +- src/eckit/geo/projection/Composer.h | 2 +- src/eckit/geo/projection/LonLatToXY.cc | 4 +- src/eckit/geo/projection/LonLatToXY.h | 2 +- src/eckit/geo/projection/LonLatToXYZ.cc | 11 ++- src/eckit/geo/projection/LonLatToXYZ.h | 4 +- src/eckit/geo/projection/None.cc | 5 -- src/eckit/geo/projection/None.h | 2 +- src/eckit/geo/projection/PROJ.cc | 17 ++-- src/eckit/geo/projection/PROJ.h | 2 +- .../geo/projection/ProjectionOnFigure.cc | 27 +++--- src/eckit/geo/projection/ProjectionOnFigure.h | 15 +--- src/eckit/geo/projection/Rotation.cc | 21 +++-- src/eckit/geo/projection/Rotation.h | 4 +- src/eckit/geo/projection/XYToLonLat.cc | 4 +- src/eckit/geo/projection/XYToLonLat.h | 2 +- .../figure/LambertAzimuthalEqualArea.cc | 34 ++++--- .../figure/LambertAzimuthalEqualArea.h | 4 +- .../figure/LambertConformalConic.cc | 21 +++-- .../projection/figure/LambertConformalConic.h | 2 +- src/eckit/geo/projection/figure/Mercator.cc | 15 ++-- src/eckit/geo/projection/figure/Mercator.h | 2 +- .../projection/figure/PolarStereographic.cc | 89 +++++++++---------- .../projection/figure/PolarStereographic.h | 15 +++- src/eckit/geo/projection/figure/SpaceView.cc | 4 +- src/eckit/geo/projection/figure/SpaceView.h | 2 +- tests/geo/pointlonlatr.cc | 9 +- 32 files changed, 177 insertions(+), 160 deletions(-) diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index edb80d884..2c963659a 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -17,7 +17,6 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/PointLonLatR.h" #include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -66,8 +65,8 @@ PointLonLat PointLonLat::make(value_type lon, value_type lat, value_type lon_min } -PointLonLat PointLonLat::make_from(const PointLonLatR& p) { - return make(util::RADIAN_TO_DEGREE * p.lonr, util::RADIAN_TO_DEGREE * p.latr); +PointLonLat PointLonLat::make_from_lonlatr(value_type lonr, value_type latr) { + return make(util::RADIAN_TO_DEGREE * lonr, util::RADIAN_TO_DEGREE * latr); } diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index db2dd7071..495b6caf8 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -74,7 +74,7 @@ class PointLonLat final : protected std::array { [[nodiscard]] static PointLonLat make(value_type lon, value_type lat, value_type lon_minimum = EQUATOR, value_type eps = EPS); - [[nodiscard]] static PointLonLat make_from(const PointLonLatR&); + [[nodiscard]] static PointLonLat make_from_lonlatr(value_type lonr, value_type latr); PointLonLat antipode() const { return make(lon, lat + GLOBE / 2.); } diff --git a/src/eckit/geo/PointLonLatR.cc b/src/eckit/geo/PointLonLatR.cc index dcf6f1751..48279d788 100644 --- a/src/eckit/geo/PointLonLatR.cc +++ b/src/eckit/geo/PointLonLatR.cc @@ -12,7 +12,6 @@ #include "eckit/geo/PointLonLatR.h" -#include "eckit/geo/PointLonLat.h" #include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -51,8 +50,8 @@ PointLonLatR PointLonLatR::make(value_type lon, value_type lat, value_type lon_m } -PointLonLatR PointLonLatR::make_from(const PointLonLat& p) { - return make(util::DEGREE_TO_RADIAN * p.lon, util::DEGREE_TO_RADIAN * p.lat); +PointLonLatR PointLonLatR::make_from_lonlat(value_type lon, value_type lat) { + return make(util::DEGREE_TO_RADIAN * lon, util::DEGREE_TO_RADIAN * lat); } diff --git a/src/eckit/geo/PointLonLatR.h b/src/eckit/geo/PointLonLatR.h index e2861c93e..4db6ada3a 100644 --- a/src/eckit/geo/PointLonLatR.h +++ b/src/eckit/geo/PointLonLatR.h @@ -72,7 +72,7 @@ class PointLonLatR final : protected std::array { [[nodiscard]] static PointLonLatR make(value_type lon, value_type lat, value_type lon_minimum = EQUATOR, value_type eps = EPS); - [[nodiscard]] static PointLonLatR make_from(const PointLonLat&); + [[nodiscard]] static PointLonLatR make_from_lonlat(value_type lon, value_type lat); PointLonLatR antipode() const { return make(lonr, latr + GLOBE / 2.); } diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 2d50dc81f..3378378c2 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -66,7 +66,7 @@ class Projection { virtual Point fwd(const Point&) const = 0; virtual Point inv(const Point&) const = 0; - [[nodiscard]] virtual Spec* spec() const = 0; + virtual void spec(spec::Custom&) const = 0; }; diff --git a/src/eckit/geo/projection/Composer.cc b/src/eckit/geo/projection/Composer.cc index 1e510d934..b4eb38f22 100644 --- a/src/eckit/geo/projection/Composer.cc +++ b/src/eckit/geo/projection/Composer.cc @@ -55,7 +55,7 @@ std::vector Composer::inv_points(const Point& p) const { } -Spec* Composer::spec() const { +void Composer::spec(spec::Custom& custom) const { NOTIMP; } diff --git a/src/eckit/geo/projection/Composer.h b/src/eckit/geo/projection/Composer.h index 6f276b9bf..ca19f3750 100644 --- a/src/eckit/geo/projection/Composer.h +++ b/src/eckit/geo/projection/Composer.h @@ -42,7 +42,7 @@ class Composer final : public Projection, private std::deque { // -- Overridden methods - [[nodiscard]] Spec* spec() const override; + void spec(spec::Custom&) const override; Point fwd(const Point&) const override; Point inv(const Point&) const override; diff --git a/src/eckit/geo/projection/LonLatToXY.cc b/src/eckit/geo/projection/LonLatToXY.cc index 2be295d56..aa6c5ff72 100644 --- a/src/eckit/geo/projection/LonLatToXY.cc +++ b/src/eckit/geo/projection/LonLatToXY.cc @@ -21,8 +21,8 @@ namespace eckit::geo::projection { static ProjectionBuilder PROJECTION("ll_to_xy"); -Spec* LonLatToXY::spec() const { - return new spec::Custom({{"projection", "ll_to_xy"}}); +void LonLatToXY::spec(spec::Custom& custom) const { + custom.set("projection", "ll_to_xy"); } diff --git a/src/eckit/geo/projection/LonLatToXY.h b/src/eckit/geo/projection/LonLatToXY.h index 2f47fd1c6..0699e35c2 100644 --- a/src/eckit/geo/projection/LonLatToXY.h +++ b/src/eckit/geo/projection/LonLatToXY.h @@ -32,7 +32,7 @@ class LonLatToXY final : public Projection { // -- Overridden methods - [[nodiscard]] Spec* spec() const override; + void spec(spec::Custom&) const override; private: // -- Overridden methods diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc index 24b7ed537..4559b28b2 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -34,7 +34,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { explicit LonLatToSphereXYZ(double R) : R_(R) {} Point3 operator()(const PointLonLat& p) const override { return S::convertSphericalToCartesian(R_, p, 0.); } PointLonLat operator()(const Point3& q) const override { return S::convertCartesianToSpherical(R_, q); } - Spec* spec() const override { return new spec::Custom{{{"R", R_}}}; } + void spec(spec::Custom& custom) const override { custom.set("R", R_); } }; struct LonLatToSpheroidXYZ final : Implementation { @@ -45,7 +45,10 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) { explicit LonLatToSpheroidXYZ(double a, double b) : a_(a), b_(b) {} Point3 operator()(const PointLonLat& p) const override { return S::convertSphericalToCartesian(a_, b_, p, 0.); } PointLonLat operator()(const Point3& q) const override { NOTIMP; } - Spec* spec() const override { return new spec::Custom{{{"a", a_}, {"b", b_}}}; } + void spec(spec::Custom& custom) const override { + custom.set("a", a_); + custom.set("b", b_); + } }; impl_.reset(types::is_approximately_equal(a, b) ? static_cast(new LonLatToSphereXYZ(a)) @@ -60,8 +63,8 @@ LonLatToXYZ::LonLatToXYZ(const Spec& spec) : LonLatToXYZ(spec.get_double("a", spec.get_double("R", 1.)), spec.get_double("b", spec.get_double("R", 1.))) {} -Spec* LonLatToXYZ::spec() const { - return impl_->spec(); +void LonLatToXYZ::spec(spec::Custom& custom) const { + impl_->spec(custom); } diff --git a/src/eckit/geo/projection/LonLatToXYZ.h b/src/eckit/geo/projection/LonLatToXYZ.h index 92eb16460..193cf8213 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.h +++ b/src/eckit/geo/projection/LonLatToXYZ.h @@ -36,7 +36,7 @@ class LonLatToXYZ final : public Projection { // -- Overridden methods - Spec* spec() const override; + void spec(spec::Custom&) const override; private: // -- Types @@ -52,7 +52,7 @@ class LonLatToXYZ final : public Projection { virtual Point3 operator()(const PointLonLat&) const = 0; virtual PointLonLat operator()(const Point3&) const = 0; - [[nodiscard]] virtual Spec* spec() const = 0; + virtual void spec(spec::Custom&) const = 0; }; // -- Members diff --git a/src/eckit/geo/projection/None.cc b/src/eckit/geo/projection/None.cc index 8caf3932f..2f6e81cbf 100644 --- a/src/eckit/geo/projection/None.cc +++ b/src/eckit/geo/projection/None.cc @@ -21,9 +21,4 @@ namespace eckit::geo::projection { static ProjectionBuilder PROJECTION("none"); -Spec* None::spec() const { - return nullptr; -} - - } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index 48f4cd08e..203819700 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -27,7 +27,7 @@ class None final : public Projection { // -- Overridden methods - [[nodiscard]] Spec* spec() const override; + void spec(spec::Custom&) const override {} inline Point fwd(const Point& p) const override { return p; } inline Point inv(const Point& q) const override { return q; } diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 2e0dfb24d..fa52834e5 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -27,7 +27,8 @@ static ProjectionBuilder PROJECTION("proj"); namespace { -constexpr auto CTX = PJ_DEFAULT_CTX; +constexpr auto CTX = PJ_DEFAULT_CTX; +static const std::string DEFAULT = "EPSG:4326"; struct pj_t : std::unique_ptr { @@ -145,8 +146,8 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini PROJ::PROJ(const Spec& spec) : - PROJ(spec.get_string("source", "EPSG:4326"), // default to WGS 84 - spec.get_string("target", "EPSG:4326"), // ... + PROJ(spec.get_string("source", DEFAULT), // default to WGS 84 + spec.get_string("target", DEFAULT), // ... spec.get_double("lon_minimum", 0)) {} @@ -175,8 +176,14 @@ Point PROJ::inv(const Point& q) const { } -Spec* PROJ::spec() const { - return new spec::Custom{{{"projection", "proj"}, {"source", source_}, {"target", target_}}}; +void PROJ::spec(spec::Custom& custom) const { + custom.set("projection", "proj"); + if (source_ != DEFAULT) { + custom.set("source", source_); + } + if (target_ != DEFAULT) { + custom.set("target", target_); + } } diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index fbe057ba5..157afd2ce 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -40,7 +40,7 @@ class PROJ final : public Projection { Point fwd(const Point&) const override; Point inv(const Point&) const override; - [[nodiscard]] Spec* spec() const override; + void spec(spec::Custom&) const override; private: // -- Types diff --git a/src/eckit/geo/projection/ProjectionOnFigure.cc b/src/eckit/geo/projection/ProjectionOnFigure.cc index 33088a79d..0f479363c 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.cc +++ b/src/eckit/geo/projection/ProjectionOnFigure.cc @@ -12,21 +12,15 @@ #include "eckit/geo/projection/ProjectionOnFigure.h" -#include "eckit/geo/PointLonLat.h" +#include "eckit/exception/Exceptions.h" #include "eckit/geo/geometry/Earth.h" -#include "eckit/geo/util.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo::projection { -ProjectionOnFigure::PointLonLatR::PointLonLatR(value_type lonr, value_type latr) : array{lonr, latr} {} - - -ProjectionOnFigure::PointLonLatR::PointLonLatR(const PointLonLat& p) : - PointLonLatR{p.lon * util::DEGREE_TO_RADIAN, p.lat * util::DEGREE_TO_RADIAN} {} - - // FIXME refactor figures into a single hierarchy struct Earth final : Figure { Earth() = default; @@ -40,7 +34,20 @@ struct Earth final : Figure { ProjectionOnFigure::ProjectionOnFigure(const Spec&) : ProjectionOnFigure() {} -ProjectionOnFigure::ProjectionOnFigure(Figure* figure_ptr) : figure_(figure_ptr != nullptr ? figure_ptr : new Earth) {} +ProjectionOnFigure::ProjectionOnFigure(Figure* figure_ptr) : figure_(figure_ptr != nullptr ? figure_ptr : new Earth) { + ASSERT(figure_); +} + + +void ProjectionOnFigure::spec(spec::Custom& custom) const { + // FIXME OO figure + if (types::is_approximately_equal(figure_->a(), figure_->b())) { + custom.set("R", figure_->R()); + return; + } + custom.set("a", figure_->a()); + custom.set("b", figure_->b()); +} } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/ProjectionOnFigure.h b/src/eckit/geo/projection/ProjectionOnFigure.h index 2f3367dff..f8f8e2682 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.h +++ b/src/eckit/geo/projection/ProjectionOnFigure.h @@ -12,7 +12,6 @@ #pragma once -#include #include #include "eckit/geo/Figure.h" @@ -24,16 +23,6 @@ namespace eckit::geo::projection { class ProjectionOnFigure : public Projection { protected: - // -- Types - - struct PointLonLatR final : protected std::array { - PointLonLatR(value_type lonr, value_type latr); - explicit PointLonLatR(const PointLonLat&); - - const value_type& lonr = array::operator[](0); - const value_type& latr = array::operator[](1); - }; - // -- Constructors explicit ProjectionOnFigure(const Spec&); @@ -43,6 +32,10 @@ class ProjectionOnFigure : public Projection { const Figure& figure() const { return *figure_; } + // -- Overridden methods + + void spec(spec::Custom&) const override; + private: // -- Members diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 2ee42124b..f9622d0c6 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -36,13 +36,16 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : struct NonRotated final : Implementation { PointLonLat operator()(const PointLonLat& p) const override { return p; } - Spec* spec() const override { return nullptr; } + void spec(spec::Custom& custom) const override {} }; struct RotationAngle final : Implementation { explicit RotationAngle(double angle) : angle_(angle) {} PointLonLat operator()(const PointLonLat& p) const override { return {p.lon + angle_, p.lat}; } - Spec* spec() const override { return new spec::Custom{{{"projection", "rotation"}, {"angle", angle_}}}; } + void spec(spec::Custom& custom) const override { + custom.set("projection", "rotation"); + custom.set("angle", angle_); + } const double angle_; }; @@ -54,11 +57,11 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : return geometry::UnitSphere::convertCartesianToSpherical( R_ * geometry::UnitSphere::convertSphericalToCartesian(p)); } - Spec* spec() const override { - return new spec::Custom{{{"projection", "rotation"}, - {"south_pole_lon", south_pole_lon_}, - {"south_pole_lat", south_pole_lat_}, - {"angle", angle_}}}; + void spec(spec::Custom& custom) const override { + custom.set("projection", "rotation"); + custom.set("south_pole_lon", south_pole_lon_); + custom.set("south_pole_lat", south_pole_lat_); + custom.set("angle", angle_); } const M R_; const double south_pole_lon_; @@ -116,8 +119,8 @@ Rotation::Rotation(const Spec& spec) : Rotation(spec.get_double("south_pole_lon"), spec.get_double("south_pole_lat"), spec.get_double("angle", 0)) {} -Spec* Rotation::spec() const { - return fwd_->spec(); +void Rotation::spec(spec::Custom& custom) const { + return fwd_->spec(custom); } diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index 3012f146e..bbbfa0b73 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -37,7 +37,7 @@ class Rotation final : public Projection { // -- Overridden methods - [[nodiscard]] Spec* spec() const override; + void spec(spec::Custom&) const override; private: // -- Types @@ -52,7 +52,7 @@ class Rotation final : public Projection { void operator=(Implementation&&) = delete; virtual PointLonLat operator()(const PointLonLat&) const = 0; - virtual Spec* spec() const = 0; + virtual void spec(spec::Custom&) const = 0; }; // -- Members diff --git a/src/eckit/geo/projection/XYToLonLat.cc b/src/eckit/geo/projection/XYToLonLat.cc index 04c2c40b7..86341a7a3 100644 --- a/src/eckit/geo/projection/XYToLonLat.cc +++ b/src/eckit/geo/projection/XYToLonLat.cc @@ -22,8 +22,8 @@ static ProjectionBuilder PROJECTION1("xy_to_ll"); static ProjectionBuilder PROJECTION2("plate-carree"); -Spec* XYToLonLat::spec() const { - return new spec::Custom({{"projection", "plate-carree"}}); +void XYToLonLat::spec(spec::Custom& custom) const { + custom.set("projection", "plate-carree"); } diff --git a/src/eckit/geo/projection/XYToLonLat.h b/src/eckit/geo/projection/XYToLonLat.h index 061b4cb60..c2c817535 100644 --- a/src/eckit/geo/projection/XYToLonLat.h +++ b/src/eckit/geo/projection/XYToLonLat.h @@ -32,7 +32,7 @@ class XYToLonLat final : public Projection { // -- Overridden methods - [[nodiscard]] Spec* spec() const override; + void spec(spec::Custom&) const override; private: // -- Overridden methods diff --git a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc index 06f188c30..6c8dd07c4 100644 --- a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc @@ -14,9 +14,7 @@ #include -#include "eckit/geo/geometry/Earth.h" #include "eckit/geo/spec/Custom.h" -#include "eckit/geo/util.h" #include "eckit/types/FloatCompare.h" @@ -34,9 +32,9 @@ LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(const Spec& spec) : LambertAzimuthalEqualArea::LambertAzimuthalEqualArea(PointLonLat centre, PointLonLat first) : centre_(centre), - centre_r_(centre), + centre_r_(PointLonLatR::make_from_lonlat(centre.lon, centre.lat)), first_(first), - first_r_(first), + first_r_(PointLonLatR::make_from_lonlat(first.lon, first.lat)), phi0_(centre_r_.latr), phi_(first_r_.latr), dlam_(first_r_.lonr - centre_r_.lonr) {} @@ -53,25 +51,23 @@ Point2 LambertAzimuthalEqualArea::fwd(const PointLonLat& p) const { PointLonLat LambertAzimuthalEqualArea::inv(const Point2& p) const { - if (auto x = p.X, y = p.Y, rho = std::sqrt(x * x + y * y); !types::is_approximately_equal(rho, 0.)) { - const util::sincos_t c(2. * std::asin(rho / (2. * figure().R()))); + auto rho = std::sqrt(p.X * p.X + p.Y * p.Y); + const util::sincos_t c(2. * std::asin(rho / (2. * figure().R()))); - const auto lonr = centre_r_.lonr + std::atan2(x * c.sin, rho * phi0_.cos * c.cos - y * phi0_.sin * c.sin); - const auto latr = std::asin(c.cos * phi0_.sin + y * c.sin * phi0_.cos / rho); - - return PointLonLat::make(util::RADIAN_TO_DEGREE * lonr, util::RADIAN_TO_DEGREE * latr); - } - - return PointLonLat::make(centre_.lon, centre_.lat); + return PointLonLat::make_from_lonlatr( + centre_r_.lonr + std::atan2(p.X * c.sin, rho * phi0_.cos * c.cos - p.Y * phi0_.sin * c.sin), + std::asin(c.cos * phi0_.sin + p.Y * c.sin * phi0_.cos / rho)); } -Spec* LambertAzimuthalEqualArea::spec() const { - return new spec::Custom({{"projection", "laea"}, - {"lon_0", centre_.lon}, - {"lat_0", centre_.lat}, - {"lon_first", first_.lon}, - {"lat_first", first_.lat}}); +void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { + ProjectionOnFigure::spec(custom); + + custom.set("projection", "laea"); + custom.set("lon_0", centre_.lon); + custom.set("lat_0", centre_.lat); + custom.set("lon_first", first_.lon); + custom.set("lat_first", first_.lat); } diff --git a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h index e6f53d213..81f823ab6 100644 --- a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h @@ -48,7 +48,7 @@ class LambertAzimuthalEqualArea final : public ProjectionOnFigure { // -- Overridden methods - [[nodiscard]] Spec* spec() const override; + void spec(spec::Custom&) const override; // -- Class members // None @@ -57,8 +57,6 @@ class LambertAzimuthalEqualArea final : public ProjectionOnFigure { // None private: - // -- Types - // -- Members const PointLonLat centre_; // central meridian/standard parallel [degree] diff --git a/src/eckit/geo/projection/figure/LambertConformalConic.cc b/src/eckit/geo/projection/figure/LambertConformalConic.cc index 5bc522374..f73c14274 100644 --- a/src/eckit/geo/projection/figure/LambertConformalConic.cc +++ b/src/eckit/geo/projection/figure/LambertConformalConic.cc @@ -30,10 +30,10 @@ LambertConformalConic::LambertConformalConic(const Spec& spec) : LambertConformalConic::LambertConformalConic(PointLonLat centre, PointLonLat first, double lat_1, double lat_2) : - centre_(centre), - centre_r_(centre), - first_(first), - first_r_(first), + centre_(PointLonLat::make(centre.lon, centre.lat)), + centre_r_(PointLonLatR::make_from_lonlat(centre.lon, centre.lat)), + first_(PointLonLat::make(first.lon, first.lat)), + first_r_(PointLonLatR::make_from_lonlat(first.lon, first.lat)), lat_1_(lat_1), lat_1_r_(lat_1 * util::DEGREE_TO_RADIAN), lat_2_(lat_2), @@ -61,7 +61,7 @@ LambertConformalConic::LambertConformalConic(PointLonLat centre, PointLonLat fir Point2 LambertConformalConic::fwd(const PointLonLat& p) const { - PointLonLatR q(p); + auto q = PointLonLatR::make_from_lonlat(p.lon, p.lat); auto rho = figure().R() * f_ * std::pow(std::tan(M_PI_4 + q.latr / 2.), -n_); auto rho0 = figure().R() * rho0_bare_; // scaled @@ -91,8 +91,15 @@ PointLonLat LambertConformalConic::inv(const Point2& p) const { } -Spec* LambertConformalConic::spec() const { - NOTIMP; +void LambertConformalConic::spec(spec::Custom& custom) const { + ProjectionOnFigure::spec(custom); + + custom.set("lon_0", centre_.lon); + custom.set("lat_0", centre_.lat); + custom.set("first_lon", first_.lon); + custom.set("first_lat", first_.lat); + custom.set("lat_1", lat_1_); + custom.set("lat_2", lat_1_); } diff --git a/src/eckit/geo/projection/figure/LambertConformalConic.h b/src/eckit/geo/projection/figure/LambertConformalConic.h index fe1e678c0..1cbfef412 100644 --- a/src/eckit/geo/projection/figure/LambertConformalConic.h +++ b/src/eckit/geo/projection/figure/LambertConformalConic.h @@ -55,7 +55,7 @@ class LambertConformalConic final : public ProjectionOnFigure { // -- Overridden methods - [[nodiscard]] Spec* spec() const override; + void spec(spec::Custom&) const override; // -- Class members // None diff --git a/src/eckit/geo/projection/figure/Mercator.cc b/src/eckit/geo/projection/figure/Mercator.cc index fdc42486d..74a2f1938 100644 --- a/src/eckit/geo/projection/figure/Mercator.cc +++ b/src/eckit/geo/projection/figure/Mercator.cc @@ -42,13 +42,14 @@ Mercator::Mercator(PointLonLat centre, PointLonLat first, Figure* figure_ptr) : throw ProjectionProblem("Mercator: projection cannot be calculated at the poles", Here()); } - e_ = figure().eccentricity(); - lam0_ = util::DEGREE_TO_RADIAN * centre_.lon; - + auto lam0 = util::DEGREE_TO_RADIAN * centre_.lon; auto phi0 = util::DEGREE_TO_RADIAN * centre_.lat; auto lam1 = util::DEGREE_TO_RADIAN * first.lon; auto phi1 = util::DEGREE_TO_RADIAN * first.lat; + e_ = figure().eccentricity(); + lam0_ = lam0; + m_ = figure().a() * std::cos(phi0) / (std::sqrt(1. - e_ * e_ * std::sin(phi0) * std::sin(phi0))); ASSERT(!types::is_approximately_equal(m_, 0.)); @@ -105,8 +106,12 @@ PointLonLat Mercator::inv(const Point2& q) const { } -Spec* Mercator::spec() const { - return new spec::Custom{{{"projection", "mercator"}, {"lat_ts", centre_.lat}, {"lon_0", centre_.lon}}}; +void Mercator::spec(spec::Custom& custom) const { + ProjectionOnFigure::spec(custom); + + custom.set("projection", "mercator"); + custom.set("lat_ts", centre_.lat); + custom.set("lon_0", centre_.lon); } diff --git a/src/eckit/geo/projection/figure/Mercator.h b/src/eckit/geo/projection/figure/Mercator.h index b68dd337d..77d973c99 100644 --- a/src/eckit/geo/projection/figure/Mercator.h +++ b/src/eckit/geo/projection/figure/Mercator.h @@ -34,7 +34,7 @@ class Mercator final : public ProjectionOnFigure { // -- Overridden methods - [[nodiscard]] Spec* spec() const override; + void spec(spec::Custom&) const override; private: // -- Members diff --git a/src/eckit/geo/projection/figure/PolarStereographic.cc b/src/eckit/geo/projection/figure/PolarStereographic.cc index 74af31c46..9dbdbb839 100644 --- a/src/eckit/geo/projection/figure/PolarStereographic.cc +++ b/src/eckit/geo/projection/figure/PolarStereographic.cc @@ -14,73 +14,66 @@ #include -#include "eckit/exception/Exceptions.h" -#include "eckit/geo/util.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo::projection::figure { -PolarStereographic::PolarStereographic(const Spec&) {} - - -Point2 PolarStereographic::fwd(const PointLonLat&) const { - NOTIMP; +PolarStereographic::PolarStereographic(const Spec& spec) : + PolarStereographic({spec.get_double("lon_0"), spec.get_double("lat_0")}, + {spec.get_double("first_lon"), spec.get_double("first_lat")}) {} + + +PolarStereographic::PolarStereographic(PointLonLat centre, PointLonLat first, Figure* figure_ptr) : + ProjectionOnFigure(figure_ptr), + centre_(PointLonLat::make(centre.lon, centre.lat)), + centre_r_(PointLonLatR::make_from_lonlat(centre.lon, centre.lat)), + first_(first), + first_r_(PointLonLatR::make_from_lonlat(first.lon, first.lat)), + sign_(centre_.lat < 0. ? -1. : 1.), + F_(types::is_approximately_equal(centre_.lat, PointLonLat::NORTH_POLE, PointLonLat::EPS) + || types::is_approximately_equal(centre_.lat, PointLonLat::SOUTH_POLE, PointLonLat::EPS) + ? 0.5 + : std::tan(0.5 * (M_PI_2 - sign_ * centre_r_.latr)) / std::cos(sign_ * centre_r_.latr)) { + auto z = fwd(first_); + x0_ = z.X; + y0_ = z.Y; } -PointLonLat PolarStereographic::inv(const Point2&) const { - NOTIMP; -} +Point2 PolarStereographic::fwd(const PointLonLat& q) const { + auto p = PointLonLatR::make_from_lonlat(q.lon, q.lat); + auto a = sign_ * (p.lonr - centre_r_.lonr); + auto tsf = std::tan(0.5 * (M_PI_2 - sign_ * p.latr)); + auto height = figure().R() * tsf / F_; -Spec* PolarStereographic::spec() const { - NOTIMP; + return {-sign_ * height * std::sin(a), sign_ * height * std::cos(a)}; } -namespace { - - -void init() { - static constexpr double EPSILON = 1e-10; - - const double radius = 1.; - const double centralLongitude = util::DEGREE_TO_RADIAN * 0. /*centralLongitudeInDegrees*/; - const double centralLatitude = util::DEGREE_TO_RADIAN * 0. /*centralLatitudeInDegrees*/; - const double lonFirst = util::DEGREE_TO_RADIAN * 0. /*lonFirstInDegrees*/; - const double latFirst = util::DEGREE_TO_RADIAN * 0. /*latFirstInDegrees*/; +PointLonLat PolarStereographic::inv(const Point2& q) const { + Point2 p{q.X - x0_, q.Y - y0_}; - const double sign = centralLatitude < 0 ? -1. : 1.; - const bool ind = fabs(fabs(centralLatitude) - M_PI_2) > EPSILON; + auto rh = std::sqrt(p.X * p.X + p.Y * p.Y); + auto tsi = rh / figure().R() * F_; - const double mcs = ind ? cos(sign * centralLatitude) : 0.; - const double tcs = ind ? tan(0.5 * (M_PI_2 - sign * centralLatitude)) : 0.; - - /* Forward projection from initial lat,lon to initial x,y */ - double tsf = tan(0.5 * (M_PI_2 - sign * latFirst)); - double height = ind ? radius * mcs * tsf / tcs : 2.0 * radius * tsf; - - double a = sign * (lonFirst - centralLongitude); - double x0 = -sign * height * sin(a); - double y0 = sign * height * cos(a); - - /* Inverse projection from x,y to lat,lon */ - double x = 0; - double y = 0; - Point2 p{(x - x0) * sign, (y - y0) * sign}; + return PointLonLat::make_from_lonlatr(sign_ * std::atan2(sign_ * p.X, -sign_ * p.Y) + centre_r_.lonr, + sign_ * (M_PI_2 - 2 * std::atan(tsi))); +} - double rh = sqrt(p.X * p.X + p.Y * p.Y); - double tsi = ind ? rh * tcs / (radius * mcs) : rh / (radius * 2.0); - double latr = sign * (M_PI_2 - 2 * atan(tsi)); - double lonr = rh == 0 ? sign * centralLongitude : sign * atan2(p.X, -p.Y) + centralLongitude; +void PolarStereographic::spec(spec::Custom& custom) const { + ProjectionOnFigure::spec(custom); - PointLonLat::make(lonr * util::RADIAN_TO_DEGREE, latr * util::RADIAN_TO_DEGREE); + custom.set("projection", "stere"); + custom.set("lon_0", centre_.lon); + custom.set("lat_0", centre_.lat); + custom.set("lon_first", first_.lon); + custom.set("lat_first", first_.lat); } -} // namespace - - } // namespace eckit::geo::projection::figure diff --git a/src/eckit/geo/projection/figure/PolarStereographic.h b/src/eckit/geo/projection/figure/PolarStereographic.h index ca5764824..e04aa233b 100644 --- a/src/eckit/geo/projection/figure/PolarStereographic.h +++ b/src/eckit/geo/projection/figure/PolarStereographic.h @@ -29,6 +29,7 @@ class PolarStereographic final : public ProjectionOnFigure { // -- Constructors explicit PolarStereographic(const Spec&); + PolarStereographic(PointLonLat centre, PointLonLat first = {0, 0}, Figure* = nullptr); // -- Destructor // None @@ -46,7 +47,7 @@ class PolarStereographic final : public ProjectionOnFigure { // -- Overridden methods - [[nodiscard]] Spec* spec() const override; + void spec(spec::Custom&) const override; // -- Class members // None @@ -56,7 +57,17 @@ class PolarStereographic final : public ProjectionOnFigure { private: // -- Members - // None + + const PointLonLat centre_; // projection centre [degree] + const PointLonLatR centre_r_; // projection centre [radian] + + const PointLonLat first_; // first point [degree] + const PointLonLatR first_r_; // first point [radian] + + const double sign_; + const double F_; + double x0_; + double y0_; // -- Methods // None diff --git a/src/eckit/geo/projection/figure/SpaceView.cc b/src/eckit/geo/projection/figure/SpaceView.cc index 3ae06afff..93694040c 100644 --- a/src/eckit/geo/projection/figure/SpaceView.cc +++ b/src/eckit/geo/projection/figure/SpaceView.cc @@ -15,6 +15,7 @@ #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" @@ -45,7 +46,8 @@ PointLonLat SpaceView::inv(const Point2&) const { } -Spec* SpaceView::spec() const { +void SpaceView::spec(spec::Custom& custom) const { + ProjectionOnFigure::spec(custom); NOTIMP; } diff --git a/src/eckit/geo/projection/figure/SpaceView.h b/src/eckit/geo/projection/figure/SpaceView.h index 99b40a707..697cb8970 100644 --- a/src/eckit/geo/projection/figure/SpaceView.h +++ b/src/eckit/geo/projection/figure/SpaceView.h @@ -50,7 +50,7 @@ class SpaceView final : public ProjectionOnFigure { // -- Overridden methods - [[nodiscard]] Spec* spec() const override; + void spec(spec::Custom&) const override; // -- Class members // None diff --git a/tests/geo/pointlonlatr.cc b/tests/geo/pointlonlatr.cc index a8dcbce70..ab7691f19 100644 --- a/tests/geo/pointlonlatr.cc +++ b/tests/geo/pointlonlatr.cc @@ -123,17 +123,16 @@ CASE("PointLonLatR normalise angles") { CASE("PointLonLatR conversion to/from PointLonLat") { PointLonLatR p{0., 0.}; - EXPECT(points_equal(p, PointLonLatR::make_from(PointLonLat{0., 0.}))); + EXPECT(points_equal(p, PointLonLatR::make_from_lonlat(0., 0.))); PointLonLatR q{0., PointLonLatR::NORTH_POLE}; - EXPECT(points_equal(q, PointLonLatR::make_from(PointLonLat{1., PointLonLat::NORTH_POLE}))); + EXPECT(points_equal(q, PointLonLatR::make_from_lonlat(1., PointLonLat::NORTH_POLE))); PointLonLatR r{42. * PointLonLatR::GLOBE, PointLonLatR::SOUTH_POLE}; - EXPECT( - points_equal(r, PointLonLatR::make_from(PointLonLat{0., PointLonLat::SOUTH_POLE - 42. * PointLonLat::GLOBE}))); + EXPECT(points_equal(r, PointLonLatR::make_from_lonlat(0., PointLonLat::SOUTH_POLE - 42. * PointLonLat::GLOBE))); PointLonLatR s{10. * util::DEGREE_TO_RADIAN, 42. * PointLonLatR::GLOBE}; - EXPECT(points_equal(s, PointLonLatR::make_from(PointLonLat{10. - 42. * PointLonLat::GLOBE, 0.}))); + EXPECT(points_equal(s, PointLonLatR::make_from_lonlat(10. - 42. * PointLonLat::GLOBE, 0.))); } From 02ec08ae09ab747edce83ea8fecdd3593fae02c2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 17 May 2024 16:59:33 +0100 Subject: [PATCH 647/737] eckit::geo::Projection --- src/eckit/geo/CMakeLists.txt | 2 ++ src/eckit/geo/projection/Stretch.cc | 53 +++++++++++++++++++++++++++++ src/eckit/geo/projection/Stretch.h | 53 +++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 src/eckit/geo/projection/Stretch.cc create mode 100644 src/eckit/geo/projection/Stretch.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 56f066567..32f6648d8 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -85,6 +85,8 @@ list(APPEND eckit_geo_srcs projection/ProjectionOnFigure.h projection/Rotation.cc projection/Rotation.h + projection/Stretch.cc + projection/Stretch.h projection/XYToLonLat.cc projection/XYToLonLat.h projection/figure/LambertAzimuthalEqualArea.cc diff --git a/src/eckit/geo/projection/Stretch.cc b/src/eckit/geo/projection/Stretch.cc new file mode 100644 index 000000000..cabf6be14 --- /dev/null +++ b/src/eckit/geo/projection/Stretch.cc @@ -0,0 +1,53 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/projection/Stretch.h" + +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/geo/util.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::projection { + + +static ProjectionBuilder PROJECTION("stretch"); + + +Stretch::Stretch(double c) : c_(c) { + if (types::is_approximately_equal(c_, 0.)) { + throw ProjectionProblem("Stretch: stretching_factor != 0", Here()); + } + ASSERT(c_ != 0.); +} + + +Stretch::Stretch(const Spec& spec) : Stretch(spec.get_double("stretching_factor")) {} + + +double Stretch::stretch(double a, double c) { + auto ar = util::DEGREE_TO_RADIAN * a; + ar = std::asin(std::cos(2. * std::atan(c * std::tan(std::acos(std::sin(ar)) * 0.5)))); + return util::RADIAN_TO_DEGREE * ar; +} + + +void Stretch::spec(spec::Custom& spec) const { + spec.set("projection", "stretch"); + spec.set("stretching_factor", c_); +} + + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/Stretch.h b/src/eckit/geo/projection/Stretch.h new file mode 100644 index 000000000..c20a5620f --- /dev/null +++ b/src/eckit/geo/projection/Stretch.h @@ -0,0 +1,53 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Projection.h" + + +namespace eckit::geo::projection { + + +class Stretch final : public Projection { +public: + // -- Constructors + + explicit Stretch(double c); + explicit Stretch(const Spec&); + + // -- Methods + + PointLonLat fwd(const PointLonLat& p) const { return PointLonLat::make(p.lon, stretch(p.lat, 1. / c_)); } + PointLonLat inv(const PointLonLat& p) const { return PointLonLat::make(p.lon, stretch(p.lat, c_)); } + + // -- Overridden methods + + void spec(spec::Custom&) const override; + +private: + // -- Members + + double c_; + + // -- Methods + + static double stretch(double a, double c); + + // -- Overridden methods + + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } +}; + + +} // namespace eckit::geo::projection From c2a25c17053032e4041e4fb339881916e0e6e29b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 20 May 2024 12:17:19 +0100 Subject: [PATCH 648/737] clang-format version 19 --- src/tools/eckit-grid-list.cc | 3 +-- src/tools/eckit-grid-spec.cc | 3 +-- src/tools/eckit-grid.cc | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/tools/eckit-grid-list.cc b/src/tools/eckit-grid-list.cc index 40c8f6f7c..6c03ff999 100644 --- a/src/tools/eckit-grid-list.cc +++ b/src/tools/eckit-grid-list.cc @@ -18,8 +18,7 @@ namespace eckit::tools { struct EckitGridList final : EckitTool { - EckitGridList(int argc, char** argv) : - EckitTool(argc, argv) {} + EckitGridList(int argc, char** argv) : EckitTool(argc, argv) {} void execute(const option::CmdArgs&) override { geo::GridFactory::list(Log::info()); diff --git a/src/tools/eckit-grid-spec.cc b/src/tools/eckit-grid-spec.cc index bf0249fc9..52e01b7ea 100644 --- a/src/tools/eckit-grid-spec.cc +++ b/src/tools/eckit-grid-spec.cc @@ -27,8 +27,7 @@ namespace eckit { class EckitGrid final : public EckitTool { public: - EckitGrid(int argc, char** argv) : - EckitTool(argc, argv) { + EckitGrid(int argc, char** argv) : EckitTool(argc, argv) { options_.push_back(new option::SimpleOption("check", "regex to check against result")); } diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index 5324201a1..c452cdf56 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -29,8 +29,7 @@ namespace eckit { class EckitGrid final : public EckitTool { public: - EckitGrid(int argc, char** argv) : - EckitTool(argc, argv) { + EckitGrid(int argc, char** argv) : EckitTool(argc, argv) { options_.push_back(new option::SimpleOption("uid", "by grid unique identifier, instead of name")); options_.push_back(new option::VectorOption("nearest-point", "nearest point location (lon/lat)", 2)); options_.push_back(new option::SimpleOption("nearest-k", "nearest k points")); From 830e6807f99e08fb75dde9119701f226d0688ca1 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 20 May 2024 14:47:39 +0100 Subject: [PATCH 649/737] Testing --- tests/geo/grid_reorder.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/geo/grid_reorder.cc b/tests/geo/grid_reorder.cc index b1f1b9fab..109eed30f 100644 --- a/tests/geo/grid_reorder.cc +++ b/tests/geo/grid_reorder.cc @@ -31,8 +31,8 @@ namespace eckit::geo::test { CASE("HEALPix") { SECTION("HEALPix::reorder") { - std::unique_ptr ring( - GridFactory::build(*std::unique_ptr(new spec::Custom({{"grid", "H2"}})))); + std::unique_ptr spec(new spec::Custom({{"grid", "H2"}})); + std::unique_ptr ring(GridFactory::build(*spec)); static const Renumber expected_ren_ring_to_nested{ 3, 7, 11, 15, 2, 1, 6, 5, 10, 9, 14, 13, 19, 0, 23, 4, 27, 8, 31, 12, 17, 22, 21, 26, From 4b95972727b653775b8b1e70cf4d43d014340b78 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 21 May 2024 11:08:37 +0100 Subject: [PATCH 650/737] Compatibility --- src/eckit/geo/Grid.cc | 2 +- src/eckit/geo/area/BoundingBox.h | 4 ++-- src/eckit/geo/etc/Grid.cc | 30 +++++++++++++-------------- src/eckit/geo/grid/ORCA.cc | 3 +-- src/eckit/geo/spec/Custom.cc | 27 +++++++----------------- src/eckit/geo/spec/Custom.h | 25 ++++++++++------------- tests/geo/grid_reduced_gg.cc | 20 ++++++++++-------- tests/geo/grid_regular_gg.cc | 16 +++++++-------- tests/geo/spec.cc | 35 +++++++++++++++++--------------- 9 files changed, 74 insertions(+), 88 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index a292fab74..9b1a10e76 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -162,7 +162,7 @@ void Grid::spec(spec::Custom&) const { const Grid* GridFactory::make_from_string(const std::string& str) { - std::unique_ptr spec(new spec::Custom(YAMLParser::decodeString(str))); + std::unique_ptr spec(spec::Custom::make_from_value(YAMLParser::decodeString(str))); return instance().make_from_spec_(*spec); } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 0a55490bd..f586ceaa1 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -42,9 +42,9 @@ class BoundingBox : public Area, protected std::array { BoundingBox(); - BoundingBox(const BoundingBox& other) : container_type(other) {} + BoundingBox(const BoundingBox& other) : Area(other), container_type(other) {} - BoundingBox(BoundingBox&& other) : container_type(other) {} + BoundingBox(BoundingBox&& other) : Area(other), container_type(other) {} // -- Destructor diff --git a/src/eckit/geo/etc/Grid.cc b/src/eckit/geo/etc/Grid.cc index 406ec9b54..4d42fb03c 100644 --- a/src/eckit/geo/etc/Grid.cc +++ b/src/eckit/geo/etc/Grid.cc @@ -46,25 +46,21 @@ void Grid::load(const PathName& path) { auto* custom = dynamic_cast((spec_ ? spec_ : (spec_ = std::make_unique())).get()); ASSERT(custom != nullptr); - auto spec_from_value_map = [](const ValueMap& map) { - auto* custom = new spec::Custom; - for (const auto& kv : map) { - custom->set(kv.first, kv.second); - } - return custom; - }; - struct SpecByUIDGenerator final : SpecByUID::generator_t { - explicit SpecByUIDGenerator(spec::Custom* spec) : spec_(spec) {} - Spec* spec() const override { return new spec::Custom(*spec_); } + explicit SpecByUIDGenerator(spec::Custom* spec) : spec_(spec) { ASSERT(spec_); } + Spec* spec() const override { return new spec::Custom(spec_->container()); } bool match(const spec::Custom& other) const override { return other == *spec_; } + + private: std::unique_ptr spec_; }; struct SpecByNameGenerator final : SpecByName::generator_t { - explicit SpecByNameGenerator(spec::Custom* spec) : spec_(spec) {} - Spec* spec(SpecByName::generator_t::arg1_t) const override { return new spec::Custom(*spec_); } + explicit SpecByNameGenerator(spec::Custom* spec) : spec_(spec) { ASSERT(spec_); } + Spec* spec(SpecByName::generator_t::arg1_t) const override { return new spec::Custom(spec_->container()); } bool match(const spec::Custom& other) const override { return other == *spec_; } + + private: std::unique_ptr spec_; }; @@ -77,8 +73,9 @@ void Grid::load(const PathName& path) { if (key == "grid_uids") { for (ValueMap m : static_cast(kv.second)) { ASSERT(m.size() == 1); - SpecByUID::instance().regist(m.begin()->first.as(), - new SpecByUIDGenerator(spec_from_value_map(m.begin()->second))); + SpecByUID::instance().regist( + m.begin()->first.as(), + new SpecByUIDGenerator(spec::Custom::make_from_value(m.begin()->second))); } continue; } @@ -86,8 +83,9 @@ void Grid::load(const PathName& path) { if (key == "grid_names") { for (ValueMap m : static_cast(kv.second)) { ASSERT(m.size() == 1); - SpecByName::instance().regist(m.begin()->first.as(), - new SpecByNameGenerator(spec_from_value_map(m.begin()->second))); + SpecByName::instance().regist( + m.begin()->first.as(), + new SpecByNameGenerator(spec::Custom::make_from_value(m.begin()->second))); } continue; } diff --git a/src/eckit/geo/grid/ORCA.cc b/src/eckit/geo/grid/ORCA.cc index 0301f70ae..3e59e05c6 100644 --- a/src/eckit/geo/grid/ORCA.cc +++ b/src/eckit/geo/grid/ORCA.cc @@ -147,8 +147,7 @@ ORCA::ORCA(const Spec& spec) : spec)) {} -ORCA::ORCA(uid_t uid) : - ORCA(*std::unique_ptr(GridFactory::make_spec(spec::Custom(spec::Custom::container_type{{"uid", uid}})))) {} +ORCA::ORCA(uid_t uid) : ORCA(*std::unique_ptr(GridFactory::make_spec(spec::Custom({{"uid", uid}})))) {} std::string ORCA::arrangement() const { diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 13dcc9183..f2a79c121 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -14,6 +14,7 @@ #include #include #include +#include #include "eckit/exception/Exceptions.h" #include "eckit/geo/util.h" @@ -154,7 +155,9 @@ Custom::Custom(const Custom::container_type& map) : map_(map) {} Custom::Custom(Custom::container_type&& map) : map_(map) {} -Custom::Custom(const Value& value) { +Custom* Custom::make_from_value(const Value& value) { + ASSERT(value.isMap()); + auto scalar = [](const Value& value) -> value_type { return value.isNumber() ? value_type(static_cast(value)) : value.isDouble() ? value_type(static_cast(value)) @@ -171,23 +174,13 @@ Custom::Custom(const Value& value) { : throw BadValue(value, Here()); }; - ASSERT(value.isMap()); + Custom::container_type container; for (const auto& [key, value] : static_cast(value)) { const std::string name = key; - map_[name] = value.isList() ? vector(value) : scalar(value); + container[name] = value.isList() ? vector(value) : scalar(value); } -} - - -Custom::Custom(const Custom& custom) : Custom(custom.map_) {} - -Custom::Custom(Custom&& custom) : Custom(custom.map_) {} - - -Custom& Custom::operator=(Custom&& custom) { - map_.swap(custom.map_); - return *this; + return new Custom(std::move(container)); } @@ -208,12 +201,6 @@ bool Custom::operator==(const Custom& other) const { } -Custom& Custom::operator=(const Custom& custom) { - map_ = custom.map_; - return *this; -} - - void Custom::set(const std::string& name, const std::string& value) { map_[name] = value; } diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 46c7a2ca6..dcfe26595 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -11,6 +11,7 @@ #pragma once +#include #include #include @@ -31,7 +32,7 @@ class Custom final : public Spec { struct key_type : std::string { key_type(const std::string&); - key_type(const char* s) : key_type(std::string{s}) {}; + key_type(const char* s) : key_type(std::string{s}) {} }; using value_type = std::variant, @@ -42,27 +43,19 @@ class Custom final : public Spec { // -- Constructors - explicit Custom(const container_type& = {}); - explicit Custom(container_type&&); - - explicit Custom(const Value&); - - Custom(const Custom&); - Custom(Custom&&); - - // -- Destructor + Custom() = default; + Custom(std::initializer_list init) : map_{init} {} - ~Custom() override = default; + explicit Custom(const container_type&); + explicit Custom(container_type&&); // -- Operators - Custom& operator=(const Custom&); - Custom& operator=(Custom&&); - bool operator==(const Custom&) const; // -- Methods + const container_type& container() const { return map_; } bool empty() const { return map_.empty(); } void clear() { map_.clear(); } @@ -108,6 +101,10 @@ class Custom final : public Spec { bool get(const std::string& name, std::vector& value) const override; bool get(const std::string& name, std::vector& value) const override; + // -- Class methods + + static Custom* make_from_value(const Value&); + private: // -- Members diff --git a/tests/geo/grid_reduced_gg.cc b/tests/geo/grid_reduced_gg.cc index e1ef8ca10..270d9b3c5 100644 --- a/tests/geo/grid_reduced_gg.cc +++ b/tests/geo/grid_reduced_gg.cc @@ -24,7 +24,7 @@ namespace eckit::geo::test { CASE("ReducedGaussianOctahedral") { SECTION("gridspec") { // different ways to instantiate the same grid (O2) - for (auto spec : { + for (const auto& spec : { spec::Custom({{"grid", "o2"}}), spec::Custom({{"N", 2}}), spec::Custom({{"pl", pl_type{20, 24, 24, 20}}}), @@ -34,8 +34,10 @@ CASE("ReducedGaussianOctahedral") { EXPECT_EQUAL(n1, 88); - spec.set("south", 0); - std::unique_ptr grid2(GridFactory::build(spec)); + spec::Custom hemisphere(spec.container()); + hemisphere.set("south", 0); + + std::unique_ptr grid2(GridFactory::build(hemisphere)); auto n2 = grid2->size(); EXPECT_EQUAL(n2, n1 / 2); @@ -102,20 +104,20 @@ CASE("ReducedGaussianOctahedral") { SECTION("crop") { - spec::Custom spec({{"grid", "o2"}}); - std::unique_ptr grid1(GridFactory::build(spec)); + spec::Custom a({{"grid", "o2"}}); + std::unique_ptr grid1(GridFactory::build(a)); auto n1 = grid1->size(); EXPECT_EQUAL(n1, 88); - spec.set("south", 0.); - std::unique_ptr grid2(GridFactory::build(spec)); + a.set("south", 0.); + std::unique_ptr grid2(GridFactory::build(a)); auto n2 = grid2->size(); EXPECT_EQUAL(n2, n1 / 2); - spec = spec::Custom{{{"grid", "o2"}, {"west", -180}}}; - std::unique_ptr grid3(GridFactory::build(spec)); + spec::Custom b{{{"grid", "o2"}, {"west", -180}}}; + std::unique_ptr grid3(GridFactory::build(b)); auto n3 = grid3->size(); EXPECT_EQUAL(n3, n1); diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index fc9a37295..0aab0496e 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -74,20 +74,20 @@ CASE("RegularGaussian") { SECTION("crop") { - spec::Custom spec({{"grid", "f2"}}); - std::unique_ptr grid1(GridFactory::build(spec)); + spec::Custom a({{"grid", "f2"}}); + std::unique_ptr grid1(GridFactory::build(a)); auto n1 = grid1->size(); EXPECT_EQUAL(n1, 32); - spec.set("south", 0.); - std::unique_ptr grid2(GridFactory::build(spec)); + a.set("south", 0.); + std::unique_ptr grid2(GridFactory::build(a)); auto n2 = grid2->size(); EXPECT_EQUAL(n2, n1 / 2); - spec = spec::Custom{{{"grid", "f2"}, {"west", -180}}}; - std::unique_ptr grid3(GridFactory::build(spec)); + spec::Custom b{{{"grid", "f2"}, {"west", -180}}}; + std::unique_ptr grid3(GridFactory::build(b)); auto n3 = grid3->size(); EXPECT_EQUAL(n3, n1); @@ -105,8 +105,8 @@ CASE("RegularGaussian") { EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj - spec.set("east", -1.); - std::unique_ptr grid5(GridFactory::build(spec)); + b.set("east", -1.); + std::unique_ptr grid5(GridFactory::build(b)); auto n5 = grid5->size(); EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 5b0d72ea8..e484449ce 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -85,10 +85,10 @@ CASE("Spec <- Custom") { EXPECT(a.get(key, value_as_long) && value_as_long == static_cast(one)); EXPECT(a.get(key, value_as_size_t) && value_as_size_t == static_cast(one)); - EXPECT_EQUAL(a.get_string(key), std::to_string(1)); + EXPECT(a.get_string(key) == std::to_string(1)); } else { - EXPECT_EQUAL(a.get_string(key), std::to_string(1.)); + EXPECT(a.get_string(key) == std::to_string(1.)); } } } @@ -139,26 +139,26 @@ CASE("Spec <- Custom") { EXPECT(c.get_string("foo") == std::to_string(two)); c.set("bar", one); - EXPECT_EQUAL(c.get_int("bar"), one); + EXPECT(c.get_int("bar") == one); EXPECT(::eckit::types::is_approximately_equal(c.get_double("bar"), static_cast(one))); EXPECT(c.get_string("bar") == "1"); c.set("foo", three); - EXPECT_EQUAL(c.get_string("foo"), three); + EXPECT(c.get_string("foo") == three); - spec::Custom d(c); + spec::Custom d(c.container()); EXPECT(d.has("foo")); - EXPECT_EQUAL(d.get_string("foo"), three); + EXPECT(d.get_string("foo") == three); EXPECT_THROWS_AS(d.get_int("foo"), SpecNotFound); // cannot access as int EXPECT_THROWS_AS(d.get_double("foo"), SpecNotFound); // cannot access as real d.set("foo", one); - EXPECT_EQUAL(d.get_int("foo"), one); + EXPECT(d.get_int("foo") == one); - spec::Custom e(d); + spec::Custom e(d.container()); ASSERT(e.has("foo")); ASSERT(e.has("bar")); @@ -229,16 +229,16 @@ CASE("Spec <- Layered") { b.unhide("foo"); ASSERT(b.has("foo")); - EXPECT_EQUAL(a.get_int("foo"), one); + EXPECT(a.get_int("foo") == one); auto value = b.get_int("foo"); - EXPECT_EQUAL(value, one); + EXPECT(value == one); } CASE("spec") { SECTION("user -> type") { - using C = spec::Custom; + using C = spec::Custom::container_type; using v = std::vector; static const C BAD; @@ -291,21 +291,24 @@ CASE("spec") { C()}, }; - for (const auto& [user, gridspec] : tests) { - Log::info() << user << " -> " << gridspec << std::endl; + for (const auto& [user, ref] : tests) { + spec::Custom userspec(user); + spec::Custom refspec(ref); + + Log::info() << userspec << " -> " << refspec << std::endl; try { - std::unique_ptr spec(GridFactory::make_spec(user)); + std::unique_ptr spec(GridFactory::make_spec(userspec)); EXPECT(spec); std::unique_ptr grid(GridFactory::build(*spec)); EXPECT(grid); } catch (const SpecNotFound& e) { - EXPECT(gridspec.empty() /*BAD*/); + EXPECT(refspec.empty() /*BAD*/); } catch (const BadParameter& e) { - EXPECT(gridspec.empty() /*BAD*/); + EXPECT(refspec.empty() /*BAD*/); } } } From db50ee26ab2dc1e8c91d2d75f6551e9b15b3faeb Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 21 May 2024 14:20:59 +0100 Subject: [PATCH 651/737] Fixes --- src/eckit/geo/GreatCircle.cc | 2 +- src/eckit/geo/geometry/Sphere.cc | 2 +- src/eckit/geo/util/sincos.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/eckit/geo/GreatCircle.cc b/src/eckit/geo/GreatCircle.cc index 2f9a18fb1..ead1b10e0 100644 --- a/src/eckit/geo/GreatCircle.cc +++ b/src/eckit/geo/GreatCircle.cc @@ -120,7 +120,7 @@ bool GreatCircle::crossesPoles() const { std::pair GreatCircle::calculate_course(const PointLonLat& A, const PointLonLat& B) { - const util::sincos_t dl(util::DEGREE_TO_RADIAN * (A.lon - B.lon)); + const util::sincos_t dl(util::DEGREE_TO_RADIAN * (B.lon - A.lon)); const util::sincos_t scA(util::DEGREE_TO_RADIAN * A.lat); const util::sincos_t scB(util::DEGREE_TO_RADIAN * B.lat); diff --git a/src/eckit/geo/geometry/Sphere.cc b/src/eckit/geo/geometry/Sphere.cc index 016dc09b5..3def214b9 100644 --- a/src/eckit/geo/geometry/Sphere.cc +++ b/src/eckit/geo/geometry/Sphere.cc @@ -112,7 +112,7 @@ double Sphere::area(double radius, const area::BoundingBox& bbox) { ASSERT(radius > 0.); // Set longitude and latitude fractions - auto lonf = bbox.isPeriodicWestEast() ? 1. : (bbox.west - bbox.east) / PointLonLat::GLOBE; + auto lonf = bbox.isPeriodicWestEast() ? 1. : (bbox.east - bbox.west) / PointLonLat::GLOBE; ASSERT(0. <= lonf && lonf <= 1.); auto sn = std::sin(util::DEGREE_TO_RADIAN * bbox.north); diff --git a/src/eckit/geo/util/sincos.h b/src/eckit/geo/util/sincos.h index 6fe51cf6e..ec7cc9eb8 100644 --- a/src/eckit/geo/util/sincos.h +++ b/src/eckit/geo/util/sincos.h @@ -20,7 +20,7 @@ namespace eckit::geo::util { struct sincos_t final : std::array { - explicit sincos_t(value_type r) : array{std::sin(r), std::sqrt(1. - std::sin(r) * std::sin(r))} {} + explicit sincos_t(value_type r) : array{std::sin(r), std::cos(r)} {} const value_type& sin = array::operator[](0); const value_type& cos = array::operator[](1); From 8e68e66d323dd5bbae0c3949fd2aebddd71962a0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 21 May 2024 14:21:05 +0100 Subject: [PATCH 652/737] Testing --- src/eckit/geo/GreatCircle.cc | 8 ++++---- src/eckit/geo/GreatCircle.h | 6 ++---- src/eckit/geo/geometry/Sphere.cc | 5 ++--- tests/geo/great_circle.cc | 14 +++++++++----- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/eckit/geo/GreatCircle.cc b/src/eckit/geo/GreatCircle.cc index ead1b10e0..7b37edc73 100644 --- a/src/eckit/geo/GreatCircle.cc +++ b/src/eckit/geo/GreatCircle.cc @@ -119,10 +119,10 @@ bool GreatCircle::crossesPoles() const { } -std::pair GreatCircle::calculate_course(const PointLonLat& A, const PointLonLat& B) { - const util::sincos_t dl(util::DEGREE_TO_RADIAN * (B.lon - A.lon)); - const util::sincos_t scA(util::DEGREE_TO_RADIAN * A.lat); - const util::sincos_t scB(util::DEGREE_TO_RADIAN * B.lat); +std::pair GreatCircle::course() const { + const util::sincos_t dl(util::DEGREE_TO_RADIAN * (B_.lon - A_.lon)); + const util::sincos_t scA(util::DEGREE_TO_RADIAN * A_.lat); + const util::sincos_t scB(util::DEGREE_TO_RADIAN * B_.lat); return {util::RADIAN_TO_DEGREE * std::atan2(scB.cos * dl.sin, scA.cos * scB.sin - scA.sin * scB.cos * dl.cos), util::RADIAN_TO_DEGREE * std::atan2(scA.cos * dl.sin, -scB.cos * scA.sin + scB.sin * scA.cos * dl.cos)}; diff --git a/src/eckit/geo/GreatCircle.h b/src/eckit/geo/GreatCircle.h index 5a7a24ad9..fed7e941b 100644 --- a/src/eckit/geo/GreatCircle.h +++ b/src/eckit/geo/GreatCircle.h @@ -31,9 +31,7 @@ class GreatCircle { /// Great circle longitude given latitude, see http://www.edwilliams.org/avform.htm#Par std::vector longitude(double lat) const; - // Calculate great circle course between two points - std::pair course(const PointLonLat& A, const PointLonLat& B) { return calculate_course(A_, B_); } - + /// If great circle crosses the poles (meridian/anti-meridian) bool crossesPoles() const; /** @@ -45,7 +43,7 @@ class GreatCircle { * * @ref https://en.wikipedia.org/wiki/Great-circle_navigation */ - static std::pair calculate_course(const PointLonLat&, const PointLonLat&); + std::pair course() const; private: const PointLonLat A_; diff --git a/src/eckit/geo/geometry/Sphere.cc b/src/eckit/geo/geometry/Sphere.cc index 3def214b9..7eb89c320 100644 --- a/src/eckit/geo/geometry/Sphere.cc +++ b/src/eckit/geo/geometry/Sphere.cc @@ -148,13 +148,12 @@ Point3 Sphere::convertSphericalToCartesian(double radius, const PointLonLat& P, * See https://en.wikipedia.org/wiki/Reference_ellipsoid#Coordinates * numerical conditioning for both ϕ (poles) and λ (Greenwich/Date Line). * - * cos α = sqrt( 1 - sin^2 α) is better conditioned than explicit cos α, and + * cos φ = sqrt( 1 - sin^2 φ) is better conditioned than explicit cos φ, and * coupled with λ in [-180°, 180°[ the accuracy of the trigonometric * functions is the same (before converting/multiplying its angle argument * to radian) and explicitly chosing -180° over 180° for longitude. * - * These three conditionings combined project very accurately to the sphere - * poles and quadrants. + * These conditionings combined project accurately to sphere poles and quadrants. */ const auto Q = PointLonLat::make(P.lon, P.lat, -180.); diff --git a/tests/geo/great_circle.cc b/tests/geo/great_circle.cc index 6da020776..283f4da2f 100644 --- a/tests/geo/great_circle.cc +++ b/tests/geo/great_circle.cc @@ -25,6 +25,10 @@ namespace eckit::geo::test { +const PointLonLat VALPARAISO(-71.6, -33.); +const PointLonLat SHANGHAI(121.8, 31.4); + + CASE("great circle intersections") { using types::is_approximately_equal; using types::is_approximately_greater_or_equal; @@ -63,9 +67,7 @@ CASE("great circle intersections") { SECTION("example intersection with meridian and parallel") { // latitude at Valparaíso-Shanghai mid-point - const PointLonLat P1(-71.6, -33.); - const PointLonLat P2(121.8, 31.4); - GreatCircle gc(P1, P2); + GreatCircle gc(VALPARAISO, SHANGHAI); const PointLonLat mid(-159.18, -6.81); @@ -206,14 +208,16 @@ CASE("great circle intersections") { CASE("great circle course") { SECTION("Valparaíso-Shanghai") { - const auto [course1, course2] = GreatCircle::calculate_course({-71.6, -33.}, {121.8, 31.4}); + GreatCircle gc(VALPARAISO, SHANGHAI); + const auto [course1, course2] = gc.course(); EXPECT_APPROX(-94.41, course1, 0.01); EXPECT_APPROX(-78.42, course2, 0.01); } SECTION("polar") { - const auto [course3, course4] = GreatCircle::calculate_course({0., 89.}, {180., 89.}); + GreatCircle gc({0., 89.}, {180., 89.}); + const auto [course3, course4] = gc.course(); EXPECT_APPROX(0., course3, 1.e-14); EXPECT_APPROX(180., std::abs(course4), 1.e-14); From 6b760a8a75e1f90c591c9b2e9691b9895b8a252b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 22 May 2024 09:48:48 +0100 Subject: [PATCH 653/737] Testing --- src/eckit/geo/Cache.h | 2 +- src/eckit/geo/etc/Grid.cc | 3 +- tests/geo/CMakeLists.txt | 2 +- .../{figure_sphere.cc => geometry_sphere.cc} | 0 tests/geo/spec.cc | 73 ++++++++++++++++++- 5 files changed, 75 insertions(+), 5 deletions(-) rename tests/geo/{figure_sphere.cc => geometry_sphere.cc} (100%) diff --git a/src/eckit/geo/Cache.h b/src/eckit/geo/Cache.h index 05cc72928..165edc597 100644 --- a/src/eckit/geo/Cache.h +++ b/src/eckit/geo/Cache.h @@ -48,7 +48,7 @@ class CacheT final : private Cache { struct has_footprint : std::false_type {}; template - struct has_footprint>> : std::true_type{}; + struct has_footprint>> : std::true_type {}; template static inline constexpr bool has_footprint_v = has_footprint::value; diff --git a/src/eckit/geo/etc/Grid.cc b/src/eckit/geo/etc/Grid.cc index 4d42fb03c..c712ef509 100644 --- a/src/eckit/geo/etc/Grid.cc +++ b/src/eckit/geo/etc/Grid.cc @@ -31,8 +31,7 @@ const Grid& Grid::instance() { Grid::Grid(const std::vector& paths) { - auto* custom = new spec::Custom; - spec_.reset(custom); + spec_ = std::make_unique(); for (const auto& path : paths) { if (path.exists()) { diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 030db62b8..e0ebd3bf4 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -2,7 +2,7 @@ foreach(_test area_boundingbox area_polygon cache - figure_sphere + geometry_sphere great_circle grid grid_healpix diff --git a/tests/geo/figure_sphere.cc b/tests/geo/geometry_sphere.cc similarity index 100% rename from tests/geo/figure_sphere.cc rename to tests/geo/geometry_sphere.cc diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index e484449ce..c01ba7c83 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -11,6 +11,7 @@ #include +#include #include #include "eckit/geo/Grid.h" @@ -25,6 +26,76 @@ namespace eckit::geo::test { +template +struct is_vector : std::false_type {}; + + +template +struct is_vector> : std::true_type {}; + + +template +constexpr bool is_vector_v = is_vector::value; + + +template +void test_t() { + T a; + T b; + T c; + + if constexpr (std::is_same_v>) { + a = b = {"1", "2", "3"}; + c = {"7", "8", "9", "10"}; + } + else if constexpr (std::is_same_v) { + a = b = "1"; + c = "7"; + } + else if constexpr (is_vector_v) { + a = b = {1, 2, 3}; + c = {7, 8, 9, 10}; + } + else { + a = b = 1; + c = 7; + } + + EXPECT_NOT(a != b); + EXPECT(a == b); + EXPECT_NOT(a < b); + EXPECT(a <= b); + EXPECT_NOT(a > b); + EXPECT(a >= b); + + EXPECT(a != c); + EXPECT_NOT(a == c); + EXPECT(a < c); + EXPECT(a <= c); + EXPECT_NOT(a > c); + EXPECT_NOT(a >= c); +} + + +CASE("Custom::value_type") { + test_t(); + // test_t(); + test_t(); + test_t(); + test_t(); + test_t(); + test_t(); + test_t(); + test_t>(); + test_t>(); + test_t>(); + test_t>(); + test_t>(); + test_t>(); + test_t>(); +} + + CASE("Spec <- Custom") { constexpr int zero = 0; constexpr int one = 1; @@ -315,7 +386,7 @@ CASE("spec") { SECTION("grid: name -> spec -> grid: name") { - for (const std::string name : {"LAEA-EFAS-5km", "SMUFF-OPERA-2km"}) { + for (const std::string& name : {"LAEA-EFAS-5km", "SMUFF-OPERA-2km"}) { std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", name}}))); EXPECT(grid); From 39ab0cb499800d70801a5ab4a1ae28b34f7e09b2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 22 May 2024 09:52:41 +0100 Subject: [PATCH 654/737] Fixes --- src/eckit/geo/spec/Custom.cc | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index f2a79c121..6eee7b270 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -185,18 +185,24 @@ Custom* Custom::make_from_value(const Value& value) { bool Custom::operator==(const Custom& other) const { - auto custom_value_equal = [](const auto& a, const auto& b) -> bool { - if constexpr (std::is_same_v) { - return a == b; - } - else { - return false; - } + auto custom_value_equal + = [](const Custom& ca, const Custom& cb, const Custom::key_type& name, const auto& type_instance) -> bool { + auto a = type_instance; + auto b = type_instance; + return ca.get(name, a) && cb.get(name, b) && a == b; }; + // check every local key exists in other and is convertible to an equal value return std::all_of(map_.begin(), map_.end(), [&](const auto& _a) { - auto _b = other.map_.find(_a.first); - return _b != other.map_.end() && custom_value_equal(_a.second, _b->second); + const auto& name = _a.first; + auto _b = other.map_.find(name); + return _b != other.map_.end() + && (custom_value_equal(*this, other, name, long{}) + || custom_value_equal(*this, other, name, std::vector{}) + || custom_value_equal(*this, other, name, double{}) + || custom_value_equal(*this, other, name, std::vector{}) + || custom_value_equal(*this, other, name, std::string{}) + || custom_value_equal(*this, other, name, std::vector{})); }); } From fd0b51433e3f576bcba38739e4105c98cd2d9f1c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 22 May 2024 16:10:40 +0100 Subject: [PATCH 655/737] eckit::geo::Figure --- src/eckit/geo/CMakeLists.txt | 6 +- src/eckit/geo/Figure.cc | 15 ++- src/eckit/geo/Figure.h | 10 ++ src/eckit/geo/Projection.cc | 9 ++ src/eckit/geo/Projection.h | 13 ++- src/eckit/geo/{geometry => figure}/Earth.h | 10 +- src/eckit/geo/figure/OblateSpheroid.cc | 2 +- src/eckit/geo/figure/OblateSpheroid.h | 2 + src/eckit/geo/figure/Sphere.h | 4 +- src/eckit/geo/projection/Composer.cc | 11 +- src/eckit/geo/projection/LonLatToXYZ.cc | 71 ------------ .../geo/projection/ProjectionOnFigure.cc | 15 +-- .../geo/projection/figure/LonLatToXYZ.cc | 75 +++++++++++++ .../geo/projection/{ => figure}/LonLatToXYZ.h | 14 ++- tests/geo/projection_ll_to_xyz.cc | 105 ++++++++++++------ 15 files changed, 220 insertions(+), 142 deletions(-) rename src/eckit/geo/{geometry => figure}/Earth.h (77%) delete mode 100644 src/eckit/geo/projection/LonLatToXYZ.cc create mode 100644 src/eckit/geo/projection/figure/LonLatToXYZ.cc rename src/eckit/geo/projection/{ => figure}/LonLatToXYZ.h (84%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 32f6648d8..c16d45ca4 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -40,11 +40,11 @@ list(APPEND eckit_geo_srcs area/BoundingBox.h etc/Grid.cc etc/Grid.h + figure/Earth.h figure/OblateSpheroid.cc figure/OblateSpheroid.h figure/Sphere.cc figure/Sphere.h - geometry/Earth.h geometry/OblateSpheroid.cc geometry/OblateSpheroid.h geometry/Sphere.cc @@ -77,8 +77,6 @@ list(APPEND eckit_geo_srcs projection/Composer.h projection/LonLatToXY.cc projection/LonLatToXY.h - projection/LonLatToXYZ.cc - projection/LonLatToXYZ.h projection/None.cc projection/None.h projection/ProjectionOnFigure.cc @@ -93,6 +91,8 @@ list(APPEND eckit_geo_srcs projection/figure/LambertAzimuthalEqualArea.h projection/figure/LambertConformalConic.cc projection/figure/LambertConformalConic.h + projection/figure/LonLatToXYZ.cc + projection/figure/LonLatToXYZ.h projection/figure/Mercator.cc projection/figure/Mercator.h projection/figure/PolarStereographic.cc diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc index 846ad4045..27989ca59 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/geo/Figure.cc @@ -12,10 +12,9 @@ #include "eckit/geo/Figure.h" -#include - #include "eckit/exception/Exceptions.h" #include "eckit/geo/geometry/OblateSpheroid.h" +#include "eckit/geo/spec/Custom.h" namespace eckit::geo { @@ -36,9 +35,21 @@ double Figure::b() const { } +std::string Figure::spec() const { + spec::Custom gridspec; + spec(gridspec); + return gridspec.str(); +} + + double Figure::eccentricity() const { return geometry::OblateSpheroid::eccentricity(a(), b()); } +void Figure::spec(spec::Custom&) const { + NOTIMP; +} + + } // namespace eckit::geo diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index 833062964..bf83a5889 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -22,6 +22,9 @@ namespace eckit::geo { namespace area { class BoundingBox; } +namespace spec { +class Custom; +} class Spec; } // namespace eckit::geo @@ -64,7 +67,14 @@ class Figure { virtual double a() const; virtual double b() const; + virtual std::string spec() const; + double eccentricity() const; + +private: + // -- Methods + + virtual void spec(spec::Custom&) const; }; diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index 29080179b..0231f6750 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -14,6 +14,8 @@ #include +#include "eckit/geo/spec/Custom.h" + namespace eckit::geo { @@ -25,4 +27,11 @@ ProjectionProblem::ProjectionProblem(const std::string& what, const CodeLocation }; +std::string Projection::spec() const { + spec::Custom gridspec; + spec(gridspec); + return gridspec.str(); +} + + } // namespace eckit::geo diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 3378378c2..021eabf5f 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -61,12 +61,19 @@ class Projection { // -- Methods - static std::string className() { return "projection"; } - virtual Point fwd(const Point&) const = 0; virtual Point inv(const Point&) const = 0; - virtual void spec(spec::Custom&) const = 0; + std::string spec() const; + + // -- Class methods + + static std::string className() { return "projection"; } + +private: + // -- Methods + + virtual void spec(spec::Custom&) const { NOTIMP; } }; diff --git a/src/eckit/geo/geometry/Earth.h b/src/eckit/geo/figure/Earth.h similarity index 77% rename from src/eckit/geo/geometry/Earth.h rename to src/eckit/geo/figure/Earth.h index 2b08c332c..7bb4584ad 100644 --- a/src/eckit/geo/geometry/Earth.h +++ b/src/eckit/geo/figure/Earth.h @@ -12,10 +12,10 @@ #pragma once -#include "eckit/geo/geometry/SphereT.h" +#include "eckit/geo/figure/Sphere.h" -namespace eckit::geo::geometry { +namespace eckit::geo::figure { struct DatumIFS { @@ -33,7 +33,9 @@ struct DatumWGS84SemiMajorAxis { }; -using Earth = SphereT; +struct Earth final : public Sphere { + explicit Earth() : Sphere(DatumIFS::radius()) {} +}; -} // namespace eckit::geo::geometry +} // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/OblateSpheroid.cc b/src/eckit/geo/figure/OblateSpheroid.cc index e14e9a39b..6287fd8e1 100644 --- a/src/eckit/geo/figure/OblateSpheroid.cc +++ b/src/eckit/geo/figure/OblateSpheroid.cc @@ -21,7 +21,7 @@ namespace eckit::geo::figure { OblateSpheroid::OblateSpheroid(double a, double b) : a_(a), b_(b) { - ASSERT_MSG(0. < b && b_ <= a_, "OblateSpheroid requires 0 < b <= a"); + ASSERT_MSG(types::is_strictly_greater(b, 0.) && b_ <= a_, "OblateSpheroid requires 0 < b <= a"); } diff --git a/src/eckit/geo/figure/OblateSpheroid.h b/src/eckit/geo/figure/OblateSpheroid.h index 8876c37e1..8aa1af9a0 100644 --- a/src/eckit/geo/figure/OblateSpheroid.h +++ b/src/eckit/geo/figure/OblateSpheroid.h @@ -31,6 +31,8 @@ class OblateSpheroid final : public Figure { double a() const override { return a_; } double b() const override { return b_; } + void spec(spec::Custom&) const override {} + private: // -- Members diff --git a/src/eckit/geo/figure/Sphere.h b/src/eckit/geo/figure/Sphere.h index fc165d110..8c6772af3 100644 --- a/src/eckit/geo/figure/Sphere.h +++ b/src/eckit/geo/figure/Sphere.h @@ -18,7 +18,7 @@ namespace eckit::geo::figure { -class Sphere final : public Figure { +class Sphere : public Figure { public: // -- Constructors @@ -31,6 +31,8 @@ class Sphere final : public Figure { double a() const override { return R_; } double b() const override { return R_; } + void spec(spec::Custom&) const override {} + private: // -- Members diff --git a/src/eckit/geo/projection/Composer.cc b/src/eckit/geo/projection/Composer.cc index b4eb38f22..106cf687c 100644 --- a/src/eckit/geo/projection/Composer.cc +++ b/src/eckit/geo/projection/Composer.cc @@ -12,8 +12,10 @@ #include "eckit/geo/projection/Composer.h" +#include + #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Spec.h" +#include "eckit/geo/spec/Custom.h" namespace eckit::geo::projection { @@ -56,7 +58,12 @@ std::vector Composer::inv_points(const Point& p) const { void Composer::spec(spec::Custom& custom) const { - NOTIMP; + std::vector specs; + for (const auto* proj : *this) { + specs.emplace_back(proj->spec()); + } + + custom.set("projections", specs); } diff --git a/src/eckit/geo/projection/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc deleted file mode 100644 index 4559b28b2..000000000 --- a/src/eckit/geo/projection/LonLatToXYZ.cc +++ /dev/null @@ -1,71 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/projection/LonLatToXYZ.h" - -#include "eckit/geo/geometry/OblateSpheroid.h" -#include "eckit/geo/geometry/Sphere.h" -#include "eckit/geo/spec/Custom.h" -#include "eckit/types/FloatCompare.h" - - -namespace eckit::geo::projection { - - -static ProjectionBuilder PROJECTION("ll_to_xyz"); - - -LonLatToXYZ::LonLatToXYZ(double a, double b) { - ASSERT_MSG(types::is_strictly_greater(b, 0.) && b <= a, "LonLatToXYZ requires 0 < b <= a"); - - struct LonLatToSphereXYZ final : Implementation { - using S = geometry::Sphere; - const double R_; - - explicit LonLatToSphereXYZ(double R) : R_(R) {} - Point3 operator()(const PointLonLat& p) const override { return S::convertSphericalToCartesian(R_, p, 0.); } - PointLonLat operator()(const Point3& q) const override { return S::convertCartesianToSpherical(R_, q); } - void spec(spec::Custom& custom) const override { custom.set("R", R_); } - }; - - struct LonLatToSpheroidXYZ final : Implementation { - using S = geometry::OblateSpheroid; - const double a_; - const double b_; - - explicit LonLatToSpheroidXYZ(double a, double b) : a_(a), b_(b) {} - Point3 operator()(const PointLonLat& p) const override { return S::convertSphericalToCartesian(a_, b_, p, 0.); } - PointLonLat operator()(const Point3& q) const override { NOTIMP; } - void spec(spec::Custom& custom) const override { - custom.set("a", a_); - custom.set("b", b_); - } - }; - - impl_.reset(types::is_approximately_equal(a, b) ? static_cast(new LonLatToSphereXYZ(a)) - : new LonLatToSpheroidXYZ(a, b)); -} - - -LonLatToXYZ::LonLatToXYZ(double R) : LonLatToXYZ(R, R) {} - - -LonLatToXYZ::LonLatToXYZ(const Spec& spec) : - LonLatToXYZ(spec.get_double("a", spec.get_double("R", 1.)), spec.get_double("b", spec.get_double("R", 1.))) {} - - -void LonLatToXYZ::spec(spec::Custom& custom) const { - impl_->spec(custom); -} - - -} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/ProjectionOnFigure.cc b/src/eckit/geo/projection/ProjectionOnFigure.cc index 0f479363c..9f7cf4a50 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.cc +++ b/src/eckit/geo/projection/ProjectionOnFigure.cc @@ -13,7 +13,7 @@ #include "eckit/geo/projection/ProjectionOnFigure.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geo/geometry/Earth.h" +#include "eckit/geo/figure/Earth.h" #include "eckit/geo/spec/Custom.h" #include "eckit/types/FloatCompare.h" @@ -21,20 +21,11 @@ namespace eckit::geo::projection { -// FIXME refactor figures into a single hierarchy -struct Earth final : Figure { - Earth() = default; - - double R() const override { return geometry::Earth::radius(); } - double a() const override { return geometry::Earth::radius(); } - double b() const override { return geometry::Earth::radius(); } -}; - - ProjectionOnFigure::ProjectionOnFigure(const Spec&) : ProjectionOnFigure() {} -ProjectionOnFigure::ProjectionOnFigure(Figure* figure_ptr) : figure_(figure_ptr != nullptr ? figure_ptr : new Earth) { +ProjectionOnFigure::ProjectionOnFigure(Figure* figure_ptr) : + figure_(figure_ptr != nullptr ? figure_ptr : new figure::Earth) { ASSERT(figure_); } diff --git a/src/eckit/geo/projection/figure/LonLatToXYZ.cc b/src/eckit/geo/projection/figure/LonLatToXYZ.cc new file mode 100644 index 000000000..2b334acf2 --- /dev/null +++ b/src/eckit/geo/projection/figure/LonLatToXYZ.cc @@ -0,0 +1,75 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/projection/figure/LonLatToXYZ.h" + +#include "eckit/geo/Spec.h" +#include "eckit/geo/figure/OblateSpheroid.h" +#include "eckit/geo/figure/Sphere.h" +#include "eckit/geo/geometry/OblateSpheroid.h" +#include "eckit/geo/geometry/Sphere.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::projection::figure { + + +static ProjectionBuilder PROJECTION("ll_to_xyz"); + + +LonLatToXYZ::LonLatToXYZ(Figure* figure_ptr) : ProjectionOnFigure(figure_ptr) { + struct LonLatToSphereXYZ final : Implementation { + const Figure& figure_; + + explicit LonLatToSphereXYZ(const Figure& figure) : figure_(figure) {} + Point3 operator()(const PointLonLat& p) const override { + return geometry::Sphere::convertSphericalToCartesian(figure_.R(), p, 0.); + } + PointLonLat operator()(const Point3& q) const override { + return geometry::Sphere::convertCartesianToSpherical(figure_.R(), q); + } + }; + + struct LonLatToSpheroidXYZ final : Implementation { + const Figure& figure_; + + explicit LonLatToSpheroidXYZ(const Figure& figure) : figure_(figure) {} + Point3 operator()(const PointLonLat& p) const override { + return geometry::OblateSpheroid::convertSphericalToCartesian(figure_.a(), figure_.b(), p, 0.); + } + PointLonLat operator()(const Point3& q) const override { NOTIMP; } + }; + + impl_.reset(types::is_approximately_equal(figure().eccentricity(), 0.) + ? static_cast(new LonLatToSphereXYZ(figure())) + : new LonLatToSpheroidXYZ(figure())); +} + + +LonLatToXYZ::LonLatToXYZ(double R) : LonLatToXYZ(R, R) {} + + +LonLatToXYZ::LonLatToXYZ(double a, double b) : + LonLatToXYZ(types::is_approximately_equal(a, b) ? static_cast(new geo::figure::Sphere(a)) + : new geo::figure::OblateSpheroid(a, b)) {} + + +LonLatToXYZ::LonLatToXYZ(const Spec& spec) : + LonLatToXYZ(FigureFactory::instance().get(spec.get_string("figure")).create(spec)) {} + + +void LonLatToXYZ::spec(spec::Custom& custom) const { + ProjectionOnFigure::spec(custom); +} + + +} // namespace eckit::geo::projection::figure diff --git a/src/eckit/geo/projection/LonLatToXYZ.h b/src/eckit/geo/projection/figure/LonLatToXYZ.h similarity index 84% rename from src/eckit/geo/projection/LonLatToXYZ.h rename to src/eckit/geo/projection/figure/LonLatToXYZ.h index 193cf8213..6692e9dd4 100644 --- a/src/eckit/geo/projection/LonLatToXYZ.h +++ b/src/eckit/geo/projection/figure/LonLatToXYZ.h @@ -14,19 +14,22 @@ #include -#include "eckit/geo/Projection.h" +#include "eckit/geo/projection/ProjectionOnFigure.h" -namespace eckit::geo::projection { +namespace eckit::geo::projection::figure { /// Calculate coordinates of a point on a sphere or spheroid, in [x, y, z] -class LonLatToXYZ final : public Projection { +class LonLatToXYZ final : public ProjectionOnFigure { public: // -- Constructors - LonLatToXYZ(double a, double b); + explicit LonLatToXYZ(Figure* = nullptr); + explicit LonLatToXYZ(double R); + explicit LonLatToXYZ(double a, double b); + explicit LonLatToXYZ(const Spec&); // -- Methods @@ -52,7 +55,6 @@ class LonLatToXYZ final : public Projection { virtual Point3 operator()(const PointLonLat&) const = 0; virtual PointLonLat operator()(const Point3&) const = 0; - virtual void spec(spec::Custom&) const = 0; }; // -- Members @@ -66,4 +68,4 @@ class LonLatToXYZ final : public Projection { }; -} // namespace eckit::geo::projection +} // namespace eckit::geo::projection::figure diff --git a/tests/geo/projection_ll_to_xyz.cc b/tests/geo/projection_ll_to_xyz.cc index 0245c4726..f5c76e20d 100644 --- a/tests/geo/projection_ll_to_xyz.cc +++ b/tests/geo/projection_ll_to_xyz.cc @@ -10,9 +10,10 @@ */ +#include #include -#include "eckit/geo/projection/LonLatToXYZ.h" +#include "eckit/geo/projection/figure/LonLatToXYZ.h" #include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" @@ -20,59 +21,89 @@ namespace eckit::geo::test { -using P = std::unique_ptr; - - CASE("projection: ll_to_xyz") { - Point p = PointLonLat{1, 1}; - P s1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"R", 1.}}))); - P s2(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 1.}}))); - P s3(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 0.5}}))); - - EXPECT(points_equal(p, s1->inv(s1->fwd(p)))); - EXPECT(points_equal(p, s2->inv(s2->fwd(p)))); - EXPECT(points_equal(s1->fwd(p), s2->fwd(p))); + using P = std::unique_ptr; - Point q = PointLonLat{1, 0}; + constexpr double R = 1.; + const auto L = R * std::sqrt(2.) / 2.; - EXPECT(points_equal(s1->fwd(q), s3->fwd(q))); - EXPECT(points_equal(s2->fwd(q), s3->fwd(q))); - - struct { + struct test_t { PointLonLat a; Point3 b; - } tests[] = { - {{0, 0}, {1, 0, 0}}, {{90, 0}, {0, 1, 0}}, {{180, 0}, {-1, 0, 0}}, {{270, 0}, {0, -1, 0}}, - {{0, -90}, {0, 0, -0.5}}, {{42, -90}, {0, 0, -0.5}}, {{0, 90}, {0, 0, 0.5}}, {{42, 90}, {0, 0, 0.5}}, }; - for (const auto& test : tests) { - EXPECT(points_equal(s3->fwd(test.a), test.b)); + test_t test_sphere[] = { + {{0, 0}, {R, 0, 0}}, // + {{90, 0}, {0, R, 0}}, // + {{180, 0}, {-R, 0, 0}}, // + {{270, 0}, {0, -R, 0}}, // + }; + + test_t test_oblate_spheroid[] = { + {{0, -90}, {0, 0, -0.5}}, // + {{42, -90}, {0, 0, -0.5}}, // + {{0, 90}, {0, 0, 0.5}}, // + {{42, 90}, {0, 0, 0.5}}, // + }; + + + SECTION("oblate/prolate spheroid") { + // oblate spheroid (supported) + EXPECT(P(new projection::figure::LonLatToXYZ(1., 0.5))); + + // problate spheroid (not supported) + EXPECT_THROWS(projection::figure::LonLatToXYZ(0.5, 1.)); } -} -CASE("projection: ll_to_xyz") { - const PointLonLat p(723., 1.); // <- FIXME + P to_xyz_1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"R", 1.}}))); + P to_xyz_2(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 1.}}))); + P to_xyz_3(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 0.5}}))); + + + SECTION("spec") { + auto x = to_xyz_1->spec(); + } + + + SECTION("") { + Point p = PointLonLat{1, 1}; - projection::LonLatToXYZ to_xyz_r(1.); + EXPECT(points_equal(p, to_xyz_1->inv(to_xyz_1->fwd(p)))); + EXPECT(points_equal(p, to_xyz_2->inv(to_xyz_2->fwd(p)))); + EXPECT(points_equal(to_xyz_1->fwd(p), to_xyz_2->fwd(p))); - auto q = to_xyz_r.fwd(p); - auto r = to_xyz_r.inv(q); - Log::info() << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; + Point q = PointLonLat{1, 0}; - EXPECT(points_equal(p, r)); + EXPECT(points_equal(to_xyz_1->fwd(q), to_xyz_3->fwd(q))); + EXPECT(points_equal(to_xyz_2->fwd(q), to_xyz_3->fwd(q))); - // oblate spheroid (supported) - projection::LonLatToXYZ to_xyz_ab(3., 2.); + for (const auto& test : test_sphere) { + EXPECT(points_equal(to_xyz_1->fwd(test.a), test.b)); + EXPECT(points_equal(to_xyz_2->fwd(test.a), test.b)); + EXPECT(points_equal(to_xyz_3->fwd(test.a), test.b)); + } - for (const auto& lon : {0., 90., 180., 270.}) { - PointLonLat p{lon, 0.}; - Log::info() << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_ab.fwd(p) << std::endl; + for (const auto& test : test_oblate_spheroid) { + EXPECT(points_equal(to_xyz_3->fwd(test.a), test.b)); + } } - // problate spheroid (not supported) - EXPECT_THROWS(projection::LonLatToXYZ(2., 3.)); + + SECTION("") { + const PointLonLat p(723., 1.); // <- FIXME + + auto q = to_xyz_1->fwd(p); + auto r = to_xyz_1->inv(q); + Log::info() << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; + + EXPECT(points_equal(p, r)); + + for (const auto& lon : {0., 90., 180., 270.}) { + PointLonLat p{lon, 0.}; + Log::info() << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_3->fwd(p) << std::endl; + } + } } From a1c629466c9ab78ea98605ff3f8f677179483568 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 22 May 2024 16:34:11 +0100 Subject: [PATCH 656/737] eckit::geo::Figure --- src/eckit/geo/Figure.cc | 44 +++++++++++++++++++ src/eckit/geo/Figure.h | 12 ++++- src/eckit/geo/figure/OblateSpheroid.cc | 8 +++- src/eckit/geo/figure/OblateSpheroid.h | 6 ++- src/eckit/geo/figure/Sphere.cc | 10 ++++- src/eckit/geo/figure/Sphere.h | 6 ++- .../geo/projection/figure/LonLatToXYZ.cc | 3 +- src/eckit/geo/projection/figure/Mercator.cc | 3 +- 8 files changed, 80 insertions(+), 12 deletions(-) diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc index 27989ca59..9374036a0 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/geo/Figure.cc @@ -12,14 +12,29 @@ #include "eckit/geo/Figure.h" +#include + #include "eckit/exception/Exceptions.h" +#include "eckit/geo/figure/OblateSpheroid.h" +#include "eckit/geo/figure/Sphere.h" #include "eckit/geo/geometry/OblateSpheroid.h" #include "eckit/geo/spec/Custom.h" +#include "eckit/geo/util/mutex.h" +#include "eckit/parser/YAMLParser.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo { +static util::recursive_mutex MUTEX; + + +class lock_type { + util::lock_guard lock_guard_{MUTEX}; +}; + + double Figure::R() const { NOTIMP; } @@ -52,4 +67,33 @@ void Figure::spec(spec::Custom&) const { } +FigureFactory& FigureFactory::instance() { + static FigureFactory obj; + return obj; +} + + +Figure* FigureFactory::make_from_string(const std::string& str) { + std::unique_ptr spec(spec::Custom::make_from_value(YAMLParser::decodeString(str))); + return instance().make_from_spec_(*spec); +} + + +Figure* FigureFactory::make_from_spec_(const Spec& spec) const { + lock_type lock; + + if (double a = 0., b = 0.; spec.get("a", a) && spec.get("b", b)) { + return types::is_approximately_equal(a, b) ? static_cast(new figure::Sphere(a)) + : new figure::OblateSpheroid(a, b); + } + + if (double R = 0.; spec.get("R", R)) { + return new figure::Sphere(R); + } + + Log::error() << "Figure: cannot build figure without 'R' or 'a', 'b'" << std::endl; + throw SpecNotFound("Figure: cannot build figure without 'R' or 'a', 'b'", Here()); +} + + } // namespace eckit::geo diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index bf83a5889..015d53561 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -12,6 +12,7 @@ #pragma once +#include #include #include "eckit/memory/Builder.h" @@ -78,7 +79,16 @@ class Figure { }; -using FigureFactory = Factory
; +struct FigureFactory { + [[nodiscard]] static Figure* build(const Spec& spec) { return instance().make_from_spec_(spec); } + [[nodiscard]] static Figure* make_from_string(const std::string&); + +private: + static FigureFactory& instance(); + + [[nodiscard]] Figure* make_from_spec_(const Spec&) const; +}; + template using FigureBuilder = ConcreteBuilderT1; diff --git a/src/eckit/geo/figure/OblateSpheroid.cc b/src/eckit/geo/figure/OblateSpheroid.cc index 6287fd8e1..1b5894e5d 100644 --- a/src/eckit/geo/figure/OblateSpheroid.cc +++ b/src/eckit/geo/figure/OblateSpheroid.cc @@ -13,7 +13,7 @@ #include "eckit/geo/figure/OblateSpheroid.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Spec.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/types/FloatCompare.h" @@ -34,4 +34,10 @@ double OblateSpheroid::R() const { } +void OblateSpheroid::spec(spec::Custom& custom) const { + custom.set("a", a_); + custom.set("b", b_); +} + + } // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/OblateSpheroid.h b/src/eckit/geo/figure/OblateSpheroid.h index 8aa1af9a0..11ac858bb 100644 --- a/src/eckit/geo/figure/OblateSpheroid.h +++ b/src/eckit/geo/figure/OblateSpheroid.h @@ -31,13 +31,15 @@ class OblateSpheroid final : public Figure { double a() const override { return a_; } double b() const override { return b_; } - void spec(spec::Custom&) const override {} - private: // -- Members const double a_; const double b_; + + // -- Overridden methods + + void spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/figure/Sphere.cc b/src/eckit/geo/figure/Sphere.cc index b85cd6f41..b644b713b 100644 --- a/src/eckit/geo/figure/Sphere.cc +++ b/src/eckit/geo/figure/Sphere.cc @@ -13,18 +13,24 @@ #include "eckit/geo/figure/Sphere.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Spec.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo::figure { Sphere::Sphere(double R) : R_(R) { - ASSERT_MSG(R_ > 0., "Sphere requires R > 0"); + ASSERT_MSG(types::is_strictly_greater(R_, 0.), "Sphere requires R > 0"); } Sphere::Sphere(const Spec& spec) : Sphere(spec.get_double("R")) {} +void Sphere::spec(spec::Custom& custom) const { + custom.set("R", R_); +} + + } // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/Sphere.h b/src/eckit/geo/figure/Sphere.h index 8c6772af3..68684c5d6 100644 --- a/src/eckit/geo/figure/Sphere.h +++ b/src/eckit/geo/figure/Sphere.h @@ -31,12 +31,14 @@ class Sphere : public Figure { double a() const override { return R_; } double b() const override { return R_; } - void spec(spec::Custom&) const override {} - private: // -- Members const double R_; + + // -- Overridden methods + + void spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/projection/figure/LonLatToXYZ.cc b/src/eckit/geo/projection/figure/LonLatToXYZ.cc index 2b334acf2..a8c17dd7e 100644 --- a/src/eckit/geo/projection/figure/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/figure/LonLatToXYZ.cc @@ -63,8 +63,7 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) : : new geo::figure::OblateSpheroid(a, b)) {} -LonLatToXYZ::LonLatToXYZ(const Spec& spec) : - LonLatToXYZ(FigureFactory::instance().get(spec.get_string("figure")).create(spec)) {} +LonLatToXYZ::LonLatToXYZ(const Spec& spec) : LonLatToXYZ(FigureFactory::build(spec)) {} void LonLatToXYZ::spec(spec::Custom& custom) const { diff --git a/src/eckit/geo/projection/figure/Mercator.cc b/src/eckit/geo/projection/figure/Mercator.cc index 74a2f1938..b121da332 100644 --- a/src/eckit/geo/projection/figure/Mercator.cc +++ b/src/eckit/geo/projection/figure/Mercator.cc @@ -65,8 +65,7 @@ Mercator::Mercator(PointLonLat centre, PointLonLat first, Figure* figure_ptr) : Mercator::Mercator(const Spec& spec) : Mercator({spec.get_double("lon_0"), spec.get_double("lat_ts")}, - {spec.get_double("first_lon"), spec.get_double("first_lat")}, - FigureFactory::instance().get(spec.get_string("figure")).create(spec)) {} + {spec.get_double("first_lon"), spec.get_double("first_lat")}, FigureFactory::build(spec)) {} double Mercator::calculate_phi(double t) const { From 92251d2fa2f8d8815b52f43ad5479a1ca5bc83cc Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 22 May 2024 16:53:58 +0100 Subject: [PATCH 657/737] Fixes --- src/eckit/geo/Point3.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eckit/geo/Point3.h b/src/eckit/geo/Point3.h index 4db3871c5..523c8df91 100644 --- a/src/eckit/geo/Point3.h +++ b/src/eckit/geo/Point3.h @@ -79,7 +79,7 @@ class Point3 final : protected std::array { // -- Friends friend std::ostream& operator<<(std::ostream& out, const Point3& p) { - return out << '{' << p.X << ", " << p.X << ", " << p.Z << '}'; + return out << '{' << p.X << ", " << p.Y << ", " << p.Z << '}'; } friend Point3 operator-(const Point3& p, const Point3& q) { return {p.X - q.X, p.Y - q.Y, p.Z - q.Z}; } From 9cac4e3e0ebbe84216c9e24a275b448e33dade4e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 22 May 2024 20:08:42 +0100 Subject: [PATCH 658/737] eckit::geo::Projection --- src/eckit/geo/Projection.h | 5 ++ tests/geo/projection_ll_to_xyz.cc | 124 +++++++++++++++++------------- 2 files changed, 77 insertions(+), 52 deletions(-) diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 021eabf5f..b4b59ccb4 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -74,6 +74,11 @@ class Projection { // -- Methods virtual void spec(spec::Custom&) const { NOTIMP; } + + // -- Friends + + friend bool operator==(const Projection& a, const Projection& b) { return a.spec() == b.spec(); } + friend bool operator!=(const Projection& a, const Projection& b) { return !(a == b); } }; diff --git a/tests/geo/projection_ll_to_xyz.cc b/tests/geo/projection_ll_to_xyz.cc index f5c76e20d..d6a63ff5c 100644 --- a/tests/geo/projection_ll_to_xyz.cc +++ b/tests/geo/projection_ll_to_xyz.cc @@ -22,86 +22,106 @@ namespace eckit::geo::test { CASE("projection: ll_to_xyz") { - using P = std::unique_ptr; - - constexpr double R = 1.; - const auto L = R * std::sqrt(2.) / 2.; + struct P : std::unique_ptr { + explicit P(Projection* ptr) : unique_ptr(ptr) { ASSERT(unique_ptr::operator bool()); } + }; struct test_t { PointLonLat a; Point3 b; }; - test_t test_sphere[] = { - {{0, 0}, {R, 0, 0}}, // - {{90, 0}, {0, R, 0}}, // - {{180, 0}, {-R, 0, 0}}, // - {{270, 0}, {0, -R, 0}}, // - }; + constexpr double R = 1.; + const auto L = R * std::sqrt(2.) / 2.; - test_t test_oblate_spheroid[] = { - {{0, -90}, {0, 0, -0.5}}, // - {{42, -90}, {0, 0, -0.5}}, // - {{0, 90}, {0, 0, 0.5}}, // - {{42, 90}, {0, 0, 0.5}}, // - }; + // spherical projections + P to_xyz_1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom{{"R", 1.}})); + P to_xyz_2(new projection::figure::LonLatToXYZ(1., 1.)); - SECTION("oblate/prolate spheroid") { - // oblate spheroid (supported) - EXPECT(P(new projection::figure::LonLatToXYZ(1., 0.5))); + EXPECT(*to_xyz_1 == *to_xyz_2); + EXPECT(*to_xyz_1 == projection::figure::LonLatToXYZ(1.)); - // problate spheroid (not supported) - EXPECT_THROWS(projection::figure::LonLatToXYZ(0.5, 1.)); - } + + // oblate spheroid projections + P to_xyz_3(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom{{"a", 1.}, {"b", 0.5}})); + P to_xyz_4(new projection::figure::LonLatToXYZ(1., 0.5)); + + EXPECT(*to_xyz_3 == *to_xyz_4); - P to_xyz_1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"R", 1.}}))); - P to_xyz_2(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 1.}}))); - P to_xyz_3(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom({{"a", 1.}, {"b", 0.5}}))); + // problate spheroid (not supported) + EXPECT_THROWS(projection::figure::LonLatToXYZ(0.5, 1.)); SECTION("spec") { - auto x = to_xyz_1->spec(); + EXPECT(to_xyz_1->spec() == R"({"r":1})"); + EXPECT(to_xyz_2->spec() == R"({"r":1})"); + EXPECT(to_xyz_3->spec() == R"({"a":1,"b":0.5})"); + EXPECT(to_xyz_4->spec() == R"({"a":1,"b":0.5})"); } - SECTION("") { - Point p = PointLonLat{1, 1}; + SECTION("roundtrip") { + for (const auto& p : { + PointLonLat{1, 1}, + PointLonLat{1, 0}, + PointLonLat(723., 1.), + }) { + EXPECT(points_equal(p, to_xyz_1->inv(to_xyz_1->fwd(p)))); + EXPECT(points_equal(p, to_xyz_2->inv(to_xyz_2->fwd(p)))); - EXPECT(points_equal(p, to_xyz_1->inv(to_xyz_1->fwd(p)))); - EXPECT(points_equal(p, to_xyz_2->inv(to_xyz_2->fwd(p)))); - EXPECT(points_equal(to_xyz_1->fwd(p), to_xyz_2->fwd(p))); + EXPECT(points_equal(to_xyz_1->fwd(p), to_xyz_2->fwd(p))); + EXPECT(points_equal(to_xyz_2->fwd(p), to_xyz_1->fwd(p))); - Point q = PointLonLat{1, 0}; + if (p.lat == 0) { + auto q = to_xyz_3->fwd(p); + EXPECT(points_equal(to_xyz_1->fwd(p), q)); + EXPECT(points_equal(to_xyz_2->inv(q), p)); + } + } + } - EXPECT(points_equal(to_xyz_1->fwd(q), to_xyz_3->fwd(q))); - EXPECT(points_equal(to_xyz_2->fwd(q), to_xyz_3->fwd(q))); - for (const auto& test : test_sphere) { + SECTION("sphere (ll -> xyz, xyz -> ll)") { + for (const auto& test : { + test_t{{0, 90}, {0, 0, R}}, // + {{0, -90}, {0, 0, -R}}, // + {{0, 0}, {R, 0, 0}}, // + {{-360, 0}, {R, 0, 0}}, // + {{90, 0}, {0, R, 0}}, // + {{-270, 0}, {0, R, 0}}, // + {{180, 0}, {-R, 0, 0}}, // + {{-180, 0}, {-R, 0, 0}}, // + {{270, 0}, {0, -R, 0}}, // + {{-90, 0}, {0, -R, 0}}, // + {{45, 0}, {L, L, 0}}, // + {{-315, 0}, {L, L, 0}}, // + {{135, 0}, {-L, L, 0}}, // + {{-225, 0}, {-L, L, 0}}, // + {{225, 0}, {-L, -L, 0}}, // + {{-135, 0}, {-L, -L, 0}}, // + {{315, 0}, {L, -L, 0}}, // + {{-45, 0}, {L, -L, 0}}, // + }) { EXPECT(points_equal(to_xyz_1->fwd(test.a), test.b)); - EXPECT(points_equal(to_xyz_2->fwd(test.a), test.b)); - EXPECT(points_equal(to_xyz_3->fwd(test.a), test.b)); - } + EXPECT(points_equal(to_xyz_1->inv(test.b), test.a)); - for (const auto& test : test_oblate_spheroid) { - EXPECT(points_equal(to_xyz_3->fwd(test.a), test.b)); + EXPECT(points_equal(to_xyz_2->fwd(test.a), test.b)); + EXPECT(points_equal(to_xyz_2->inv(test.b), test.a)); } } - SECTION("") { - const PointLonLat p(723., 1.); // <- FIXME - - auto q = to_xyz_1->fwd(p); - auto r = to_xyz_1->inv(q); - Log::info() << "p(lat, lon): " << p << " -> p(x,y,z): " << q << " -> p(lat, lon): " << r << std::endl; - - EXPECT(points_equal(p, r)); - - for (const auto& lon : {0., 90., 180., 270.}) { - PointLonLat p{lon, 0.}; - Log::info() << "p(lat, lon): " << p << " -> p_ab(x,y,z): " << to_xyz_3->fwd(p) << std::endl; + SECTION("spheroid (ll -> xyz)") { + for (const auto& test : { + test_t{{0, -90}, {0, 0, -0.5}}, // + {{42, -90}, {0, 0, -0.5}}, // + {{0, 90}, {0, 0, 0.5}}, // + {{42, 90}, {0, 0, 0.5}}, // + }) { + EXPECT(points_equal(to_xyz_3->fwd(test.a), test.b)); + EXPECT(points_equal(to_xyz_4->fwd(test.a), test.b)); } } } From 768f35fe130614ed5b79bbeffe26ce63422c1b29 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 22 May 2024 21:49:14 +0100 Subject: [PATCH 659/737] eckit::geo::Figure --- src/eckit/geo/CMakeLists.txt | 1 + src/eckit/geo/Figure.cc | 4 ++ src/eckit/geo/Figure.h | 7 +++- src/eckit/geo/figure/Earth.cc | 22 +++++++++++ src/eckit/geo/figure/Earth.h | 1 + tests/geo/CMakeLists.txt | 1 + tests/geo/figure.cc | 73 +++++++++++++++++++++++++++++++++++ 7 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 src/eckit/geo/figure/Earth.cc create mode 100644 tests/geo/figure.cc diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index c16d45ca4..4e98f1379 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -40,6 +40,7 @@ list(APPEND eckit_geo_srcs area/BoundingBox.h etc/Grid.cc etc/Grid.h + figure/Earth.cc figure/Earth.h figure/OblateSpheroid.cc figure/OblateSpheroid.h diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc index 9374036a0..8f18bf1f1 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/geo/Figure.cc @@ -82,6 +82,10 @@ Figure* FigureFactory::make_from_string(const std::string& str) { Figure* FigureFactory::make_from_spec_(const Spec& spec) const { lock_type lock; + if (std::string figure; spec.get("figure", figure)) { + return Factory
::instance().get(figure).create(spec); + } + if (double a = 0., b = 0.; spec.get("a", a) && spec.get("b", b)) { return types::is_approximately_equal(a, b) ? static_cast(new figure::Sphere(a)) : new figure::OblateSpheroid(a, b); diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index 015d53561..1df83f600 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -76,6 +76,11 @@ class Figure { // -- Methods virtual void spec(spec::Custom&) const; + + // -- Friends + + friend bool operator==(const Figure& a, const Figure& b) { return a.spec() == b.spec(); } + friend bool operator!=(const Figure& a, const Figure& b) { return !(a == b); } }; @@ -91,7 +96,7 @@ struct FigureFactory { template -using FigureBuilder = ConcreteBuilderT1; +using FigureBuilder = ConcreteBuilderT0; } // namespace eckit::geo diff --git a/src/eckit/geo/figure/Earth.cc b/src/eckit/geo/figure/Earth.cc new file mode 100644 index 000000000..9bdc5438a --- /dev/null +++ b/src/eckit/geo/figure/Earth.cc @@ -0,0 +1,22 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/figure/Earth.h" + + +namespace eckit::geo::figure { + + +static const ConcreteBuilderT1 REGISTER("earth"); + + +} // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/Earth.h b/src/eckit/geo/figure/Earth.h index 7bb4584ad..7b99973c5 100644 --- a/src/eckit/geo/figure/Earth.h +++ b/src/eckit/geo/figure/Earth.h @@ -35,6 +35,7 @@ struct DatumWGS84SemiMajorAxis { struct Earth final : public Sphere { explicit Earth() : Sphere(DatumIFS::radius()) {} + explicit Earth(const Spec&) : Earth() {} }; diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index e0ebd3bf4..e1cee83b3 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -2,6 +2,7 @@ foreach(_test area_boundingbox area_polygon cache + figure geometry_sphere great_circle grid diff --git a/tests/geo/figure.cc b/tests/geo/figure.cc new file mode 100644 index 000000000..122b1ba8d --- /dev/null +++ b/tests/geo/figure.cc @@ -0,0 +1,73 @@ +/* + * (C) Copyright 1996- 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 + +#include "eckit/geo/Figure.h" +#include "eckit/geo/figure/Earth.h" +#include "eckit/geo/figure/OblateSpheroid.h" +#include "eckit/geo/figure/Sphere.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/testing/Test.h" + + +namespace eckit::geo::test { + + +struct F : std::unique_ptr
{ + explicit F(Figure* ptr) : unique_ptr(ptr) { ASSERT(unique_ptr::operator bool()); } +}; + + +CASE("figure: sphere") { + F f1(FigureFactory::build(spec::Custom{{"R", 1.}})); + F f2(FigureFactory::build(spec::Custom{{"a", 1.}, {"b", 1.}})); + F f3(new figure::Sphere(1.)); + + EXPECT_THROWS_AS(figure::Sphere(-1.), AssertionFailed); + + EXPECT(*f1 == *f2); + EXPECT(*f1 == *f3); + + EXPECT(f1->spec() == R"({"r":1})"); +} + + +CASE("figure: oblate spheroid") { + F f1(FigureFactory::build(spec::Custom{{"b", 0.5}, {"a", 1.}})); + F f2(new figure::OblateSpheroid(1., 0.5)); + + EXPECT_THROWS_AS(figure::OblateSpheroid(0.5, 1.), AssertionFailed); + EXPECT_THROWS_AS(figure::OblateSpheroid(1., -1.), AssertionFailed); + + EXPECT(*f1 == *f2); + + EXPECT(f1->spec() == R"({"a":1,"b":0.5})"); +} + + +CASE("figure: oblate spheroid") { + F f1(FigureFactory::build(spec::Custom{{"figure", "earth"}})); + F f2(new figure::Earth); + + EXPECT(*f1 == *f2); + + EXPECT(f1->spec() == R"({"r":6.37123e+06})"); +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From 17a9f386a4c3b10950918e89c3573d5d255cbd4f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 22 May 2024 22:11:55 +0100 Subject: [PATCH 660/737] eckit::geo::Point --- src/eckit/geo/PointLonLatR.cc | 20 ++++++++++---------- src/eckit/geo/PointLonLatR.h | 5 +++-- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/eckit/geo/PointLonLatR.cc b/src/eckit/geo/PointLonLatR.cc index 48279d788..d20c1d26b 100644 --- a/src/eckit/geo/PointLonLatR.cc +++ b/src/eckit/geo/PointLonLatR.cc @@ -35,23 +35,23 @@ PointLonLatR::value_type PointLonLatR::normalise_angle_to_maximum(value_type a, } -PointLonLatR PointLonLatR::make(value_type lon, value_type lat, value_type lon_minimum, value_type eps) { - lat = normalise_angle_to_minimum(lat, SOUTH_POLE); +PointLonLatR PointLonLatR::make(value_type lonr, value_type latr, value_type lonr_minimum, value_type eps) { + latr = normalise_angle_to_minimum(latr, SOUTH_POLE); - if (types::is_strictly_greater(lat, NORTH_POLE, eps)) { - lat = GLOBE / 2. - lat; - lon += GLOBE / 2.; + if (types::is_strictly_greater(latr, NORTH_POLE, eps)) { + latr = GLOBE / 2. - latr; + lonr += GLOBE / 2.; } - return types::is_approximately_equal(lat, NORTH_POLE, eps) ? PointLonLatR{0., NORTH_POLE} - : types::is_approximately_equal(lat, SOUTH_POLE, eps) + return types::is_approximately_equal(latr, NORTH_POLE, eps) ? PointLonLatR{0., NORTH_POLE} + : types::is_approximately_equal(latr, SOUTH_POLE, eps) ? PointLonLatR{EQUATOR, SOUTH_POLE} - : PointLonLatR{normalise_angle_to_minimum(lon, lon_minimum), lat}; + : PointLonLatR{normalise_angle_to_minimum(lonr, lonr_minimum), latr}; } -PointLonLatR PointLonLatR::make_from_lonlat(value_type lon, value_type lat) { - return make(util::DEGREE_TO_RADIAN * lon, util::DEGREE_TO_RADIAN * lat); +PointLonLatR PointLonLatR::make_from_lonlat(value_type lon, value_type lat, value_type lon_minimum) { + return make(util::DEGREE_TO_RADIAN * lon, util::DEGREE_TO_RADIAN * lat, util::DEGREE_TO_RADIAN * lon_minimum); } diff --git a/src/eckit/geo/PointLonLatR.h b/src/eckit/geo/PointLonLatR.h index 4db6ada3a..d9afe5853 100644 --- a/src/eckit/geo/PointLonLatR.h +++ b/src/eckit/geo/PointLonLatR.h @@ -69,10 +69,11 @@ class PointLonLatR final : protected std::array { static value_type normalise_angle_to_maximum(value_type, value_type maximum); - [[nodiscard]] static PointLonLatR make(value_type lon, value_type lat, value_type lon_minimum = EQUATOR, + [[nodiscard]] static PointLonLatR make(value_type lonr, value_type latr, value_type lonr_minimum = EQUATOR, value_type eps = EPS); - [[nodiscard]] static PointLonLatR make_from_lonlat(value_type lon, value_type lat); + [[nodiscard]] static PointLonLatR make_from_lonlat(value_type lon, value_type lat, + value_type lon_minimum = EQUATOR); PointLonLatR antipode() const { return make(lonr, latr + GLOBE / 2.); } From a9bcf159a7dffb3a14e2205fec43c8ca43970901 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 22 May 2024 22:57:33 +0100 Subject: [PATCH 661/737] Testing --- tests/geo/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index e1cee83b3..c665978e4 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -31,9 +31,10 @@ foreach(_test spec util ) ecbuild_add_test( - TARGET eckit_test_geo_${_test} - SOURCES ${_test}.cc - LIBS eckit_geo ) + TARGET eckit_test_geo_${_test} + SOURCES ${_test}.cc + LIBS eckit_geo + ENVIRONMENT "ECKIT_GEO_CACHE_PATH=${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_cache" ) endforeach() ecbuild_add_test( From 85817517e8c23b7dd232fa7276cf8345d4f3295e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 23 May 2024 07:50:31 +0100 Subject: [PATCH 662/737] Testing --- .github/ci-config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ci-config.yml b/.github/ci-config.yml index c1c0c52bf..fc5c84481 100644 --- a/.github/ci-config.yml +++ b/.github/ci-config.yml @@ -1,4 +1,4 @@ -cmake_options: -DENABLE_ECKIT_GEO=ON +cmake_options: -DENABLE_ECKIT_GEO=ON -DENABLE_CURL=ON dependencies: | ecmwf/ecbuild dependency_branch: develop From e187a02816fc7f72c40cfb206ce11a97ceba1a06 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 23 May 2024 09:39:45 +0100 Subject: [PATCH 663/737] eckit::geo::Figure --- tests/geo/figure.cc | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/geo/figure.cc b/tests/geo/figure.cc index 122b1ba8d..6a0d900e9 100644 --- a/tests/geo/figure.cc +++ b/tests/geo/figure.cc @@ -18,6 +18,7 @@ #include "eckit/geo/figure/Sphere.h" #include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" namespace eckit::geo::test { @@ -28,7 +29,7 @@ struct F : std::unique_ptr
{ }; -CASE("figure: sphere") { +CASE("Sphere") { F f1(FigureFactory::build(spec::Custom{{"R", 1.}})); F f2(FigureFactory::build(spec::Custom{{"a", 1.}, {"b", 1.}})); F f3(new figure::Sphere(1.)); @@ -38,24 +39,30 @@ CASE("figure: sphere") { EXPECT(*f1 == *f2); EXPECT(*f1 == *f3); + auto e = f1->eccentricity(); + EXPECT(types::is_approximately_equal(e, 0.)); + EXPECT(f1->spec() == R"({"r":1})"); } -CASE("figure: oblate spheroid") { +CASE("Oblate spheroid") { F f1(FigureFactory::build(spec::Custom{{"b", 0.5}, {"a", 1.}})); F f2(new figure::OblateSpheroid(1., 0.5)); - EXPECT_THROWS_AS(figure::OblateSpheroid(0.5, 1.), AssertionFailed); + EXPECT_THROWS_AS(figure::OblateSpheroid(0.5, 1.), AssertionFailed); // prolate spheroid EXPECT_THROWS_AS(figure::OblateSpheroid(1., -1.), AssertionFailed); EXPECT(*f1 == *f2); + auto e = f1->eccentricity(); + EXPECT(types::is_strictly_greater(e, 0.)); + EXPECT(f1->spec() == R"({"a":1,"b":0.5})"); } -CASE("figure: oblate spheroid") { +CASE("Earth") { F f1(FigureFactory::build(spec::Custom{{"figure", "earth"}})); F f2(new figure::Earth); From d7fe922f0477715a0650f5617a9e27be065d0ccb Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 23 May 2024 12:47:57 +0100 Subject: [PATCH 664/737] eckit::geo::etc::Grid --- src/eckit/geo/etc/Grid.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/eckit/geo/etc/Grid.cc b/src/eckit/geo/etc/Grid.cc index c712ef509..a4e4f531f 100644 --- a/src/eckit/geo/etc/Grid.cc +++ b/src/eckit/geo/etc/Grid.cc @@ -70,7 +70,7 @@ void Grid::load(const PathName& path) { const auto key = kv.first.as(); if (key == "grid_uids") { - for (ValueMap m : static_cast(kv.second)) { + for (ValueMap m : kv.second.as>()) { ASSERT(m.size() == 1); SpecByUID::instance().regist( m.begin()->first.as(), @@ -80,7 +80,7 @@ void Grid::load(const PathName& path) { } if (key == "grid_names") { - for (ValueMap m : static_cast(kv.second)) { + for (ValueMap m : kv.second.as>()) { ASSERT(m.size() == 1); SpecByName::instance().regist( m.begin()->first.as(), From db2fb576e0e72c35bb65cd4efa22cb497b702a68 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 23 May 2024 13:07:56 +0100 Subject: [PATCH 665/737] Testing --- tests/geo/CMakeLists.txt | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index c665978e4..182b3e002 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -37,11 +37,20 @@ foreach(_test ENVIRONMENT "ECKIT_GEO_CACHE_PATH=${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_cache" ) endforeach() -ecbuild_add_test( - TARGET eckit_test_geo_grid_orca - SOURCES grid_orca.cc - LIBS eckit_geo - CONDITION eckit_HAVE_ECKIT_CODEC ) +if(eckit_HAVE_ECKIT_CODEC) + file( DOWNLOAD + "https://get.ecmwf.int/repository/atlas/grids/orca/v0/ORCA2_T.atlas" + "${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_cache/eckit/geo/grid/orca/d5bde4f52ff3a9bea5629cd9ac514410.atlas" + EXPECTED_MD5 "f279b48c171409f46bfd27dff98d454a" + SHOW_PROGRESS + TIMEOUT 30 ) + + ecbuild_add_test( + TARGET eckit_test_geo_grid_orca + SOURCES grid_orca.cc + LIBS eckit_geo + ENVIRONMENT "ECKIT_GEO_CACHE_PATH=${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_cache" ) +endif() ecbuild_add_test( TARGET eckit_test_geo_tool_grid_spec_1_1 From 9336358df074d0e0da7aa180684b5a3b86e87e83 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 23 May 2024 13:33:27 +0100 Subject: [PATCH 666/737] Testing --- .github/ci-config.yml | 2 +- src/eckit/geo/etc/Grid.cc | 4 ++-- src/eckit/geo/spec/Custom.cc | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/ci-config.yml b/.github/ci-config.yml index fc5c84481..fb4c6f974 100644 --- a/.github/ci-config.yml +++ b/.github/ci-config.yml @@ -1,4 +1,4 @@ -cmake_options: -DENABLE_ECKIT_GEO=ON -DENABLE_CURL=ON +cmake_options: -DENABLE_ECKIT_GEO=ON -DENABLE_CURL=ON -DENABLE_LZ4=ON dependencies: | ecmwf/ecbuild dependency_branch: develop diff --git a/src/eckit/geo/etc/Grid.cc b/src/eckit/geo/etc/Grid.cc index a4e4f531f..5c4d0f6c3 100644 --- a/src/eckit/geo/etc/Grid.cc +++ b/src/eckit/geo/etc/Grid.cc @@ -70,7 +70,7 @@ void Grid::load(const PathName& path) { const auto key = kv.first.as(); if (key == "grid_uids") { - for (ValueMap m : kv.second.as>()) { + for (ValueMap m : kv.second.as()) { ASSERT(m.size() == 1); SpecByUID::instance().regist( m.begin()->first.as(), @@ -80,7 +80,7 @@ void Grid::load(const PathName& path) { } if (key == "grid_names") { - for (ValueMap m : kv.second.as>()) { + for (ValueMap m : kv.second.as()) { ASSERT(m.size() == 1); SpecByName::instance().regist( m.begin()->first.as(), diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 6eee7b270..cad2a9ea8 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -166,8 +166,9 @@ Custom* Custom::make_from_value(const Value& value) { }; auto vector = [](const Value& value) -> value_type { - const ValueList list(value); + const auto list(value.as()); ASSERT(!list.empty()); + return list.front().isNumber() ? value_type(std::vector(list.begin(), list.end())) : list.front().isDouble() ? value_type(std::vector(list.begin(), list.end())) : list.front().isString() ? std::vector(list.begin(), list.end()) From 8b233a65422bed57498b9a785294c9d842a1be39 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 23 May 2024 16:52:01 +0100 Subject: [PATCH 667/737] Testing --- CMakeLists.txt | 5 +++++ src/eckit/geo/CMakeLists.txt | 2 +- tests/geo/CMakeLists.txt | 29 +++++++++++++++++++---------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd7a4e7b0..6148163fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,6 +175,11 @@ ecbuild_add_option( FEATURE ECKIT_GEO DEFAULT OFF DESCRIPTION "eckit::geo geometry library" ) +ecbuild_add_option( FEATURE ECKIT_GEO_GRID_ORCA + DEFAULT ON + CONDITION HAVE_ECKIT_GEO AND HAVE_ECKIT_CODEC AND HAVE_LZ4 + DESCRIPTION "eckit::geo geometry library support for ORCA grids" ) + ecbuild_add_option( FEATURE GEO_CACHING DEFAULT OFF CONDITION HAVE_ECKIT_GEO diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 4e98f1379..9e2ae20cb 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -141,7 +141,7 @@ if(eckit_HAVE_PROJ) list(APPEND eckit_geo_libs PROJ::proj) endif() -if(eckit_HAVE_ECKIT_CODEC) +if(eckit_HAVE_ECKIT_GEO_GRID_ORCA) list(APPEND eckit_geo_srcs grid/ORCA.cc grid/ORCA.h) list(APPEND eckit_geo_libs eckit_codec) list(APPEND eckit_GEO_ETC_GRID "~eckit/etc/eckit/geo/ORCA.yaml") diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 182b3e002..2fb2ff27b 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -1,3 +1,5 @@ +set(CACHE_PATH "${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_cache") + foreach(_test area_boundingbox area_polygon @@ -34,22 +36,29 @@ foreach(_test TARGET eckit_test_geo_${_test} SOURCES ${_test}.cc LIBS eckit_geo - ENVIRONMENT "ECKIT_GEO_CACHE_PATH=${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_cache" ) + ENVIRONMENT "ECKIT_GEO_CACHE_PATH=${CACHE_PATH}" ) endforeach() -if(eckit_HAVE_ECKIT_CODEC) - file( DOWNLOAD - "https://get.ecmwf.int/repository/atlas/grids/orca/v0/ORCA2_T.atlas" - "${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_cache/eckit/geo/grid/orca/d5bde4f52ff3a9bea5629cd9ac514410.atlas" - EXPECTED_MD5 "f279b48c171409f46bfd27dff98d454a" - SHOW_PROGRESS - TIMEOUT 30 ) - +if(eckit_HAVE_ECKIT_GEO_GRID_ORCA) + set(URL "https://get.ecmwf.int/repository/atlas/grids/orca/v0/ORCA2_T.atlas") + set(FILE "${CACHE_PATH}/eckit/geo/grid/orca/d5bde4f52ff3a9bea5629cd9ac514410.atlas") + set(MD5 "f279b48c171409f46bfd27dff98d454a") + + file(DOWNLOAD ${URL} ${FILE} EXPECTED_MD5 ${MD5} TIMEOUT 30 STATUS DOWNLOAD_STATUS) + + list(GET DOWNLOAD_STATUS 0 STATUS_CODE) + if(${STATUS_CODE} EQUAL 0) + message(STATUS "File downloaded: '${FILE}'") + else() + list(GET DOWNLOAD_STATUS 1 STATUS_MESSAGE) + message(FATAL_ERROR "File download failed: ${STATUS_MESSAGE}, file: '${FILE}'") + endif() + ecbuild_add_test( TARGET eckit_test_geo_grid_orca SOURCES grid_orca.cc LIBS eckit_geo - ENVIRONMENT "ECKIT_GEO_CACHE_PATH=${CMAKE_CURRENT_BINARY_DIR}/eckit_geo_cache" ) + ENVIRONMENT "ECKIT_GEO_CACHE_PATH=${CACHE_PATH}" ) endif() ecbuild_add_test( From 0818ec1f4cd193aef5186d45428eb8eeb7626b99 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 23 May 2024 20:54:18 +0100 Subject: [PATCH 668/737] Testing --- src/eckit/geo/spec/Custom.cc | 22 ++++++++++++++++++++-- src/eckit/geo/spec/Custom.h | 9 +++++---- tests/geo/spec.cc | 8 ++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index cad2a9ea8..ef10d5663 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -141,6 +141,15 @@ JSON& operator<<(JSON& out, const Custom::value_type& value) { } +void sanitise(Custom::container_type& container) { + std::for_each(container.begin(), container.end(), [](auto& p) { + if (auto& value = p.second; std::holds_alternative(value)) { + value = std::string{std::get(value)}; + } + }); +} + + } // namespace @@ -149,10 +158,19 @@ Custom::key_type::key_type(const std::string& s) : std::string{s} { } -Custom::Custom(const Custom::container_type& map) : map_(map) {} +Custom::Custom(std::initializer_list init) : map_(init) { + sanitise(map_); +} + +Custom::Custom(const Custom::container_type& map) : map_(map) { + sanitise(map_); +} -Custom::Custom(Custom::container_type&& map) : map_(map) {} + +Custom::Custom(Custom::container_type&& map) : map_(map) { + sanitise(map_); +} Custom* Custom::make_from_value(const Value& value) { diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index dcfe26595..56b8c422f 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -35,16 +35,17 @@ class Custom final : public Spec { key_type(const char* s) : key_type(std::string{s}) {} }; - using value_type = std::variant, - std::vector, std::vector, std::vector, std::vector, - std::vector, std::vector>; + using value_type + = std::variant, + std::vector, std::vector, std::vector, std::vector, + std::vector, std::vector, const char* /* converted to std::string */>; using container_type = std::map; // -- Constructors Custom() = default; - Custom(std::initializer_list init) : map_{init} {} + Custom(std::initializer_list); explicit Custom(const container_type&); explicit Custom(container_type&&); diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index c01ba7c83..0bc6b0c26 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -96,6 +96,14 @@ CASE("Custom::value_type") { } +CASE("Custom::container_type") { + spec::Custom spec({{std::string{"foo"}, "bar"}}); + + std::string bar; + EXPECT(spec.get("foo", bar) && bar == "bar"); +} + + CASE("Spec <- Custom") { constexpr int zero = 0; constexpr int one = 1; From 7729190165fcbc6a57a2c7f37bb7301feb6d1085 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 23 May 2024 20:55:00 +0100 Subject: [PATCH 669/737] eckit::geo::grid::ORCA --- CMakeLists.txt | 4 ++-- src/eckit/geo/CMakeLists.txt | 2 +- src/eckit/geo/eckit_geo_config.h.in | 1 + tests/geo/CMakeLists.txt | 2 +- tests/geo/grid.cc | 2 ++ 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6148163fa..a082ef95a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,9 +175,9 @@ ecbuild_add_option( FEATURE ECKIT_GEO DEFAULT OFF DESCRIPTION "eckit::geo geometry library" ) -ecbuild_add_option( FEATURE ECKIT_GEO_GRID_ORCA +ecbuild_add_option( FEATURE GEO_GRID_ORCA DEFAULT ON - CONDITION HAVE_ECKIT_GEO AND HAVE_ECKIT_CODEC AND HAVE_LZ4 + CONDITION eckit_HAVE_ECKIT_GEO AND eckit_HAVE_ECKIT_CODEC AND eckit_HAVE_LZ4 DESCRIPTION "eckit::geo geometry library support for ORCA grids" ) ecbuild_add_option( FEATURE GEO_CACHING diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 9e2ae20cb..6f0db797a 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -141,7 +141,7 @@ if(eckit_HAVE_PROJ) list(APPEND eckit_geo_libs PROJ::proj) endif() -if(eckit_HAVE_ECKIT_GEO_GRID_ORCA) +if(eckit_HAVE_GEO_GRID_ORCA) list(APPEND eckit_geo_srcs grid/ORCA.cc grid/ORCA.h) list(APPEND eckit_geo_libs eckit_codec) list(APPEND eckit_GEO_ETC_GRID "~eckit/etc/eckit/geo/ORCA.yaml") diff --git a/src/eckit/geo/eckit_geo_config.h.in b/src/eckit/geo/eckit_geo_config.h.in index 036cba383..a61625d44 100644 --- a/src/eckit/geo/eckit_geo_config.h.in +++ b/src/eckit/geo/eckit_geo_config.h.in @@ -16,6 +16,7 @@ #cmakedefine01 eckit_HAVE_GEO_BITREPRODUCIBLE #cmakedefine01 eckit_HAVE_GEO_CACHING #cmakedefine01 eckit_HAVE_GEO_CONVEX_HULL +#cmakedefine01 eckit_HAVE_GEO_GRID_ORCA #cmakedefine eckit_GEO_CACHE_PATH "@eckit_GEO_CACHE_PATH@" #cmakedefine eckit_GEO_ETC_GRID "@eckit_GEO_ETC_GRID@" diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 2fb2ff27b..800e3db71 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -39,7 +39,7 @@ foreach(_test ENVIRONMENT "ECKIT_GEO_CACHE_PATH=${CACHE_PATH}" ) endforeach() -if(eckit_HAVE_ECKIT_GEO_GRID_ORCA) +if(eckit_HAVE_GEO_GRID_ORCA) set(URL "https://get.ecmwf.int/repository/atlas/grids/orca/v0/ORCA2_T.atlas") set(FILE "${CACHE_PATH}/eckit/geo/grid/orca/d5bde4f52ff3a9bea5629cd9ac514410.atlas") set(MD5 "f279b48c171409f46bfd27dff98d454a") diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index 159a047c6..49478c2d0 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -39,6 +39,7 @@ CASE("GridFactory::build") { } +#if eckit_HAVE_GEO_GRID_ORCA if (LibEcKitGeo::caching()) { SECTION("Grid::build_from_uid") { spec::Custom spec({ @@ -62,6 +63,7 @@ CASE("GridFactory::build") { EXPECT_EQUAL(size_a, size_b); } } +#endif SECTION("Grid::build_from_increments (global)") { From 40efdf759ce79ca1d6af6cb928442ed284bb6c40 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 23 May 2024 21:02:21 +0100 Subject: [PATCH 670/737] Testing --- .github/ci-config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ci-config.yml b/.github/ci-config.yml index fb4c6f974..c1c0c52bf 100644 --- a/.github/ci-config.yml +++ b/.github/ci-config.yml @@ -1,4 +1,4 @@ -cmake_options: -DENABLE_ECKIT_GEO=ON -DENABLE_CURL=ON -DENABLE_LZ4=ON +cmake_options: -DENABLE_ECKIT_GEO=ON dependencies: | ecmwf/ecbuild dependency_branch: develop From 361b8b55b65e9c3504b023e76ce86f1c51c12458 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 23 May 2024 21:18:22 +0100 Subject: [PATCH 671/737] Testing --- tests/geo/spec.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 0bc6b0c26..b5a7e8bff 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -15,6 +15,7 @@ #include #include "eckit/geo/Grid.h" +#include "eckit/geo/eckit_geo_config.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/spec/Layered.h" #include "eckit/geo/util.h" @@ -442,6 +443,7 @@ CASE("spec") { } +#if eckit_HAVE_GEO_GRID_ORCA SECTION("grid: ORCA") { Grid::uid_t uid = "d5bde4f52ff3a9bea5629cd9ac514410"; @@ -453,6 +455,7 @@ CASE("spec") { EXPECT(o1->spec() == o2->spec()); } +#endif } From 5d9b69cb91569195fb10ef5eba81b967bffd8b9a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 23 May 2024 21:35:03 +0100 Subject: [PATCH 672/737] Testing --- src/eckit/geo/Range.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 99d26181a..a47c19456 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -12,6 +12,7 @@ #pragma once +#include #include From 43d6aca7b64fe1771bf2ebfc9552ba04f4a9116f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 May 2024 16:41:37 +0100 Subject: [PATCH 673/737] eckit::Factory: testing --- tests/memory/test_factory.cc | 142 +++++++++++++++-------------------- 1 file changed, 60 insertions(+), 82 deletions(-) diff --git a/tests/memory/test_factory.cc b/tests/memory/test_factory.cc index 11d88e76f..1bacd1f88 100644 --- a/tests/memory/test_factory.cc +++ b/tests/memory/test_factory.cc @@ -8,40 +8,29 @@ * does it submit to any jurisdiction. */ -#include + #include +#include -#include "eckit/log/Log.h" #include "eckit/memory/Builder.h" +#include "eckit/memory/Factory.h" #include "eckit/memory/Owned.h" -#include "eckit/runtime/Tool.h" -#include "eckit/utils/Translator.h" -#include "eckit/value/Properties.h" - - #include "eckit/testing/Test.h" +#include "eckit/value/Properties.h" -using namespace std; -using namespace eckit; -using namespace eckit::testing; namespace eckit::test { -/// These tests are similar to the test for boost scoped_ptr and shared ptrs -/// This allows as in the future to drop out, our own home grown managed -/// ptr's in favour of the standards. - //---------------------------------------------------------------------------------------------------------------------- class Base0 { public: - typedef BuilderT0 builder_t; - - typedef std::shared_ptr Ptr; + using builder_t = BuilderT0; static std::string className() { return "eckit_test.Base0"; } - virtual ~Base0() {} + virtual ~Base0() = default; + virtual std::string foo() const = 0; }; @@ -49,10 +38,9 @@ class A0 : public Base0 { public: static std::string className() { return "eckit_test.A0"; } - A0() : - s1_("A.0") {} + A0() : s1_("A.0") {} - virtual std::string foo() const { return className() + "." + s1_; } + std::string foo() const override { return className() + "." + s1_; } private: std::string s1_; @@ -62,30 +50,28 @@ class B0 : public Base0 { public: static std::string className() { return "eckit_test.B0"; } - B0() : - s2_("B.0") {} + B0() : s2_("B.0") {} - virtual std::string foo() const { return className() + "." + s2_; } + std::string foo() const override { return className() + "." + s2_; } private: std::string s2_; }; -ConcreteBuilderT0 builder_A0; -ConcreteBuilderT0 builder_B0; +static const ConcreteBuilderT0 builder_A0; +static const ConcreteBuilderT0 builder_B0; //---------------------------------------------------------------------------------------------------------------------- class Base1 : public Owned { public: - typedef BuilderT1 builder_t; - typedef const Params& ARG1; - - typedef std::shared_ptr Ptr; + using builder_t = BuilderT1; + using ARG1 = const Properties&; static std::string className() { return "eckit_test.Base1"; } - virtual ~Base1() {} + virtual ~Base1() = default; + virtual std::string foo() const = 0; }; @@ -93,10 +79,9 @@ class A1 : public Base1 { public: static std::string className() { return "eckit_test.A1"; } - A1(const Params& p) : - s1_(p["mystr"].as() + ".1") {} + explicit A1(const Properties& p) : s1_(p["mystr"].as() + ".1") {} - virtual std::string foo() const { return className() + "." + s1_; } + std::string foo() const override { return className() + "." + s1_; } private: std::string s1_; @@ -106,31 +91,29 @@ class B1 : public Base1 { public: static std::string className() { return "eckit_test.B1"; } - B1(const Params& p) : - s2_(p["mystr"].as() + ".2") {} + explicit B1(const Properties& p) : s2_(p["mystr"].as() + ".2") {} - virtual std::string foo() const { return className() + "." + s2_; } + std::string foo() const override { return className() + "." + s2_; } private: std::string s2_; }; -ConcreteBuilderT1 builder_A1; -ConcreteBuilderT1 builder_B1; +static const ConcreteBuilderT1 builder_A1; +static const ConcreteBuilderT1 builder_B1; //---------------------------------------------------------------------------------------------------------------------- class Base2 : public Owned { public: - typedef BuilderT2 builder_t; - typedef std::string ARG1; - typedef int ARG2; - - typedef std::shared_ptr Ptr; + using builder_t = BuilderT2; + using ARG1 = std::string; + using ARG2 = int; static std::string className() { return "eckit_test.Base2"; } - virtual ~Base2() {} + virtual ~Base2() = default; + virtual std::string foo() const = 0; }; @@ -138,10 +121,9 @@ class A2 : public Base2 { public: static std::string className() { return "eckit_test.A2"; } - A2(std::string s, int i) : - s1_(s + "." + Translator()(i)) {} + A2(std::string s, int i) : s1_(s + "." + std::to_string(i)) {} - virtual std::string foo() const { return className() + "." + s1_; } + std::string foo() const override { return className() + "." + s1_; } private: std::string s1_; @@ -151,35 +133,33 @@ class B2 : public Base2 { public: static std::string className() { return "eckit_test.B2"; } - B2(std::string s, int i) : - s2_(s + "." + Translator()(i)) {} + B2(std::string s, int i) : s2_(s + "." + std::to_string(i)) {} - virtual std::string foo() const { return className() + "." + s2_; } + std::string foo() const override { return className() + "." + s2_; } private: std::string s2_; }; -ConcreteBuilderT2 builder_A2; -ConcreteBuilderT2 builder_B2; +static const ConcreteBuilderT2 builder_A2; +static const ConcreteBuilderT2 builder_B2; //---------------------------------------------------------------------------------------------------------------------- CASE("test_eckit_memory_factory_0") { - // std::cout << Factory::instance() << std::endl; - EXPECT(Factory::build_type() == "eckit_test.Base0"); + const auto& factory = Factory::instance(); - EXPECT(Factory::instance().size() == 2); + EXPECT(factory.size() == 2); - EXPECT(Factory::instance().exists("eckit_test.A0")); - EXPECT(Factory::instance().exists("eckit_test.B0")); + EXPECT(factory.exists("eckit_test.A0")); + EXPECT(factory.exists("eckit_test.B0")); - EXPECT(Factory::instance().get("eckit_test.A0").name() == "eckit_test.A0"); - EXPECT(Factory::instance().get("eckit_test.B0").name() == "eckit_test.B0"); + EXPECT(factory.get("eckit_test.A0").name() == "eckit_test.A0"); + EXPECT(factory.get("eckit_test.B0").name() == "eckit_test.B0"); - Base0::Ptr p1(Factory::instance().get("eckit_test.A0").create()); - Base0::Ptr p2(Factory::instance().get("eckit_test.B0").create()); + std::unique_ptr p1(factory.get("eckit_test.A0").create()); + std::unique_ptr p2(factory.get("eckit_test.B0").create()); EXPECT(p1); EXPECT(p2); @@ -189,23 +169,22 @@ CASE("test_eckit_memory_factory_0") { } CASE("test_eckit_memory_factory_1") { - // std::cout << Factory::instance() << std::endl; - EXPECT(Factory::build_type() == "eckit_test.Base1"); + const auto& factory = Factory::instance(); - EXPECT(Factory::instance().size() == 2); + EXPECT(factory.size() == 2); - EXPECT(Factory::instance().exists("eckit_test.A1")); - EXPECT(Factory::instance().exists("eckit_test.B1")); + EXPECT(factory.exists("eckit_test.A1")); + EXPECT(factory.exists("eckit_test.B1")); - EXPECT(Factory::instance().get("eckit_test.A1").name() == "eckit_test.A1"); - EXPECT(Factory::instance().get("eckit_test.B1").name() == "eckit_test.B1"); + EXPECT(factory.get("eckit_test.A1").name() == "eckit_test.A1"); + EXPECT(factory.get("eckit_test.B1").name() == "eckit_test.B1"); Properties p; p.set("mystr", "lolo"); - Base1::Ptr p1(Factory::instance().get("eckit_test.A1").create(Params(p))); - Base1::Ptr p2(Factory::instance().get("eckit_test.B1").create(Params(p))); + std::unique_ptr p1(factory.get("eckit_test.A1").create(p)); + std::unique_ptr p2(factory.get("eckit_test.B1").create(p)); EXPECT(p1); EXPECT(p2); @@ -215,22 +194,21 @@ CASE("test_eckit_memory_factory_1") { } CASE("test_eckit_memory_factory_2") { - // std::cout << Factory::instance() << std::endl; - EXPECT(Factory::build_type() == "eckit_test.Base2"); + const auto& factory = Factory::instance(); - EXPECT(Factory::instance().size() == 2); + EXPECT(factory.size() == 2); - EXPECT(Factory::instance().exists("eckit_test.A2")); - EXPECT(Factory::instance().exists("eckit_test.B2")); + EXPECT(factory.exists("eckit_test.A2")); + EXPECT(factory.exists("eckit_test.B2")); - EXPECT(Factory::instance().get("eckit_test.A2").name() == "eckit_test.A2"); - EXPECT(Factory::instance().get("eckit_test.B2").name() == "eckit_test.B2"); + EXPECT(factory.get("eckit_test.A2").name() == "eckit_test.A2"); + EXPECT(factory.get("eckit_test.B2").name() == "eckit_test.B2"); - string s("lolo"); + std::string s("lolo"); - Base2::Ptr p1(Factory::instance().get("eckit_test.A2").create(s, 42)); - Base2::Ptr p2(Factory::instance().get("eckit_test.B2").create(s, 42)); + std::unique_ptr p1(factory.get("eckit_test.A2").create(s, 42)); + std::unique_ptr p2(factory.get("eckit_test.B2").create(s, 42)); EXPECT(p1); EXPECT(p2); @@ -244,5 +222,5 @@ CASE("test_eckit_memory_factory_2") { } // namespace eckit::test int main(int argc, char** argv) { - return run_tests(argc, argv); + return eckit::testing::run_tests(argc, argv); } From d4d7ea79ea97c8671879833b055cba7c196e3766 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 24 May 2024 16:42:33 +0100 Subject: [PATCH 674/737] eckit::Factory: testing --- tests/memory/test_factory.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/memory/test_factory.cc b/tests/memory/test_factory.cc index 1bacd1f88..69f435002 100644 --- a/tests/memory/test_factory.cc +++ b/tests/memory/test_factory.cc @@ -142,7 +142,8 @@ class B2 : public Base2 { }; static const ConcreteBuilderT2 builder_A2; -static const ConcreteBuilderT2 builder_B2; +static const ConcreteBuilderT2 builder_B2_1; +static const ConcreteBuilderT2 builder_B2_2("eckit_test.B2.x"); //---------------------------------------------------------------------------------------------------------------------- @@ -197,7 +198,7 @@ CASE("test_eckit_memory_factory_2") { EXPECT(Factory::build_type() == "eckit_test.Base2"); const auto& factory = Factory::instance(); - EXPECT(factory.size() == 2); + EXPECT(factory.size() == 3); EXPECT(factory.exists("eckit_test.A2")); EXPECT(factory.exists("eckit_test.B2")); @@ -209,12 +210,15 @@ CASE("test_eckit_memory_factory_2") { std::unique_ptr p1(factory.get("eckit_test.A2").create(s, 42)); std::unique_ptr p2(factory.get("eckit_test.B2").create(s, 42)); + std::unique_ptr p3(factory.get("eckit_test.B2.x").create(s, -42)); EXPECT(p1); EXPECT(p2); + EXPECT(p3); EXPECT(p1->foo() == "eckit_test.A2.lolo.42"); EXPECT(p2->foo() == "eckit_test.B2.lolo.42"); + EXPECT(p3->foo() == "eckit_test.B2.lolo.-42"); } //---------------------------------------------------------------------------------------------------------------------- From 079bdc2cbab90b1c3a8e2894955a6229c3d99d78 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 May 2024 14:33:51 +0100 Subject: [PATCH 675/737] eckit::Factory: control --- CMakeLists.txt | 10 ++++++++++ src/eckit/eckit_config.h.in | 5 +++++ src/eckit/memory/Builder.h | 32 +++++++++++++++++--------------- src/eckit/memory/Factory.h | 8 +++++--- 4 files changed, 37 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a082ef95a..098bc752e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,6 +51,16 @@ set( THREADS_HAVE_PTHREAD_ARG FALSE ) find_package( Threads REQUIRED ) set( THREADS_LIBRARIES ${CMAKE_THREAD_LIBS_INIT} ) +ecbuild_add_option( FEATURE ECKIT_MEMORY_FACTORY_BUILDERS_DEBUG + DEFAULT OFF + DESCRIPTION "eckit::Factory builders debug" + ADVANCED ) + +ecbuild_add_option( FEATURE ECKIT_MEMORY_FACTORY_EMPTY_DESTRUCTION + DEFAULT ON + DESCRIPTION "eckit::Factory empty destruction (system dependant)" + ADVANCED ) + ### eckit::mpi ecbuild_add_option( FEATURE MPI diff --git a/src/eckit/eckit_config.h.in b/src/eckit/eckit_config.h.in index 18c4bfab8..0f92d7f7c 100644 --- a/src/eckit/eckit_config.h.in +++ b/src/eckit/eckit_config.h.in @@ -36,6 +36,11 @@ #cmakedefine01 eckit_HAVE_UNICODE #cmakedefine01 eckit_HAVE_XXHASH +// memory + +#cmakedefine01 eckit_HAVE_ECKIT_MEMORY_FACTORY_BUILDERS_DEBUG +#cmakedefine01 eckit_HAVE_ECKIT_MEMORY_FACTORY_EMPTY_DESTRUCTION + // external packages #cmakedefine01 eckit_HAVE_ARMADILLO diff --git a/src/eckit/memory/Builder.h b/src/eckit/memory/Builder.h index f429d97a6..5878a35ba 100644 --- a/src/eckit/memory/Builder.h +++ b/src/eckit/memory/Builder.h @@ -16,10 +16,10 @@ #pragma once +#include "eckit/eckit_config.h" #include "eckit/memory/Factory.h" -// #define DEBUG_ECKIT_BUILDERS -#ifdef DEBUG_ECKIT_BUILDERS +#if eckit_HAVE_ECKIT_MEMORY_FACTORY_BUILDERS_DEBUG #include "eckit/exception/Exceptions.h" #define DEBUG_BUILDER(x) std::cerr << " DEBUG (" << x << ") " << Here() << std::endl; #else @@ -141,14 +141,12 @@ class ConcreteBuilderT0 final : public BuilderT0 { // -- Constructors - ConcreteBuilderT0() : - key_(name()) { + ConcreteBuilderT0() : key_(name()) { DEBUG_BUILDER("ConcreteBuilderT0() -- " << T::className()); Factory::instance().regist(key_, this); } - explicit ConcreteBuilderT0(const typename base_t::key_t& k) : - key_(k) { + explicit ConcreteBuilderT0(const typename base_t::key_t& k) : key_(k) { DEBUG_BUILDER("ConcreteBuilderT0() -- " << T::className()); Factory::instance().regist(key_, this); } @@ -160,7 +158,9 @@ class ConcreteBuilderT0 final : public BuilderT0 { ~ConcreteBuilderT0() override { DEBUG_BUILDER("~ConcreteBuilderT0() -- " << T::className()); +#if eckit_HAVE_ECKIT_MEMORY_FACTORY_EMPTY_DESTRUCTION Factory::instance().unregist(key_); +#endif } // -- Operators @@ -199,14 +199,12 @@ class ConcreteBuilderT1 final : public BuilderT1 { // -- Constructors - ConcreteBuilderT1() : - key_(name()) { + ConcreteBuilderT1() : key_(name()) { DEBUG_BUILDER("ConcreteBuilderT1() -- " << T::className()); Factory::instance().regist(key_, this); } - explicit ConcreteBuilderT1(const typename base_t::key_t& k) : - key_(k) { + explicit ConcreteBuilderT1(const typename base_t::key_t& k) : key_(k) { DEBUG_BUILDER("ConcreteBuilderT1() -- " << T::className()); Factory::instance().regist(key_, this); } @@ -218,7 +216,9 @@ class ConcreteBuilderT1 final : public BuilderT1 { ~ConcreteBuilderT1() override { DEBUG_BUILDER("~ConcreteBuilderT1() -- " << T::className()); +#if ECKIT_MEMORY_FACTORY_EMPTY_DESTRUCTION Factory::instance().unregist(key_); +#endif } // -- Operators @@ -258,14 +258,12 @@ class ConcreteBuilderT2 final : public BuilderT2 { // -- Constructors - ConcreteBuilderT2() : - key_(name()) { + ConcreteBuilderT2() : key_(name()) { DEBUG_BUILDER("ConcreteBuilderT2() -- " << T::className()); Factory::instance().regist(key_, this); } - explicit ConcreteBuilderT2(const typename base_t::key_t& k) : - key_(k) { + explicit ConcreteBuilderT2(const typename base_t::key_t& k) : key_(k) { DEBUG_BUILDER("ConcreteBuilderT2() -- " << T::className()); Factory::instance().regist(key_, this); } @@ -277,7 +275,9 @@ class ConcreteBuilderT2 final : public BuilderT2 { ~ConcreteBuilderT2() override { DEBUG_BUILDER("~ConcreteBuilderT2() -- " << T::className()); +#if eckit_HAVE_ECKIT_MEMORY_FACTORY_EMPTY_DESTRUCTION Factory::instance().unregist(key_); +#endif } // -- Operators @@ -288,7 +288,9 @@ class ConcreteBuilderT2 final : public BuilderT2 { // -- Overridden methods typename base_t::key_t name() const override { return T::className(); } - typename base_t::product_t* create(typename base_t::ARG1 p1, typename base_t::ARG2 p2) const override { return new T(p1, p2); } + typename base_t::product_t* create(typename base_t::ARG1 p1, typename base_t::ARG2 p2) const override { + return new T(p1, p2); + } private: diff --git a/src/eckit/memory/Factory.h b/src/eckit/memory/Factory.h index ab2b468f7..87731b830 100644 --- a/src/eckit/memory/Factory.h +++ b/src/eckit/memory/Factory.h @@ -21,6 +21,7 @@ #include #include +#include "eckit/eckit_config.h" #include "eckit/exception/Exceptions.h" #include "eckit/thread/AutoLock.h" #include "eckit/thread/Mutex.h" @@ -82,13 +83,14 @@ class Factory { std::vector keys() const; private: - // Constructors + // -- Constructors Factory() = default; - // Destructor - +#if eckit_HAVE_ECKIT_MEMORY_FACTORY_EMPTY_DESTRUCTION + // -- Destructor ~Factory() { ASSERT(store_.empty()); } +#endif // -- Members From e22e41e71e1d0333b43d791deca823b7a01d8c71 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 May 2024 14:54:50 +0100 Subject: [PATCH 676/737] Testing --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 098bc752e..df40ba9f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,7 +57,7 @@ ecbuild_add_option( FEATURE ECKIT_MEMORY_FACTORY_BUILDERS_DEBUG ADVANCED ) ecbuild_add_option( FEATURE ECKIT_MEMORY_FACTORY_EMPTY_DESTRUCTION - DEFAULT ON + DEFAULT OFF DESCRIPTION "eckit::Factory empty destruction (system dependant)" ADVANCED ) From 66785859004c4b58fdc322deed4b79e61e81898d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 May 2024 15:16:39 +0100 Subject: [PATCH 677/737] eckit-grid --- src/tools/CMakeLists.txt | 12 ++++++------ src/tools/{eckit-grid.cc => eckit-grid-nearest.cc} | 6 +++--- src/tools/eckit-grid-spec.cc | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) rename src/tools/{eckit-grid.cc => eckit-grid-nearest.cc} (95%) diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index 804d10f96..acca06aca 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -18,18 +18,18 @@ ecbuild_add_executable( TARGET eckit_codec_list SOURCES eckit-codec-list.cc LIBS eckit_codec eckit_option ) -ecbuild_add_executable( TARGET eckit_grid - OUTPUT_NAME eckit-grid - CONDITION eckit_HAVE_ECKIT_GEO - SOURCES eckit-grid.cc - LIBS eckit_geo eckit_option ) - ecbuild_add_executable( TARGET eckit_grid_list OUTPUT_NAME eckit-grid-list CONDITION eckit_HAVE_ECKIT_GEO SOURCES eckit-grid-list.cc LIBS eckit_geo eckit_option ) +ecbuild_add_executable( TARGET eckit_grid_nearest + OUTPUT_NAME eckit-grid-nearest + CONDITION eckit_HAVE_ECKIT_GEO + SOURCES eckit-grid-nearest.cc + LIBS eckit_geo eckit_option ) + ecbuild_add_executable( TARGET eckit_grid_spec OUTPUT_NAME eckit-grid-spec CONDITION eckit_HAVE_ECKIT_GEO diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid-nearest.cc similarity index 95% rename from src/tools/eckit-grid.cc rename to src/tools/eckit-grid-nearest.cc index c452cdf56..27af0e012 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid-nearest.cc @@ -27,9 +27,9 @@ namespace eckit { -class EckitGrid final : public EckitTool { +class EckitGridNearest final : public EckitTool { public: - EckitGrid(int argc, char** argv) : EckitTool(argc, argv) { + EckitGridNearest(int argc, char** argv) : EckitTool(argc, argv) { options_.push_back(new option::SimpleOption("uid", "by grid unique identifier, instead of name")); options_.push_back(new option::VectorOption("nearest-point", "nearest point location (lon/lat)", 2)); options_.push_back(new option::SimpleOption("nearest-k", "nearest k points")); @@ -96,6 +96,6 @@ class EckitGrid final : public EckitTool { //---------------------------------------------------------------------------------------------------------------------- int main(int argc, char** argv) { - eckit::EckitGrid app(argc, argv); + eckit::EckitGridNearest app(argc, argv); return app.start(); } diff --git a/src/tools/eckit-grid-spec.cc b/src/tools/eckit-grid-spec.cc index 52e01b7ea..a0ea7ac3e 100644 --- a/src/tools/eckit-grid-spec.cc +++ b/src/tools/eckit-grid-spec.cc @@ -25,9 +25,9 @@ namespace eckit { -class EckitGrid final : public EckitTool { +class EckitGridSpec final : public EckitTool { public: - EckitGrid(int argc, char** argv) : EckitTool(argc, argv) { + EckitGridSpec(int argc, char** argv) : EckitTool(argc, argv) { options_.push_back(new option::SimpleOption("check", "regex to check against result")); } @@ -70,6 +70,6 @@ class EckitGrid final : public EckitTool { int main(int argc, char** argv) { - eckit::EckitGrid app(argc, argv); + eckit::EckitGridSpec app(argc, argv); return app.start(); } From 3088ac3c6eefb7ee69e1a8b76285b952c2b97fef Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 May 2024 16:33:15 +0100 Subject: [PATCH 678/737] eckit-grid --- src/tools/CMakeLists.txt | 6 ++ src/tools/eckit-grid.cc | 115 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 src/tools/eckit-grid.cc diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index acca06aca..aa58c45a8 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -18,6 +18,12 @@ ecbuild_add_executable( TARGET eckit_codec_list SOURCES eckit-codec-list.cc LIBS eckit_codec eckit_option ) +ecbuild_add_executable( TARGET eckit_grid + OUTPUT_NAME eckit-grid + CONDITION eckit_HAVE_ECKIT_GEO + SOURCES eckit-grid.cc + LIBS eckit_geo eckit_option ) + ecbuild_add_executable( TARGET eckit_grid_list OUTPUT_NAME eckit-grid-list CONDITION eckit_HAVE_ECKIT_GEO diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc new file mode 100644 index 000000000..1beba116a --- /dev/null +++ b/src/tools/eckit-grid.cc @@ -0,0 +1,115 @@ +/* + * (C) Copyright 1996- 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 +#include +#include +#include + +#include "eckit/geo/Grid.h" +#include "eckit/geo/Point.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/log/JSON.h" +#include "eckit/log/Log.h" +#include "eckit/option/CmdArgs.h" +#include "eckit/option/EckitTool.h" +#include "eckit/option/SimpleOption.h" +#include "eckit/parser/YAMLParser.h" + + +namespace eckit { + +class EckitGrid final : public EckitTool { +public: + EckitGrid(int argc, char** argv) : EckitTool(argc, argv) { + options_.push_back(new option::SimpleOption("grid", "grid spec")); + options_.push_back(new option::SimpleOption("bounding-box", "Bounding box")); + options_.push_back(new option::SimpleOption("precision", "Output precision")); + } + +private: + void usage(const std::string& tool) const override { + Log::info() << "\n" + "Usage: " + << tool << "[options] ..." << std::endl; + } + + int minimumPositionalArguments() const override { return 1; } + + void execute(const option::CmdArgs& args) override { + std::stringstream stream; + eckit::JSON out(stream); + out.precision(args.getInt("precision", 16)); + + std::string user; + for (const auto& arg : args) { + user += " " + arg; + } + + std::unique_ptr grid([](const std::string& str) -> const geo::Grid* { + std::unique_ptr spec(geo::spec::Custom::make_from_value(YAMLParser::decodeString(str))); + return geo::GridFactory::build(*spec); + }(user)); + + out << "spec" << grid->spec(); + out << "uid" << grid->uid(); + out << "size" << grid->size(); + + + // Earth's equator ~= 40075 km + auto deg_km + = [](double deg) { return std::to_string(deg) + " deg, " + std::to_string(deg * 40075. / 360.) + " km"; }; + + auto nx = 1; // grid->nx(); + auto ny = 1; // grid->ny(); + + out << "shape"; + (out.startList() << nx << ny).endList(); + + // out << "resolution N-S" << deg_km((grid->y().front() - grid->y().back()) / (ny - 1)); + // out << "resolution E-W equator" << deg_km(360. / static_cast(grid->nx(ny / 2))); + // out << "resolution E-W midlat" << deg_km(360. * std::cos(grid->y(ny / 4) * M_PI / 180.) / + // static_cast(grid->nx(ny / 4))) << "resolution E-W pole" << deg_km(360. * + // std::cos(grid->y().front() * M_PI / 180.) / static_cast(grid->nx().front())); + + out << "spectral truncation linear" << (ny - 1); + out << "spectral truncation quadratic" << (static_cast(std::floor(2. / 3. * ny + 0.5)) - 1); + out << "spectral truncation cubic" << (static_cast(std::floor(0.5 * ny + 0.5)) - 1); + + { + auto points = grid->to_points(); + auto first = std::get(points.front()); + auto last = std::get(points.back()); + + out << "first"; + (out.startList() << first.lon << first.lat).endList(); + + out << "last"; + (out.startList() << last.lon << last.lat).endList(); + } + + { + auto bbox = grid->boundingBox(); + out << "bounding box"; + (out.startList() << bbox.north << bbox.west << bbox.south << bbox.east).endList(); + } + + Log::info() << stream.str() << std::endl; + } +}; + +} // namespace eckit + + +int main(int argc, char** argv) { + eckit::EckitGrid app(argc, argv); + return app.start(); +} From b3b57a0d114144d4b8e5760db9a124c84b7e87bc Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 May 2024 16:59:16 +0100 Subject: [PATCH 679/737] eckit::geo ORCA --- tests/geo/CMakeLists.txt | 3 +- tests/geo/grid.cc | 27 ------------ tests/geo/grid_orca.cc | 92 ++++++++++++++++++++++++++-------------- tests/geo/spec.cc | 15 ------- 4 files changed, 62 insertions(+), 75 deletions(-) diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 800e3db71..fc9247a06 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -35,8 +35,7 @@ foreach(_test ecbuild_add_test( TARGET eckit_test_geo_${_test} SOURCES ${_test}.cc - LIBS eckit_geo - ENVIRONMENT "ECKIT_GEO_CACHE_PATH=${CACHE_PATH}" ) + LIBS eckit_geo ) endforeach() if(eckit_HAVE_GEO_GRID_ORCA) diff --git a/tests/geo/grid.cc b/tests/geo/grid.cc index 49478c2d0..3101ee292 100644 --- a/tests/geo/grid.cc +++ b/tests/geo/grid.cc @@ -39,33 +39,6 @@ CASE("GridFactory::build") { } -#if eckit_HAVE_GEO_GRID_ORCA - if (LibEcKitGeo::caching()) { - SECTION("Grid::build_from_uid") { - spec::Custom spec({ - {"uid", "d5bde4f52ff3a9bea5629cd9ac514410"}, - }); - - const auto footprint = Cache::total_footprint(); - - std::unique_ptr a(GridFactory::build(spec)); - - const auto footprint_a = Cache::total_footprint(); - EXPECT(footprint < footprint_a); - - std::unique_ptr b(GridFactory::build(spec)); - - const auto footprint_b = Cache::total_footprint(); - EXPECT_EQUAL(footprint_a, footprint_b); - - const auto size_a = a->size(); - const auto size_b = b->size(); - EXPECT_EQUAL(size_a, size_b); - } - } -#endif - - SECTION("Grid::build_from_increments (global)") { std::unique_ptr global(GridFactory::build(spec::Custom({ {"type", "regular_ll"}, diff --git a/tests/geo/grid_orca.cc b/tests/geo/grid_orca.cc index 3e4284e6f..7c0254b30 100644 --- a/tests/geo/grid_orca.cc +++ b/tests/geo/grid_orca.cc @@ -12,6 +12,8 @@ #include +#include "eckit/geo/Cache.h" +#include "eckit/geo/LibEcKitGeo.h" #include "eckit/geo/grid/ORCA.h" #include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" @@ -20,55 +22,83 @@ namespace eckit::geo::test { -CASE("ORCA") { - const Grid::uid_t uid = "d5bde4f52ff3a9bea5629cd9ac514410"; - const std::vector dimensions{182, 149}; +static const Grid::uid_t uid = "d5bde4f52ff3a9bea5629cd9ac514410"; +static const std::vector dimensions{182, 149}; - SECTION("gridspec") { +CASE("spec") { + std::unique_ptr spec(GridFactory::make_spec(spec::Custom({{"uid", uid}}))); - std::unique_ptr spec(GridFactory::make_spec(spec::Custom({{"uid", uid}}))); + EXPECT(spec->get_string("type") == "ORCA"); + EXPECT(spec->get_string("orca_name") == "ORCA2"); + EXPECT(spec->get_string("orca_arrangement") == "T"); + EXPECT(spec->get_string("orca_uid") == uid); + EXPECT(spec->get_long_vector("dimensions") == dimensions); - EXPECT(spec->get_string("type") == "ORCA"); - EXPECT(spec->get_string("orca_name") == "ORCA2"); - EXPECT(spec->get_string("orca_arrangement") == "T"); - EXPECT(spec->get_string("orca_uid") == uid); - EXPECT(spec->get_long_vector("dimensions") == dimensions); + std::unique_ptr grid1(GridFactory::make_from_string("{uid:" + uid + "}")); - std::unique_ptr grid1(GridFactory::make_from_string("{uid:" + uid + "}")); + EXPECT(grid1->size() == dimensions[0] * dimensions[1]); + EXPECT(grid1->uid() == uid); - EXPECT(grid1->size() == dimensions[0] * dimensions[1]); - EXPECT(grid1->uid() == uid); + std::unique_ptr grid2(GridFactory::build(spec::Custom({{"uid", uid}}))); - std::unique_ptr grid2(GridFactory::build(spec::Custom({{"uid", uid}}))); + EXPECT(grid2->size() == dimensions[0] * dimensions[1]); + EXPECT(grid2->uid() == uid); - EXPECT(grid2->size() == dimensions[0] * dimensions[1]); - EXPECT(grid2->uid() == uid); + grid::ORCA grid3(uid); - grid::ORCA grid3(uid); + EXPECT(grid3.uid() == uid); + EXPECT(grid3.calculate_uid() == uid); + EXPECT(static_cast(grid3).spec() == R"({"type":"ORCA","uid":")" + uid + R"("})"); - EXPECT(grid3.uid() == uid); - EXPECT(grid3.calculate_uid() == uid); - EXPECT(static_cast(grid3).spec() == R"({"type":"ORCA","uid":")" + uid + R"("})"); + EXPECT(grid1->spec() == grid2->spec()); - EXPECT(grid1->spec() == grid2->spec()); - } + std::unique_ptr grid4(GridFactory::build(spec::Custom({{"grid", "ORCA2_T"}}))); + + EXPECT(grid4->spec() == R"({"type":"ORCA","uid":")" + uid + R"("})"); + + std::unique_ptr grid5(GridFactory::build(spec::Custom({{"uid", uid}}))); + + EXPECT(grid4->spec() == grid5->spec()); +} + + +CASE("caching") { + if (LibEcKitGeo::caching()) { + std::unique_ptr spec(GridFactory::make_spec(spec::Custom({{"uid", uid}}))); + + const auto footprint = Cache::total_footprint(); + + std::unique_ptr grid1(GridFactory::build(*spec)); + + const auto footprint_1 = Cache::total_footprint(); + EXPECT(footprint < footprint_1); + std::unique_ptr grid2(GridFactory::build(*spec)); - SECTION("equals") { - std::unique_ptr grid1(GridFactory::make_from_string("{uid:" + uid + "}")); - std::unique_ptr grid2(GridFactory::build(spec::Custom({{"uid", uid}}))); - std::unique_ptr grid3(GridFactory::build(spec::Custom({{"grid", uid}}))); - grid::ORCA grid4(uid); + const auto footprint_2 = Cache::total_footprint(); + EXPECT_EQUAL(footprint_1, footprint_2); - EXPECT(*grid1 == *grid2); - EXPECT(*grid2 == *grid3); - EXPECT(*grid3 == grid4); - EXPECT(grid4 == *grid1); + const auto size_a = grid1->size(); + const auto size_b = grid2->size(); + EXPECT_EQUAL(size_a, size_b); } } +CASE("equals") { + std::unique_ptr grid1(GridFactory::make_from_string("{uid:" + uid + "}")); + std::unique_ptr grid2(GridFactory::build(spec::Custom({{"uid", uid}}))); + std::unique_ptr grid3(GridFactory::build(spec::Custom({{"grid", uid}}))); + grid::ORCA grid4(uid); + + EXPECT(*grid1 == *grid2); + EXPECT(*grid2 == *grid3); + EXPECT(*grid3 == grid4); + EXPECT(grid4 == *grid1); +} + + } // namespace eckit::geo::test diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index b5a7e8bff..9b72a9e51 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -441,21 +441,6 @@ CASE("spec") { EXPECT(h2n->spec() == R"({"grid":"H2","ordering":"nested"})"); } - - -#if eckit_HAVE_GEO_GRID_ORCA - SECTION("grid: ORCA") { - Grid::uid_t uid = "d5bde4f52ff3a9bea5629cd9ac514410"; - - std::unique_ptr o1(GridFactory::build(spec::Custom({{"grid", "ORCA2_T"}}))); - - EXPECT(o1->spec() == R"({"type":"ORCA","uid":")" + uid + R"("})"); - - std::unique_ptr o2(GridFactory::build(spec::Custom({{"uid", uid}}))); - - EXPECT(o1->spec() == o2->spec()); - } -#endif } From 16da8996148d5ef70f81edc57afdca891c644b3d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 29 May 2024 23:24:29 +0100 Subject: [PATCH 680/737] eckit::geo ORCA --- tests/geo/grid_orca.cc | 45 +++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/tests/geo/grid_orca.cc b/tests/geo/grid_orca.cc index 7c0254b30..1fae15109 100644 --- a/tests/geo/grid_orca.cc +++ b/tests/geo/grid_orca.cc @@ -26,6 +26,28 @@ static const Grid::uid_t uid = "d5bde4f52ff3a9bea5629cd9ac514410"; static const std::vector dimensions{182, 149}; +CASE("caching") { + if (LibEcKitGeo::caching()) { + SECTION("Grid::build_from_uid") { + spec::Custom spec({{"uid", uid}}); + + const auto footprint_1 = Cache::total_footprint(); + + std::unique_ptr grid1(GridFactory::build(spec)); + + const auto footprint_2 = Cache::total_footprint(); + EXPECT(footprint_1 < footprint_2); + + std::unique_ptr grid2(GridFactory::build(spec)); + + EXPECT(footprint_2 == Cache::total_footprint()); + + EXPECT(grid1->size() == grid2->size()); + } + } +} + + CASE("spec") { std::unique_ptr spec(GridFactory::make_spec(spec::Custom({{"uid", uid}}))); @@ -63,29 +85,6 @@ CASE("spec") { } -CASE("caching") { - if (LibEcKitGeo::caching()) { - std::unique_ptr spec(GridFactory::make_spec(spec::Custom({{"uid", uid}}))); - - const auto footprint = Cache::total_footprint(); - - std::unique_ptr grid1(GridFactory::build(*spec)); - - const auto footprint_1 = Cache::total_footprint(); - EXPECT(footprint < footprint_1); - - std::unique_ptr grid2(GridFactory::build(*spec)); - - const auto footprint_2 = Cache::total_footprint(); - EXPECT_EQUAL(footprint_1, footprint_2); - - const auto size_a = grid1->size(); - const auto size_b = grid2->size(); - EXPECT_EQUAL(size_a, size_b); - } -} - - CASE("equals") { std::unique_ptr grid1(GridFactory::make_from_string("{uid:" + uid + "}")); std::unique_ptr grid2(GridFactory::build(spec::Custom({{"uid", uid}}))); From b0c405a663db589fe67e020cbb27385045cfb6bc Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 May 2024 09:00:33 +0100 Subject: [PATCH 681/737] Testing --- src/tools/eckit-grid-spec.cc | 12 +----------- tests/geo/CMakeLists.txt | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/tools/eckit-grid-spec.cc b/src/tools/eckit-grid-spec.cc index a0ea7ac3e..1be9b128c 100644 --- a/src/tools/eckit-grid-spec.cc +++ b/src/tools/eckit-grid-spec.cc @@ -10,16 +10,13 @@ #include -#include #include #include -#include "eckit/exception/Exceptions.h" #include "eckit/geo/Grid.h" #include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" #include "eckit/option/EckitTool.h" -#include "eckit/option/SimpleOption.h" #include "eckit/parser/YAMLParser.h" @@ -27,9 +24,7 @@ namespace eckit { class EckitGridSpec final : public EckitTool { public: - EckitGridSpec(int argc, char** argv) : EckitTool(argc, argv) { - options_.push_back(new option::SimpleOption("check", "regex to check against result")); - } + EckitGridSpec(int argc, char** argv) : EckitTool(argc, argv) {} private: void execute(const option::CmdArgs& args) override { @@ -49,11 +44,6 @@ class EckitGridSpec final : public EckitTool { std::unique_ptr grid(geo::GridFactory::make_from_string(user)); auto spec = grid->spec(); Log::info() << spec << std::endl; - - if (std::string check; args.get("check", check)) { - std::regex regex(check); - ASSERT_MSG(std::regex_match(spec, regex), "Check failed: '" + check + "'"); - } } void usage(const std::string& tool) const override { diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index fc9247a06..2f21fc25f 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -62,9 +62,19 @@ endif() ecbuild_add_test( TARGET eckit_test_geo_tool_grid_spec_1_1 - COMMAND eckit_grid_spec ARGS "grid: 1/1.0" [=[--check=[{]"grid":\[1,1\][}]]=] ) + COMMAND eckit_grid_spec ARGS "grid: 1/1.0" ) + +set_tests_properties( + eckit_test_geo_tool_grid_spec_1_1 + PROPERTIES + PASS_REGULAR_EXPRESSION [=[{"grid":\[1,1\]}]=] ) ecbuild_add_test( TARGET eckit_test_geo_tool_grid_spec_025_01 - COMMAND eckit_grid_spec ARGS "grid: .250/001e-1" [=[--check=[{]"grid":\[0\.25,0\.1\][}]]=] ) + COMMAND eckit_grid_spec ARGS "grid: .250/001e-1" ) + +set_tests_properties( + eckit_test_geo_tool_grid_spec_025_01 + PROPERTIES + PASS_REGULAR_EXPRESSION [=[{"grid":\[0\.25,0\.1\]}]=] ) From 14bdfc848fe5f850c677f77bb852d2a86dba0230 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 May 2024 10:56:00 +0100 Subject: [PATCH 682/737] Fix warnings --- src/eckit/option/EckitTool.cc | 30 +++++++++--------------------- src/eckit/option/EckitTool.h | 11 +++++------ 2 files changed, 14 insertions(+), 27 deletions(-) diff --git a/src/eckit/option/EckitTool.cc b/src/eckit/option/EckitTool.cc index 0d34ce379..69146f7c7 100644 --- a/src/eckit/option/EckitTool.cc +++ b/src/eckit/option/EckitTool.cc @@ -11,46 +11,34 @@ #include "EckitTool.h" #include "eckit/exception/Exceptions.h" -#include "eckit/log/Log.h" #include "eckit/option/CmdArgs.h" namespace eckit { //---------------------------------------------------------------------------------------------------------------------- -static EckitTool* instance_ = 0; +static EckitTool* INSTANCE = nullptr; -EckitTool::EckitTool(int argc, char** argv) : - eckit::Tool(argc, argv, "ECKIT_HOME") { - ASSERT(instance_ == 0); - instance_ = this; +static void usage(const std::string& tool) { + ASSERT(INSTANCE != nullptr); + INSTANCE->usage(tool); } -static void usage(const std::string& tool) { - ASSERT(instance_); - instance_->usage(tool); +EckitTool::EckitTool(int argc, char** argv) : Tool(argc, argv, "ECKIT_HOME") { + ASSERT(INSTANCE == nullptr); + INSTANCE = this; } void EckitTool::run() { - - eckit::option::CmdArgs args(&eckit::usage, - options_, - numberOfPositionalArguments(), - minimumPositionalArguments()); + option::CmdArgs args(&eckit::usage, options_, numberOfPositionalArguments(), minimumPositionalArguments()); init(args); execute(args); finish(args); } -void EckitTool::usage(const std::string& tool) const { -} +void EckitTool::usage(const std::string& tool) const {} -void EckitTool::init(const eckit::option::CmdArgs& args) { -} - -void EckitTool::finish(const eckit::option::CmdArgs& args) { -} //---------------------------------------------------------------------------------------------------------------------- diff --git a/src/eckit/option/EckitTool.h b/src/eckit/option/EckitTool.h index 58f5e786b..3d4f5a0f1 100644 --- a/src/eckit/option/EckitTool.h +++ b/src/eckit/option/EckitTool.h @@ -15,7 +15,6 @@ #pragma once -#include "eckit/filesystem/PathName.h" #include "eckit/option/Option.h" #include "eckit/runtime/Tool.h" @@ -28,7 +27,7 @@ class CmdArgs; //---------------------------------------------------------------------------------------------------------------------- -class EckitTool : public eckit::Tool { +class EckitTool : public Tool { protected: // methods EckitTool(int argc, char** argv); @@ -40,14 +39,14 @@ class EckitTool : public eckit::Tool { std::vector options_; private: // methods - virtual void init(const eckit::option::CmdArgs& args); - virtual void execute(const eckit::option::CmdArgs& args) = 0; - virtual void finish(const eckit::option::CmdArgs& args); + virtual void init(const option::CmdArgs&) {} + virtual void execute(const option::CmdArgs&) = 0; + virtual void finish(const option::CmdArgs&) {} virtual int numberOfPositionalArguments() const { return -1; } virtual int minimumPositionalArguments() const { return -1; } - virtual void run(); + void run() override; }; //---------------------------------------------------------------------------------------------------------------------- From 1bbe518b3fa0d055ae90570050a37c57ad1c8a93 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 May 2024 12:21:56 +0100 Subject: [PATCH 683/737] eckit::geo::Spec --- src/eckit/geo/Grid.cc | 31 ++++++++++++++++++++++++------ src/eckit/geo/Grid.h | 22 ++++++++++++--------- src/eckit/geo/grid/ORCA.h | 4 +--- src/eckit/geo/grid/Unstructured.cc | 5 ----- src/eckit/geo/grid/Unstructured.h | 1 - src/tools/eckit-grid-spec.cc | 2 +- src/tools/eckit-grid.cc | 2 +- tests/geo/grid_orca.cc | 10 ++++++---- tests/geo/spec.cc | 16 +++++++-------- 9 files changed, 55 insertions(+), 38 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 9b1a10e76..8b378b479 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -18,7 +18,6 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/etc/Grid.h" -#include "eckit/geo/spec/Custom.h" #include "eckit/geo/spec/Layered.h" #include "eckit/geo/util/mutex.h" #include "eckit/log/Log.h" @@ -43,10 +42,23 @@ Grid::Grid(const Spec& spec) : bbox_(area::BoundingBox::make_from_spec(spec)) {} Grid::Grid(const area::BoundingBox& bbox) : bbox_(new area::BoundingBox(bbox)) {} -std::string Grid::spec() const { - spec::Custom gridspec; - this->spec(gridspec); - return gridspec.str(); +const Spec& Grid::spec() const { + if (!spec_) { + spec_.reset(calculate_spec()); + } + + ASSERT(spec_); + return *spec_; +} + + +spec::Custom* Grid::calculate_spec() const { + auto* custom = new spec::Custom; + ASSERT(custom != nullptr); + + spec(*custom); + + return custom; } @@ -56,7 +68,14 @@ size_t Grid::size() const { Grid::uid_t Grid::uid() const { - return MD5(spec()); + return uid_.empty() ? (uid_ = calculate_uid()) : uid_; +} + + +Grid::uid_t Grid::calculate_uid() const { + auto id = MD5{spec_str()}.digest(); + ASSERT(id.length() == MD5_DIGEST_LENGTH * 2); + return id; } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 86998fef3..3ab8170aa 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -26,6 +26,7 @@ #include "eckit/geo/Projection.h" #include "eckit/geo/Renumber.h" #include "eckit/geo/area/BoundingBox.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/geo/spec/Generator.h" #include "eckit/memory/Builder.h" #include "eckit/memory/Factory.h" @@ -35,10 +36,6 @@ namespace eckit { class JSON; namespace geo { class Area; -class Spec; -namespace spec { -class Custom; -} } // namespace geo } // namespace eckit @@ -108,17 +105,21 @@ class Grid { virtual iterator cbegin() const = 0; virtual iterator cend() const = 0; - std::string spec() const; + const Spec& spec() const; + std::string spec_str() const { return spec().str(); } + [[nodiscard]] virtual spec::Custom* calculate_spec() const; virtual size_t size() const; - virtual uid_t uid() const; + + uid_t uid() const; + [[nodiscard]] virtual uid_t calculate_uid() const; virtual bool includesNorthPole() const; virtual bool includesSouthPole() const; virtual bool isPeriodicWestEast() const; - virtual std::vector to_points() const; - virtual std::pair, std::vector> to_latlon() const; + [[nodiscard]] virtual std::vector to_points() const; + [[nodiscard]] virtual std::pair, std::vector> to_latlon() const; virtual Ordering order() const; virtual Renumber reorder(Ordering) const; @@ -150,6 +151,9 @@ class Grid { // -- Members mutable std::unique_ptr bbox_; + mutable std::unique_ptr spec_; + mutable uid_t uid_; + std::unique_ptr projection_; // -- Methods @@ -160,7 +164,7 @@ class Grid { // -- Friends - friend bool operator==(const Grid& a, const Grid& b) { return a.spec() == b.spec(); } + friend bool operator==(const Grid& a, const Grid& b) { return a.spec_str() == b.spec_str(); } friend bool operator!=(const Grid& a, const Grid& b) { return !(a == b); } }; diff --git a/src/eckit/geo/grid/ORCA.h b/src/eckit/geo/grid/ORCA.h index 8b21ad635..a08c5ada6 100644 --- a/src/eckit/geo/grid/ORCA.h +++ b/src/eckit/geo/grid/ORCA.h @@ -76,14 +76,12 @@ class ORCA final : public Regular { std::string name() const { return name_; } std::string arrangement() const; - uid_t calculate_uid() const; - // -- Overridden methods iterator cbegin() const override; iterator cend() const override; - uid_t uid() const override { return uid_; } + uid_t calculate_uid() const override; bool includesNorthPole() const override { return true; } bool includesSouthPole() const override { return true; } // FIXME: not sure this is semanticaly correct diff --git a/src/eckit/geo/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc index c79846299..cf477256e 100644 --- a/src/eckit/geo/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -44,9 +44,4 @@ void Unstructured::spec(spec::Custom& custom) const { } -Grid::uid_t Unstructured::uid() const { - NOTIMP; -} - - } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h index e247966cd..ed7bc68ad 100644 --- a/src/eckit/geo/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -37,7 +37,6 @@ class Unstructured final : public Grid { iterator cend() const override; size_t size() const override { return points_.size(); } - uid_t uid() const override; bool includesNorthPole() const override { return true; } bool includesSouthPole() const override { return true; } diff --git a/src/tools/eckit-grid-spec.cc b/src/tools/eckit-grid-spec.cc index 1be9b128c..a2953ffae 100644 --- a/src/tools/eckit-grid-spec.cc +++ b/src/tools/eckit-grid-spec.cc @@ -42,7 +42,7 @@ class EckitGridSpec final : public EckitTool { } std::unique_ptr grid(geo::GridFactory::make_from_string(user)); - auto spec = grid->spec(); + auto spec = grid->spec_str(); Log::info() << spec << std::endl; } diff --git a/src/tools/eckit-grid.cc b/src/tools/eckit-grid.cc index 1beba116a..4fe4594bf 100644 --- a/src/tools/eckit-grid.cc +++ b/src/tools/eckit-grid.cc @@ -59,7 +59,7 @@ class EckitGrid final : public EckitTool { return geo::GridFactory::build(*spec); }(user)); - out << "spec" << grid->spec(); + out << "spec" << grid->spec_str(); out << "uid" << grid->uid(); out << "size" << grid->size(); diff --git a/tests/geo/grid_orca.cc b/tests/geo/grid_orca.cc index 1fae15109..b4be928ef 100644 --- a/tests/geo/grid_orca.cc +++ b/tests/geo/grid_orca.cc @@ -69,19 +69,21 @@ CASE("spec") { grid::ORCA grid3(uid); + const std::string expected_spec_str = R"({"type":"ORCA","uid":")" + uid + R"("})"; + EXPECT(grid3.uid() == uid); EXPECT(grid3.calculate_uid() == uid); - EXPECT(static_cast(grid3).spec() == R"({"type":"ORCA","uid":")" + uid + R"("})"); + EXPECT(static_cast(grid3).spec_str() == expected_spec_str); - EXPECT(grid1->spec() == grid2->spec()); + EXPECT(grid1->spec_str() == grid2->spec_str()); std::unique_ptr grid4(GridFactory::build(spec::Custom({{"grid", "ORCA2_T"}}))); - EXPECT(grid4->spec() == R"({"type":"ORCA","uid":")" + uid + R"("})"); + EXPECT(grid4->spec_str() == expected_spec_str); std::unique_ptr grid5(GridFactory::build(spec::Custom({{"uid", uid}}))); - EXPECT(grid4->spec() == grid5->spec()); + EXPECT(*grid4 == *grid5); } diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 9b72a9e51..40e027d09 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -399,7 +399,7 @@ CASE("spec") { std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", name}}))); EXPECT(grid); - auto gridspec = grid->spec(); + auto gridspec = grid->spec_str(); EXPECT(gridspec == R"({"grid":")" + name + R"("})"); } } @@ -408,38 +408,38 @@ CASE("spec") { SECTION("grid: reduced_gg") { std::unique_ptr o16(GridFactory::build(spec::Custom({{"grid", "o16"}}))); - EXPECT(o16->spec() == R"({"grid":"O16"})"); + EXPECT(o16->spec_str() == R"({"grid":"O16"})"); std::unique_ptr n16(GridFactory::build(spec::Custom({{"grid", "n16"}}))); - EXPECT(n16->spec() == R"({"grid":"N16"})"); + EXPECT(n16->spec_str() == R"({"grid":"N16"})"); std::unique_ptr known_pl_1(GridFactory::build( spec::Custom({{"pl", pl_type{20, 27, 32, 40, 45, 48, 60, 60, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 60, 60, 48, 45, 40, 32, 27, 20}}}))); - EXPECT(known_pl_1->spec() == R"({"grid":"N16"})"); + EXPECT(known_pl_1->spec_str() == R"({"grid":"N16"})"); std::unique_ptr known_pl_2( GridFactory::build(spec::Custom({{"pl", pl_type{20, 24, 28, 32, 32, 28, 24, 20}}}))); - EXPECT(known_pl_2->spec() == R"({"grid":"O4"})"); + EXPECT(known_pl_2->spec_str() == R"({"grid":"O4"})"); std::unique_ptr unknown_pl( GridFactory::build(spec::Custom({{"pl", pl_type{20, 24, 28, 32, 32, 28, 24, 99}}}))); - EXPECT(unknown_pl->spec() == R"({"grid":"N4","pl":[20,24,28,32,32,28,24,99]})"); + EXPECT(unknown_pl->spec_str() == R"({"grid":"N4","pl":[20,24,28,32,32,28,24,99]})"); } SECTION("grid: HEALPix") { std::unique_ptr h2(GridFactory::build(spec::Custom({{"grid", "h2"}}))); - EXPECT(h2->spec() == R"({"grid":"H2","ordering":"ring"})"); + EXPECT(h2->spec_str() == R"({"grid":"H2","ordering":"ring"})"); std::unique_ptr h2n(GridFactory::build(spec::Custom({{"grid", "H2"}, {"ordering", "nested"}}))); - EXPECT(h2n->spec() == R"({"grid":"H2","ordering":"nested"})"); + EXPECT(h2n->spec_str() == R"({"grid":"H2","ordering":"nested"})"); } } From a095b79075865f520acfa2f70557aa2c4d2b0361 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 May 2024 15:52:57 +0100 Subject: [PATCH 684/737] Testing --- tests/geo/pointlonlat.cc | 243 ++++++++++++++++++++------------------- 1 file changed, 125 insertions(+), 118 deletions(-) diff --git a/tests/geo/pointlonlat.cc b/tests/geo/pointlonlat.cc index 8fcfd0dd4..5088dbef4 100644 --- a/tests/geo/pointlonlat.cc +++ b/tests/geo/pointlonlat.cc @@ -64,116 +64,137 @@ CASE("PointLonLat normalise_angle_to_*") { test.ref, PointLonLat::normalise_angle_to_maximum(test.angle, test.lim), PointLonLat::EPS)); } } +} + + +CASE("PointLonLat antipode") { + PointLonLat p(300., -10.); + auto q = p.antipode(); + + EXPECT(points_equal(q, {120., 10.})); + EXPECT(points_equal(p, q.antipode())); + + PointLonLat r(-10., -91.); + + EXPECT(points_equal(r.antipode(), {350., 89.})); + EXPECT(points_equal(r, r.antipode().antipode())); + + PointLonLat s(1., -90.); + auto t = s.antipode(); + + EXPECT_EQUAL(t.lon, 0.); + EXPECT(points_equal(t, {2., 90.})); + EXPECT(points_equal(t.antipode(), s)); +} #if eckit_HAVE_GEO_BITREPRODUCIBLE - SECTION("bit-identical behaviour normalising angles") { - auto normalise = [](double a, double minimum) -> double { - auto modulo_360 = [](double a) { return a - 360. * std::floor(a / 360.); }; - auto diff = a - minimum; - return 0. <= diff && diff < 360. ? a : modulo_360(diff) + minimum; - }; - - struct test_t { - double angle; - double ref_norm_angle_m_360; - double ref_norm_angle_m_720; - double ref_norm_angle_p_360; - double ref_norm_angle_p_720; - }; +CASE("bit-identical behaviour normalising angles") { + auto normalise = [](double a, double minimum) -> double { + auto modulo_360 = [](double a) { return a - 360. * std::floor(a / 360.); }; + auto diff = a - minimum; + return 0. <= diff && diff < 360. ? a : modulo_360(diff) + minimum; + }; - for (const auto& test : { - test_t{0x1.a99999999999fp+3, 0x1.a9999999999ap+3, 0x1.a99999999998p+3, 0x1.a99999999998p+3, - 0x1.a99999999998p+3}, // 13.30000000000001 - {0x1.7599999999999p+5, 0x1.7599999999998p+5, 0x1.75999999999ap+5, 0x1.75999999999ap+5, - 0x1.75999999999ap+5}, // 46.699999999999996 - {-0x1.37823af2187f7p+4, -0x1.37823af2187fp+4, -0x1.37823af2188p+4, -0x1.37823af2188p+4, - -0x1.37823af2188p+4}, //-19.469294496237094 - {0x1.14f26c8adc252p+3, 0x1.14f26c8adc26p+3, 0x1.14f26c8adc24p+3, 0x1.14f26c8adc28p+3, - 0x1.14f26c8adc24p+3}, // 8.6545927726848824 - {0x1.237e9f537dd2dp+5, 0x1.237e9f537dd3p+5, 0x1.237e9f537dd3p+5, 0x1.237e9f537dd3p+5, - 0x1.237e9f537dd3p+5}, // 36.436827327992752 - {0x1.eb74b977e1e89p+5, 0x1.eb74b977e1e88p+5, 0x1.eb74b977e1e9p+5, 0x1.eb74b977e1e8p+5, - 0x1.eb74b977e1e9p+5}, // 61.431994377690962 - {0x1.1008717af4f67p+6, 0x1.1008717af4f68p+6, 0x1.1008717af4f68p+6, 0x1.1008717af4f68p+6, - 0x1.1008717af4f68p+6}, // 68.008245392991384 - {-0x1.b4f88656270d9p+4, -0x1.b4f88656270ep+4, -0x1.b4f88656270ep+4, -0x1.b4f88656270ep+4, - -0x1.b4f88656270ep+4}, //-27.31067498830166 - {-0x1.eb22f87f6ac12p+1, -0x1.eb22f87f6acp+1, -0x1.eb22f87f6acp+1, -0x1.eb22f87f6acp+1, - -0x1.eb22f87f6acp+1}, //-3.8370047208932272 - {0x1.40de11e0c3e99p+4, 0x1.40de11e0c3eap+4, 0x1.40de11e0c3eap+4, 0x1.40de11e0c3eap+4, - 0x1.40de11e0c3eap+4}, // 20.054216268529306 - {0x1.4aeba99be1331p+5, 0x1.4aeba99be133p+5, 0x1.4aeba99be133p+5, 0x1.4aeba99be133p+5, - 0x1.4aeba99be133p+5}, // 41.365069597063105 - {0x1.aa5c50f727ae6p+5, 0x1.aa5c50f727ae8p+5, 0x1.aa5c50f727aep+5, 0x1.aa5c50f727aep+5, - 0x1.aa5c50f727aep+5}, // 53.295076304338906 - {-0x1.556ccf04ef1bbp+4, -0x1.556ccf04ef1cp+4, -0x1.556ccf04ef1cp+4, -0x1.556ccf04ef1cp+4, - -0x1.556ccf04ef1cp+4}, //-21.339064616464139 - {0x1.556ccf04ef1bbp+4, 0x1.556ccf04ef1cp+4, 0x1.556ccf04ef1cp+4, 0x1.556ccf04ef1cp+4, - 0x1.556ccf04ef1cp+4}, // 21.339064616464139 - {0x1.388f683df92bbp+5, 0x1.388f683df92b8p+5, 0x1.388f683df92cp+5, 0x1.388f683df92cp+5, - 0x1.388f683df92cp+5}, // 39.070023044745049 - {-0x1.40de11e0c3e9dp+4, -0x1.40de11e0c3eap+4, -0x1.40de11e0c3eap+4, -0x1.40de11e0c3eap+4, - -0x1.40de11e0c3eap+4}, //-20.05421626852932 - {0x1.eb22f87f6abf5p+1, 0x1.eb22f87f6acp+1, 0x1.eb22f87f6acp+1, 0x1.eb22f87f6acp+1, - 0x1.eb22f87f6acp+1}, // 3.8370047208932143 - {0x1.b4f88656270d7p+4, 0x1.b4f88656270dp+4, 0x1.b4f88656270ep+4, 0x1.b4f88656270cp+4, - 0x1.b4f88656270ep+4}, // 27.310674988301653 - {-0x1.3f0f4411db559p+5, -0x1.3f0f4411db558p+5, -0x1.3f0f4411db56p+5, -0x1.3f0f4411db558p+5, - -0x1.3f0f4411db56p+5}, //-39.882454051500368 - {-0x1.63664f7d2181dp+5, -0x1.63664f7d2182p+5, -0x1.63664f7d2182p+5, -0x1.63664f7d2182p+5, - -0x1.63664f7d2182p+5}, //-44.424956300339751 - {-0x1.75e470fd085aap+5, -0x1.75e470fd085a8p+5, -0x1.75e470fd085bp+5, -0x1.75e470fd085a8p+5, - -0x1.75e470fd085bp+5}, //-46.7365436332869 - {-0x1.b2a6314996231p+4, -0x1.b2a631499623p+4, -0x1.b2a631499624p+4, -0x1.b2a631499624p+4, - -0x1.b2a631499624p+4}, //-27.165574347922476 - {-0x1.f720e2a9525edp+5, -0x1.f720e2a9525fp+5, -0x1.f720e2a9525fp+5, -0x1.f720e2a9525fp+5, - -0x1.f720e2a9525fp+5}, //-62.89105732233643 - {-0x1.236723c039272p+5, -0x1.236723c03927p+5, -0x1.236723c03927p+5, -0x1.236723c03927p+5, - -0x1.236723c03927p+5}, //-36.425361158126989 - {-0x1.7f9f1a40a5d1fp+4, -0x1.7f9f1a40a5d2p+4, -0x1.7f9f1a40a5d2p+4, -0x1.7f9f1a40a5d2p+4, - -0x1.7f9f1a40a5d2p+4}, //-23.976343395738805 - {0x1.ffffffffffffep+0, 0x1p+1, 0x1p+1, 0x1p+1, 0x1p+1}, // 1.9999999999999996 - {0x1.0b907154a92f7p+6, 0x1.0b907154a92f8p+6, 0x1.0b907154a92f8p+6, 0x1.0b907154a92f8p+6, - 0x1.0b907154a92f8p+6}, // 66.891057322336437 - {0x1.436723c039272p+5, 0x1.436723c03927p+5, 0x1.436723c03927p+5, 0x1.436723c03927p+5, - 0x1.436723c03927p+5}, // 40.425361158126989 - {0x1.bf9f1a40a5d1fp+4, 0x1.bf9f1a40a5d2p+4, 0x1.bf9f1a40a5d2p+4, 0x1.bf9f1a40a5d2p+4, - 0x1.bf9f1a40a5d2p+4}, // 27.976343395738805 - {0x1.0f266c20b79f9p+7, 0x1.0f266c20b79f8p+7, 0x1.0f266c20b79f8p+7, 0x1.0f266c20b79f8p+7, - 0x1.0f266c20b79f8p+7}, // 135.57504369966026 - {0x1.787bbbb54c676p+6, 0x1.787bbbb54c678p+6, 0x1.787bbbb54c678p+6, 0x1.787bbbb54c678p+6, - 0x1.787bbbb54c678p+6}, // 94.120833237446135 - {0x1.95e470fd085aap+5, 0x1.95e470fd085a8p+5, 0x1.95e470fd085bp+5, 0x1.95e470fd085ap+5, - 0x1.95e470fd085bp+5}, // 50.7365436332869 - {0x1.1bd0dd7b42b69p+7, 0x1.1bd0dd7b42b68p+7, 0x1.1bd0dd7b42b68p+7, 0x1.1bd0dd7b42b68p+7, - 0x1.1bd0dd7b42b68p+7}, // 141.90793976964349 - {0x1.19981bd70b549p+6, 0x1.19981bd70b548p+6, 0x1.19981bd70b548p+6, 0x1.19981bd70b548p+6, - 0x1.19981bd70b548p+6}, // 70.39854370123534 - {0x1.50bc8a12f525bp+5, 0x1.50bc8a12f5258p+5, 0x1.50bc8a12f526p+5, 0x1.50bc8a12f526p+5, - 0x1.50bc8a12f526p+5}, // 42.092060230356502 - {0x1.cb2a2664f7bbdp+6, 0x1.cb2a2664f7bbcp+6, 0x1.cb2a2664f7bcp+6, 0x1.cb2a2664f7bcp+6, - 0x1.cb2a2664f7bcp+6}, // 114.79116208803221 - {0x1.6784444ab398ap+6, 0x1.6784444ab3988p+6, 0x1.6784444ab3988p+6, 0x1.6784444ab3988p+6, - 0x1.6784444ab3988p+6}, // 89.879166762553865 - {0x1.83664f7d2181ep+5, 0x1.83664f7d2182p+5, 0x1.83664f7d2182p+5, 0x1.83664f7d2182p+5, - 0x1.83664f7d2182p+5}, // 48.424956300339758 - {0x1.380c1cb7eb45dp+7, 0x1.380c1cb7eb45cp+7, 0x1.380c1cb7eb45cp+7, 0x1.380c1cb7eb45cp+7, - 0x1.380c1cb7eb46p+7}, // 156.02365660426122 - {0x1.d46f8eab56d0bp+6, 0x1.d46f8eab56d0cp+6, 0x1.d46f8eab56d08p+6, 0x1.d46f8eab56d1p+6, - 0x1.d46f8eab56d08p+6}, // 117.10894267766359 - {0x1.5f0f4411db559p+5, 0x1.5f0f4411db558p+5, 0x1.5f0f4411db56p+5, 0x1.5f0f4411db56p+5, - 0x1.5f0f4411db56p+5}, // 43.882454051500368 - }) { - EXPECT(test.angle == normalise(test.angle, -180.)); - EXPECT(test.ref_norm_angle_m_360 == normalise(test.angle - 360., -180.)); - EXPECT(test.ref_norm_angle_m_720 == normalise(test.angle - 720., -180.)); - EXPECT(test.ref_norm_angle_p_360 == normalise(test.angle + 360., -180.)); - EXPECT(test.ref_norm_angle_p_720 == normalise(test.angle + 720., -180.)); - } + struct test_t { + double angle; + double ref_norm_angle_m_360; + double ref_norm_angle_m_720; + double ref_norm_angle_p_360; + double ref_norm_angle_p_720; + }; + + for (const auto& test : { + test_t{0x1.a99999999999fp+3, 0x1.a9999999999ap+3, 0x1.a99999999998p+3, 0x1.a99999999998p+3, + 0x1.a99999999998p+3}, // 13.30000000000001 + {0x1.7599999999999p+5, 0x1.7599999999998p+5, 0x1.75999999999ap+5, 0x1.75999999999ap+5, + 0x1.75999999999ap+5}, // 46.699999999999996 + {-0x1.37823af2187f7p+4, -0x1.37823af2187fp+4, -0x1.37823af2188p+4, -0x1.37823af2188p+4, + -0x1.37823af2188p+4}, //-19.469294496237094 + {0x1.14f26c8adc252p+3, 0x1.14f26c8adc26p+3, 0x1.14f26c8adc24p+3, 0x1.14f26c8adc28p+3, + 0x1.14f26c8adc24p+3}, // 8.6545927726848824 + {0x1.237e9f537dd2dp+5, 0x1.237e9f537dd3p+5, 0x1.237e9f537dd3p+5, 0x1.237e9f537dd3p+5, + 0x1.237e9f537dd3p+5}, // 36.436827327992752 + {0x1.eb74b977e1e89p+5, 0x1.eb74b977e1e88p+5, 0x1.eb74b977e1e9p+5, 0x1.eb74b977e1e8p+5, + 0x1.eb74b977e1e9p+5}, // 61.431994377690962 + {0x1.1008717af4f67p+6, 0x1.1008717af4f68p+6, 0x1.1008717af4f68p+6, 0x1.1008717af4f68p+6, + 0x1.1008717af4f68p+6}, // 68.008245392991384 + {-0x1.b4f88656270d9p+4, -0x1.b4f88656270ep+4, -0x1.b4f88656270ep+4, -0x1.b4f88656270ep+4, + -0x1.b4f88656270ep+4}, //-27.31067498830166 + {-0x1.eb22f87f6ac12p+1, -0x1.eb22f87f6acp+1, -0x1.eb22f87f6acp+1, -0x1.eb22f87f6acp+1, + -0x1.eb22f87f6acp+1}, //-3.8370047208932272 + {0x1.40de11e0c3e99p+4, 0x1.40de11e0c3eap+4, 0x1.40de11e0c3eap+4, 0x1.40de11e0c3eap+4, + 0x1.40de11e0c3eap+4}, // 20.054216268529306 + {0x1.4aeba99be1331p+5, 0x1.4aeba99be133p+5, 0x1.4aeba99be133p+5, 0x1.4aeba99be133p+5, + 0x1.4aeba99be133p+5}, // 41.365069597063105 + {0x1.aa5c50f727ae6p+5, 0x1.aa5c50f727ae8p+5, 0x1.aa5c50f727aep+5, 0x1.aa5c50f727aep+5, + 0x1.aa5c50f727aep+5}, // 53.295076304338906 + {-0x1.556ccf04ef1bbp+4, -0x1.556ccf04ef1cp+4, -0x1.556ccf04ef1cp+4, -0x1.556ccf04ef1cp+4, + -0x1.556ccf04ef1cp+4}, //-21.339064616464139 + {0x1.556ccf04ef1bbp+4, 0x1.556ccf04ef1cp+4, 0x1.556ccf04ef1cp+4, 0x1.556ccf04ef1cp+4, + 0x1.556ccf04ef1cp+4}, // 21.339064616464139 + {0x1.388f683df92bbp+5, 0x1.388f683df92b8p+5, 0x1.388f683df92cp+5, 0x1.388f683df92cp+5, + 0x1.388f683df92cp+5}, // 39.070023044745049 + {-0x1.40de11e0c3e9dp+4, -0x1.40de11e0c3eap+4, -0x1.40de11e0c3eap+4, -0x1.40de11e0c3eap+4, + -0x1.40de11e0c3eap+4}, //-20.05421626852932 + {0x1.eb22f87f6abf5p+1, 0x1.eb22f87f6acp+1, 0x1.eb22f87f6acp+1, 0x1.eb22f87f6acp+1, + 0x1.eb22f87f6acp+1}, // 3.8370047208932143 + {0x1.b4f88656270d7p+4, 0x1.b4f88656270dp+4, 0x1.b4f88656270ep+4, 0x1.b4f88656270cp+4, + 0x1.b4f88656270ep+4}, // 27.310674988301653 + {-0x1.3f0f4411db559p+5, -0x1.3f0f4411db558p+5, -0x1.3f0f4411db56p+5, -0x1.3f0f4411db558p+5, + -0x1.3f0f4411db56p+5}, //-39.882454051500368 + {-0x1.63664f7d2181dp+5, -0x1.63664f7d2182p+5, -0x1.63664f7d2182p+5, -0x1.63664f7d2182p+5, + -0x1.63664f7d2182p+5}, //-44.424956300339751 + {-0x1.75e470fd085aap+5, -0x1.75e470fd085a8p+5, -0x1.75e470fd085bp+5, -0x1.75e470fd085a8p+5, + -0x1.75e470fd085bp+5}, //-46.7365436332869 + {-0x1.b2a6314996231p+4, -0x1.b2a631499623p+4, -0x1.b2a631499624p+4, -0x1.b2a631499624p+4, + -0x1.b2a631499624p+4}, //-27.165574347922476 + {-0x1.f720e2a9525edp+5, -0x1.f720e2a9525fp+5, -0x1.f720e2a9525fp+5, -0x1.f720e2a9525fp+5, + -0x1.f720e2a9525fp+5}, //-62.89105732233643 + {-0x1.236723c039272p+5, -0x1.236723c03927p+5, -0x1.236723c03927p+5, -0x1.236723c03927p+5, + -0x1.236723c03927p+5}, //-36.425361158126989 + {-0x1.7f9f1a40a5d1fp+4, -0x1.7f9f1a40a5d2p+4, -0x1.7f9f1a40a5d2p+4, -0x1.7f9f1a40a5d2p+4, + -0x1.7f9f1a40a5d2p+4}, //-23.976343395738805 + {0x1.ffffffffffffep+0, 0x1p+1, 0x1p+1, 0x1p+1, 0x1p+1}, // 1.9999999999999996 + {0x1.0b907154a92f7p+6, 0x1.0b907154a92f8p+6, 0x1.0b907154a92f8p+6, 0x1.0b907154a92f8p+6, + 0x1.0b907154a92f8p+6}, // 66.891057322336437 + {0x1.436723c039272p+5, 0x1.436723c03927p+5, 0x1.436723c03927p+5, 0x1.436723c03927p+5, + 0x1.436723c03927p+5}, // 40.425361158126989 + {0x1.bf9f1a40a5d1fp+4, 0x1.bf9f1a40a5d2p+4, 0x1.bf9f1a40a5d2p+4, 0x1.bf9f1a40a5d2p+4, + 0x1.bf9f1a40a5d2p+4}, // 27.976343395738805 + {0x1.0f266c20b79f9p+7, 0x1.0f266c20b79f8p+7, 0x1.0f266c20b79f8p+7, 0x1.0f266c20b79f8p+7, + 0x1.0f266c20b79f8p+7}, // 135.57504369966026 + {0x1.787bbbb54c676p+6, 0x1.787bbbb54c678p+6, 0x1.787bbbb54c678p+6, 0x1.787bbbb54c678p+6, + 0x1.787bbbb54c678p+6}, // 94.120833237446135 + {0x1.95e470fd085aap+5, 0x1.95e470fd085a8p+5, 0x1.95e470fd085bp+5, 0x1.95e470fd085ap+5, + 0x1.95e470fd085bp+5}, // 50.7365436332869 + {0x1.1bd0dd7b42b69p+7, 0x1.1bd0dd7b42b68p+7, 0x1.1bd0dd7b42b68p+7, 0x1.1bd0dd7b42b68p+7, + 0x1.1bd0dd7b42b68p+7}, // 141.90793976964349 + {0x1.19981bd70b549p+6, 0x1.19981bd70b548p+6, 0x1.19981bd70b548p+6, 0x1.19981bd70b548p+6, + 0x1.19981bd70b548p+6}, // 70.39854370123534 + {0x1.50bc8a12f525bp+5, 0x1.50bc8a12f5258p+5, 0x1.50bc8a12f526p+5, 0x1.50bc8a12f526p+5, + 0x1.50bc8a12f526p+5}, // 42.092060230356502 + {0x1.cb2a2664f7bbdp+6, 0x1.cb2a2664f7bbcp+6, 0x1.cb2a2664f7bcp+6, 0x1.cb2a2664f7bcp+6, + 0x1.cb2a2664f7bcp+6}, // 114.79116208803221 + {0x1.6784444ab398ap+6, 0x1.6784444ab3988p+6, 0x1.6784444ab3988p+6, 0x1.6784444ab3988p+6, + 0x1.6784444ab3988p+6}, // 89.879166762553865 + {0x1.83664f7d2181ep+5, 0x1.83664f7d2182p+5, 0x1.83664f7d2182p+5, 0x1.83664f7d2182p+5, + 0x1.83664f7d2182p+5}, // 48.424956300339758 + {0x1.380c1cb7eb45dp+7, 0x1.380c1cb7eb45cp+7, 0x1.380c1cb7eb45cp+7, 0x1.380c1cb7eb45cp+7, + 0x1.380c1cb7eb46p+7}, // 156.02365660426122 + {0x1.d46f8eab56d0bp+6, 0x1.d46f8eab56d0cp+6, 0x1.d46f8eab56d08p+6, 0x1.d46f8eab56d1p+6, + 0x1.d46f8eab56d08p+6}, // 117.10894267766359 + {0x1.5f0f4411db559p+5, 0x1.5f0f4411db558p+5, 0x1.5f0f4411db56p+5, 0x1.5f0f4411db56p+5, + 0x1.5f0f4411db56p+5}, // 43.882454051500368 + }) { + EXPECT(test.angle == normalise(test.angle, -180.)); + EXPECT(test.ref_norm_angle_m_360 == normalise(test.angle - 360., -180.)); + EXPECT(test.ref_norm_angle_m_720 == normalise(test.angle - 720., -180.)); + EXPECT(test.ref_norm_angle_p_360 == normalise(test.angle + 360., -180.)); + EXPECT(test.ref_norm_angle_p_720 == normalise(test.angle + 720., -180.)); } -#endif } +#endif CASE("PointLonLat normalisation") { @@ -199,24 +220,10 @@ CASE("PointLonLat normalisation") { auto p3 = PointLonLat(50., 90.); EXPECT(points_equal(p, p3)); - - PointLonLat q(1., -90.); - EXPECT_EQUAL(q.lon, 1.); - EXPECT_EQUAL(q.lat, -90.); - - auto q2 = q.antipode(); - EXPECT_EQUAL(q2.lon, 0.); - EXPECT(points_equal(q2, p)); - - auto q3 = q2.antipode(); - EXPECT(points_equal(q3, q)); } CASE("PointLonLat comparison") { - auto r(PointLonLat::make(-10., -91.)); - EXPECT(points_equal(r, r.antipode().antipode())); - Point a1 = PointLonLat{180., 0.}; Point a2 = PointLonLat{-180., 0.}; EXPECT(points_equal(a1, a2)); From fe23df970f718fca380c07761057c0dcabc9fc8c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 May 2024 16:58:07 +0100 Subject: [PATCH 685/737] eckit::geo::Point --- src/eckit/geo/GreatCircle.cc | 6 +- src/eckit/geo/PointLonLat.cc | 36 +++++---- src/eckit/geo/PointLonLat.h | 24 +++--- src/eckit/geo/PointLonLatR.cc | 31 ++++---- src/eckit/geo/PointLonLatR.h | 23 +++--- src/eckit/geo/area/BoundingBox.cc | 6 +- src/eckit/geo/geometry/Sphere.cc | 2 +- .../figure/LambertConformalConic.cc | 4 +- src/eckit/geo/projection/figure/Mercator.cc | 6 +- .../projection/figure/PolarStereographic.cc | 4 +- tests/geo/pointlonlatr.cc | 75 ++++++++----------- 11 files changed, 107 insertions(+), 110 deletions(-) diff --git a/src/eckit/geo/GreatCircle.cc b/src/eckit/geo/GreatCircle.cc index 7b37edc73..13bab2187 100644 --- a/src/eckit/geo/GreatCircle.cc +++ b/src/eckit/geo/GreatCircle.cc @@ -34,7 +34,7 @@ static bool is_pole(const double lat) { GreatCircle::GreatCircle(const PointLonLat& Alonlat, const PointLonLat& Blonlat) : A_(Alonlat), B_(Blonlat) { const bool Apole = is_pole(A_.lat); const bool Bpole = is_pole(B_.lat); - const double lon12_deg = PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, PointLonLat::ANTIMERIDIAN); + const double lon12_deg = PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -PointLonLat::FLAT_ANGLE); const bool lon_same = Apole || Bpole || is_approximately_equal(lon12_deg, 0.); const bool lon_opposite = Apole || Bpole || is_approximately_equal(std::abs(lon12_deg), 180.); @@ -62,7 +62,7 @@ std::vector GreatCircle::latitude(double lon) const { const double lambda1p = util::DEGREE_TO_RADIAN * (lon - A_.lon); const double lambda2p = util::DEGREE_TO_RADIAN * (lon - B_.lon); const double lambda - = util::DEGREE_TO_RADIAN * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, PointLonLat::ANTIMERIDIAN); + = util::DEGREE_TO_RADIAN * PointLonLat::normalise_angle_to_minimum(B_.lon - A_.lon, -PointLonLat::FLAT_ANGLE); double lat = std::atan((std::tan(lat2) * std::sin(lambda1p) - std::tan(lat1) * std::sin(lambda2p)) / (std::sin(lambda))); @@ -81,7 +81,7 @@ std::vector GreatCircle::longitude(double lat) const { } const double lon12 - = util::DEGREE_TO_RADIAN * PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, PointLonLat::ANTIMERIDIAN); + = util::DEGREE_TO_RADIAN * PointLonLat::normalise_angle_to_minimum(A_.lon - B_.lon, -PointLonLat::FLAT_ANGLE); const double lon1 = util::DEGREE_TO_RADIAN * A_.lon; const double lat1 = util::DEGREE_TO_RADIAN * A_.lat; const double lat2 = util::DEGREE_TO_RADIAN * B_.lat; diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index 2c963659a..d1959d159 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -25,23 +25,23 @@ namespace eckit::geo { PointLonLat::value_type PointLonLat::normalise_angle_to_minimum(value_type a, value_type minimum) { - static const auto modulo_globe = [](auto a) { return a - GLOBE * std::floor(a / GLOBE); }; + static const auto modulus = [](auto a) { return a - FULL_ANGLE * std::floor(a / FULL_ANGLE); }; auto diff = a - minimum; - return 0. <= diff && diff < GLOBE ? a : (modulo_globe(diff) + minimum); + return 0. <= diff && diff < FULL_ANGLE ? a : (modulus(diff) + minimum); } PointLonLat::value_type PointLonLat::normalise_angle_to_maximum(value_type a, value_type maximum) { - auto modulo_globe = [](auto a) { return a - GLOBE * std::ceil(a / GLOBE); }; + auto modulus = [](auto a) { return a - FULL_ANGLE * std::ceil(a / FULL_ANGLE); }; auto diff = a - maximum; - return -GLOBE < diff && diff <= 0. ? a : (modulo_globe(diff) + maximum); + return -FULL_ANGLE < diff && diff <= 0. ? a : (modulus(diff) + maximum); } void PointLonLat::assert_latitude_range(const PointLonLat& P) { - if (!(SOUTH_POLE <= P.lat && P.lat <= NORTH_POLE)) { + if (!(-RIGHT_ANGLE <= P.lat && P.lat <= RIGHT_ANGLE)) { std::ostringstream oss; oss.precision(std::numeric_limits::max_digits10); oss << "Invalid latitude [degree] " << P.lat; @@ -51,30 +51,34 @@ void PointLonLat::assert_latitude_range(const PointLonLat& P) { PointLonLat PointLonLat::make(value_type lon, value_type lat, value_type lon_minimum, value_type eps) { - lat = normalise_angle_to_minimum(lat, SOUTH_POLE); + lat = normalise_angle_to_minimum(lat, -RIGHT_ANGLE); - if (types::is_strictly_greater(lat, NORTH_POLE, eps)) { - lat = GLOBE / 2. - lat; - lon += GLOBE / 2.; + if (types::is_strictly_greater(lat, RIGHT_ANGLE, eps)) { + lat = FULL_ANGLE / 2. - lat; + lon += FULL_ANGLE / 2.; } - return types::is_approximately_equal(lat, NORTH_POLE, eps) ? PointLonLat{0., NORTH_POLE} - : types::is_approximately_equal(lat, SOUTH_POLE, eps) - ? PointLonLat{EQUATOR, SOUTH_POLE} + return types::is_approximately_equal(lat, RIGHT_ANGLE, eps) ? PointLonLat{0., RIGHT_ANGLE} + : types::is_approximately_equal(lat, -RIGHT_ANGLE, eps) + ? PointLonLat{ZERO_ANGLE, -RIGHT_ANGLE} : PointLonLat{normalise_angle_to_minimum(lon, lon_minimum), lat}; } -PointLonLat PointLonLat::make_from_lonlatr(value_type lonr, value_type latr) { - return make(util::RADIAN_TO_DEGREE * lonr, util::RADIAN_TO_DEGREE * latr); +PointLonLat PointLonLat::make_from_lonlatr(value_type lonr, value_type latr, value_type lonr_minimum) { + return make(util::RADIAN_TO_DEGREE * lonr, util::RADIAN_TO_DEGREE * latr, util::RADIAN_TO_DEGREE * lonr_minimum); } bool points_equal(const PointLonLat& a, const PointLonLat& b, PointLonLat::value_type eps) { - const auto c = PointLonLat::make(a.lon, a.lat, PointLonLat::EQUATOR, eps); - const auto d = PointLonLat::make(b.lon, b.lat, PointLonLat::EQUATOR, eps); + const auto c = PointLonLat::make(a.lon, a.lat, PointLonLat::ZERO_ANGLE, eps); + const auto d = PointLonLat::make(b.lon, b.lat, PointLonLat::ZERO_ANGLE, eps); return types::is_approximately_equal(c.lon, d.lon, eps) && types::is_approximately_equal(c.lat, d.lat, eps); } +const PointLonLat NORTH_POLE{PointLonLat::ZERO_ANGLE, PointLonLat::RIGHT_ANGLE}; +const PointLonLat SOUTH_POLE{PointLonLat::ZERO_ANGLE, -PointLonLat::RIGHT_ANGLE}; + + } // namespace eckit::geo diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index 495b6caf8..e923b22eb 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -71,23 +71,21 @@ class PointLonLat final : protected std::array { static void assert_latitude_range(const PointLonLat&); - [[nodiscard]] static PointLonLat make(value_type lon, value_type lat, value_type lon_minimum = EQUATOR, + [[nodiscard]] static PointLonLat make(value_type lon, value_type lat, value_type lon_minimum = ZERO_ANGLE, value_type eps = EPS); - [[nodiscard]] static PointLonLat make_from_lonlatr(value_type lonr, value_type latr); + [[nodiscard]] static PointLonLat make_from_lonlatr(value_type lonr, value_type latr, + value_type lonr_minimum = ZERO_ANGLE); - PointLonLat antipode() const { return make(lon, lat + GLOBE / 2.); } + PointLonLat antipode() const { return make(lon, lat + FULL_ANGLE / 2.); } // -- Class members - static constexpr double GLOBE = 360.; - static constexpr double GREENWICH = 0.; - static constexpr double ANTIMERIDIAN = -180.; - static constexpr double EQUATOR = 0.; - static constexpr double NORTH_POLE = 90.; - static constexpr double SOUTH_POLE = -90.; - - static constexpr value_type EPS = 1e-9; + static constexpr value_type FULL_ANGLE = 360.; + static constexpr value_type FLAT_ANGLE = 180.; + static constexpr value_type RIGHT_ANGLE = 90.; + static constexpr value_type ZERO_ANGLE = 0.; + static constexpr value_type EPS = 1e-9; // -- Class methods @@ -118,4 +116,8 @@ class PointLonLat final : protected std::array { bool points_equal(const PointLonLat&, const PointLonLat&, PointLonLat::value_type eps = PointLonLat::EPS); +extern const PointLonLat NORTH_POLE; +extern const PointLonLat SOUTH_POLE; + + } // namespace eckit::geo diff --git a/src/eckit/geo/PointLonLatR.cc b/src/eckit/geo/PointLonLatR.cc index d20c1d26b..aba543c67 100644 --- a/src/eckit/geo/PointLonLatR.cc +++ b/src/eckit/geo/PointLonLatR.cc @@ -20,32 +20,32 @@ namespace eckit::geo { PointLonLatR::value_type PointLonLatR::normalise_angle_to_minimum(value_type a, value_type minimum) { - static const auto modulo_globe = [](auto a) { return a - GLOBE * std::floor(a / GLOBE); }; + static const auto modulus = [](auto a) { return a - FULL_ANGLE * std::floor(a / FULL_ANGLE); }; auto diff = a - minimum; - return 0. <= diff && diff < GLOBE ? a : (modulo_globe(diff) + minimum); + return 0. <= diff && diff < FULL_ANGLE ? a : (modulus(diff) + minimum); } PointLonLatR::value_type PointLonLatR::normalise_angle_to_maximum(value_type a, value_type maximum) { - auto modulo_globe = [](auto a) { return a - GLOBE * std::ceil(a / GLOBE); }; + auto modulus = [](auto a) { return a - FULL_ANGLE * std::ceil(a / FULL_ANGLE); }; auto diff = a - maximum; - return -GLOBE < diff && diff <= 0. ? a : (modulo_globe(diff) + maximum); + return -FULL_ANGLE < diff && diff <= 0. ? a : (modulus(diff) + maximum); } PointLonLatR PointLonLatR::make(value_type lonr, value_type latr, value_type lonr_minimum, value_type eps) { - latr = normalise_angle_to_minimum(latr, SOUTH_POLE); + latr = normalise_angle_to_minimum(latr, -RIGHT_ANGLE); - if (types::is_strictly_greater(latr, NORTH_POLE, eps)) { - latr = GLOBE / 2. - latr; - lonr += GLOBE / 2.; + if (types::is_strictly_greater(latr, RIGHT_ANGLE, eps)) { + latr = FULL_ANGLE / 2. - latr; + lonr += FULL_ANGLE / 2.; } - return types::is_approximately_equal(latr, NORTH_POLE, eps) ? PointLonLatR{0., NORTH_POLE} - : types::is_approximately_equal(latr, SOUTH_POLE, eps) - ? PointLonLatR{EQUATOR, SOUTH_POLE} + return types::is_approximately_equal(latr, RIGHT_ANGLE, eps) ? PointLonLatR{0., RIGHT_ANGLE} + : types::is_approximately_equal(latr, -RIGHT_ANGLE, eps) + ? PointLonLatR{ZERO_ANGLE, -RIGHT_ANGLE} : PointLonLatR{normalise_angle_to_minimum(lonr, lonr_minimum), latr}; } @@ -56,9 +56,14 @@ PointLonLatR PointLonLatR::make_from_lonlat(value_type lon, value_type lat, valu bool points_equal(const PointLonLatR& a, const PointLonLatR& b, PointLonLatR::value_type eps) { - const auto c = PointLonLatR::make(a.lonr, a.latr, PointLonLatR::EQUATOR, eps); - const auto d = PointLonLatR::make(b.lonr, b.latr, PointLonLatR::EQUATOR, eps); + const auto c = PointLonLatR::make(a.lonr, a.latr, PointLonLatR::ZERO_ANGLE, eps); + const auto d = PointLonLatR::make(b.lonr, b.latr, PointLonLatR::ZERO_ANGLE, eps); return types::is_approximately_equal(c.lonr, d.lonr, eps) && types::is_approximately_equal(c.latr, d.latr, eps); } + +const PointLonLatR NORTH_POLE_R{PointLonLatR::ZERO_ANGLE, PointLonLatR::RIGHT_ANGLE}; +const PointLonLatR SOUTH_POLE_R{PointLonLatR::ZERO_ANGLE, -PointLonLatR::RIGHT_ANGLE}; + + } // namespace eckit::geo diff --git a/src/eckit/geo/PointLonLatR.h b/src/eckit/geo/PointLonLatR.h index d9afe5853..dd019e658 100644 --- a/src/eckit/geo/PointLonLatR.h +++ b/src/eckit/geo/PointLonLatR.h @@ -69,24 +69,21 @@ class PointLonLatR final : protected std::array { static value_type normalise_angle_to_maximum(value_type, value_type maximum); - [[nodiscard]] static PointLonLatR make(value_type lonr, value_type latr, value_type lonr_minimum = EQUATOR, + [[nodiscard]] static PointLonLatR make(value_type lonr, value_type latr, value_type lonr_minimum = ZERO_ANGLE, value_type eps = EPS); [[nodiscard]] static PointLonLatR make_from_lonlat(value_type lon, value_type lat, - value_type lon_minimum = EQUATOR); + value_type lon_minimum = ZERO_ANGLE); - PointLonLatR antipode() const { return make(lonr, latr + GLOBE / 2.); } + PointLonLatR antipode() const { return make(lonr, latr + FULL_ANGLE / 2.); } // -- Class members - static constexpr double GLOBE = 2. * M_PI; - static constexpr double GREENWICH = 0.; - static constexpr double ANTIMERIDIAN = -M_PI; - static constexpr double EQUATOR = 0.; - static constexpr double NORTH_POLE = M_PI_2; - static constexpr double SOUTH_POLE = -M_PI_2; - - static constexpr value_type EPS = 1e-10; + static constexpr value_type FULL_ANGLE = 2. * M_PI; + static constexpr value_type FLAT_ANGLE = M_PI; + static constexpr value_type RIGHT_ANGLE = M_PI_2; + static constexpr value_type ZERO_ANGLE = 0.; + static constexpr value_type EPS = 1e-10; // -- Class methods // None @@ -102,4 +99,8 @@ class PointLonLatR final : protected std::array { bool points_equal(const PointLonLatR&, const PointLonLatR&, PointLonLatR::value_type eps = PointLonLatR::EPS); +extern const PointLonLatR NORTH_POLE_R; +extern const PointLonLatR SOUTH_POLE_R; + + } // namespace eckit::geo diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 9eeb13bc2..3fbf2702e 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -106,14 +106,12 @@ bool BoundingBox::isPeriodicWestEast() const { bool BoundingBox::containsNorthPole() const { - static const auto POLE = PointLonLat::make(PointLonLat::EQUATOR, PointLonLat::NORTH_POLE); - return points_equal({PointLonLat::EQUATOR, north}, POLE); + return types::is_approximately_equal(north, NORTH_POLE.lat, PointLonLat::EPS); } bool BoundingBox::containsSouthPole() const { - static const auto POLE = PointLonLat::make(PointLonLat::EQUATOR, PointLonLat::SOUTH_POLE); - return points_equal({PointLonLat::EQUATOR, south}, POLE); + return types::is_approximately_equal(south, SOUTH_POLE.lat, PointLonLat::EPS); } diff --git a/src/eckit/geo/geometry/Sphere.cc b/src/eckit/geo/geometry/Sphere.cc index 7eb89c320..303729653 100644 --- a/src/eckit/geo/geometry/Sphere.cc +++ b/src/eckit/geo/geometry/Sphere.cc @@ -112,7 +112,7 @@ double Sphere::area(double radius, const area::BoundingBox& bbox) { ASSERT(radius > 0.); // Set longitude and latitude fractions - auto lonf = bbox.isPeriodicWestEast() ? 1. : (bbox.east - bbox.west) / PointLonLat::GLOBE; + auto lonf = bbox.isPeriodicWestEast() ? 1. : (bbox.east - bbox.west) / PointLonLat::FULL_ANGLE; ASSERT(0. <= lonf && lonf <= 1.); auto sn = std::sin(util::DEGREE_TO_RADIAN * bbox.north); diff --git a/src/eckit/geo/projection/figure/LambertConformalConic.cc b/src/eckit/geo/projection/figure/LambertConformalConic.cc index f73c14274..38414ec40 100644 --- a/src/eckit/geo/projection/figure/LambertConformalConic.cc +++ b/src/eckit/geo/projection/figure/LambertConformalConic.cc @@ -84,10 +84,10 @@ PointLonLat LambertConformalConic::inv(const Point2& p) const { auto lonr = std::atan2(x, y) / n_ + centre_r_.lonr; auto latr = 2. * std::atan(std::pow(f_ / rho, 1. / n_)) - M_PI_2; - return PointLonLat::make(util::RADIAN_TO_DEGREE * lonr, util::RADIAN_TO_DEGREE * latr); + return PointLonLat::make_from_lonlatr(lonr, latr); } - return PointLonLat::make(0., n_ > 0 ? PointLonLat::NORTH_POLE : PointLonLat::SOUTH_POLE); + return PointLonLat::make(0., n_ > 0 ? PointLonLat::RIGHT_ANGLE : -PointLonLat::RIGHT_ANGLE); } diff --git a/src/eckit/geo/projection/figure/Mercator.cc b/src/eckit/geo/projection/figure/Mercator.cc index b121da332..965f11134 100644 --- a/src/eckit/geo/projection/figure/Mercator.cc +++ b/src/eckit/geo/projection/figure/Mercator.cc @@ -29,7 +29,7 @@ static ProjectionBuilder PROJECTION_2("merc"); Mercator::Mercator(PointLonLat centre, PointLonLat first, Figure* figure_ptr) : ProjectionOnFigure(figure_ptr), - centre_(PointLonLat::make(centre.lon, centre.lat, PointLonLat::ANTIMERIDIAN)), + centre_(PointLonLat::make(centre.lon, centre.lat, -PointLonLat::FLAT_ANGLE)), first_(first), eps_(1e-10), max_iter_(15) { @@ -37,8 +37,8 @@ Mercator::Mercator(PointLonLat centre, PointLonLat first, Figure* figure_ptr) : // - Equation (7-9) to calculate phi iteratively // - Equation (15-11) to calculate t - if (types::is_approximately_equal(first.lat, PointLonLat::NORTH_POLE) - || types::is_approximately_equal(first.lat, PointLonLat::SOUTH_POLE)) { + if (types::is_approximately_equal(first.lat, PointLonLat::RIGHT_ANGLE) + || types::is_approximately_equal(first.lat, -PointLonLat::RIGHT_ANGLE)) { throw ProjectionProblem("Mercator: projection cannot be calculated at the poles", Here()); } diff --git a/src/eckit/geo/projection/figure/PolarStereographic.cc b/src/eckit/geo/projection/figure/PolarStereographic.cc index 9dbdbb839..21d55a746 100644 --- a/src/eckit/geo/projection/figure/PolarStereographic.cc +++ b/src/eckit/geo/projection/figure/PolarStereographic.cc @@ -33,8 +33,8 @@ PolarStereographic::PolarStereographic(PointLonLat centre, PointLonLat first, Fi first_(first), first_r_(PointLonLatR::make_from_lonlat(first.lon, first.lat)), sign_(centre_.lat < 0. ? -1. : 1.), - F_(types::is_approximately_equal(centre_.lat, PointLonLat::NORTH_POLE, PointLonLat::EPS) - || types::is_approximately_equal(centre_.lat, PointLonLat::SOUTH_POLE, PointLonLat::EPS) + F_(types::is_approximately_equal(centre_.lat, PointLonLat::RIGHT_ANGLE, PointLonLat::EPS) + || types::is_approximately_equal(centre_.lat, -PointLonLat::RIGHT_ANGLE, PointLonLat::EPS) ? 0.5 : std::tan(0.5 * (M_PI_2 - sign_ * centre_r_.latr)) / std::cos(sign_ * centre_r_.latr)) { auto z = fwd(first_); diff --git a/tests/geo/pointlonlatr.cc b/tests/geo/pointlonlatr.cc index ab7691f19..61742fe2f 100644 --- a/tests/geo/pointlonlatr.cc +++ b/tests/geo/pointlonlatr.cc @@ -31,10 +31,10 @@ CASE("PointLonLatR normalise_angle_to_*") { SECTION("normalise_angle_to_minimum") { for (const auto& test : { test_t{1., 0., 1.}, - {1. + 42. * PointLonLatR::GLOBE, 0., 1.}, - {1. - 42. * PointLonLatR::GLOBE, 0., 1.}, - {1., 3. * PointLonLatR::GLOBE, 3. * PointLonLatR::GLOBE + 1.}, - {-1., 3. * PointLonLatR::GLOBE, 4. * PointLonLatR::GLOBE - 1.}, + {1. + 42. * PointLonLatR::FULL_ANGLE, 0., 1.}, + {1. - 42. * PointLonLatR::FULL_ANGLE, 0., 1.}, + {1., 3. * PointLonLatR::FULL_ANGLE, 3. * PointLonLatR::FULL_ANGLE + 1.}, + {-1., 3. * PointLonLatR::FULL_ANGLE, 4. * PointLonLatR::FULL_ANGLE - 1.}, }) { EXPECT(types::is_approximately_equal( test.ref, PointLonLatR::normalise_angle_to_minimum(test.angle, test.lim), PointLonLatR::EPS)); @@ -44,9 +44,9 @@ CASE("PointLonLatR normalise_angle_to_*") { SECTION("normalise_angle_to_maximum") { for (const auto& test : { - test_t{1., 0., 1. - PointLonLatR::GLOBE}, - {1., 3. * PointLonLatR::GLOBE, 2. * PointLonLatR::GLOBE + 1.}, - {-1., 3. * PointLonLatR::GLOBE, 3. * PointLonLatR::GLOBE - 1.}, + test_t{1., 0., 1. - PointLonLatR::FULL_ANGLE}, + {1., 3. * PointLonLatR::FULL_ANGLE, 2. * PointLonLatR::FULL_ANGLE + 1.}, + {-1., 3. * PointLonLatR::FULL_ANGLE, 3. * PointLonLatR::FULL_ANGLE - 1.}, }) { EXPECT(types::is_approximately_equal( test.ref, PointLonLatR::normalise_angle_to_maximum(test.angle, test.lim), PointLonLatR::EPS)); @@ -56,26 +56,20 @@ CASE("PointLonLatR normalise_angle_to_*") { CASE("PointLonLatR normalisation") { - PointLonLatR p(1, PointLonLatR::NORTH_POLE); - EXPECT_EQUAL(p.lonr, 1.); - EXPECT_EQUAL(p.latr, PointLonLatR::NORTH_POLE); - + PointLonLatR p(1, PointLonLatR::RIGHT_ANGLE); auto p2 = PointLonLatR::make(p.lonr, p.latr); + auto p3 = PointLonLatR(1. + 42. * PointLonLatR::FULL_ANGLE, PointLonLatR::RIGHT_ANGLE); + EXPECT_EQUAL(p2.lonr, 0.); EXPECT(points_equal(p, p2)); - - auto p3 = PointLonLatR(1. + 42. * PointLonLatR::GLOBE, PointLonLatR::NORTH_POLE); EXPECT(points_equal(p, p3)); - PointLonLatR q(1., PointLonLatR::SOUTH_POLE); - EXPECT_EQUAL(q.lonr, 1.); - EXPECT_EQUAL(q.latr, PointLonLatR::SOUTH_POLE); - + PointLonLatR q(1., SOUTH_POLE_R.latr); auto q2 = q.antipode(); + auto q3 = q2.antipode(); + EXPECT_EQUAL(q2.lonr, 0.); EXPECT(points_equal(q2, p)); - - auto q3 = q2.antipode(); EXPECT(points_equal(q3, q)); } @@ -84,39 +78,32 @@ CASE("PointLonLatR comparison") { auto r(PointLonLatR::make(-10., -91.)); EXPECT(points_equal(r, r.antipode().antipode())); - PointLonLatR a1{PointLonLatR::ANTIMERIDIAN, 0.}; - PointLonLatR a2{-PointLonLatR::ANTIMERIDIAN, 0.}; + PointLonLatR a1{PointLonLatR::FLAT_ANGLE, 0.}; + PointLonLatR a2{-PointLonLatR::FLAT_ANGLE, 0.}; EXPECT(points_equal(a1, a2)); - PointLonLatR b1{0., PointLonLatR::SOUTH_POLE}; - auto b2 = PointLonLatR::make(1., PointLonLatR::SOUTH_POLE + PointLonLatR::GLOBE); - EXPECT(points_equal(b1, b2)); + EXPECT(points_equal(SOUTH_POLE_R, {1., SOUTH_POLE_R.latr + PointLonLatR::FULL_ANGLE})); PointLonLatR c1{300., -30.}; - PointLonLatR c2{c1.lonr - PointLonLatR::GLOBE - PointLonLatR::EPS / 10., - c1.latr + PointLonLatR::GLOBE + PointLonLatR::EPS / 10.}; + PointLonLatR c2{c1.lonr - PointLonLatR::FULL_ANGLE - PointLonLatR::EPS / 10., + c1.latr + PointLonLatR::FULL_ANGLE + PointLonLatR::EPS / 10.}; EXPECT(points_equal(c1, c2)); - PointLonLatR e1{PointLonLatR::GREENWICH, PointLonLatR::NORTH_POLE}; - PointLonLatR e2{PointLonLatR::ANTIMERIDIAN, PointLonLatR::NORTH_POLE}; - EXPECT(points_equal(e1, e2)); - - PointLonLatR f1{PointLonLatR::GREENWICH, PointLonLatR::SOUTH_POLE}; - PointLonLatR f2{-PointLonLatR::ANTIMERIDIAN, PointLonLatR::SOUTH_POLE}; - EXPECT(points_equal(f1, f2)); + EXPECT(points_equal(NORTH_POLE_R, {-42, PointLonLatR::RIGHT_ANGLE})); + EXPECT(points_equal(SOUTH_POLE_R, {42., -PointLonLatR::RIGHT_ANGLE})); } CASE("PointLonLatR normalise angles") { - EXPECT(types::is_approximately_equal(0., PointLonLatR::normalise_angle_to_minimum(0. + PointLonLatR::GLOBE, 0.), - PointLonLatR::EPS)); + EXPECT(types::is_approximately_equal( + 0., PointLonLatR::normalise_angle_to_minimum(0. + PointLonLatR::FULL_ANGLE, 0.), PointLonLatR::EPS)); EXPECT(types::is_approximately_equal( - 1., PointLonLatR::normalise_angle_to_minimum(1. + PointLonLatR::GLOBE * 11, 0.), PointLonLatR::EPS)); + 1., PointLonLatR::normalise_angle_to_minimum(1. + PointLonLatR::FULL_ANGLE * 11, 0.), PointLonLatR::EPS)); EXPECT(types::is_approximately_equal( - 2. + PointLonLatR::GLOBE * 11, - PointLonLatR::normalise_angle_to_minimum(2. + PointLonLatR::GLOBE * 11, PointLonLatR::GLOBE * 11), + 2. + PointLonLatR::FULL_ANGLE * 11, + PointLonLatR::normalise_angle_to_minimum(2. + PointLonLatR::FULL_ANGLE * 11, PointLonLatR::FULL_ANGLE * 11), PointLonLatR::EPS)); } @@ -125,14 +112,14 @@ CASE("PointLonLatR conversion to/from PointLonLat") { PointLonLatR p{0., 0.}; EXPECT(points_equal(p, PointLonLatR::make_from_lonlat(0., 0.))); - PointLonLatR q{0., PointLonLatR::NORTH_POLE}; - EXPECT(points_equal(q, PointLonLatR::make_from_lonlat(1., PointLonLat::NORTH_POLE))); + PointLonLatR q{0., PointLonLatR::RIGHT_ANGLE}; + EXPECT(points_equal(q, PointLonLatR::make_from_lonlat(1., PointLonLat::RIGHT_ANGLE))); - PointLonLatR r{42. * PointLonLatR::GLOBE, PointLonLatR::SOUTH_POLE}; - EXPECT(points_equal(r, PointLonLatR::make_from_lonlat(0., PointLonLat::SOUTH_POLE - 42. * PointLonLat::GLOBE))); + PointLonLatR r{42. * PointLonLatR::FULL_ANGLE, SOUTH_POLE_R.latr}; + EXPECT(points_equal(r, PointLonLatR::make_from_lonlat(0., SOUTH_POLE.lat - 42. * PointLonLat::FULL_ANGLE))); - PointLonLatR s{10. * util::DEGREE_TO_RADIAN, 42. * PointLonLatR::GLOBE}; - EXPECT(points_equal(s, PointLonLatR::make_from_lonlat(10. - 42. * PointLonLat::GLOBE, 0.))); + PointLonLatR s{10. * util::DEGREE_TO_RADIAN, 42. * PointLonLatR::FULL_ANGLE}; + EXPECT(points_equal(s, PointLonLatR::make_from_lonlat(10. - 42. * PointLonLat::FULL_ANGLE, 0.))); } From ac19348c108417533bb108bc2e0c289c41ef7fe2 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 May 2024 20:04:35 +0100 Subject: [PATCH 686/737] eckit::geo::Point --- src/eckit/geo/PointLonLat.cc | 4 ++-- src/eckit/geo/PointLonLatR.cc | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index d1959d159..7dc611545 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -54,8 +54,8 @@ PointLonLat PointLonLat::make(value_type lon, value_type lat, value_type lon_min lat = normalise_angle_to_minimum(lat, -RIGHT_ANGLE); if (types::is_strictly_greater(lat, RIGHT_ANGLE, eps)) { - lat = FULL_ANGLE / 2. - lat; - lon += FULL_ANGLE / 2.; + lat = FLAT_ANGLE - lat; + lon += FLAT_ANGLE; } return types::is_approximately_equal(lat, RIGHT_ANGLE, eps) ? PointLonLat{0., RIGHT_ANGLE} diff --git a/src/eckit/geo/PointLonLatR.cc b/src/eckit/geo/PointLonLatR.cc index aba543c67..bcbada27b 100644 --- a/src/eckit/geo/PointLonLatR.cc +++ b/src/eckit/geo/PointLonLatR.cc @@ -39,8 +39,8 @@ PointLonLatR PointLonLatR::make(value_type lonr, value_type latr, value_type lon latr = normalise_angle_to_minimum(latr, -RIGHT_ANGLE); if (types::is_strictly_greater(latr, RIGHT_ANGLE, eps)) { - latr = FULL_ANGLE / 2. - latr; - lonr += FULL_ANGLE / 2.; + latr = FLAT_ANGLE - latr; + lonr += FLAT_ANGLE; } return types::is_approximately_equal(latr, RIGHT_ANGLE, eps) ? PointLonLatR{0., RIGHT_ANGLE} From 406976f97fd1ecfd890297706703c2cb0eda14e5 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 May 2024 20:26:48 +0100 Subject: [PATCH 687/737] eckit::geo::Spec --- tests/geo/CMakeLists.txt | 2 + tests/geo/spec.cc | 497 ++++++++------------------------------ tests/geo/spec_custom.cc | 293 ++++++++++++++++++++++ tests/geo/spec_layered.cc | 53 ++++ 4 files changed, 450 insertions(+), 395 deletions(-) create mode 100644 tests/geo/spec_custom.cc create mode 100644 tests/geo/spec_layered.cc diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 2f21fc25f..4aff5b21a 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -31,6 +31,8 @@ foreach(_test range search spec + spec_custom + spec_layered util ) ecbuild_add_test( TARGET eckit_test_geo_${_test} diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 40e027d09..78de03db4 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -11,436 +11,143 @@ #include -#include +#include #include +#include #include "eckit/geo/Grid.h" -#include "eckit/geo/eckit_geo_config.h" #include "eckit/geo/spec/Custom.h" -#include "eckit/geo/spec/Layered.h" #include "eckit/geo/util.h" #include "eckit/log/Log.h" #include "eckit/testing/Test.h" -#include "eckit/types/FloatCompare.h" namespace eckit::geo::test { -template -struct is_vector : std::false_type {}; - - -template -struct is_vector> : std::true_type {}; - - -template -constexpr bool is_vector_v = is_vector::value; - - -template -void test_t() { - T a; - T b; - T c; - - if constexpr (std::is_same_v>) { - a = b = {"1", "2", "3"}; - c = {"7", "8", "9", "10"}; - } - else if constexpr (std::is_same_v) { - a = b = "1"; - c = "7"; - } - else if constexpr (is_vector_v) { - a = b = {1, 2, 3}; - c = {7, 8, 9, 10}; - } - else { - a = b = 1; - c = 7; - } - - EXPECT_NOT(a != b); - EXPECT(a == b); - EXPECT_NOT(a < b); - EXPECT(a <= b); - EXPECT_NOT(a > b); - EXPECT(a >= b); - - EXPECT(a != c); - EXPECT_NOT(a == c); - EXPECT(a < c); - EXPECT(a <= c); - EXPECT_NOT(a > c); - EXPECT_NOT(a >= c); -} - - -CASE("Custom::value_type") { - test_t(); - // test_t(); - test_t(); - test_t(); - test_t(); - test_t(); - test_t(); - test_t(); - test_t>(); - test_t>(); - test_t>(); - test_t>(); - test_t>(); - test_t>(); - test_t>(); -} - - -CASE("Custom::container_type") { - spec::Custom spec({{std::string{"foo"}, "bar"}}); - - std::string bar; - EXPECT(spec.get("foo", bar) && bar == "bar"); -} - - -CASE("Spec <- Custom") { - constexpr int zero = 0; - constexpr int one = 1; - constexpr double two = 2.; - const std::string three = "3"; - - - SECTION("access") { - std::unique_ptr spec(new spec::Custom({{"a", -123}, {"b", "B"}, {"c", 123UL}})); - - int a = 0; - EXPECT(spec->get("a", a)); - EXPECT_EQUAL(a, -123); - std::cout << "a: '" << a << "'" << std::endl; - - std::string b; - EXPECT(spec->get("b", b)); - EXPECT_EQUAL(b, "B"); - - size_t c = 0; - EXPECT(spec->get("c", c)); - EXPECT_EQUAL(c, 123UL); - - std::string b2; - EXPECT(spec->get("B", b2)); - EXPECT_EQUAL(b2, b); - - int d = 0; - dynamic_cast(spec.get())->set("B", 321); - EXPECT(spec->get("b", d)); - EXPECT_EQUAL(d, 321); - } - - - SECTION("conversion (1)") { - spec::Custom a({ - {"double", static_cast(one)}, - {"float", static_cast(one)}, - {"int", static_cast(one)}, - {"long", static_cast(one)}, - {"size_t", static_cast(one)}, - }); - - // test scalar type conversion - for (const std::string& key : {"double", "float", "int", "long", "size_t"}) { - double value_as_double = 0; - float value_as_float = 0; - - EXPECT(a.get(key, value_as_double) && value_as_double == static_cast(one)); - EXPECT(a.get(key, value_as_float) && value_as_float == static_cast(one)); - - if (key == "int" || key == "long" || key == "size_t") { - int value_as_int = 0; - long value_as_long = 0; - size_t value_as_size_t = 0; - - EXPECT(a.get(key, value_as_int) && value_as_int == static_cast(one)); - EXPECT(a.get(key, value_as_long) && value_as_long == static_cast(one)); - EXPECT(a.get(key, value_as_size_t) && value_as_size_t == static_cast(one)); - - EXPECT(a.get_string(key) == std::to_string(1)); - } - else { - EXPECT(a.get_string(key) == std::to_string(1.)); - } +CASE("user -> type") { + using C = spec::Custom::container_type; + using v = std::vector; + + static const C BAD; + ASSERT(BAD.empty()); + + static std::pair tests[]{ + {C({{"N", 2}}), C({{"N", 2}, {"type", "reduced_gg"}})}, + {C({{"area", v{90, -180, -90, 180}}, {"grid", v{2, 2}}}), C({{"type", "regular_ll"}})}, + {C({{"area", v{90, -180, -90, 180}}}), BAD}, + {C({{"grid", "B48"}}), BAD}, + {C({{"grid", "F48"}}), C({{"type", "regular_gg"}})}, + {C({{"grid", "N48"}}), C({{"type", "reduced_gg"}})}, + {C({{"grid", "O48"}}), C({{"type", "reduced_gg"}})}, + {C({{"grid", 48}}), BAD}, + {C({{"grid", v{2, 2}}}), C({{"grid", v{2, 2}}, {"type", "regular_ll"}})}, + {C({{"type", "latlon"}, {"grid", v{2, 2}}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "48"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "F048"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "N"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "N048"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "N48"}}), C({{"type", "reduced_gg"}})}, + {C({{"type", "reduced_gg"}, {"grid", "O048"}}), BAD}, + {C({{"type", "reduced_gg"}, {"grid", "O48"}}), C({{"type", "reduced_gg"}})}, + {C({{"type", "reduced_gg"}, {"grid", 48}}), BAD}, + {C({{"type", "reduced_gg"}}), BAD}, + {C({{"type", "reduced_latlon"}, {"grid", 2}}), BAD}, + {C({{"type", "reduced_ll"}, {"grid", 12}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "48"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "F048"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "F48"}}), C({{"type", "regular_gg"}})}, + {C({{"type", "regular_gg"}, {"grid", "N48"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "O48"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", "a"}}), BAD}, + {C({{"type", "regular_gg"}, {"grid", 48}}), BAD}, + {C({{"type", "regular_ll"}, {"area", v{90, -180, -90, 180}}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", "F48"}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", "a"}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", 48}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", std::vector{"a", "b"}}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", v{1, 2, 3}}}), BAD}, + {C({{"type", "regular_ll"}, {"grid", v{1, 2}}}), C({{"type", "regular_ll"}})}, + {C({{"type", "regular_ll"}, {"grid", v{1}}}), BAD}, + + {C({{"type", "mercator"}, + {"area", v{31.173058, 262.036499, 14.736453, 284.975281}}, + {"grid", v{45000.0, 45000.0}}, + {"shape", std::vector{56, 44}}, + {"lad", 14.0}, + {"orientation", 0.0}}), + C()}, + }; + + for (const auto& [user, ref] : tests) { + spec::Custom userspec(user); + spec::Custom refspec(ref); + + Log::info() << userspec << " -> " << refspec << std::endl; + + try { + std::unique_ptr spec(GridFactory::make_spec(userspec)); + EXPECT(spec); + + std::unique_ptr grid(GridFactory::build(*spec)); + EXPECT(grid); } - } - - - SECTION("conversion (2)") { - spec::Custom b({ - {"true", true}, - {"false", false}, - {"zero", 0}, - {"one", 1}, - }); - - EXPECT(b.get_bool("true")); - EXPECT(!b.get_bool("false")); - - bool maybe = false; - EXPECT(!b.has("?")); - EXPECT(!b.get_bool("?", false)); - EXPECT(b.get_bool("?", true)); - - EXPECT(b.get("true", maybe = false) && maybe); - EXPECT(b.get_bool("true", true)); - EXPECT(b.get_bool("true", false)); - - EXPECT(b.get("false", maybe = true) && !maybe); - EXPECT(!b.get_bool("false", true)); - EXPECT(!b.get_bool("false", false)); - - EXPECT(!b.get_bool("zero")); - EXPECT(!b.get_bool("zero", maybe = true)); - EXPECT(b.get("zero", maybe = true) && !maybe); - - EXPECT(b.get_bool("one")); - EXPECT(b.get_bool("one", maybe = false)); - EXPECT(b.get("one", maybe = false) && maybe); - } - - - SECTION("conversion (3)") { - spec::Custom c; - EXPECT_NOT(c.has("foo")); - - c.set("foo", two); - EXPECT(c.has("foo")); - EXPECT_THROWS_AS(c.get_int("foo"), SpecNotFound); // cannot access as int - EXPECT(::eckit::types::is_approximately_equal(c.get_double("foo"), two)); - EXPECT(c.get_string("foo") == std::to_string(two)); - - c.set("bar", one); - EXPECT(c.get_int("bar") == one); - EXPECT(::eckit::types::is_approximately_equal(c.get_double("bar"), static_cast(one))); - EXPECT(c.get_string("bar") == "1"); - - c.set("foo", three); - EXPECT(c.get_string("foo") == three); - - - spec::Custom d(c.container()); - - EXPECT(d.has("foo")); - EXPECT(d.get_string("foo") == three); - EXPECT_THROWS_AS(d.get_int("foo"), SpecNotFound); // cannot access as int - EXPECT_THROWS_AS(d.get_double("foo"), SpecNotFound); // cannot access as real - - d.set("foo", one); - EXPECT(d.get_int("foo") == one); - - - spec::Custom e(d.container()); - - ASSERT(e.has("foo")); - ASSERT(e.has("bar")); - } - - - SECTION("conversion (4)") { - spec::Custom e({{"zero", zero}, {"one", one}, {"two", two}}); - - bool maybe = true; - EXPECT(!e.get("?", maybe) && maybe); // non-existant key - EXPECT(!e.get("two", maybe) && maybe); // non-convertible - - EXPECT(e.get("zero", maybe) && !maybe); - EXPECT(e.get("one", maybe) && maybe); - } - - - SECTION("json") { - // test ordering - std::unique_ptr a(new spec::Custom({{"c", "c"}, {"a", "a"}, {"b", 1}})); - - const std::string a_str = a->str(); - const std::string a_ref = R"({"a":"a","b":1,"c":"c"})"; - EXPECT_EQUAL(a_str, a_ref); - - // test types - std::unique_ptr b(new spec::Custom({{"string", "string"}, - {"bool", true}, - {"int", static_cast(1)}, - {"long", static_cast(2)}, - {"long long", static_cast(3)}, - {"size_t", static_cast(4)}, - {"float", static_cast(5)}, - {"double", static_cast(6)}, - {"vector", std::vector{1, 1}}, - {"vector", std::vector{2, 2}}, - {"vector", std::vector{3, 3}}, - {"vector", std::vector{4, 4}}, - {"vector", std::vector{5, 5}}, - {"vector", std::vector{6, 6}}, - {"vector", std::vector{"string", "string"}}})); - - const std::string b_str = b->str(); - const std::string b_ref - = R"({"bool":true,"double":6,"float":5,"int":1,"long":2,"long long":3,"size_t":4,"string":"string","vector":[6,6],"vector":[5,5],"vector":[1,1],"vector":[3,3],"vector":[2,2],"vector":[4,4],"vector":["string","string"]})"; - EXPECT_EQUAL(b_str, b_ref); - } -} - - -CASE("Spec <- Layered") { - int one = 1; - double two = 2.; - - spec::Custom a({{"foo", one}, {"bar", two}}); - ASSERT(a.has("foo")); - ASSERT(a.has("bar")); - - spec::Layered b(a); - - ASSERT(b.has("foo")); - ASSERT(b.has("bar")); - - b.hide("foo"); - EXPECT_NOT(b.has("foo")); - - b.unhide("foo"); - ASSERT(b.has("foo")); - - EXPECT(a.get_int("foo") == one); - - auto value = b.get_int("foo"); - EXPECT(value == one); -} - - -CASE("spec") { - SECTION("user -> type") { - using C = spec::Custom::container_type; - using v = std::vector; - - static const C BAD; - ASSERT(BAD.empty()); - - static std::pair tests[]{ - {C({{"N", 2}}), C({{"N", 2}, {"type", "reduced_gg"}})}, - {C({{"area", v{90, -180, -90, 180}}, {"grid", v{2, 2}}}), C({{"type", "regular_ll"}})}, - {C({{"area", v{90, -180, -90, 180}}}), BAD}, - {C({{"grid", "B48"}}), BAD}, - {C({{"grid", "F48"}}), C({{"type", "regular_gg"}})}, - {C({{"grid", "N48"}}), C({{"type", "reduced_gg"}})}, - {C({{"grid", "O48"}}), C({{"type", "reduced_gg"}})}, - {C({{"grid", 48}}), BAD}, - {C({{"grid", v{2, 2}}}), C({{"grid", v{2, 2}}, {"type", "regular_ll"}})}, - {C({{"type", "latlon"}, {"grid", v{2, 2}}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "48"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "F048"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "N"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "N048"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "N48"}}), C({{"type", "reduced_gg"}})}, - {C({{"type", "reduced_gg"}, {"grid", "O048"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "O48"}}), C({{"type", "reduced_gg"}})}, - {C({{"type", "reduced_gg"}, {"grid", 48}}), BAD}, - {C({{"type", "reduced_gg"}}), BAD}, - {C({{"type", "reduced_latlon"}, {"grid", 2}}), BAD}, - {C({{"type", "reduced_ll"}, {"grid", 12}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "48"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "F048"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "F48"}}), C({{"type", "regular_gg"}})}, - {C({{"type", "regular_gg"}, {"grid", "N48"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "O48"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "a"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", 48}}), BAD}, - {C({{"type", "regular_ll"}, {"area", v{90, -180, -90, 180}}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", "F48"}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", "a"}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", 48}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", std::vector{"a", "b"}}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", v{1, 2, 3}}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", v{1, 2}}}), C({{"type", "regular_ll"}})}, - {C({{"type", "regular_ll"}, {"grid", v{1}}}), BAD}, - - {C({{"type", "mercator"}, - {"area", v{31.173058, 262.036499, 14.736453, 284.975281}}, - {"grid", v{45000.0, 45000.0}}, - {"shape", std::vector{56, 44}}, - {"lad", 14.0}, - {"orientation", 0.0}}), - C()}, - }; - - for (const auto& [user, ref] : tests) { - spec::Custom userspec(user); - spec::Custom refspec(ref); - - Log::info() << userspec << " -> " << refspec << std::endl; - - try { - std::unique_ptr spec(GridFactory::make_spec(userspec)); - EXPECT(spec); - - std::unique_ptr grid(GridFactory::build(*spec)); - EXPECT(grid); - } - catch (const SpecNotFound& e) { - EXPECT(refspec.empty() /*BAD*/); - } - catch (const BadParameter& e) { - EXPECT(refspec.empty() /*BAD*/); - } + catch (const SpecNotFound& e) { + EXPECT(refspec.empty() /*BAD*/); + } + catch (const BadParameter& e) { + EXPECT(refspec.empty() /*BAD*/); } } +} - SECTION("grid: name -> spec -> grid: name") { - for (const std::string& name : {"LAEA-EFAS-5km", "SMUFF-OPERA-2km"}) { - std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", name}}))); - EXPECT(grid); +CASE("grid: name -> spec -> grid: name") { + for (const std::string& name : {"LAEA-EFAS-5km", "SMUFF-OPERA-2km"}) { + std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", name}}))); + EXPECT(grid); - auto gridspec = grid->spec_str(); - EXPECT(gridspec == R"({"grid":")" + name + R"("})"); - } + auto gridspec = grid->spec_str(); + EXPECT(gridspec == R"({"grid":")" + name + R"("})"); } +} - SECTION("grid: reduced_gg") { - std::unique_ptr o16(GridFactory::build(spec::Custom({{"grid", "o16"}}))); +CASE("grid: reduced_gg") { + std::unique_ptr o16(GridFactory::build(spec::Custom({{"grid", "o16"}}))); - EXPECT(o16->spec_str() == R"({"grid":"O16"})"); + EXPECT(o16->spec_str() == R"({"grid":"O16"})"); - std::unique_ptr n16(GridFactory::build(spec::Custom({{"grid", "n16"}}))); + std::unique_ptr n16(GridFactory::build(spec::Custom({{"grid", "n16"}}))); - EXPECT(n16->spec_str() == R"({"grid":"N16"})"); + EXPECT(n16->spec_str() == R"({"grid":"N16"})"); - std::unique_ptr known_pl_1(GridFactory::build( - spec::Custom({{"pl", pl_type{20, 27, 32, 40, 45, 48, 60, 60, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 60, 60, 48, 45, 40, 32, 27, 20}}}))); + std::unique_ptr known_pl_1(GridFactory::build( + spec::Custom({{"pl", pl_type{20, 27, 32, 40, 45, 48, 60, 60, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 60, 60, 48, 45, 40, 32, 27, 20}}}))); - EXPECT(known_pl_1->spec_str() == R"({"grid":"N16"})"); + EXPECT(known_pl_1->spec_str() == R"({"grid":"N16"})"); - std::unique_ptr known_pl_2( - GridFactory::build(spec::Custom({{"pl", pl_type{20, 24, 28, 32, 32, 28, 24, 20}}}))); + std::unique_ptr known_pl_2( + GridFactory::build(spec::Custom({{"pl", pl_type{20, 24, 28, 32, 32, 28, 24, 20}}}))); - EXPECT(known_pl_2->spec_str() == R"({"grid":"O4"})"); + EXPECT(known_pl_2->spec_str() == R"({"grid":"O4"})"); - std::unique_ptr unknown_pl( - GridFactory::build(spec::Custom({{"pl", pl_type{20, 24, 28, 32, 32, 28, 24, 99}}}))); + std::unique_ptr unknown_pl( + GridFactory::build(spec::Custom({{"pl", pl_type{20, 24, 28, 32, 32, 28, 24, 99}}}))); - EXPECT(unknown_pl->spec_str() == R"({"grid":"N4","pl":[20,24,28,32,32,28,24,99]})"); - } + EXPECT(unknown_pl->spec_str() == R"({"grid":"N4","pl":[20,24,28,32,32,28,24,99]})"); +} - SECTION("grid: HEALPix") { - std::unique_ptr h2(GridFactory::build(spec::Custom({{"grid", "h2"}}))); +CASE("grid: HEALPix") { + std::unique_ptr h2(GridFactory::build(spec::Custom({{"grid", "h2"}}))); - EXPECT(h2->spec_str() == R"({"grid":"H2","ordering":"ring"})"); + EXPECT(h2->spec_str() == R"({"grid":"H2","ordering":"ring"})"); - std::unique_ptr h2n(GridFactory::build(spec::Custom({{"grid", "H2"}, {"ordering", "nested"}}))); + std::unique_ptr h2n(GridFactory::build(spec::Custom({{"grid", "H2"}, {"ordering", "nested"}}))); - EXPECT(h2n->spec_str() == R"({"grid":"H2","ordering":"nested"})"); - } + EXPECT(h2n->spec_str() == R"({"grid":"H2","ordering":"nested"})"); } diff --git a/tests/geo/spec_custom.cc b/tests/geo/spec_custom.cc new file mode 100644 index 000000000..c622cc1b0 --- /dev/null +++ b/tests/geo/spec_custom.cc @@ -0,0 +1,293 @@ +/* + * (C) Copyright 1996- 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 +#include +#include + +#include "eckit/exception/Exceptions.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/testing/Test.h" +#include "eckit/types/FloatCompare.h" + + +namespace eckit::geo::test { + + +template +struct is_vector : std::false_type {}; + + +template +struct is_vector> : std::true_type {}; + + +template +constexpr bool is_vector_v = is_vector::value; + + +template +void test_t() { + T a; + T b; + T c; + + if constexpr (std::is_same_v>) { + a = b = {"1", "2", "3"}; + c = {"7", "8", "9", "10"}; + } + else if constexpr (std::is_same_v) { + a = b = "1"; + c = "7"; + } + else if constexpr (is_vector_v) { + a = b = {1, 2, 3}; + c = {7, 8, 9, 10}; + } + else { + a = b = 1; + c = 7; + } + + EXPECT_NOT(a != b); + EXPECT(a == b); + EXPECT_NOT(a < b); + EXPECT(a <= b); + EXPECT_NOT(a > b); + EXPECT(a >= b); + + EXPECT(a != c); + EXPECT_NOT(a == c); + EXPECT(a < c); + EXPECT(a <= c); + EXPECT_NOT(a > c); + EXPECT_NOT(a >= c); +} + + +CASE("Custom::value_type") { + test_t(); + // test_t(); + test_t(); + test_t(); + test_t(); + test_t(); + test_t(); + test_t(); + test_t>(); + test_t>(); + test_t>(); + test_t>(); + test_t>(); + test_t>(); + test_t>(); +} + + +CASE("Custom::container_type") { + spec::Custom spec({{std::string{"foo"}, "bar"}}); + + std::string bar; + EXPECT(spec.get("foo", bar) && bar == "bar"); +} + + +CASE("Spec <- Custom") { + constexpr int zero = 0; + constexpr int one = 1; + constexpr double two = 2.; + const std::string three = "3"; + + + SECTION("access") { + std::unique_ptr spec(new spec::Custom({{"a", -123}, {"b", "B"}, {"c", 123UL}})); + + int a = 0; + EXPECT(spec->get("a", a)); + EXPECT_EQUAL(a, -123); + + std::string b; + EXPECT(spec->get("b", b)); + EXPECT_EQUAL(b, "B"); + + size_t c = 0; + EXPECT(spec->get("c", c)); + EXPECT_EQUAL(c, 123UL); + + std::string b2; + EXPECT(spec->get("B", b2)); + EXPECT_EQUAL(b2, b); + + int d = 0; + dynamic_cast(spec.get())->set("B", 321); + EXPECT(spec->get("b", d)); + EXPECT_EQUAL(d, 321); + } + + + SECTION("conversion (1)") { + spec::Custom a({ + {"double", static_cast(one)}, + {"float", static_cast(one)}, + {"int", static_cast(one)}, + {"long", static_cast(one)}, + {"size_t", static_cast(one)}, + }); + + // test scalar type conversion + for (const std::string& key : {"double", "float", "int", "long", "size_t"}) { + double value_as_double = 0; + float value_as_float = 0; + + EXPECT(a.get(key, value_as_double) && value_as_double == static_cast(one)); + EXPECT(a.get(key, value_as_float) && value_as_float == static_cast(one)); + + if (key == "int" || key == "long" || key == "size_t") { + int value_as_int = 0; + long value_as_long = 0; + size_t value_as_size_t = 0; + + EXPECT(a.get(key, value_as_int) && value_as_int == static_cast(one)); + EXPECT(a.get(key, value_as_long) && value_as_long == static_cast(one)); + EXPECT(a.get(key, value_as_size_t) && value_as_size_t == static_cast(one)); + + EXPECT(a.get_string(key) == std::to_string(1)); + } + else { + EXPECT(a.get_string(key) == std::to_string(1.)); + } + } + } + + + SECTION("conversion (2)") { + spec::Custom b({ + {"true", true}, + {"false", false}, + {"zero", 0}, + {"one", 1}, + }); + + EXPECT(b.get_bool("true")); + EXPECT(!b.get_bool("false")); + + bool maybe = false; + EXPECT(!b.has("?")); + EXPECT(!b.get_bool("?", false)); + EXPECT(b.get_bool("?", true)); + + EXPECT(b.get("true", maybe = false) && maybe); + EXPECT(b.get_bool("true", true)); + EXPECT(b.get_bool("true", false)); + + EXPECT(b.get("false", maybe = true) && !maybe); + EXPECT(!b.get_bool("false", true)); + EXPECT(!b.get_bool("false", false)); + + EXPECT(!b.get_bool("zero")); + EXPECT(!b.get_bool("zero", maybe = true)); + EXPECT(b.get("zero", maybe = true) && !maybe); + + EXPECT(b.get_bool("one")); + EXPECT(b.get_bool("one", maybe = false)); + EXPECT(b.get("one", maybe = false) && maybe); + } + + + SECTION("conversion (3)") { + spec::Custom c; + EXPECT_NOT(c.has("foo")); + + c.set("foo", two); + EXPECT(c.has("foo")); + EXPECT_THROWS_AS(c.get_int("foo"), SpecNotFound); // cannot access as int + EXPECT(::eckit::types::is_approximately_equal(c.get_double("foo"), two)); + EXPECT(c.get_string("foo") == std::to_string(two)); + + c.set("bar", one); + EXPECT(c.get_int("bar") == one); + EXPECT(::eckit::types::is_approximately_equal(c.get_double("bar"), static_cast(one))); + EXPECT(c.get_string("bar") == "1"); + + c.set("foo", three); + EXPECT(c.get_string("foo") == three); + + + spec::Custom d(c.container()); + + EXPECT(d.has("foo")); + EXPECT(d.get_string("foo") == three); + EXPECT_THROWS_AS(d.get_int("foo"), SpecNotFound); // cannot access as int + EXPECT_THROWS_AS(d.get_double("foo"), SpecNotFound); // cannot access as real + + d.set("foo", one); + EXPECT(d.get_int("foo") == one); + + + spec::Custom e(d.container()); + + ASSERT(e.has("foo")); + ASSERT(e.has("bar")); + } + + + SECTION("conversion (4)") { + spec::Custom e({{"zero", zero}, {"one", one}, {"two", two}}); + + bool maybe = true; + EXPECT(!e.get("?", maybe) && maybe); // non-existant key + EXPECT(!e.get("two", maybe) && maybe); // non-convertible + + EXPECT(e.get("zero", maybe) && !maybe); + EXPECT(e.get("one", maybe) && maybe); + } + + + SECTION("json") { + // test ordering + std::unique_ptr a(new spec::Custom({{"c", "c"}, {"a", "a"}, {"b", 1}})); + + const std::string a_str = a->str(); + const std::string a_ref = R"({"a":"a","b":1,"c":"c"})"; + EXPECT_EQUAL(a_str, a_ref); + + // test types + std::unique_ptr b(new spec::Custom({{"string", "string"}, + {"bool", true}, + {"int", static_cast(1)}, + {"long", static_cast(2)}, + {"long long", static_cast(3)}, + {"size_t", static_cast(4)}, + {"float", static_cast(5)}, + {"double", static_cast(6)}, + {"vector", std::vector{1, 1}}, + {"vector", std::vector{2, 2}}, + {"vector", std::vector{3, 3}}, + {"vector", std::vector{4, 4}}, + {"vector", std::vector{5, 5}}, + {"vector", std::vector{6, 6}}, + {"vector", std::vector{"string", "string"}}})); + + const std::string b_str = b->str(); + const std::string b_ref + = R"({"bool":true,"double":6,"float":5,"int":1,"long":2,"long long":3,"size_t":4,"string":"string","vector":[6,6],"vector":[5,5],"vector":[1,1],"vector":[3,3],"vector":[2,2],"vector":[4,4],"vector":["string","string"]})"; + EXPECT_EQUAL(b_str, b_ref); + } +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/spec_layered.cc b/tests/geo/spec_layered.cc new file mode 100644 index 000000000..9b405d765 --- /dev/null +++ b/tests/geo/spec_layered.cc @@ -0,0 +1,53 @@ +/* + * (C) Copyright 1996- 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 "eckit/exception/Exceptions.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/geo/spec/Layered.h" +#include "eckit/testing/Test.h" + + +namespace eckit::geo::test { + + +CASE("Spec <- Layered") { + int one = 1; + double two = 2.; + + spec::Custom a({{"foo", one}, {"bar", two}}); + ASSERT(a.has("foo")); + ASSERT(a.has("bar")); + + spec::Layered b(a); + + ASSERT(b.has("foo")); + ASSERT(b.has("bar")); + + b.hide("foo"); + EXPECT_NOT(b.has("foo")); + + b.unhide("foo"); + ASSERT(b.has("foo")); + + EXPECT(a.get_int("foo") == one); + + auto value = b.get_int("foo"); + EXPECT(value == one); +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} From 1260b7d19d6bf2c0e7f288197b0488d0e86c272b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 May 2024 20:57:49 +0100 Subject: [PATCH 688/737] eckit::geo::Spec --- src/eckit/geo/Area.h | 9 ++++++++- src/eckit/geo/CMakeLists.txt | 1 + src/eckit/geo/Grid.cc | 26 ++++++++++++++++++++++++-- src/eckit/geo/Grid.h | 10 +++++++--- src/eckit/geo/Iterator.cc | 26 ++++++++++++++++++++++++++ src/eckit/geo/Iterator.h | 11 +++++++++++ src/eckit/geo/Projection.cc | 6 ++++++ src/eckit/geo/Projection.h | 5 +++-- src/eckit/geo/grid/HEALPix.cc | 2 +- src/eckit/geo/grid/HEALPix.h | 2 +- src/eckit/geo/grid/ORCA.cc | 2 +- src/eckit/geo/grid/ORCA.h | 2 +- src/eckit/geo/grid/ReducedGaussian.cc | 2 +- src/eckit/geo/grid/ReducedGaussian.h | 2 +- src/eckit/geo/grid/ReducedLL.cc | 2 +- src/eckit/geo/grid/ReducedLL.h | 2 +- src/eckit/geo/grid/Regular.cc | 8 ++++---- src/eckit/geo/grid/Regular.h | 4 ++-- src/eckit/geo/grid/Unstructured.cc | 2 +- src/eckit/geo/grid/Unstructured.h | 2 +- 20 files changed, 102 insertions(+), 24 deletions(-) create mode 100644 src/eckit/geo/Iterator.cc diff --git a/src/eckit/geo/Area.h b/src/eckit/geo/Area.h index 6d43cff32..63f4e7130 100644 --- a/src/eckit/geo/Area.h +++ b/src/eckit/geo/Area.h @@ -51,11 +51,18 @@ class Area { Area& operator=(const Area&) = default; Area& operator=(Area&&) = default; - // -- Methods + // -- Class methods static std::string className() { return "area"; } +private: + // -- Methods + virtual void spec(spec::Custom&) const; + + // -- Friends + + friend class Grid; }; diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 6f0db797a..b67db9547 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -12,6 +12,7 @@ list(APPEND eckit_geo_srcs Grid.h Increments.cc Increments.h + Iterator.cc Iterator.h LibEcKitGeo.cc LibEcKitGeo.h diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 8b378b479..4a12be6d5 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -56,7 +56,10 @@ spec::Custom* Grid::calculate_spec() const { auto* custom = new spec::Custom; ASSERT(custom != nullptr); - spec(*custom); + grid_spec(*custom); + iterator_spec(*custom); + area_spec(*custom); + projection_spec(*custom); return custom; } @@ -175,11 +178,30 @@ Renumber Grid::no_reorder(size_t size) { } -void Grid::spec(spec::Custom&) const { +void Grid::grid_spec(spec::Custom&) const { NOTIMP; } +void Grid::iterator_spec(spec::Custom& custom) const { + cbegin()->spec(custom); +} + + +void Grid::area_spec(spec::Custom& custom) const { + if (area_) { + area_->spec(custom); + } +} + + +void Grid::projection_spec(spec::Custom& custom) const { + if (projection_) { + projection_->spec(custom); + } +} + + const Grid* GridFactory::make_from_string(const std::string& str) { std::unique_ptr spec(spec::Custom::make_from_value(YAMLParser::decodeString(str))); return instance().make_from_spec_(*spec); diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 3ab8170aa..6dcff2dde 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -150,15 +150,19 @@ class Grid { private: // -- Members + std::unique_ptr area_; + std::unique_ptr projection_; + mutable std::unique_ptr bbox_; mutable std::unique_ptr spec_; mutable uid_t uid_; - std::unique_ptr projection_; - // -- Methods - virtual void spec(spec::Custom&) const; + virtual void grid_spec(spec::Custom&) const; + virtual void iterator_spec(spec::Custom&) const; + virtual void area_spec(spec::Custom&) const; + virtual void projection_spec(spec::Custom&) const; [[nodiscard]] virtual area::BoundingBox* calculate_bbox() const { return new area::BoundingBox{}; } diff --git a/src/eckit/geo/Iterator.cc b/src/eckit/geo/Iterator.cc new file mode 100644 index 000000000..ae720abfe --- /dev/null +++ b/src/eckit/geo/Iterator.cc @@ -0,0 +1,26 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Iterator.h" + +#include "eckit/exception/Exceptions.h" + + +namespace eckit::geo { + + +void Iterator::spec(spec::Custom&) const { + NOTIMP; +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index 4149db8aa..4e47f5f92 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -19,7 +19,10 @@ namespace eckit::geo { class Grid; +namespace spec { +class Custom; } +} // namespace eckit::geo namespace eckit::geo { @@ -65,6 +68,14 @@ class Iterator { // -- Constructors Iterator() = default; + + // -- Methods + + virtual void spec(spec::Custom&) const; + + // -- Friends + + friend class Grid; }; diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index 0231f6750..a4d464f88 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -14,6 +14,7 @@ #include +#include "eckit/exception/Exceptions.h" #include "eckit/geo/spec/Custom.h" @@ -34,4 +35,9 @@ std::string Projection::spec() const { } +void Projection::spec(spec::Custom&) const { + NOTIMP; +} + + } // namespace eckit::geo diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index b4b59ccb4..83e2525c8 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -14,7 +14,6 @@ #include -#include "eckit/exception/Exceptions.h" #include "eckit/geo/Point.h" #include "eckit/memory/Builder.h" #include "eckit/memory/Factory.h" @@ -73,10 +72,12 @@ class Projection { private: // -- Methods - virtual void spec(spec::Custom&) const { NOTIMP; } + virtual void spec(spec::Custom&) const; // -- Friends + friend class Grid; + friend bool operator==(const Projection& a, const Projection& b) { return a.spec() == b.spec(); } friend bool operator!=(const Projection& a, const Projection& b) { return !(a == b); } }; diff --git a/src/eckit/geo/grid/HEALPix.cc b/src/eckit/geo/grid/HEALPix.cc index 9bf0d0108..d9f9d10bf 100644 --- a/src/eckit/geo/grid/HEALPix.cc +++ b/src/eckit/geo/grid/HEALPix.cc @@ -358,7 +358,7 @@ std::vector HEALPix::longitudes(size_t j) const { } -void HEALPix::spec(spec::Custom& custom) const { +void HEALPix::grid_spec(spec::Custom& custom) const { custom.set("grid", "H" + std::to_string(Nside_)); custom.set("ordering", ordering_ == Ordering::healpix_ring ? "ring" : "nested"); } diff --git a/src/eckit/geo/grid/HEALPix.h b/src/eckit/geo/grid/HEALPix.h index 55a547125..e2e28d08a 100644 --- a/src/eckit/geo/grid/HEALPix.h +++ b/src/eckit/geo/grid/HEALPix.h @@ -64,7 +64,7 @@ class HEALPix final : public Reduced { bool includesSouthPole() const override { return true; } bool isPeriodicWestEast() const override { return true; } - void spec(spec::Custom&) const override; + void grid_spec(spec::Custom&) const override; const std::vector& latitudes() const override; std::vector longitudes(size_t i) const override; diff --git a/src/eckit/geo/grid/ORCA.cc b/src/eckit/geo/grid/ORCA.cc index 3e59e05c6..e19ecfbb8 100644 --- a/src/eckit/geo/grid/ORCA.cc +++ b/src/eckit/geo/grid/ORCA.cc @@ -321,7 +321,7 @@ Spec* ORCA::spec(const std::string& name) { } -void ORCA::spec(spec::Custom& custom) const { +void ORCA::grid_spec(spec::Custom& custom) const { custom.set("type", "ORCA"); custom.set("uid", uid_); } diff --git a/src/eckit/geo/grid/ORCA.h b/src/eckit/geo/grid/ORCA.h index a08c5ada6..d48dcd97b 100644 --- a/src/eckit/geo/grid/ORCA.h +++ b/src/eckit/geo/grid/ORCA.h @@ -104,7 +104,7 @@ class ORCA final : public Regular { // -- Overridden methods - void spec(spec::Custom&) const override; + void grid_spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/grid/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc index d57f999c3..c9df186db 100644 --- a/src/eckit/geo/grid/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -108,7 +108,7 @@ std::vector ReducedGaussian::longitudes(size_t j) const { } -void ReducedGaussian::spec(spec::Custom& custom) const { +void ReducedGaussian::grid_spec(spec::Custom& custom) const { if (pl_ == util::reduced_octahedral_pl(N_)) { custom.set("grid", "O" + std::to_string(N_)); } diff --git a/src/eckit/geo/grid/ReducedGaussian.h b/src/eckit/geo/grid/ReducedGaussian.h index 781f3b7af..2657be29d 100644 --- a/src/eckit/geo/grid/ReducedGaussian.h +++ b/src/eckit/geo/grid/ReducedGaussian.h @@ -53,7 +53,7 @@ class ReducedGaussian : public Reduced { // -- Overridden methods - void spec(spec::Custom&) const override; + void grid_spec(spec::Custom&) const override; const std::vector& latitudes() const override; std::vector longitudes(size_t i) const override; diff --git a/src/eckit/geo/grid/ReducedLL.cc b/src/eckit/geo/grid/ReducedLL.cc index f98c2e7be..82ecd54f4 100644 --- a/src/eckit/geo/grid/ReducedLL.cc +++ b/src/eckit/geo/grid/ReducedLL.cc @@ -66,7 +66,7 @@ std::vector ReducedLL::longitudes(size_t j) const { } -void ReducedLL::spec(spec::Custom& custom) const { +void ReducedLL::grid_spec(spec::Custom& custom) const { custom.set("type", "reduced_ll"); custom.set("pl", pl_); boundingBox().spec(custom); diff --git a/src/eckit/geo/grid/ReducedLL.h b/src/eckit/geo/grid/ReducedLL.h index 114e7d055..c11bd1331 100644 --- a/src/eckit/geo/grid/ReducedLL.h +++ b/src/eckit/geo/grid/ReducedLL.h @@ -50,7 +50,7 @@ class ReducedLL : public Reduced { const std::vector& latitudes() const override; std::vector longitudes(size_t j) const override; - void spec(spec::Custom&) const override; + void grid_spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index ef87fc103..975ceb6da 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -125,7 +125,7 @@ Spec* RegularLL::spec(const std::string& name) { } -void RegularLL::spec(spec::Custom& custom) const { +void RegularLL::grid_spec(spec::Custom& custom) const { custom.set("grid", std::vector{dx(), dy()}); boundingBox().spec(custom); } @@ -158,7 +158,7 @@ Spec* RegularGaussian::spec(const std::string& name) { } -void RegularGaussian::spec(spec::Custom& custom) const { +void RegularGaussian::grid_spec(spec::Custom& custom) const { custom.set("grid", "F" + std::to_string(N_)); boundingBox().spec(custom); } @@ -167,7 +167,7 @@ void RegularGaussian::spec(spec::Custom& custom) const { struct Mercator final : public Regular { explicit Mercator(const Spec& spec) : Regular(Regular::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} - void spec(spec::Custom& custom) const override { + void grid_spec(spec::Custom& custom) const override { custom.set("type", "mercator"); custom.set("grid", std::vector{dx(), dy()}); custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); @@ -186,7 +186,7 @@ struct Mercator final : public Regular { struct LambertAzimuthalEqualArea final : public Regular { explicit LambertAzimuthalEqualArea(const Spec& spec) : Regular(Regular::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} - void spec(spec::Custom& custom) const override { + void grid_spec(spec::Custom& custom) const override { custom.set("type", "lambert_azimuthal_equal_area"); custom.set("grid", std::vector{dx(), dy()}); custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index 037f88d66..c03973f06 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -82,7 +82,7 @@ struct RegularLL final : public Regular { RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); [[nodiscard]] static Spec* spec(const std::string& name); - void spec(spec::Custom&) const override; + void grid_spec(spec::Custom&) const override; }; @@ -93,7 +93,7 @@ struct RegularGaussian final : public Regular { [[nodiscard]] Grid* make_grid_cropped(const area::BoundingBox& crop) const override; [[nodiscard]] static Spec* spec(const std::string& name); - void spec(spec::Custom&) const override; + void grid_spec(spec::Custom&) const override; size_t N() const { return N_; } diff --git a/src/eckit/geo/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc index cf477256e..0af13c8c7 100644 --- a/src/eckit/geo/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -38,7 +38,7 @@ Spec* Unstructured::spec(const std::string& name) { } -void Unstructured::spec(spec::Custom& custom) const { +void Unstructured::grid_spec(spec::Custom& custom) const { custom.set("type", "unstructured"); custom.set("uid", uid()); } diff --git a/src/eckit/geo/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h index ed7bc68ad..d0fb9359d 100644 --- a/src/eckit/geo/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -55,7 +55,7 @@ class Unstructured final : public Grid { // -- Overridden methods - void spec(spec::Custom&) const override; + void grid_spec(spec::Custom&) const override; // -- Friends From c9b84f036ac0138773a08162cafd2873dec0521c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 30 May 2024 22:31:26 +0100 Subject: [PATCH 689/737] eckit::geo::Spec --- src/eckit/geo/Area.cc | 18 ++++++++++++++++ src/eckit/geo/Area.h | 8 ++++++- src/eckit/geo/Grid.cc | 30 ++++++++++++++++++-------- src/eckit/geo/Grid.h | 11 +++++----- src/eckit/geo/Iterator.cc | 9 ++++++-- src/eckit/geo/Iterator.h | 4 +++- src/eckit/geo/Projection.cc | 17 +++++++++++---- src/eckit/geo/Projection.h | 5 +++-- src/eckit/geo/iterator/Reduced.cc | 5 +++++ src/eckit/geo/iterator/Reduced.h | 2 ++ src/eckit/geo/iterator/Regular.cc | 5 +++++ src/eckit/geo/iterator/Regular.h | 2 ++ src/eckit/geo/iterator/Unstructured.cc | 5 +++++ src/eckit/geo/iterator/Unstructured.h | 2 ++ src/eckit/geo/projection/Composer.cc | 2 +- tests/geo/projection_ll_to_xyz.cc | 8 +++---- 16 files changed, 103 insertions(+), 30 deletions(-) diff --git a/src/eckit/geo/Area.cc b/src/eckit/geo/Area.cc index 742452b4b..37e4a9a8e 100644 --- a/src/eckit/geo/Area.cc +++ b/src/eckit/geo/Area.cc @@ -12,12 +12,30 @@ #include "eckit/geo/Area.h" +#include + #include "eckit/exception/Exceptions.h" +#include "eckit/geo/spec/Custom.h" namespace eckit::geo { +spec::Custom* Area::spec() const { + auto* custom = new spec::Custom; + ASSERT(custom != nullptr); + + spec(*custom); + return custom; +} + + +std::string Area::spec_str() const { + std::unique_ptr custom(spec()); + return custom->str(); +} + + void Area::spec(spec::Custom&) const { NOTIMP; } diff --git a/src/eckit/geo/Area.h b/src/eckit/geo/Area.h index 63f4e7130..f5081aee0 100644 --- a/src/eckit/geo/Area.h +++ b/src/eckit/geo/Area.h @@ -38,7 +38,8 @@ class Area { // -- Constructors - Area() noexcept = default; + Area() noexcept = default; + Area(const Area&) = default; Area(Area&&) = default; @@ -51,6 +52,11 @@ class Area { Area& operator=(const Area&) = default; Area& operator=(Area&&) = default; + // -- Methods + + [[nodiscard]] spec::Custom* spec() const; + std::string spec_str() const; + // -- Class methods static std::string className() { return "area"; } diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 4a12be6d5..86b767fcc 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -45,9 +45,9 @@ Grid::Grid(const area::BoundingBox& bbox) : bbox_(new area::BoundingBox(bbox)) { const Spec& Grid::spec() const { if (!spec_) { spec_.reset(calculate_spec()); + ASSERT(spec_); } - ASSERT(spec_); return *spec_; } @@ -57,7 +57,6 @@ spec::Custom* Grid::calculate_spec() const { ASSERT(custom != nullptr); grid_spec(*custom); - iterator_spec(*custom); area_spec(*custom); projection_spec(*custom); @@ -137,8 +136,19 @@ Grid* Grid::make_grid_reordered(Ordering) const { } -Area* Grid::area() const { - return new area::BoundingBox(*bbox_); +const Area& Grid::area() const { + if (!area_) { + area_.reset(calculate_area()); + ASSERT(area_); + } + + return *area_; +} + + +Area* Grid::calculate_area() const { + // FIXME temporary implementation + return calculate_bbox(); } @@ -157,10 +167,17 @@ const area::BoundingBox& Grid::boundingBox() const { bbox_.reset(calculate_bbox()); ASSERT(bbox_); } + return *bbox_; } +area::BoundingBox* Grid::calculate_bbox() const { + // FIXME temporary implementation + return new area::BoundingBox; +} + + Renumber Grid::crop(const area::BoundingBox& bbox) const { return crop(static_cast(bbox)); } @@ -183,11 +200,6 @@ void Grid::grid_spec(spec::Custom&) const { } -void Grid::iterator_spec(spec::Custom& custom) const { - cbegin()->spec(custom); -} - - void Grid::area_spec(spec::Custom& custom) const { if (area_) { area_->spec(custom); diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 6dcff2dde..2e534b339 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -124,10 +124,12 @@ class Grid { virtual Ordering order() const; virtual Renumber reorder(Ordering) const; - virtual Area* area() const; + virtual const Area& area() const; + [[nodiscard]] virtual Area* calculate_area() const; virtual Renumber crop(const Area&) const; virtual const area::BoundingBox& boundingBox() const; + [[nodiscard]] virtual area::BoundingBox* calculate_bbox() const; virtual Renumber crop(const area::BoundingBox&) const; [[nodiscard]] virtual Grid* make_grid_reordered(Ordering) const; @@ -150,8 +152,8 @@ class Grid { private: // -- Members - std::unique_ptr area_; - std::unique_ptr projection_; + mutable std::unique_ptr area_; + mutable std::unique_ptr projection_; mutable std::unique_ptr bbox_; mutable std::unique_ptr spec_; @@ -160,12 +162,9 @@ class Grid { // -- Methods virtual void grid_spec(spec::Custom&) const; - virtual void iterator_spec(spec::Custom&) const; virtual void area_spec(spec::Custom&) const; virtual void projection_spec(spec::Custom&) const; - [[nodiscard]] virtual area::BoundingBox* calculate_bbox() const { return new area::BoundingBox{}; } - // -- Friends friend bool operator==(const Grid& a, const Grid& b) { return a.spec_str() == b.spec_str(); } diff --git a/src/eckit/geo/Iterator.cc b/src/eckit/geo/Iterator.cc index ae720abfe..80a445e16 100644 --- a/src/eckit/geo/Iterator.cc +++ b/src/eckit/geo/Iterator.cc @@ -13,13 +13,18 @@ #include "eckit/geo/Iterator.h" #include "eckit/exception/Exceptions.h" +#include "eckit/geo/spec/Custom.h" namespace eckit::geo { -void Iterator::spec(spec::Custom&) const { - NOTIMP; +spec::Custom* Iterator::spec() const { + auto* custom = new spec::Custom; + ASSERT(custom != nullptr); + + spec(*custom); + return custom; } diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index 4e47f5f92..84446e05d 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -64,6 +64,8 @@ class Iterator { virtual size_t index() const = 0; + [[nodiscard]] spec::Custom* spec() const; + protected: // -- Constructors @@ -71,7 +73,7 @@ class Iterator { // -- Methods - virtual void spec(spec::Custom&) const; + virtual void spec(spec::Custom&) const = 0; // -- Friends diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index a4d464f88..721a1f1fd 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -12,6 +12,7 @@ #include "eckit/geo/Projection.h" +#include #include #include "eckit/exception/Exceptions.h" @@ -28,10 +29,18 @@ ProjectionProblem::ProjectionProblem(const std::string& what, const CodeLocation }; -std::string Projection::spec() const { - spec::Custom gridspec; - spec(gridspec); - return gridspec.str(); +spec::Custom* Projection::spec() const { + auto* custom = new spec::Custom; + ASSERT(custom != nullptr); + + spec(*custom); + return custom; +} + + +std::string Projection::spec_str() const { + std::unique_ptr custom(spec()); + return custom->str(); } diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 83e2525c8..c2cdbb5f3 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -63,7 +63,8 @@ class Projection { virtual Point fwd(const Point&) const = 0; virtual Point inv(const Point&) const = 0; - std::string spec() const; + [[nodiscard]] spec::Custom* spec() const; + std::string spec_str() const; // -- Class methods @@ -78,7 +79,7 @@ class Projection { friend class Grid; - friend bool operator==(const Projection& a, const Projection& b) { return a.spec() == b.spec(); } + friend bool operator==(const Projection& a, const Projection& b) { return a.spec_str() == b.spec_str(); } friend bool operator!=(const Projection& a, const Projection& b) { return !(a == b); } }; diff --git a/src/eckit/geo/iterator/Reduced.cc b/src/eckit/geo/iterator/Reduced.cc index 3e0348893..e6e785f4c 100644 --- a/src/eckit/geo/iterator/Reduced.cc +++ b/src/eckit/geo/iterator/Reduced.cc @@ -92,4 +92,9 @@ size_t Reduced::j(size_t idx) const { } +void Reduced::spec(spec::Custom&) const { + // FIXME implement +} + + } // namespace eckit::geo::iterator diff --git a/src/eckit/geo/iterator/Reduced.h b/src/eckit/geo/iterator/Reduced.h index b886feaad..95c9cb121 100644 --- a/src/eckit/geo/iterator/Reduced.h +++ b/src/eckit/geo/iterator/Reduced.h @@ -54,6 +54,8 @@ class Reduced final : public geo::Iterator { size_t index() const override { return index_; } size_t j(size_t idx) const; + + void spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/iterator/Regular.cc b/src/eckit/geo/iterator/Regular.cc index c1bbadf29..362a7b420 100644 --- a/src/eckit/geo/iterator/Regular.cc +++ b/src/eckit/geo/iterator/Regular.cc @@ -67,4 +67,9 @@ Point Regular::operator*() const { } +void Regular::spec(spec::Custom&) const { + // FIXME implement +} + + } // namespace eckit::geo::iterator diff --git a/src/eckit/geo/iterator/Regular.h b/src/eckit/geo/iterator/Regular.h index 389b40662..dd1dec5a6 100644 --- a/src/eckit/geo/iterator/Regular.h +++ b/src/eckit/geo/iterator/Regular.h @@ -56,6 +56,8 @@ class Regular final : public Iterator { Point operator*() const override; size_t index() const override { return index_; } + + void spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/iterator/Unstructured.cc b/src/eckit/geo/iterator/Unstructured.cc index 70ab4c3be..07377eea6 100644 --- a/src/eckit/geo/iterator/Unstructured.cc +++ b/src/eckit/geo/iterator/Unstructured.cc @@ -122,4 +122,9 @@ Point Unstructured::operator*() const { } +void Unstructured::spec(spec::Custom&) const { + // FIXME implement +} + + } // namespace eckit::geo::iterator diff --git a/src/eckit/geo/iterator/Unstructured.h b/src/eckit/geo/iterator/Unstructured.h index 4636c8e34..ac3fb53ee 100644 --- a/src/eckit/geo/iterator/Unstructured.h +++ b/src/eckit/geo/iterator/Unstructured.h @@ -66,6 +66,8 @@ class Unstructured final : public Iterator { Point operator*() const override; size_t index() const override { return index_; } + + void spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/projection/Composer.cc b/src/eckit/geo/projection/Composer.cc index 106cf687c..4dc930d79 100644 --- a/src/eckit/geo/projection/Composer.cc +++ b/src/eckit/geo/projection/Composer.cc @@ -60,7 +60,7 @@ std::vector Composer::inv_points(const Point& p) const { void Composer::spec(spec::Custom& custom) const { std::vector specs; for (const auto* proj : *this) { - specs.emplace_back(proj->spec()); + specs.emplace_back(proj->spec_str()); } custom.set("projections", specs); diff --git a/tests/geo/projection_ll_to_xyz.cc b/tests/geo/projection_ll_to_xyz.cc index d6a63ff5c..49b4ae2bd 100644 --- a/tests/geo/projection_ll_to_xyz.cc +++ b/tests/geo/projection_ll_to_xyz.cc @@ -55,10 +55,10 @@ CASE("projection: ll_to_xyz") { SECTION("spec") { - EXPECT(to_xyz_1->spec() == R"({"r":1})"); - EXPECT(to_xyz_2->spec() == R"({"r":1})"); - EXPECT(to_xyz_3->spec() == R"({"a":1,"b":0.5})"); - EXPECT(to_xyz_4->spec() == R"({"a":1,"b":0.5})"); + EXPECT(to_xyz_1->spec_str() == R"({"r":1})"); + EXPECT(to_xyz_2->spec_str() == R"({"r":1})"); + EXPECT(to_xyz_3->spec_str() == R"({"a":1,"b":0.5})"); + EXPECT(to_xyz_4->spec_str() == R"({"a":1,"b":0.5})"); } From 0b11df2ca811fec93ad1ace4351351c86dfec31a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 31 May 2024 13:11:48 +0100 Subject: [PATCH 690/737] eckit::geo::Spec --- src/eckit/geo/Grid.cc | 36 +++++++-------- src/eckit/geo/Grid.h | 4 +- src/eckit/geo/grid/HEALPix.cc | 2 +- src/eckit/geo/grid/HEALPix.h | 2 +- src/eckit/geo/grid/ORCA.cc | 2 +- src/eckit/geo/grid/ORCA.h | 2 +- src/eckit/geo/grid/ReducedGaussian.cc | 2 +- src/eckit/geo/grid/ReducedGaussian.h | 2 +- src/eckit/geo/grid/ReducedLL.cc | 2 +- src/eckit/geo/grid/ReducedLL.h | 2 +- src/eckit/geo/grid/Regular.cc | 8 ++-- src/eckit/geo/grid/Regular.h | 4 +- src/eckit/geo/grid/Unstructured.cc | 2 +- src/eckit/geo/grid/Unstructured.h | 2 +- src/eckit/geo/spec/Custom.cc | 1 - src/eckit/geo/spec/Custom.h | 65 ++++++++++++++------------- 16 files changed, 68 insertions(+), 70 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 86b767fcc..0b2ba6cdc 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -56,9 +56,23 @@ spec::Custom* Grid::calculate_spec() const { auto* custom = new spec::Custom; ASSERT(custom != nullptr); - grid_spec(*custom); - area_spec(*custom); - projection_spec(*custom); + spec(*custom); + + if (area_) { + static const auto AREA_DEFAULT(area::BoundingBox{}.spec_str()); + + std::unique_ptr area(area_->spec()); + if (area->str() != AREA_DEFAULT) { + custom->set("area", area->str()); + } + } + + if (projection_) { + std::unique_ptr projection(projection_->spec()); + if (!projection->str().empty()) { + custom->set("projection", projection->str()); + } + } return custom; } @@ -195,25 +209,11 @@ Renumber Grid::no_reorder(size_t size) { } -void Grid::grid_spec(spec::Custom&) const { +void Grid::spec(spec::Custom&) const { NOTIMP; } -void Grid::area_spec(spec::Custom& custom) const { - if (area_) { - area_->spec(custom); - } -} - - -void Grid::projection_spec(spec::Custom& custom) const { - if (projection_) { - projection_->spec(custom); - } -} - - const Grid* GridFactory::make_from_string(const std::string& str) { std::unique_ptr spec(spec::Custom::make_from_value(YAMLParser::decodeString(str))); return instance().make_from_spec_(*spec); diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index 2e534b339..f8b004945 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -161,9 +161,7 @@ class Grid { // -- Methods - virtual void grid_spec(spec::Custom&) const; - virtual void area_spec(spec::Custom&) const; - virtual void projection_spec(spec::Custom&) const; + virtual void spec(spec::Custom&) const; // -- Friends diff --git a/src/eckit/geo/grid/HEALPix.cc b/src/eckit/geo/grid/HEALPix.cc index d9f9d10bf..9bf0d0108 100644 --- a/src/eckit/geo/grid/HEALPix.cc +++ b/src/eckit/geo/grid/HEALPix.cc @@ -358,7 +358,7 @@ std::vector HEALPix::longitudes(size_t j) const { } -void HEALPix::grid_spec(spec::Custom& custom) const { +void HEALPix::spec(spec::Custom& custom) const { custom.set("grid", "H" + std::to_string(Nside_)); custom.set("ordering", ordering_ == Ordering::healpix_ring ? "ring" : "nested"); } diff --git a/src/eckit/geo/grid/HEALPix.h b/src/eckit/geo/grid/HEALPix.h index e2e28d08a..55a547125 100644 --- a/src/eckit/geo/grid/HEALPix.h +++ b/src/eckit/geo/grid/HEALPix.h @@ -64,7 +64,7 @@ class HEALPix final : public Reduced { bool includesSouthPole() const override { return true; } bool isPeriodicWestEast() const override { return true; } - void grid_spec(spec::Custom&) const override; + void spec(spec::Custom&) const override; const std::vector& latitudes() const override; std::vector longitudes(size_t i) const override; diff --git a/src/eckit/geo/grid/ORCA.cc b/src/eckit/geo/grid/ORCA.cc index e19ecfbb8..3e59e05c6 100644 --- a/src/eckit/geo/grid/ORCA.cc +++ b/src/eckit/geo/grid/ORCA.cc @@ -321,7 +321,7 @@ Spec* ORCA::spec(const std::string& name) { } -void ORCA::grid_spec(spec::Custom& custom) const { +void ORCA::spec(spec::Custom& custom) const { custom.set("type", "ORCA"); custom.set("uid", uid_); } diff --git a/src/eckit/geo/grid/ORCA.h b/src/eckit/geo/grid/ORCA.h index d48dcd97b..a08c5ada6 100644 --- a/src/eckit/geo/grid/ORCA.h +++ b/src/eckit/geo/grid/ORCA.h @@ -104,7 +104,7 @@ class ORCA final : public Regular { // -- Overridden methods - void grid_spec(spec::Custom&) const override; + void spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/grid/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc index c9df186db..d57f999c3 100644 --- a/src/eckit/geo/grid/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -108,7 +108,7 @@ std::vector ReducedGaussian::longitudes(size_t j) const { } -void ReducedGaussian::grid_spec(spec::Custom& custom) const { +void ReducedGaussian::spec(spec::Custom& custom) const { if (pl_ == util::reduced_octahedral_pl(N_)) { custom.set("grid", "O" + std::to_string(N_)); } diff --git a/src/eckit/geo/grid/ReducedGaussian.h b/src/eckit/geo/grid/ReducedGaussian.h index 2657be29d..781f3b7af 100644 --- a/src/eckit/geo/grid/ReducedGaussian.h +++ b/src/eckit/geo/grid/ReducedGaussian.h @@ -53,7 +53,7 @@ class ReducedGaussian : public Reduced { // -- Overridden methods - void grid_spec(spec::Custom&) const override; + void spec(spec::Custom&) const override; const std::vector& latitudes() const override; std::vector longitudes(size_t i) const override; diff --git a/src/eckit/geo/grid/ReducedLL.cc b/src/eckit/geo/grid/ReducedLL.cc index 82ecd54f4..f98c2e7be 100644 --- a/src/eckit/geo/grid/ReducedLL.cc +++ b/src/eckit/geo/grid/ReducedLL.cc @@ -66,7 +66,7 @@ std::vector ReducedLL::longitudes(size_t j) const { } -void ReducedLL::grid_spec(spec::Custom& custom) const { +void ReducedLL::spec(spec::Custom& custom) const { custom.set("type", "reduced_ll"); custom.set("pl", pl_); boundingBox().spec(custom); diff --git a/src/eckit/geo/grid/ReducedLL.h b/src/eckit/geo/grid/ReducedLL.h index c11bd1331..114e7d055 100644 --- a/src/eckit/geo/grid/ReducedLL.h +++ b/src/eckit/geo/grid/ReducedLL.h @@ -50,7 +50,7 @@ class ReducedLL : public Reduced { const std::vector& latitudes() const override; std::vector longitudes(size_t j) const override; - void grid_spec(spec::Custom&) const override; + void spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index 975ceb6da..ef87fc103 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -125,7 +125,7 @@ Spec* RegularLL::spec(const std::string& name) { } -void RegularLL::grid_spec(spec::Custom& custom) const { +void RegularLL::spec(spec::Custom& custom) const { custom.set("grid", std::vector{dx(), dy()}); boundingBox().spec(custom); } @@ -158,7 +158,7 @@ Spec* RegularGaussian::spec(const std::string& name) { } -void RegularGaussian::grid_spec(spec::Custom& custom) const { +void RegularGaussian::spec(spec::Custom& custom) const { custom.set("grid", "F" + std::to_string(N_)); boundingBox().spec(custom); } @@ -167,7 +167,7 @@ void RegularGaussian::grid_spec(spec::Custom& custom) const { struct Mercator final : public Regular { explicit Mercator(const Spec& spec) : Regular(Regular::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} - void grid_spec(spec::Custom& custom) const override { + void spec(spec::Custom& custom) const override { custom.set("type", "mercator"); custom.set("grid", std::vector{dx(), dy()}); custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); @@ -186,7 +186,7 @@ struct Mercator final : public Regular { struct LambertAzimuthalEqualArea final : public Regular { explicit LambertAzimuthalEqualArea(const Spec& spec) : Regular(Regular::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} - void grid_spec(spec::Custom& custom) const override { + void spec(spec::Custom& custom) const override { custom.set("type", "lambert_azimuthal_equal_area"); custom.set("grid", std::vector{dx(), dy()}); custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index c03973f06..037f88d66 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -82,7 +82,7 @@ struct RegularLL final : public Regular { RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); [[nodiscard]] static Spec* spec(const std::string& name); - void grid_spec(spec::Custom&) const override; + void spec(spec::Custom&) const override; }; @@ -93,7 +93,7 @@ struct RegularGaussian final : public Regular { [[nodiscard]] Grid* make_grid_cropped(const area::BoundingBox& crop) const override; [[nodiscard]] static Spec* spec(const std::string& name); - void grid_spec(spec::Custom&) const override; + void spec(spec::Custom&) const override; size_t N() const { return N_; } diff --git a/src/eckit/geo/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc index 0af13c8c7..cf477256e 100644 --- a/src/eckit/geo/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -38,7 +38,7 @@ Spec* Unstructured::spec(const std::string& name) { } -void Unstructured::grid_spec(spec::Custom& custom) const { +void Unstructured::spec(spec::Custom& custom) const { custom.set("type", "unstructured"); custom.set("uid", uid()); } diff --git a/src/eckit/geo/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h index d0fb9359d..ed7bc68ad 100644 --- a/src/eckit/geo/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -55,7 +55,7 @@ class Unstructured final : public Grid { // -- Overridden methods - void grid_spec(spec::Custom&) const override; + void spec(spec::Custom&) const override; // -- Friends diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index ef10d5663..01edaf633 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -13,7 +13,6 @@ #include #include -#include #include #include "eckit/exception/Exceptions.h" diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 56b8c422f..1c202556c 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -64,43 +64,44 @@ class Custom final : public Spec { void set(const std::string& name, const char* value) { set(name, std::string{value}); } - void set(const std::string& name, const std::string& value); - void set(const std::string& name, bool value); - void set(const std::string& name, int value); - void set(const std::string& name, long value); - void set(const std::string& name, long long value); - void set(const std::string& name, size_t value); - void set(const std::string& name, float value); - void set(const std::string& name, double value); - void set(const std::string& name, const std::vector& value); - void set(const std::string& name, const std::vector& value); - void set(const std::string& name, const std::vector& value); - void set(const std::string& name, const std::vector& value); - void set(const std::string& name, const std::vector& value); - void set(const std::string& name, const std::vector& value); - void set(const std::string& name, const std::vector& value); - - void set(const std::string& name, const Value& value); + void set(const std::string& name, const std::string&); + void set(const std::string& name, bool); + void set(const std::string& name, int); + void set(const std::string& name, long); + void set(const std::string& name, long long); + void set(const std::string& name, size_t); + void set(const std::string& name, float); + void set(const std::string& name, double); + void set(const std::string& name, const std::vector&); + void set(const std::string& name, const std::vector&); + void set(const std::string& name, const std::vector&); + void set(const std::string& name, const std::vector&); + void set(const std::string& name, const std::vector&); + void set(const std::string& name, const std::vector&); + void set(const std::string& name, const std::vector&); + + void set(const std::string& name, const Value&); + void set(const std::string& name, const Custom&); // -- Overridden methods bool has(const std::string& name) const override; - bool get(const std::string& name, std::string& value) const override; - bool get(const std::string& name, bool& value) const override; - bool get(const std::string& name, int& value) const override; - bool get(const std::string& name, long& value) const override; - bool get(const std::string& name, long long& value) const override; - bool get(const std::string& name, size_t& value) const override; - bool get(const std::string& name, float& value) const override; - bool get(const std::string& name, double& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; - bool get(const std::string& name, std::vector& value) const override; + bool get(const std::string& name, std::string&) const override; + bool get(const std::string& name, bool&) const override; + bool get(const std::string& name, int&) const override; + bool get(const std::string& name, long&) const override; + bool get(const std::string& name, long long&) const override; + bool get(const std::string& name, size_t&) const override; + bool get(const std::string& name, float&) const override; + bool get(const std::string& name, double&) const override; + bool get(const std::string& name, std::vector&) const override; + bool get(const std::string& name, std::vector&) const override; + bool get(const std::string& name, std::vector&) const override; + bool get(const std::string& name, std::vector&) const override; + bool get(const std::string& name, std::vector&) const override; + bool get(const std::string& name, std::vector&) const override; + bool get(const std::string& name, std::vector&) const override; // -- Class methods From 887900491f26de295669a23e9d3e97c6c7766c37 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 31 May 2024 17:44:08 +0100 Subject: [PATCH 691/737] eckit::geo::Spec --- src/eckit/geo/spec/Custom.cc | 56 +++++++++++++++---- src/eckit/geo/spec/Custom.h | 24 +++++++-- tests/geo/spec.cc | 88 +++++++++++++++--------------- tests/geo/spec_custom.cc | 101 ++++++++++++++++++++++++++--------- 4 files changed, 186 insertions(+), 83 deletions(-) diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 01edaf633..02cca923d 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -134,17 +134,14 @@ Custom::value_type from_value_t(const Value& value) { } -JSON& operator<<(JSON& out, const Custom::value_type& value) { - std::visit([&](const auto& arg) { out << arg; }, value); - return out; -} - - void sanitise(Custom::container_type& container) { std::for_each(container.begin(), container.end(), [](auto& p) { if (auto& value = p.second; std::holds_alternative(value)) { value = std::string{std::get(value)}; } + else if (std::holds_alternative(value)) { + ASSERT(std::get(value)); + } }); } @@ -195,7 +192,10 @@ Custom* Custom::make_from_value(const Value& value) { Custom::container_type container; for (const auto& [key, value] : static_cast(value)) { const std::string name = key; - container[name] = value.isList() ? vector(value) : scalar(value); + + container[name] = value.isMap() ? custom_type(Custom::make_from_value(value)) + : value.isList() ? vector(value) + : scalar(value); } return new Custom(std::move(container)); @@ -318,6 +318,30 @@ void Custom::set(const std::string& key, const Value& value) { } +void Custom::set(const std::string& name, Custom* value) { + ASSERT(value != nullptr); + map_[name] = custom_type(value); +} + + +bool Custom::get(const std::string& name, custom_type& value) const { + if (auto it = map_.find(name); it != map_.cend()) { + if (std::holds_alternative(it->second)) { + value = std::get(it->second); + return true; + } + } + + return false; +} + + +void Custom::set(const std::string& name, const custom_type& value) { + ASSERT(value); + map_[name] = value; +} + + bool Custom::has(const std::string& name) const { return map_.find(name) != map_.cend(); } @@ -425,11 +449,25 @@ bool Custom::get(const std::string& name, std::vector& value) const void Custom::json(JSON& j) const { j.startObject(); - for (const auto& nv : map_) { - j << nv.first << nv.second; + for (const auto& [key, value] : map_) { + j << key; + std::visit([&](const auto& arg) { j << arg; }, value); } j.endObject(); } +JSON& operator<<(JSON& j, const Custom::custom_type& value) { + ASSERT(value); + j.startObject(); + for (const auto& [key, value] : value->container()) { + j << key; + std::visit([&](const auto& arg) { j << arg; }, value); + } + + j.endObject(); + return j; +} + + } // namespace eckit::geo::spec diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 1c202556c..88f4e3c87 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -13,6 +13,7 @@ #include #include +#include #include #include "eckit/geo/Spec.h" @@ -35,10 +36,14 @@ class Custom final : public Spec { key_type(const char* s) : key_type(std::string{s}) {} }; - using value_type - = std::variant, - std::vector, std::vector, std::vector, std::vector, - std::vector, std::vector, const char* /* converted to std::string */>; + struct custom_type : std::shared_ptr { + using shared_ptr::shared_ptr; + }; + + using value_type = std::variant, + std::vector, std::vector, std::vector, std::vector, + std::vector, std::vector, custom_type, + const char* /* converted to std::string */>; using container_type = std::map; @@ -81,7 +86,9 @@ class Custom final : public Spec { void set(const std::string& name, const std::vector&); void set(const std::string& name, const Value&); - void set(const std::string& name, const Custom&); + void set(const std::string& name, Custom*); + + bool get(const std::string& name, custom_type&) const; // -- Overridden methods @@ -111,7 +118,14 @@ class Custom final : public Spec { // -- Members container_type map_; + + // -- Methods + + void set(const std::string& name, const custom_type&); }; +JSON& operator<<(JSON&, const Custom::custom_type&); + + } // namespace eckit::geo::spec diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 78de03db4..6107ab590 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -33,50 +33,50 @@ CASE("user -> type") { ASSERT(BAD.empty()); static std::pair tests[]{ - {C({{"N", 2}}), C({{"N", 2}, {"type", "reduced_gg"}})}, - {C({{"area", v{90, -180, -90, 180}}, {"grid", v{2, 2}}}), C({{"type", "regular_ll"}})}, - {C({{"area", v{90, -180, -90, 180}}}), BAD}, - {C({{"grid", "B48"}}), BAD}, - {C({{"grid", "F48"}}), C({{"type", "regular_gg"}})}, - {C({{"grid", "N48"}}), C({{"type", "reduced_gg"}})}, - {C({{"grid", "O48"}}), C({{"type", "reduced_gg"}})}, - {C({{"grid", 48}}), BAD}, - {C({{"grid", v{2, 2}}}), C({{"grid", v{2, 2}}, {"type", "regular_ll"}})}, - {C({{"type", "latlon"}, {"grid", v{2, 2}}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "48"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "F048"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "N"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "N048"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "N48"}}), C({{"type", "reduced_gg"}})}, - {C({{"type", "reduced_gg"}, {"grid", "O048"}}), BAD}, - {C({{"type", "reduced_gg"}, {"grid", "O48"}}), C({{"type", "reduced_gg"}})}, - {C({{"type", "reduced_gg"}, {"grid", 48}}), BAD}, - {C({{"type", "reduced_gg"}}), BAD}, - {C({{"type", "reduced_latlon"}, {"grid", 2}}), BAD}, - {C({{"type", "reduced_ll"}, {"grid", 12}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "48"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "F048"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "F48"}}), C({{"type", "regular_gg"}})}, - {C({{"type", "regular_gg"}, {"grid", "N48"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "O48"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", "a"}}), BAD}, - {C({{"type", "regular_gg"}, {"grid", 48}}), BAD}, - {C({{"type", "regular_ll"}, {"area", v{90, -180, -90, 180}}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", "F48"}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", "a"}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", 48}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", std::vector{"a", "b"}}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", v{1, 2, 3}}}), BAD}, - {C({{"type", "regular_ll"}, {"grid", v{1, 2}}}), C({{"type", "regular_ll"}})}, - {C({{"type", "regular_ll"}, {"grid", v{1}}}), BAD}, - - {C({{"type", "mercator"}, - {"area", v{31.173058, 262.036499, 14.736453, 284.975281}}, - {"grid", v{45000.0, 45000.0}}, - {"shape", std::vector{56, 44}}, - {"lad", 14.0}, - {"orientation", 0.0}}), - C()}, + {{{"N", 2}}, {{"N", 2}, {"type", "reduced_gg"}}}, + {{{"area", v{90, -180, -90, 180}}, {"grid", v{2, 2}}}, {{"type", "regular_ll"}}}, + {{{"area", v{90, -180, -90, 180}}}, BAD}, + {{{"grid", "B48"}}, BAD}, + {{{"grid", "F48"}}, {{"type", "regular_gg"}}}, + {{{"grid", "N48"}}, {{"type", "reduced_gg"}}}, + {{{"grid", "O48"}}, {{"type", "reduced_gg"}}}, + {{{"grid", 48}}, BAD}, + {{{"grid", v{2, 2}}}, {{"grid", v{2, 2}}, {"type", "regular_ll"}}}, + {{{"type", "latlon"}, {"grid", v{2, 2}}}, BAD}, + {{{"type", "reduced_gg"}, {"grid", "48"}}, BAD}, + {{{"type", "reduced_gg"}, {"grid", "F048"}}, BAD}, + {{{"type", "reduced_gg"}, {"grid", "N"}}, BAD}, + {{{"type", "reduced_gg"}, {"grid", "N048"}}, BAD}, + {{{"type", "reduced_gg"}, {"grid", "N48"}}, {{"type", "reduced_gg"}}}, + {{{"type", "reduced_gg"}, {"grid", "O048"}}, BAD}, + {{{"type", "reduced_gg"}, {"grid", "O48"}}, {{"type", "reduced_gg"}}}, + {{{"type", "reduced_gg"}, {"grid", 48}}, BAD}, + {{{"type", "reduced_gg"}}, BAD}, + {{{"type", "reduced_latlon"}, {"grid", 2}}, BAD}, + {{{"type", "reduced_ll"}, {"grid", 12}}, BAD}, + {{{"type", "regular_gg"}, {"grid", "48"}}, BAD}, + {{{"type", "regular_gg"}, {"grid", "F048"}}, BAD}, + {{{"type", "regular_gg"}, {"grid", "F48"}}, {{"type", "regular_gg"}}}, + {{{"type", "regular_gg"}, {"grid", "N48"}}, BAD}, + {{{"type", "regular_gg"}, {"grid", "O48"}}, BAD}, + {{{"type", "regular_gg"}, {"grid", "a"}}, BAD}, + {{{"type", "regular_gg"}, {"grid", 48}}, BAD}, + {{{"type", "regular_ll"}, {"area", v{90, -180, -90, 180}}}, BAD}, + {{{"type", "regular_ll"}, {"grid", "F48"}}, BAD}, + {{{"type", "regular_ll"}, {"grid", "a"}}, BAD}, + {{{"type", "regular_ll"}, {"grid", 48}}, BAD}, + {{{"type", "regular_ll"}, {"grid", std::vector{"a", "b"}}}, BAD}, + {{{"type", "regular_ll"}, {"grid", v{1, 2, 3}}}, BAD}, + {{{"type", "regular_ll"}, {"grid", v{1, 2}}}, {{"type", "regular_ll"}}}, + {{{"type", "regular_ll"}, {"grid", v{1}}}, BAD}, + + {{{"type", "mercator"}, + {"area", v{31.173058, 262.036499, 14.736453, 284.975281}}, + {"grid", v{45000.0, 45000.0}}, + {"shape", std::vector{56, 44}}, + {"lad", 14.0}, + {"orientation", 0.0}}, + {}}, }; for (const auto& [user, ref] : tests) { diff --git a/tests/geo/spec_custom.cc b/tests/geo/spec_custom.cc index c622cc1b0..1b88d2d95 100644 --- a/tests/geo/spec_custom.cc +++ b/tests/geo/spec_custom.cc @@ -16,6 +16,7 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/spec/Custom.h" +#include "eckit/parser/YAMLParser.h" #include "eckit/testing/Test.h" #include "eckit/types/FloatCompare.h" @@ -23,6 +24,9 @@ namespace eckit::geo::test { +using spec::Custom; + + template struct is_vector : std::false_type {}; @@ -94,13 +98,60 @@ CASE("Custom::value_type") { CASE("Custom::container_type") { - spec::Custom spec({{std::string{"foo"}, "bar"}}); + Custom spec({{std::string{"foo"}, "bar"}}); std::string bar; EXPECT(spec.get("foo", bar) && bar == "bar"); } +CASE("Custom::custom_type") { + Custom custom1({{"custom1", Custom::custom_type(new Custom({{"foo", "bar"}, {"boo", "far"}}))}}); + + EXPECT(custom1.str() == R"({"custom1":{"boo":"far","foo":"bar"}})"); + + Custom custom2({{"custom2", Custom::custom_type(new Custom(custom1.container()))}}); + + EXPECT(custom2.str() == R"({"custom2":{"custom1":{"boo":"far","foo":"bar"}}})"); + + Custom customer1({{"customer", Custom::custom_type(Custom::make_from_value( + YAMLParser::decodeString("{name: John Smith, age: 33}")))}}); + + EXPECT(customer1.str() == R"({"customer":{"age":33,"name":"John Smith"}})"); + + Custom customer2({{"customer", Custom::custom_type(Custom::make_from_value(YAMLParser::decodeString(R"( +name: John Smith +age: 33 +)")))}}); + + EXPECT(customer2.str() == customer1.str()); + + Custom nested({{"a", Custom::custom_type(Custom::make_from_value(YAMLParser::decodeString(R"( +b: + c: 1 + d: "2" +)")))}}); + + EXPECT(nested.str() == R"({"a":{"b":{"c":1,"d":"2"}}})"); + + Custom::custom_type a; + + EXPECT(not a && not nested.get("a?", a) && nested.get("a", a) && a); + + Custom::custom_type b; + + EXPECT(not b && a->get("b", b) && b); + + int c = 0; + + EXPECT(b->get("c", c) && c == 1); + + std::string d; + + EXPECT(b->get("d", d) && d == "2"); +} + + CASE("Spec <- Custom") { constexpr int zero = 0; constexpr int one = 1; @@ -109,7 +160,7 @@ CASE("Spec <- Custom") { SECTION("access") { - std::unique_ptr spec(new spec::Custom({{"a", -123}, {"b", "B"}, {"c", 123UL}})); + std::unique_ptr spec(new Custom({{"a", -123}, {"b", "B"}, {"c", 123UL}})); int a = 0; EXPECT(spec->get("a", a)); @@ -128,14 +179,14 @@ CASE("Spec <- Custom") { EXPECT_EQUAL(b2, b); int d = 0; - dynamic_cast(spec.get())->set("B", 321); + dynamic_cast(spec.get())->set("B", 321); EXPECT(spec->get("b", d)); EXPECT_EQUAL(d, 321); } SECTION("conversion (1)") { - spec::Custom a({ + Custom a({ {"double", static_cast(one)}, {"float", static_cast(one)}, {"int", static_cast(one)}, @@ -170,7 +221,7 @@ CASE("Spec <- Custom") { SECTION("conversion (2)") { - spec::Custom b({ + Custom b({ {"true", true}, {"false", false}, {"zero", 0}, @@ -204,7 +255,7 @@ CASE("Spec <- Custom") { SECTION("conversion (3)") { - spec::Custom c; + Custom c; EXPECT_NOT(c.has("foo")); c.set("foo", two); @@ -222,7 +273,7 @@ CASE("Spec <- Custom") { EXPECT(c.get_string("foo") == three); - spec::Custom d(c.container()); + Custom d(c.container()); EXPECT(d.has("foo")); EXPECT(d.get_string("foo") == three); @@ -233,7 +284,7 @@ CASE("Spec <- Custom") { EXPECT(d.get_int("foo") == one); - spec::Custom e(d.container()); + Custom e(d.container()); ASSERT(e.has("foo")); ASSERT(e.has("bar")); @@ -241,7 +292,7 @@ CASE("Spec <- Custom") { SECTION("conversion (4)") { - spec::Custom e({{"zero", zero}, {"one", one}, {"two", two}}); + Custom e({{"zero", zero}, {"one", one}, {"two", two}}); bool maybe = true; EXPECT(!e.get("?", maybe) && maybe); // non-existant key @@ -254,28 +305,28 @@ CASE("Spec <- Custom") { SECTION("json") { // test ordering - std::unique_ptr a(new spec::Custom({{"c", "c"}, {"a", "a"}, {"b", 1}})); + std::unique_ptr a(new Custom({{"c", "c"}, {"a", "a"}, {"b", 1}})); const std::string a_str = a->str(); const std::string a_ref = R"({"a":"a","b":1,"c":"c"})"; EXPECT_EQUAL(a_str, a_ref); // test types - std::unique_ptr b(new spec::Custom({{"string", "string"}, - {"bool", true}, - {"int", static_cast(1)}, - {"long", static_cast(2)}, - {"long long", static_cast(3)}, - {"size_t", static_cast(4)}, - {"float", static_cast(5)}, - {"double", static_cast(6)}, - {"vector", std::vector{1, 1}}, - {"vector", std::vector{2, 2}}, - {"vector", std::vector{3, 3}}, - {"vector", std::vector{4, 4}}, - {"vector", std::vector{5, 5}}, - {"vector", std::vector{6, 6}}, - {"vector", std::vector{"string", "string"}}})); + std::unique_ptr b(new Custom({{"string", "string"}, + {"bool", true}, + {"int", static_cast(1)}, + {"long", static_cast(2)}, + {"long long", static_cast(3)}, + {"size_t", static_cast(4)}, + {"float", static_cast(5)}, + {"double", static_cast(6)}, + {"vector", std::vector{1, 1}}, + {"vector", std::vector{2, 2}}, + {"vector", std::vector{3, 3}}, + {"vector", std::vector{4, 4}}, + {"vector", std::vector{5, 5}}, + {"vector", std::vector{6, 6}}, + {"vector", std::vector{"string", "string"}}})); const std::string b_str = b->str(); const std::string b_ref From 2e47861d08391ba3466b561391bbe7527f5535ee Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 1 Jun 2024 09:01:08 +0100 Subject: [PATCH 692/737] eckit::geo::Spec --- src/eckit/geo/Grid.cc | 5 +++-- src/eckit/geo/Projection.cc | 5 +---- src/eckit/geo/Spec.cc | 4 +--- src/eckit/geo/spec/Custom.cc | 10 ++++++---- src/eckit/geo/spec/Custom.h | 6 +++--- tests/geo/spec_custom.cc | 32 ++++++++++++++++++++++++-------- 6 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 0b2ba6cdc..d76b36aa8 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -63,14 +63,15 @@ spec::Custom* Grid::calculate_spec() const { std::unique_ptr area(area_->spec()); if (area->str() != AREA_DEFAULT) { - custom->set("area", area->str()); + custom->set("area", area.release()); } } if (projection_) { std::unique_ptr projection(projection_->spec()); + if (!projection->str().empty()) { - custom->set("projection", projection->str()); + custom->set("projection", projection.release()); } } diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index 721a1f1fd..56a3061eb 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -13,7 +13,6 @@ #include "eckit/geo/Projection.h" #include -#include #include "eckit/exception/Exceptions.h" #include "eckit/geo/spec/Custom.h" @@ -23,9 +22,7 @@ namespace eckit::geo { ProjectionProblem::ProjectionProblem(const std::string& what, const CodeLocation& loc) : Exception(loc) { - std::ostringstream s; - s << "ProjectionProblem: [" << what << "], in " << loc; - reason(s.str()); + reason("ProjectionProblem: [" + what + "], in " + loc.asString()); }; diff --git a/src/eckit/geo/Spec.cc b/src/eckit/geo/Spec.cc index f12d3d707..5f5d8e89d 100644 --- a/src/eckit/geo/Spec.cc +++ b/src/eckit/geo/Spec.cc @@ -35,9 +35,7 @@ static T _get_t(const Spec& spec, const std::string& name) { SpecNotFound::SpecNotFound(const std::string& name, const CodeLocation& loc) : Exception(loc) { - std::ostringstream s; - s << "SpecNotFound: [" << name << "], in " << loc; - reason(s.str()); + reason("SpecNotFound: [" + name + "], in " + loc.asString()); } diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 02cca923d..d502db6a6 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -324,15 +324,17 @@ void Custom::set(const std::string& name, Custom* value) { } -bool Custom::get(const std::string& name, custom_type& value) const { +const Custom::custom_type& Custom::custom(const std::string& name) const { if (auto it = map_.find(name); it != map_.cend()) { if (std::holds_alternative(it->second)) { - value = std::get(it->second); - return true; + const auto& value = std::get(it->second); + ASSERT(value); + + return value; } } - return false; + throw SpecNotFound("Custom::get(" + name + ") -> custom_type& ", Here()); } diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 88f4e3c87..9869453e0 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -58,6 +58,7 @@ class Custom final : public Spec { // -- Operators bool operator==(const Custom&) const; + bool operator!=(const Custom& other) const { return !operator==(other); } // -- Methods @@ -67,7 +68,7 @@ class Custom final : public Spec { void json(JSON&) const override; - void set(const std::string& name, const char* value) { set(name, std::string{value}); } + const custom_type& custom(const std::string& name) const; void set(const std::string& name, const std::string&); void set(const std::string& name, bool); @@ -85,11 +86,10 @@ class Custom final : public Spec { void set(const std::string& name, const std::vector&); void set(const std::string& name, const std::vector&); + void set(const std::string& name, const char* value) { set(name, std::string{value}); } void set(const std::string& name, const Value&); void set(const std::string& name, Custom*); - bool get(const std::string& name, custom_type&) const; - // -- Overridden methods bool has(const std::string& name) const override; diff --git a/tests/geo/spec_custom.cc b/tests/geo/spec_custom.cc index 1b88d2d95..fa8fdcb55 100644 --- a/tests/geo/spec_custom.cc +++ b/tests/geo/spec_custom.cc @@ -134,21 +134,37 @@ age: 33 EXPECT(nested.str() == R"({"a":{"b":{"c":1,"d":"2"}}})"); - Custom::custom_type a; + EXPECT_THROWS_AS(nested.custom("a?"), SpecNotFound); + EXPECT_THROWS_AS(nested.custom("a")->custom("b?"), SpecNotFound); - EXPECT(not a && not nested.get("a?", a) && nested.get("a", a) && a); - - Custom::custom_type b; - - EXPECT(not b && a->get("b", b) && b); + const auto& b = nested.custom("a")->custom("b"); + ASSERT(b); int c = 0; + std::string d; EXPECT(b->get("c", c) && c == 1); + EXPECT(b->get("d", d) && d == "2"); +} - std::string d; - EXPECT(b->get("d", d) && d == "2"); +CASE("Custom::operator==") { + Custom a({{"foo", "bar"}, {"boo", "far"}}); + Custom b({{"bOo", "far"}, {"Foo", "bar"}}); + Custom c({{"foo", "bar"}, {"boo", "faR"}}); + + EXPECT(a == b); + EXPECT(a != c); + EXPECT_NOT(a != b); + EXPECT_NOT(a == c); + + // not commutative + Custom d({{"foo", "bar"}, {"boo", "far"}, {"roo", "fab"}}); + + EXPECT(a == d); + EXPECT(d != a); + EXPECT_NOT(a != d); + EXPECT_NOT(d == a); } From a4f332fd3b79c9160c72b97a06c745a8515491eb Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 1 Jun 2024 21:01:15 +0100 Subject: [PATCH 693/737] eckit::geo::Spec --- src/eckit/geo/spec/Custom.cc | 6 ++++++ src/eckit/geo/spec/Custom.h | 1 + tests/geo/spec_custom.cc | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index d502db6a6..43b5239ec 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -324,6 +324,12 @@ void Custom::set(const std::string& name, Custom* value) { } +bool Custom::has_custom(const std::string& name) const { + auto it = map_.find(name); + return it != map_.cend() && std::holds_alternative(it->second); +} + + const Custom::custom_type& Custom::custom(const std::string& name) const { if (auto it = map_.find(name); it != map_.cend()) { if (std::holds_alternative(it->second)) { diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 9869453e0..8671e4de0 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -68,6 +68,7 @@ class Custom final : public Spec { void json(JSON&) const override; + bool has_custom(const std::string& name) const; const custom_type& custom(const std::string& name) const; void set(const std::string& name, const std::string&); diff --git a/tests/geo/spec_custom.cc b/tests/geo/spec_custom.cc index fa8fdcb55..71f11abc7 100644 --- a/tests/geo/spec_custom.cc +++ b/tests/geo/spec_custom.cc @@ -134,7 +134,12 @@ age: 33 EXPECT(nested.str() == R"({"a":{"b":{"c":1,"d":"2"}}})"); + EXPECT(nested.has_custom("a")); + EXPECT_NOT(nested.has_custom("a?")); EXPECT_THROWS_AS(nested.custom("a?"), SpecNotFound); + + EXPECT(nested.custom("a")->has_custom("b")); + EXPECT_NOT(nested.custom("a")->has_custom("b?")); EXPECT_THROWS_AS(nested.custom("a")->custom("b?"), SpecNotFound); const auto& b = nested.custom("a")->custom("b"); From e5eb3d07253a3a1b42c30d21d9a54a29631c0cad Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 2 Jun 2024 12:35:27 +0100 Subject: [PATCH 694/737] eckit::geo::Spec --- src/eckit/geo/Area.cc | 5 -- src/eckit/geo/Area.h | 7 ++- src/eckit/geo/Grid.cc | 67 ++++++++------------------- src/eckit/geo/Grid.h | 21 ++++----- src/eckit/geo/area/BoundingBox.cc | 10 ++-- src/eckit/geo/area/BoundingBox.h | 3 +- src/eckit/geo/grid/ReducedGaussian.cc | 10 ++-- src/eckit/geo/grid/ReducedGaussian.h | 2 +- src/eckit/geo/grid/ReducedLL.cc | 3 +- src/eckit/geo/grid/Regular.cc | 25 ++++++++-- src/eckit/geo/grid/Regular.h | 6 ++- src/eckit/geo/grid/Unstructured.cc | 2 + src/eckit/geo/spec/Custom.cc | 20 ++++---- src/eckit/geo/spec/Custom.h | 16 +++---- tests/geo/spec.cc | 5 +- tests/geo/spec_custom.cc | 10 ++-- 16 files changed, 101 insertions(+), 111 deletions(-) diff --git a/src/eckit/geo/Area.cc b/src/eckit/geo/Area.cc index 37e4a9a8e..c54f6b814 100644 --- a/src/eckit/geo/Area.cc +++ b/src/eckit/geo/Area.cc @@ -36,9 +36,4 @@ std::string Area::spec_str() const { } -void Area::spec(spec::Custom&) const { - NOTIMP; -} - - } // namespace eckit::geo diff --git a/src/eckit/geo/Area.h b/src/eckit/geo/Area.h index f5081aee0..6bde03de4 100644 --- a/src/eckit/geo/Area.h +++ b/src/eckit/geo/Area.h @@ -19,6 +19,9 @@ namespace eckit::geo { +namespace area { +class BoundingBox; +} class Spec; namespace spec { class Custom; @@ -57,6 +60,8 @@ class Area { [[nodiscard]] spec::Custom* spec() const; std::string spec_str() const; + virtual bool intersects(area::BoundingBox&) const = 0; + // -- Class methods static std::string className() { return "area"; } @@ -64,7 +69,7 @@ class Area { private: // -- Methods - virtual void spec(spec::Custom&) const; + virtual void spec(spec::Custom&) const = 0; // -- Friends diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index d76b36aa8..aff654593 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -44,41 +44,15 @@ Grid::Grid(const area::BoundingBox& bbox) : bbox_(new area::BoundingBox(bbox)) { const Spec& Grid::spec() const { if (!spec_) { - spec_.reset(calculate_spec()); + spec_ = std::make_unique(); ASSERT(spec_); + spec(*spec_); } return *spec_; } -spec::Custom* Grid::calculate_spec() const { - auto* custom = new spec::Custom; - ASSERT(custom != nullptr); - - spec(*custom); - - if (area_) { - static const auto AREA_DEFAULT(area::BoundingBox{}.spec_str()); - - std::unique_ptr area(area_->spec()); - if (area->str() != AREA_DEFAULT) { - custom->set("area", area.release()); - } - } - - if (projection_) { - std::unique_ptr projection(projection_->spec()); - - if (!projection->str().empty()) { - custom->set("projection", projection.release()); - } - } - - return custom; -} - - size_t Grid::size() const { NOTIMP; } @@ -153,7 +127,7 @@ Grid* Grid::make_grid_reordered(Ordering) const { const Area& Grid::area() const { if (!area_) { - area_.reset(calculate_area()); + area_ = std::make_unique(); ASSERT(area_); } @@ -161,12 +135,6 @@ const Area& Grid::area() const { } -Area* Grid::calculate_area() const { - // FIXME temporary implementation - return calculate_bbox(); -} - - Renumber Grid::crop(const Area&) const { NOTIMP; } @@ -193,16 +161,6 @@ area::BoundingBox* Grid::calculate_bbox() const { } -Renumber Grid::crop(const area::BoundingBox& bbox) const { - return crop(static_cast(bbox)); -} - - -Grid* Grid::make_grid_cropped(const area::BoundingBox& bbox) const { - return make_grid_cropped(static_cast(bbox)); -} - - Renumber Grid::no_reorder(size_t size) { Renumber ren(size); std::iota(ren.begin(), ren.end(), 0); @@ -210,8 +168,23 @@ Renumber Grid::no_reorder(size_t size) { } -void Grid::spec(spec::Custom&) const { - NOTIMP; +void Grid::spec(spec::Custom& custom) const { + if (area_) { + static const auto AREA_DEFAULT(area::BoundingBox{}.spec_str()); + + std::unique_ptr area(area_->spec()); + if (area->str() != AREA_DEFAULT) { + custom.set("area", area.release()); + } + } + + if (projection_) { + std::unique_ptr projection(projection_->spec()); + + if (!projection->str().empty()) { + custom.set("projection", projection.release()); + } + } } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index f8b004945..e16464656 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -107,7 +107,6 @@ class Grid { const Spec& spec() const; std::string spec_str() const { return spec().str(); } - [[nodiscard]] virtual spec::Custom* calculate_spec() const; virtual size_t size() const; @@ -125,16 +124,13 @@ class Grid { virtual Renumber reorder(Ordering) const; virtual const Area& area() const; - [[nodiscard]] virtual Area* calculate_area() const; virtual Renumber crop(const Area&) const; virtual const area::BoundingBox& boundingBox() const; [[nodiscard]] virtual area::BoundingBox* calculate_bbox() const; - virtual Renumber crop(const area::BoundingBox&) const; [[nodiscard]] virtual Grid* make_grid_reordered(Ordering) const; [[nodiscard]] virtual Grid* make_grid_cropped(const Area&) const; - [[nodiscard]] virtual Grid* make_grid_cropped(const area::BoundingBox&) const; // -- Class methods @@ -147,22 +143,23 @@ class Grid { // -- Methods + virtual void spec(spec::Custom&) const; + static Renumber no_reorder(size_t size); + void area(Area* ptr) { area_.reset(ptr); } + void projection(Projection* ptr) { projection_.reset(ptr); } + private: // -- Members - mutable std::unique_ptr area_; - mutable std::unique_ptr projection_; + mutable std::unique_ptr area_; + mutable std::unique_ptr projection_; - mutable std::unique_ptr bbox_; - mutable std::unique_ptr spec_; + mutable std::unique_ptr bbox_; + mutable std::unique_ptr spec_; mutable uid_t uid_; - // -- Methods - - virtual void spec(spec::Custom&) const; - // -- Friends friend bool operator==(const Grid& a, const Grid& b) { return a.spec_str() == b.spec_str(); } diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 3fbf2702e..1f5192f3c 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -29,6 +29,7 @@ namespace eckit::geo::area { static const BoundingBox GLOBE_PRIME{90., 0., -90., 360.}; static const BoundingBox GLOBE_ANTIPRIME{90., -180., -90., 180.}; +static const BoundingBox& DEFAULT = GLOBE_PRIME; BoundingBox* BoundingBox::make_global_prime() { @@ -42,14 +43,15 @@ BoundingBox* BoundingBox::make_global_antiprime() { void BoundingBox::spec(spec::Custom& custom) const { - if (operator!=(GLOBE_PRIME)) { - custom.set("area", std::vector{north, west, south, east}); + if (operator!=(DEFAULT)) { + custom.set("type", "bounding-box"); + custom.set("bounding-box", std::vector{north, west, south, east}); } } BoundingBox* BoundingBox::make_from_spec(const Spec& spec) { - const auto [n, w, s, e] = GLOBE_PRIME.deconstruct(); + const auto [n, w, s, e] = DEFAULT.deconstruct(); if (std::vector area{n, w, s, e}; spec.get("area", area)) { ASSERT_MSG(area.size() == 4, "BoundingBox: 'area' expected list of size 4"); @@ -87,7 +89,7 @@ BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s } -BoundingBox::BoundingBox() : BoundingBox(GLOBE_PRIME) {} +BoundingBox::BoundingBox() : BoundingBox(DEFAULT) {} bool BoundingBox::operator==(const BoundingBox& other) const { diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index f586ceaa1..9c8b506d3 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -73,8 +73,6 @@ class BoundingBox : public Area, protected std::array { bool containsNorthPole() const; bool containsSouthPole() const; - bool intersects(BoundingBox&) const; - bool contains(const PointLonLat&) const; bool contains(const BoundingBox&) const; bool empty() const; @@ -82,6 +80,7 @@ class BoundingBox : public Area, protected std::array { // -- Overridden methods void spec(spec::Custom&) const override; + bool intersects(BoundingBox&) const override; // -- Class methods diff --git a/src/eckit/geo/grid/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc index d57f999c3..7f2e00413 100644 --- a/src/eckit/geo/grid/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -109,6 +109,8 @@ std::vector ReducedGaussian::longitudes(size_t j) const { void ReducedGaussian::spec(spec::Custom& custom) const { + Reduced::spec(custom); + if (pl_ == util::reduced_octahedral_pl(N_)) { custom.set("grid", "O" + std::to_string(N_)); } @@ -118,14 +120,12 @@ void ReducedGaussian::spec(spec::Custom& custom) const { custom.set("pl", pl_); } } - - boundingBox().spec(custom); } -Grid* ReducedGaussian::make_grid_cropped(const area::BoundingBox& crop) const { - if (auto bbox(boundingBox()); crop.intersects(bbox)) { - return new ReducedGaussian(pl_, bbox); +Grid* ReducedGaussian::make_grid_cropped(const Area& crop) const { + if (auto cropped(boundingBox()); crop.intersects(cropped)) { + return new ReducedGaussian(pl_, cropped); } throw UserError("ReducedGaussian: cannot crop grid (empty intersection)", Here()); diff --git a/src/eckit/geo/grid/ReducedGaussian.h b/src/eckit/geo/grid/ReducedGaussian.h index 781f3b7af..d5a14527c 100644 --- a/src/eckit/geo/grid/ReducedGaussian.h +++ b/src/eckit/geo/grid/ReducedGaussian.h @@ -58,7 +58,7 @@ class ReducedGaussian : public Reduced { const std::vector& latitudes() const override; std::vector longitudes(size_t i) const override; - [[nodiscard]] Grid* make_grid_cropped(const area::BoundingBox&) const override; + [[nodiscard]] Grid* make_grid_cropped(const Area&) const override; }; diff --git a/src/eckit/geo/grid/ReducedLL.cc b/src/eckit/geo/grid/ReducedLL.cc index f98c2e7be..5116f0d39 100644 --- a/src/eckit/geo/grid/ReducedLL.cc +++ b/src/eckit/geo/grid/ReducedLL.cc @@ -67,9 +67,10 @@ std::vector ReducedLL::longitudes(size_t j) const { void ReducedLL::spec(spec::Custom& custom) const { + Reduced::spec(custom); + custom.set("type", "reduced_ll"); custom.set("pl", pl_); - boundingBox().spec(custom); } diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index ef87fc103..b662359ac 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -126,8 +126,18 @@ Spec* RegularLL::spec(const std::string& name) { void RegularLL::spec(spec::Custom& custom) const { + Regular::spec(custom); + custom.set("grid", std::vector{dx(), dy()}); - boundingBox().spec(custom); +} + + +Grid* RegularLL::make_grid_cropped(const Area& crop) const { + if (auto cropped(boundingBox()); crop.intersects(cropped)) { + return new RegularLL({dx(), dy()}, cropped); + } + + throw UserError("RegularGaussian: cannot crop grid (empty intersection)", Here()); } @@ -143,9 +153,9 @@ RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : } -Grid* RegularGaussian::make_grid_cropped(const area::BoundingBox& crop) const { - if (auto bbox(boundingBox()); crop.intersects(bbox)) { - return new RegularGaussian(N_, bbox); +Grid* RegularGaussian::make_grid_cropped(const Area& crop) const { + if (auto cropped(boundingBox()); crop.intersects(cropped)) { + return new RegularGaussian(N_, cropped); } throw UserError("RegularGaussian: cannot crop grid (empty intersection)", Here()); @@ -159,8 +169,9 @@ Spec* RegularGaussian::spec(const std::string& name) { void RegularGaussian::spec(spec::Custom& custom) const { + Regular::spec(custom); + custom.set("grid", "F" + std::to_string(N_)); - boundingBox().spec(custom); } @@ -168,6 +179,8 @@ struct Mercator final : public Regular { explicit Mercator(const Spec& spec) : Regular(Regular::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} void spec(spec::Custom& custom) const override { + Regular::spec(custom); + custom.set("type", "mercator"); custom.set("grid", std::vector{dx(), dy()}); custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); @@ -187,6 +200,8 @@ struct LambertAzimuthalEqualArea final : public Regular { explicit LambertAzimuthalEqualArea(const Spec& spec) : Regular(Regular::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} void spec(spec::Custom& custom) const override { + Regular::spec(custom); + custom.set("type", "lambert_azimuthal_equal_area"); custom.set("grid", std::vector{dx(), dy()}); custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index 037f88d66..cee2a5207 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -83,6 +83,8 @@ struct RegularLL final : public Regular { [[nodiscard]] static Spec* spec(const std::string& name); void spec(spec::Custom&) const override; + + [[nodiscard]] Grid* make_grid_cropped(const Area&) const override; }; @@ -90,13 +92,13 @@ struct RegularGaussian final : public Regular { explicit RegularGaussian(const Spec&); explicit RegularGaussian(size_t N, const area::BoundingBox& = {}); - [[nodiscard]] Grid* make_grid_cropped(const area::BoundingBox& crop) const override; - [[nodiscard]] static Spec* spec(const std::string& name); void spec(spec::Custom&) const override; size_t N() const { return N_; } + [[nodiscard]] Grid* make_grid_cropped(const Area&) const override; + private: const size_t N_; }; diff --git a/src/eckit/geo/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc index cf477256e..af8b93cff 100644 --- a/src/eckit/geo/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -39,6 +39,8 @@ Spec* Unstructured::spec(const std::string& name) { void Unstructured::spec(spec::Custom& custom) const { + Grid::spec(custom); + custom.set("type", "unstructured"); custom.set("uid", uid()); } diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 43b5239ec..5df1a9a76 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -139,8 +139,8 @@ void sanitise(Custom::container_type& container) { if (auto& value = p.second; std::holds_alternative(value)) { value = std::string{std::get(value)}; } - else if (std::holds_alternative(value)) { - ASSERT(std::get(value)); + else if (std::holds_alternative(value)) { + ASSERT(std::get(value)); } }); } @@ -193,7 +193,7 @@ Custom* Custom::make_from_value(const Value& value) { for (const auto& [key, value] : static_cast(value)) { const std::string name = key; - container[name] = value.isMap() ? custom_type(Custom::make_from_value(value)) + container[name] = value.isMap() ? custom_ptr(Custom::make_from_value(value)) : value.isList() ? vector(value) : scalar(value); } @@ -320,20 +320,20 @@ void Custom::set(const std::string& key, const Value& value) { void Custom::set(const std::string& name, Custom* value) { ASSERT(value != nullptr); - map_[name] = custom_type(value); + map_[name] = custom_ptr(value); } bool Custom::has_custom(const std::string& name) const { auto it = map_.find(name); - return it != map_.cend() && std::holds_alternative(it->second); + return it != map_.cend() && std::holds_alternative(it->second); } -const Custom::custom_type& Custom::custom(const std::string& name) const { +const Custom::custom_ptr& Custom::custom(const std::string& name) const { if (auto it = map_.find(name); it != map_.cend()) { - if (std::holds_alternative(it->second)) { - const auto& value = std::get(it->second); + if (std::holds_alternative(it->second)) { + const auto& value = std::get(it->second); ASSERT(value); return value; @@ -344,7 +344,7 @@ const Custom::custom_type& Custom::custom(const std::string& name) const { } -void Custom::set(const std::string& name, const custom_type& value) { +void Custom::set(const std::string& name, const custom_ptr& value) { ASSERT(value); map_[name] = value; } @@ -465,7 +465,7 @@ void Custom::json(JSON& j) const { } -JSON& operator<<(JSON& j, const Custom::custom_type& value) { +JSON& operator<<(JSON& j, const Custom::custom_ptr& value) { ASSERT(value); j.startObject(); for (const auto& [key, value] : value->container()) { diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index 8671e4de0..f6989d121 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -31,18 +31,18 @@ class Custom final : public Spec { public: // -- Types + struct custom_ptr : std::shared_ptr { + using shared_ptr::shared_ptr; + }; + struct key_type : std::string { key_type(const std::string&); key_type(const char* s) : key_type(std::string{s}) {} }; - struct custom_type : std::shared_ptr { - using shared_ptr::shared_ptr; - }; - using value_type = std::variant, std::vector, std::vector, std::vector, std::vector, - std::vector, std::vector, custom_type, + std::vector, std::vector, custom_ptr, const char* /* converted to std::string */>; using container_type = std::map; @@ -69,7 +69,7 @@ class Custom final : public Spec { void json(JSON&) const override; bool has_custom(const std::string& name) const; - const custom_type& custom(const std::string& name) const; + const custom_ptr& custom(const std::string& name) const; void set(const std::string& name, const std::string&); void set(const std::string& name, bool); @@ -122,11 +122,11 @@ class Custom final : public Spec { // -- Methods - void set(const std::string& name, const custom_type&); + void set(const std::string& name, const custom_ptr&); }; -JSON& operator<<(JSON&, const Custom::custom_type&); +JSON& operator<<(JSON&, const Custom::custom_ptr&); } // namespace eckit::geo::spec diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index 6107ab590..e3cee83a9 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -26,13 +26,12 @@ namespace eckit::geo::test { CASE("user -> type") { - using C = spec::Custom::container_type; using v = std::vector; - static const C BAD; + static const spec::Custom::container_type BAD; ASSERT(BAD.empty()); - static std::pair tests[]{ + static std::pair tests[]{ {{{"N", 2}}, {{"N", 2}, {"type", "reduced_gg"}}}, {{{"area", v{90, -180, -90, 180}}, {"grid", v{2, 2}}}, {{"type", "regular_ll"}}}, {{{"area", v{90, -180, -90, 180}}}, BAD}, diff --git a/tests/geo/spec_custom.cc b/tests/geo/spec_custom.cc index 71f11abc7..df9dae950 100644 --- a/tests/geo/spec_custom.cc +++ b/tests/geo/spec_custom.cc @@ -106,27 +106,27 @@ CASE("Custom::container_type") { CASE("Custom::custom_type") { - Custom custom1({{"custom1", Custom::custom_type(new Custom({{"foo", "bar"}, {"boo", "far"}}))}}); + Custom custom1({{"custom1", Custom::custom_ptr(new Custom({{"foo", "bar"}, {"boo", "far"}}))}}); EXPECT(custom1.str() == R"({"custom1":{"boo":"far","foo":"bar"}})"); - Custom custom2({{"custom2", Custom::custom_type(new Custom(custom1.container()))}}); + Custom custom2({{"custom2", Custom::custom_ptr(new Custom(custom1.container()))}}); EXPECT(custom2.str() == R"({"custom2":{"custom1":{"boo":"far","foo":"bar"}}})"); - Custom customer1({{"customer", Custom::custom_type(Custom::make_from_value( + Custom customer1({{"customer", Custom::custom_ptr(Custom::make_from_value( YAMLParser::decodeString("{name: John Smith, age: 33}")))}}); EXPECT(customer1.str() == R"({"customer":{"age":33,"name":"John Smith"}})"); - Custom customer2({{"customer", Custom::custom_type(Custom::make_from_value(YAMLParser::decodeString(R"( + Custom customer2({{"customer", Custom::custom_ptr(Custom::make_from_value(YAMLParser::decodeString(R"( name: John Smith age: 33 )")))}}); EXPECT(customer2.str() == customer1.str()); - Custom nested({{"a", Custom::custom_type(Custom::make_from_value(YAMLParser::decodeString(R"( + Custom nested({{"a", Custom::custom_ptr(Custom::make_from_value(YAMLParser::decodeString(R"( b: c: 1 d: "2" From 6d2e24ed0acdb58577e204a7100b9d976c9d0916 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 2 Jun 2024 13:26:58 +0100 Subject: [PATCH 695/737] eckit::geo::Grid --- src/eckit/geo/CMakeLists.txt | 22 +- src/eckit/geo/Grid.cc | 9 +- src/eckit/geo/grid/ReducedLonLat.cc | 16 ++ src/eckit/geo/grid/ReducedLonLat.h | 30 +++ src/eckit/geo/grid/Regular.cc | 144 +--------- src/eckit/geo/grid/Regular.h | 33 +-- src/eckit/geo/grid/RegularGaussian.cc | 62 +++++ src/eckit/geo/grid/RegularGaussian.h | 37 +++ src/eckit/geo/grid/RegularLonLat.cc | 28 ++ src/eckit/geo/grid/RegularLonLat.h | 42 +++ .../grid/{ => reduced-lonlat}/ReducedLL.cc | 8 +- .../geo/grid/{ => reduced-lonlat}/ReducedLL.h | 8 +- .../LambertAzimuthalEqualArea.cc | 34 +++ .../LambertAzimuthalEqualArea.h | 29 ++ .../regular-lonlat/LambertConformalConic.cc | 34 +++ .../regular-lonlat/LambertConformalConic.h | 29 ++ src/eckit/geo/grid/regular-lonlat/Mercator.cc | 34 +++ src/eckit/geo/grid/regular-lonlat/Mercator.h | 29 ++ .../grid/regular-lonlat/PolarStereographic.cc | 34 +++ .../grid/regular-lonlat/PolarStereographic.h | 29 ++ .../geo/grid/regular-lonlat/RegularLL.cc | 87 ++++++ src/eckit/geo/grid/regular-lonlat/RegularLL.h | 33 +++ .../geo/grid/regular-lonlat/SpaceView.cc | 34 +++ src/eckit/geo/grid/regular-lonlat/SpaceView.h | 29 ++ tests/geo/CMakeLists.txt | 4 +- tests/geo/grid_reduced_gg.cc | 247 +++++++++--------- tests/geo/grid_regular_gg.cc | 181 +++++++------ tests/geo/grid_regular_ll.cc | 15 +- 28 files changed, 917 insertions(+), 404 deletions(-) create mode 100644 src/eckit/geo/grid/ReducedLonLat.cc create mode 100644 src/eckit/geo/grid/ReducedLonLat.h create mode 100644 src/eckit/geo/grid/RegularGaussian.cc create mode 100644 src/eckit/geo/grid/RegularGaussian.h create mode 100644 src/eckit/geo/grid/RegularLonLat.cc create mode 100644 src/eckit/geo/grid/RegularLonLat.h rename src/eckit/geo/grid/{ => reduced-lonlat}/ReducedLL.cc (87%) rename src/eckit/geo/grid/{ => reduced-lonlat}/ReducedLL.h (86%) create mode 100644 src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.cc create mode 100644 src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.h create mode 100644 src/eckit/geo/grid/regular-lonlat/LambertConformalConic.cc create mode 100644 src/eckit/geo/grid/regular-lonlat/LambertConformalConic.h create mode 100644 src/eckit/geo/grid/regular-lonlat/Mercator.cc create mode 100644 src/eckit/geo/grid/regular-lonlat/Mercator.h create mode 100644 src/eckit/geo/grid/regular-lonlat/PolarStereographic.cc create mode 100644 src/eckit/geo/grid/regular-lonlat/PolarStereographic.h create mode 100644 src/eckit/geo/grid/regular-lonlat/RegularLL.cc create mode 100644 src/eckit/geo/grid/regular-lonlat/RegularLL.h create mode 100644 src/eckit/geo/grid/regular-lonlat/SpaceView.cc create mode 100644 src/eckit/geo/grid/regular-lonlat/SpaceView.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index b67db9547..33cc35039 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -59,12 +59,30 @@ list(APPEND eckit_geo_srcs grid/Reduced.h grid/ReducedGaussian.cc grid/ReducedGaussian.h - grid/ReducedLL.cc - grid/ReducedLL.h + grid/ReducedLonLat.cc + grid/ReducedLonLat.h grid/Regular.cc grid/Regular.h + grid/RegularGaussian.cc + grid/RegularGaussian.h + grid/RegularLonLat.cc + grid/RegularLonLat.h grid/Unstructured.cc grid/Unstructured.h + grid/reduced-lonlat/ReducedLL.cc + grid/reduced-lonlat/ReducedLL.h + grid/regular-lonlat/LambertAzimuthalEqualArea.cc + grid/regular-lonlat/LambertAzimuthalEqualArea.h + grid/regular-lonlat/LambertConformalConic.cc + grid/regular-lonlat/LambertConformalConic.h + grid/regular-lonlat/Mercator.cc + grid/regular-lonlat/Mercator.h + grid/regular-lonlat/PolarStereographic.cc + grid/regular-lonlat/PolarStereographic.h + grid/regular-lonlat/RegularLL.cc + grid/regular-lonlat/RegularLL.h + grid/regular-lonlat/SpaceView.cc + grid/regular-lonlat/SpaceView.h iterator/Reduced.cc iterator/Reduced.h iterator/Regular.cc diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index aff654593..0f69ed347 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -46,7 +46,14 @@ const Spec& Grid::spec() const { if (!spec_) { spec_ = std::make_unique(); ASSERT(spec_); - spec(*spec_); + + auto& custom = *spec_; + spec(custom); + + if (std::string name; SpecByName::instance().match(custom, name)) { + custom.clear(); + custom.set("grid", name); + } } return *spec_; diff --git a/src/eckit/geo/grid/ReducedLonLat.cc b/src/eckit/geo/grid/ReducedLonLat.cc new file mode 100644 index 000000000..b03f47acb --- /dev/null +++ b/src/eckit/geo/grid/ReducedLonLat.cc @@ -0,0 +1,16 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/ReducedLonLat.h" + + +namespace eckit::geo::grid {} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedLonLat.h b/src/eckit/geo/grid/ReducedLonLat.h new file mode 100644 index 000000000..eeb5c1fa2 --- /dev/null +++ b/src/eckit/geo/grid/ReducedLonLat.h @@ -0,0 +1,30 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/PointLonLat.h" +#include "eckit/geo/grid/Reduced.h" + + +namespace eckit::geo::grid { + + +class ReducedLonLat : public Reduced { +public: + // -- Constructors + + using Reduced::Reduced; +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index b662359ac..2c0bc72bb 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -20,10 +20,7 @@ #include "eckit/geo/Spec.h" #include "eckit/geo/etc/Grid.h" #include "eckit/geo/iterator/Regular.h" -#include "eckit/geo/range/GaussianLatitude.h" #include "eckit/geo/range/RegularCartesian.h" -#include "eckit/geo/range/RegularLatitude.h" -#include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" #include "eckit/types/Fraction.h" #include "eckit/utils/Translator.h" @@ -84,146 +81,11 @@ std::pair Regular::make_cartesian_ranges_from_spec(const Spec& s } -#define POSITIVE_REAL "[+]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][-+][0-9]+)?" -static const std::string REGULAR_LL_PATTERN("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); -#undef POSITIVE_REAL +void Regular::spec(spec::Custom& custom) const { + Grid::spec(custom); - -RegularLL::RegularLL(const Spec& spec) : - RegularLL(Increments{spec}, area::BoundingBox{spec}, [&spec]() -> PointLonLat { - if (double lon = 0., lat = 0.; spec.get("reference_lon", lon) && spec.get("reference_lat", lat)) { - return {lon, lat}; - } - - area::BoundingBox area{spec}; - return {area.west, area.south}; - }()) { - ASSERT(size() > 0); -} - - -RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : - RegularLL(inc, bbox, {bbox.south, bbox.west}) {} - - -RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& ref) : - Regular({new range::RegularLongitude(inc.dx, bbox.west, bbox.east, ref.lon, 0.), - new range::RegularLatitude(inc.dy, bbox.north, bbox.south, ref.lat, 0.)}, - bbox) { - ASSERT(size() > 0); -} - - -Spec* RegularLL::spec(const std::string& name) { - std::smatch match; - std::regex_match(name, match, std::regex(REGULAR_LL_PATTERN)); - ASSERT(match.size() == 9); - - auto d = Translator{}; - - return new spec::Custom({{"type", "regular_ll"}, {"grid", std::vector{d(match[1]), d(match[5])}}}); -} - - -void RegularLL::spec(spec::Custom& custom) const { - Regular::spec(custom); - - custom.set("grid", std::vector{dx(), dy()}); -} - - -Grid* RegularLL::make_grid_cropped(const Area& crop) const { - if (auto cropped(boundingBox()); crop.intersects(cropped)) { - return new RegularLL({dx(), dy()}, cropped); - } - - throw UserError("RegularGaussian: cannot crop grid (empty intersection)", Here()); -} - - -RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian(spec.get_unsigned("N"), area::BoundingBox(spec)) {} - - -RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : - Regular({range::RegularLongitude(4 * N, 0., 360.).crop(bbox.west, bbox.east), - range::GaussianLatitude(N, false).crop(bbox.north, bbox.south)}, - bbox), - N_(N) { - ASSERT(size() > 0); + custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); } -Grid* RegularGaussian::make_grid_cropped(const Area& crop) const { - if (auto cropped(boundingBox()); crop.intersects(cropped)) { - return new RegularGaussian(N_, cropped); - } - - throw UserError("RegularGaussian: cannot crop grid (empty intersection)", Here()); -} - - -Spec* RegularGaussian::spec(const std::string& name) { - auto N = Translator{}(name.substr(1)); - return new spec::Custom({{"type", "regular_gg"}, {"N", N}}); -} - - -void RegularGaussian::spec(spec::Custom& custom) const { - Regular::spec(custom); - - custom.set("grid", "F" + std::to_string(N_)); -} - - -struct Mercator final : public Regular { - explicit Mercator(const Spec& spec) : - Regular(Regular::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} - void spec(spec::Custom& custom) const override { - Regular::spec(custom); - - custom.set("type", "mercator"); - custom.set("grid", std::vector{dx(), dy()}); - custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); - - // FIXME a lot more stuff to add here! - //... - - if (std::string name; SpecByName::instance().match(custom, name)) { - custom.clear(); - custom.set("grid", name); - } - } -}; - - -struct LambertAzimuthalEqualArea final : public Regular { - explicit LambertAzimuthalEqualArea(const Spec& spec) : - Regular(Regular::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} - void spec(spec::Custom& custom) const override { - Regular::spec(custom); - - custom.set("type", "lambert_azimuthal_equal_area"); - custom.set("grid", std::vector{dx(), dy()}); - custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); - - // FIXME a lot more stuff to add here! - //... - - if (std::string name; SpecByName::instance().match(custom, name)) { - custom.clear(); - custom.set("grid", name); - } - } -}; - - -static const GridRegisterName GRIDNAME1(REGULAR_LL_PATTERN); -static const GridRegisterName GRIDNAME2("[fF][1-9][0-9]*"); - -static const GridRegisterType GRIDTYPE1("regular_ll"); -static const GridRegisterType GRIDTYPE2("regular_gg"); -static const GridRegisterType GRIDTYPE3("mercator"); -static const GridRegisterType GRIDTYPE4("lambert_azimuthal_equal_area"); - - } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index cee2a5207..58abd0853 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -16,7 +16,6 @@ #include #include "eckit/geo/Grid.h" -#include "eckit/geo/PointLonLat.h" #include "eckit/geo/Range.h" @@ -64,6 +63,10 @@ class Regular : public Grid { static std::pair make_cartesian_ranges_from_spec(const Spec& spec); + // -- Overridden methods + + void spec(spec::Custom&) const override; + private: // -- Members @@ -76,32 +79,4 @@ class Regular : public Grid { }; -struct RegularLL final : public Regular { - explicit RegularLL(const Spec&); - explicit RegularLL(const Increments&, const area::BoundingBox& = {}); - RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); - - [[nodiscard]] static Spec* spec(const std::string& name); - void spec(spec::Custom&) const override; - - [[nodiscard]] Grid* make_grid_cropped(const Area&) const override; -}; - - -struct RegularGaussian final : public Regular { - explicit RegularGaussian(const Spec&); - explicit RegularGaussian(size_t N, const area::BoundingBox& = {}); - - [[nodiscard]] static Spec* spec(const std::string& name); - void spec(spec::Custom&) const override; - - size_t N() const { return N_; } - - [[nodiscard]] Grid* make_grid_cropped(const Area&) const override; - -private: - const size_t N_; -}; - - } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularGaussian.cc b/src/eckit/geo/grid/RegularGaussian.cc new file mode 100644 index 000000000..01b1dc123 --- /dev/null +++ b/src/eckit/geo/grid/RegularGaussian.cc @@ -0,0 +1,62 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/RegularGaussian.h" + +#include "eckit/geo/range/GaussianLatitude.h" +#include "eckit/geo/range/RegularLongitude.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/utils/Translator.h" + + +namespace eckit::geo::grid { + + +RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian(spec.get_unsigned("N"), area::BoundingBox(spec)) {} + + +RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : + Regular({range::RegularLongitude(4 * N, 0., 360.).crop(bbox.west, bbox.east), + range::GaussianLatitude(N, false).crop(bbox.north, bbox.south)}, + bbox), + N_(N) { + ASSERT(size() > 0); +} + + +Grid* RegularGaussian::make_grid_cropped(const Area& crop) const { + if (auto cropped(boundingBox()); crop.intersects(cropped)) { + return new RegularGaussian(N_, cropped); + } + + throw UserError("RegularGaussian: cannot crop grid (empty intersection)", Here()); +} + + +Spec* RegularGaussian::spec(const std::string& name) { + auto N = Translator{}(name.substr(1)); + return new spec::Custom({{"type", "regular_gg"}, {"N", N}}); +} + + +void RegularGaussian::spec(spec::Custom& custom) const { + Regular::spec(custom); + + custom.set("grid", "F" + std::to_string(N_)); +} + + +static const GridRegisterName GRIDNAME("[fF][1-9][0-9]*"); +static const GridRegisterType GRIDTYPE("regular_gg"); + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularGaussian.h b/src/eckit/geo/grid/RegularGaussian.h new file mode 100644 index 000000000..7c1c24b2b --- /dev/null +++ b/src/eckit/geo/grid/RegularGaussian.h @@ -0,0 +1,37 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/Regular.h" + + +namespace eckit::geo::grid { + + +struct RegularGaussian final : public Regular { + explicit RegularGaussian(const Spec&); + explicit RegularGaussian(size_t N, const area::BoundingBox& = {}); + + [[nodiscard]] static Spec* spec(const std::string& name); + void spec(spec::Custom&) const override; + + size_t N() const { return N_; } + + [[nodiscard]] Grid* make_grid_cropped(const Area&) const override; + +private: + const size_t N_; +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularLonLat.cc b/src/eckit/geo/grid/RegularLonLat.cc new file mode 100644 index 000000000..f8e2aa4bc --- /dev/null +++ b/src/eckit/geo/grid/RegularLonLat.cc @@ -0,0 +1,28 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/RegularLonLat.h" + +#include "eckit/geo/spec/Custom.h" + + +namespace eckit::geo::grid { + + +void RegularLonLat::spec(spec::Custom& custom) const { + Regular::spec(custom); + + custom.set("grid", std::vector{dlon(), dlat()}); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularLonLat.h b/src/eckit/geo/grid/RegularLonLat.h new file mode 100644 index 000000000..b747fcc4b --- /dev/null +++ b/src/eckit/geo/grid/RegularLonLat.h @@ -0,0 +1,42 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/PointLonLat.h" +#include "eckit/geo/grid/Regular.h" + + +namespace eckit::geo::grid { + + +class RegularLonLat : public Regular { +public: + // -- Constructors + + using Regular::Regular; + + // -- Methods + + double dlon() const { return dx(); } + double dlat() const { return dy(); } + + size_t nlon() const { return x().size(); } + size_t nlat() const { return y().size(); } + + // -- Overridden methods + + void spec(spec::Custom&) const override; +}; + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedLL.cc b/src/eckit/geo/grid/reduced-lonlat/ReducedLL.cc similarity index 87% rename from src/eckit/geo/grid/ReducedLL.cc rename to src/eckit/geo/grid/reduced-lonlat/ReducedLL.cc index 5116f0d39..09f612bee 100644 --- a/src/eckit/geo/grid/ReducedLL.cc +++ b/src/eckit/geo/grid/reduced-lonlat/ReducedLL.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/ReducedLL.h" +#include "eckit/geo/grid/reduced-lonlat/ReducedLL.h" #include "eckit/geo/iterator/Reduced.h" #include "eckit/geo/range/RegularLatitude.h" @@ -18,14 +18,14 @@ #include "eckit/geo/spec/Custom.h" -namespace eckit::geo::grid { +namespace eckit::geo::grid::reducedlonlat { ReducedLL::ReducedLL(const Spec& spec) : ReducedLL(spec.get_long_vector("pl"), area::BoundingBox(spec)) {} ReducedLL::ReducedLL(const pl_type& pl, const area::BoundingBox& bbox) : - Reduced(bbox), pl_(pl), y_(new range::RegularLatitude(pl_.size(), bbox.north, bbox.south)) { + ReducedLonLat(bbox), pl_(pl), y_(new range::RegularLatitude(pl_.size(), bbox.north, bbox.south)) { ASSERT(y_); } @@ -74,4 +74,4 @@ void ReducedLL::spec(spec::Custom& custom) const { } -} // namespace eckit::geo::grid +} // namespace eckit::geo::grid::reducedlonlat diff --git a/src/eckit/geo/grid/ReducedLL.h b/src/eckit/geo/grid/reduced-lonlat/ReducedLL.h similarity index 86% rename from src/eckit/geo/grid/ReducedLL.h rename to src/eckit/geo/grid/reduced-lonlat/ReducedLL.h index 114e7d055..9a2d80e71 100644 --- a/src/eckit/geo/grid/ReducedLL.h +++ b/src/eckit/geo/grid/reduced-lonlat/ReducedLL.h @@ -15,14 +15,14 @@ #include #include "eckit/geo/Range.h" -#include "eckit/geo/grid/Reduced.h" +#include "eckit/geo/grid/ReducedLonLat.h" #include "eckit/geo/util.h" -namespace eckit::geo::grid { +namespace eckit::geo::grid::reducedlonlat { -class ReducedLL : public Reduced { +class ReducedLL : public ReducedLonLat { public: // -- Constructors @@ -54,4 +54,4 @@ class ReducedLL : public Reduced { }; -} // namespace eckit::geo::grid +} // namespace eckit::geo::grid::reducedlonlat diff --git a/src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.cc b/src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.cc new file mode 100644 index 000000000..0f0c5920a --- /dev/null +++ b/src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.cc @@ -0,0 +1,34 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.h" + +#include "eckit/geo/spec/Custom.h" + + +namespace eckit::geo::grid::regularlonlat { + + +static const GridRegisterType GRIDTYPE("lambert_azimuthal_equal_area"); + + +void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { + RegularLonLat::spec(custom); + + custom.set("type", "lambert_azimuthal_equal_area"); + + // FIXME a lot more stuff to add here! + //... +} + + +} // namespace eckit::geo::grid::regularlonlat diff --git a/src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.h b/src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.h new file mode 100644 index 000000000..d5a14dc4c --- /dev/null +++ b/src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.h @@ -0,0 +1,29 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/RegularLonLat.h" + + +namespace eckit::geo::grid::regularlonlat { + + +struct LambertAzimuthalEqualArea final : public RegularLonLat { + explicit LambertAzimuthalEqualArea(const Spec& spec) : + RegularLonLat(RegularLonLat::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} + + void spec(spec::Custom& custom) const override; +}; + + +} // namespace eckit::geo::grid::regularlonlat diff --git a/src/eckit/geo/grid/regular-lonlat/LambertConformalConic.cc b/src/eckit/geo/grid/regular-lonlat/LambertConformalConic.cc new file mode 100644 index 000000000..c865b8aec --- /dev/null +++ b/src/eckit/geo/grid/regular-lonlat/LambertConformalConic.cc @@ -0,0 +1,34 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/regular-lonlat/LambertConformalConic.h" + +#include "eckit/geo/spec/Custom.h" + + +namespace eckit::geo::grid::regularlonlat { + + +static const GridRegisterType GRIDTYPE("lambert"); + + +void LambertConformalConic::spec(spec::Custom& custom) const { + RegularLonLat::spec(custom); + + custom.set("type", "lambert"); + + // FIXME a lot more stuff to add here! + //... +} + + +} // namespace eckit::geo::grid::regularlonlat diff --git a/src/eckit/geo/grid/regular-lonlat/LambertConformalConic.h b/src/eckit/geo/grid/regular-lonlat/LambertConformalConic.h new file mode 100644 index 000000000..9e237b0f2 --- /dev/null +++ b/src/eckit/geo/grid/regular-lonlat/LambertConformalConic.h @@ -0,0 +1,29 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/RegularLonLat.h" + + +namespace eckit::geo::grid::regularlonlat { + + +struct LambertConformalConic final : public RegularLonLat { + explicit LambertConformalConic(const Spec& spec) : + RegularLonLat(RegularLonLat::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} + + void spec(spec::Custom& custom) const override; +}; + + +} // namespace eckit::geo::grid::regularlonlat diff --git a/src/eckit/geo/grid/regular-lonlat/Mercator.cc b/src/eckit/geo/grid/regular-lonlat/Mercator.cc new file mode 100644 index 000000000..dd1480741 --- /dev/null +++ b/src/eckit/geo/grid/regular-lonlat/Mercator.cc @@ -0,0 +1,34 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/regular-lonlat/Mercator.h" + +#include "eckit/geo/spec/Custom.h" + + +namespace eckit::geo::grid::regularlonlat { + + +static const GridRegisterType GRIDTYPE("mercator"); + + +void eckit::geo::grid::regularlonlat::Mercator::spec(spec::Custom& custom) const { + RegularLonLat::spec(custom); + + custom.set("type", "mercator"); + + // FIXME a lot more stuff to add here! + //... +} + + +} // namespace eckit::geo::grid::regularlonlat diff --git a/src/eckit/geo/grid/regular-lonlat/Mercator.h b/src/eckit/geo/grid/regular-lonlat/Mercator.h new file mode 100644 index 000000000..b395afa55 --- /dev/null +++ b/src/eckit/geo/grid/regular-lonlat/Mercator.h @@ -0,0 +1,29 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/RegularLonLat.h" + + +namespace eckit::geo::grid::regularlonlat { + + +struct Mercator final : public RegularLonLat { + explicit Mercator(const Spec& spec) : + RegularLonLat(RegularLonLat::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} + + void spec(spec::Custom& custom) const override; +}; + + +} // namespace eckit::geo::grid::regularlonlat diff --git a/src/eckit/geo/grid/regular-lonlat/PolarStereographic.cc b/src/eckit/geo/grid/regular-lonlat/PolarStereographic.cc new file mode 100644 index 000000000..418fcec6a --- /dev/null +++ b/src/eckit/geo/grid/regular-lonlat/PolarStereographic.cc @@ -0,0 +1,34 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/regular-lonlat/PolarStereographic.h" + +#include "eckit/geo/spec/Custom.h" + + +namespace eckit::geo::grid::regularlonlat { + + +static const GridRegisterType GRIDTYPE("polar_stereographic"); + + +void PolarStereographic::spec(spec::Custom& custom) const { + RegularLonLat::spec(custom); + + custom.set("type", "polar_stereographic"); + + // FIXME a lot more stuff to add here! + //... +} + + +} // namespace eckit::geo::grid::regularlonlat diff --git a/src/eckit/geo/grid/regular-lonlat/PolarStereographic.h b/src/eckit/geo/grid/regular-lonlat/PolarStereographic.h new file mode 100644 index 000000000..f937f5815 --- /dev/null +++ b/src/eckit/geo/grid/regular-lonlat/PolarStereographic.h @@ -0,0 +1,29 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/RegularLonLat.h" + + +namespace eckit::geo::grid::regularlonlat { + + +struct PolarStereographic final : public RegularLonLat { + explicit PolarStereographic(const Spec& spec) : + RegularLonLat(RegularLonLat::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} + + void spec(spec::Custom& custom) const override; +}; + + +} // namespace eckit::geo::grid::regularlonlat diff --git a/src/eckit/geo/grid/regular-lonlat/RegularLL.cc b/src/eckit/geo/grid/regular-lonlat/RegularLL.cc new file mode 100644 index 000000000..ca378f071 --- /dev/null +++ b/src/eckit/geo/grid/regular-lonlat/RegularLL.cc @@ -0,0 +1,87 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/regular-lonlat/RegularLL.h" + +// #include "eckit/geo/Increments.h" +// #include "eckit/types/Fraction.h" +#include "eckit/geo/range/RegularLatitude.h" +#include "eckit/geo/range/RegularLongitude.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/utils/Translator.h" + + +namespace eckit::geo::grid::regularlonlat { + + +#define POSITIVE_REAL "[+]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][-+][0-9]+)?" +static const std::string REGULAR_LL_PATTERN("(" POSITIVE_REAL ")/(" POSITIVE_REAL ")"); +#undef POSITIVE_REAL + + +RegularLL::RegularLL(const Spec& spec) : + RegularLL(Increments{spec}, area::BoundingBox{spec}, [&spec]() -> PointLonLat { + if (double lon = 0., lat = 0.; spec.get("reference_lon", lon) && spec.get("reference_lat", lat)) { + return {lon, lat}; + } + + area::BoundingBox area{spec}; + return {area.west, area.south}; + }()) { + ASSERT(size() > 0); +} + + +RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : + RegularLL(inc, bbox, {bbox.south, bbox.west}) {} + + +RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& ref) : + RegularLonLat({new range::RegularLongitude(inc.dx, bbox.west, bbox.east, ref.lon, 0.), + new range::RegularLatitude(inc.dy, bbox.north, bbox.south, ref.lat, 0.)}, + bbox) { + ASSERT(size() > 0); +} + + +Spec* RegularLL::spec(const std::string& name) { + std::smatch match; + std::regex_match(name, match, std::regex(REGULAR_LL_PATTERN)); + ASSERT(match.size() == 9); + + auto d = Translator{}; + + return new spec::Custom({{"type", "regular_ll"}, {"grid", std::vector{d(match[1]), d(match[5])}}}); +} + + +void RegularLL::spec(spec::Custom& custom) const { + RegularLonLat::spec(custom); + + custom.set("grid", std::vector{dx(), dy()}); +} + + +Grid* RegularLL::make_grid_cropped(const Area& crop) const { + if (auto cropped(boundingBox()); crop.intersects(cropped)) { + return new RegularLL({dx(), dy()}, cropped); + } + + throw UserError("RegularLL: cannot crop grid (empty intersection)", Here()); +} + + +static const GridRegisterName GRIDNAME(REGULAR_LL_PATTERN); +static const GridRegisterType GRIDTYPE("regular_ll"); + + +} // namespace eckit::geo::grid::regularlonlat diff --git a/src/eckit/geo/grid/regular-lonlat/RegularLL.h b/src/eckit/geo/grid/regular-lonlat/RegularLL.h new file mode 100644 index 000000000..53ec121b1 --- /dev/null +++ b/src/eckit/geo/grid/regular-lonlat/RegularLL.h @@ -0,0 +1,33 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/RegularLonLat.h" + + +namespace eckit::geo::grid::regularlonlat { + + +struct RegularLL final : public RegularLonLat { + explicit RegularLL(const Spec&); + explicit RegularLL(const Increments&, const area::BoundingBox& = {}); + RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); + + [[nodiscard]] static Spec* spec(const std::string& name); + void spec(spec::Custom&) const override; + + [[nodiscard]] Grid* make_grid_cropped(const Area&) const override; +}; + + +} // namespace eckit::geo::grid::regularlonlat diff --git a/src/eckit/geo/grid/regular-lonlat/SpaceView.cc b/src/eckit/geo/grid/regular-lonlat/SpaceView.cc new file mode 100644 index 000000000..b1f8c4237 --- /dev/null +++ b/src/eckit/geo/grid/regular-lonlat/SpaceView.cc @@ -0,0 +1,34 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/regular-lonlat/SpaceView.h" + +#include "eckit/geo/spec/Custom.h" + + +namespace eckit::geo::grid::regularlonlat { + + +static const GridRegisterType GRIDTYPE("space_view"); + + +void SpaceView::spec(spec::Custom& custom) const { + RegularLonLat::spec(custom); + + custom.set("type", "space_view"); + + // FIXME a lot more stuff to add here! + //... +} + + +} // namespace eckit::geo::grid::regularlonlat diff --git a/src/eckit/geo/grid/regular-lonlat/SpaceView.h b/src/eckit/geo/grid/regular-lonlat/SpaceView.h new file mode 100644 index 000000000..cbbf5b823 --- /dev/null +++ b/src/eckit/geo/grid/regular-lonlat/SpaceView.h @@ -0,0 +1,29 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/grid/RegularLonLat.h" + + +namespace eckit::geo::grid::regularlonlat { + + +struct SpaceView final : public RegularLonLat { + explicit SpaceView(const Spec& spec) : + RegularLonLat(RegularLonLat::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} + + void spec(spec::Custom& custom) const override; +}; + + +} // namespace eckit::geo::grid::regularlonlat diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 4aff5b21a..b1cc9f0b5 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -69,7 +69,7 @@ ecbuild_add_test( set_tests_properties( eckit_test_geo_tool_grid_spec_1_1 PROPERTIES - PASS_REGULAR_EXPRESSION [=[{"grid":\[1,1\]}]=] ) + PASS_REGULAR_EXPRESSION [=[{"grid":\[1,1\],"shape":\[360,181\]}]=] ) ecbuild_add_test( TARGET eckit_test_geo_tool_grid_spec_025_01 @@ -78,5 +78,5 @@ ecbuild_add_test( set_tests_properties( eckit_test_geo_tool_grid_spec_025_01 PROPERTIES - PASS_REGULAR_EXPRESSION [=[{"grid":\[0\.25,0\.1\]}]=] ) + PASS_REGULAR_EXPRESSION [=[{"grid":\[0\.25,0\.1\],"shape":\[1440,1801\]}]=] ) diff --git a/tests/geo/grid_reduced_gg.cc b/tests/geo/grid_reduced_gg.cc index 270d9b3c5..0f3e1cc99 100644 --- a/tests/geo/grid_reduced_gg.cc +++ b/tests/geo/grid_reduced_gg.cc @@ -21,157 +21,156 @@ namespace eckit::geo::test { -CASE("ReducedGaussianOctahedral") { - SECTION("gridspec") { - // different ways to instantiate the same grid (O2) - for (const auto& spec : { - spec::Custom({{"grid", "o2"}}), - spec::Custom({{"N", 2}}), - spec::Custom({{"pl", pl_type{20, 24, 24, 20}}}), - }) { - std::unique_ptr grid1(GridFactory::build(spec)); - auto n1 = grid1->size(); - - EXPECT_EQUAL(n1, 88); - - spec::Custom hemisphere(spec.container()); - hemisphere.set("south", 0); - - std::unique_ptr grid2(GridFactory::build(hemisphere)); - auto n2 = grid2->size(); - - EXPECT_EQUAL(n2, n1 / 2); - } +using ReducedGaussian = grid::ReducedGaussian; + + +CASE("gridspec") { + // different ways to instantiate the same grid (O2) + for (const auto& spec : { + spec::Custom({{"grid", "o2"}}), + spec::Custom({{"N", 2}}), + spec::Custom({{"pl", pl_type{20, 24, 24, 20}}}), + }) { + std::unique_ptr grid1(GridFactory::build(spec)); + auto n1 = grid1->size(); + + EXPECT_EQUAL(n1, 88); + + spec::Custom hemisphere(spec.container()); + hemisphere.set("south", 0); + + std::unique_ptr grid2(GridFactory::build(hemisphere)); + auto n2 = grid2->size(); + + EXPECT_EQUAL(n2, n1 / 2); } +} + +CASE("sizes") { + struct test_t { + explicit test_t(size_t N) : N(N), size(4 * N * (N + 9)) {} + size_t N; + size_t size; + } tests[]{test_t{2}, test_t{3}, test_t{64}}; - SECTION("sizes") { - struct test_t { - explicit test_t(size_t N) : N(N), size(4 * N * (N + 9)) {} - size_t N; - size_t size; - } tests[]{test_t{2}, test_t{3}, test_t{64}}; - - for (const auto& test : tests) { - std::unique_ptr grid1( - GridFactory::build(spec::Custom({{"grid", "o" + std::to_string(test.N)}}))); - std::unique_ptr grid2( - GridFactory::build(spec::Custom({{"type", "reduced_gg"}, {"N", test.N}}))); - grid::ReducedGaussian grid3(test.N); - - EXPECT(grid1->size() == test.size); - EXPECT(grid2->size() == test.size); - EXPECT(grid3.size() == test.size); - } + for (const auto& test : tests) { + std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "o" + std::to_string(test.N)}}))); + std::unique_ptr grid2(GridFactory::build(spec::Custom({{"type", "reduced_gg"}, {"N", test.N}}))); + ReducedGaussian grid3(test.N); + + EXPECT(grid1->size() == test.size); + EXPECT(grid2->size() == test.size); + EXPECT(grid3.size() == test.size); } +} - SECTION("points") { - grid::ReducedGaussian grid(1); - - const std::vector ref{ - {0., 35.264389683}, {18., 35.264389683}, {36., 35.264389683}, {54., 35.264389683}, - {72., 35.264389683}, {90., 35.264389683}, {108., 35.264389683}, {126., 35.264389683}, - {144., 35.264389683}, {162., 35.264389683}, {180., 35.264389683}, {198., 35.264389683}, - {216., 35.264389683}, {234., 35.264389683}, {252., 35.264389683}, {270., 35.264389683}, - {288., 35.264389683}, {306., 35.264389683}, {324., 35.264389683}, {342., 35.264389683}, - {0., -35.264389683}, {18., -35.264389683}, {36., -35.264389683}, {54., -35.264389683}, - {72., -35.264389683}, {90., -35.264389683}, {108., -35.264389683}, {126., -35.264389683}, - {144., -35.264389683}, {162., -35.264389683}, {180., -35.264389683}, {198., -35.264389683}, - {216., -35.264389683}, {234., -35.264389683}, {252., -35.264389683}, {270., -35.264389683}, - {288., -35.264389683}, {306., -35.264389683}, {324., -35.264389683}, {342., -35.264389683}, - }; - - auto points = grid.to_points(); - - EXPECT(points.size() == grid.size()); - ASSERT(points.size() == ref.size()); - - auto it = grid.begin(); - for (size_t i = 0; i < points.size(); ++i) { - EXPECT(points_equal(ref[i], points[i])); - EXPECT(points_equal(ref[i], *it)); - ++it; - } - EXPECT(it == grid.end()); - - size_t i = 0; - for (const auto& it : grid) { - EXPECT(points_equal(ref[i++], it)); - } - EXPECT(i == grid.size()); +CASE("points") { + ReducedGaussian grid(1); + + const std::vector ref{ + {0., 35.264389683}, {18., 35.264389683}, {36., 35.264389683}, {54., 35.264389683}, + {72., 35.264389683}, {90., 35.264389683}, {108., 35.264389683}, {126., 35.264389683}, + {144., 35.264389683}, {162., 35.264389683}, {180., 35.264389683}, {198., 35.264389683}, + {216., 35.264389683}, {234., 35.264389683}, {252., 35.264389683}, {270., 35.264389683}, + {288., 35.264389683}, {306., 35.264389683}, {324., 35.264389683}, {342., 35.264389683}, + {0., -35.264389683}, {18., -35.264389683}, {36., -35.264389683}, {54., -35.264389683}, + {72., -35.264389683}, {90., -35.264389683}, {108., -35.264389683}, {126., -35.264389683}, + {144., -35.264389683}, {162., -35.264389683}, {180., -35.264389683}, {198., -35.264389683}, + {216., -35.264389683}, {234., -35.264389683}, {252., -35.264389683}, {270., -35.264389683}, + {288., -35.264389683}, {306., -35.264389683}, {324., -35.264389683}, {342., -35.264389683}, + }; + + auto points = grid.to_points(); + + EXPECT(points.size() == grid.size()); + ASSERT(points.size() == ref.size()); + + auto it = grid.begin(); + for (size_t i = 0; i < points.size(); ++i) { + EXPECT(points_equal(ref[i], points[i])); + EXPECT(points_equal(ref[i], *it)); + ++it; } + EXPECT(it == grid.end()); + size_t i = 0; + for (const auto& it : grid) { + EXPECT(points_equal(ref[i++], it)); + } + EXPECT(i == grid.size()); +} - SECTION("crop") { - spec::Custom a({{"grid", "o2"}}); - std::unique_ptr grid1(GridFactory::build(a)); - auto n1 = grid1->size(); - EXPECT_EQUAL(n1, 88); +CASE("crop") { + spec::Custom a({{"grid", "o2"}}); + std::unique_ptr grid1(GridFactory::build(a)); + auto n1 = grid1->size(); - a.set("south", 0.); - std::unique_ptr grid2(GridFactory::build(a)); - auto n2 = grid2->size(); + EXPECT_EQUAL(n1, 88); - EXPECT_EQUAL(n2, n1 / 2); + a.set("south", 0.); + std::unique_ptr grid2(GridFactory::build(a)); + auto n2 = grid2->size(); + + EXPECT_EQUAL(n2, n1 / 2); - spec::Custom b{{{"grid", "o2"}, {"west", -180}}}; - std::unique_ptr grid3(GridFactory::build(b)); - auto n3 = grid3->size(); + spec::Custom b{{{"grid", "o2"}, {"west", -180}}}; + std::unique_ptr grid3(GridFactory::build(b)); + auto n3 = grid3->size(); - EXPECT_EQUAL(n3, n1); + EXPECT_EQUAL(n3, n1); - EXPECT(grid3->boundingBox().isPeriodicWestEast()); + EXPECT(grid3->boundingBox().isPeriodicWestEast()); - // (exclude Greenwhich meridian) - std::unique_ptr grid4(grid3->make_grid_cropped(area::BoundingBox(90., -180., 0., -1.e-6))); + // (exclude Greenwhich meridian) + std::unique_ptr grid4(grid3->make_grid_cropped(area::BoundingBox(90., -180., 0., -1.e-6))); - auto n4 = grid4->size(); + auto n4 = grid4->size(); - EXPECT_EQUAL(n4, n3 / 4); + EXPECT_EQUAL(n4, n3 / 4); - const std::vector ref{ - {-180., 59.444408289}, {-162., 59.444408289}, {-144., 59.444408289}, {-126., 59.444408289}, - {-108., 59.444408289}, {-90., 59.444408289}, {-72., 59.444408289}, {-54., 59.444408289}, - {-36., 59.444408289}, {-18., 59.444408289}, {-180., 19.875719147}, {-165., 19.875719147}, - {-150., 19.875719147}, {-135., 19.875719147}, {-120., 19.875719147}, {-105., 19.875719147}, - {-90., 19.875719147}, {-75., 19.875719147}, {-60., 19.875719147}, {-45., 19.875719147}, - {-30., 19.875719147}, {-15., 19.875719147}, - }; + const std::vector ref{ + {-180., 59.444408289}, {-162., 59.444408289}, {-144., 59.444408289}, {-126., 59.444408289}, + {-108., 59.444408289}, {-90., 59.444408289}, {-72., 59.444408289}, {-54., 59.444408289}, + {-36., 59.444408289}, {-18., 59.444408289}, {-180., 19.875719147}, {-165., 19.875719147}, + {-150., 19.875719147}, {-135., 19.875719147}, {-120., 19.875719147}, {-105., 19.875719147}, + {-90., 19.875719147}, {-75., 19.875719147}, {-60., 19.875719147}, {-45., 19.875719147}, + {-30., 19.875719147}, {-15., 19.875719147}, + }; - auto points4 = grid4->to_points(); + auto points4 = grid4->to_points(); - EXPECT(points4.size() == n4); - ASSERT(points4.size() == ref.size()); + EXPECT(points4.size() == n4); + ASSERT(points4.size() == ref.size()); - auto it = grid4->begin(); - for (size_t i = 0; i < points4.size(); ++i) { - EXPECT(points_equal(ref[i], points4[i])); - EXPECT(points_equal(ref[i], *it)); - ++it; - } - EXPECT(it == grid4->end()); + auto it = grid4->begin(); + for (size_t i = 0; i < points4.size(); ++i) { + EXPECT(points_equal(ref[i], points4[i])); + EXPECT(points_equal(ref[i], *it)); + ++it; + } + EXPECT(it == grid4->end()); - size_t i = 0; - for (const auto& it : *grid4) { - EXPECT(points_equal(ref[i++], it)); - } - EXPECT_EQUAL(i, n4); + size_t i = 0; + for (const auto& it : *grid4) { + EXPECT(points_equal(ref[i++], it)); } + EXPECT_EQUAL(i, n4); +} - SECTION("equals") { - std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "o3"}}))); - std::unique_ptr grid2(GridFactory::make_from_string("N: 3")); - std::unique_ptr grid3(new grid::ReducedGaussian(3)); - std::unique_ptr grid4(new grid::ReducedGaussian(pl_type{20, 24, 28, 28, 24, 20})); +CASE("equals") { + std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "o3"}}))); + std::unique_ptr grid2(GridFactory::make_from_string("N: 3")); + std::unique_ptr grid3(new ReducedGaussian(3)); + std::unique_ptr grid4(new ReducedGaussian(pl_type{20, 24, 28, 28, 24, 20})); - EXPECT(*grid1 == *grid2); - EXPECT(*grid2 == *grid3); - EXPECT(*grid3 == *grid4); - EXPECT(*grid4 == *grid1); - } + EXPECT(*grid1 == *grid2); + EXPECT(*grid2 == *grid3); + EXPECT(*grid3 == *grid4); + EXPECT(*grid4 == *grid1); } diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index 0aab0496e..10190da0f 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -13,7 +13,7 @@ #include #include "eckit/geo/Grid.h" -#include "eckit/geo/grid/Regular.h" +#include "eckit/geo/grid/RegularGaussian.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/util.h" #include "eckit/testing/Test.h" @@ -22,129 +22,128 @@ namespace eckit::geo::test { -CASE("RegularGaussian") { - SECTION("sizes") { - struct test_t { - explicit test_t(size_t N) : N(N), size(4 * N * 2 * N) {} - size_t N; - size_t size; - } tests[]{test_t{2}, test_t{3}, test_t{64}}; - - for (const auto& test : tests) { - std::unique_ptr grid1( - GridFactory::build(spec::Custom({{"grid", "f" + std::to_string(test.N)}}))); - std::unique_ptr grid2( - GridFactory::build(spec::Custom({{"type", "regular_gg"}, {"N", test.N}}))); - grid::RegularGaussian grid3(test.N); - - EXPECT(grid1->size() == test.size); - EXPECT(grid2->size() == test.size); - EXPECT(grid3.size() == test.size); - } +using RegularGaussian = grid::RegularGaussian; + + +CASE("sizes") { + struct test_t { + explicit test_t(size_t N) : N(N), size(4 * N * 2 * N) {} + size_t N; + size_t size; + } tests[]{test_t{2}, test_t{3}, test_t{64}}; + + for (const auto& test : tests) { + std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "f" + std::to_string(test.N)}}))); + std::unique_ptr grid2(GridFactory::build(spec::Custom({{"type", "regular_gg"}, {"N", test.N}}))); + RegularGaussian grid3(test.N); + + EXPECT(grid1->size() == test.size); + EXPECT(grid2->size() == test.size); + EXPECT(grid3.size() == test.size); } +} - SECTION("points") { - grid::RegularGaussian grid(1); +CASE("points") { + RegularGaussian grid(1); - const std::vector ref{ - {0., 35.264389683}, {90., 35.264389683}, {180., 35.264389683}, {270., 35.264389683}, - {0., -35.264389683}, {90., -35.264389683}, {180., -35.264389683}, {270., -35.264389683}, - }; + const std::vector ref{ + {0., 35.264389683}, {90., 35.264389683}, {180., 35.264389683}, {270., 35.264389683}, + {0., -35.264389683}, {90., -35.264389683}, {180., -35.264389683}, {270., -35.264389683}, + }; - auto points = grid.to_points(); + auto points = grid.to_points(); - EXPECT(points.size() == grid.size()); - ASSERT(points.size() == ref.size()); + EXPECT(points.size() == grid.size()); + ASSERT(points.size() == ref.size()); - auto it = grid.begin(); - for (size_t i = 0; i < points.size(); ++i) { - EXPECT(points_equal(ref[i], points[i])); - EXPECT(points_equal(ref[i], *it)); - ++it; - } - EXPECT(it == grid.end()); + auto it = grid.begin(); + for (size_t i = 0; i < points.size(); ++i) { + EXPECT(points_equal(ref[i], points[i])); + EXPECT(points_equal(ref[i], *it)); + ++it; + } + EXPECT(it == grid.end()); - size_t i = 0; - for (const auto& it : grid) { - EXPECT(points_equal(ref[i++], it)); - } - EXPECT(i == grid.size()); + size_t i = 0; + for (const auto& it : grid) { + EXPECT(points_equal(ref[i++], it)); } + EXPECT(i == grid.size()); +} - SECTION("crop") { - spec::Custom a({{"grid", "f2"}}); - std::unique_ptr grid1(GridFactory::build(a)); - auto n1 = grid1->size(); +CASE("crop") { + spec::Custom a({{"grid", "f2"}}); + std::unique_ptr grid1(GridFactory::build(a)); + auto n1 = grid1->size(); - EXPECT_EQUAL(n1, 32); + EXPECT_EQUAL(n1, 32); - a.set("south", 0.); - std::unique_ptr grid2(GridFactory::build(a)); - auto n2 = grid2->size(); + a.set("south", 0.); + std::unique_ptr grid2(GridFactory::build(a)); + auto n2 = grid2->size(); - EXPECT_EQUAL(n2, n1 / 2); + EXPECT_EQUAL(n2, n1 / 2); - spec::Custom b{{{"grid", "f2"}, {"west", -180}}}; - std::unique_ptr grid3(GridFactory::build(b)); - auto n3 = grid3->size(); + spec::Custom b{{{"grid", "f2"}, {"west", -180}}}; + std::unique_ptr grid3(GridFactory::build(b)); + auto n3 = grid3->size(); - EXPECT_EQUAL(n3, n1); + EXPECT_EQUAL(n3, n1); - auto bbox3 = grid3->boundingBox(); + auto bbox3 = grid3->boundingBox(); - EXPECT(bbox3.isPeriodicWestEast()); + EXPECT(bbox3.isPeriodicWestEast()); - bbox3 = {bbox3.north, bbox3.west, bbox3.south, 0.}; + bbox3 = {bbox3.north, bbox3.west, bbox3.south, 0.}; - EXPECT_NOT(bbox3.isPeriodicWestEast()); + EXPECT_NOT(bbox3.isPeriodicWestEast()); - std::unique_ptr grid4(grid3->make_grid_cropped(bbox3)); - auto n4 = grid4->size(); + std::unique_ptr grid4(grid3->make_grid_cropped(bbox3)); + auto n4 = grid4->size(); - EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj + EXPECT_EQUAL(n4, 5 * 4); // Ni * Nj - b.set("east", -1.); - std::unique_ptr grid5(GridFactory::build(b)); - auto n5 = grid5->size(); + b.set("east", -1.); + std::unique_ptr grid5(GridFactory::build(b)); + auto n5 = grid5->size(); - EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj + EXPECT_EQUAL(n5, 4 * 4); // Ni * Nj - const std::vector ref{ - {-180., 59.444408289}, {-135., 59.444408289}, {-90., 59.444408289}, {-45., 59.444408289}, - {-180., 19.875719147}, {-135., 19.875719147}, {-90., 19.875719147}, {-45., 19.875719147}, - {-180., -19.875719147}, {-135., -19.875719147}, {-90., -19.875719147}, {-45., -19.875719147}, - {-180., -59.444408289}, {-135., -59.444408289}, {-90., -59.444408289}, {-45., -59.444408289}, - }; + const std::vector ref{ + {-180., 59.444408289}, {-135., 59.444408289}, {-90., 59.444408289}, {-45., 59.444408289}, + {-180., 19.875719147}, {-135., 19.875719147}, {-90., 19.875719147}, {-45., 19.875719147}, + {-180., -19.875719147}, {-135., -19.875719147}, {-90., -19.875719147}, {-45., -19.875719147}, + {-180., -59.444408289}, {-135., -59.444408289}, {-90., -59.444408289}, {-45., -59.444408289}, + }; - auto points5 = grid5->to_points(); + auto points5 = grid5->to_points(); - EXPECT(points5.size() == grid5->size()); - ASSERT(points5.size() == ref.size()); + EXPECT(points5.size() == grid5->size()); + ASSERT(points5.size() == ref.size()); - auto it = grid5->begin(); - for (size_t i = 0; i < points5.size(); ++i) { - EXPECT(points_equal(ref[i], points5[i])); - EXPECT(points_equal(ref[i], *it)); - ++it; - } - EXPECT(it == grid5->end()); + auto it = grid5->begin(); + for (size_t i = 0; i < points5.size(); ++i) { + EXPECT(points_equal(ref[i], points5[i])); + EXPECT(points_equal(ref[i], *it)); + ++it; + } + EXPECT(it == grid5->end()); - size_t i = 0; - for (const auto& it : *grid5) { - EXPECT(points_equal(ref[i++], it)); - } - EXPECT_EQUAL(i, n5); + size_t i = 0; + for (const auto& it : *grid5) { + EXPECT(points_equal(ref[i++], it)); } + EXPECT_EQUAL(i, n5); +} - SECTION("equals") { - std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "f3"}}))); - std::unique_ptr grid2(new grid::RegularGaussian(3)); +CASE("equals") { + std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "f3"}}))); + std::unique_ptr grid2(new RegularGaussian(3)); - EXPECT(*grid1 == *grid2); - } + EXPECT(*grid1 == *grid2); } diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index 188526cd9..cf02ab156 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -12,7 +12,7 @@ #include -#include "eckit/geo/grid/Regular.h" +#include "eckit/geo/grid/regular-lonlat/RegularLL.h" #include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" @@ -20,18 +20,21 @@ namespace eckit::geo::test { +using RegularLL = grid::regularlonlat::RegularLL; + + CASE("global") { - std::unique_ptr grid1(new grid::RegularLL(spec::Custom{{{"grid", std::vector{1, 1}}}})); + std::unique_ptr grid1(new RegularLL(spec::Custom{{{"grid", std::vector{1, 1}}}})); EXPECT(grid1->size() == 360 * 181); - std::unique_ptr grid2(new grid::RegularLL( + std::unique_ptr grid2(new RegularLL( spec::Custom{{{"grid", std::vector{2, 1}}, {"area", std::vector{10, 1, 1, 10}}}})); EXPECT(grid2->size() == 5 * 10); - for (const auto& grid : {grid::RegularLL({1., 1.}, {89.5, 0.5, -89.5, 359.5}), - grid::RegularLL({1., 1.}, {90., 0., -90, 360.}, {0.5, 0.5})}) { + for (const auto& grid : + {RegularLL({1., 1.}, {89.5, 0.5, -89.5, 359.5}), RegularLL({1., 1.}, {90., 0., -90, 360.}, {0.5, 0.5})}) { EXPECT(grid.nx() == 360); EXPECT(grid.ny() == 180); EXPECT(grid.size() == 360 * 180); @@ -46,7 +49,7 @@ CASE("non-global") { * -1 . . . . * -1 0 1 2 */ - grid::RegularLL grid({1, 2}, {1, -1, -1, 2}); + RegularLL grid({1, 2}, {1, -1, -1, 2}); const std::vector ref{ {-1., 1.}, {0., 1.}, {1., 1.}, {2., 1.}, {-1., -1.}, {0., -1.}, {1., -1.}, {2., -1.}, From 998bfe6fb4b6853085323eabf4b2b6e129dc84c6 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 2 Jun 2024 19:53:45 +0100 Subject: [PATCH 696/737] eckit::geo::Grid --- etc/eckit/geo/grid.yaml | 6 +- src/eckit/geo/CMakeLists.txt | 35 +-- src/eckit/geo/Grid.cc | 8 +- src/eckit/geo/Grid.h | 6 +- src/eckit/geo/Increments.cc | 27 +- src/eckit/geo/Ordering.cc | 96 ++++++ src/eckit/geo/Ordering.h | 59 ++-- src/eckit/geo/Shape.cc | 17 +- src/eckit/geo/grid/HEALPix.h | 2 +- .../grid/{reduced-lonlat => }/ReducedLL.cc | 8 +- .../geo/grid/{reduced-lonlat => }/ReducedLL.h | 8 +- src/eckit/geo/grid/ReducedLonLat.cc | 16 - src/eckit/geo/grid/ReducedLonLat.h | 30 -- src/eckit/geo/grid/Regular.cc | 21 -- src/eckit/geo/grid/Regular.h | 6 +- .../grid/{regular-lonlat => }/RegularLL.cc | 28 +- .../geo/grid/{regular-lonlat => }/RegularLL.h | 8 +- src/eckit/geo/grid/RegularLonLat.cc | 28 -- src/eckit/geo/grid/RegularXY.cc | 61 ++++ .../geo/grid/{RegularLonLat.h => RegularXY.h} | 16 +- .../LambertAzimuthalEqualArea.cc | 8 +- .../LambertAzimuthalEqualArea.h | 10 +- .../LambertConformalConic.cc | 8 +- .../LambertConformalConic.h | 10 +- .../Mercator.cc | 10 +- .../{regular-lonlat => regular-xy}/Mercator.h | 10 +- .../PolarStereographic.cc | 8 +- .../PolarStereographic.h | 10 +- .../SpaceView.cc | 8 +- .../SpaceView.h | 10 +- tests/geo/CMakeLists.txt | 1 + tests/geo/grid_healpix.cc | 290 +++++++++--------- tests/geo/grid_regular_ll.cc | 4 +- tests/geo/grid_reorder.cc | 4 +- tests/geo/ordering.cc | 48 +++ tests/geo/spec.cc | 3 + 36 files changed, 532 insertions(+), 396 deletions(-) create mode 100644 src/eckit/geo/Ordering.cc rename src/eckit/geo/grid/{reduced-lonlat => }/ReducedLL.cc (87%) rename src/eckit/geo/grid/{reduced-lonlat => }/ReducedLL.h (86%) delete mode 100644 src/eckit/geo/grid/ReducedLonLat.cc delete mode 100644 src/eckit/geo/grid/ReducedLonLat.h rename src/eckit/geo/grid/{regular-lonlat => }/RegularLL.cc (76%) rename src/eckit/geo/grid/{regular-lonlat => }/RegularLL.h (81%) delete mode 100644 src/eckit/geo/grid/RegularLonLat.cc create mode 100644 src/eckit/geo/grid/RegularXY.cc rename src/eckit/geo/grid/{RegularLonLat.h => RegularXY.h} (76%) rename src/eckit/geo/grid/{regular-lonlat => regular-xy}/LambertAzimuthalEqualArea.cc (78%) rename src/eckit/geo/grid/{regular-lonlat => regular-xy}/LambertAzimuthalEqualArea.h (63%) rename src/eckit/geo/grid/{regular-lonlat => regular-xy}/LambertConformalConic.cc (77%) rename src/eckit/geo/grid/{regular-lonlat => regular-xy}/LambertConformalConic.h (63%) rename src/eckit/geo/grid/{regular-lonlat => regular-xy}/Mercator.cc (69%) rename src/eckit/geo/grid/{regular-lonlat => regular-xy}/Mercator.h (64%) rename src/eckit/geo/grid/{regular-lonlat => regular-xy}/PolarStereographic.cc (78%) rename src/eckit/geo/grid/{regular-lonlat => regular-xy}/PolarStereographic.h (64%) rename src/eckit/geo/grid/{regular-lonlat => regular-xy}/SpaceView.cc (78%) rename src/eckit/geo/grid/{regular-lonlat => regular-xy}/SpaceView.h (64%) create mode 100644 tests/geo/ordering.cc diff --git a/etc/eckit/geo/grid.yaml b/etc/eckit/geo/grid.yaml index 8e2b0e4f2..0bf610987 100644 --- a/etc/eckit/geo/grid.yaml +++ b/etc/eckit/geo/grid.yaml @@ -9,8 +9,7 @@ grid_names: gaussianNumber: 1280 standardParallelInDegrees: 52. centralLongitudeInDegrees: 10. - latitudeOfFirstGridPointInDegrees: 66.982143 - longitudeOfFirstGridPointInDegrees: -35.034024 + first_lonlat: [-35.034024,66.982143] shape: [1000, 950] - SMUFF-OPERA-2km: @@ -19,7 +18,6 @@ grid_names: shapeOfTheEarth: 5 grid: [2000., 2000.] gaussianNumber: 1280 - latitudeOfFirstGridPointInDegrees: 67.035186732680 - longitudeOfFirstGridPointInDegrees: -39.535385563614 + first_lonlat: [-39.535385563614, 67.035186732680] shape: [1900, 2200] diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 33cc35039..6e6da1019 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -16,6 +16,7 @@ list(APPEND eckit_geo_srcs Iterator.h LibEcKitGeo.cc LibEcKitGeo.h + Ordering.cc Ordering.h Point.cc Point.h @@ -59,30 +60,28 @@ list(APPEND eckit_geo_srcs grid/Reduced.h grid/ReducedGaussian.cc grid/ReducedGaussian.h - grid/ReducedLonLat.cc - grid/ReducedLonLat.h + grid/ReducedLL.cc + grid/ReducedLL.h grid/Regular.cc grid/Regular.h grid/RegularGaussian.cc grid/RegularGaussian.h - grid/RegularLonLat.cc - grid/RegularLonLat.h + grid/RegularLL.cc + grid/RegularLL.h + grid/RegularXY.cc + grid/RegularXY.h grid/Unstructured.cc grid/Unstructured.h - grid/reduced-lonlat/ReducedLL.cc - grid/reduced-lonlat/ReducedLL.h - grid/regular-lonlat/LambertAzimuthalEqualArea.cc - grid/regular-lonlat/LambertAzimuthalEqualArea.h - grid/regular-lonlat/LambertConformalConic.cc - grid/regular-lonlat/LambertConformalConic.h - grid/regular-lonlat/Mercator.cc - grid/regular-lonlat/Mercator.h - grid/regular-lonlat/PolarStereographic.cc - grid/regular-lonlat/PolarStereographic.h - grid/regular-lonlat/RegularLL.cc - grid/regular-lonlat/RegularLL.h - grid/regular-lonlat/SpaceView.cc - grid/regular-lonlat/SpaceView.h + grid/regular-xy/LambertAzimuthalEqualArea.cc + grid/regular-xy/LambertAzimuthalEqualArea.h + grid/regular-xy/LambertConformalConic.cc + grid/regular-xy/LambertConformalConic.h + grid/regular-xy/Mercator.cc + grid/regular-xy/Mercator.h + grid/regular-xy/PolarStereographic.cc + grid/regular-xy/PolarStereographic.h + grid/regular-xy/SpaceView.cc + grid/regular-xy/SpaceView.h iterator/Reduced.cc iterator/Reduced.h iterator/Regular.cc diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index 0f69ed347..e064c83dc 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -36,10 +36,12 @@ class lock_type { }; -Grid::Grid(const Spec& spec) : bbox_(area::BoundingBox::make_from_spec(spec)) {} +Grid::Grid(const Spec& spec) : + bbox_(area::BoundingBox::make_from_spec(spec)), ordering_(make_ordering_from_spec(spec)) {} -Grid::Grid(const area::BoundingBox& bbox) : bbox_(new area::BoundingBox(bbox)) {} +Grid::Grid(const area::BoundingBox& bbox, Ordering ordering) : + bbox_(new area::BoundingBox(bbox)), ordering_(ordering) {} const Spec& Grid::spec() const { @@ -117,7 +119,7 @@ std::pair, std::vector > Grid::to_latlon() const { } -Ordering Grid::order() const { +Ordering Grid::ordering() const { NOTIMP; } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index e16464656..eecebf822 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -120,7 +120,7 @@ class Grid { [[nodiscard]] virtual std::vector to_points() const; [[nodiscard]] virtual std::pair, std::vector> to_latlon() const; - virtual Ordering order() const; + virtual Ordering ordering() const; virtual Renumber reorder(Ordering) const; virtual const Area& area() const; @@ -139,7 +139,7 @@ class Grid { protected: // -- Constructors - explicit Grid(const area::BoundingBox&); + explicit Grid(const area::BoundingBox&, Ordering = Ordering::DEFAULT); // -- Methods @@ -160,6 +160,8 @@ class Grid { mutable std::unique_ptr spec_; mutable uid_t uid_; + Ordering ordering_; + // -- Friends friend bool operator==(const Grid& a, const Grid& b) { return a.spec_str() == b.spec_str(); } diff --git a/src/eckit/geo/Increments.cc b/src/eckit/geo/Increments.cc index 317cd37a2..33c2aede8 100644 --- a/src/eckit/geo/Increments.cc +++ b/src/eckit/geo/Increments.cc @@ -21,30 +21,29 @@ namespace eckit::geo { Increments Increments::make_from_spec(const Spec& spec) { - if (std::vector value; spec.get("increments", value) && value.size() == 2) { - return {value[0], value[1]}; + if (std::vector grid; (spec.get("increments", grid) || spec.get("grid", grid)) && grid.size() == 2) { + return {grid[0], grid[1]}; } - if (std::vector value; spec.get("grid", value) && value.size() == 2) { - return {value[0], value[1]}; - } - - if (value_type x = 0, y = 0; spec.get("dx", x) && spec.get("dy", y)) { - return {x, y}; - } - - if (value_type x = 0, y = 0; spec.get("west_east_increment", x) && spec.get("south_north_increment", y)) { - return {x, y}; + if (value_type dx = 0, dy = 0; (spec.get("west_east_increment", dx) && spec.get("south_north_increment", dy)) + || (spec.get("dlon", dx) && spec.get("dlat", dy)) + || (spec.get("dx", dx) && spec.get("dy", dy))) { + return {dx, dy}; } throw SpecNotFound( - "'increments' = 'grid' = ['dx', 'dy'] = ['west_east_increment', 'south_north_increment'] expected", Here()); + "'increments' = 'grid' = ['dx', 'dy'] = ['west_east_increment', 'south_north_increment'] = ['dlon', 'dlat'] = " + "['dx', 'dy'] expected", + Here()); } Increments::Increments(value_type dx, value_type dy) : array{dx, dy} { if (!(dx != 0) || !(dy != 0)) { - throw BadValue("'shape' = ['dx', 'dy'] != 0 expected", Here()); + throw BadValue( + "'increments' = 'grid' = ['west_east_increment', 'south_north_increment'] = ['dlon', 'dlat'] = ['dx', " + "'dy'] != 0 expected", + Here()); } } diff --git a/src/eckit/geo/Ordering.cc b/src/eckit/geo/Ordering.cc new file mode 100644 index 000000000..f0d7b6e59 --- /dev/null +++ b/src/eckit/geo/Ordering.cc @@ -0,0 +1,96 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Ordering.h" + +#include "eckit/geo/Spec.h" + + +namespace eckit::geo { + + +Ordering make_ordering_from_spec(const Spec& spec) { + static const Ordering SCAN[] = { + scan_i_positively_j_negatively_ij_i_single_direction, + scan_i_negatively_j_negatively_ij_i_single_direction, + scan_i_positively_j_positively_ij_i_single_direction, + scan_i_negatively_j_positively_ij_i_single_direction, + scan_i_positively_j_negatively_ji_i_single_direction, + scan_i_negatively_j_negatively_ji_i_single_direction, + scan_i_positively_j_positively_ji_i_single_direction, + scan_i_negatively_j_positively_ji_i_single_direction, + scan_i_positively_j_negatively_ij_i_alternating_direction, + scan_i_negatively_j_negatively_ij_i_alternating_direction, + scan_i_positively_j_positively_ij_i_alternating_direction, + scan_i_negatively_j_positively_ij_i_alternating_direction, + scan_i_positively_j_negatively_ji_i_alternating_direction, + scan_i_negatively_j_negatively_ji_i_alternating_direction, + scan_i_positively_j_positively_ji_i_alternating_direction, + scan_i_negatively_j_positively_ji_i_alternating_direction, + }; + + int key = (spec.get_bool("scan_i_plus", true) ? 0 : 1) + (spec.get_bool("scan_j_plus", false) ? 1 << 1 : 0) + + (spec.get_bool("scan_ij", true) ? 0 : 1 << 2) + (spec.get_bool("scan_alternating", false) ? 1 << 3 : 0); + + return SCAN[key]; +} + + +bool ordering_is_i_positive(Ordering o) { + return o == scan_i_positively_j_negatively_ij_i_single_direction + || o == scan_i_positively_j_positively_ij_i_single_direction + || o == scan_i_positively_j_negatively_ji_i_single_direction + || o == scan_i_positively_j_positively_ji_i_single_direction + || o == scan_i_positively_j_negatively_ij_i_alternating_direction + || o == scan_i_positively_j_positively_ij_i_alternating_direction + || o == scan_i_positively_j_negatively_ji_i_alternating_direction + || o == scan_i_positively_j_positively_ji_i_alternating_direction; +} + + +bool ordering_is_j_positive(Ordering o) { + return o == scan_i_positively_j_positively_ij_i_single_direction + || o == scan_i_negatively_j_positively_ij_i_single_direction + || o == scan_i_positively_j_positively_ji_i_single_direction + || o == scan_i_negatively_j_positively_ji_i_single_direction + || o == scan_i_positively_j_positively_ij_i_alternating_direction + || o == scan_i_negatively_j_positively_ij_i_alternating_direction + || o == scan_i_positively_j_positively_ji_i_alternating_direction + || o == scan_i_negatively_j_positively_ji_i_alternating_direction; +} + + +bool ordering_is_ij(Ordering o) { + return o == scan_i_positively_j_negatively_ij_i_single_direction + || o == scan_i_negatively_j_negatively_ij_i_single_direction + || o == scan_i_positively_j_positively_ij_i_single_direction + || o == scan_i_negatively_j_positively_ij_i_single_direction + || o == scan_i_positively_j_negatively_ij_i_alternating_direction + || o == scan_i_negatively_j_negatively_ij_i_alternating_direction + || o == scan_i_positively_j_positively_ij_i_alternating_direction + || o == scan_i_negatively_j_positively_ij_i_alternating_direction; +} + + +bool ordering_is_alternating(Ordering o) { + return o == scan_i_positively_j_negatively_ij_i_alternating_direction + || o == scan_i_negatively_j_negatively_ij_i_alternating_direction + || o == scan_i_positively_j_positively_ij_i_alternating_direction + || o == scan_i_negatively_j_positively_ij_i_alternating_direction + || o == scan_i_positively_j_negatively_ji_i_alternating_direction + || o == scan_i_negatively_j_negatively_ji_i_alternating_direction + || o == scan_i_positively_j_positively_ji_i_alternating_direction + || o == scan_i_negatively_j_positively_ji_i_alternating_direction; +} + + +} // namespace eckit::geo diff --git a/src/eckit/geo/Ordering.h b/src/eckit/geo/Ordering.h index c077c1f17..44d3ee073 100644 --- a/src/eckit/geo/Ordering.h +++ b/src/eckit/geo/Ordering.h @@ -13,45 +13,52 @@ #pragma once +namespace eckit::geo { +class Spec; +} + + namespace eckit::geo { enum Ordering { - regular_i_positively_j_negatively_ij_i_single_direction, - regular_i_negatively_j_negatively_ij_i_single_direction, - regular_i_positively_j_positively_ij_i_single_direction, - regular_i_negatively_j_positively_ij_i_single_direction, - regular_i_positively_j_negatively_ji_i_single_direction, - regular_i_negatively_j_negatively_ji_i_single_direction, - regular_i_positively_j_positively_ji_i_single_direction, - regular_i_negatively_j_positively_ji_i_single_direction, - regular_i_positively_j_negatively_ij_i_alternating_direction, - regular_i_negatively_j_negatively_ij_i_alternating_direction, - regular_i_positively_j_positively_ij_i_alternating_direction, - regular_i_negatively_j_positively_ij_i_alternating_direction, - regular_i_positively_j_negatively_ji_i_alternating_direction, - regular_i_negatively_j_negatively_ji_i_alternating_direction, - regular_i_positively_j_positively_ji_i_alternating_direction, - regular_i_negatively_j_positively_ji_i_alternating_direction, + scan_i_positively_j_negatively_ij_i_single_direction, + scan_i_negatively_j_negatively_ij_i_single_direction, + scan_i_positively_j_positively_ij_i_single_direction, + scan_i_negatively_j_positively_ij_i_single_direction, + scan_i_positively_j_negatively_ji_i_single_direction, + scan_i_negatively_j_negatively_ji_i_single_direction, + scan_i_positively_j_positively_ji_i_single_direction, + scan_i_negatively_j_positively_ji_i_single_direction, + scan_i_positively_j_negatively_ij_i_alternating_direction, + scan_i_negatively_j_negatively_ij_i_alternating_direction, + scan_i_positively_j_positively_ij_i_alternating_direction, + scan_i_negatively_j_positively_ij_i_alternating_direction, + scan_i_positively_j_negatively_ji_i_alternating_direction, + scan_i_negatively_j_negatively_ji_i_alternating_direction, + scan_i_positively_j_positively_ji_i_alternating_direction, + scan_i_negatively_j_positively_ji_i_alternating_direction, // TODO regular_ ... shift - reduced_i_positively_j_negatively, - reduced_i_negatively_j_negatively, - reduced_i_positively_j_positively, - reduced_i_negatively_j_positively, - // TODO reduced_ ... shift - healpix_ring, healpix_nested, - regular_ordering = regular_i_positively_j_negatively_ij_i_single_direction, - regular_ordering_end = regular_i_negatively_j_positively_ji_i_alternating_direction, - reduced_ordering = reduced_i_positively_j_negatively, - reduced_ordering_end = reduced_i_negatively_j_positively, + scan_ordering = scan_i_positively_j_negatively_ij_i_single_direction, + scan_ordering_end = scan_i_negatively_j_positively_ji_i_alternating_direction, healpix_ordering = healpix_ring, healpix_ordering_end = healpix_nested, + + DEFAULT = scan_i_positively_j_negatively_ij_i_single_direction }; +Ordering make_ordering_from_spec(const Spec&); + +bool ordering_is_i_positive(Ordering); +bool ordering_is_j_positive(Ordering); +bool ordering_is_ij(Ordering); +bool ordering_is_alternating(Ordering); + + } // namespace eckit::geo diff --git a/src/eckit/geo/Shape.cc b/src/eckit/geo/Shape.cc index 70ab10bbe..06e8bfbc8 100644 --- a/src/eckit/geo/Shape.cc +++ b/src/eckit/geo/Shape.cc @@ -20,23 +20,22 @@ namespace eckit::geo { Shape Shape::make_from_spec(const Spec& spec) { - value_type x = 0; - value_type y = 0; - if (std::vector value; spec.get("shape", value) && value.size() == 2) { - x = value[0]; - y = value[1]; + if (std::vector shape; spec.get("shape", shape) && shape.size() == 2) { + return {shape[0], shape[1]}; } - else if (!spec.get("nx", x) || !spec.get("ny", y)) { - throw SpecNotFound("'shape' = ['nx', 'ny'] expected", Here()); + + if (value_type nx = 0, ny = 0; + (spec.get("nlon", nx) && spec.get("nlat", ny)) || (spec.get("nlon", nx) && spec.get("nlat", ny))) { + return {nx, ny}; } - return {x, y}; + throw SpecNotFound("'shape' = ['nlon', 'nlat'] = ['nx', 'ny'] expected", Here()); } Shape::Shape(value_type nx, value_type ny) : array{nx, ny} { if (!(nx > 0) || !(ny > 0)) { - throw BadValue("'shape' = ['nx', 'ny'] > 0 expected", Here()); + throw BadValue("'shape' = ['nlon', 'nlat'] = ['nx', 'ny'] > 0 expected", Here()); } } diff --git a/src/eckit/geo/grid/HEALPix.h b/src/eckit/geo/grid/HEALPix.h index 55a547125..5c77ee871 100644 --- a/src/eckit/geo/grid/HEALPix.h +++ b/src/eckit/geo/grid/HEALPix.h @@ -42,7 +42,7 @@ class HEALPix final : public Reduced { std::vector to_points() const override; std::pair, std::vector> to_latlon() const override; - Ordering order() const override { return ordering_; } + Ordering ordering() const override { return ordering_; } Renumber reorder(Ordering) const override; [[nodiscard]] Grid* make_grid_reordered(Ordering ordering) const override { return new HEALPix(Nside_, ordering); } diff --git a/src/eckit/geo/grid/reduced-lonlat/ReducedLL.cc b/src/eckit/geo/grid/ReducedLL.cc similarity index 87% rename from src/eckit/geo/grid/reduced-lonlat/ReducedLL.cc rename to src/eckit/geo/grid/ReducedLL.cc index 09f612bee..5116f0d39 100644 --- a/src/eckit/geo/grid/reduced-lonlat/ReducedLL.cc +++ b/src/eckit/geo/grid/ReducedLL.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/grid/reduced-lonlat/ReducedLL.h" +#include "eckit/geo/grid/ReducedLL.h" #include "eckit/geo/iterator/Reduced.h" #include "eckit/geo/range/RegularLatitude.h" @@ -18,14 +18,14 @@ #include "eckit/geo/spec/Custom.h" -namespace eckit::geo::grid::reducedlonlat { +namespace eckit::geo::grid { ReducedLL::ReducedLL(const Spec& spec) : ReducedLL(spec.get_long_vector("pl"), area::BoundingBox(spec)) {} ReducedLL::ReducedLL(const pl_type& pl, const area::BoundingBox& bbox) : - ReducedLonLat(bbox), pl_(pl), y_(new range::RegularLatitude(pl_.size(), bbox.north, bbox.south)) { + Reduced(bbox), pl_(pl), y_(new range::RegularLatitude(pl_.size(), bbox.north, bbox.south)) { ASSERT(y_); } @@ -74,4 +74,4 @@ void ReducedLL::spec(spec::Custom& custom) const { } -} // namespace eckit::geo::grid::reducedlonlat +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/reduced-lonlat/ReducedLL.h b/src/eckit/geo/grid/ReducedLL.h similarity index 86% rename from src/eckit/geo/grid/reduced-lonlat/ReducedLL.h rename to src/eckit/geo/grid/ReducedLL.h index 9a2d80e71..114e7d055 100644 --- a/src/eckit/geo/grid/reduced-lonlat/ReducedLL.h +++ b/src/eckit/geo/grid/ReducedLL.h @@ -15,14 +15,14 @@ #include #include "eckit/geo/Range.h" -#include "eckit/geo/grid/ReducedLonLat.h" +#include "eckit/geo/grid/Reduced.h" #include "eckit/geo/util.h" -namespace eckit::geo::grid::reducedlonlat { +namespace eckit::geo::grid { -class ReducedLL : public ReducedLonLat { +class ReducedLL : public Reduced { public: // -- Constructors @@ -54,4 +54,4 @@ class ReducedLL : public ReducedLonLat { }; -} // namespace eckit::geo::grid::reducedlonlat +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedLonLat.cc b/src/eckit/geo/grid/ReducedLonLat.cc deleted file mode 100644 index b03f47acb..000000000 --- a/src/eckit/geo/grid/ReducedLonLat.cc +++ /dev/null @@ -1,16 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/ReducedLonLat.h" - - -namespace eckit::geo::grid {} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/ReducedLonLat.h b/src/eckit/geo/grid/ReducedLonLat.h deleted file mode 100644 index eeb5c1fa2..000000000 --- a/src/eckit/geo/grid/ReducedLonLat.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/PointLonLat.h" -#include "eckit/geo/grid/Reduced.h" - - -namespace eckit::geo::grid { - - -class ReducedLonLat : public Reduced { -public: - // -- Constructors - - using Reduced::Reduced; -}; - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index 2c0bc72bb..466d17006 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -12,18 +12,10 @@ #include "eckit/geo/grid/Regular.h" -#include - #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Increments.h" -#include "eckit/geo/Shape.h" -#include "eckit/geo/Spec.h" -#include "eckit/geo/etc/Grid.h" #include "eckit/geo/iterator/Regular.h" -#include "eckit/geo/range/RegularCartesian.h" #include "eckit/geo/spec/Custom.h" #include "eckit/types/Fraction.h" -#include "eckit/utils/Translator.h" namespace eckit::geo::grid { @@ -68,19 +60,6 @@ Regular::Regular(std::pair xy, const area::BoundingBox& bbox) : } -std::pair Regular::make_cartesian_ranges_from_spec(const Spec& spec) { - Increments inc(spec); - Shape shape(spec); - - // FIXME This is a hack, we should not be using these keys - Point2 a{spec.get_double("longitudeOfFirstGridPointInDegrees"), - spec.get_double("latitudeOfFirstGridPointInDegrees")}; - Point2 b{a.X + inc.dx * static_cast(shape.nx - 1), a.Y - inc.dy * static_cast(shape.ny - 1)}; - - return {new range::RegularCartesian(shape.nx, a.X, b.X), new range::RegularCartesian(shape.ny, a.Y, b.Y)}; -} - - void Regular::spec(spec::Custom& custom) const { Grid::spec(custom); diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index 58abd0853..270214e7f 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -44,6 +44,8 @@ class Regular : public Grid { virtual size_t nx() const { return x_->size(); } virtual size_t ny() const { return y_->size(); } + [[nodiscard]] static std::pair make_lonlat_ranges_from_spec(const Spec&); + // -- Overridden methods iterator cbegin() const override; @@ -59,10 +61,6 @@ class Regular : public Grid { Regular(std::pair xy, const area::BoundingBox&); - // -- Methods - - static std::pair make_cartesian_ranges_from_spec(const Spec& spec); - // -- Overridden methods void spec(spec::Custom&) const override; diff --git a/src/eckit/geo/grid/regular-lonlat/RegularLL.cc b/src/eckit/geo/grid/RegularLL.cc similarity index 76% rename from src/eckit/geo/grid/regular-lonlat/RegularLL.cc rename to src/eckit/geo/grid/RegularLL.cc index ca378f071..a6b72242a 100644 --- a/src/eckit/geo/grid/regular-lonlat/RegularLL.cc +++ b/src/eckit/geo/grid/RegularLL.cc @@ -10,17 +10,18 @@ */ -#include "eckit/geo/grid/regular-lonlat/RegularLL.h" +#include "eckit/geo/grid/RegularLL.h" -// #include "eckit/geo/Increments.h" -// #include "eckit/types/Fraction.h" +#include + +#include "eckit/geo/Increments.h" #include "eckit/geo/range/RegularLatitude.h" #include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" #include "eckit/utils/Translator.h" -namespace eckit::geo::grid::regularlonlat { +namespace eckit::geo::grid { #define POSITIVE_REAL "[+]?([0-9]+([.][0-9]*)?|[.][0-9]+)([eE][-+][0-9]+)?" @@ -30,8 +31,13 @@ static const std::string REGULAR_LL_PATTERN("(" POSITIVE_REAL ")/(" POSITIVE_REA RegularLL::RegularLL(const Spec& spec) : RegularLL(Increments{spec}, area::BoundingBox{spec}, [&spec]() -> PointLonLat { - if (double lon = 0., lat = 0.; spec.get("reference_lon", lon) && spec.get("reference_lat", lat)) { - return {lon, lat}; + std::vector v(2); + if (spec.get("reference_lon", v[0]) && spec.get("reference_lat", v[1])) { + return {v[0], v[1]}; + } + + if (spec.get("reference_lonlat", v) && v.size() == 2) { + return {v[0], v[1]}; } area::BoundingBox area{spec}; @@ -46,9 +52,9 @@ RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& ref) : - RegularLonLat({new range::RegularLongitude(inc.dx, bbox.west, bbox.east, ref.lon, 0.), - new range::RegularLatitude(inc.dy, bbox.north, bbox.south, ref.lat, 0.)}, - bbox) { + Regular({new range::RegularLongitude(inc.dx, bbox.west, bbox.east, ref.lon, 0.), + new range::RegularLatitude(inc.dy, bbox.north, bbox.south, ref.lat, 0.)}, + bbox) { ASSERT(size() > 0); } @@ -65,7 +71,7 @@ Spec* RegularLL::spec(const std::string& name) { void RegularLL::spec(spec::Custom& custom) const { - RegularLonLat::spec(custom); + Regular::spec(custom); custom.set("grid", std::vector{dx(), dy()}); } @@ -84,4 +90,4 @@ static const GridRegisterName GRIDNAME(REGULAR_LL_PATTERN); static const GridRegisterType GRIDTYPE("regular_ll"); -} // namespace eckit::geo::grid::regularlonlat +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/regular-lonlat/RegularLL.h b/src/eckit/geo/grid/RegularLL.h similarity index 81% rename from src/eckit/geo/grid/regular-lonlat/RegularLL.h rename to src/eckit/geo/grid/RegularLL.h index 53ec121b1..2ba39b4c6 100644 --- a/src/eckit/geo/grid/regular-lonlat/RegularLL.h +++ b/src/eckit/geo/grid/RegularLL.h @@ -12,13 +12,13 @@ #pragma once -#include "eckit/geo/grid/RegularLonLat.h" +#include "eckit/geo/grid/Regular.h" -namespace eckit::geo::grid::regularlonlat { +namespace eckit::geo::grid { -struct RegularLL final : public RegularLonLat { +struct RegularLL final : public Regular { explicit RegularLL(const Spec&); explicit RegularLL(const Increments&, const area::BoundingBox& = {}); RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); @@ -30,4 +30,4 @@ struct RegularLL final : public RegularLonLat { }; -} // namespace eckit::geo::grid::regularlonlat +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularLonLat.cc b/src/eckit/geo/grid/RegularLonLat.cc deleted file mode 100644 index f8e2aa4bc..000000000 --- a/src/eckit/geo/grid/RegularLonLat.cc +++ /dev/null @@ -1,28 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/grid/RegularLonLat.h" - -#include "eckit/geo/spec/Custom.h" - - -namespace eckit::geo::grid { - - -void RegularLonLat::spec(spec::Custom& custom) const { - Regular::spec(custom); - - custom.set("grid", std::vector{dlon(), dlat()}); -} - - -} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularXY.cc b/src/eckit/geo/grid/RegularXY.cc new file mode 100644 index 000000000..714cf7034 --- /dev/null +++ b/src/eckit/geo/grid/RegularXY.cc @@ -0,0 +1,61 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/grid/RegularXY.h" + +#include + +#include "eckit/geo/Increments.h" +#include "eckit/geo/Projection.h" +#include "eckit/geo/Shape.h" +#include "eckit/geo/range/RegularCartesian.h" +#include "eckit/geo/spec/Custom.h" + + +namespace eckit::geo::grid { + + +std::pair RegularXY::make_xy_ranges_from_spec(const Spec& spec) { +#if 0 + Increments inc(spec); + Shape shape(spec); + + std::unique_ptr projection(ProjectionFactory::instance().get("proj").create(spec)); + + std::vector v(2); + auto first_lonlat((spec.get("first_lon", v[0]) && spec.get("first_lat", v[1])) + || (spec.get("first_lonlat", v) && v.size() == 2) + ? PointLonLat{v[0], v[1]} + : throw SpecNotFound("['first_lonlat' = ['first_lon', 'first_lat'] expected", Here())); + + // TODO; + + + Point2 a = std::get(projection->inv(first_lonlat)); + Point2 b{a.X + inc.dx * static_cast(shape.nx - 1), a.Y - inc.dy * static_cast(shape.ny - 1)}; + + return {new range::RegularCartesian(shape.nx, a.X, b.X), new range::RegularCartesian(shape.ny, a.Y, b.Y)}; +#else + return {new range::RegularCartesian(11, 0, 10), new range::RegularCartesian(11, 0, 10)}; +#endif +} + + +void RegularXY::spec(spec::Custom& custom) const { + Regular::spec(custom); + + custom.set("grid", std::vector{dx(), dy()}); + custom.set("first_lonlat", std::vector{first_lonlat.lon, first_lonlat.lat}); +} + + +} // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularLonLat.h b/src/eckit/geo/grid/RegularXY.h similarity index 76% rename from src/eckit/geo/grid/RegularLonLat.h rename to src/eckit/geo/grid/RegularXY.h index b747fcc4b..dae4f2dc3 100644 --- a/src/eckit/geo/grid/RegularLonLat.h +++ b/src/eckit/geo/grid/RegularXY.h @@ -12,14 +12,15 @@ #pragma once -#include "eckit/geo/PointLonLat.h" +#include + #include "eckit/geo/grid/Regular.h" namespace eckit::geo::grid { -class RegularLonLat : public Regular { +class RegularXY : public Regular { public: // -- Constructors @@ -33,9 +34,20 @@ class RegularLonLat : public Regular { size_t nlon() const { return x().size(); } size_t nlat() const { return y().size(); } +protected: + // -- Methods + + [[nodiscard]] static std::pair make_xy_ranges_from_spec(const Spec&); + // -- Overridden methods void spec(spec::Custom&) const override; + +private: + // -- Members + + PointLonLat first_lonlat; + Point2 first_xy; }; diff --git a/src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.cc b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.cc similarity index 78% rename from src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.cc rename to src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.cc index 0f0c5920a..3313c8cb7 100644 --- a/src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.cc @@ -10,19 +10,19 @@ */ -#include "eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.h" +#include "eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h" #include "eckit/geo/spec/Custom.h" -namespace eckit::geo::grid::regularlonlat { +namespace eckit::geo::grid::regularxy { static const GridRegisterType GRIDTYPE("lambert_azimuthal_equal_area"); void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { - RegularLonLat::spec(custom); + RegularXY::spec(custom); custom.set("type", "lambert_azimuthal_equal_area"); @@ -31,4 +31,4 @@ void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { } -} // namespace eckit::geo::grid::regularlonlat +} // namespace eckit::geo::grid::regularxy diff --git a/src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.h b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h similarity index 63% rename from src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.h rename to src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h index d5a14dc4c..824a500c9 100644 --- a/src/eckit/geo/grid/regular-lonlat/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h @@ -12,18 +12,18 @@ #pragma once -#include "eckit/geo/grid/RegularLonLat.h" +#include "eckit/geo/grid/RegularXY.h" -namespace eckit::geo::grid::regularlonlat { +namespace eckit::geo::grid::regularxy { -struct LambertAzimuthalEqualArea final : public RegularLonLat { +struct LambertAzimuthalEqualArea final : public RegularXY { explicit LambertAzimuthalEqualArea(const Spec& spec) : - RegularLonLat(RegularLonLat::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} + RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} void spec(spec::Custom& custom) const override; }; -} // namespace eckit::geo::grid::regularlonlat +} // namespace eckit::geo::grid::regularxy diff --git a/src/eckit/geo/grid/regular-lonlat/LambertConformalConic.cc b/src/eckit/geo/grid/regular-xy/LambertConformalConic.cc similarity index 77% rename from src/eckit/geo/grid/regular-lonlat/LambertConformalConic.cc rename to src/eckit/geo/grid/regular-xy/LambertConformalConic.cc index c865b8aec..9cdad559b 100644 --- a/src/eckit/geo/grid/regular-lonlat/LambertConformalConic.cc +++ b/src/eckit/geo/grid/regular-xy/LambertConformalConic.cc @@ -10,19 +10,19 @@ */ -#include "eckit/geo/grid/regular-lonlat/LambertConformalConic.h" +#include "eckit/geo/grid/regular-xy/LambertConformalConic.h" #include "eckit/geo/spec/Custom.h" -namespace eckit::geo::grid::regularlonlat { +namespace eckit::geo::grid::regularxy { static const GridRegisterType GRIDTYPE("lambert"); void LambertConformalConic::spec(spec::Custom& custom) const { - RegularLonLat::spec(custom); + RegularXY::spec(custom); custom.set("type", "lambert"); @@ -31,4 +31,4 @@ void LambertConformalConic::spec(spec::Custom& custom) const { } -} // namespace eckit::geo::grid::regularlonlat +} // namespace eckit::geo::grid::regularxy diff --git a/src/eckit/geo/grid/regular-lonlat/LambertConformalConic.h b/src/eckit/geo/grid/regular-xy/LambertConformalConic.h similarity index 63% rename from src/eckit/geo/grid/regular-lonlat/LambertConformalConic.h rename to src/eckit/geo/grid/regular-xy/LambertConformalConic.h index 9e237b0f2..978d6e149 100644 --- a/src/eckit/geo/grid/regular-lonlat/LambertConformalConic.h +++ b/src/eckit/geo/grid/regular-xy/LambertConformalConic.h @@ -12,18 +12,18 @@ #pragma once -#include "eckit/geo/grid/RegularLonLat.h" +#include "eckit/geo/grid/RegularXY.h" -namespace eckit::geo::grid::regularlonlat { +namespace eckit::geo::grid::regularxy { -struct LambertConformalConic final : public RegularLonLat { +struct LambertConformalConic final : public RegularXY { explicit LambertConformalConic(const Spec& spec) : - RegularLonLat(RegularLonLat::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} + RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} void spec(spec::Custom& custom) const override; }; -} // namespace eckit::geo::grid::regularlonlat +} // namespace eckit::geo::grid::regularxy diff --git a/src/eckit/geo/grid/regular-lonlat/Mercator.cc b/src/eckit/geo/grid/regular-xy/Mercator.cc similarity index 69% rename from src/eckit/geo/grid/regular-lonlat/Mercator.cc rename to src/eckit/geo/grid/regular-xy/Mercator.cc index dd1480741..3b7530982 100644 --- a/src/eckit/geo/grid/regular-lonlat/Mercator.cc +++ b/src/eckit/geo/grid/regular-xy/Mercator.cc @@ -10,19 +10,19 @@ */ -#include "eckit/geo/grid/regular-lonlat/Mercator.h" +#include "eckit/geo/grid/regular-xy/Mercator.h" #include "eckit/geo/spec/Custom.h" -namespace eckit::geo::grid::regularlonlat { +namespace eckit::geo::grid::regularxy { static const GridRegisterType GRIDTYPE("mercator"); -void eckit::geo::grid::regularlonlat::Mercator::spec(spec::Custom& custom) const { - RegularLonLat::spec(custom); +void eckit::geo::grid::regularxy::Mercator::spec(spec::Custom& custom) const { + RegularXY::spec(custom); custom.set("type", "mercator"); @@ -31,4 +31,4 @@ void eckit::geo::grid::regularlonlat::Mercator::spec(spec::Custom& custom) const } -} // namespace eckit::geo::grid::regularlonlat +} // namespace eckit::geo::grid::regularxy diff --git a/src/eckit/geo/grid/regular-lonlat/Mercator.h b/src/eckit/geo/grid/regular-xy/Mercator.h similarity index 64% rename from src/eckit/geo/grid/regular-lonlat/Mercator.h rename to src/eckit/geo/grid/regular-xy/Mercator.h index b395afa55..f62dacaff 100644 --- a/src/eckit/geo/grid/regular-lonlat/Mercator.h +++ b/src/eckit/geo/grid/regular-xy/Mercator.h @@ -12,18 +12,18 @@ #pragma once -#include "eckit/geo/grid/RegularLonLat.h" +#include "eckit/geo/grid/RegularXY.h" -namespace eckit::geo::grid::regularlonlat { +namespace eckit::geo::grid::regularxy { -struct Mercator final : public RegularLonLat { +struct Mercator final : public RegularXY { explicit Mercator(const Spec& spec) : - RegularLonLat(RegularLonLat::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} + RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} void spec(spec::Custom& custom) const override; }; -} // namespace eckit::geo::grid::regularlonlat +} // namespace eckit::geo::grid::regularxy diff --git a/src/eckit/geo/grid/regular-lonlat/PolarStereographic.cc b/src/eckit/geo/grid/regular-xy/PolarStereographic.cc similarity index 78% rename from src/eckit/geo/grid/regular-lonlat/PolarStereographic.cc rename to src/eckit/geo/grid/regular-xy/PolarStereographic.cc index 418fcec6a..425e32df2 100644 --- a/src/eckit/geo/grid/regular-lonlat/PolarStereographic.cc +++ b/src/eckit/geo/grid/regular-xy/PolarStereographic.cc @@ -10,19 +10,19 @@ */ -#include "eckit/geo/grid/regular-lonlat/PolarStereographic.h" +#include "eckit/geo/grid/regular-xy/PolarStereographic.h" #include "eckit/geo/spec/Custom.h" -namespace eckit::geo::grid::regularlonlat { +namespace eckit::geo::grid::regularxy { static const GridRegisterType GRIDTYPE("polar_stereographic"); void PolarStereographic::spec(spec::Custom& custom) const { - RegularLonLat::spec(custom); + RegularXY::spec(custom); custom.set("type", "polar_stereographic"); @@ -31,4 +31,4 @@ void PolarStereographic::spec(spec::Custom& custom) const { } -} // namespace eckit::geo::grid::regularlonlat +} // namespace eckit::geo::grid::regularxy diff --git a/src/eckit/geo/grid/regular-lonlat/PolarStereographic.h b/src/eckit/geo/grid/regular-xy/PolarStereographic.h similarity index 64% rename from src/eckit/geo/grid/regular-lonlat/PolarStereographic.h rename to src/eckit/geo/grid/regular-xy/PolarStereographic.h index f937f5815..c2302b3c3 100644 --- a/src/eckit/geo/grid/regular-lonlat/PolarStereographic.h +++ b/src/eckit/geo/grid/regular-xy/PolarStereographic.h @@ -12,18 +12,18 @@ #pragma once -#include "eckit/geo/grid/RegularLonLat.h" +#include "eckit/geo/grid/RegularXY.h" -namespace eckit::geo::grid::regularlonlat { +namespace eckit::geo::grid::regularxy { -struct PolarStereographic final : public RegularLonLat { +struct PolarStereographic final : public RegularXY { explicit PolarStereographic(const Spec& spec) : - RegularLonLat(RegularLonLat::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} + RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} void spec(spec::Custom& custom) const override; }; -} // namespace eckit::geo::grid::regularlonlat +} // namespace eckit::geo::grid::regularxy diff --git a/src/eckit/geo/grid/regular-lonlat/SpaceView.cc b/src/eckit/geo/grid/regular-xy/SpaceView.cc similarity index 78% rename from src/eckit/geo/grid/regular-lonlat/SpaceView.cc rename to src/eckit/geo/grid/regular-xy/SpaceView.cc index b1f8c4237..4d58e3ebf 100644 --- a/src/eckit/geo/grid/regular-lonlat/SpaceView.cc +++ b/src/eckit/geo/grid/regular-xy/SpaceView.cc @@ -10,19 +10,19 @@ */ -#include "eckit/geo/grid/regular-lonlat/SpaceView.h" +#include "eckit/geo/grid/regular-xy/SpaceView.h" #include "eckit/geo/spec/Custom.h" -namespace eckit::geo::grid::regularlonlat { +namespace eckit::geo::grid::regularxy { static const GridRegisterType GRIDTYPE("space_view"); void SpaceView::spec(spec::Custom& custom) const { - RegularLonLat::spec(custom); + RegularXY::spec(custom); custom.set("type", "space_view"); @@ -31,4 +31,4 @@ void SpaceView::spec(spec::Custom& custom) const { } -} // namespace eckit::geo::grid::regularlonlat +} // namespace eckit::geo::grid::regularxy diff --git a/src/eckit/geo/grid/regular-lonlat/SpaceView.h b/src/eckit/geo/grid/regular-xy/SpaceView.h similarity index 64% rename from src/eckit/geo/grid/regular-lonlat/SpaceView.h rename to src/eckit/geo/grid/regular-xy/SpaceView.h index cbbf5b823..74012f5c4 100644 --- a/src/eckit/geo/grid/regular-lonlat/SpaceView.h +++ b/src/eckit/geo/grid/regular-xy/SpaceView.h @@ -12,18 +12,18 @@ #pragma once -#include "eckit/geo/grid/RegularLonLat.h" +#include "eckit/geo/grid/RegularXY.h" -namespace eckit::geo::grid::regularlonlat { +namespace eckit::geo::grid::regularxy { -struct SpaceView final : public RegularLonLat { +struct SpaceView final : public RegularXY { explicit SpaceView(const Spec& spec) : - RegularLonLat(RegularLonLat::make_cartesian_ranges_from_spec(spec), area::BoundingBox{spec}) {} + RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} void spec(spec::Custom& custom) const override; }; -} // namespace eckit::geo::grid::regularlonlat +} // namespace eckit::geo::grid::regularxy diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index b1cc9f0b5..30f23dd8d 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -17,6 +17,7 @@ foreach(_test increments iterator kdtree + ordering point point2 point3 diff --git a/tests/geo/grid_healpix.cc b/tests/geo/grid_healpix.cc index c91d08b38..0ca67dcf1 100644 --- a/tests/geo/grid_healpix.cc +++ b/tests/geo/grid_healpix.cc @@ -20,166 +20,166 @@ namespace eckit::geo::test { -CASE("HEALPix") { - SECTION("gridspec") { - spec::Custom spec({{"grid", "h2"}}); - std::unique_ptr grid1(GridFactory::build(spec)); - auto n1 = grid1->size(); +CASE("gridspec") { + spec::Custom spec({{"grid", "h2"}}); + std::unique_ptr grid1(GridFactory::build(spec)); + auto n1 = grid1->size(); - EXPECT_EQUAL(n1, 48); + EXPECT_EQUAL(n1, 48); +} + + +CASE("sizes") { + struct test_t { + explicit test_t(size_t N) : N(N), size(12 * N * N) {} + size_t N; + size_t size; + } tests[]{test_t{2}, test_t{3}, test_t{64}}; + + for (const auto& test : tests) { + std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "h" + std::to_string(test.N)}}))); + std::unique_ptr grid2(GridFactory::build(spec::Custom({{"type", "HEALPix"}, {"Nside", test.N}}))); + grid::HEALPix grid3(test.N); + + EXPECT(grid1->size() == test.size); + EXPECT(grid2->size() == test.size); + EXPECT(grid3.size() == test.size); } +} - SECTION("sizes") { - struct test_t { - explicit test_t(size_t N) : N(N), size(12 * N * N) {} - size_t N; - size_t size; - } tests[]{test_t{2}, test_t{3}, test_t{64}}; - - for (const auto& test : tests) { - std::unique_ptr grid1( - GridFactory::build(spec::Custom({{"grid", "h" + std::to_string(test.N)}}))); - std::unique_ptr grid2( - GridFactory::build(spec::Custom({{"type", "HEALPix"}, {"Nside", test.N}}))); - grid::HEALPix grid3(test.N); - - EXPECT(grid1->size() == test.size); - EXPECT(grid2->size() == test.size); - EXPECT(grid3.size() == test.size); - } +CASE("points") { + + std::unique_ptr ring(new grid::HEALPix(2)); + + EXPECT(ring->ordering() == Ordering::healpix_ring); + + + std::unique_ptr nested(new grid::HEALPix(2, Ordering::healpix_nested)); + + EXPECT(nested->ordering() == Ordering::healpix_nested); + + // reference coordinates in ring ordering + const std::vector ref{ + {45., 66.443535691}, + {135., 66.443535691}, + {225., 66.443535691}, + {315., 66.443535691}, + {22.5, 41.810314896}, + {67.5, 41.810314896}, + {112.5, 41.810314896}, + {157.5, 41.810314896}, + {202.5, 41.810314896}, + {247.5, 41.810314896}, + {292.5, 41.810314896}, + {337.5, 41.810314896}, + {0., 19.471220634}, + {45., 19.471220634}, + {90., 19.471220634}, + {135., 19.471220634}, + {180., 19.471220634}, + {225., 19.471220634}, + {270., 19.471220634}, + {315., 19.471220634}, + {22.5, 0.}, + {67.5, 0.}, + {112.5, 0.}, + {157.5, 0.}, + {202.5, 0.}, + {247.5, 0.}, + {292.5, 0.}, + {337.5, 0.}, + {0., -19.471220634}, + {45., -19.471220634}, + {90., -19.471220634}, + {135., -19.471220634}, + {180., -19.471220634}, + {225., -19.471220634}, + {270., -19.471220634}, + {315., -19.471220634}, + {22.5, -41.810314896}, + {67.5, -41.810314896}, + {112.5, -41.810314896}, + {157.5, -41.810314896}, + {202.5, -41.810314896}, + {247.5, -41.810314896}, + {292.5, -41.810314896}, + {337.5, -41.810314896}, + {45., -66.443535691}, + {135., -66.443535691}, + {225., -66.443535691}, + {315., -66.443535691}, + }; + + + auto points_r = ring->to_points(); + + EXPECT(points_r.size() == ring->size()); + ASSERT(points_r.size() == ref.size()); + + auto itr = ring->begin(); + for (size_t i = 0; i < points_r.size(); ++i) { + EXPECT(points_equal(ref[i], points_r[i])); + EXPECT(points_equal(ref[i], *itr)); + ++itr; } + EXPECT(itr == ring->end()); - SECTION("points") { - - std::unique_ptr ring(new grid::HEALPix(2)); - - EXPECT(ring->order() == Ordering::healpix_ring); - - - std::unique_ptr nested(new grid::HEALPix(2, Ordering::healpix_nested)); - - EXPECT(nested->order() == Ordering::healpix_nested); - - // reference coordinates in ring ordering - const std::vector ref{ - {45., 66.443535691}, - {135., 66.443535691}, - {225., 66.443535691}, - {315., 66.443535691}, - {22.5, 41.810314896}, - {67.5, 41.810314896}, - {112.5, 41.810314896}, - {157.5, 41.810314896}, - {202.5, 41.810314896}, - {247.5, 41.810314896}, - {292.5, 41.810314896}, - {337.5, 41.810314896}, - {0., 19.471220634}, - {45., 19.471220634}, - {90., 19.471220634}, - {135., 19.471220634}, - {180., 19.471220634}, - {225., 19.471220634}, - {270., 19.471220634}, - {315., 19.471220634}, - {22.5, 0.}, - {67.5, 0.}, - {112.5, 0.}, - {157.5, 0.}, - {202.5, 0.}, - {247.5, 0.}, - {292.5, 0.}, - {337.5, 0.}, - {0., -19.471220634}, - {45., -19.471220634}, - {90., -19.471220634}, - {135., -19.471220634}, - {180., -19.471220634}, - {225., -19.471220634}, - {270., -19.471220634}, - {315., -19.471220634}, - {22.5, -41.810314896}, - {67.5, -41.810314896}, - {112.5, -41.810314896}, - {157.5, -41.810314896}, - {202.5, -41.810314896}, - {247.5, -41.810314896}, - {292.5, -41.810314896}, - {337.5, -41.810314896}, - {45., -66.443535691}, - {135., -66.443535691}, - {225., -66.443535691}, - {315., -66.443535691}, - }; - - - auto points_r = ring->to_points(); - - EXPECT(points_r.size() == ring->size()); - ASSERT(points_r.size() == ref.size()); - - auto itr = ring->begin(); - for (size_t i = 0; i < points_r.size(); ++i) { - EXPECT(points_equal(ref[i], points_r[i])); - EXPECT(points_equal(ref[i], *itr)); - ++itr; - } - - EXPECT(itr == ring->end()); - - size_t i = 0; - for (const auto& it : *ring) { - EXPECT(points_equal(ref[i++], it)); - } - - EXPECT(i == ring->size()); - - - auto ren = nested->reorder(Ordering::healpix_ring); - auto points_n = nested->to_points(); - - EXPECT(points_n.size() == nested->size()); - ASSERT(points_n.size() == ref.size()); - - auto it = nested->begin(); - for (size_t i = 0; i < points_n.size(); ++i) { - EXPECT(points_equal(ref[ren.at(i)], points_n[i])); - EXPECT(points_equal(ref[ren.at(i)], *it)); - ++it; - } - - EXPECT(it == nested->end()); - - size_t j = 0; - for (const auto& it : *nested) { - EXPECT(points_equal(ref[ren.at(j++)], it)); - } - - EXPECT(i == nested->size()); + size_t i = 0; + for (const auto& it : *ring) { + EXPECT(points_equal(ref[i++], it)); } + EXPECT(i == ring->size()); + - SECTION("equals") { - std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "h2"}}))); - std::unique_ptr grid2(GridFactory::make_from_string("{type: HEALPix, Nside: 2}")); - std::unique_ptr grid3(new grid::HEALPix(2)); + auto ren = nested->reorder(Ordering::healpix_ring); + auto points_n = nested->to_points(); - EXPECT(*grid1 == *grid2); - EXPECT(*grid2 == *grid3); - EXPECT(*grid3 == *grid1); + EXPECT(points_n.size() == nested->size()); + ASSERT(points_n.size() == ref.size()); - std::unique_ptr grid4(GridFactory::build(spec::Custom({{"grid", "h2"}, {"ordering", "nested"}}))); - std::unique_ptr grid5(GridFactory::make_from_string("{type: HEALPix, Nside: 2, ordering: nested}")); - std::unique_ptr grid6(new grid::HEALPix(2, Ordering::healpix_nested)); + auto it = nested->begin(); + for (size_t i = 0; i < points_n.size(); ++i) { + EXPECT(points_equal(ref[ren.at(i)], points_n[i])); + EXPECT(points_equal(ref[ren.at(i)], *it)); + ++it; + } - EXPECT(*grid4 != *grid1); + EXPECT(it == nested->end()); - EXPECT(*grid4 == *grid5); - EXPECT(*grid5 == *grid6); - EXPECT(*grid6 == *grid4); + size_t j = 0; + for (const auto& it : *nested) { + EXPECT(points_equal(ref[ren.at(j++)], it)); } + + EXPECT(i == nested->size()); +} + + +CASE("equals") { + std::unique_ptr grid1(GridFactory::build(spec::Custom({{"grid", "h2"}}))); + std::unique_ptr grid2(GridFactory::make_from_string("{type: HEALPix, Nside: 2}")); + std::unique_ptr grid3(new grid::HEALPix(2)); + + EXPECT(*grid1 == *grid2); + EXPECT(*grid2 == *grid3); + EXPECT(*grid3 == *grid1); + + EXPECT(grid1->ordering() == Ordering::healpix_ring); + + std::unique_ptr grid4(GridFactory::build(spec::Custom({{"grid", "h2"}, {"ordering", "nested"}}))); + std::unique_ptr grid5(GridFactory::make_from_string("{type: HEALPix, Nside: 2, ordering: nested}")); + std::unique_ptr grid6(new grid::HEALPix(2, Ordering::healpix_nested)); + + EXPECT(*grid4 != *grid1); + + EXPECT(*grid4 == *grid5); + EXPECT(*grid5 == *grid6); + EXPECT(*grid6 == *grid4); + + EXPECT(grid4->ordering() == Ordering::healpix_nested); } diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index cf02ab156..9b5a1b2b2 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -12,7 +12,7 @@ #include -#include "eckit/geo/grid/regular-lonlat/RegularLL.h" +#include "eckit/geo/grid/RegularLL.h" #include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" @@ -20,7 +20,7 @@ namespace eckit::geo::test { -using RegularLL = grid::regularlonlat::RegularLL; +using RegularLL = grid::RegularLL; CASE("global") { diff --git a/tests/geo/grid_reorder.cc b/tests/geo/grid_reorder.cc index 109eed30f..ca395a03b 100644 --- a/tests/geo/grid_reorder.cc +++ b/tests/geo/grid_reorder.cc @@ -49,7 +49,7 @@ CASE("HEALPix") { 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, }; - auto order_ring = ring->order(); + auto order_ring = ring->ordering(); EXPECT_EQUAL(order_ring, Ordering::healpix_ring); auto ren_to_ring = ring->reorder(Ordering::healpix_ring); @@ -61,7 +61,7 @@ CASE("HEALPix") { std::unique_ptr nested(ring->make_grid_reordered(Ordering::healpix_nested)); - auto order_nested = nested->order(); + auto order_nested = nested->ordering(); EXPECT_EQUAL(order_nested, Ordering::healpix_nested); ren_to_nested = nested->reorder(Ordering::healpix_nested); diff --git a/tests/geo/ordering.cc b/tests/geo/ordering.cc new file mode 100644 index 000000000..ee4c9d4c4 --- /dev/null +++ b/tests/geo/ordering.cc @@ -0,0 +1,48 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/Ordering.h" +#include "eckit/geo/spec/Custom.h" +#include "eckit/testing/Test.h" + + +namespace eckit::geo::test { + + +CASE("ordering ('scan')") { + int ordering = 0; + + for (bool scan_alternating : {false, true}) { + for (bool scan_ij : {true, false}) { + for (bool j_plus : {false, true}) { + for (bool i_plus : {true, false}) { + spec::Custom spec({{"scan_i_plus", i_plus}, + {"scan_j_plus", j_plus}, + {"scan_ij", scan_ij}, + {"scan_alternating", scan_alternating}}); + + EXPECT(static_cast(make_ordering_from_spec(spec)) == ordering); + + ++ordering; + } + } + } + } +} + + +} // namespace eckit::geo::test + + +int main(int argc, char** argv) { + return eckit::testing::run_tests(argc, argv); +} diff --git a/tests/geo/spec.cc b/tests/geo/spec.cc index e3cee83a9..5b67f9762 100644 --- a/tests/geo/spec.cc +++ b/tests/geo/spec.cc @@ -102,6 +102,8 @@ CASE("user -> type") { CASE("grid: name -> spec -> grid: name") { +// FIXME +#if 0 for (const std::string& name : {"LAEA-EFAS-5km", "SMUFF-OPERA-2km"}) { std::unique_ptr grid(GridFactory::build(spec::Custom({{"grid", name}}))); EXPECT(grid); @@ -109,6 +111,7 @@ CASE("grid: name -> spec -> grid: name") { auto gridspec = grid->spec_str(); EXPECT(gridspec == R"({"grid":")" + name + R"("})"); } +#endif } From 722714a233d889d83e2179f8d15a5ac223a5c355 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 3 Jun 2024 00:40:40 +0200 Subject: [PATCH 697/737] eckit::geo::Figure --- src/eckit/geo/Figure.cc | 46 ++++++++++++++++++++---- src/eckit/geo/Figure.h | 6 ++-- src/eckit/geo/figure/Earth.cc | 4 ++- src/eckit/geo/figure/Earth.h | 30 +++++++++++++--- src/eckit/geo/figure/OblateSpheroid.cc | 17 +++++---- src/eckit/geo/figure/OblateSpheroid.h | 6 +--- src/eckit/geo/figure/Sphere.cc | 12 +++---- src/eckit/geo/figure/Sphere.h | 4 --- src/eckit/geo/geometry/OblateSpheroid.cc | 6 ++++ src/eckit/geo/geometry/OblateSpheroid.h | 3 ++ tests/geo/figure.cc | 20 +++++++---- 11 files changed, 107 insertions(+), 47 deletions(-) diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc index 8f18bf1f1..693af1734 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/geo/Figure.cc @@ -13,8 +13,10 @@ #include "eckit/geo/Figure.h" #include +#include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/figure/Earth.h" #include "eckit/geo/figure/OblateSpheroid.h" #include "eckit/geo/figure/Sphere.h" #include "eckit/geo/geometry/OblateSpheroid.h" @@ -50,10 +52,18 @@ double Figure::b() const { } -std::string Figure::spec() const { - spec::Custom gridspec; - spec(gridspec); - return gridspec.str(); +spec::Custom* Figure::spec() const { + auto* custom = new spec::Custom; + ASSERT(custom != nullptr); + + spec(*custom); + return custom; +} + + +std::string Figure::spec_str() const { + std::unique_ptr custom(spec()); + return custom->str(); } @@ -62,8 +72,32 @@ double Figure::eccentricity() const { } -void Figure::spec(spec::Custom&) const { - NOTIMP; +double Figure::flattening() const { + return geometry::OblateSpheroid::flattening(a(), b()); +} + + +void Figure::spec(spec::Custom& custom) const { + static const std::map, std::string> KNOWN{ + {std::shared_ptr
{new figure::Earth}, "earth"}, + {std::shared_ptr
{new figure::GRS80}, "grs80"}, + {std::shared_ptr
{new figure::WGS84}, "wgs84"}, + }; + + for (const auto& [figure, name] : KNOWN) { + if (types::is_approximately_equal(figure->a(), a()) && types::is_approximately_equal(figure->b(), b())) { + custom.set("figure", name); + return; + } + } + + if (types::is_approximately_equal(a(), b())) { + custom.set("R", R()); + } + else { + custom.set("a", a()); + custom.set("b", b()); + } } diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index 1df83f600..b26598edd 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -68,9 +68,11 @@ class Figure { virtual double a() const; virtual double b() const; - virtual std::string spec() const; + [[nodiscard]] spec::Custom* spec() const; + std::string spec_str() const; double eccentricity() const; + double flattening() const; private: // -- Methods @@ -79,7 +81,7 @@ class Figure { // -- Friends - friend bool operator==(const Figure& a, const Figure& b) { return a.spec() == b.spec(); } + friend bool operator==(const Figure& a, const Figure& b) { return a.spec_str() == b.spec_str(); } friend bool operator!=(const Figure& a, const Figure& b) { return !(a == b); } }; diff --git a/src/eckit/geo/figure/Earth.cc b/src/eckit/geo/figure/Earth.cc index 9bdc5438a..2c8a70bf5 100644 --- a/src/eckit/geo/figure/Earth.cc +++ b/src/eckit/geo/figure/Earth.cc @@ -16,7 +16,9 @@ namespace eckit::geo::figure { -static const ConcreteBuilderT1 REGISTER("earth"); +static const ConcreteBuilderT1 REGISTER1("earth"); +static const ConcreteBuilderT1 REGISTER2("grs80"); +static const ConcreteBuilderT1 REGISTER3("wgs84"); } // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/Earth.h b/src/eckit/geo/figure/Earth.h index 7b99973c5..996d4006a 100644 --- a/src/eckit/geo/figure/Earth.h +++ b/src/eckit/geo/figure/Earth.h @@ -12,6 +12,7 @@ #pragma once +#include "eckit/geo/figure/OblateSpheroid.h" #include "eckit/geo/figure/Sphere.h" @@ -19,24 +20,43 @@ namespace eckit::geo::figure { struct DatumIFS { - static constexpr double radius() { return 6371229.; } + static constexpr double radius = 6371229.; }; struct DatumGRIB1 { - static constexpr double radius() { return 6367470.; } + static constexpr double radius = 6367470.; }; -struct DatumWGS84SemiMajorAxis { - static constexpr double radius() { return 6378137.; } +struct DatumGRS80 { + static constexpr double a = 6378137.; + static constexpr double b = 6356752.314140; +}; + + +struct DatumWGS84 { + static constexpr double a = 6378137.; + static constexpr double b = 6356752.314245; }; struct Earth final : public Sphere { - explicit Earth() : Sphere(DatumIFS::radius()) {} + explicit Earth() : Sphere(DatumIFS::radius) {} explicit Earth(const Spec&) : Earth() {} }; +struct GRS80 final : public OblateSpheroid { + explicit GRS80() : OblateSpheroid(DatumGRS80::a, DatumGRS80::b) {} + explicit GRS80(const Spec&) : GRS80() {} +}; + + +struct WGS84 final : public OblateSpheroid { + explicit WGS84() : OblateSpheroid(DatumWGS84::a, DatumWGS84::b) {} + explicit WGS84(const Spec&) : WGS84() {} +}; + + } // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/OblateSpheroid.cc b/src/eckit/geo/figure/OblateSpheroid.cc index 1b5894e5d..86e796358 100644 --- a/src/eckit/geo/figure/OblateSpheroid.cc +++ b/src/eckit/geo/figure/OblateSpheroid.cc @@ -13,7 +13,7 @@ #include "eckit/geo/figure/OblateSpheroid.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geo/spec/Custom.h" +#include "eckit/geo/Spec.h" #include "eckit/types/FloatCompare.h" @@ -21,7 +21,9 @@ namespace eckit::geo::figure { OblateSpheroid::OblateSpheroid(double a, double b) : a_(a), b_(b) { - ASSERT_MSG(types::is_strictly_greater(b, 0.) && b_ <= a_, "OblateSpheroid requires 0 < b <= a"); + if (!(0. < b && b_ <= a_)) { + throw BadValue("OblateSpheroid::R requires 0 < b <= a", Here()); + } } @@ -29,14 +31,11 @@ OblateSpheroid::OblateSpheroid(const Spec& spec) : OblateSpheroid(spec.get_doubl double OblateSpheroid::R() const { - ASSERT_MSG(types::is_approximately_equal(a_, b_), "OblateSpheroid::R requires a ~= b"); - return a_; -} - + if (types::is_approximately_equal(a_, b_)) { + return a_; + } -void OblateSpheroid::spec(spec::Custom& custom) const { - custom.set("a", a_); - custom.set("b", b_); + throw BadValue("OblateSpheroid::R requires a ~= b", Here()); } diff --git a/src/eckit/geo/figure/OblateSpheroid.h b/src/eckit/geo/figure/OblateSpheroid.h index 11ac858bb..f061c11da 100644 --- a/src/eckit/geo/figure/OblateSpheroid.h +++ b/src/eckit/geo/figure/OblateSpheroid.h @@ -18,7 +18,7 @@ namespace eckit::geo::figure { -class OblateSpheroid final : public Figure { +class OblateSpheroid : public Figure { public: // -- Constructors @@ -36,10 +36,6 @@ class OblateSpheroid final : public Figure { const double a_; const double b_; - - // -- Overridden methods - - void spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/figure/Sphere.cc b/src/eckit/geo/figure/Sphere.cc index b644b713b..663a3b56c 100644 --- a/src/eckit/geo/figure/Sphere.cc +++ b/src/eckit/geo/figure/Sphere.cc @@ -13,24 +13,20 @@ #include "eckit/geo/figure/Sphere.h" #include "eckit/exception/Exceptions.h" -#include "eckit/geo/spec/Custom.h" -#include "eckit/types/FloatCompare.h" +#include "eckit/geo/Spec.h" namespace eckit::geo::figure { Sphere::Sphere(double R) : R_(R) { - ASSERT_MSG(types::is_strictly_greater(R_, 0.), "Sphere requires R > 0"); + if (!(0. < R_)) { + throw BadValue("Sphere::R requires 0 < R", Here()); + } } Sphere::Sphere(const Spec& spec) : Sphere(spec.get_double("R")) {} -void Sphere::spec(spec::Custom& custom) const { - custom.set("R", R_); -} - - } // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/Sphere.h b/src/eckit/geo/figure/Sphere.h index 68684c5d6..162d08f04 100644 --- a/src/eckit/geo/figure/Sphere.h +++ b/src/eckit/geo/figure/Sphere.h @@ -35,10 +35,6 @@ class Sphere : public Figure { // -- Members const double R_; - - // -- Overridden methods - - void spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/geometry/OblateSpheroid.cc b/src/eckit/geo/geometry/OblateSpheroid.cc index 3f72715ce..a94d8fddc 100644 --- a/src/eckit/geo/geometry/OblateSpheroid.cc +++ b/src/eckit/geo/geometry/OblateSpheroid.cc @@ -28,6 +28,12 @@ double OblateSpheroid::eccentricity(double a, double b) { } +double OblateSpheroid::flattening(double a, double b) { + ASSERT(0. < b && b <= a); + return (a - b) / a; +} + + Point3 OblateSpheroid::convertSphericalToCartesian(double a, double b, const PointLonLat& P, double height) { ASSERT(0. < b && 0. < a); diff --git a/src/eckit/geo/geometry/OblateSpheroid.h b/src/eckit/geo/geometry/OblateSpheroid.h index 8db515444..3261dcd3a 100644 --- a/src/eckit/geo/geometry/OblateSpheroid.h +++ b/src/eckit/geo/geometry/OblateSpheroid.h @@ -25,6 +25,9 @@ struct OblateSpheroid { /// Elliptic eccentricity static double eccentricity(double a, double b); + /// Flattening + static double flattening(double a, double b); + /// Surface area [m ** 2] static double area(double a, double b); diff --git a/tests/geo/figure.cc b/tests/geo/figure.cc index 6a0d900e9..4d4786015 100644 --- a/tests/geo/figure.cc +++ b/tests/geo/figure.cc @@ -34,7 +34,7 @@ CASE("Sphere") { F f2(FigureFactory::build(spec::Custom{{"a", 1.}, {"b", 1.}})); F f3(new figure::Sphere(1.)); - EXPECT_THROWS_AS(figure::Sphere(-1.), AssertionFailed); + EXPECT_THROWS_AS(figure::Sphere(-1.), BadValue); EXPECT(*f1 == *f2); EXPECT(*f1 == *f3); @@ -42,7 +42,7 @@ CASE("Sphere") { auto e = f1->eccentricity(); EXPECT(types::is_approximately_equal(e, 0.)); - EXPECT(f1->spec() == R"({"r":1})"); + EXPECT(f1->spec_str() == R"({"r":1})"); } @@ -50,25 +50,31 @@ CASE("Oblate spheroid") { F f1(FigureFactory::build(spec::Custom{{"b", 0.5}, {"a", 1.}})); F f2(new figure::OblateSpheroid(1., 0.5)); - EXPECT_THROWS_AS(figure::OblateSpheroid(0.5, 1.), AssertionFailed); // prolate spheroid - EXPECT_THROWS_AS(figure::OblateSpheroid(1., -1.), AssertionFailed); + EXPECT_THROWS_AS(figure::OblateSpheroid(0.5, 1.), BadValue); // prolate spheroid + EXPECT_THROWS_AS(figure::OblateSpheroid(1., -1.), BadValue); EXPECT(*f1 == *f2); auto e = f1->eccentricity(); EXPECT(types::is_strictly_greater(e, 0.)); - EXPECT(f1->spec() == R"({"a":1,"b":0.5})"); + EXPECT(f1->spec_str() == R"({"a":1,"b":0.5})"); } CASE("Earth") { - F f1(FigureFactory::build(spec::Custom{{"figure", "earth"}})); + F f1(FigureFactory::build(spec::Custom{{"r", 6371229.}})); F f2(new figure::Earth); EXPECT(*f1 == *f2); + EXPECT(f1->spec_str() == R"({"figure":"earth"})"); + EXPECT(types::is_approximately_equal(f1->R(), 6371229., 1e-8)); - EXPECT(f1->spec() == R"({"r":6.37123e+06})"); + F f4(FigureFactory::build(spec::Custom{{"figure", "wgs84"}})); + + EXPECT(f4->spec_str() == R"({"figure":"wgs84"})"); + EXPECT(types::is_approximately_equal(1. / f4->flattening(), 298.257223563, 1e-8)); + EXPECT_THROWS_AS(f4->R(), BadValue); } From 1680e35b1a8ff1823c16d45fdafc74c69e88543e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 3 Jun 2024 07:53:46 +0200 Subject: [PATCH 698/737] eckit::geo::Projection --- etc/eckit/geo/grid.yaml | 12 ++++-------- src/eckit/geo/LibEcKitGeo.cc | 7 +++++++ src/eckit/geo/LibEcKitGeo.h | 2 ++ src/eckit/geo/Projection.cc | 6 ++++++ src/eckit/geo/Projection.h | 2 ++ src/eckit/geo/eckit_geo_config.h.in | 2 ++ src/eckit/geo/projection/PROJ.cc | 4 ++-- 7 files changed, 25 insertions(+), 10 deletions(-) diff --git a/etc/eckit/geo/grid.yaml b/etc/eckit/geo/grid.yaml index 0bf610987..cf0abd94b 100644 --- a/etc/eckit/geo/grid.yaml +++ b/etc/eckit/geo/grid.yaml @@ -4,20 +4,16 @@ grid_names: - LAEA-EFAS-5km: type: lambert_azimuthal_equal_area proj: +proj=laea +lat_0=52 +lon_0=10 +ellps=GRS80 +units=m +no_defs - shapeOfTheEarth: 4 + figure: grs80 + first_lonlat: [-35.034024, 66.982143] grid: [5000., 5000.] - gaussianNumber: 1280 - standardParallelInDegrees: 52. - centralLongitudeInDegrees: 10. - first_lonlat: [-35.034024,66.982143] shape: [1000, 950] - SMUFF-OPERA-2km: type: lambert_azimuthal_equal_area proj: +proj=laea +lat_0=55 +lon_0=10 +ellps=WGS84 +units=m +no_defs - shapeOfTheEarth: 5 - grid: [2000., 2000.] - gaussianNumber: 1280 + figure: wgs84 first_lonlat: [-39.535385563614, 67.035186732680] + grid: [2000., 2000.] shape: [1900, 2200] diff --git a/src/eckit/geo/LibEcKitGeo.cc b/src/eckit/geo/LibEcKitGeo.cc index 5854ef749..d021fd692 100644 --- a/src/eckit/geo/LibEcKitGeo.cc +++ b/src/eckit/geo/LibEcKitGeo.cc @@ -57,6 +57,13 @@ std::string LibEcKitGeo::cacheDir() { } +bool LibEcKitGeo::proj() { + static const bool yes{ + LibResource("eckit-geo-proj-projections;$ECKIT_GEO_PROJ_PROJECTIONS", eckit_HAVE_PROJ != 0)}; + return yes; +} + + const void* LibEcKitGeo::addr() const { return this; } diff --git a/src/eckit/geo/LibEcKitGeo.h b/src/eckit/geo/LibEcKitGeo.h index ec0c40f48..5a729e6c0 100644 --- a/src/eckit/geo/LibEcKitGeo.h +++ b/src/eckit/geo/LibEcKitGeo.h @@ -36,6 +36,8 @@ class LibEcKitGeo final : public system::Library { static bool caching(); static std::string cacheDir(); + static bool proj(); + private: // -- Constructors diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index 56a3061eb..e4064d46a 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -15,6 +15,7 @@ #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/LibEcKitGeo.h" #include "eckit/geo/spec/Custom.h" @@ -41,6 +42,11 @@ std::string Projection::spec_str() const { } +Projection* Projection::make_from_spec(const Spec& spec) { + return ProjectionFactory::instance().get(spec.get_string(LibEcKitGeo::proj() ? "proj" : "type")).create(spec); +} + + void Projection::spec(spec::Custom&) const { NOTIMP; } diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index c2cdbb5f3..44ef9cace 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -70,6 +70,8 @@ class Projection { static std::string className() { return "projection"; } + [[nodiscard]] static Projection* make_from_spec(const Spec&); + private: // -- Methods diff --git a/src/eckit/geo/eckit_geo_config.h.in b/src/eckit/geo/eckit_geo_config.h.in index a61625d44..d4d3c26de 100644 --- a/src/eckit/geo/eckit_geo_config.h.in +++ b/src/eckit/geo/eckit_geo_config.h.in @@ -20,3 +20,5 @@ #cmakedefine eckit_GEO_CACHE_PATH "@eckit_GEO_CACHE_PATH@" #cmakedefine eckit_GEO_ETC_GRID "@eckit_GEO_ETC_GRID@" +#cmakedefine01 eckit_HAVE_PROJ + diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index fa52834e5..71b05332d 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -146,8 +146,8 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini PROJ::PROJ(const Spec& spec) : - PROJ(spec.get_string("source", DEFAULT), // default to WGS 84 - spec.get_string("target", DEFAULT), // ... + PROJ(spec.get_string("source", spec.get_string("proj", DEFAULT)), // default to WGS 84 + spec.get_string("target", DEFAULT), // ... spec.get_double("lon_minimum", 0)) {} From e2740f5e3b136b3ec572b50f4cad7d46947a3745 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 4 Jun 2024 01:30:25 +0200 Subject: [PATCH 699/737] eckit::geo::Projection --- src/eckit/geo/CMakeLists.txt | 2 - src/eckit/geo/Figure.h | 8 ++-- src/eckit/geo/Projection.cc | 16 +++++++ src/eckit/geo/Projection.h | 9 ++++ src/eckit/geo/grid/regular-xy/Mercator.cc | 2 +- src/eckit/geo/projection/LonLatToXY.cc | 29 ------------ src/eckit/geo/projection/LonLatToXY.h | 45 ------------------- src/eckit/geo/projection/PROJ.cc | 8 ++-- src/eckit/geo/projection/PROJ.h | 1 + .../geo/projection/ProjectionOnFigure.cc | 5 +++ src/eckit/geo/projection/ProjectionOnFigure.h | 5 +-- src/eckit/geo/projection/XYToLonLat.cc | 2 +- .../geo/projection/figure/LonLatToXYZ.cc | 19 ++++---- 13 files changed, 53 insertions(+), 98 deletions(-) delete mode 100644 src/eckit/geo/projection/LonLatToXY.cc delete mode 100644 src/eckit/geo/projection/LonLatToXY.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 6e6da1019..beb1f6eda 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -94,8 +94,6 @@ list(APPEND eckit_geo_srcs polygon/Polygon.h projection/Composer.cc projection/Composer.h - projection/LonLatToXY.cc - projection/LonLatToXY.h projection/None.cc projection/None.h projection/ProjectionOnFigure.cc diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index b26598edd..a7d4b17e0 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -46,8 +46,8 @@ class Figure { // -- Constructors Figure() noexcept = default; - Figure(const Figure&) = default; - Figure(Figure&&) = default; + Figure(const Figure&) = delete; + Figure(Figure&&) = delete; explicit Figure(const Spec&); @@ -57,8 +57,8 @@ class Figure { // -- Operators - Figure& operator=(const Figure&) = default; - Figure& operator=(Figure&&) = default; + Figure& operator=(const Figure&) = delete; + Figure& operator=(Figure&&) = delete; // -- Methods diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index e4064d46a..ec0c41c72 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -15,6 +15,7 @@ #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Figure.h" #include "eckit/geo/LibEcKitGeo.h" #include "eckit/geo/spec/Custom.h" @@ -27,6 +28,21 @@ ProjectionProblem::ProjectionProblem(const std::string& what, const CodeLocation }; +Figure* Projection::make_figure() const { + NOTIMP; +} + + +const Figure& Projection::figure() const { + if (!figure_) { + figure_.reset(make_figure()); + ASSERT(figure_); + } + + return *figure_; +} + + spec::Custom* Projection::spec() const { auto* custom = new spec::Custom; ASSERT(custom != nullptr); diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 44ef9cace..3dc3d5148 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -12,6 +12,7 @@ #pragma once +#include #include #include "eckit/geo/Point.h" @@ -20,6 +21,7 @@ namespace eckit::geo { +class Figure; class Spec; namespace spec { class Custom; @@ -63,6 +65,9 @@ class Projection { virtual Point fwd(const Point&) const = 0; virtual Point inv(const Point&) const = 0; + [[nodiscard]] virtual Figure* make_figure() const; + const Figure& figure() const; + [[nodiscard]] spec::Custom* spec() const; std::string spec_str() const; @@ -73,6 +78,10 @@ class Projection { [[nodiscard]] static Projection* make_from_spec(const Spec&); private: + // -- Members + + mutable std::shared_ptr
figure_; + // -- Methods virtual void spec(spec::Custom&) const; diff --git a/src/eckit/geo/grid/regular-xy/Mercator.cc b/src/eckit/geo/grid/regular-xy/Mercator.cc index 3b7530982..5d973b623 100644 --- a/src/eckit/geo/grid/regular-xy/Mercator.cc +++ b/src/eckit/geo/grid/regular-xy/Mercator.cc @@ -21,7 +21,7 @@ namespace eckit::geo::grid::regularxy { static const GridRegisterType GRIDTYPE("mercator"); -void eckit::geo::grid::regularxy::Mercator::spec(spec::Custom& custom) const { +void Mercator::spec(spec::Custom& custom) const { RegularXY::spec(custom); custom.set("type", "mercator"); diff --git a/src/eckit/geo/projection/LonLatToXY.cc b/src/eckit/geo/projection/LonLatToXY.cc deleted file mode 100644 index aa6c5ff72..000000000 --- a/src/eckit/geo/projection/LonLatToXY.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* - * (C) Copyright 1996- 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 "eckit/geo/projection/LonLatToXY.h" - -#include "eckit/geo/spec/Custom.h" - - -namespace eckit::geo::projection { - - -static ProjectionBuilder PROJECTION("ll_to_xy"); - - -void LonLatToXY::spec(spec::Custom& custom) const { - custom.set("projection", "ll_to_xy"); -} - - -} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/LonLatToXY.h b/src/eckit/geo/projection/LonLatToXY.h deleted file mode 100644 index 0699e35c2..000000000 --- a/src/eckit/geo/projection/LonLatToXY.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * (C) Copyright 1996- 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. - */ - - -#pragma once - -#include "eckit/geo/Projection.h" - - -namespace eckit::geo::projection { - - -class LonLatToXY final : public Projection { -public: - // -- Constructors - - explicit LonLatToXY() = default; - explicit LonLatToXY(const Spec&) {} - - // -- Methods - - inline Point2 fwd(const PointLonLat& p) const { return {p.lon, p.lat}; } - inline PointLonLat inv(const Point2& q) const { return {q.X, q.Y}; } - - // -- Overridden methods - - void spec(spec::Custom&) const override; - -private: - // -- Overridden methods - - inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } - inline Point inv(const Point& q) const override { return inv(std::get(q)); } -}; - - -} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 71b05332d..7f6318fe9 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -15,6 +15,7 @@ #include #include "eckit/exception/Exceptions.h" +#include "eckit/geo/Figure.h" #include "eckit/geo/spec/Custom.h" @@ -151,8 +152,9 @@ PROJ::PROJ(const Spec& spec) : spec.get_double("lon_minimum", 0)) {} -std::string PROJ::ellipsoid(const std::string& string) { - pj_t identity(proj_create_crs_to_crs(CTX, string.c_str(), string.c_str(), nullptr)); +Figure* PROJ::make_figure() const { + pj_t identity(proj_create_crs_to_crs(CTX, target_.c_str(), target_.c_str(), nullptr)); + pj_t crs(proj_get_target_crs(CTX, identity.get())); pj_t ellipsoid(proj_get_ellipsoid(CTX, crs.get())); ASSERT(ellipsoid); @@ -162,7 +164,7 @@ std::string PROJ::ellipsoid(const std::string& string) { ASSERT(proj_ellipsoid_get_parameters(CTX, ellipsoid.get(), &a, &b, nullptr, nullptr)); ASSERT(0 < b && b <= a); - return b < a ? "+a=" + std::to_string(a) + " +b=" + std::to_string(b) : "+R=" + std::to_string(a); + return FigureFactory::build(spec::Custom{{{"a", a}, {"b", b}}}); } diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index 157afd2ce..01c771d4d 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -40,6 +40,7 @@ class PROJ final : public Projection { Point fwd(const Point&) const override; Point inv(const Point&) const override; + [[nodiscard]] Figure* make_figure() const override; void spec(spec::Custom&) const override; private: diff --git a/src/eckit/geo/projection/ProjectionOnFigure.cc b/src/eckit/geo/projection/ProjectionOnFigure.cc index 9f7cf4a50..38355949a 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.cc +++ b/src/eckit/geo/projection/ProjectionOnFigure.cc @@ -30,6 +30,11 @@ ProjectionOnFigure::ProjectionOnFigure(Figure* figure_ptr) : } +Figure* ProjectionOnFigure::make_figure() const { + return FigureFactory::build(spec::Custom{{"a", figure_->a()}, {"b", figure_->b()}}); +} + + void ProjectionOnFigure::spec(spec::Custom& custom) const { // FIXME OO figure if (types::is_approximately_equal(figure_->a(), figure_->b())) { diff --git a/src/eckit/geo/projection/ProjectionOnFigure.h b/src/eckit/geo/projection/ProjectionOnFigure.h index f8f8e2682..266a48bd4 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.h +++ b/src/eckit/geo/projection/ProjectionOnFigure.h @@ -28,12 +28,9 @@ class ProjectionOnFigure : public Projection { explicit ProjectionOnFigure(const Spec&); explicit ProjectionOnFigure(Figure* = nullptr); - // -- Methods - - const Figure& figure() const { return *figure_; } - // -- Overridden methods + [[nodiscard]] Figure* make_figure() const override; void spec(spec::Custom&) const override; private: diff --git a/src/eckit/geo/projection/XYToLonLat.cc b/src/eckit/geo/projection/XYToLonLat.cc index 86341a7a3..e37297fb7 100644 --- a/src/eckit/geo/projection/XYToLonLat.cc +++ b/src/eckit/geo/projection/XYToLonLat.cc @@ -23,7 +23,7 @@ static ProjectionBuilder PROJECTION2("plate-carree"); void XYToLonLat::spec(spec::Custom& custom) const { - custom.set("projection", "plate-carree"); + custom.set("projection", "ll_to_xy"); } diff --git a/src/eckit/geo/projection/figure/LonLatToXYZ.cc b/src/eckit/geo/projection/figure/LonLatToXYZ.cc index a8c17dd7e..5812e6308 100644 --- a/src/eckit/geo/projection/figure/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/figure/LonLatToXYZ.cc @@ -28,30 +28,31 @@ static ProjectionBuilder PROJECTION("ll_to_xyz"); LonLatToXYZ::LonLatToXYZ(Figure* figure_ptr) : ProjectionOnFigure(figure_ptr) { struct LonLatToSphereXYZ final : Implementation { - const Figure& figure_; + const double R; - explicit LonLatToSphereXYZ(const Figure& figure) : figure_(figure) {} + explicit LonLatToSphereXYZ(double _R) : R(_R) {} Point3 operator()(const PointLonLat& p) const override { - return geometry::Sphere::convertSphericalToCartesian(figure_.R(), p, 0.); + return geometry::Sphere::convertSphericalToCartesian(R, p, 0.); } PointLonLat operator()(const Point3& q) const override { - return geometry::Sphere::convertCartesianToSpherical(figure_.R(), q); + return geometry::Sphere::convertCartesianToSpherical(R, q); } }; struct LonLatToSpheroidXYZ final : Implementation { - const Figure& figure_; + const double a; + const double b; - explicit LonLatToSpheroidXYZ(const Figure& figure) : figure_(figure) {} + explicit LonLatToSpheroidXYZ(double _a, double _b) : a(_a), b(_b) {} Point3 operator()(const PointLonLat& p) const override { - return geometry::OblateSpheroid::convertSphericalToCartesian(figure_.a(), figure_.b(), p, 0.); + return geometry::OblateSpheroid::convertSphericalToCartesian(a, b, p, 0.); } PointLonLat operator()(const Point3& q) const override { NOTIMP; } }; impl_.reset(types::is_approximately_equal(figure().eccentricity(), 0.) - ? static_cast(new LonLatToSphereXYZ(figure())) - : new LonLatToSpheroidXYZ(figure())); + ? static_cast(new LonLatToSphereXYZ(figure().R())) + : new LonLatToSpheroidXYZ(figure().a(), figure().b())); } From c6fc3827915f30c1fdb301851214cf66d47c8be9 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 4 Jun 2024 17:27:53 +0200 Subject: [PATCH 700/737] eckit::geo::Point --- src/eckit/geo/PointLonLat.cc | 23 +++++++++++++++++------ src/eckit/geo/PointLonLat.h | 16 ++++------------ src/eckit/geo/PointLonLatR.cc | 12 ++++++------ src/eckit/geo/PointLonLatR.h | 6 ++---- 4 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index 7dc611545..88cb8eb73 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -12,6 +12,7 @@ #include "eckit/geo/PointLonLat.h" +#include #include #include #include @@ -58,9 +59,9 @@ PointLonLat PointLonLat::make(value_type lon, value_type lat, value_type lon_min lon += FLAT_ANGLE; } - return types::is_approximately_equal(lat, RIGHT_ANGLE, eps) ? PointLonLat{0., RIGHT_ANGLE} + return types::is_approximately_equal(lat, RIGHT_ANGLE, eps) ? NORTH_POLE : types::is_approximately_equal(lat, -RIGHT_ANGLE, eps) - ? PointLonLat{ZERO_ANGLE, -RIGHT_ANGLE} + ? SOUTH_POLE : PointLonLat{normalise_angle_to_minimum(lon, lon_minimum), lat}; } @@ -70,15 +71,25 @@ PointLonLat PointLonLat::make_from_lonlatr(value_type lonr, value_type latr, val } +PointLonLat PointLonLat::componentsMin(const PointLonLat& p, const PointLonLat& q) { + return {std::min(p.lon, q.lon), std::min(p.lat, q.lat)}; +} + + +PointLonLat PointLonLat::componentsMax(const PointLonLat& p, const PointLonLat& q) { + return {std::max(p.lon, q.lon), std::max(p.lat, q.lat)}; +} + + bool points_equal(const PointLonLat& a, const PointLonLat& b, PointLonLat::value_type eps) { - const auto c = PointLonLat::make(a.lon, a.lat, PointLonLat::ZERO_ANGLE, eps); - const auto d = PointLonLat::make(b.lon, b.lat, PointLonLat::ZERO_ANGLE, eps); + const auto c = PointLonLat::make(a.lon, a.lat, 0., eps); + const auto d = PointLonLat::make(b.lon, b.lat, 0., eps); return types::is_approximately_equal(c.lon, d.lon, eps) && types::is_approximately_equal(c.lat, d.lat, eps); } -const PointLonLat NORTH_POLE{PointLonLat::ZERO_ANGLE, PointLonLat::RIGHT_ANGLE}; -const PointLonLat SOUTH_POLE{PointLonLat::ZERO_ANGLE, -PointLonLat::RIGHT_ANGLE}; +const PointLonLat NORTH_POLE{0., PointLonLat::RIGHT_ANGLE}; +const PointLonLat SOUTH_POLE{0., -PointLonLat::RIGHT_ANGLE}; } // namespace eckit::geo diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index e923b22eb..1e65fafc7 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -12,7 +12,6 @@ #pragma once -#include #include #include @@ -71,11 +70,10 @@ class PointLonLat final : protected std::array { static void assert_latitude_range(const PointLonLat&); - [[nodiscard]] static PointLonLat make(value_type lon, value_type lat, value_type lon_minimum = ZERO_ANGLE, + [[nodiscard]] static PointLonLat make(value_type lon, value_type lat, value_type lon_minimum = 0., value_type eps = EPS); - [[nodiscard]] static PointLonLat make_from_lonlatr(value_type lonr, value_type latr, - value_type lonr_minimum = ZERO_ANGLE); + [[nodiscard]] static PointLonLat make_from_lonlatr(value_type lonr, value_type latr, value_type lonr_minimum = 0.); PointLonLat antipode() const { return make(lon, lat + FULL_ANGLE / 2.); } @@ -84,18 +82,12 @@ class PointLonLat final : protected std::array { static constexpr value_type FULL_ANGLE = 360.; static constexpr value_type FLAT_ANGLE = 180.; static constexpr value_type RIGHT_ANGLE = 90.; - static constexpr value_type ZERO_ANGLE = 0.; static constexpr value_type EPS = 1e-9; // -- Class methods - static PointLonLat componentsMin(const PointLonLat& p, const PointLonLat& q) { - return {std::min(p.lon, q.lon), std::min(p.lat, q.lat)}; - } - - static PointLonLat componentsMax(const PointLonLat& p, const PointLonLat& q) { - return {std::max(p.lon, q.lon), std::max(p.lat, q.lat)}; - } + static PointLonLat componentsMin(const PointLonLat& p, const PointLonLat& q); + static PointLonLat componentsMax(const PointLonLat& p, const PointLonLat& q); // -- Friends diff --git a/src/eckit/geo/PointLonLatR.cc b/src/eckit/geo/PointLonLatR.cc index bcbada27b..ae6103e2d 100644 --- a/src/eckit/geo/PointLonLatR.cc +++ b/src/eckit/geo/PointLonLatR.cc @@ -43,9 +43,9 @@ PointLonLatR PointLonLatR::make(value_type lonr, value_type latr, value_type lon lonr += FLAT_ANGLE; } - return types::is_approximately_equal(latr, RIGHT_ANGLE, eps) ? PointLonLatR{0., RIGHT_ANGLE} + return types::is_approximately_equal(latr, RIGHT_ANGLE, eps) ? NORTH_POLE_R : types::is_approximately_equal(latr, -RIGHT_ANGLE, eps) - ? PointLonLatR{ZERO_ANGLE, -RIGHT_ANGLE} + ? SOUTH_POLE_R : PointLonLatR{normalise_angle_to_minimum(lonr, lonr_minimum), latr}; } @@ -56,14 +56,14 @@ PointLonLatR PointLonLatR::make_from_lonlat(value_type lon, value_type lat, valu bool points_equal(const PointLonLatR& a, const PointLonLatR& b, PointLonLatR::value_type eps) { - const auto c = PointLonLatR::make(a.lonr, a.latr, PointLonLatR::ZERO_ANGLE, eps); - const auto d = PointLonLatR::make(b.lonr, b.latr, PointLonLatR::ZERO_ANGLE, eps); + const auto c = PointLonLatR::make(a.lonr, a.latr, 0., eps); + const auto d = PointLonLatR::make(b.lonr, b.latr, 0., eps); return types::is_approximately_equal(c.lonr, d.lonr, eps) && types::is_approximately_equal(c.latr, d.latr, eps); } -const PointLonLatR NORTH_POLE_R{PointLonLatR::ZERO_ANGLE, PointLonLatR::RIGHT_ANGLE}; -const PointLonLatR SOUTH_POLE_R{PointLonLatR::ZERO_ANGLE, -PointLonLatR::RIGHT_ANGLE}; +const PointLonLatR NORTH_POLE_R{0., PointLonLatR::RIGHT_ANGLE}; +const PointLonLatR SOUTH_POLE_R{0., -PointLonLatR::RIGHT_ANGLE}; } // namespace eckit::geo diff --git a/src/eckit/geo/PointLonLatR.h b/src/eckit/geo/PointLonLatR.h index dd019e658..077e2d039 100644 --- a/src/eckit/geo/PointLonLatR.h +++ b/src/eckit/geo/PointLonLatR.h @@ -69,11 +69,10 @@ class PointLonLatR final : protected std::array { static value_type normalise_angle_to_maximum(value_type, value_type maximum); - [[nodiscard]] static PointLonLatR make(value_type lonr, value_type latr, value_type lonr_minimum = ZERO_ANGLE, + [[nodiscard]] static PointLonLatR make(value_type lonr, value_type latr, value_type lonr_minimum = 0., value_type eps = EPS); - [[nodiscard]] static PointLonLatR make_from_lonlat(value_type lon, value_type lat, - value_type lon_minimum = ZERO_ANGLE); + [[nodiscard]] static PointLonLatR make_from_lonlat(value_type lon, value_type lat, value_type lon_minimum = 0.); PointLonLatR antipode() const { return make(lonr, latr + FULL_ANGLE / 2.); } @@ -82,7 +81,6 @@ class PointLonLatR final : protected std::array { static constexpr value_type FULL_ANGLE = 2. * M_PI; static constexpr value_type FLAT_ANGLE = M_PI; static constexpr value_type RIGHT_ANGLE = M_PI_2; - static constexpr value_type ZERO_ANGLE = 0.; static constexpr value_type EPS = 1e-10; // -- Class methods From 85edbba2c7a740ea19e2e63309ce91156468389e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Wed, 5 Jun 2024 10:18:55 +0200 Subject: [PATCH 701/737] eckit::geo::Grid (eckit::codec) --- src/tools/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt index aa58c45a8..eaff5c5a0 100644 --- a/src/tools/CMakeLists.txt +++ b/src/tools/CMakeLists.txt @@ -14,7 +14,7 @@ ecbuild_add_executable( TARGET eckit_info ecbuild_add_executable( TARGET eckit_codec_list OUTPUT_NAME eckit-codec-list - CONDITION ECKIT_CODEC + CONDITION eckit_HAVE_ECKIT_CODEC SOURCES eckit-codec-list.cc LIBS eckit_codec eckit_option ) From a1c15eb5db0f50c2d39ca3c1ff03d483014c4936 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 10 Jun 2024 13:28:39 +0100 Subject: [PATCH 702/737] eckit::geo::Point --- src/eckit/geo/PointLonLat.h | 2 +- src/eckit/geo/PointLonLatR.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index 1e65fafc7..650789ad8 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -75,7 +75,7 @@ class PointLonLat final : protected std::array { [[nodiscard]] static PointLonLat make_from_lonlatr(value_type lonr, value_type latr, value_type lonr_minimum = 0.); - PointLonLat antipode() const { return make(lon, lat + FULL_ANGLE / 2.); } + PointLonLat antipode() const { return make(lon, lat + FLAT_ANGLE); } // -- Class members diff --git a/src/eckit/geo/PointLonLatR.h b/src/eckit/geo/PointLonLatR.h index 077e2d039..623161fc7 100644 --- a/src/eckit/geo/PointLonLatR.h +++ b/src/eckit/geo/PointLonLatR.h @@ -74,7 +74,7 @@ class PointLonLatR final : protected std::array { [[nodiscard]] static PointLonLatR make_from_lonlat(value_type lon, value_type lat, value_type lon_minimum = 0.); - PointLonLatR antipode() const { return make(lonr, latr + FULL_ANGLE / 2.); } + PointLonLatR antipode() const { return make(lonr, latr + FLAT_ANGLE); } // -- Class members From 6fa0e8119d445283fe9329678f72dcccc583b662 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 14 Jun 2024 00:28:55 +0100 Subject: [PATCH 703/737] eckit::geo::Projection --- src/eckit/geo/CMakeLists.txt | 3 + src/eckit/geo/Projection.cc | 4 +- src/eckit/geo/Projection.h | 2 +- src/eckit/geo/figure/UnitSphere.cc | 22 ++++++++ src/eckit/geo/figure/UnitSphere.h | 27 +++++++++ src/eckit/geo/projection/Composer.cc | 2 +- src/eckit/geo/projection/Composer.h | 4 +- src/eckit/geo/projection/None.h | 6 +- src/eckit/geo/projection/PROJ.cc | 2 +- src/eckit/geo/projection/PROJ.h | 9 +-- .../geo/projection/ProjectionOnFigure.cc | 2 +- src/eckit/geo/projection/ProjectionOnFigure.h | 11 ++-- src/eckit/geo/projection/Reverse.h | 55 +++++++++++++++++++ src/eckit/geo/projection/Rotation.cc | 11 ++-- src/eckit/geo/projection/Rotation.h | 16 +++--- src/eckit/geo/projection/Stretch.cc | 2 +- src/eckit/geo/projection/Stretch.h | 15 ++--- src/eckit/geo/projection/XYToLonLat.cc | 2 +- src/eckit/geo/projection/XYToLonLat.h | 10 ++-- .../figure/LambertAzimuthalEqualArea.cc | 4 +- .../figure/LambertAzimuthalEqualArea.h | 15 ++--- .../figure/LambertConformalConic.cc | 5 +- .../projection/figure/LambertConformalConic.h | 16 +++--- .../geo/projection/figure/LonLatToXYZ.cc | 7 ++- src/eckit/geo/projection/figure/LonLatToXYZ.h | 15 ++--- src/eckit/geo/projection/figure/Mercator.cc | 4 +- src/eckit/geo/projection/figure/Mercator.h | 15 ++--- .../projection/figure/PolarStereographic.cc | 4 +- .../projection/figure/PolarStereographic.h | 15 ++--- src/eckit/geo/projection/figure/SpaceView.cc | 6 +- src/eckit/geo/projection/figure/SpaceView.h | 15 ++--- tests/geo/projection.cc | 36 ++++++++++-- 32 files changed, 254 insertions(+), 108 deletions(-) create mode 100644 src/eckit/geo/figure/UnitSphere.cc create mode 100644 src/eckit/geo/figure/UnitSphere.h create mode 100644 src/eckit/geo/projection/Reverse.h diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index beb1f6eda..3b1b156bf 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -48,6 +48,8 @@ list(APPEND eckit_geo_srcs figure/OblateSpheroid.h figure/Sphere.cc figure/Sphere.h + figure/UnitSphere.cc + figure/UnitSphere.h geometry/OblateSpheroid.cc geometry/OblateSpheroid.h geometry/Sphere.cc @@ -98,6 +100,7 @@ list(APPEND eckit_geo_srcs projection/None.h projection/ProjectionOnFigure.cc projection/ProjectionOnFigure.h + projection/Reverse.h projection/Rotation.cc projection/Rotation.h projection/Stretch.cc diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index ec0c41c72..e05b20e69 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -47,7 +47,7 @@ spec::Custom* Projection::spec() const { auto* custom = new spec::Custom; ASSERT(custom != nullptr); - spec(*custom); + fill_spec(*custom); return custom; } @@ -63,7 +63,7 @@ Projection* Projection::make_from_spec(const Spec& spec) { } -void Projection::spec(spec::Custom&) const { +void Projection::fill_spec(spec::Custom&) const { NOTIMP; } diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 3dc3d5148..1895b648e 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -84,7 +84,7 @@ class Projection { // -- Methods - virtual void spec(spec::Custom&) const; + virtual void fill_spec(spec::Custom&) const; // -- Friends diff --git a/src/eckit/geo/figure/UnitSphere.cc b/src/eckit/geo/figure/UnitSphere.cc new file mode 100644 index 000000000..2fe0015db --- /dev/null +++ b/src/eckit/geo/figure/UnitSphere.cc @@ -0,0 +1,22 @@ +/* + * (C) Copyright 1996- 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 "eckit/geo/figure/UnitSphere.h" + + +namespace eckit::geo::figure { + + +static const ConcreteBuilderT1 REGISTER("unit-sphere"); + + +} // namespace eckit::geo::figure diff --git a/src/eckit/geo/figure/UnitSphere.h b/src/eckit/geo/figure/UnitSphere.h new file mode 100644 index 000000000..5d6ba19fd --- /dev/null +++ b/src/eckit/geo/figure/UnitSphere.h @@ -0,0 +1,27 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/figure/Sphere.h" + + +namespace eckit::geo::figure { + + +struct UnitSphere final : public Sphere { + explicit UnitSphere() : Sphere(1.) {} + explicit UnitSphere(const Spec&) : UnitSphere() {} +}; + + +} // namespace eckit::geo::figure diff --git a/src/eckit/geo/projection/Composer.cc b/src/eckit/geo/projection/Composer.cc index 4dc930d79..ef00afa12 100644 --- a/src/eckit/geo/projection/Composer.cc +++ b/src/eckit/geo/projection/Composer.cc @@ -57,7 +57,7 @@ std::vector Composer::inv_points(const Point& p) const { } -void Composer::spec(spec::Custom& custom) const { +void Composer::fill_spec(spec::Custom& custom) const { std::vector specs; for (const auto* proj : *this) { specs.emplace_back(proj->spec_str()); diff --git a/src/eckit/geo/projection/Composer.h b/src/eckit/geo/projection/Composer.h index ca19f3750..10aaf783a 100644 --- a/src/eckit/geo/projection/Composer.h +++ b/src/eckit/geo/projection/Composer.h @@ -21,7 +21,7 @@ namespace eckit::geo::projection { -class Composer final : public Projection, private std::deque { +class Composer : public Projection, private std::deque { public: // -- Constructors @@ -42,7 +42,7 @@ class Composer final : public Projection, private std::deque { // -- Overridden methods - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; Point fwd(const Point&) const override; Point inv(const Point&) const override; diff --git a/src/eckit/geo/projection/None.h b/src/eckit/geo/projection/None.h index 203819700..fd60b05e2 100644 --- a/src/eckit/geo/projection/None.h +++ b/src/eckit/geo/projection/None.h @@ -18,7 +18,7 @@ namespace eckit::geo::projection { -class None final : public Projection { +class None : public Projection { public: // -- Constructors @@ -27,10 +27,10 @@ class None final : public Projection { // -- Overridden methods - void spec(spec::Custom&) const override {} - inline Point fwd(const Point& p) const override { return p; } inline Point inv(const Point& q) const override { return q; } + + void fill_spec(spec::Custom&) const override {} }; diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 7f6318fe9..edacaa2f1 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -178,7 +178,7 @@ Point PROJ::inv(const Point& q) const { } -void PROJ::spec(spec::Custom& custom) const { +void PROJ::fill_spec(spec::Custom& custom) const { custom.set("projection", "proj"); if (source_ != DEFAULT) { custom.set("source", source_); diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index 01c771d4d..4fa0b0277 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -21,7 +21,7 @@ namespace eckit::geo::projection { /// Calculate coordinates using PROJ -class PROJ final : public Projection { +class PROJ : public Projection { public: // -- Constructors @@ -33,15 +33,12 @@ class PROJ final : public Projection { const std::string& source() const { return source_; } const std::string& target() const { return target_; } - static std::string ellipsoid(const std::string& string); - // -- Overridden methods Point fwd(const Point&) const override; Point inv(const Point&) const override; [[nodiscard]] Figure* make_figure() const override; - void spec(spec::Custom&) const override; private: // -- Types @@ -54,6 +51,10 @@ class PROJ final : public Projection { const std::string source_; const std::string target_; + + // -- Overridden methods + + void fill_spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/projection/ProjectionOnFigure.cc b/src/eckit/geo/projection/ProjectionOnFigure.cc index 38355949a..6def64351 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.cc +++ b/src/eckit/geo/projection/ProjectionOnFigure.cc @@ -35,7 +35,7 @@ Figure* ProjectionOnFigure::make_figure() const { } -void ProjectionOnFigure::spec(spec::Custom& custom) const { +void ProjectionOnFigure::fill_spec(spec::Custom& custom) const { // FIXME OO figure if (types::is_approximately_equal(figure_->a(), figure_->b())) { custom.set("R", figure_->R()); diff --git a/src/eckit/geo/projection/ProjectionOnFigure.h b/src/eckit/geo/projection/ProjectionOnFigure.h index 266a48bd4..2f2d92a0d 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.h +++ b/src/eckit/geo/projection/ProjectionOnFigure.h @@ -22,17 +22,18 @@ namespace eckit::geo::projection { class ProjectionOnFigure : public Projection { +public: + // -- Overridden methods + + [[nodiscard]] Figure* make_figure() const override; + void fill_spec(spec::Custom&) const override; + protected: // -- Constructors explicit ProjectionOnFigure(const Spec&); explicit ProjectionOnFigure(Figure* = nullptr); - // -- Overridden methods - - [[nodiscard]] Figure* make_figure() const override; - void spec(spec::Custom&) const override; - private: // -- Members diff --git a/src/eckit/geo/projection/Reverse.h b/src/eckit/geo/projection/Reverse.h new file mode 100644 index 000000000..f83c84871 --- /dev/null +++ b/src/eckit/geo/projection/Reverse.h @@ -0,0 +1,55 @@ +/* + * (C) Copyright 1996- 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. + */ + + +#pragma once + +#include "eckit/geo/Projection.h" +#include "eckit/geo/spec/Custom.h" + + +namespace eckit::geo::projection { + + +template +class Reverse : protected P { +public: + // -- Types + + using projection_type = P; + + // -- Constructors + + using P::P; + + // -- Methods + + using P::figure; + using P::make_figure; + + using P::spec; + using P::spec_str; + + // -- Overridden methods + + Point fwd(const Point& p) const override { return P::inv(p); } + Point inv(const Point& p) const override { return P::fwd(p); } + +private: + // -- Overridden methods + + void fill_spec(spec::Custom& custom) const override { + P::fill_spec(custom); + custom.set("projection", "reverse_" + custom.get_string("projection")); + } +}; + +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index f9622d0c6..516d1a542 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -42,10 +42,7 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : struct RotationAngle final : Implementation { explicit RotationAngle(double angle) : angle_(angle) {} PointLonLat operator()(const PointLonLat& p) const override { return {p.lon + angle_, p.lat}; } - void spec(spec::Custom& custom) const override { - custom.set("projection", "rotation"); - custom.set("angle", angle_); - } + void spec(spec::Custom& custom) const override { custom.set("angle", angle_); } const double angle_; }; @@ -58,7 +55,6 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : R_ * geometry::UnitSphere::convertSphericalToCartesian(p)); } void spec(spec::Custom& custom) const override { - custom.set("projection", "rotation"); custom.set("south_pole_lon", south_pole_lon_); custom.set("south_pole_lat", south_pole_lat_); custom.set("angle", angle_); @@ -119,8 +115,9 @@ Rotation::Rotation(const Spec& spec) : Rotation(spec.get_double("south_pole_lon"), spec.get_double("south_pole_lat"), spec.get_double("angle", 0)) {} -void Rotation::spec(spec::Custom& custom) const { - return fwd_->spec(custom); +void Rotation::fill_spec(spec::Custom& custom) const { + fwd_->spec(custom); + custom.set("projection", "rotation"); } diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index bbbfa0b73..5659501a0 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -21,7 +21,7 @@ namespace eckit::geo::projection { /// Calculate coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle -class Rotation final : public Projection { +class Rotation : public Projection { public: // -- Constructors @@ -32,12 +32,19 @@ class Rotation final : public Projection { // -- Methods bool rotated() const { return rotated_; } + PointLonLat fwd(const PointLonLat& p) const { return (*fwd_)(p); } PointLonLat inv(const PointLonLat& q) const { return (*inv_)(q); } // -- Overridden methods - void spec(spec::Custom&) const override; + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } + +protected: + // -- Overridden methods + + void fill_spec(spec::Custom&) const override; private: // -- Types @@ -60,11 +67,6 @@ class Rotation final : public Projection { std::unique_ptr fwd_; std::unique_ptr inv_; bool rotated_; - - // -- Overridden methods - - Point fwd(const Point& p) const override { return (*fwd_)(std::get(p)); } - Point inv(const Point& q) const override { return (*inv_)(std::get(q)); } }; diff --git a/src/eckit/geo/projection/Stretch.cc b/src/eckit/geo/projection/Stretch.cc index cabf6be14..35a1977e6 100644 --- a/src/eckit/geo/projection/Stretch.cc +++ b/src/eckit/geo/projection/Stretch.cc @@ -44,7 +44,7 @@ double Stretch::stretch(double a, double c) { } -void Stretch::spec(spec::Custom& spec) const { +void Stretch::fill_spec(spec::Custom& spec) const { spec.set("projection", "stretch"); spec.set("stretching_factor", c_); } diff --git a/src/eckit/geo/projection/Stretch.h b/src/eckit/geo/projection/Stretch.h index c20a5620f..1f43f21dc 100644 --- a/src/eckit/geo/projection/Stretch.h +++ b/src/eckit/geo/projection/Stretch.h @@ -18,7 +18,7 @@ namespace eckit::geo::projection { -class Stretch final : public Projection { +class Stretch : public Projection { public: // -- Constructors @@ -32,7 +32,13 @@ class Stretch final : public Projection { // -- Overridden methods - void spec(spec::Custom&) const override; + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } + +protected: + // -- Overridden methods + + void fill_spec(spec::Custom&) const override; private: // -- Members @@ -42,11 +48,6 @@ class Stretch final : public Projection { // -- Methods static double stretch(double a, double c); - - // -- Overridden methods - - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } }; diff --git a/src/eckit/geo/projection/XYToLonLat.cc b/src/eckit/geo/projection/XYToLonLat.cc index e37297fb7..e12d6f623 100644 --- a/src/eckit/geo/projection/XYToLonLat.cc +++ b/src/eckit/geo/projection/XYToLonLat.cc @@ -22,7 +22,7 @@ static ProjectionBuilder PROJECTION1("xy_to_ll"); static ProjectionBuilder PROJECTION2("plate-carree"); -void XYToLonLat::spec(spec::Custom& custom) const { +void XYToLonLat::fill_spec(spec::Custom& custom) const { custom.set("projection", "ll_to_xy"); } diff --git a/src/eckit/geo/projection/XYToLonLat.h b/src/eckit/geo/projection/XYToLonLat.h index c2c817535..cd9e5f462 100644 --- a/src/eckit/geo/projection/XYToLonLat.h +++ b/src/eckit/geo/projection/XYToLonLat.h @@ -18,7 +18,7 @@ namespace eckit::geo::projection { -class XYToLonLat final : public Projection { +class XYToLonLat : public Projection { public: // -- Constructors @@ -32,13 +32,13 @@ class XYToLonLat final : public Projection { // -- Overridden methods - void spec(spec::Custom&) const override; + inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } + inline Point inv(const Point& q) const override { return inv(std::get(q)); } -private: +protected: // -- Overridden methods - inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } - inline Point inv(const Point& q) const override { return inv(std::get(q)); } + void fill_spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc index 6c8dd07c4..63d1975da 100644 --- a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc @@ -60,8 +60,8 @@ PointLonLat LambertAzimuthalEqualArea::inv(const Point2& p) const { } -void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { - ProjectionOnFigure::spec(custom); +void LambertAzimuthalEqualArea::fill_spec(spec::Custom& custom) const { + ProjectionOnFigure::fill_spec(custom); custom.set("projection", "laea"); custom.set("lon_0", centre_.lon); diff --git a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h index 81f823ab6..461d30037 100644 --- a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h @@ -19,7 +19,7 @@ namespace eckit::geo::projection::figure { -class LambertAzimuthalEqualArea final : public ProjectionOnFigure { +class LambertAzimuthalEqualArea : public ProjectionOnFigure { public: // -- Types // None @@ -48,7 +48,8 @@ class LambertAzimuthalEqualArea final : public ProjectionOnFigure { // -- Overridden methods - void spec(spec::Custom&) const override; + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } // -- Class members // None @@ -56,6 +57,11 @@ class LambertAzimuthalEqualArea final : public ProjectionOnFigure { // -- Class methods // None +protected: + // -- Overridden methods + + void fill_spec(spec::Custom&) const override; + private: // -- Members @@ -72,11 +78,6 @@ class LambertAzimuthalEqualArea final : public ProjectionOnFigure { // -- Methods // None - // -- Overridden methods - - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } - // -- Class members // None diff --git a/src/eckit/geo/projection/figure/LambertConformalConic.cc b/src/eckit/geo/projection/figure/LambertConformalConic.cc index 38414ec40..18914a178 100644 --- a/src/eckit/geo/projection/figure/LambertConformalConic.cc +++ b/src/eckit/geo/projection/figure/LambertConformalConic.cc @@ -91,9 +91,10 @@ PointLonLat LambertConformalConic::inv(const Point2& p) const { } -void LambertConformalConic::spec(spec::Custom& custom) const { - ProjectionOnFigure::spec(custom); +void LambertConformalConic::fill_spec(spec::Custom& custom) const { + ProjectionOnFigure::fill_spec(custom); + custom.set("projection", "lcc"); custom.set("lon_0", centre_.lon); custom.set("lat_0", centre_.lat); custom.set("first_lon", first_.lon); diff --git a/src/eckit/geo/projection/figure/LambertConformalConic.h b/src/eckit/geo/projection/figure/LambertConformalConic.h index 1cbfef412..63d5d7018 100644 --- a/src/eckit/geo/projection/figure/LambertConformalConic.h +++ b/src/eckit/geo/projection/figure/LambertConformalConic.h @@ -23,7 +23,7 @@ namespace eckit::geo::projection::figure { * @ref Map Projections: A Working Manual, John P. Snyder (1987) * @ref Wolfram MathWorld (http://mathworld.wolfram.com/LambertConformalConicProjection.html) */ -class LambertConformalConic final : public ProjectionOnFigure { +class LambertConformalConic : public ProjectionOnFigure { public: // -- Types // None @@ -55,7 +55,8 @@ class LambertConformalConic final : public ProjectionOnFigure { // -- Overridden methods - void spec(spec::Custom&) const override; + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } // -- Class members // None @@ -63,6 +64,11 @@ class LambertConformalConic final : public ProjectionOnFigure { // -- Class methods // None +protected: + // -- Overridden methods + + void fill_spec(spec::Custom&) const override; + private: // -- Members @@ -81,15 +87,9 @@ class LambertConformalConic final : public ProjectionOnFigure { double f_; double rho0_bare_; - // -- Methods // None - // -- Overridden methods - - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } - // -- Class members // None diff --git a/src/eckit/geo/projection/figure/LonLatToXYZ.cc b/src/eckit/geo/projection/figure/LonLatToXYZ.cc index 5812e6308..43b5dd4f4 100644 --- a/src/eckit/geo/projection/figure/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/figure/LonLatToXYZ.cc @@ -17,6 +17,7 @@ #include "eckit/geo/figure/Sphere.h" #include "eckit/geo/geometry/OblateSpheroid.h" #include "eckit/geo/geometry/Sphere.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/types/FloatCompare.h" @@ -67,8 +68,10 @@ LonLatToXYZ::LonLatToXYZ(double a, double b) : LonLatToXYZ::LonLatToXYZ(const Spec& spec) : LonLatToXYZ(FigureFactory::build(spec)) {} -void LonLatToXYZ::spec(spec::Custom& custom) const { - ProjectionOnFigure::spec(custom); +void LonLatToXYZ::fill_spec(spec::Custom& custom) const { + ProjectionOnFigure::fill_spec(custom); + + custom.set("projection", "ll_to_xyz"); } diff --git a/src/eckit/geo/projection/figure/LonLatToXYZ.h b/src/eckit/geo/projection/figure/LonLatToXYZ.h index 6692e9dd4..d5541d494 100644 --- a/src/eckit/geo/projection/figure/LonLatToXYZ.h +++ b/src/eckit/geo/projection/figure/LonLatToXYZ.h @@ -21,7 +21,7 @@ namespace eckit::geo::projection::figure { /// Calculate coordinates of a point on a sphere or spheroid, in [x, y, z] -class LonLatToXYZ final : public ProjectionOnFigure { +class LonLatToXYZ : public ProjectionOnFigure { public: // -- Constructors @@ -39,7 +39,13 @@ class LonLatToXYZ final : public ProjectionOnFigure { // -- Overridden methods - void spec(spec::Custom&) const override; + Point fwd(const Point& p) const override { return (*impl_)(std::get(p)); } + Point inv(const Point& q) const override { return (*impl_)(std::get(q)); } + +protected: + // -- Overridden methods + + void fill_spec(spec::Custom&) const override; private: // -- Types @@ -60,11 +66,6 @@ class LonLatToXYZ final : public ProjectionOnFigure { // -- Members std::unique_ptr impl_; - - // -- Overridden methods - - Point fwd(const Point& p) const override { return (*impl_)(std::get(p)); } - Point inv(const Point& q) const override { return (*impl_)(std::get(q)); } }; diff --git a/src/eckit/geo/projection/figure/Mercator.cc b/src/eckit/geo/projection/figure/Mercator.cc index 965f11134..609e6c816 100644 --- a/src/eckit/geo/projection/figure/Mercator.cc +++ b/src/eckit/geo/projection/figure/Mercator.cc @@ -105,8 +105,8 @@ PointLonLat Mercator::inv(const Point2& q) const { } -void Mercator::spec(spec::Custom& custom) const { - ProjectionOnFigure::spec(custom); +void Mercator::fill_spec(spec::Custom& custom) const { + ProjectionOnFigure::fill_spec(custom); custom.set("projection", "mercator"); custom.set("lat_ts", centre_.lat); diff --git a/src/eckit/geo/projection/figure/Mercator.h b/src/eckit/geo/projection/figure/Mercator.h index 77d973c99..1ff805c13 100644 --- a/src/eckit/geo/projection/figure/Mercator.h +++ b/src/eckit/geo/projection/figure/Mercator.h @@ -19,7 +19,7 @@ namespace eckit::geo::projection::figure { /// Calculate coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle -class Mercator final : public ProjectionOnFigure { +class Mercator : public ProjectionOnFigure { public: // -- Constructors @@ -34,7 +34,13 @@ class Mercator final : public ProjectionOnFigure { // -- Overridden methods - void spec(spec::Custom&) const override; + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } + +protected: + // -- Overridden methods + + void fill_spec(spec::Custom&) const override; private: // -- Members @@ -56,11 +62,6 @@ class Mercator final : public ProjectionOnFigure { // -- Methods double calculate_phi(double t) const; - - // -- Overridden methods - - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } }; diff --git a/src/eckit/geo/projection/figure/PolarStereographic.cc b/src/eckit/geo/projection/figure/PolarStereographic.cc index 21d55a746..9d6dba635 100644 --- a/src/eckit/geo/projection/figure/PolarStereographic.cc +++ b/src/eckit/geo/projection/figure/PolarStereographic.cc @@ -65,8 +65,8 @@ PointLonLat PolarStereographic::inv(const Point2& q) const { } -void PolarStereographic::spec(spec::Custom& custom) const { - ProjectionOnFigure::spec(custom); +void PolarStereographic::fill_spec(spec::Custom& custom) const { + ProjectionOnFigure::fill_spec(custom); custom.set("projection", "stere"); custom.set("lon_0", centre_.lon); diff --git a/src/eckit/geo/projection/figure/PolarStereographic.h b/src/eckit/geo/projection/figure/PolarStereographic.h index e04aa233b..a5b782761 100644 --- a/src/eckit/geo/projection/figure/PolarStereographic.h +++ b/src/eckit/geo/projection/figure/PolarStereographic.h @@ -18,7 +18,7 @@ namespace eckit::geo::projection::figure { -class PolarStereographic final : public ProjectionOnFigure { +class PolarStereographic : public ProjectionOnFigure { public: // -- Types // None @@ -47,7 +47,8 @@ class PolarStereographic final : public ProjectionOnFigure { // -- Overridden methods - void spec(spec::Custom&) const override; + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } // -- Class members // None @@ -55,6 +56,11 @@ class PolarStereographic final : public ProjectionOnFigure { // -- Class methods // None +protected: + // -- Overridden methods + + void fill_spec(spec::Custom&) const override; + private: // -- Members @@ -72,11 +78,6 @@ class PolarStereographic final : public ProjectionOnFigure { // -- Methods // None - // -- Overridden methods - - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } - // -- Class members // None diff --git a/src/eckit/geo/projection/figure/SpaceView.cc b/src/eckit/geo/projection/figure/SpaceView.cc index 93694040c..574224461 100644 --- a/src/eckit/geo/projection/figure/SpaceView.cc +++ b/src/eckit/geo/projection/figure/SpaceView.cc @@ -46,8 +46,10 @@ PointLonLat SpaceView::inv(const Point2&) const { } -void SpaceView::spec(spec::Custom& custom) const { - ProjectionOnFigure::spec(custom); +void SpaceView::fill_spec(spec::Custom& custom) const { + ProjectionOnFigure::fill_spec(custom); + + custom.set("projection", "geos"); //? NOTIMP; } diff --git a/src/eckit/geo/projection/figure/SpaceView.h b/src/eckit/geo/projection/figure/SpaceView.h index 697cb8970..121ce6e6f 100644 --- a/src/eckit/geo/projection/figure/SpaceView.h +++ b/src/eckit/geo/projection/figure/SpaceView.h @@ -22,7 +22,7 @@ namespace eckit::geo::projection::figure { * @brief SpaceView projection * @ref LRIT/HRIT Global Specification (CGMS 03, Issue 2.6, 12.08.1999) */ -class SpaceView final : public ProjectionOnFigure { +class SpaceView : public ProjectionOnFigure { public: // -- Types // None @@ -50,7 +50,8 @@ class SpaceView final : public ProjectionOnFigure { // -- Overridden methods - void spec(spec::Custom&) const override; + Point fwd(const Point& p) const override { return fwd(std::get(p)); } + Point inv(const Point& q) const override { return inv(std::get(q)); } // -- Class members // None @@ -58,6 +59,11 @@ class SpaceView final : public ProjectionOnFigure { // -- Class methods // None +protected: + // -- Overridden methods + + void fill_spec(spec::Custom&) const override; + private: // -- Members // None @@ -65,11 +71,6 @@ class SpaceView final : public ProjectionOnFigure { // -- Methods // None - // -- Overridden methods - - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } - // -- Class members // None diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index b1f2e7b70..aa49698be 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -13,25 +13,51 @@ #include #include "eckit/geo/Projection.h" -#include "eckit/geo/spec/Custom.h" +#include "eckit/geo/figure/UnitSphere.h" +#include "eckit/geo/projection/Reverse.h" +#include "eckit/geo/projection/figure/LonLatToXYZ.h" // to test Reverse #include "eckit/testing/Test.h" namespace eckit::geo::test { -using P = std::unique_ptr; - - CASE("projection: none") { Point p = PointLonLat{1, 1}; - P projection(ProjectionFactory::instance().get("none").create(spec::Custom{})); + std::unique_ptr projection(ProjectionFactory::instance().get("none").create(spec::Custom{})); EXPECT(points_equal(p, projection->inv(p))); EXPECT(points_equal(p, projection->fwd(p))); } +CASE("projection: reverse") { + projection::figure::LonLatToXYZ ab(new figure::UnitSphere); + projection::Reverse ba(new figure::UnitSphere); + + PointLonLat p = NORTH_POLE; + Point3 q{0., 0., 1.}; + + EXPECT(points_equal(q, ab.fwd(p))); + EXPECT(points_equal(p, ba.fwd(q))); + + EXPECT(points_equal(p, ab.inv(q))); + EXPECT(points_equal(q, ba.inv(p))); + + // ensure fwd(Point3) -> PointLonLat, inv(PointLonLat) -> Point3 + try { + points_equal(p, std::get(ba.fwd(q))); + points_equal(q, std::get(ba.inv(p))); + } + catch (...) { + EXPECT(false); + } + + ASSERT(std::unique_ptr(ab.spec())->get_string("projection") == "ll_to_xyz"); + EXPECT(std::unique_ptr(ba.spec())->get_string("projection") == "reverse_ll_to_xyz"); +} + + } // namespace eckit::geo::test From 30fa8474f0844860197086b5e99b43d135d67a8f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 14 Jun 2024 00:42:53 +0100 Subject: [PATCH 704/737] eckit::geo::Projection --- src/eckit/geo/projection/Reverse.h | 10 +++------- src/eckit/geo/projection/Rotation.h | 8 ++++---- src/eckit/geo/projection/Stretch.h | 8 ++++---- .../figure/LambertAzimuthalEqualArea.h | 4 ++-- .../projection/figure/LambertConformalConic.h | 4 ++-- src/eckit/geo/projection/figure/LonLatToXYZ.h | 8 ++++---- src/eckit/geo/projection/figure/Mercator.h | 4 ++-- .../geo/projection/figure/PolarStereographic.h | 4 ++-- src/eckit/geo/projection/figure/SpaceView.h | 4 ++-- tests/geo/projection.cc | 16 ++++------------ 10 files changed, 29 insertions(+), 41 deletions(-) diff --git a/src/eckit/geo/projection/Reverse.h b/src/eckit/geo/projection/Reverse.h index f83c84871..350320a6e 100644 --- a/src/eckit/geo/projection/Reverse.h +++ b/src/eckit/geo/projection/Reverse.h @@ -20,12 +20,8 @@ namespace eckit::geo::projection { template -class Reverse : protected P { +class Reverse : protected P /* hide interface incosistentwith reversing inv/fwd */ { public: - // -- Types - - using projection_type = P; - // -- Constructors using P::P; @@ -40,8 +36,8 @@ class Reverse : protected P { // -- Overridden methods - Point fwd(const Point& p) const override { return P::inv(p); } - Point inv(const Point& p) const override { return P::fwd(p); } + inline Point fwd(const Point& p) const override { return P::inv(p); } + inline Point inv(const Point& p) const override { return P::fwd(p); } private: // -- Overridden methods diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index 5659501a0..798f9c6cd 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -33,13 +33,13 @@ class Rotation : public Projection { bool rotated() const { return rotated_; } - PointLonLat fwd(const PointLonLat& p) const { return (*fwd_)(p); } - PointLonLat inv(const PointLonLat& q) const { return (*inv_)(q); } + inline PointLonLat fwd(const PointLonLat& p) const { return (*fwd_)(p); } + inline PointLonLat inv(const PointLonLat& q) const { return (*inv_)(q); } // -- Overridden methods - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } + inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } + inline Point inv(const Point& q) const override { return inv(std::get(q)); } protected: // -- Overridden methods diff --git a/src/eckit/geo/projection/Stretch.h b/src/eckit/geo/projection/Stretch.h index 1f43f21dc..0a50139f3 100644 --- a/src/eckit/geo/projection/Stretch.h +++ b/src/eckit/geo/projection/Stretch.h @@ -27,13 +27,13 @@ class Stretch : public Projection { // -- Methods - PointLonLat fwd(const PointLonLat& p) const { return PointLonLat::make(p.lon, stretch(p.lat, 1. / c_)); } - PointLonLat inv(const PointLonLat& p) const { return PointLonLat::make(p.lon, stretch(p.lat, c_)); } + inline PointLonLat fwd(const PointLonLat& p) const { return PointLonLat::make(p.lon, stretch(p.lat, 1. / c_)); } + inline PointLonLat inv(const PointLonLat& p) const { return PointLonLat::make(p.lon, stretch(p.lat, c_)); } // -- Overridden methods - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } + inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } + inline Point inv(const Point& q) const override { return inv(std::get(q)); } protected: // -- Overridden methods diff --git a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h index 461d30037..3cf28b56b 100644 --- a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h @@ -48,8 +48,8 @@ class LambertAzimuthalEqualArea : public ProjectionOnFigure { // -- Overridden methods - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } + inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } + inline Point inv(const Point& q) const override { return inv(std::get(q)); } // -- Class members // None diff --git a/src/eckit/geo/projection/figure/LambertConformalConic.h b/src/eckit/geo/projection/figure/LambertConformalConic.h index 63d5d7018..4d403978b 100644 --- a/src/eckit/geo/projection/figure/LambertConformalConic.h +++ b/src/eckit/geo/projection/figure/LambertConformalConic.h @@ -55,8 +55,8 @@ class LambertConformalConic : public ProjectionOnFigure { // -- Overridden methods - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } + inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } + inline Point inv(const Point& q) const override { return inv(std::get(q)); } // -- Class members // None diff --git a/src/eckit/geo/projection/figure/LonLatToXYZ.h b/src/eckit/geo/projection/figure/LonLatToXYZ.h index d5541d494..53d19b569 100644 --- a/src/eckit/geo/projection/figure/LonLatToXYZ.h +++ b/src/eckit/geo/projection/figure/LonLatToXYZ.h @@ -34,13 +34,13 @@ class LonLatToXYZ : public ProjectionOnFigure { // -- Methods - Point3 fwd(const PointLonLat& p) const { return (*impl_)(p); } - PointLonLat inv(const Point3& q) const { return (*impl_)(q); } + inline Point3 fwd(const PointLonLat& p) const { return (*impl_)(p); } + inline PointLonLat inv(const Point3& q) const { return (*impl_)(q); } // -- Overridden methods - Point fwd(const Point& p) const override { return (*impl_)(std::get(p)); } - Point inv(const Point& q) const override { return (*impl_)(std::get(q)); } + inline Point fwd(const Point& p) const override { return (*impl_)(std::get(p)); } + inline Point inv(const Point& q) const override { return (*impl_)(std::get(q)); } protected: // -- Overridden methods diff --git a/src/eckit/geo/projection/figure/Mercator.h b/src/eckit/geo/projection/figure/Mercator.h index 1ff805c13..4956bc2e4 100644 --- a/src/eckit/geo/projection/figure/Mercator.h +++ b/src/eckit/geo/projection/figure/Mercator.h @@ -34,8 +34,8 @@ class Mercator : public ProjectionOnFigure { // -- Overridden methods - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } + inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } + inline Point inv(const Point& q) const override { return inv(std::get(q)); } protected: // -- Overridden methods diff --git a/src/eckit/geo/projection/figure/PolarStereographic.h b/src/eckit/geo/projection/figure/PolarStereographic.h index a5b782761..763b5ac68 100644 --- a/src/eckit/geo/projection/figure/PolarStereographic.h +++ b/src/eckit/geo/projection/figure/PolarStereographic.h @@ -47,8 +47,8 @@ class PolarStereographic : public ProjectionOnFigure { // -- Overridden methods - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } + inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } + inline Point inv(const Point& q) const override { return inv(std::get(q)); } // -- Class members // None diff --git a/src/eckit/geo/projection/figure/SpaceView.h b/src/eckit/geo/projection/figure/SpaceView.h index 121ce6e6f..cfe8f1a78 100644 --- a/src/eckit/geo/projection/figure/SpaceView.h +++ b/src/eckit/geo/projection/figure/SpaceView.h @@ -50,8 +50,8 @@ class SpaceView : public ProjectionOnFigure { // -- Overridden methods - Point fwd(const Point& p) const override { return fwd(std::get(p)); } - Point inv(const Point& q) const override { return inv(std::get(q)); } + inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } + inline Point inv(const Point& q) const override { return inv(std::get(q)); } // -- Class members // None diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index aa49698be..af835ab82 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -38,20 +38,12 @@ CASE("projection: reverse") { PointLonLat p = NORTH_POLE; Point3 q{0., 0., 1.}; - EXPECT(points_equal(q, ab.fwd(p))); - EXPECT(points_equal(p, ba.fwd(q))); - - EXPECT(points_equal(p, ab.inv(q))); - EXPECT(points_equal(q, ba.inv(p))); + ASSERT(points_equal(q, ab.fwd(p))); + ASSERT(points_equal(p, ab.inv(q))); // ensure fwd(Point3) -> PointLonLat, inv(PointLonLat) -> Point3 - try { - points_equal(p, std::get(ba.fwd(q))); - points_equal(q, std::get(ba.inv(p))); - } - catch (...) { - EXPECT(false); - } + EXPECT(points_equal(p, ba.fwd(q))); + EXPECT(points_equal(q, ba.inv(p))); ASSERT(std::unique_ptr(ab.spec())->get_string("projection") == "ll_to_xyz"); EXPECT(std::unique_ptr(ba.spec())->get_string("projection") == "reverse_ll_to_xyz"); From c387cfb825226c99e36ea323dda37f499122703e Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 14 Jun 2024 07:26:39 +0100 Subject: [PATCH 705/737] eckit::geo::Projection --- tests/geo/projection_ll_to_xyz.cc | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/geo/projection_ll_to_xyz.cc b/tests/geo/projection_ll_to_xyz.cc index 49b4ae2bd..18a30439b 100644 --- a/tests/geo/projection_ll_to_xyz.cc +++ b/tests/geo/projection_ll_to_xyz.cc @@ -55,10 +55,14 @@ CASE("projection: ll_to_xyz") { SECTION("spec") { - EXPECT(to_xyz_1->spec_str() == R"({"r":1})"); - EXPECT(to_xyz_2->spec_str() == R"({"r":1})"); - EXPECT(to_xyz_3->spec_str() == R"({"a":1,"b":0.5})"); - EXPECT(to_xyz_4->spec_str() == R"({"a":1,"b":0.5})"); + Log::info() << to_xyz_1->spec_str() << std::endl; + Log::info() << to_xyz_2->spec_str() << std::endl; + Log::info() << to_xyz_3->spec_str() << std::endl; + Log::info() << to_xyz_4->spec_str() << std::endl; + EXPECT(to_xyz_1->spec_str() == R"({"projection":"ll_to_xyz","r":1})"); + EXPECT(to_xyz_2->spec_str() == R"({"projection":"ll_to_xyz","r":1})"); + EXPECT(to_xyz_3->spec_str() == R"({"a":1,"b":0.5,"projection":"ll_to_xyz"})"); + EXPECT(to_xyz_4->spec_str() == R"({"a":1,"b":0.5,"projection":"ll_to_xyz"})"); } From b2476305f042419cf358230a1ac2a88aad6ca126 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 14 Jun 2024 21:35:25 +0100 Subject: [PATCH 706/737] eckit::geo::Projection --- src/eckit/geo/CMakeLists.txt | 24 +++++----- .../{figure => }/LambertAzimuthalEqualArea.cc | 6 +-- .../{figure => }/LambertAzimuthalEqualArea.h | 4 +- .../{figure => }/LambertConformalConic.cc | 6 +-- .../{figure => }/LambertConformalConic.h | 4 +- .../projection/{figure => }/LonLatToXYZ.cc | 6 +-- .../geo/projection/{figure => }/LonLatToXYZ.h | 4 +- .../geo/projection/{figure => }/Mercator.cc | 6 +-- .../geo/projection/{figure => }/Mercator.h | 4 +- .../{figure => }/PolarStereographic.cc | 6 +-- .../{figure => }/PolarStereographic.h | 4 +- .../geo/projection/{figure => }/SpaceView.cc | 6 +-- .../geo/projection/{figure => }/SpaceView.h | 4 +- tests/geo/projection.cc | 6 +-- tests/geo/projection_ll_to_xyz.cc | 10 ++--- tests/geo/projection_mercator.cc | 45 +++++++------------ 16 files changed, 66 insertions(+), 79 deletions(-) rename src/eckit/geo/projection/{figure => }/LambertAzimuthalEqualArea.cc (93%) rename src/eckit/geo/projection/{figure => }/LambertAzimuthalEqualArea.h (95%) rename src/eckit/geo/projection/{figure => }/LambertConformalConic.cc (95%) rename src/eckit/geo/projection/{figure => }/LambertConformalConic.h (96%) rename src/eckit/geo/projection/{figure => }/LonLatToXYZ.cc (94%) rename src/eckit/geo/projection/{figure => }/LonLatToXYZ.h (95%) rename src/eckit/geo/projection/{figure => }/Mercator.cc (96%) rename src/eckit/geo/projection/{figure => }/Mercator.h (94%) rename src/eckit/geo/projection/{figure => }/PolarStereographic.cc (94%) rename src/eckit/geo/projection/{figure => }/PolarStereographic.h (95%) rename src/eckit/geo/projection/{figure => }/SpaceView.cc (95%) rename src/eckit/geo/projection/{figure => }/SpaceView.h (94%) diff --git a/src/eckit/geo/CMakeLists.txt b/src/eckit/geo/CMakeLists.txt index 3b1b156bf..bea069047 100644 --- a/src/eckit/geo/CMakeLists.txt +++ b/src/eckit/geo/CMakeLists.txt @@ -96,29 +96,29 @@ list(APPEND eckit_geo_srcs polygon/Polygon.h projection/Composer.cc projection/Composer.h + projection/LambertAzimuthalEqualArea.cc + projection/LambertAzimuthalEqualArea.h + projection/LambertConformalConic.cc + projection/LambertConformalConic.h + projection/LonLatToXYZ.cc + projection/LonLatToXYZ.h + projection/Mercator.cc + projection/Mercator.h projection/None.cc projection/None.h + projection/PolarStereographic.cc + projection/PolarStereographic.h projection/ProjectionOnFigure.cc projection/ProjectionOnFigure.h projection/Reverse.h projection/Rotation.cc projection/Rotation.h + projection/SpaceView.cc + projection/SpaceView.h projection/Stretch.cc projection/Stretch.h projection/XYToLonLat.cc projection/XYToLonLat.h - projection/figure/LambertAzimuthalEqualArea.cc - projection/figure/LambertAzimuthalEqualArea.h - projection/figure/LambertConformalConic.cc - projection/figure/LambertConformalConic.h - projection/figure/LonLatToXYZ.cc - projection/figure/LonLatToXYZ.h - projection/figure/Mercator.cc - projection/figure/Mercator.h - projection/figure/PolarStereographic.cc - projection/figure/PolarStereographic.h - projection/figure/SpaceView.cc - projection/figure/SpaceView.h range/GaussianLatitude.cc range/GaussianLatitude.h range/Regular.cc diff --git a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc similarity index 93% rename from src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc rename to src/eckit/geo/projection/LambertAzimuthalEqualArea.cc index 63d1975da..b06fd4d76 100644 --- a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/projection/LambertAzimuthalEqualArea.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/projection/figure/LambertAzimuthalEqualArea.h" +#include "eckit/geo/projection/LambertAzimuthalEqualArea.h" #include @@ -18,7 +18,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geo::projection::figure { +namespace eckit::geo::projection { static ProjectionBuilder PROJECTION_1("lambert_azimuthal_equal_area"); @@ -71,4 +71,4 @@ void LambertAzimuthalEqualArea::fill_spec(spec::Custom& custom) const { } -} // namespace eckit::geo::projection::figure +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h b/src/eckit/geo/projection/LambertAzimuthalEqualArea.h similarity index 95% rename from src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h rename to src/eckit/geo/projection/LambertAzimuthalEqualArea.h index 3cf28b56b..dadc35ee7 100644 --- a/src/eckit/geo/projection/figure/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/projection/LambertAzimuthalEqualArea.h @@ -16,7 +16,7 @@ #include "eckit/geo/util/sincos.h" -namespace eckit::geo::projection::figure { +namespace eckit::geo::projection { class LambertAzimuthalEqualArea : public ProjectionOnFigure { @@ -89,4 +89,4 @@ class LambertAzimuthalEqualArea : public ProjectionOnFigure { }; -} // namespace eckit::geo::projection::figure +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/figure/LambertConformalConic.cc b/src/eckit/geo/projection/LambertConformalConic.cc similarity index 95% rename from src/eckit/geo/projection/figure/LambertConformalConic.cc rename to src/eckit/geo/projection/LambertConformalConic.cc index 18914a178..0d654c2ac 100644 --- a/src/eckit/geo/projection/figure/LambertConformalConic.cc +++ b/src/eckit/geo/projection/LambertConformalConic.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/projection/figure/LambertConformalConic.h" +#include "eckit/geo/projection/LambertConformalConic.h" #include @@ -20,7 +20,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geo::projection::figure { +namespace eckit::geo::projection { LambertConformalConic::LambertConformalConic(const Spec& spec) : @@ -104,4 +104,4 @@ void LambertConformalConic::fill_spec(spec::Custom& custom) const { } -} // namespace eckit::geo::projection::figure +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/figure/LambertConformalConic.h b/src/eckit/geo/projection/LambertConformalConic.h similarity index 96% rename from src/eckit/geo/projection/figure/LambertConformalConic.h rename to src/eckit/geo/projection/LambertConformalConic.h index 4d403978b..bc9c7128f 100644 --- a/src/eckit/geo/projection/figure/LambertConformalConic.h +++ b/src/eckit/geo/projection/LambertConformalConic.h @@ -15,7 +15,7 @@ #include "eckit/geo/projection/ProjectionOnFigure.h" -namespace eckit::geo::projection::figure { +namespace eckit::geo::projection { /** @@ -101,4 +101,4 @@ class LambertConformalConic : public ProjectionOnFigure { }; -} // namespace eckit::geo::projection::figure +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/figure/LonLatToXYZ.cc b/src/eckit/geo/projection/LonLatToXYZ.cc similarity index 94% rename from src/eckit/geo/projection/figure/LonLatToXYZ.cc rename to src/eckit/geo/projection/LonLatToXYZ.cc index 43b5dd4f4..e868fccf4 100644 --- a/src/eckit/geo/projection/figure/LonLatToXYZ.cc +++ b/src/eckit/geo/projection/LonLatToXYZ.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/projection/figure/LonLatToXYZ.h" +#include "eckit/geo/projection/LonLatToXYZ.h" #include "eckit/geo/Spec.h" #include "eckit/geo/figure/OblateSpheroid.h" @@ -21,7 +21,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geo::projection::figure { +namespace eckit::geo::projection { static ProjectionBuilder PROJECTION("ll_to_xyz"); @@ -75,4 +75,4 @@ void LonLatToXYZ::fill_spec(spec::Custom& custom) const { } -} // namespace eckit::geo::projection::figure +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/figure/LonLatToXYZ.h b/src/eckit/geo/projection/LonLatToXYZ.h similarity index 95% rename from src/eckit/geo/projection/figure/LonLatToXYZ.h rename to src/eckit/geo/projection/LonLatToXYZ.h index 53d19b569..f7e9dd520 100644 --- a/src/eckit/geo/projection/figure/LonLatToXYZ.h +++ b/src/eckit/geo/projection/LonLatToXYZ.h @@ -17,7 +17,7 @@ #include "eckit/geo/projection/ProjectionOnFigure.h" -namespace eckit::geo::projection::figure { +namespace eckit::geo::projection { /// Calculate coordinates of a point on a sphere or spheroid, in [x, y, z] @@ -69,4 +69,4 @@ class LonLatToXYZ : public ProjectionOnFigure { }; -} // namespace eckit::geo::projection::figure +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/figure/Mercator.cc b/src/eckit/geo/projection/Mercator.cc similarity index 96% rename from src/eckit/geo/projection/figure/Mercator.cc rename to src/eckit/geo/projection/Mercator.cc index 609e6c816..932de765f 100644 --- a/src/eckit/geo/projection/figure/Mercator.cc +++ b/src/eckit/geo/projection/Mercator.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/projection/figure/Mercator.h" +#include "eckit/geo/projection/Mercator.h" #include #include @@ -20,7 +20,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geo::projection::figure { +namespace eckit::geo::projection { static ProjectionBuilder PROJECTION_1("mercator"); @@ -114,4 +114,4 @@ void Mercator::fill_spec(spec::Custom& custom) const { } -} // namespace eckit::geo::projection::figure +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/figure/Mercator.h b/src/eckit/geo/projection/Mercator.h similarity index 94% rename from src/eckit/geo/projection/figure/Mercator.h rename to src/eckit/geo/projection/Mercator.h index 4956bc2e4..45d63fcd1 100644 --- a/src/eckit/geo/projection/figure/Mercator.h +++ b/src/eckit/geo/projection/Mercator.h @@ -15,7 +15,7 @@ #include "eckit/geo/projection/ProjectionOnFigure.h" -namespace eckit::geo::projection::figure { +namespace eckit::geo::projection { /// Calculate coordinates of a point on a rotated sphere given new location of South Pole (vector) and angle @@ -65,4 +65,4 @@ class Mercator : public ProjectionOnFigure { }; -} // namespace eckit::geo::projection::figure +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/figure/PolarStereographic.cc b/src/eckit/geo/projection/PolarStereographic.cc similarity index 94% rename from src/eckit/geo/projection/figure/PolarStereographic.cc rename to src/eckit/geo/projection/PolarStereographic.cc index 9d6dba635..6def4696a 100644 --- a/src/eckit/geo/projection/figure/PolarStereographic.cc +++ b/src/eckit/geo/projection/PolarStereographic.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/projection/figure/PolarStereographic.h" +#include "eckit/geo/projection/PolarStereographic.h" #include @@ -18,7 +18,7 @@ #include "eckit/types/FloatCompare.h" -namespace eckit::geo::projection::figure { +namespace eckit::geo::projection { PolarStereographic::PolarStereographic(const Spec& spec) : @@ -76,4 +76,4 @@ void PolarStereographic::fill_spec(spec::Custom& custom) const { } -} // namespace eckit::geo::projection::figure +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/figure/PolarStereographic.h b/src/eckit/geo/projection/PolarStereographic.h similarity index 95% rename from src/eckit/geo/projection/figure/PolarStereographic.h rename to src/eckit/geo/projection/PolarStereographic.h index 763b5ac68..bbc1e4892 100644 --- a/src/eckit/geo/projection/figure/PolarStereographic.h +++ b/src/eckit/geo/projection/PolarStereographic.h @@ -15,7 +15,7 @@ #include "eckit/geo/projection/ProjectionOnFigure.h" -namespace eckit::geo::projection::figure { +namespace eckit::geo::projection { class PolarStereographic : public ProjectionOnFigure { @@ -89,4 +89,4 @@ class PolarStereographic : public ProjectionOnFigure { }; -} // namespace eckit::geo::projection::figure +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/figure/SpaceView.cc b/src/eckit/geo/projection/SpaceView.cc similarity index 95% rename from src/eckit/geo/projection/figure/SpaceView.cc rename to src/eckit/geo/projection/SpaceView.cc index 574224461..ea78463a9 100644 --- a/src/eckit/geo/projection/figure/SpaceView.cc +++ b/src/eckit/geo/projection/SpaceView.cc @@ -10,7 +10,7 @@ */ -#include "eckit/geo/projection/figure/SpaceView.h" +#include "eckit/geo/projection/SpaceView.h" #include @@ -19,7 +19,7 @@ #include "eckit/geo/util.h" -namespace eckit::geo::projection::figure { +namespace eckit::geo::projection { SpaceView::SpaceView(const Spec&) { @@ -114,4 +114,4 @@ void init() { } // namespace -} // namespace eckit::geo::projection::figure +} // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/figure/SpaceView.h b/src/eckit/geo/projection/SpaceView.h similarity index 94% rename from src/eckit/geo/projection/figure/SpaceView.h rename to src/eckit/geo/projection/SpaceView.h index cfe8f1a78..1915a4c37 100644 --- a/src/eckit/geo/projection/figure/SpaceView.h +++ b/src/eckit/geo/projection/SpaceView.h @@ -15,7 +15,7 @@ #include "eckit/geo/projection/ProjectionOnFigure.h" -namespace eckit::geo::projection::figure { +namespace eckit::geo::projection { /** @@ -82,4 +82,4 @@ class SpaceView : public ProjectionOnFigure { }; -} // namespace eckit::geo::projection::figure +} // namespace eckit::geo::projection diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index af835ab82..4797d21a5 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -14,8 +14,8 @@ #include "eckit/geo/Projection.h" #include "eckit/geo/figure/UnitSphere.h" +#include "eckit/geo/projection/LonLatToXYZ.h" // to test Reverse #include "eckit/geo/projection/Reverse.h" -#include "eckit/geo/projection/figure/LonLatToXYZ.h" // to test Reverse #include "eckit/testing/Test.h" @@ -32,8 +32,8 @@ CASE("projection: none") { CASE("projection: reverse") { - projection::figure::LonLatToXYZ ab(new figure::UnitSphere); - projection::Reverse ba(new figure::UnitSphere); + projection::LonLatToXYZ ab(new figure::UnitSphere); + projection::Reverse ba(new figure::UnitSphere); PointLonLat p = NORTH_POLE; Point3 q{0., 0., 1.}; diff --git a/tests/geo/projection_ll_to_xyz.cc b/tests/geo/projection_ll_to_xyz.cc index 18a30439b..6d40cf28b 100644 --- a/tests/geo/projection_ll_to_xyz.cc +++ b/tests/geo/projection_ll_to_xyz.cc @@ -13,7 +13,7 @@ #include #include -#include "eckit/geo/projection/figure/LonLatToXYZ.h" +#include "eckit/geo/projection/LonLatToXYZ.h" #include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" @@ -37,21 +37,21 @@ CASE("projection: ll_to_xyz") { // spherical projections P to_xyz_1(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom{{"R", 1.}})); - P to_xyz_2(new projection::figure::LonLatToXYZ(1., 1.)); + P to_xyz_2(new projection::LonLatToXYZ(1., 1.)); EXPECT(*to_xyz_1 == *to_xyz_2); - EXPECT(*to_xyz_1 == projection::figure::LonLatToXYZ(1.)); + EXPECT(*to_xyz_1 == projection::LonLatToXYZ(1.)); // oblate spheroid projections P to_xyz_3(ProjectionFactory::instance().get("ll_to_xyz").create(spec::Custom{{"a", 1.}, {"b", 0.5}})); - P to_xyz_4(new projection::figure::LonLatToXYZ(1., 0.5)); + P to_xyz_4(new projection::LonLatToXYZ(1., 0.5)); EXPECT(*to_xyz_3 == *to_xyz_4); // problate spheroid (not supported) - EXPECT_THROWS(projection::figure::LonLatToXYZ(0.5, 1.)); + EXPECT_THROWS(projection::LonLatToXYZ(0.5, 1.)); SECTION("spec") { diff --git a/tests/geo/projection_mercator.cc b/tests/geo/projection_mercator.cc index beb90e2d1..b4958d715 100644 --- a/tests/geo/projection_mercator.cc +++ b/tests/geo/projection_mercator.cc @@ -12,44 +12,31 @@ #include -#include "eckit/geo/figure/Sphere.h" -#include "eckit/geo/projection/figure/Mercator.h" +#include "eckit/geo/projection/Mercator.h" #include "eckit/testing/Test.h" namespace eckit::geo::test { -CASE("projection: mercator (poles)") { - projection::figure::Mercator projection({0., 14.}, {0., 0.}, new figure::Sphere(1.)); +CASE("projection: mercator") { + for (const auto& projection : { + projection::Mercator({0., 14.}, {262.036, 14.7365}), + projection::Mercator({-180., 0.}, {0., 0.}), + projection::Mercator({0., 14.}, {0., 0.}), + }) { + Point2 a{0., 0.}; + EXPECT(points_equal(a, projection.fwd(projection.inv(a)))); - auto a = projection.fwd(PointLonLat{0., 90.}); - EXPECT(a.Y > std::numeric_limits::max()); + PointLonLat b{-75., 35.}; + EXPECT(points_equal(b, projection.inv(projection.fwd(b)))); - auto b = projection.fwd(PointLonLat{0., -90.}); - EXPECT(b.Y < std::numeric_limits::lowest()); -} - - -CASE("projection: mercator (1)") { - projection::figure::Mercator projection({0., 14.}, {262.036, 14.7365}, new figure::Sphere(6371229.)); - - Point2 a{0., 0.}; - auto b = projection.inv(a); - auto c = projection.fwd(b); - - EXPECT(points_equal(c, a)); -} - - -CASE("projection: mercator (2)") { - projection::figure::Mercator projection({-180., 0.}, {0., 0.}, new figure::Sphere(1.)); - - PointLonLat a{-75., 35.}; - auto b = projection.fwd(a); - auto c = projection.inv(b); + Point2 c = projection.fwd(NORTH_POLE); + EXPECT(c.Y > std::numeric_limits::max()); - EXPECT(points_equal(c, a)); + Point2 d = projection.fwd(SOUTH_POLE); + EXPECT(d.Y < std::numeric_limits::lowest()); + } } From 31f81b164cf690efd384a1f933b31d4e893da25b Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 15 Jun 2024 23:47:39 +0100 Subject: [PATCH 707/737] eckit::geo::Projection --- src/eckit/geo/Projection.cc | 17 ++++++++++ src/eckit/geo/Projection.h | 2 ++ src/eckit/geo/projection/Mercator.cc | 10 ++++-- .../geo/projection/ProjectionOnFigure.cc | 11 +++++++ src/eckit/geo/projection/ProjectionOnFigure.h | 1 + src/eckit/geo/spec/Custom.cc | 32 +++++++++++++++++-- src/eckit/geo/spec/Custom.h | 3 ++ tests/geo/projection_mercator.cc | 20 +++++++++++- 8 files changed, 90 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index e05b20e69..a80418abe 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -58,6 +58,18 @@ std::string Projection::spec_str() const { } +std::string Projection::proj_str() const { + std::string str; + fill_proj(str); + + if (!str.empty() && str.front() == ' ') { + str.erase(0, 1); + } + + return str; +} + + Projection* Projection::make_from_spec(const Spec& spec) { return ProjectionFactory::instance().get(spec.get_string(LibEcKitGeo::proj() ? "proj" : "type")).create(spec); } @@ -68,4 +80,9 @@ void Projection::fill_spec(spec::Custom&) const { } +void Projection::fill_proj(std::string&) const { + NOTIMP; +} + + } // namespace eckit::geo diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 1895b648e..6f3443063 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -70,6 +70,7 @@ class Projection { [[nodiscard]] spec::Custom* spec() const; std::string spec_str() const; + std::string proj_str() const; // -- Class methods @@ -85,6 +86,7 @@ class Projection { // -- Methods virtual void fill_spec(spec::Custom&) const; + virtual void fill_proj(std::string&) const; // -- Friends diff --git a/src/eckit/geo/projection/Mercator.cc b/src/eckit/geo/projection/Mercator.cc index 932de765f..d3003f1c9 100644 --- a/src/eckit/geo/projection/Mercator.cc +++ b/src/eckit/geo/projection/Mercator.cc @@ -108,9 +108,13 @@ PointLonLat Mercator::inv(const Point2& q) const { void Mercator::fill_spec(spec::Custom& custom) const { ProjectionOnFigure::fill_spec(custom); - custom.set("projection", "mercator"); - custom.set("lat_ts", centre_.lat); - custom.set("lon_0", centre_.lon); + custom.set("proj", "merc"); + if (!types::is_approximately_equal(centre_.lat, 0.)) { + custom.set("lat_ts", centre_.lat); + } + if (!types::is_approximately_equal(centre_.lon, 0.)) { + custom.set("lon_0", centre_.lon); + } } diff --git a/src/eckit/geo/projection/ProjectionOnFigure.cc b/src/eckit/geo/projection/ProjectionOnFigure.cc index 6def64351..00489015d 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.cc +++ b/src/eckit/geo/projection/ProjectionOnFigure.cc @@ -12,6 +12,9 @@ #include "eckit/geo/projection/ProjectionOnFigure.h" +#include +#include + #include "eckit/exception/Exceptions.h" #include "eckit/geo/figure/Earth.h" #include "eckit/geo/spec/Custom.h" @@ -46,4 +49,12 @@ void ProjectionOnFigure::fill_spec(spec::Custom& custom) const { } +void ProjectionOnFigure::fill_proj(std::string& str) const { + std::unique_ptr spec(this->spec()); + for (const auto& [key, value] : spec->container()) { + str += " +" + key + "=" + to_string(value); + } +} + + } // namespace eckit::geo::projection diff --git a/src/eckit/geo/projection/ProjectionOnFigure.h b/src/eckit/geo/projection/ProjectionOnFigure.h index 2f2d92a0d..964e40bd2 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.h +++ b/src/eckit/geo/projection/ProjectionOnFigure.h @@ -27,6 +27,7 @@ class ProjectionOnFigure : public Projection { [[nodiscard]] Figure* make_figure() const override; void fill_spec(spec::Custom&) const override; + void fill_proj(std::string&) const override; protected: // -- Constructors diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 5df1a9a76..59bdf1e56 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -13,6 +13,8 @@ #include #include +#include +#include #include #include "eckit/exception/Exceptions.h" @@ -60,8 +62,11 @@ bool get_t_v(const std::vector& from, std::vector& to) { template -bool get_t_v(const std::vector& from, std::vector& to) { - to = from; +bool get_t_v(const std::vector& from, std::vector& to) { + to.clear(); + for (const auto& f : from) { + to.emplace_back(std::to_string(f)); + } return true; } @@ -478,4 +483,27 @@ JSON& operator<<(JSON& j, const Custom::custom_ptr& value) { } +template +struct is_vector : std::false_type {}; + + +template +struct is_vector> : std::true_type {}; + + +template +constexpr bool is_vector_v = is_vector::value; + + +std::string to_string(const Custom::value_type& value) { + return std::visit( + [&](const auto& arg) { + std::ostringstream str; + str << std::setprecision(15) << arg; + return str.str(); + }, + value); +} + + } // namespace eckit::geo::spec diff --git a/src/eckit/geo/spec/Custom.h b/src/eckit/geo/spec/Custom.h index f6989d121..b2aca90a7 100644 --- a/src/eckit/geo/spec/Custom.h +++ b/src/eckit/geo/spec/Custom.h @@ -129,4 +129,7 @@ class Custom final : public Spec { JSON& operator<<(JSON&, const Custom::custom_ptr&); +std::string to_string(const Custom::value_type&); + + } // namespace eckit::geo::spec diff --git a/tests/geo/projection_mercator.cc b/tests/geo/projection_mercator.cc index b4958d715..be395747b 100644 --- a/tests/geo/projection_mercator.cc +++ b/tests/geo/projection_mercator.cc @@ -19,7 +19,7 @@ namespace eckit::geo::test { -CASE("projection: mercator") { +CASE("projection inv(fwd(.)) == . and fwd(inv(.)) == .") { for (const auto& projection : { projection::Mercator({0., 14.}, {262.036, 14.7365}), projection::Mercator({-180., 0.}, {0., 0.}), @@ -40,6 +40,24 @@ CASE("projection: mercator") { } +CASE("spec_str, proj_str") { + projection::Mercator proj1({0., 14.}, {262.036, 14.7365}); + + EXPECT(proj1.proj_str() == "+lat_ts=14 +proj=merc +r=6371229"); + EXPECT(proj1.spec_str() == R"({"lat_ts":14,"proj":"merc","r":6.37123e+06})"); + + projection::Mercator proj2({-180., 0.}, {0., 0.}); + + EXPECT(proj2.proj_str() == "+lon_0=-180 +proj=merc +r=6371229"); + EXPECT(proj2.spec_str() == R"({"lon_0":-180,"proj":"merc","r":6.37123e+06})"); + + projection::Mercator proj3({0., 14.}, {0., 0.}); + + EXPECT(proj3.proj_str() == "+lat_ts=14 +proj=merc +r=6371229"); + EXPECT(proj3.spec_str() == R"({"lat_ts":14,"proj":"merc","r":6.37123e+06})"); +} + + } // namespace eckit::geo::test From 04ec2619bb02969f194ab6b12b55a7b89c815875 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 17 Jun 2024 08:21:28 +0100 Subject: [PATCH 708/737] eckit::geo::Projection --- src/eckit/geo/Area.cc | 2 +- src/eckit/geo/Area.h | 2 +- src/eckit/geo/Figure.cc | 4 ++-- src/eckit/geo/Figure.h | 3 ++- src/eckit/geo/Grid.cc | 4 ++-- src/eckit/geo/Grid.h | 2 +- src/eckit/geo/Iterator.cc | 2 +- src/eckit/geo/Iterator.h | 2 +- src/eckit/geo/area/BoundingBox.cc | 2 +- src/eckit/geo/area/BoundingBox.h | 2 +- src/eckit/geo/grid/HEALPix.cc | 2 +- src/eckit/geo/grid/HEALPix.h | 2 +- src/eckit/geo/grid/ORCA.cc | 2 +- src/eckit/geo/grid/ORCA.h | 2 +- src/eckit/geo/grid/ReducedGaussian.cc | 4 ++-- src/eckit/geo/grid/ReducedGaussian.h | 2 +- src/eckit/geo/grid/ReducedLL.cc | 4 ++-- src/eckit/geo/grid/ReducedLL.h | 2 +- src/eckit/geo/grid/Regular.cc | 4 ++-- src/eckit/geo/grid/Regular.h | 2 +- src/eckit/geo/grid/RegularGaussian.cc | 4 ++-- src/eckit/geo/grid/RegularGaussian.h | 2 +- src/eckit/geo/grid/RegularLL.cc | 4 ++-- src/eckit/geo/grid/RegularLL.h | 2 +- src/eckit/geo/grid/RegularXY.cc | 4 ++-- src/eckit/geo/grid/RegularXY.h | 2 +- src/eckit/geo/grid/Unstructured.cc | 4 ++-- src/eckit/geo/grid/Unstructured.h | 2 +- .../geo/grid/regular-xy/LambertAzimuthalEqualArea.cc | 4 ++-- src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h | 2 +- src/eckit/geo/grid/regular-xy/LambertConformalConic.cc | 4 ++-- src/eckit/geo/grid/regular-xy/LambertConformalConic.h | 2 +- src/eckit/geo/grid/regular-xy/Mercator.cc | 4 ++-- src/eckit/geo/grid/regular-xy/Mercator.h | 2 +- src/eckit/geo/grid/regular-xy/PolarStereographic.cc | 4 ++-- src/eckit/geo/grid/regular-xy/PolarStereographic.h | 2 +- src/eckit/geo/grid/regular-xy/SpaceView.cc | 4 ++-- src/eckit/geo/grid/regular-xy/SpaceView.h | 2 +- src/eckit/geo/iterator/Reduced.cc | 2 +- src/eckit/geo/iterator/Reduced.h | 2 +- src/eckit/geo/iterator/Regular.cc | 2 +- src/eckit/geo/iterator/Regular.h | 2 +- src/eckit/geo/iterator/Unstructured.cc | 2 +- src/eckit/geo/iterator/Unstructured.h | 2 +- src/eckit/geo/projection/ProjectionOnFigure.cc | 2 +- src/eckit/geo/projection/Rotation.cc | 8 ++++---- src/eckit/geo/projection/Rotation.h | 2 +- 47 files changed, 65 insertions(+), 64 deletions(-) diff --git a/src/eckit/geo/Area.cc b/src/eckit/geo/Area.cc index c54f6b814..1f11164a1 100644 --- a/src/eckit/geo/Area.cc +++ b/src/eckit/geo/Area.cc @@ -25,7 +25,7 @@ spec::Custom* Area::spec() const { auto* custom = new spec::Custom; ASSERT(custom != nullptr); - spec(*custom); + fill_spec(*custom); return custom; } diff --git a/src/eckit/geo/Area.h b/src/eckit/geo/Area.h index 6bde03de4..7335d492a 100644 --- a/src/eckit/geo/Area.h +++ b/src/eckit/geo/Area.h @@ -69,7 +69,7 @@ class Area { private: // -- Methods - virtual void spec(spec::Custom&) const = 0; + virtual void fill_spec(spec::Custom&) const = 0; // -- Friends diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc index 693af1734..f2f4fbd08 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/geo/Figure.cc @@ -56,7 +56,7 @@ spec::Custom* Figure::spec() const { auto* custom = new spec::Custom; ASSERT(custom != nullptr); - spec(*custom); + fill_spec(*custom); return custom; } @@ -77,7 +77,7 @@ double Figure::flattening() const { } -void Figure::spec(spec::Custom& custom) const { +void Figure::fill_spec(spec::Custom& custom) const { static const std::map, std::string> KNOWN{ {std::shared_ptr
{new figure::Earth}, "earth"}, {std::shared_ptr
{new figure::GRS80}, "grs80"}, diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index a7d4b17e0..c955d69aa 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -70,6 +70,7 @@ class Figure { [[nodiscard]] spec::Custom* spec() const; std::string spec_str() const; + std::string proj_str() const; double eccentricity() const; double flattening() const; @@ -77,7 +78,7 @@ class Figure { private: // -- Methods - virtual void spec(spec::Custom&) const; + virtual void fill_spec(spec::Custom&) const; // -- Friends diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index e064c83dc..e75e7af24 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -50,7 +50,7 @@ const Spec& Grid::spec() const { ASSERT(spec_); auto& custom = *spec_; - spec(custom); + fill_spec(custom); if (std::string name; SpecByName::instance().match(custom, name)) { custom.clear(); @@ -177,7 +177,7 @@ Renumber Grid::no_reorder(size_t size) { } -void Grid::spec(spec::Custom& custom) const { +void Grid::fill_spec(spec::Custom& custom) const { if (area_) { static const auto AREA_DEFAULT(area::BoundingBox{}.spec_str()); diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index eecebf822..e8ea8b8c8 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -143,7 +143,7 @@ class Grid { // -- Methods - virtual void spec(spec::Custom&) const; + virtual void fill_spec(spec::Custom&) const; static Renumber no_reorder(size_t size); diff --git a/src/eckit/geo/Iterator.cc b/src/eckit/geo/Iterator.cc index 80a445e16..ae0400338 100644 --- a/src/eckit/geo/Iterator.cc +++ b/src/eckit/geo/Iterator.cc @@ -23,7 +23,7 @@ spec::Custom* Iterator::spec() const { auto* custom = new spec::Custom; ASSERT(custom != nullptr); - spec(*custom); + fill_spec(*custom); return custom; } diff --git a/src/eckit/geo/Iterator.h b/src/eckit/geo/Iterator.h index 84446e05d..b4cfb6404 100644 --- a/src/eckit/geo/Iterator.h +++ b/src/eckit/geo/Iterator.h @@ -73,7 +73,7 @@ class Iterator { // -- Methods - virtual void spec(spec::Custom&) const = 0; + virtual void fill_spec(spec::Custom&) const = 0; // -- Friends diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 1f5192f3c..d4a24ca7e 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -42,7 +42,7 @@ BoundingBox* BoundingBox::make_global_antiprime() { } -void BoundingBox::spec(spec::Custom& custom) const { +void BoundingBox::fill_spec(spec::Custom& custom) const { if (operator!=(DEFAULT)) { custom.set("type", "bounding-box"); custom.set("bounding-box", std::vector{north, west, south, east}); diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 9c8b506d3..f1fe7a5de 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -79,7 +79,7 @@ class BoundingBox : public Area, protected std::array { // -- Overridden methods - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; bool intersects(BoundingBox&) const override; // -- Class methods diff --git a/src/eckit/geo/grid/HEALPix.cc b/src/eckit/geo/grid/HEALPix.cc index 9bf0d0108..25c5352ca 100644 --- a/src/eckit/geo/grid/HEALPix.cc +++ b/src/eckit/geo/grid/HEALPix.cc @@ -358,7 +358,7 @@ std::vector HEALPix::longitudes(size_t j) const { } -void HEALPix::spec(spec::Custom& custom) const { +void HEALPix::fill_spec(spec::Custom& custom) const { custom.set("grid", "H" + std::to_string(Nside_)); custom.set("ordering", ordering_ == Ordering::healpix_ring ? "ring" : "nested"); } diff --git a/src/eckit/geo/grid/HEALPix.h b/src/eckit/geo/grid/HEALPix.h index 5c77ee871..e0508c262 100644 --- a/src/eckit/geo/grid/HEALPix.h +++ b/src/eckit/geo/grid/HEALPix.h @@ -64,7 +64,7 @@ class HEALPix final : public Reduced { bool includesSouthPole() const override { return true; } bool isPeriodicWestEast() const override { return true; } - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; const std::vector& latitudes() const override; std::vector longitudes(size_t i) const override; diff --git a/src/eckit/geo/grid/ORCA.cc b/src/eckit/geo/grid/ORCA.cc index 3e59e05c6..c73628754 100644 --- a/src/eckit/geo/grid/ORCA.cc +++ b/src/eckit/geo/grid/ORCA.cc @@ -321,7 +321,7 @@ Spec* ORCA::spec(const std::string& name) { } -void ORCA::spec(spec::Custom& custom) const { +void ORCA::fill_spec(spec::Custom& custom) const { custom.set("type", "ORCA"); custom.set("uid", uid_); } diff --git a/src/eckit/geo/grid/ORCA.h b/src/eckit/geo/grid/ORCA.h index a08c5ada6..f35680649 100644 --- a/src/eckit/geo/grid/ORCA.h +++ b/src/eckit/geo/grid/ORCA.h @@ -104,7 +104,7 @@ class ORCA final : public Regular { // -- Overridden methods - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/grid/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc index 7f2e00413..c72ce12fd 100644 --- a/src/eckit/geo/grid/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -108,8 +108,8 @@ std::vector ReducedGaussian::longitudes(size_t j) const { } -void ReducedGaussian::spec(spec::Custom& custom) const { - Reduced::spec(custom); +void ReducedGaussian::fill_spec(spec::Custom& custom) const { + Reduced::fill_spec(custom); if (pl_ == util::reduced_octahedral_pl(N_)) { custom.set("grid", "O" + std::to_string(N_)); diff --git a/src/eckit/geo/grid/ReducedGaussian.h b/src/eckit/geo/grid/ReducedGaussian.h index d5a14527c..2065c4816 100644 --- a/src/eckit/geo/grid/ReducedGaussian.h +++ b/src/eckit/geo/grid/ReducedGaussian.h @@ -53,7 +53,7 @@ class ReducedGaussian : public Reduced { // -- Overridden methods - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; const std::vector& latitudes() const override; std::vector longitudes(size_t i) const override; diff --git a/src/eckit/geo/grid/ReducedLL.cc b/src/eckit/geo/grid/ReducedLL.cc index 5116f0d39..02c277cf5 100644 --- a/src/eckit/geo/grid/ReducedLL.cc +++ b/src/eckit/geo/grid/ReducedLL.cc @@ -66,8 +66,8 @@ std::vector ReducedLL::longitudes(size_t j) const { } -void ReducedLL::spec(spec::Custom& custom) const { - Reduced::spec(custom); +void ReducedLL::fill_spec(spec::Custom& custom) const { + Reduced::fill_spec(custom); custom.set("type", "reduced_ll"); custom.set("pl", pl_); diff --git a/src/eckit/geo/grid/ReducedLL.h b/src/eckit/geo/grid/ReducedLL.h index 114e7d055..ac520edab 100644 --- a/src/eckit/geo/grid/ReducedLL.h +++ b/src/eckit/geo/grid/ReducedLL.h @@ -50,7 +50,7 @@ class ReducedLL : public Reduced { const std::vector& latitudes() const override; std::vector longitudes(size_t j) const override; - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index 466d17006..b236e5e39 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -60,8 +60,8 @@ Regular::Regular(std::pair xy, const area::BoundingBox& bbox) : } -void Regular::spec(spec::Custom& custom) const { - Grid::spec(custom); +void Regular::fill_spec(spec::Custom& custom) const { + Grid::fill_spec(custom); custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); } diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index 270214e7f..e7c8bf4ce 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -63,7 +63,7 @@ class Regular : public Grid { // -- Overridden methods - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; private: // -- Members diff --git a/src/eckit/geo/grid/RegularGaussian.cc b/src/eckit/geo/grid/RegularGaussian.cc index 01b1dc123..77502f1d7 100644 --- a/src/eckit/geo/grid/RegularGaussian.cc +++ b/src/eckit/geo/grid/RegularGaussian.cc @@ -48,8 +48,8 @@ Spec* RegularGaussian::spec(const std::string& name) { } -void RegularGaussian::spec(spec::Custom& custom) const { - Regular::spec(custom); +void RegularGaussian::fill_spec(spec::Custom& custom) const { + Regular::fill_spec(custom); custom.set("grid", "F" + std::to_string(N_)); } diff --git a/src/eckit/geo/grid/RegularGaussian.h b/src/eckit/geo/grid/RegularGaussian.h index 7c1c24b2b..b8610dff4 100644 --- a/src/eckit/geo/grid/RegularGaussian.h +++ b/src/eckit/geo/grid/RegularGaussian.h @@ -23,7 +23,7 @@ struct RegularGaussian final : public Regular { explicit RegularGaussian(size_t N, const area::BoundingBox& = {}); [[nodiscard]] static Spec* spec(const std::string& name); - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; size_t N() const { return N_; } diff --git a/src/eckit/geo/grid/RegularLL.cc b/src/eckit/geo/grid/RegularLL.cc index a6b72242a..976db8a9b 100644 --- a/src/eckit/geo/grid/RegularLL.cc +++ b/src/eckit/geo/grid/RegularLL.cc @@ -70,8 +70,8 @@ Spec* RegularLL::spec(const std::string& name) { } -void RegularLL::spec(spec::Custom& custom) const { - Regular::spec(custom); +void RegularLL::fill_spec(spec::Custom& custom) const { + Regular::fill_spec(custom); custom.set("grid", std::vector{dx(), dy()}); } diff --git a/src/eckit/geo/grid/RegularLL.h b/src/eckit/geo/grid/RegularLL.h index 2ba39b4c6..7ef16f284 100644 --- a/src/eckit/geo/grid/RegularLL.h +++ b/src/eckit/geo/grid/RegularLL.h @@ -24,7 +24,7 @@ struct RegularLL final : public Regular { RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); [[nodiscard]] static Spec* spec(const std::string& name); - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; [[nodiscard]] Grid* make_grid_cropped(const Area&) const override; }; diff --git a/src/eckit/geo/grid/RegularXY.cc b/src/eckit/geo/grid/RegularXY.cc index 714cf7034..edd1658d8 100644 --- a/src/eckit/geo/grid/RegularXY.cc +++ b/src/eckit/geo/grid/RegularXY.cc @@ -50,8 +50,8 @@ std::pair RegularXY::make_xy_ranges_from_spec(const Spec& spec) } -void RegularXY::spec(spec::Custom& custom) const { - Regular::spec(custom); +void RegularXY::fill_spec(spec::Custom& custom) const { + Regular::fill_spec(custom); custom.set("grid", std::vector{dx(), dy()}); custom.set("first_lonlat", std::vector{first_lonlat.lon, first_lonlat.lat}); diff --git a/src/eckit/geo/grid/RegularXY.h b/src/eckit/geo/grid/RegularXY.h index dae4f2dc3..68aa73534 100644 --- a/src/eckit/geo/grid/RegularXY.h +++ b/src/eckit/geo/grid/RegularXY.h @@ -41,7 +41,7 @@ class RegularXY : public Regular { // -- Overridden methods - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; private: // -- Members diff --git a/src/eckit/geo/grid/Unstructured.cc b/src/eckit/geo/grid/Unstructured.cc index af8b93cff..ced92f6f0 100644 --- a/src/eckit/geo/grid/Unstructured.cc +++ b/src/eckit/geo/grid/Unstructured.cc @@ -38,8 +38,8 @@ Spec* Unstructured::spec(const std::string& name) { } -void Unstructured::spec(spec::Custom& custom) const { - Grid::spec(custom); +void Unstructured::fill_spec(spec::Custom& custom) const { + Grid::fill_spec(custom); custom.set("type", "unstructured"); custom.set("uid", uid()); diff --git a/src/eckit/geo/grid/Unstructured.h b/src/eckit/geo/grid/Unstructured.h index ed7bc68ad..2424bd9f8 100644 --- a/src/eckit/geo/grid/Unstructured.h +++ b/src/eckit/geo/grid/Unstructured.h @@ -55,7 +55,7 @@ class Unstructured final : public Grid { // -- Overridden methods - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; // -- Friends diff --git a/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.cc b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.cc index 3313c8cb7..be5ee261a 100644 --- a/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.cc +++ b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.cc @@ -21,8 +21,8 @@ namespace eckit::geo::grid::regularxy { static const GridRegisterType GRIDTYPE("lambert_azimuthal_equal_area"); -void LambertAzimuthalEqualArea::spec(spec::Custom& custom) const { - RegularXY::spec(custom); +void LambertAzimuthalEqualArea::fill_spec(spec::Custom& custom) const { + RegularXY::fill_spec(custom); custom.set("type", "lambert_azimuthal_equal_area"); diff --git a/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h index 824a500c9..84be8d26d 100644 --- a/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h @@ -22,7 +22,7 @@ struct LambertAzimuthalEqualArea final : public RegularXY { explicit LambertAzimuthalEqualArea(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} - void spec(spec::Custom& custom) const override; + void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/grid/regular-xy/LambertConformalConic.cc b/src/eckit/geo/grid/regular-xy/LambertConformalConic.cc index 9cdad559b..a4700daeb 100644 --- a/src/eckit/geo/grid/regular-xy/LambertConformalConic.cc +++ b/src/eckit/geo/grid/regular-xy/LambertConformalConic.cc @@ -21,8 +21,8 @@ namespace eckit::geo::grid::regularxy { static const GridRegisterType GRIDTYPE("lambert"); -void LambertConformalConic::spec(spec::Custom& custom) const { - RegularXY::spec(custom); +void LambertConformalConic::fill_spec(spec::Custom& custom) const { + RegularXY::fill_spec(custom); custom.set("type", "lambert"); diff --git a/src/eckit/geo/grid/regular-xy/LambertConformalConic.h b/src/eckit/geo/grid/regular-xy/LambertConformalConic.h index 978d6e149..247cfe35e 100644 --- a/src/eckit/geo/grid/regular-xy/LambertConformalConic.h +++ b/src/eckit/geo/grid/regular-xy/LambertConformalConic.h @@ -22,7 +22,7 @@ struct LambertConformalConic final : public RegularXY { explicit LambertConformalConic(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} - void spec(spec::Custom& custom) const override; + void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/grid/regular-xy/Mercator.cc b/src/eckit/geo/grid/regular-xy/Mercator.cc index 5d973b623..09e4264b2 100644 --- a/src/eckit/geo/grid/regular-xy/Mercator.cc +++ b/src/eckit/geo/grid/regular-xy/Mercator.cc @@ -21,8 +21,8 @@ namespace eckit::geo::grid::regularxy { static const GridRegisterType GRIDTYPE("mercator"); -void Mercator::spec(spec::Custom& custom) const { - RegularXY::spec(custom); +void Mercator::fill_spec(spec::Custom& custom) const { + RegularXY::fill_spec(custom); custom.set("type", "mercator"); diff --git a/src/eckit/geo/grid/regular-xy/Mercator.h b/src/eckit/geo/grid/regular-xy/Mercator.h index f62dacaff..751d23849 100644 --- a/src/eckit/geo/grid/regular-xy/Mercator.h +++ b/src/eckit/geo/grid/regular-xy/Mercator.h @@ -22,7 +22,7 @@ struct Mercator final : public RegularXY { explicit Mercator(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} - void spec(spec::Custom& custom) const override; + void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/grid/regular-xy/PolarStereographic.cc b/src/eckit/geo/grid/regular-xy/PolarStereographic.cc index 425e32df2..dc88d6c99 100644 --- a/src/eckit/geo/grid/regular-xy/PolarStereographic.cc +++ b/src/eckit/geo/grid/regular-xy/PolarStereographic.cc @@ -21,8 +21,8 @@ namespace eckit::geo::grid::regularxy { static const GridRegisterType GRIDTYPE("polar_stereographic"); -void PolarStereographic::spec(spec::Custom& custom) const { - RegularXY::spec(custom); +void PolarStereographic::fill_spec(spec::Custom& custom) const { + RegularXY::fill_spec(custom); custom.set("type", "polar_stereographic"); diff --git a/src/eckit/geo/grid/regular-xy/PolarStereographic.h b/src/eckit/geo/grid/regular-xy/PolarStereographic.h index c2302b3c3..6b230de2b 100644 --- a/src/eckit/geo/grid/regular-xy/PolarStereographic.h +++ b/src/eckit/geo/grid/regular-xy/PolarStereographic.h @@ -22,7 +22,7 @@ struct PolarStereographic final : public RegularXY { explicit PolarStereographic(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} - void spec(spec::Custom& custom) const override; + void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/grid/regular-xy/SpaceView.cc b/src/eckit/geo/grid/regular-xy/SpaceView.cc index 4d58e3ebf..1a74628ab 100644 --- a/src/eckit/geo/grid/regular-xy/SpaceView.cc +++ b/src/eckit/geo/grid/regular-xy/SpaceView.cc @@ -21,8 +21,8 @@ namespace eckit::geo::grid::regularxy { static const GridRegisterType GRIDTYPE("space_view"); -void SpaceView::spec(spec::Custom& custom) const { - RegularXY::spec(custom); +void SpaceView::fill_spec(spec::Custom& custom) const { + RegularXY::fill_spec(custom); custom.set("type", "space_view"); diff --git a/src/eckit/geo/grid/regular-xy/SpaceView.h b/src/eckit/geo/grid/regular-xy/SpaceView.h index 74012f5c4..5e39aca7a 100644 --- a/src/eckit/geo/grid/regular-xy/SpaceView.h +++ b/src/eckit/geo/grid/regular-xy/SpaceView.h @@ -22,7 +22,7 @@ struct SpaceView final : public RegularXY { explicit SpaceView(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} - void spec(spec::Custom& custom) const override; + void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/iterator/Reduced.cc b/src/eckit/geo/iterator/Reduced.cc index e6e785f4c..5f1ba889e 100644 --- a/src/eckit/geo/iterator/Reduced.cc +++ b/src/eckit/geo/iterator/Reduced.cc @@ -92,7 +92,7 @@ size_t Reduced::j(size_t idx) const { } -void Reduced::spec(spec::Custom&) const { +void Reduced::fill_spec(spec::Custom&) const { // FIXME implement } diff --git a/src/eckit/geo/iterator/Reduced.h b/src/eckit/geo/iterator/Reduced.h index 95c9cb121..05d8d8c5d 100644 --- a/src/eckit/geo/iterator/Reduced.h +++ b/src/eckit/geo/iterator/Reduced.h @@ -55,7 +55,7 @@ class Reduced final : public geo::Iterator { size_t index() const override { return index_; } size_t j(size_t idx) const; - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/iterator/Regular.cc b/src/eckit/geo/iterator/Regular.cc index 362a7b420..a7d8673e2 100644 --- a/src/eckit/geo/iterator/Regular.cc +++ b/src/eckit/geo/iterator/Regular.cc @@ -67,7 +67,7 @@ Point Regular::operator*() const { } -void Regular::spec(spec::Custom&) const { +void Regular::fill_spec(spec::Custom&) const { // FIXME implement } diff --git a/src/eckit/geo/iterator/Regular.h b/src/eckit/geo/iterator/Regular.h index dd1dec5a6..5bf27c948 100644 --- a/src/eckit/geo/iterator/Regular.h +++ b/src/eckit/geo/iterator/Regular.h @@ -57,7 +57,7 @@ class Regular final : public Iterator { size_t index() const override { return index_; } - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/iterator/Unstructured.cc b/src/eckit/geo/iterator/Unstructured.cc index 07377eea6..b647beeba 100644 --- a/src/eckit/geo/iterator/Unstructured.cc +++ b/src/eckit/geo/iterator/Unstructured.cc @@ -122,7 +122,7 @@ Point Unstructured::operator*() const { } -void Unstructured::spec(spec::Custom&) const { +void Unstructured::fill_spec(spec::Custom&) const { // FIXME implement } diff --git a/src/eckit/geo/iterator/Unstructured.h b/src/eckit/geo/iterator/Unstructured.h index ac3fb53ee..cc163221c 100644 --- a/src/eckit/geo/iterator/Unstructured.h +++ b/src/eckit/geo/iterator/Unstructured.h @@ -67,7 +67,7 @@ class Unstructured final : public Iterator { size_t index() const override { return index_; } - void spec(spec::Custom&) const override; + void fill_spec(spec::Custom&) const override; }; diff --git a/src/eckit/geo/projection/ProjectionOnFigure.cc b/src/eckit/geo/projection/ProjectionOnFigure.cc index 00489015d..05f56f663 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.cc +++ b/src/eckit/geo/projection/ProjectionOnFigure.cc @@ -24,7 +24,7 @@ namespace eckit::geo::projection { -ProjectionOnFigure::ProjectionOnFigure(const Spec&) : ProjectionOnFigure() {} +ProjectionOnFigure::ProjectionOnFigure(const Spec&) {} ProjectionOnFigure::ProjectionOnFigure(Figure* figure_ptr) : diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 516d1a542..863f9a562 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -36,13 +36,13 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : struct NonRotated final : Implementation { PointLonLat operator()(const PointLonLat& p) const override { return p; } - void spec(spec::Custom& custom) const override {} + void fill_spec(spec::Custom& custom) const override {} }; struct RotationAngle final : Implementation { explicit RotationAngle(double angle) : angle_(angle) {} PointLonLat operator()(const PointLonLat& p) const override { return {p.lon + angle_, p.lat}; } - void spec(spec::Custom& custom) const override { custom.set("angle", angle_); } + void fill_spec(spec::Custom& custom) const override { custom.set("angle", angle_); } const double angle_; }; @@ -54,7 +54,7 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : return geometry::UnitSphere::convertCartesianToSpherical( R_ * geometry::UnitSphere::convertSphericalToCartesian(p)); } - void spec(spec::Custom& custom) const override { + void fill_spec(spec::Custom& custom) const override { custom.set("south_pole_lon", south_pole_lon_); custom.set("south_pole_lat", south_pole_lat_); custom.set("angle", angle_); @@ -116,7 +116,7 @@ Rotation::Rotation(const Spec& spec) : void Rotation::fill_spec(spec::Custom& custom) const { - fwd_->spec(custom); + fwd_->fill_spec(custom); custom.set("projection", "rotation"); } diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index 798f9c6cd..454d0cf8c 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -59,7 +59,7 @@ class Rotation : public Projection { void operator=(Implementation&&) = delete; virtual PointLonLat operator()(const PointLonLat&) const = 0; - virtual void spec(spec::Custom&) const = 0; + virtual void fill_spec(spec::Custom&) const = 0; }; // -- Members From 04ff7a99acbe758fe635f117928a1dc0e81b1a67 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 17 Jun 2024 17:02:54 +0100 Subject: [PATCH 709/737] eckit::geo::Projection --- CMakeLists.txt | 5 +++++ src/eckit/geo/LibEcKitGeo.cc | 3 ++- src/eckit/geo/Projection.cc | 2 +- src/eckit/geo/eckit_geo_config.h.in | 1 + src/eckit/geo/projection/Mercator.cc | 2 +- tests/geo/projection_mercator.cc | 10 +++++----- 6 files changed, 15 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index df40ba9f5..3a281ae6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -200,6 +200,11 @@ ecbuild_add_option( FEATURE GEO_BITREPRODUCIBLE CONDITION HAVE_ECKIT_GEO DESCRIPTION "eckit::geo geometry library bit reproducibility tests" ) +ecbuild_add_option( FEATURE GEO_PROJECTION_PROJ_DEFAULT + DEFAULT OFF + CONDITION HAVE_ECKIT_GEO + DESCRIPTION "eckit::geo geometry library default to PROJ-based projections" ) + set( eckit_GEO_CACHE_PATH "/tmp/cache" ) ### LAPACK diff --git a/src/eckit/geo/LibEcKitGeo.cc b/src/eckit/geo/LibEcKitGeo.cc index d021fd692..62e479c6f 100644 --- a/src/eckit/geo/LibEcKitGeo.cc +++ b/src/eckit/geo/LibEcKitGeo.cc @@ -59,7 +59,8 @@ std::string LibEcKitGeo::cacheDir() { bool LibEcKitGeo::proj() { static const bool yes{ - LibResource("eckit-geo-proj-projections;$ECKIT_GEO_PROJ_PROJECTIONS", eckit_HAVE_PROJ != 0)}; + LibResource("eckit-geo-projection-proj;$ECKIT_GEO_PROJECTION_PROJ", + (eckit_HAVE_PROJ != 0) && (eckit_HAVE_GEO_PROJECTION_PROJ_DEFAULT != 0))}; return yes; } diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index a80418abe..d4b9aa742 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -71,7 +71,7 @@ std::string Projection::proj_str() const { Projection* Projection::make_from_spec(const Spec& spec) { - return ProjectionFactory::instance().get(spec.get_string(LibEcKitGeo::proj() ? "proj" : "type")).create(spec); + return ProjectionFactory::instance().get(spec.get_string(LibEcKitGeo::proj() ? "proj" : "projection")).create(spec); } diff --git a/src/eckit/geo/eckit_geo_config.h.in b/src/eckit/geo/eckit_geo_config.h.in index d4d3c26de..11f373160 100644 --- a/src/eckit/geo/eckit_geo_config.h.in +++ b/src/eckit/geo/eckit_geo_config.h.in @@ -17,6 +17,7 @@ #cmakedefine01 eckit_HAVE_GEO_CACHING #cmakedefine01 eckit_HAVE_GEO_CONVEX_HULL #cmakedefine01 eckit_HAVE_GEO_GRID_ORCA +#cmakedefine01 eckit_HAVE_GEO_PROJECTION_PROJ_DEFAULT #cmakedefine eckit_GEO_CACHE_PATH "@eckit_GEO_CACHE_PATH@" #cmakedefine eckit_GEO_ETC_GRID "@eckit_GEO_ETC_GRID@" diff --git a/src/eckit/geo/projection/Mercator.cc b/src/eckit/geo/projection/Mercator.cc index d3003f1c9..e7a48ea9c 100644 --- a/src/eckit/geo/projection/Mercator.cc +++ b/src/eckit/geo/projection/Mercator.cc @@ -108,7 +108,7 @@ PointLonLat Mercator::inv(const Point2& q) const { void Mercator::fill_spec(spec::Custom& custom) const { ProjectionOnFigure::fill_spec(custom); - custom.set("proj", "merc"); + custom.set("projection", "mercator"); if (!types::is_approximately_equal(centre_.lat, 0.)) { custom.set("lat_ts", centre_.lat); } diff --git a/tests/geo/projection_mercator.cc b/tests/geo/projection_mercator.cc index be395747b..11e8cc97f 100644 --- a/tests/geo/projection_mercator.cc +++ b/tests/geo/projection_mercator.cc @@ -19,7 +19,7 @@ namespace eckit::geo::test { -CASE("projection inv(fwd(.)) == . and fwd(inv(.)) == .") { +CASE("Mercator: projection inv(fwd(.)) == . and fwd(inv(.)) == .") { for (const auto& projection : { projection::Mercator({0., 14.}, {262.036, 14.7365}), projection::Mercator({-180., 0.}, {0., 0.}), @@ -40,21 +40,21 @@ CASE("projection inv(fwd(.)) == . and fwd(inv(.)) == .") { } -CASE("spec_str, proj_str") { +CASE("Mercator: spec_str, proj_str") { projection::Mercator proj1({0., 14.}, {262.036, 14.7365}); EXPECT(proj1.proj_str() == "+lat_ts=14 +proj=merc +r=6371229"); - EXPECT(proj1.spec_str() == R"({"lat_ts":14,"proj":"merc","r":6.37123e+06})"); + EXPECT(proj1.spec_str() == R"({"lat_ts":14,"projection":"mercator","r":6371229})"); projection::Mercator proj2({-180., 0.}, {0., 0.}); EXPECT(proj2.proj_str() == "+lon_0=-180 +proj=merc +r=6371229"); - EXPECT(proj2.spec_str() == R"({"lon_0":-180,"proj":"merc","r":6.37123e+06})"); + EXPECT(proj2.spec_str() == R"({"lon_0":-180,"projection":"mercator","r":6371229})"); projection::Mercator proj3({0., 14.}, {0., 0.}); EXPECT(proj3.proj_str() == "+lat_ts=14 +proj=merc +r=6371229"); - EXPECT(proj3.spec_str() == R"({"lat_ts":14,"proj":"merc","r":6.37123e+06})"); + EXPECT(proj3.spec_str() == R"({"lat_ts":14,"projection":"mercator","r":6371229})"); } From 0c007e06c6fff6e62c455ae3dfb7f78381ac05ef Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 17 Jun 2024 17:02:40 +0100 Subject: [PATCH 710/737] eckit::geo::Projection --- src/eckit/geo/Figure.cc | 1 - tests/geo/figure.cc | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc index f2f4fbd08..3909045ca 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/geo/Figure.cc @@ -79,7 +79,6 @@ double Figure::flattening() const { void Figure::fill_spec(spec::Custom& custom) const { static const std::map, std::string> KNOWN{ - {std::shared_ptr
{new figure::Earth}, "earth"}, {std::shared_ptr
{new figure::GRS80}, "grs80"}, {std::shared_ptr
{new figure::WGS84}, "wgs84"}, }; diff --git a/tests/geo/figure.cc b/tests/geo/figure.cc index 4d4786015..a89eabb43 100644 --- a/tests/geo/figure.cc +++ b/tests/geo/figure.cc @@ -67,7 +67,7 @@ CASE("Earth") { F f2(new figure::Earth); EXPECT(*f1 == *f2); - EXPECT(f1->spec_str() == R"({"figure":"earth"})"); + EXPECT(f1->spec_str() == R"({"r":6371229})"); EXPECT(types::is_approximately_equal(f1->R(), 6371229., 1e-8)); F f4(FigureFactory::build(spec::Custom{{"figure", "wgs84"}})); From 85d1723d1dd402984ca5aca94c59db78f02f9d37 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 17 Jun 2024 17:03:22 +0100 Subject: [PATCH 711/737] eckit::geo::Projection --- src/eckit/geo/spec/Custom.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/eckit/geo/spec/Custom.cc b/src/eckit/geo/spec/Custom.cc index 59bdf1e56..be6ea6f3e 100644 --- a/src/eckit/geo/spec/Custom.cc +++ b/src/eckit/geo/spec/Custom.cc @@ -13,7 +13,6 @@ #include #include -#include #include #include @@ -30,6 +29,9 @@ namespace eckit::geo::spec { namespace { +constexpr int STREAM_PRECISION = 15; + + template bool get_t_s(const From& from, To& to) { to = static_cast(from); @@ -462,6 +464,7 @@ bool Custom::get(const std::string& name, std::vector& value) const void Custom::json(JSON& j) const { j.startObject(); + j.precision(STREAM_PRECISION); for (const auto& [key, value] : map_) { j << key; std::visit([&](const auto& arg) { j << arg; }, value); @@ -499,7 +502,8 @@ std::string to_string(const Custom::value_type& value) { return std::visit( [&](const auto& arg) { std::ostringstream str; - str << std::setprecision(15) << arg; + str.precision(STREAM_PRECISION); + str << arg; return str.str(); }, value); From 8a7b43777576143169fade4fabb0c24a12cd3178 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Mon, 17 Jun 2024 17:09:53 +0100 Subject: [PATCH 712/737] eckit::geo::Spec --- src/eckit/geo/Figure.h | 5 ++++ src/eckit/geo/Projection.cc | 12 ++++++-- src/eckit/geo/projection/PROJ.cc | 28 ++++++++++++++++++- src/eckit/geo/projection/PROJ.h | 4 +++ .../geo/projection/ProjectionOnFigure.cc | 20 +------------ src/eckit/geo/projection/ProjectionOnFigure.h | 1 - 6 files changed, 47 insertions(+), 23 deletions(-) diff --git a/src/eckit/geo/Figure.h b/src/eckit/geo/Figure.h index c955d69aa..3e3f5065c 100644 --- a/src/eckit/geo/Figure.h +++ b/src/eckit/geo/Figure.h @@ -23,6 +23,9 @@ namespace eckit::geo { namespace area { class BoundingBox; } +namespace projection { +class ProjectionOnFigure; +} namespace spec { class Custom; } @@ -84,6 +87,8 @@ class Figure { friend bool operator==(const Figure& a, const Figure& b) { return a.spec_str() == b.spec_str(); } friend bool operator!=(const Figure& a, const Figure& b) { return !(a == b); } + + friend class projection::ProjectionOnFigure; }; diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index d4b9aa742..fe4843c1b 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -17,8 +17,13 @@ #include "eckit/exception/Exceptions.h" #include "eckit/geo/Figure.h" #include "eckit/geo/LibEcKitGeo.h" +#include "eckit/geo/eckit_geo_config.h" #include "eckit/geo/spec/Custom.h" +#if eckit_HAVE_PROJ +#include "eckit/geo/projection/PROJ.h" +#endif + namespace eckit::geo { @@ -80,8 +85,11 @@ void Projection::fill_spec(spec::Custom&) const { } -void Projection::fill_proj(std::string&) const { - NOTIMP; +void Projection::fill_proj(std::string& str) const { +#if eckit_HAVE_PROJ + std::unique_ptr custom(spec()); + projection::PROJ::fill_proj(str, *custom); +#endif } diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index edacaa2f1..abbf56dcc 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -14,6 +14,8 @@ #include +#include + #include "eckit/exception/Exceptions.h" #include "eckit/geo/Figure.h" #include "eckit/geo/spec/Custom.h" @@ -29,7 +31,7 @@ namespace { constexpr auto CTX = PJ_DEFAULT_CTX; -static const std::string DEFAULT = "EPSG:4326"; +static const std::string DEFAULT = "EPSG:4326"; // wgs84, latitude/longitude coordinate system struct pj_t : std::unique_ptr { @@ -178,6 +180,30 @@ Point PROJ::inv(const Point& q) const { } +void PROJ::fill_proj(std::string& str, const spec::Custom& custom) { + struct rename_type : std::map { + using map::map; + const std::string& operator()(const std::string& key) const { + const auto it = find(key); + return it != end() ? it->second : key; + } + }; + + static const rename_type RENAME_KEYS{ + {"figure", "ellps"}, + {"projection", "proj"}, + }; + + static const rename_type RENAME_VALUES{ + {"mercator", "merc"}, + }; + + for (const auto& [key, value] : custom.container()) { + str += " +" + RENAME_KEYS(key) + "=" + RENAME_VALUES(to_string(value)); + } +} + + void PROJ::fill_spec(spec::Custom& custom) const { custom.set("projection", "proj"); if (source_ != DEFAULT) { diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index 4fa0b0277..a3ff4b665 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -40,6 +40,10 @@ class PROJ : public Projection { [[nodiscard]] Figure* make_figure() const override; + // -- Class methods + + static void fill_proj(std::string&, const spec::Custom&); + private: // -- Types diff --git a/src/eckit/geo/projection/ProjectionOnFigure.cc b/src/eckit/geo/projection/ProjectionOnFigure.cc index 05f56f663..49e1953b6 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.cc +++ b/src/eckit/geo/projection/ProjectionOnFigure.cc @@ -12,13 +12,9 @@ #include "eckit/geo/projection/ProjectionOnFigure.h" -#include -#include - #include "eckit/exception/Exceptions.h" #include "eckit/geo/figure/Earth.h" #include "eckit/geo/spec/Custom.h" -#include "eckit/types/FloatCompare.h" namespace eckit::geo::projection { @@ -39,21 +35,7 @@ Figure* ProjectionOnFigure::make_figure() const { void ProjectionOnFigure::fill_spec(spec::Custom& custom) const { - // FIXME OO figure - if (types::is_approximately_equal(figure_->a(), figure_->b())) { - custom.set("R", figure_->R()); - return; - } - custom.set("a", figure_->a()); - custom.set("b", figure_->b()); -} - - -void ProjectionOnFigure::fill_proj(std::string& str) const { - std::unique_ptr spec(this->spec()); - for (const auto& [key, value] : spec->container()) { - str += " +" + key + "=" + to_string(value); - } + figure_->fill_spec(custom); } diff --git a/src/eckit/geo/projection/ProjectionOnFigure.h b/src/eckit/geo/projection/ProjectionOnFigure.h index 964e40bd2..2f2d92a0d 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.h +++ b/src/eckit/geo/projection/ProjectionOnFigure.h @@ -27,7 +27,6 @@ class ProjectionOnFigure : public Projection { [[nodiscard]] Figure* make_figure() const override; void fill_spec(spec::Custom&) const override; - void fill_proj(std::string&) const override; protected: // -- Constructors From 15b5318cf100e359f7ed65215b88e04619407d5f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 20 Jun 2024 16:38:34 +0100 Subject: [PATCH 713/737] eckit::geo::Spec --- src/eckit/geo/projection/PROJ.cc | 12 +++++++++--- tests/geo/projection_mercator.cc | 6 +++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index abbf56dcc..1006f3ae3 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -190,16 +190,22 @@ void PROJ::fill_proj(std::string& str, const spec::Custom& custom) { }; static const rename_type RENAME_KEYS{ - {"figure", "ellps"}, {"projection", "proj"}, + {"figure", "ellps"}, + {"r", "R"}, }; static const rename_type RENAME_VALUES{ {"mercator", "merc"}, + {"grs80", "GRS80"}, + {"wgs84", "WGS84"}, }; - for (const auto& [key, value] : custom.container()) { - str += " +" + RENAME_KEYS(key) + "=" + RENAME_VALUES(to_string(value)); + for (const auto& [k, v] : custom.container()) { + if (const auto& key = RENAME_KEYS(k); !key.empty()) { + const auto value = RENAME_VALUES(to_string(v)); + str += " +" + key + "=" + value; + } } } diff --git a/tests/geo/projection_mercator.cc b/tests/geo/projection_mercator.cc index 11e8cc97f..50958a94b 100644 --- a/tests/geo/projection_mercator.cc +++ b/tests/geo/projection_mercator.cc @@ -43,17 +43,17 @@ CASE("Mercator: projection inv(fwd(.)) == . and fwd(inv(.)) == .") { CASE("Mercator: spec_str, proj_str") { projection::Mercator proj1({0., 14.}, {262.036, 14.7365}); - EXPECT(proj1.proj_str() == "+lat_ts=14 +proj=merc +r=6371229"); + EXPECT(proj1.proj_str() == "+lat_ts=14 +proj=merc +R=6371229"); EXPECT(proj1.spec_str() == R"({"lat_ts":14,"projection":"mercator","r":6371229})"); projection::Mercator proj2({-180., 0.}, {0., 0.}); - EXPECT(proj2.proj_str() == "+lon_0=-180 +proj=merc +r=6371229"); + EXPECT(proj2.proj_str() == "+lon_0=-180 +proj=merc +R=6371229"); EXPECT(proj2.spec_str() == R"({"lon_0":-180,"projection":"mercator","r":6371229})"); projection::Mercator proj3({0., 14.}, {0., 0.}); - EXPECT(proj3.proj_str() == "+lat_ts=14 +proj=merc +r=6371229"); + EXPECT(proj3.proj_str() == "+lat_ts=14 +proj=merc +R=6371229"); EXPECT(proj3.spec_str() == R"({"lat_ts":14,"projection":"mercator","r":6371229})"); } From 46d65fcfd3ac24d15ac047ec172bc7dde35050ec Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Thu, 20 Jun 2024 16:41:02 +0100 Subject: [PATCH 714/737] eckit::geo::Spec --- src/eckit/geo/projection/PROJ.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 1006f3ae3..23037c496 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -31,7 +31,7 @@ namespace { constexpr auto CTX = PJ_DEFAULT_CTX; -static const std::string DEFAULT = "EPSG:4326"; // wgs84, latitude/longitude coordinate system +static const std::string DEFAULT = "EPSG:4326"; // WGS84, latitude/longitude coordinate system struct pj_t : std::unique_ptr { @@ -149,8 +149,8 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini PROJ::PROJ(const Spec& spec) : - PROJ(spec.get_string("source", spec.get_string("proj", DEFAULT)), // default to WGS 84 - spec.get_string("target", DEFAULT), // ... + PROJ(spec.get_string("source", spec.get_string("proj", DEFAULT)), + spec.get_string("target", DEFAULT), spec.get_double("lon_minimum", 0)) {} From 1d8d08451a313826c59a4f37da02dc222155628a Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 21 Jun 2024 09:47:25 +0100 Subject: [PATCH 715/737] eckit::geo::Spec canonical proj string --- src/eckit/geo/Projection.cc | 22 ++++-------- src/eckit/geo/Projection.h | 1 - src/eckit/geo/projection/PROJ.cc | 60 ++++++++++++++++++++++++-------- src/eckit/geo/projection/PROJ.h | 2 +- tests/geo/projection_mercator.cc | 6 ++-- 5 files changed, 56 insertions(+), 35 deletions(-) diff --git a/src/eckit/geo/Projection.cc b/src/eckit/geo/Projection.cc index fe4843c1b..5b69d1e11 100644 --- a/src/eckit/geo/Projection.cc +++ b/src/eckit/geo/Projection.cc @@ -64,14 +64,12 @@ std::string Projection::spec_str() const { std::string Projection::proj_str() const { - std::string str; - fill_proj(str); - - if (!str.empty() && str.front() == ' ') { - str.erase(0, 1); - } - - return str; +#if eckit_HAVE_PROJ + std::unique_ptr custom(spec()); + return projection::PROJ::proj_str(*custom); +#else + NOTIMP; +#endif } @@ -85,12 +83,4 @@ void Projection::fill_spec(spec::Custom&) const { } -void Projection::fill_proj(std::string& str) const { -#if eckit_HAVE_PROJ - std::unique_ptr custom(spec()); - projection::PROJ::fill_proj(str, *custom); -#endif -} - - } // namespace eckit::geo diff --git a/src/eckit/geo/Projection.h b/src/eckit/geo/Projection.h index 6f3443063..e29a0da8d 100644 --- a/src/eckit/geo/Projection.h +++ b/src/eckit/geo/Projection.h @@ -86,7 +86,6 @@ class Projection { // -- Methods virtual void fill_spec(spec::Custom&) const; - virtual void fill_proj(std::string&) const; // -- Friends diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 23037c496..1fa45f136 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -15,6 +15,8 @@ #include #include +#include +#include #include "eckit/exception/Exceptions.h" #include "eckit/geo/Figure.h" @@ -149,8 +151,7 @@ PROJ::PROJ(const std::string& source, const std::string& target, double lon_mini PROJ::PROJ(const Spec& spec) : - PROJ(spec.get_string("source", spec.get_string("proj", DEFAULT)), - spec.get_string("target", DEFAULT), + PROJ(spec.get_string("source", spec.get_string("proj", DEFAULT)), spec.get_string("target", DEFAULT), spec.get_double("lon_minimum", 0)) {} @@ -180,33 +181,64 @@ Point PROJ::inv(const Point& q) const { } -void PROJ::fill_proj(std::string& str, const spec::Custom& custom) { - struct rename_type : std::map { - using map::map; - const std::string& operator()(const std::string& key) const { - const auto it = find(key); - return it != end() ? it->second : key; - } +std::string PROJ::proj_str(const spec::Custom& custom) { + using key_value_type = std::pair; + + struct key_value_compare { + bool operator()(const key_value_type& a, const key_value_type& b) const { + if (a.first != b.first) { + // keys that come first in string + for (const std::string& key : {"proj"}) { + if (a.first == key || b.first == key) { + return a.first == key; + } + } + + // keys that come last in string + for (const std::string& key : {"R", "a", "b"}) { + if (a.first == key || b.first == key) { + return b.first == key; + } + } + } + + return a < b; + }; }; - static const rename_type RENAME_KEYS{ + static const std::map KEYS{ {"projection", "proj"}, {"figure", "ellps"}, {"r", "R"}, }; - static const rename_type RENAME_VALUES{ + static const std::map VALUES{ {"mercator", "merc"}, {"grs80", "GRS80"}, {"wgs84", "WGS84"}, }; + auto rename = [](const std::map& map, const std::string& key) { + const auto it = map.find(key); + return it != map.end() ? it->second : key; + }; + + std::set set; for (const auto& [k, v] : custom.container()) { - if (const auto& key = RENAME_KEYS(k); !key.empty()) { - const auto value = RENAME_VALUES(to_string(v)); - str += " +" + key + "=" + value; + if (const auto& key = rename(KEYS, k); !key.empty()) { + const auto& value = rename(VALUES, to_string(v)); + set.emplace(key, value); } } + + std::string str; + const auto* sep = "+"; + for (const auto& [key, value] : set) { + str += sep + key + "=" + value; + sep = " +"; + } + + return str; } diff --git a/src/eckit/geo/projection/PROJ.h b/src/eckit/geo/projection/PROJ.h index a3ff4b665..1cb1d9353 100644 --- a/src/eckit/geo/projection/PROJ.h +++ b/src/eckit/geo/projection/PROJ.h @@ -42,7 +42,7 @@ class PROJ : public Projection { // -- Class methods - static void fill_proj(std::string&, const spec::Custom&); + static std::string proj_str(const spec::Custom&); private: // -- Types diff --git a/tests/geo/projection_mercator.cc b/tests/geo/projection_mercator.cc index 50958a94b..ecf893edf 100644 --- a/tests/geo/projection_mercator.cc +++ b/tests/geo/projection_mercator.cc @@ -43,17 +43,17 @@ CASE("Mercator: projection inv(fwd(.)) == . and fwd(inv(.)) == .") { CASE("Mercator: spec_str, proj_str") { projection::Mercator proj1({0., 14.}, {262.036, 14.7365}); - EXPECT(proj1.proj_str() == "+lat_ts=14 +proj=merc +R=6371229"); + EXPECT(proj1.proj_str() == "+proj=merc +lat_ts=14 +R=6371229"); EXPECT(proj1.spec_str() == R"({"lat_ts":14,"projection":"mercator","r":6371229})"); projection::Mercator proj2({-180., 0.}, {0., 0.}); - EXPECT(proj2.proj_str() == "+lon_0=-180 +proj=merc +R=6371229"); + EXPECT(proj2.proj_str() == "+proj=merc +lon_0=-180 +R=6371229"); EXPECT(proj2.spec_str() == R"({"lon_0":-180,"projection":"mercator","r":6371229})"); projection::Mercator proj3({0., 14.}, {0., 0.}); - EXPECT(proj3.proj_str() == "+lat_ts=14 +proj=merc +R=6371229"); + EXPECT(proj3.proj_str() == "+proj=merc +lat_ts=14 +R=6371229"); EXPECT(proj3.spec_str() == R"({"lat_ts":14,"projection":"mercator","r":6371229})"); } From b1316f488d1a4417e8cb6183096f22f43d6a407f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 21 Jun 2024 09:37:08 +0100 Subject: [PATCH 716/737] eckit::geo::Spec reverse projection (for eccodes) --- src/eckit/geo/projection/Reverse.h | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/eckit/geo/projection/Reverse.h b/src/eckit/geo/projection/Reverse.h index 350320a6e..cc71eca96 100644 --- a/src/eckit/geo/projection/Reverse.h +++ b/src/eckit/geo/projection/Reverse.h @@ -12,15 +12,18 @@ #pragma once -#include "eckit/geo/Projection.h" -#include "eckit/geo/spec/Custom.h" +#include "eckit/geo/Point.h" namespace eckit::geo::projection { +/** + * @brief Reverse class + * @details Used to reverse the forward and inverse methods of a projection. + */ template -class Reverse : protected P /* hide interface incosistentwith reversing inv/fwd */ { +class Reverse : protected P { public: // -- Constructors @@ -38,14 +41,6 @@ class Reverse : protected P /* hide interface incosistentwith reversing inv/fwd inline Point fwd(const Point& p) const override { return P::inv(p); } inline Point inv(const Point& p) const override { return P::fwd(p); } - -private: - // -- Overridden methods - - void fill_spec(spec::Custom& custom) const override { - P::fill_spec(custom); - custom.set("projection", "reverse_" + custom.get_string("projection")); - } }; } // namespace eckit::geo::projection From cc205748c5eb387de6c64e3ac087c6539e6b780c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 21 Jun 2024 09:50:31 +0100 Subject: [PATCH 717/737] eckit::geo::Spec --- tests/geo/projection.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/geo/projection.cc b/tests/geo/projection.cc index 4797d21a5..47add37be 100644 --- a/tests/geo/projection.cc +++ b/tests/geo/projection.cc @@ -16,6 +16,7 @@ #include "eckit/geo/figure/UnitSphere.h" #include "eckit/geo/projection/LonLatToXYZ.h" // to test Reverse #include "eckit/geo/projection/Reverse.h" +#include "eckit/geo/spec/Custom.h" #include "eckit/testing/Test.h" From 7dd5484b2d1afd0dada5b4e2e66761b66f309c94 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 21 Jun 2024 12:44:48 +0100 Subject: [PATCH 718/737] eckit::geo::Spec --- src/eckit/geo/projection/ProjectionOnFigure.h | 2 +- tests/geo/projection_mercator.cc | 60 ++++++++++--------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/eckit/geo/projection/ProjectionOnFigure.h b/src/eckit/geo/projection/ProjectionOnFigure.h index 2f2d92a0d..348cd4f14 100644 --- a/src/eckit/geo/projection/ProjectionOnFigure.h +++ b/src/eckit/geo/projection/ProjectionOnFigure.h @@ -37,7 +37,7 @@ class ProjectionOnFigure : public Projection { private: // -- Members - const std::unique_ptr
figure_; + std::shared_ptr
figure_; }; diff --git a/tests/geo/projection_mercator.cc b/tests/geo/projection_mercator.cc index ecf893edf..e3a9ad347 100644 --- a/tests/geo/projection_mercator.cc +++ b/tests/geo/projection_mercator.cc @@ -12,6 +12,7 @@ #include +#include "eckit/geo/eckit_geo_config.h" #include "eckit/geo/projection/Mercator.h" #include "eckit/testing/Test.h" @@ -19,42 +20,47 @@ namespace eckit::geo::test { -CASE("Mercator: projection inv(fwd(.)) == . and fwd(inv(.)) == .") { - for (const auto& projection : { - projection::Mercator({0., 14.}, {262.036, 14.7365}), - projection::Mercator({-180., 0.}, {0., 0.}), - projection::Mercator({0., 14.}, {0., 0.}), - }) { - Point2 a{0., 0.}; - EXPECT(points_equal(a, projection.fwd(projection.inv(a)))); - - PointLonLat b{-75., 35.}; - EXPECT(points_equal(b, projection.inv(projection.fwd(b)))); +CASE("Mercator: spec_str, proj_str") { + projection::Mercator proj1({0., 14.}, {262.036, 14.7365}); + projection::Mercator proj2({0., 14.}, {0., 0.}); + projection::Mercator proj3({-180., 0.}, {0., 0.}); - Point2 c = projection.fwd(NORTH_POLE); - EXPECT(c.Y > std::numeric_limits::max()); - Point2 d = projection.fwd(SOUTH_POLE); - EXPECT(d.Y < std::numeric_limits::lowest()); - } -} + SECTION("inv(fwd(.)) == . and fwd(inv(.)) == .") { + for (const auto& projection : { + proj1, + proj2, + proj3, + }) { + Point2 a{0., 0.}; + EXPECT(points_equal(a, projection.fwd(projection.inv(a)))); + PointLonLat b{-75., 35.}; + EXPECT(points_equal(b, projection.inv(projection.fwd(b)))); -CASE("Mercator: spec_str, proj_str") { - projection::Mercator proj1({0., 14.}, {262.036, 14.7365}); + Point2 c = projection.fwd(NORTH_POLE); + EXPECT(c.Y > std::numeric_limits::max()); - EXPECT(proj1.proj_str() == "+proj=merc +lat_ts=14 +R=6371229"); - EXPECT(proj1.spec_str() == R"({"lat_ts":14,"projection":"mercator","r":6371229})"); + Point2 d = projection.fwd(SOUTH_POLE); + EXPECT(d.Y < std::numeric_limits::lowest()); + } + } - projection::Mercator proj2({-180., 0.}, {0., 0.}); - EXPECT(proj2.proj_str() == "+proj=merc +lon_0=-180 +R=6371229"); - EXPECT(proj2.spec_str() == R"({"lon_0":-180,"projection":"mercator","r":6371229})"); + SECTION("spec_str") { + EXPECT(proj1.spec_str() == R"({"lat_ts":14,"projection":"mercator","r":6371229})"); + EXPECT(proj2.spec_str() == R"({"lat_ts":14,"projection":"mercator","r":6371229})"); + EXPECT(proj3.spec_str() == R"({"lon_0":-180,"projection":"mercator","r":6371229})"); + } - projection::Mercator proj3({0., 14.}, {0., 0.}); - EXPECT(proj3.proj_str() == "+proj=merc +lat_ts=14 +R=6371229"); - EXPECT(proj3.spec_str() == R"({"lat_ts":14,"projection":"mercator","r":6371229})"); +#if eckit_HAVE_PROJ + SECTION("proj_str") { + EXPECT(proj1.proj_str() == "+proj=merc +lat_ts=14 +R=6371229"); + EXPECT(proj2.proj_str() == "+proj=merc +lat_ts=14 +R=6371229"); + EXPECT(proj3.proj_str() == "+proj=merc +lon_0=-180 +R=6371229"); + } +#endif } From dc1e9d995aac3f3b5098cb32778746f0cdb925a0 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 21 Jun 2024 12:45:12 +0100 Subject: [PATCH 719/737] eckit::geo::Spec reverse projection (for eccodes) (partially reverts commit b1316f488d1a4417e8cb6183096f22f43d6a407f. --- src/eckit/geo/projection/PROJ.cc | 1 + src/eckit/geo/projection/Reverse.h | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/projection/PROJ.cc b/src/eckit/geo/projection/PROJ.cc index 1fa45f136..c0aa7b482 100644 --- a/src/eckit/geo/projection/PROJ.cc +++ b/src/eckit/geo/projection/PROJ.cc @@ -214,6 +214,7 @@ std::string PROJ::proj_str(const spec::Custom& custom) { static const std::map VALUES{ {"mercator", "merc"}, + {"reverse_mercator", "merc"}, {"grs80", "GRS80"}, {"wgs84", "WGS84"}, }; diff --git a/src/eckit/geo/projection/Reverse.h b/src/eckit/geo/projection/Reverse.h index cc71eca96..96231ad4c 100644 --- a/src/eckit/geo/projection/Reverse.h +++ b/src/eckit/geo/projection/Reverse.h @@ -12,7 +12,8 @@ #pragma once -#include "eckit/geo/Point.h" +#include "eckit/geo/Projection.h" +#include "eckit/geo/spec/Custom.h" namespace eckit::geo::projection { @@ -41,6 +42,14 @@ class Reverse : protected P { inline Point fwd(const Point& p) const override { return P::inv(p); } inline Point inv(const Point& p) const override { return P::fwd(p); } + +private: + // -- Overridden methods + + void fill_spec(spec::Custom& custom) const override { + P::fill_spec(custom); + custom.set("projection", "reverse_" + custom.get_string("projection")); + } }; } // namespace eckit::geo::projection From 4286ffe80ce8d625b638acf35a77d5b59f31a151 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 21 Jun 2024 12:52:11 +0100 Subject: [PATCH 720/737] eckit::geo Documentation --- src/eckit/geo/Point2.h | 4 ++++ src/eckit/geo/Point3.h | 4 ++++ src/eckit/geo/PointLonLat.h | 4 ++++ src/eckit/geo/PointLonLatR.h | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/src/eckit/geo/Point2.h b/src/eckit/geo/Point2.h index 466443749..6f3f55b28 100644 --- a/src/eckit/geo/Point2.h +++ b/src/eckit/geo/Point2.h @@ -18,6 +18,10 @@ namespace eckit::geo { +/** + * @brief The Point2 class + * @details A point on two-dimensional space, in (X, Y) coordinates. + */ class Point2 final : protected std::array { public: // -- Types diff --git a/src/eckit/geo/Point3.h b/src/eckit/geo/Point3.h index 523c8df91..a41bbb459 100644 --- a/src/eckit/geo/Point3.h +++ b/src/eckit/geo/Point3.h @@ -18,6 +18,10 @@ namespace eckit::geo { +/** + * @brief The Point3 class + * @details A point on three-dimensional space, in (X, Y, Z) coordinates. + */ class Point3 final : protected std::array { public: // -- Types diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index 650789ad8..db05079a1 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -24,6 +24,10 @@ class PointLonLatR; namespace eckit::geo { +/** + * @brief The PointLonLat class + * @details A point on a geographic coordinate system, in (longitude, latitude) coordinates [degree]. + */ class PointLonLat final : protected std::array { public: // -- Types diff --git a/src/eckit/geo/PointLonLatR.h b/src/eckit/geo/PointLonLatR.h index 623161fc7..32d64bd4f 100644 --- a/src/eckit/geo/PointLonLatR.h +++ b/src/eckit/geo/PointLonLatR.h @@ -25,6 +25,10 @@ class PointLonLat; namespace eckit::geo { +/** + * @brief The PointLonLatR class + * @details A point on a geographic coordinate system, in (longitude, latitude) coordinates [radian]. + */ class PointLonLatR final : protected std::array { public: // -- Types From a11ed08f4b24fd0a49cffe822a36456bab7b2252 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 21 Jun 2024 16:20:18 +0100 Subject: [PATCH 721/737] eckit::geo Documentation --- src/eckit/geo/Point2.h | 2 +- src/eckit/geo/Point3.h | 2 +- src/eckit/geo/PointLonLat.h | 4 +++- src/eckit/geo/PointLonLatR.h | 4 +++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/eckit/geo/Point2.h b/src/eckit/geo/Point2.h index 6f3f55b28..b0f9651c0 100644 --- a/src/eckit/geo/Point2.h +++ b/src/eckit/geo/Point2.h @@ -20,7 +20,7 @@ namespace eckit::geo { /** * @brief The Point2 class - * @details A point on two-dimensional space, in (X, Y) coordinates. + * @details A point on two-dimensional space, in (X, Y) coordinates, linear in space. */ class Point2 final : protected std::array { public: diff --git a/src/eckit/geo/Point3.h b/src/eckit/geo/Point3.h index a41bbb459..efdad55b5 100644 --- a/src/eckit/geo/Point3.h +++ b/src/eckit/geo/Point3.h @@ -20,7 +20,7 @@ namespace eckit::geo { /** * @brief The Point3 class - * @details A point on three-dimensional space, in (X, Y, Z) coordinates. + * @details A point on three-dimensional space, in (X, Y, Z) coordinates, linear in space. */ class Point3 final : protected std::array { public: diff --git a/src/eckit/geo/PointLonLat.h b/src/eckit/geo/PointLonLat.h index db05079a1..aa5dc7b54 100644 --- a/src/eckit/geo/PointLonLat.h +++ b/src/eckit/geo/PointLonLat.h @@ -26,7 +26,9 @@ namespace eckit::geo { /** * @brief The PointLonLat class - * @details A point on a geographic coordinate system, in (longitude, latitude) coordinates [degree]. + * @details A point on a geographic coordinate system, in (longitude, latitude) coordinates [degree]; They are fully + * circular in space (also latitude), longitude is typically limited to [0, 360[ and latitude to [-90, 90], with + * normalisation functions available, as well as conversion to and from radian-based coordinates. */ class PointLonLat final : protected std::array { public: diff --git a/src/eckit/geo/PointLonLatR.h b/src/eckit/geo/PointLonLatR.h index 32d64bd4f..c44c99bc8 100644 --- a/src/eckit/geo/PointLonLatR.h +++ b/src/eckit/geo/PointLonLatR.h @@ -27,7 +27,9 @@ namespace eckit::geo { /** * @brief The PointLonLatR class - * @details A point on a geographic coordinate system, in (longitude, latitude) coordinates [radian]. + * @details A point on a geographic coordinate system, in (longitude, latitude) coordinates [radian]. They are fully + * circular in space (also latitude), longitude is typically limited to [0, 2 pi[ and latitude to [-pi, pi], with + * normalisation functions available, as well as conversion to and from degree-based coordinates. */ class PointLonLatR final : protected std::array { public: From 5d9a0106ff4e695493265412e938dc13e34b07f5 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 23 Jun 2024 00:32:16 +0100 Subject: [PATCH 722/737] eckit::geo::Spec --- src/eckit/geo/grid/Regular.cc | 2 -- src/eckit/geo/grid/RegularXY.cc | 1 + tests/geo/CMakeLists.txt | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index b236e5e39..640a8ab57 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -62,8 +62,6 @@ Regular::Regular(std::pair xy, const area::BoundingBox& bbox) : void Regular::fill_spec(spec::Custom& custom) const { Grid::fill_spec(custom); - - custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); } diff --git a/src/eckit/geo/grid/RegularXY.cc b/src/eckit/geo/grid/RegularXY.cc index edd1658d8..038c95731 100644 --- a/src/eckit/geo/grid/RegularXY.cc +++ b/src/eckit/geo/grid/RegularXY.cc @@ -54,6 +54,7 @@ void RegularXY::fill_spec(spec::Custom& custom) const { Regular::fill_spec(custom); custom.set("grid", std::vector{dx(), dy()}); + custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); custom.set("first_lonlat", std::vector{first_lonlat.lon, first_lonlat.lat}); } diff --git a/tests/geo/CMakeLists.txt b/tests/geo/CMakeLists.txt index 30f23dd8d..f183b58fa 100644 --- a/tests/geo/CMakeLists.txt +++ b/tests/geo/CMakeLists.txt @@ -70,7 +70,7 @@ ecbuild_add_test( set_tests_properties( eckit_test_geo_tool_grid_spec_1_1 PROPERTIES - PASS_REGULAR_EXPRESSION [=[{"grid":\[1,1\],"shape":\[360,181\]}]=] ) + PASS_REGULAR_EXPRESSION [=[{"grid":\[1,1\]}]=] ) ecbuild_add_test( TARGET eckit_test_geo_tool_grid_spec_025_01 @@ -79,5 +79,5 @@ ecbuild_add_test( set_tests_properties( eckit_test_geo_tool_grid_spec_025_01 PROPERTIES - PASS_REGULAR_EXPRESSION [=[{"grid":\[0\.25,0\.1\],"shape":\[1440,1801\]}]=] ) + PASS_REGULAR_EXPRESSION [=[{"grid":\[0\.25,0\.1\]}]=] ) From 5ceceff40b495cff28b1dee9135f370d3d141c7c Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sun, 23 Jun 2024 00:33:14 +0100 Subject: [PATCH 723/737] eckit::geo::Grid --- src/eckit/geo/grid/HEALPix.cc | 3 +++ src/eckit/geo/grid/ReducedGaussian.cc | 4 ++++ src/eckit/geo/grid/RegularGaussian.cc | 2 ++ 3 files changed, 9 insertions(+) diff --git a/src/eckit/geo/grid/HEALPix.cc b/src/eckit/geo/grid/HEALPix.cc index 25c5352ca..642f08a7e 100644 --- a/src/eckit/geo/grid/HEALPix.cc +++ b/src/eckit/geo/grid/HEALPix.cc @@ -18,6 +18,7 @@ #include #include +#include "eckit/exception/Exceptions.h" #include "eckit/geo/iterator/Reduced.h" #include "eckit/geo/iterator/Unstructured.h" #include "eckit/geo/spec/Custom.h" @@ -277,6 +278,8 @@ size_t HEALPix::nj() const { Spec* HEALPix::spec(const std::string& name) { + ASSERT(name.size() > 1 && (name[0] == 'h' || name[0] == 'H')); + auto Nside = Translator{}(name.substr(1)); return new spec::Custom({{"type", "HEALPix"}, {"Nside", Nside}, {"ordering", "ring"}}); } diff --git a/src/eckit/geo/grid/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc index c72ce12fd..bba515b0a 100644 --- a/src/eckit/geo/grid/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -134,6 +134,8 @@ Grid* ReducedGaussian::make_grid_cropped(const Area& crop) const { struct ReducedGaussianClassical { static Spec* spec(const std::string& name) { + ASSERT(name.size() > 1 && (name[0] == 'n' || name[0] == 'N')); + auto N = Translator{}(name.substr(1)); return new spec::Custom({{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_classical_pl(N)}}); } @@ -142,6 +144,8 @@ struct ReducedGaussianClassical { struct ReducedGaussianOctahedral { static Spec* spec(const std::string& name) { + ASSERT(name.size() > 1 && (name[0] == 'o' || name[0] == 'O')); + auto N = Translator{}(name.substr(1)); return new spec::Custom({{"type", "reduced_gg"}, {"N", N}, {"pl", util::reduced_octahedral_pl(N)}}); } diff --git a/src/eckit/geo/grid/RegularGaussian.cc b/src/eckit/geo/grid/RegularGaussian.cc index 77502f1d7..908c0ecef 100644 --- a/src/eckit/geo/grid/RegularGaussian.cc +++ b/src/eckit/geo/grid/RegularGaussian.cc @@ -43,6 +43,8 @@ Grid* RegularGaussian::make_grid_cropped(const Area& crop) const { Spec* RegularGaussian::spec(const std::string& name) { + ASSERT(name.size() > 1 && (name[0] == 'f' || name[0] == 'F')); + auto N = Translator{}(name.substr(1)); return new spec::Custom({{"type", "regular_gg"}, {"N", N}}); } From c4e85b10b80eef52809eff48c8d64126ec556372 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 25 Jun 2024 01:46:02 +0100 Subject: [PATCH 724/737] eckit::geo::Grid --- src/eckit/geo/area/BoundingBox.cc | 89 +++++++++++++++++++------------ src/eckit/geo/area/BoundingBox.h | 22 +++++--- tests/geo/area_boundingbox.cc | 14 +++++ 3 files changed, 83 insertions(+), 42 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index d4a24ca7e..f603d1ff1 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -32,6 +32,11 @@ static const BoundingBox GLOBE_ANTIPRIME{90., -180., -90., 180.}; static const BoundingBox& DEFAULT = GLOBE_PRIME; +static inline bool is_approximately_equal(BoundingBox::value_type a, BoundingBox::value_type b) { + return types::is_approximately_equal(a, b, PointLonLat::EPS); +} + + BoundingBox* BoundingBox::make_global_prime() { return new BoundingBox(GLOBE_PRIME); } @@ -51,69 +56,81 @@ void BoundingBox::fill_spec(spec::Custom& custom) const { BoundingBox* BoundingBox::make_from_spec(const Spec& spec) { - const auto [n, w, s, e] = DEFAULT.deconstruct(); + auto [n, w, s, e] = DEFAULT.deconstruct(); if (std::vector area{n, w, s, e}; spec.get("area", area)) { ASSERT_MSG(area.size() == 4, "BoundingBox: 'area' expected list of size 4"); - return new BoundingBox{area[0], area[1], area[2], area[3]}; + return make_from_area(area[0], area[1], area[2], area[3]); } - std::array area{n, w, s, e}; - spec.get("north", area[0]); - spec.get("south", area[2]); + spec.get("north", n); + spec.get("south", s); - auto new_east = spec.get("west", area[1]) && !spec.has("east"); - auto new_west = spec.get("east", area[3]) && !spec.has("west"); - ASSERT(!new_east || !new_west); + if (spec.get("west", w) && !spec.has("east")) { + e = w + PointLonLat::FULL_ANGLE; + } - return new BoundingBox{area[0], new_west ? area[3] - 360. : area[1], area[2], new_east ? area[1] + 360. : area[3]}; -} + if (spec.get("east", e) && !spec.has("west")) { + w = e - PointLonLat::FULL_ANGLE; + } + return make_from_area(n, w, s, e); +} -BoundingBox::BoundingBox(const Spec& spec) : BoundingBox(*std::unique_ptr(make_from_spec(spec))) {} +BoundingBox* BoundingBox::make_from_area(value_type n, value_type w, value_type s, value_type e) { + if (n > NORTH_POLE.lat || is_approximately_equal(n, NORTH_POLE.lat)) { + n = NORTH_POLE.lat; + } -BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s, e} { - ASSERT_MSG(types::is_approximately_lesser_or_equal(-90., south), "BoundingBox: latitude range (-90 <= south)"); - ASSERT_MSG(types::is_approximately_lesser_or_equal(south, north), "BoundingBox: latitude range (south <= north)"); - ASSERT_MSG(types::is_approximately_lesser_or_equal(north, 90.), "BoundingBox: latitude range (north <= 90)"); + if (s < SOUTH_POLE.lat || is_approximately_equal(s, SOUTH_POLE.lat)) { + s = SOUTH_POLE.lat; + } - if (!types::is_approximately_equal(west, east)) { - auto e = PointLonLat::normalise_angle_to_minimum(east, west); - operator[](3) = types::is_approximately_equal(e, west) ? (e + 360.) : e; + if (is_approximately_equal(w, e)) { + w = PointLonLat::normalise_angle_to_minimum(w, 0.); + e = w; + } + else { + w = PointLonLat::normalise_angle_to_minimum(w, 0.); + e = PointLonLat::normalise_angle_to_minimum(e, w); + if (is_approximately_equal(w, e)) { + e = w + PointLonLat::FULL_ANGLE; + } } - ASSERT_MSG(types::is_approximately_lesser_or_equal(west, east), "BoundingBox: longitude range (west <= east)"); - ASSERT_MSG(types::is_approximately_lesser_or_equal(east, west + 360.), - "BoundingBox: longitude range (east <= west + 360)"); + return new BoundingBox{n, w, s, e}; } +BoundingBox::BoundingBox(const Spec& spec) : BoundingBox(*std::unique_ptr(make_from_spec(spec))) {} + + +BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s, e} {} + + BoundingBox::BoundingBox() : BoundingBox(DEFAULT) {} -bool BoundingBox::operator==(const BoundingBox& other) const { - return types::is_approximately_equal(north, other.north, PointLonLat::EPS) - && types::is_approximately_equal(south, other.south, PointLonLat::EPS) - && types::is_approximately_equal(west, other.west, PointLonLat::EPS) - && types::is_approximately_equal(east, other.east, PointLonLat::EPS); +bool BoundingBox::isGlobal() const { + return isPeriodicWestEast() && containsNorthPole() && containsSouthPole(); } bool BoundingBox::isPeriodicWestEast() const { - return west != east - && types::is_approximately_equal(west, PointLonLat::normalise_angle_to_minimum(east, west), - PointLonLat::EPS); + return west != east && is_approximately_equal(west, PointLonLat::normalise_angle_to_minimum(east, west)); } bool BoundingBox::containsNorthPole() const { - return types::is_approximately_equal(north, NORTH_POLE.lat, PointLonLat::EPS); + // NOTE: latitudes < -90 or > 90 are not considered + return is_approximately_equal(north, NORTH_POLE.lat); } bool BoundingBox::containsSouthPole() const { - return types::is_approximately_equal(south, SOUTH_POLE.lat, PointLonLat::EPS); + // NOTE: latitudes < -90 or > 90 are not considered + return is_approximately_equal(south, SOUTH_POLE.lat); } @@ -186,12 +203,16 @@ bool BoundingBox::intersects(BoundingBox& other) const { bool BoundingBox::empty() const { - return types::is_approximately_equal(north, south) || types::is_approximately_equal(west, east); + return is_approximately_equal(north, south) || is_approximately_equal(west, east); } -BoundingBox BoundingBox::calculate(const BoundingBox&, const Projection&) { - NOTIMP; +bool bounding_box_equal(const BoundingBox& a, const BoundingBox& b) { + const std::unique_ptr c(BoundingBox::make_from_area(a.north, a.west, a.south, a.east)); + const std::unique_ptr d(BoundingBox::make_from_area(b.north, b.west, b.south, b.east)); + + return is_approximately_equal(c->north, d->north) && is_approximately_equal(c->south, d->south) + && is_approximately_equal(c->west, d->west) && is_approximately_equal(c->east, d->east); } diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index f1fe7a5de..b5d984e74 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -28,17 +28,23 @@ class Projection; namespace eckit::geo::area { +class BoundingBox; + +bool bounding_box_equal(const BoundingBox&, const BoundingBox&); + + class BoundingBox : public Area, protected std::array { public: // -- Types using container_type = array; + using value_type = container_type::value_type; // -- Constructors explicit BoundingBox(const Spec&); - BoundingBox(double north, double west, double south, double east); + BoundingBox(value_type north, value_type west, value_type south, value_type east); BoundingBox(); @@ -52,7 +58,7 @@ class BoundingBox : public Area, protected std::array { // -- Operators - bool operator==(const BoundingBox&) const; + bool operator==(const BoundingBox& other) const { return bounding_box_equal(*this, other); } bool operator!=(const BoundingBox& other) const { return !operator==(other); } BoundingBox& operator=(const BoundingBox& other) { @@ -69,6 +75,7 @@ class BoundingBox : public Area, protected std::array { container_type deconstruct() const { return {north, west, south, east}; } + bool isGlobal() const; bool isPeriodicWestEast() const; bool containsNorthPole() const; bool containsSouthPole() const; @@ -84,18 +91,17 @@ class BoundingBox : public Area, protected std::array { // -- Class methods - static BoundingBox calculate(const BoundingBox&, const Projection&); - [[nodiscard]] static BoundingBox* make_global_prime(); [[nodiscard]] static BoundingBox* make_global_antiprime(); [[nodiscard]] static BoundingBox* make_from_spec(const Spec&); + [[nodiscard]] static BoundingBox* make_from_area(value_type n, value_type w, value_type s, value_type e); // -- Members - const double& north = operator[](0); - const double& west = operator[](1); - const double& south = operator[](2); - const double& east = operator[](3); + const value_type& north = operator[](0); + const value_type& west = operator[](1); + const value_type& south = operator[](2); + const value_type& east = operator[](3); private: // -- Friends diff --git a/tests/geo/area_boundingbox.cc b/tests/geo/area_boundingbox.cc index 0148c4fb0..bc4fc1728 100644 --- a/tests/geo/area_boundingbox.cc +++ b/tests/geo/area_boundingbox.cc @@ -73,6 +73,20 @@ CASE("assignment") { } +CASE("comparison") { + area::BoundingBox a(10, 1, -10, 100); + area::BoundingBox b(20, 2, -20, 200); + + EXPECT(!area::bounding_box_equal(a, b)); + + for (const auto& c : {a, b}) { + const area::BoundingBox d{c.north, c.west + 42 * PointLonLat::FULL_ANGLE, c.south, + c.east + 41 * PointLonLat::FULL_ANGLE}; + EXPECT(area::bounding_box_equal(c, d)); + } +} + + } // namespace eckit::geo::test From 8f22a2117cb18b1e05fb224b1f383b99a1fc23da Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 28 Jun 2024 12:53:41 +0100 Subject: [PATCH 725/737] eckit::geo::Area --- src/eckit/geo/area/BoundingBox.cc | 17 ++++++++++------- src/eckit/geo/area/BoundingBox.h | 12 +++++------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index f603d1ff1..c1d1b9bc0 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -17,8 +17,6 @@ #include #include "eckit/exception/Exceptions.h" -#include "eckit/geo/Figure.h" -#include "eckit/geo/PointLonLat.h" #include "eckit/geo/geometry/Sphere.h" #include "eckit/geo/spec/Custom.h" #include "eckit/types/FloatCompare.h" @@ -27,9 +25,7 @@ namespace eckit::geo::area { -static const BoundingBox GLOBE_PRIME{90., 0., -90., 360.}; -static const BoundingBox GLOBE_ANTIPRIME{90., -180., -90., 180.}; -static const BoundingBox& DEFAULT = GLOBE_PRIME; +static const auto& DEFAULT = BOUNDING_BOX_GLOBE_PRIME; static inline bool is_approximately_equal(BoundingBox::value_type a, BoundingBox::value_type b) { @@ -38,12 +34,12 @@ static inline bool is_approximately_equal(BoundingBox::value_type a, BoundingBox BoundingBox* BoundingBox::make_global_prime() { - return new BoundingBox(GLOBE_PRIME); + return new BoundingBox(BOUNDING_BOX_GLOBE_PRIME); } BoundingBox* BoundingBox::make_global_antiprime() { - return new BoundingBox(GLOBE_ANTIPRIME); + return new BoundingBox(BOUNDING_BOX_GLOBE_ANTIPRIME); } @@ -216,4 +212,11 @@ bool bounding_box_equal(const BoundingBox& a, const BoundingBox& b) { } +const BoundingBox BOUNDING_BOX_GLOBE_PRIME{PointLonLat::RIGHT_ANGLE, 0., -PointLonLat::RIGHT_ANGLE, + PointLonLat::FULL_ANGLE}; + +const BoundingBox BOUNDING_BOX_GLOBE_ANTIPRIME{PointLonLat::RIGHT_ANGLE, -PointLonLat::FLAT_ANGLE, -90., + PointLonLat::FLAT_ANGLE}; + + } // namespace eckit::geo::area diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index b5d984e74..7fe570d95 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -16,13 +16,7 @@ #include #include "eckit/geo/Area.h" -#include "eckit/geo/Point.h" - - -namespace eckit::geo { -class Figure; -class Projection; -} // namespace eckit::geo +#include "eckit/geo/PointLonLat.h" namespace eckit::geo::area { @@ -112,4 +106,8 @@ class BoundingBox : public Area, protected std::array { }; +extern const BoundingBox BOUNDING_BOX_GLOBE_PRIME; +extern const BoundingBox BOUNDING_BOX_GLOBE_ANTIPRIME; + + } // namespace eckit::geo::area From bb6d3317bd7ddfabb5a791bde61767365e68adff Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 28 Jun 2024 12:53:54 +0100 Subject: [PATCH 726/737] eckit::geo::Area --- src/eckit/geo/area/BoundingBox.cc | 36 ++++++++++++++++++++----------- src/eckit/geo/area/BoundingBox.h | 2 ++ tests/geo/area_boundingbox.cc | 36 +++++++++++++++++++++++++++---- 3 files changed, 57 insertions(+), 17 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index c1d1b9bc0..0368fdbfa 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -75,6 +75,7 @@ BoundingBox* BoundingBox::make_from_spec(const Spec& spec) { BoundingBox* BoundingBox::make_from_area(value_type n, value_type w, value_type s, value_type e) { + // set latitudes inside usual range (not a normalisation like PointLonLat::make) if (n > NORTH_POLE.lat || is_approximately_equal(n, NORTH_POLE.lat)) { n = NORTH_POLE.lat; } @@ -83,26 +84,35 @@ BoundingBox* BoundingBox::make_from_area(value_type n, value_type w, value_type s = SOUTH_POLE.lat; } - if (is_approximately_equal(w, e)) { - w = PointLonLat::normalise_angle_to_minimum(w, 0.); - e = w; - } - else { - w = PointLonLat::normalise_angle_to_minimum(w, 0.); - e = PointLonLat::normalise_angle_to_minimum(e, w); - if (is_approximately_equal(w, e)) { - e = w + PointLonLat::FULL_ANGLE; - } - } + // normalise west in [min, min + 2 pi[, east in [west, west + 2 pi[ + constexpr auto min = BOUNDING_BOX_NORMALISE_WEST; + const auto same = is_approximately_equal(w, e); + + w = is_approximately_equal(w, min) || is_approximately_equal(w, min + PointLonLat::FULL_ANGLE) + ? min + : PointLonLat::normalise_angle_to_minimum(w, min); + + auto a = PointLonLat::normalise_angle_to_minimum(e, w); + e = same ? w : is_approximately_equal(w, a) ? (w + PointLonLat::FULL_ANGLE) : a; return new BoundingBox{n, w, s, e}; } -BoundingBox::BoundingBox(const Spec& spec) : BoundingBox(*std::unique_ptr(make_from_spec(spec))) {} +BoundingBox::BoundingBox(const Spec& spec) : BoundingBox(*std::unique_ptr(make_from_spec(spec))) { + ASSERT(south <= north); + ASSERT(west <= east); +} + +BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s, e} { + // normalise east in [west, west + 2 pi[ + auto a = PointLonLat::normalise_angle_to_minimum(e, w); + operator[](3) = is_approximately_equal(w, e) ? w : is_approximately_equal(w, a) ? (w + PointLonLat::FULL_ANGLE) : a; -BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s, e} {} + ASSERT(south <= north); + ASSERT(west <= east); +} BoundingBox::BoundingBox() : BoundingBox(DEFAULT) {} diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 7fe570d95..30271a84a 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -106,6 +106,8 @@ class BoundingBox : public Area, protected std::array { }; +constexpr PointLonLat::value_type BOUNDING_BOX_NORMALISE_WEST = -PointLonLat::FLAT_ANGLE; + extern const BoundingBox BOUNDING_BOX_GLOBE_PRIME; extern const BoundingBox BOUNDING_BOX_GLOBE_ANTIPRIME; diff --git a/tests/geo/area_boundingbox.cc b/tests/geo/area_boundingbox.cc index bc4fc1728..878299ca7 100644 --- a/tests/geo/area_boundingbox.cc +++ b/tests/geo/area_boundingbox.cc @@ -10,6 +10,8 @@ */ +#include + #include "eckit/geo/area/BoundingBox.h" #include "eckit/testing/Test.h" @@ -32,43 +34,55 @@ CASE("latitude (checks)") { CASE("longitude (normalisation)") { - for (auto west : {-900, -720, -540, -360, -180, 0, 180, 360, 540, 720, 900}) { + for (double west : {-900, -720, -540, -360, -180, 0, 180, 360, 540, 720, 900}) { area::BoundingBox a(90, west, 90, west); + EXPECT_EQUAL(a.west, west); + EXPECT(a.empty()); + + area::BoundingBox b{90, west, -90, west - 1}; + std::unique_ptr c( + area::BoundingBox::make_from_area(90, west + 42 * 360., -90, west - 42 * 360. - 1)); - area::BoundingBox b(90, west, 90, west - 1); - EXPECT_EQUAL(b.east, west + 360 - 1); + EXPECT(c->east == c->west + 360 - 1); + EXPECT(b == *c); } } CASE("assignment") { area::BoundingBox a(10, 1, -10, 100); - area::BoundingBox b(20, 2, -20, 200); + EXPECT_NOT_EQUAL(a.north, b.north); EXPECT_NOT_EQUAL(a, b); b = a; + EXPECT_EQUAL(a.north, b.north); EXPECT_EQUAL(a, b); b = {30., b.west, b.south, b.east}; + EXPECT_EQUAL(b.north, 30); EXPECT_EQUAL(a.north, 10); area::BoundingBox c(a); + EXPECT_EQUAL(a.north, c.north); EXPECT_EQUAL(a, c); c = {40., c.west, c.south, c.east}; + EXPECT_EQUAL(c.north, 40); EXPECT_EQUAL(a.north, 10); auto d(std::move(a)); + EXPECT_EQUAL(d.north, 10); d = {50., d.west, d.south, d.east}; + EXPECT_EQUAL(d.north, 50); } @@ -87,6 +101,20 @@ CASE("comparison") { } +CASE("intersects") { + area::BoundingBox a(10, 1, -10, 100); + area::BoundingBox b(20, 2, -20, 200); + + EXPECT(!area::bounding_box_equal(a, b)); + + for (const auto& c : {a, b}) { + const area::BoundingBox d{c.north, c.west + 42 * PointLonLat::FULL_ANGLE, c.south, + c.east + 41 * PointLonLat::FULL_ANGLE}; + EXPECT(area::bounding_box_equal(c, d)); + } +} + + } // namespace eckit::geo::test From a83ada278b5dbbc31da8cac5a85e20d8b18fce08 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 28 Jun 2024 12:54:34 +0100 Subject: [PATCH 727/737] Cleanup --- src/eckit/geo/PointLonLat.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/eckit/geo/PointLonLat.cc b/src/eckit/geo/PointLonLat.cc index 88cb8eb73..ed0cbdbf5 100644 --- a/src/eckit/geo/PointLonLat.cc +++ b/src/eckit/geo/PointLonLat.cc @@ -26,7 +26,7 @@ namespace eckit::geo { PointLonLat::value_type PointLonLat::normalise_angle_to_minimum(value_type a, value_type minimum) { - static const auto modulus = [](auto a) { return a - FULL_ANGLE * std::floor(a / FULL_ANGLE); }; + const auto modulus = [](auto a) { return a - FULL_ANGLE * std::floor(a / FULL_ANGLE); }; auto diff = a - minimum; return 0. <= diff && diff < FULL_ANGLE ? a : (modulus(diff) + minimum); @@ -34,7 +34,7 @@ PointLonLat::value_type PointLonLat::normalise_angle_to_minimum(value_type a, va PointLonLat::value_type PointLonLat::normalise_angle_to_maximum(value_type a, value_type maximum) { - auto modulus = [](auto a) { return a - FULL_ANGLE * std::ceil(a / FULL_ANGLE); }; + const auto modulus = [](auto a) { return a - FULL_ANGLE * std::ceil(a / FULL_ANGLE); }; auto diff = a - maximum; return -FULL_ANGLE < diff && diff <= 0. ? a : (modulus(diff) + maximum); From d0b2b5c98f276cc559a1caf9fc64c47328d0d796 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 28 Jun 2024 12:54:42 +0100 Subject: [PATCH 728/737] eckit::geo::Grid --- src/eckit/geo/Grid.cc | 6 +++-- src/eckit/geo/Grid.h | 1 + src/eckit/geo/grid/Reduced.h | 4 +--- src/eckit/geo/grid/ReducedGaussian.cc | 4 +++- src/eckit/geo/grid/Regular.cc | 6 +++++ src/eckit/geo/grid/Regular.h | 9 ++++---- src/eckit/geo/grid/RegularGaussian.cc | 10 ++++++-- src/eckit/geo/grid/RegularLL.cc | 23 ++++++++++++++++++- src/eckit/geo/grid/RegularLL.h | 10 +++++++- .../regular-xy/LambertAzimuthalEqualArea.h | 3 +-- .../grid/regular-xy/LambertConformalConic.h | 3 +-- src/eckit/geo/grid/regular-xy/Mercator.h | 3 +-- .../geo/grid/regular-xy/PolarStereographic.h | 3 +-- src/eckit/geo/grid/regular-xy/SpaceView.h | 3 +-- 14 files changed, 64 insertions(+), 24 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index e75e7af24..b6fdd0668 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -40,6 +40,9 @@ Grid::Grid(const Spec& spec) : bbox_(area::BoundingBox::make_from_spec(spec)), ordering_(make_ordering_from_spec(spec)) {} +Grid::Grid(Ordering ordering) : ordering_(ordering) {} + + Grid::Grid(const area::BoundingBox& bbox, Ordering ordering) : bbox_(new area::BoundingBox(bbox)), ordering_(ordering) {} @@ -165,8 +168,7 @@ const area::BoundingBox& Grid::boundingBox() const { area::BoundingBox* Grid::calculate_bbox() const { - // FIXME temporary implementation - return new area::BoundingBox; + NOTIMP; } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index e8ea8b8c8..d1cbd55c3 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -140,6 +140,7 @@ class Grid { // -- Constructors explicit Grid(const area::BoundingBox&, Ordering = Ordering::DEFAULT); + explicit Grid(Ordering = Ordering::DEFAULT); // -- Methods diff --git a/src/eckit/geo/grid/Reduced.h b/src/eckit/geo/grid/Reduced.h index b1c41faee..6f7ece7e4 100644 --- a/src/eckit/geo/grid/Reduced.h +++ b/src/eckit/geo/grid/Reduced.h @@ -37,9 +37,7 @@ class Reduced : public Grid { protected: // -- Constructors - explicit Reduced(const Spec& spec) : Grid(spec) {} - - explicit Reduced(const area::BoundingBox& bbox) : Grid(bbox) {} + using Grid::Grid; // -- Methods diff --git a/src/eckit/geo/grid/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc index bba515b0a..a37eeff55 100644 --- a/src/eckit/geo/grid/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -152,9 +152,11 @@ struct ReducedGaussianOctahedral { }; -static const GridRegisterType GRIDTYPE("reduced_gg"); static const GridRegisterName GRIDNAME1("[nN][1-9][0-9]*"); static const GridRegisterName GRIDNAME2("[oO][1-9][0-9]*"); +static const GridRegisterType GRIDTYPE1("reduced_gg"); +static const GridRegisterType GRIDTYPE2("reduced_rotated_gg"); + } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index 640a8ab57..a9c914747 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -60,6 +60,12 @@ Regular::Regular(std::pair xy, const area::BoundingBox& bbox) : } +Regular::Regular(std::pair xy) : x_(xy.first), y_(xy.second) { + ASSERT(x_ && x_->size() > 0); + ASSERT(y_ && y_->size() > 0); +} + + void Regular::fill_spec(spec::Custom& custom) const { Grid::fill_spec(custom); } diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index e7c8bf4ce..524a2ac8c 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -46,6 +46,9 @@ class Regular : public Grid { [[nodiscard]] static std::pair make_lonlat_ranges_from_spec(const Spec&); + const Range& x() const; + const Range& y() const; + // -- Overridden methods iterator cbegin() const override; @@ -53,13 +56,11 @@ class Regular : public Grid { size_t size() const final { return nx() * ny(); } - const Range& x() const; - const Range& y() const; - protected: // -- Constructors - Regular(std::pair xy, const area::BoundingBox&); + Regular(std::pair xy, const area::BoundingBox& bbox); + Regular(std::pair xy); // -- Overridden methods diff --git a/src/eckit/geo/grid/RegularGaussian.cc b/src/eckit/geo/grid/RegularGaussian.cc index 908c0ecef..251feb56c 100644 --- a/src/eckit/geo/grid/RegularGaussian.cc +++ b/src/eckit/geo/grid/RegularGaussian.cc @@ -12,6 +12,8 @@ #include "eckit/geo/grid/RegularGaussian.h" +#include + #include "eckit/geo/range/GaussianLatitude.h" #include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" @@ -21,7 +23,9 @@ namespace eckit::geo::grid { -RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian(spec.get_unsigned("N"), area::BoundingBox(spec)) {} +RegularGaussian::RegularGaussian(const Spec& spec) : + RegularGaussian(spec.get_unsigned("N"), + *std::unique_ptr(area::BoundingBox::make_from_spec(spec))) {} RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : @@ -58,7 +62,9 @@ void RegularGaussian::fill_spec(spec::Custom& custom) const { static const GridRegisterName GRIDNAME("[fF][1-9][0-9]*"); -static const GridRegisterType GRIDTYPE("regular_gg"); + +static const GridRegisterType GRIDTYPE1("regular_gg"); +static const GridRegisterType GRIDTYPE2("rotated_gg"); } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularLL.cc b/src/eckit/geo/grid/RegularLL.cc index 976db8a9b..2cfb490de 100644 --- a/src/eckit/geo/grid/RegularLL.cc +++ b/src/eckit/geo/grid/RegularLL.cc @@ -12,6 +12,7 @@ #include "eckit/geo/grid/RegularLL.h" +#include #include #include "eckit/geo/Increments.h" @@ -74,6 +75,12 @@ void RegularLL::fill_spec(spec::Custom& custom) const { Regular::fill_spec(custom); custom.set("grid", std::vector{dx(), dy()}); + + if (!boundingBox().isGlobal()) { + custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); + } + + boundingBox().fill_spec(custom); } @@ -86,8 +93,22 @@ Grid* RegularLL::make_grid_cropped(const Area& crop) const { } +area::BoundingBox* RegularLL::calculate_bbox() const { + // FIXME depends on ordering + auto n = std::max(y().a(), y().b()); + auto s = std::min(y().a(), y().b()); + + auto w = x().a(); + auto e = x().periodic() ? w + PointLonLat::FULL_ANGLE : x().b(); + + return new area::BoundingBox{n, w, s, e}; +} + + static const GridRegisterName GRIDNAME(REGULAR_LL_PATTERN); -static const GridRegisterType GRIDTYPE("regular_ll"); + +static const GridRegisterType GRIDTYPE1("regular_ll"); +static const GridRegisterType GRIDTYPE2("rotated_ll"); } // namespace eckit::geo::grid diff --git a/src/eckit/geo/grid/RegularLL.h b/src/eckit/geo/grid/RegularLL.h index 7ef16f284..78781e743 100644 --- a/src/eckit/geo/grid/RegularLL.h +++ b/src/eckit/geo/grid/RegularLL.h @@ -18,15 +18,23 @@ namespace eckit::geo::grid { -struct RegularLL final : public Regular { +class RegularLL final : public Regular { +public: + // -- Constructors explicit RegularLL(const Spec&); explicit RegularLL(const Increments&, const area::BoundingBox& = {}); RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); + // -- Methods + [[nodiscard]] static Spec* spec(const std::string& name); + + // -- Overridden methods + void fill_spec(spec::Custom&) const override; [[nodiscard]] Grid* make_grid_cropped(const Area&) const override; + [[nodiscard]] area::BoundingBox* calculate_bbox() const override; }; diff --git a/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h index 84be8d26d..c70e6c1db 100644 --- a/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h @@ -19,8 +19,7 @@ namespace eckit::geo::grid::regularxy { struct LambertAzimuthalEqualArea final : public RegularXY { - explicit LambertAzimuthalEqualArea(const Spec& spec) : - RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} + explicit LambertAzimuthalEqualArea(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/grid/regular-xy/LambertConformalConic.h b/src/eckit/geo/grid/regular-xy/LambertConformalConic.h index 247cfe35e..3ac7f699c 100644 --- a/src/eckit/geo/grid/regular-xy/LambertConformalConic.h +++ b/src/eckit/geo/grid/regular-xy/LambertConformalConic.h @@ -19,8 +19,7 @@ namespace eckit::geo::grid::regularxy { struct LambertConformalConic final : public RegularXY { - explicit LambertConformalConic(const Spec& spec) : - RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} + explicit LambertConformalConic(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/grid/regular-xy/Mercator.h b/src/eckit/geo/grid/regular-xy/Mercator.h index 751d23849..2dcc0a6b7 100644 --- a/src/eckit/geo/grid/regular-xy/Mercator.h +++ b/src/eckit/geo/grid/regular-xy/Mercator.h @@ -19,8 +19,7 @@ namespace eckit::geo::grid::regularxy { struct Mercator final : public RegularXY { - explicit Mercator(const Spec& spec) : - RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} + explicit Mercator(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/grid/regular-xy/PolarStereographic.h b/src/eckit/geo/grid/regular-xy/PolarStereographic.h index 6b230de2b..2a20b809c 100644 --- a/src/eckit/geo/grid/regular-xy/PolarStereographic.h +++ b/src/eckit/geo/grid/regular-xy/PolarStereographic.h @@ -19,8 +19,7 @@ namespace eckit::geo::grid::regularxy { struct PolarStereographic final : public RegularXY { - explicit PolarStereographic(const Spec& spec) : - RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} + explicit PolarStereographic(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/grid/regular-xy/SpaceView.h b/src/eckit/geo/grid/regular-xy/SpaceView.h index 5e39aca7a..1a4f78279 100644 --- a/src/eckit/geo/grid/regular-xy/SpaceView.h +++ b/src/eckit/geo/grid/regular-xy/SpaceView.h @@ -19,8 +19,7 @@ namespace eckit::geo::grid::regularxy { struct SpaceView final : public RegularXY { - explicit SpaceView(const Spec& spec) : - RegularXY(RegularXY::make_xy_ranges_from_spec(spec), area::BoundingBox{spec}) {} + explicit SpaceView(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} void fill_spec(spec::Custom& custom) const override; }; From c24c24d33c0d685a35c1bc91790bd826a71f486d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 28 Jun 2024 15:21:20 +0100 Subject: [PATCH 729/737] eckit::geo::Range --- src/eckit/geo/Range.h | 8 +++--- src/eckit/geo/grid/ReducedGaussian.cc | 6 ++--- src/eckit/geo/grid/RegularGaussian.cc | 4 +-- src/eckit/geo/range/GaussianLatitude.cc | 4 +-- src/eckit/geo/range/GaussianLatitude.h | 4 +-- src/eckit/geo/range/RegularCartesian.cc | 4 +-- src/eckit/geo/range/RegularCartesian.h | 4 +-- src/eckit/geo/range/RegularLatitude.cc | 2 +- src/eckit/geo/range/RegularLatitude.h | 4 +-- src/eckit/geo/range/RegularLongitude.cc | 4 +-- src/eckit/geo/range/RegularLongitude.h | 4 +-- tests/geo/range.cc | 34 +++++++++++++++---------- 12 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index a47c19456..63216cef9 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -49,10 +49,10 @@ class Range { virtual bool periodic() const { return false; } - [[nodiscard]] virtual Range* flip() const = 0; - [[nodiscard]] virtual Range* crop(double crop_a, double crop_b) const = 0; - virtual Fraction increment() const = 0; - virtual const std::vector& values() const = 0; + [[nodiscard]] virtual Range* make_range_flipped() const = 0; + [[nodiscard]] virtual Range* make_range_cropped(double crop_a, double crop_b) const = 0; + virtual Fraction increment() const = 0; + virtual const std::vector& values() const = 0; protected: // -- Constructors diff --git a/src/eckit/geo/grid/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc index a37eeff55..b0cc06415 100644 --- a/src/eckit/geo/grid/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -43,7 +43,7 @@ ReducedGaussian::ReducedGaussian(const pl_type& pl, const area::BoundingBox& bbo j_(0), Nj_(N_ * 2), x_(Nj_), - y_(range::GaussianLatitude(N_, false).crop(bbox.north, bbox.south)) { + y_(range::GaussianLatitude(N_, false).make_range_cropped(bbox.north, bbox.south)) { ASSERT(Nj_ == pl_.size()); ASSERT(y_); } @@ -75,7 +75,7 @@ size_t ReducedGaussian::ni(size_t j) const { ASSERT(Ni >= 0); range::RegularLongitude x(static_cast(Ni), 0., 360.); - const_cast>&>(x_)[j].reset(x.crop(bbox.west, bbox.east)); + const_cast>&>(x_)[j].reset(x.make_range_cropped(bbox.west, bbox.east)); ASSERT(x_[j]); } @@ -100,7 +100,7 @@ std::vector ReducedGaussian::longitudes(size_t j) const { ASSERT(Ni >= 0); range::RegularLongitude x(static_cast(Ni), 0., 360.); - const_cast>&>(x_)[j].reset(x.crop(bbox.west, bbox.east)); + const_cast>&>(x_)[j].reset(x.make_range_cropped(bbox.west, bbox.east)); ASSERT(x_[j]); } diff --git a/src/eckit/geo/grid/RegularGaussian.cc b/src/eckit/geo/grid/RegularGaussian.cc index 251feb56c..51b51d2fa 100644 --- a/src/eckit/geo/grid/RegularGaussian.cc +++ b/src/eckit/geo/grid/RegularGaussian.cc @@ -29,8 +29,8 @@ RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : - Regular({range::RegularLongitude(4 * N, 0., 360.).crop(bbox.west, bbox.east), - range::GaussianLatitude(N, false).crop(bbox.north, bbox.south)}, + Regular({range::RegularLongitude(4 * N, 0., 360.).make_range_cropped(bbox.west, bbox.east), + range::GaussianLatitude(N, false).make_range_cropped(bbox.north, bbox.south)}, bbox), N_(N) { ASSERT(size() > 0); diff --git a/src/eckit/geo/range/GaussianLatitude.cc b/src/eckit/geo/range/GaussianLatitude.cc index 7951617b8..46e46202d 100644 --- a/src/eckit/geo/range/GaussianLatitude.cc +++ b/src/eckit/geo/range/GaussianLatitude.cc @@ -31,7 +31,7 @@ GaussianLatitude::GaussianLatitude(size_t N, bool increasing, double eps) : Range(2 * N, increasing ? -90. : 90., increasing ? 90. : -90., eps), N_(N) {} -Range* GaussianLatitude::flip() const { +Range* GaussianLatitude::make_range_flipped() const { std::vector flipped(size()); const auto& v = values(); std::reverse_copy(v.begin(), v.end(), flipped.begin()); @@ -40,7 +40,7 @@ Range* GaussianLatitude::flip() const { } -Range* GaussianLatitude::crop(double crop_a, double crop_b) const { +Range* GaussianLatitude::make_range_cropped(double crop_a, double crop_b) const { ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); diff --git a/src/eckit/geo/range/GaussianLatitude.h b/src/eckit/geo/range/GaussianLatitude.h index 3d3b9204d..06d82f716 100644 --- a/src/eckit/geo/range/GaussianLatitude.h +++ b/src/eckit/geo/range/GaussianLatitude.h @@ -30,8 +30,8 @@ class GaussianLatitude final : public Range { // -- Overridden methods - [[nodiscard]] Range* flip() const override; - [[nodiscard]] Range* crop(double crop_a, double crop_b) const override; + [[nodiscard]] Range* make_range_flipped() const override; + [[nodiscard]] Range* make_range_cropped(double crop_a, double crop_b) const override; Fraction increment() const override; const std::vector& values() const override; diff --git a/src/eckit/geo/range/RegularCartesian.cc b/src/eckit/geo/range/RegularCartesian.cc index 136df3c6e..90cb59fbe 100644 --- a/src/eckit/geo/range/RegularCartesian.cc +++ b/src/eckit/geo/range/RegularCartesian.cc @@ -35,7 +35,7 @@ static Fraction regular_adjust(const Fraction& target, const Fraction& inc, bool }; -Range* RegularCartesian::crop(double crop_a, double crop_b) const { +Range* RegularCartesian::make_range_cropped(double crop_a, double crop_b) const { ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); @@ -66,7 +66,7 @@ Range* RegularCartesian::crop(double crop_a, double crop_b) const { } -Range* RegularCartesian::flip() const { +Range* RegularCartesian::make_range_flipped() const { return new RegularCartesian(size(), b(), a(), eps()); } diff --git a/src/eckit/geo/range/RegularCartesian.h b/src/eckit/geo/range/RegularCartesian.h index 3c1b95b3c..3c7b6c981 100644 --- a/src/eckit/geo/range/RegularCartesian.h +++ b/src/eckit/geo/range/RegularCartesian.h @@ -28,8 +28,8 @@ class RegularCartesian final : public Regular { // -- Overridden methods - [[nodiscard]] Range* crop(double crop_a, double crop_b) const override; - [[nodiscard]] Range* flip() const override; + [[nodiscard]] Range* make_range_cropped(double crop_a, double crop_b) const override; + [[nodiscard]] Range* make_range_flipped() const override; }; diff --git a/src/eckit/geo/range/RegularLatitude.cc b/src/eckit/geo/range/RegularLatitude.cc index fbeaac942..6e467ceb5 100644 --- a/src/eckit/geo/range/RegularLatitude.cc +++ b/src/eckit/geo/range/RegularLatitude.cc @@ -30,7 +30,7 @@ RegularLatitude::RegularLatitude(size_t n, double _a, double _b, double _eps) : } -Range* RegularLatitude::crop(double crop_a, double crop_b) const { +Range* RegularLatitude::make_range_cropped(double crop_a, double crop_b) const { ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b) || (types::is_approximately_equal(a(), b(), eps()) && types::is_approximately_equal(crop_a, crop_b, eps()))); diff --git a/src/eckit/geo/range/RegularLatitude.h b/src/eckit/geo/range/RegularLatitude.h index 6371ec963..b6c5bf93b 100644 --- a/src/eckit/geo/range/RegularLatitude.h +++ b/src/eckit/geo/range/RegularLatitude.h @@ -27,8 +27,8 @@ class RegularLatitude final : public Regular { // -- Overridden methods - [[nodiscard]] Range* crop(double crop_a, double crop_b) const override; - [[nodiscard]] Range* flip() const override { return new RegularLatitude(size(), b(), a(), eps()); } + [[nodiscard]] Range* make_range_cropped(double crop_a, double crop_b) const override; + [[nodiscard]] Range* make_range_flipped() const override { return new RegularLatitude(size(), b(), a(), eps()); } }; diff --git a/src/eckit/geo/range/RegularLongitude.cc b/src/eckit/geo/range/RegularLongitude.cc index 171412b90..df091ac5f 100644 --- a/src/eckit/geo/range/RegularLongitude.cc +++ b/src/eckit/geo/range/RegularLongitude.cc @@ -51,7 +51,7 @@ RegularLongitude::RegularLongitude(size_t n, double _a, double _b, double _eps) Regular(n, _a, _b, types::is_approximately_lesser_or_equal(PERIOD, std::abs(_b - _a)), _eps) {} -Range* RegularLongitude::crop(double crop_a, double crop_b) const { +Range* RegularLongitude::make_range_cropped(double crop_a, double crop_b) const { ASSERT((a() < b() && crop_a <= crop_b) || (a() > b() && crop_a >= crop_b)); if (a() < b()) { @@ -87,7 +87,7 @@ Range* RegularLongitude::crop(double crop_a, double crop_b) const { } -Range* RegularLongitude::flip() const { +Range* RegularLongitude::make_range_flipped() const { std::vector flipped(size()); const auto& v = values(); std::reverse_copy(v.begin(), v.end(), flipped.begin()); diff --git a/src/eckit/geo/range/RegularLongitude.h b/src/eckit/geo/range/RegularLongitude.h index ef29dc660..916b8f12d 100644 --- a/src/eckit/geo/range/RegularLongitude.h +++ b/src/eckit/geo/range/RegularLongitude.h @@ -31,8 +31,8 @@ class RegularLongitude final : public Regular { // -- Overridden methods - [[nodiscard]] Range* crop(double crop_a, double crop_b) const override; - [[nodiscard]] Range* flip() const override; + [[nodiscard]] Range* make_range_cropped(double crop_a, double crop_b) const override; + [[nodiscard]] Range* make_range_flipped() const override; bool periodic() const override { return getPeriodic(); } diff --git a/tests/geo/range.cc b/tests/geo/range.cc index c01ee55c5..aec1104b9 100644 --- a/tests/geo/range.cc +++ b/tests/geo/range.cc @@ -133,20 +133,20 @@ CASE("range::RegularLongitude") { EXPECT(range.periodic()); - const std::unique_ptr range1(range.crop(-180., 180.)); + const std::unique_ptr range1(range.make_range_cropped(-180., 180.)); EXPECT(range1->size() == 36); EXPECT(range1->a() == -180.); EXPECT(range1->b() == 180.); EXPECT(range1->periodic()); - const std::unique_ptr range2(range.crop(-180., 170.)); + const std::unique_ptr range2(range.make_range_cropped(-180., 170.)); EXPECT(range2->size() == 36); EXPECT(range2->b() == 180.); // because it's how we can distinguish without additional metadata EXPECT(range2->periodic()); - const std::unique_ptr range3(range.crop(-180., 160.)); + const std::unique_ptr range3(range.make_range_cropped(-180., 160.)); EXPECT(range3->size() == 36 - 1); EXPECT(range3->b() == 160.); @@ -159,28 +159,28 @@ CASE("range::RegularLongitude") { EXPECT_NOT(range.periodic()); - const std::unique_ptr range1(range.crop(1., 179.)); + const std::unique_ptr range1(range.make_range_cropped(1., 179.)); EXPECT(range1->size() == 19 - 2); EXPECT(range1->a() == 10.); EXPECT(range1->b() == 170.); EXPECT_NOT(range1->periodic()); - const std::unique_ptr range2(range.crop(1., 170.)); + const std::unique_ptr range2(range.make_range_cropped(1., 170.)); EXPECT(range2->size() == 19 - 2); EXPECT(range2->a() == 10.); EXPECT(range2->b() == 170.); EXPECT_NOT(range2->periodic()); - const std::unique_ptr range3(range.crop(-180., 180.)); + const std::unique_ptr range3(range.make_range_cropped(-180., 180.)); EXPECT(range3->size() == 19); EXPECT(range3->a() == 0.); EXPECT(range3->b() == 180.); EXPECT_NOT(range3->periodic()); - const std::unique_ptr range4(range.crop(-190., 170.)); + const std::unique_ptr range4(range.make_range_cropped(-190., 170.)); EXPECT(range4->size() == 19 - 1); EXPECT(range4->a() == 0.); @@ -217,17 +217,23 @@ CASE("range::Gaussian") { SECTION("crop [50., -50.]") { - std::unique_ptr cropped(range::GaussianLatitude(2, false).crop(50., -50.)); + std::unique_ptr cropped(range::GaussianLatitude(2, false).make_range_cropped(50., -50.)); EXPECT(cropped->size() == ref.size() - 2); EXPECT_APPROX(cropped->values()[0], ref[1]); EXPECT_APPROX(cropped->values()[1], ref[2]); - EXPECT(std::unique_ptr(range::GaussianLatitude(2, false, 1e-3).crop(59.444, -59.444))->size() == 4); - EXPECT(std::unique_ptr(range::GaussianLatitude(2, false, 1e-6).crop(59.444, -59.444))->size() == 2); - EXPECT(std::unique_ptr(range::GaussianLatitude(2, false, 1e-6).crop(59.444, -59.445))->size() == 3); - - std::unique_ptr single(range::GaussianLatitude(2, false, 1e-3).crop(-59.444, -59.444)); + EXPECT( + std::unique_ptr(range::GaussianLatitude(2, false, 1e-3).make_range_cropped(59.444, -59.444))->size() + == 4); + EXPECT( + std::unique_ptr(range::GaussianLatitude(2, false, 1e-6).make_range_cropped(59.444, -59.444))->size() + == 2); + EXPECT( + std::unique_ptr(range::GaussianLatitude(2, false, 1e-6).make_range_cropped(59.444, -59.445))->size() + == 3); + + std::unique_ptr single(range::GaussianLatitude(2, false, 1e-3).make_range_cropped(-59.444, -59.444)); EXPECT(single->size() == 1); EXPECT_APPROX(single->values().front(), ref.back()); @@ -235,7 +241,7 @@ CASE("range::Gaussian") { SECTION("crop [90., 0.]") { - std::unique_ptr cropped(range::GaussianLatitude(2, false, 1e-3).crop(90., 0.)); + std::unique_ptr cropped(range::GaussianLatitude(2, false, 1e-3).make_range_cropped(90., 0.)); EXPECT(cropped->size() == ref.size() / 2); EXPECT_APPROX(cropped->values()[0], ref[0]); From d093030b45961caff8785af3339fa724de78f72d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 28 Jun 2024 15:21:31 +0100 Subject: [PATCH 730/737] Cleanup --- src/eckit/geo/Range.h | 5 +++-- src/eckit/geo/grid/ReducedGaussian.cc | 5 ++--- src/eckit/geo/grid/ReducedGaussian.h | 4 ++++ src/eckit/geo/grid/RegularGaussian.h | 16 +++++++++++++--- src/eckit/geo/grid/RegularLL.h | 1 + .../grid/regular-xy/LambertAzimuthalEqualArea.h | 7 ++++++- .../geo/grid/regular-xy/LambertConformalConic.h | 7 ++++++- src/eckit/geo/grid/regular-xy/Mercator.h | 7 ++++++- .../geo/grid/regular-xy/PolarStereographic.h | 7 ++++++- src/eckit/geo/grid/regular-xy/SpaceView.h | 7 ++++++- 10 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/eckit/geo/Range.h b/src/eckit/geo/Range.h index 63216cef9..7930afb1f 100644 --- a/src/eckit/geo/Range.h +++ b/src/eckit/geo/Range.h @@ -51,8 +51,9 @@ class Range { [[nodiscard]] virtual Range* make_range_flipped() const = 0; [[nodiscard]] virtual Range* make_range_cropped(double crop_a, double crop_b) const = 0; - virtual Fraction increment() const = 0; - virtual const std::vector& values() const = 0; + + virtual Fraction increment() const = 0; + virtual const std::vector& values() const = 0; protected: // -- Constructors diff --git a/src/eckit/geo/grid/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc index b0cc06415..1b92d40be 100644 --- a/src/eckit/geo/grid/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -19,14 +19,13 @@ #include "eckit/geo/range/GaussianLatitude.h" #include "eckit/geo/range/RegularLongitude.h" #include "eckit/geo/spec/Custom.h" -#include "eckit/geo/util.h" #include "eckit/utils/Translator.h" namespace eckit::geo::grid { -static size_t N(const pl_type& pl) { +static size_t calculate_n(const pl_type& pl) { ASSERT(!pl.empty() && pl.size() % 2 == 0); return pl.size() / 2; } @@ -38,7 +37,7 @@ ReducedGaussian::ReducedGaussian(const Spec& spec) : ReducedGaussian::ReducedGaussian(const pl_type& pl, const area::BoundingBox& bbox) : Reduced(bbox), - N_(N(pl)), + N_(calculate_n(pl)), pl_(pl), j_(0), Nj_(N_ * 2), diff --git a/src/eckit/geo/grid/ReducedGaussian.h b/src/eckit/geo/grid/ReducedGaussian.h index 2065c4816..791323fe9 100644 --- a/src/eckit/geo/grid/ReducedGaussian.h +++ b/src/eckit/geo/grid/ReducedGaussian.h @@ -31,6 +31,10 @@ class ReducedGaussian : public Reduced { explicit ReducedGaussian(const pl_type&, const area::BoundingBox& = {}); explicit ReducedGaussian(size_t N, const area::BoundingBox& = {}); + // -- Methods + + size_t N() const { return N_; } + // -- Overridden methods iterator cbegin() const override; diff --git a/src/eckit/geo/grid/RegularGaussian.h b/src/eckit/geo/grid/RegularGaussian.h index b8610dff4..55fa91288 100644 --- a/src/eckit/geo/grid/RegularGaussian.h +++ b/src/eckit/geo/grid/RegularGaussian.h @@ -18,17 +18,27 @@ namespace eckit::geo::grid { -struct RegularGaussian final : public Regular { +class RegularGaussian final : public Regular { +public: + // -- Constructors + explicit RegularGaussian(const Spec&); explicit RegularGaussian(size_t N, const area::BoundingBox& = {}); - [[nodiscard]] static Spec* spec(const std::string& name); - void fill_spec(spec::Custom&) const override; + // -- Methods size_t N() const { return N_; } + // -- Overridden methods + + void fill_spec(spec::Custom&) const override; + [[nodiscard]] Grid* make_grid_cropped(const Area&) const override; + // -- Class members + + [[nodiscard]] static Spec* spec(const std::string& name); + private: const size_t N_; }; diff --git a/src/eckit/geo/grid/RegularLL.h b/src/eckit/geo/grid/RegularLL.h index 78781e743..5c6bfd1bf 100644 --- a/src/eckit/geo/grid/RegularLL.h +++ b/src/eckit/geo/grid/RegularLL.h @@ -21,6 +21,7 @@ namespace eckit::geo::grid { class RegularLL final : public Regular { public: // -- Constructors + explicit RegularLL(const Spec&); explicit RegularLL(const Increments&, const area::BoundingBox& = {}); RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); diff --git a/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h index c70e6c1db..f99983fa1 100644 --- a/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h @@ -18,9 +18,14 @@ namespace eckit::geo::grid::regularxy { -struct LambertAzimuthalEqualArea final : public RegularXY { +class LambertAzimuthalEqualArea final : public RegularXY { +public: + // -- Constructors + explicit LambertAzimuthalEqualArea(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} + // -- Overridden methods + void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/grid/regular-xy/LambertConformalConic.h b/src/eckit/geo/grid/regular-xy/LambertConformalConic.h index 3ac7f699c..df4748392 100644 --- a/src/eckit/geo/grid/regular-xy/LambertConformalConic.h +++ b/src/eckit/geo/grid/regular-xy/LambertConformalConic.h @@ -18,9 +18,14 @@ namespace eckit::geo::grid::regularxy { -struct LambertConformalConic final : public RegularXY { +class LambertConformalConic final : public RegularXY { +public: + // -- Constructors + explicit LambertConformalConic(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} + // -- Overridden methods + void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/grid/regular-xy/Mercator.h b/src/eckit/geo/grid/regular-xy/Mercator.h index 2dcc0a6b7..a5670cc81 100644 --- a/src/eckit/geo/grid/regular-xy/Mercator.h +++ b/src/eckit/geo/grid/regular-xy/Mercator.h @@ -18,9 +18,14 @@ namespace eckit::geo::grid::regularxy { -struct Mercator final : public RegularXY { +class Mercator final : public RegularXY { +public: + // -- Constructors + explicit Mercator(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} + // -- Overridden methods + void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/grid/regular-xy/PolarStereographic.h b/src/eckit/geo/grid/regular-xy/PolarStereographic.h index 2a20b809c..dec240351 100644 --- a/src/eckit/geo/grid/regular-xy/PolarStereographic.h +++ b/src/eckit/geo/grid/regular-xy/PolarStereographic.h @@ -18,9 +18,14 @@ namespace eckit::geo::grid::regularxy { -struct PolarStereographic final : public RegularXY { +class PolarStereographic final : public RegularXY { +public: + // -- Constructors + explicit PolarStereographic(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} + // -- Overridden methods + void fill_spec(spec::Custom& custom) const override; }; diff --git a/src/eckit/geo/grid/regular-xy/SpaceView.h b/src/eckit/geo/grid/regular-xy/SpaceView.h index 1a4f78279..58b213d72 100644 --- a/src/eckit/geo/grid/regular-xy/SpaceView.h +++ b/src/eckit/geo/grid/regular-xy/SpaceView.h @@ -18,9 +18,14 @@ namespace eckit::geo::grid::regularxy { -struct SpaceView final : public RegularXY { +class SpaceView final : public RegularXY { +public: + // -- Constructors + explicit SpaceView(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} + // -- Overridden methods + void fill_spec(spec::Custom& custom) const override; }; From 34da13b3ad3a3a270a5ba53885e54b196a92fa8d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Fri, 28 Jun 2024 15:50:12 +0100 Subject: [PATCH 731/737] eckit::geo::Area --- src/eckit/geo/area/BoundingBox.cc | 34 ++++++++++++++++--------------- src/eckit/geo/area/BoundingBox.h | 6 ++---- src/eckit/geo/geometry/Sphere.cc | 2 +- src/eckit/geo/grid/RegularLL.cc | 2 +- tests/geo/area_boundingbox.cc | 16 +++++++++++++++ tests/geo/grid_reduced_gg.cc | 2 +- tests/geo/grid_regular_gg.cc | 4 ++-- tests/geo/projection_proj.cc | 12 +++++++---- 8 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 0368fdbfa..2a06530df 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -118,30 +118,32 @@ BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s BoundingBox::BoundingBox() : BoundingBox(DEFAULT) {} -bool BoundingBox::isGlobal() const { - return isPeriodicWestEast() && containsNorthPole() && containsSouthPole(); +bool BoundingBox::global() const { + return periodic() && contains(NORTH_POLE) && contains(SOUTH_POLE); } -bool BoundingBox::isPeriodicWestEast() const { +bool BoundingBox::periodic() const { return west != east && is_approximately_equal(west, PointLonLat::normalise_angle_to_minimum(east, west)); } -bool BoundingBox::containsNorthPole() const { +bool BoundingBox::contains(const PointLonLat& p) const { // NOTE: latitudes < -90 or > 90 are not considered - return is_approximately_equal(north, NORTH_POLE.lat); -} - + if (is_approximately_equal(p.lat, NORTH_POLE.lat)) { + return is_approximately_equal(p.lat, north); + } -bool BoundingBox::containsSouthPole() const { - // NOTE: latitudes < -90 or > 90 are not considered - return is_approximately_equal(south, SOUTH_POLE.lat); -} + if (is_approximately_equal(p.lat, SOUTH_POLE.lat)) { + return is_approximately_equal(p.lat, south); + } + if ((south < p.lat && p.lat < north) || is_approximately_equal(p.lat, north) + || is_approximately_equal(p.lat, south)) { + return PointLonLat::normalise_angle_to_minimum(p.lon, west) <= east; + } -bool BoundingBox::contains(const PointLonLat& p) const { - return p.lat <= north && p.lat >= south && PointLonLat::normalise_angle_to_minimum(p.lon, west) <= east; + return false; } @@ -169,7 +171,7 @@ bool BoundingBox::intersects(BoundingBox& other) const { n = s; } - if (isPeriodicWestEast() && other.isPeriodicWestEast()) { + if (periodic() && other.periodic()) { other = {n, other.west, s, other.east}; return intersectsSN; } @@ -178,8 +180,8 @@ bool BoundingBox::intersects(BoundingBox& other) const { auto e = w; auto intersect = [](const BoundingBox& a, const BoundingBox& b, double& w, double& e) { - bool p = a.isPeriodicWestEast(); - if (p || b.isPeriodicWestEast()) { + bool p = a.periodic(); + if (p || b.periodic()) { w = (p ? b : a).west; e = (p ? b : a).east; return true; diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 30271a84a..71fe29aff 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -69,10 +69,8 @@ class BoundingBox : public Area, protected std::array { container_type deconstruct() const { return {north, west, south, east}; } - bool isGlobal() const; - bool isPeriodicWestEast() const; - bool containsNorthPole() const; - bool containsSouthPole() const; + bool global() const; + bool periodic() const; bool contains(const PointLonLat&) const; bool contains(const BoundingBox&) const; diff --git a/src/eckit/geo/geometry/Sphere.cc b/src/eckit/geo/geometry/Sphere.cc index 303729653..919fa4d59 100644 --- a/src/eckit/geo/geometry/Sphere.cc +++ b/src/eckit/geo/geometry/Sphere.cc @@ -112,7 +112,7 @@ double Sphere::area(double radius, const area::BoundingBox& bbox) { ASSERT(radius > 0.); // Set longitude and latitude fractions - auto lonf = bbox.isPeriodicWestEast() ? 1. : (bbox.east - bbox.west) / PointLonLat::FULL_ANGLE; + auto lonf = bbox.periodic() ? 1. : (bbox.east - bbox.west) / PointLonLat::FULL_ANGLE; ASSERT(0. <= lonf && lonf <= 1.); auto sn = std::sin(util::DEGREE_TO_RADIAN * bbox.north); diff --git a/src/eckit/geo/grid/RegularLL.cc b/src/eckit/geo/grid/RegularLL.cc index 2cfb490de..e1ebf6cf1 100644 --- a/src/eckit/geo/grid/RegularLL.cc +++ b/src/eckit/geo/grid/RegularLL.cc @@ -76,7 +76,7 @@ void RegularLL::fill_spec(spec::Custom& custom) const { custom.set("grid", std::vector{dx(), dy()}); - if (!boundingBox().isGlobal()) { + if (!boundingBox().global()) { custom.set("shape", std::vector{static_cast(nx()), static_cast(ny())}); } diff --git a/tests/geo/area_boundingbox.cc b/tests/geo/area_boundingbox.cc index 878299ca7..53af3e3fa 100644 --- a/tests/geo/area_boundingbox.cc +++ b/tests/geo/area_boundingbox.cc @@ -101,6 +101,22 @@ CASE("comparison") { } +CASE("properties") { + area::BoundingBox a{10, 1, -10, 100}; + area::BoundingBox b{20, 2, -20, 200}; + std::unique_ptr c(area::BoundingBox::make_global_prime()); + std::unique_ptr d(area::BoundingBox::make_global_antiprime()); + area::BoundingBox e; + + for (const auto& bb : {a, b, *c, *d, e}) { + EXPECT(!bb.empty()); + EXPECT(bb.contains({10, 0})); + EXPECT(bb.global() == bb.contains({0, 0})); + EXPECT(bb.global() == (bb.periodic() && bb.contains(NORTH_POLE) && bb.contains(SOUTH_POLE))); + } +} + + CASE("intersects") { area::BoundingBox a(10, 1, -10, 100); area::BoundingBox b(20, 2, -20, 200); diff --git a/tests/geo/grid_reduced_gg.cc b/tests/geo/grid_reduced_gg.cc index 0f3e1cc99..f2278a0a2 100644 --- a/tests/geo/grid_reduced_gg.cc +++ b/tests/geo/grid_reduced_gg.cc @@ -122,7 +122,7 @@ CASE("crop") { EXPECT_EQUAL(n3, n1); - EXPECT(grid3->boundingBox().isPeriodicWestEast()); + EXPECT(grid3->boundingBox().periodic()); // (exclude Greenwhich meridian) std::unique_ptr grid4(grid3->make_grid_cropped(area::BoundingBox(90., -180., 0., -1.e-6))); diff --git a/tests/geo/grid_regular_gg.cc b/tests/geo/grid_regular_gg.cc index 10190da0f..9f9728bec 100644 --- a/tests/geo/grid_regular_gg.cc +++ b/tests/geo/grid_regular_gg.cc @@ -94,11 +94,11 @@ CASE("crop") { auto bbox3 = grid3->boundingBox(); - EXPECT(bbox3.isPeriodicWestEast()); + EXPECT(bbox3.periodic()); bbox3 = {bbox3.north, bbox3.west, bbox3.south, 0.}; - EXPECT_NOT(bbox3.isPeriodicWestEast()); + EXPECT_NOT(bbox3.periodic()); std::unique_ptr grid4(grid3->make_grid_cropped(bbox3)); auto n4 = grid4->size(); diff --git a/tests/geo/projection_proj.cc b/tests/geo/projection_proj.cc index 490affa25..8c5c8bd0c 100644 --- a/tests/geo/projection_proj.cc +++ b/tests/geo/projection_proj.cc @@ -85,7 +85,7 @@ CASE("projection: proj") { const P& projection; const Point2 min; const Point2 max; - const bool is_periodic_west_east; + const bool periodic; const bool contains_north_pole; const bool contains_south_pole; } tests_bbox[] = { @@ -106,9 +106,13 @@ CASE("projection: proj") { for (const auto& test : tests_bbox) { auto bbox = util::bounding_box(test.min, test.max, *test.projection); - EXPECT_EQUAL(test.is_periodic_west_east, bbox.isPeriodicWestEast()); - EXPECT_EQUAL(test.contains_north_pole, bbox.containsNorthPole()); - EXPECT_EQUAL(test.contains_south_pole, bbox.containsSouthPole()); + EXPECT_EQUAL(test.periodic, bbox.periodic()); + EXPECT_EQUAL(test.contains_north_pole, bbox.contains(NORTH_POLE)); + EXPECT_EQUAL(test.contains_south_pole, bbox.contains(SOUTH_POLE)); + + auto global = test.periodic && test.contains_north_pole && test.contains_south_pole; + + EXPECT(global == bbox.global()); } } } From 7c5f2cd904c4f0ab97f8eae2b19020432c9c7a5f Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 29 Jun 2024 03:33:46 +0100 Subject: [PATCH 732/737] eckit::geo::Projection --- src/eckit/geo/projection/Rotation.cc | 6 +++--- tests/geo/projection_rotation.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index 863f9a562..d68acde3d 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -42,7 +42,7 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : struct RotationAngle final : Implementation { explicit RotationAngle(double angle) : angle_(angle) {} PointLonLat operator()(const PointLonLat& p) const override { return {p.lon + angle_, p.lat}; } - void fill_spec(spec::Custom& custom) const override { custom.set("angle", angle_); } + void fill_spec(spec::Custom& custom) const override { custom.set("rotation_angle", angle_); } const double angle_; }; @@ -57,7 +57,7 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : void fill_spec(spec::Custom& custom) const override { custom.set("south_pole_lon", south_pole_lon_); custom.set("south_pole_lat", south_pole_lat_); - custom.set("angle", angle_); + custom.set("rotation_angle", angle_); } const M R_; const double south_pole_lon_; @@ -112,7 +112,7 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : Rotation::Rotation(const Spec& spec) : - Rotation(spec.get_double("south_pole_lon"), spec.get_double("south_pole_lat"), spec.get_double("angle", 0)) {} + Rotation(spec.get_double("south_pole_lon"), spec.get_double("south_pole_lat"), spec.get_double("rotation_angle", 0)) {} void Rotation::fill_spec(spec::Custom& custom) const { diff --git a/tests/geo/projection_rotation.cc b/tests/geo/projection_rotation.cc index 77de9cd14..780706ee4 100644 --- a/tests/geo/projection_rotation.cc +++ b/tests/geo/projection_rotation.cc @@ -229,7 +229,7 @@ CASE("rotation (5)") { {"projection", "rotation"}, {"south_pole_lat", -90.}, {"south_pole_lon", 0.}, - {"angle", 45.}, + {"rotation_angle", 45.}, }); // compose sequentially From 7133c2d0db0a2e25a4e6e6c259d2c17a490b9224 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 29 Jun 2024 03:35:47 +0100 Subject: [PATCH 733/737] eckit::geo::Grid --- src/eckit/geo/Figure.cc | 1 - src/eckit/geo/grid/Regular.cc | 13 ++++++------- src/eckit/geo/grid/Regular.h | 11 +++++++---- src/eckit/geo/grid/RegularXY.cc | 2 +- src/eckit/geo/grid/RegularXY.h | 4 +--- .../geo/grid/regular-xy/LambertAzimuthalEqualArea.h | 2 +- .../geo/grid/regular-xy/LambertConformalConic.h | 2 +- src/eckit/geo/grid/regular-xy/Mercator.h | 2 +- src/eckit/geo/grid/regular-xy/PolarStereographic.h | 2 +- src/eckit/geo/grid/regular-xy/SpaceView.h | 2 +- 10 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/eckit/geo/Figure.cc b/src/eckit/geo/Figure.cc index 3909045ca..d9d276ab7 100644 --- a/src/eckit/geo/Figure.cc +++ b/src/eckit/geo/Figure.cc @@ -13,7 +13,6 @@ #include "eckit/geo/Figure.h" #include -#include #include "eckit/exception/Exceptions.h" #include "eckit/geo/figure/Earth.h" diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index a9c914747..7f1f10486 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -53,21 +53,20 @@ const Range& Regular::y() const { } -Regular::Regular(std::pair xy, const area::BoundingBox& bbox) : - Grid(bbox), x_(xy.first), y_(xy.second) { +Regular::Regular(Ranges xy, const area::BoundingBox& bbox, Projection* projection) : + Grid(bbox, projection), x_(xy.first), y_(xy.second) { ASSERT(x_ && x_->size() > 0); ASSERT(y_ && y_->size() > 0); } -Regular::Regular(std::pair xy) : x_(xy.first), y_(xy.second) { - ASSERT(x_ && x_->size() > 0); - ASSERT(y_ && y_->size() > 0); +void Regular::fill_spec(spec::Custom& custom) const { + Grid::fill_spec(custom); } -void Regular::fill_spec(spec::Custom& custom) const { - Grid::fill_spec(custom); +Regular::Ranges::Ranges(Range* x, Range* y) : pair{x, y} { + ASSERT(first != nullptr && second != nullptr); } diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index 524a2ac8c..4dd97569b 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -44,8 +44,6 @@ class Regular : public Grid { virtual size_t nx() const { return x_->size(); } virtual size_t ny() const { return y_->size(); } - [[nodiscard]] static std::pair make_lonlat_ranges_from_spec(const Spec&); - const Range& x() const; const Range& y() const; @@ -57,10 +55,15 @@ class Regular : public Grid { size_t size() const final { return nx() * ny(); } protected: + // -- Types + + struct Ranges : std::pair { + Ranges(Range*, Range*); + }; + // -- Constructors - Regular(std::pair xy, const area::BoundingBox& bbox); - Regular(std::pair xy); + explicit Regular(Ranges, const area::BoundingBox& = {}, Projection* = nullptr); // -- Overridden methods diff --git a/src/eckit/geo/grid/RegularXY.cc b/src/eckit/geo/grid/RegularXY.cc index 038c95731..aa3da4e1b 100644 --- a/src/eckit/geo/grid/RegularXY.cc +++ b/src/eckit/geo/grid/RegularXY.cc @@ -24,7 +24,7 @@ namespace eckit::geo::grid { -std::pair RegularXY::make_xy_ranges_from_spec(const Spec& spec) { +Regular::Ranges RegularXY::make_ranges_from_spec(const Spec& spec) { #if 0 Increments inc(spec); Shape shape(spec); diff --git a/src/eckit/geo/grid/RegularXY.h b/src/eckit/geo/grid/RegularXY.h index 68aa73534..a6c677cca 100644 --- a/src/eckit/geo/grid/RegularXY.h +++ b/src/eckit/geo/grid/RegularXY.h @@ -12,8 +12,6 @@ #pragma once -#include - #include "eckit/geo/grid/Regular.h" @@ -37,7 +35,7 @@ class RegularXY : public Regular { protected: // -- Methods - [[nodiscard]] static std::pair make_xy_ranges_from_spec(const Spec&); + [[nodiscard]] static Ranges make_ranges_from_spec(const Spec&); // -- Overridden methods diff --git a/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h index f99983fa1..987b453a1 100644 --- a/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h +++ b/src/eckit/geo/grid/regular-xy/LambertAzimuthalEqualArea.h @@ -22,7 +22,7 @@ class LambertAzimuthalEqualArea final : public RegularXY { public: // -- Constructors - explicit LambertAzimuthalEqualArea(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} + explicit LambertAzimuthalEqualArea(const Spec& spec) : RegularXY(RegularXY::make_ranges_from_spec(spec)) {} // -- Overridden methods diff --git a/src/eckit/geo/grid/regular-xy/LambertConformalConic.h b/src/eckit/geo/grid/regular-xy/LambertConformalConic.h index df4748392..197b7765c 100644 --- a/src/eckit/geo/grid/regular-xy/LambertConformalConic.h +++ b/src/eckit/geo/grid/regular-xy/LambertConformalConic.h @@ -22,7 +22,7 @@ class LambertConformalConic final : public RegularXY { public: // -- Constructors - explicit LambertConformalConic(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} + explicit LambertConformalConic(const Spec& spec) : RegularXY(RegularXY::make_ranges_from_spec(spec)) {} // -- Overridden methods diff --git a/src/eckit/geo/grid/regular-xy/Mercator.h b/src/eckit/geo/grid/regular-xy/Mercator.h index a5670cc81..40834ba78 100644 --- a/src/eckit/geo/grid/regular-xy/Mercator.h +++ b/src/eckit/geo/grid/regular-xy/Mercator.h @@ -22,7 +22,7 @@ class Mercator final : public RegularXY { public: // -- Constructors - explicit Mercator(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} + explicit Mercator(const Spec& spec) : RegularXY(RegularXY::make_ranges_from_spec(spec)) {} // -- Overridden methods diff --git a/src/eckit/geo/grid/regular-xy/PolarStereographic.h b/src/eckit/geo/grid/regular-xy/PolarStereographic.h index dec240351..a42530945 100644 --- a/src/eckit/geo/grid/regular-xy/PolarStereographic.h +++ b/src/eckit/geo/grid/regular-xy/PolarStereographic.h @@ -22,7 +22,7 @@ class PolarStereographic final : public RegularXY { public: // -- Constructors - explicit PolarStereographic(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} + explicit PolarStereographic(const Spec& spec) : RegularXY(RegularXY::make_ranges_from_spec(spec)) {} // -- Overridden methods diff --git a/src/eckit/geo/grid/regular-xy/SpaceView.h b/src/eckit/geo/grid/regular-xy/SpaceView.h index 58b213d72..85a0a9614 100644 --- a/src/eckit/geo/grid/regular-xy/SpaceView.h +++ b/src/eckit/geo/grid/regular-xy/SpaceView.h @@ -22,7 +22,7 @@ class SpaceView final : public RegularXY { public: // -- Constructors - explicit SpaceView(const Spec& spec) : RegularXY(RegularXY::make_xy_ranges_from_spec(spec)) {} + explicit SpaceView(const Spec& spec) : RegularXY(RegularXY::make_ranges_from_spec(spec)) {} // -- Overridden methods From 32a4e75cf891663968564aa6edb0df7e3b2a83e6 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 29 Jun 2024 03:36:03 +0100 Subject: [PATCH 734/737] eckit::geo::Grid --- src/eckit/geo/Grid.cc | 12 +++------ src/eckit/geo/Grid.h | 6 ++--- src/eckit/geo/area/BoundingBox.cc | 28 ++++++--------------- src/eckit/geo/area/BoundingBox.h | 6 ++--- src/eckit/geo/grid/Reduced.cc | 3 +++ src/eckit/geo/grid/Reduced.h | 2 +- src/eckit/geo/grid/ReducedGaussian.cc | 10 ++++---- src/eckit/geo/grid/ReducedGaussian.h | 4 +-- src/eckit/geo/grid/RegularGaussian.cc | 7 +++--- src/eckit/geo/grid/RegularGaussian.h | 2 +- src/eckit/geo/grid/RegularLL.cc | 36 ++++++++++++++------------- src/eckit/geo/grid/RegularLL.h | 4 +-- tests/geo/grid_regular_ll.cc | 4 +-- 13 files changed, 56 insertions(+), 68 deletions(-) diff --git a/src/eckit/geo/Grid.cc b/src/eckit/geo/Grid.cc index b6fdd0668..e61e68fa0 100644 --- a/src/eckit/geo/Grid.cc +++ b/src/eckit/geo/Grid.cc @@ -43,8 +43,8 @@ Grid::Grid(const Spec& spec) : Grid::Grid(Ordering ordering) : ordering_(ordering) {} -Grid::Grid(const area::BoundingBox& bbox, Ordering ordering) : - bbox_(new area::BoundingBox(bbox)), ordering_(ordering) {} +Grid::Grid(const area::BoundingBox& bbox, Projection* projection, Ordering ordering) : + bbox_(new area::BoundingBox(bbox)), projection_(projection), ordering_(ordering) {} const Spec& Grid::spec() const { @@ -181,7 +181,7 @@ Renumber Grid::no_reorder(size_t size) { void Grid::fill_spec(spec::Custom& custom) const { if (area_) { - static const auto AREA_DEFAULT(area::BoundingBox{}.spec_str()); + static const auto AREA_DEFAULT(area::BOUNDING_BOX_DEFAULT.spec_str()); std::unique_ptr area(area_->spec()); if (area->str() != AREA_DEFAULT) { @@ -190,11 +190,7 @@ void Grid::fill_spec(spec::Custom& custom) const { } if (projection_) { - std::unique_ptr projection(projection_->spec()); - - if (!projection->str().empty()) { - custom.set("projection", projection.release()); - } + projection_->fill_spec(custom); } } diff --git a/src/eckit/geo/Grid.h b/src/eckit/geo/Grid.h index d1cbd55c3..6e2af71a0 100644 --- a/src/eckit/geo/Grid.h +++ b/src/eckit/geo/Grid.h @@ -26,6 +26,7 @@ #include "eckit/geo/Projection.h" #include "eckit/geo/Renumber.h" #include "eckit/geo/area/BoundingBox.h" +#include "eckit/geo/projection/Rotation.h" #include "eckit/geo/spec/Custom.h" #include "eckit/geo/spec/Generator.h" #include "eckit/memory/Builder.h" @@ -139,7 +140,7 @@ class Grid { protected: // -- Constructors - explicit Grid(const area::BoundingBox&, Ordering = Ordering::DEFAULT); + explicit Grid(const area::BoundingBox&, Projection* = nullptr, Ordering = Ordering::DEFAULT); explicit Grid(Ordering = Ordering::DEFAULT); // -- Methods @@ -155,9 +156,8 @@ class Grid { // -- Members mutable std::unique_ptr area_; - mutable std::unique_ptr projection_; - mutable std::unique_ptr bbox_; + mutable std::unique_ptr projection_; mutable std::unique_ptr spec_; mutable uid_t uid_; diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index 2a06530df..d6853b99a 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -25,7 +25,7 @@ namespace eckit::geo::area { -static const auto& DEFAULT = BOUNDING_BOX_GLOBE_PRIME; +const BoundingBox BOUNDING_BOX_DEFAULT; static inline bool is_approximately_equal(BoundingBox::value_type a, BoundingBox::value_type b) { @@ -34,25 +34,26 @@ static inline bool is_approximately_equal(BoundingBox::value_type a, BoundingBox BoundingBox* BoundingBox::make_global_prime() { - return new BoundingBox(BOUNDING_BOX_GLOBE_PRIME); + return new BoundingBox{PointLonLat::RIGHT_ANGLE, 0., -PointLonLat::RIGHT_ANGLE, PointLonLat::FULL_ANGLE}; } BoundingBox* BoundingBox::make_global_antiprime() { - return new BoundingBox(BOUNDING_BOX_GLOBE_ANTIPRIME); + return new BoundingBox{PointLonLat::RIGHT_ANGLE, -PointLonLat::FLAT_ANGLE, -PointLonLat::RIGHT_ANGLE, + PointLonLat::FLAT_ANGLE}; } void BoundingBox::fill_spec(spec::Custom& custom) const { - if (operator!=(DEFAULT)) { - custom.set("type", "bounding-box"); + if (operator!=(BOUNDING_BOX_DEFAULT)) { + custom.set("area", "bounding-box"); custom.set("bounding-box", std::vector{north, west, south, east}); } } BoundingBox* BoundingBox::make_from_spec(const Spec& spec) { - auto [n, w, s, e] = DEFAULT.deconstruct(); + auto [n, w, s, e] = BOUNDING_BOX_DEFAULT.deconstruct(); if (std::vector area{n, w, s, e}; spec.get("area", area)) { ASSERT_MSG(area.size() == 4, "BoundingBox: 'area' expected list of size 4"); @@ -99,12 +100,6 @@ BoundingBox* BoundingBox::make_from_area(value_type n, value_type w, value_type } -BoundingBox::BoundingBox(const Spec& spec) : BoundingBox(*std::unique_ptr(make_from_spec(spec))) { - ASSERT(south <= north); - ASSERT(west <= east); -} - - BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s, e} { // normalise east in [west, west + 2 pi[ auto a = PointLonLat::normalise_angle_to_minimum(e, w); @@ -115,7 +110,7 @@ BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s } -BoundingBox::BoundingBox() : BoundingBox(DEFAULT) {} +BoundingBox::BoundingBox() : BoundingBox(*std::unique_ptr(make_global_prime())) {} bool BoundingBox::global() const { @@ -224,11 +219,4 @@ bool bounding_box_equal(const BoundingBox& a, const BoundingBox& b) { } -const BoundingBox BOUNDING_BOX_GLOBE_PRIME{PointLonLat::RIGHT_ANGLE, 0., -PointLonLat::RIGHT_ANGLE, - PointLonLat::FULL_ANGLE}; - -const BoundingBox BOUNDING_BOX_GLOBE_ANTIPRIME{PointLonLat::RIGHT_ANGLE, -PointLonLat::FLAT_ANGLE, -90., - PointLonLat::FLAT_ANGLE}; - - } // namespace eckit::geo::area diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index 71fe29aff..e737b4fb7 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -36,7 +36,7 @@ class BoundingBox : public Area, protected std::array { // -- Constructors - explicit BoundingBox(const Spec&); + explicit BoundingBox(const Spec& spec) : BoundingBox(*std::unique_ptr(make_from_spec(spec))) {} BoundingBox(value_type north, value_type west, value_type south, value_type east); @@ -105,9 +105,7 @@ class BoundingBox : public Area, protected std::array { constexpr PointLonLat::value_type BOUNDING_BOX_NORMALISE_WEST = -PointLonLat::FLAT_ANGLE; - -extern const BoundingBox BOUNDING_BOX_GLOBE_PRIME; -extern const BoundingBox BOUNDING_BOX_GLOBE_ANTIPRIME; +extern const BoundingBox BOUNDING_BOX_DEFAULT; } // namespace eckit::geo::area diff --git a/src/eckit/geo/grid/Reduced.cc b/src/eckit/geo/grid/Reduced.cc index ea08fd8cc..d3a7a265c 100644 --- a/src/eckit/geo/grid/Reduced.cc +++ b/src/eckit/geo/grid/Reduced.cc @@ -63,6 +63,9 @@ std::pair, std::vector> Reduced::to_latlon() const { } +Reduced::Reduced(const area::BoundingBox& bbox, Projection* projection) : Grid(bbox, projection) {} + + const std::vector& Reduced::niacc() const { if (niacc_.empty()) { niacc_.resize(1 + nj()); diff --git a/src/eckit/geo/grid/Reduced.h b/src/eckit/geo/grid/Reduced.h index 6f7ece7e4..16f5a51b9 100644 --- a/src/eckit/geo/grid/Reduced.h +++ b/src/eckit/geo/grid/Reduced.h @@ -37,7 +37,7 @@ class Reduced : public Grid { protected: // -- Constructors - using Grid::Grid; + explicit Reduced(const area::BoundingBox& = {}, Projection* = nullptr); // -- Methods diff --git a/src/eckit/geo/grid/ReducedGaussian.cc b/src/eckit/geo/grid/ReducedGaussian.cc index 1b92d40be..ca718306a 100644 --- a/src/eckit/geo/grid/ReducedGaussian.cc +++ b/src/eckit/geo/grid/ReducedGaussian.cc @@ -32,11 +32,11 @@ static size_t calculate_n(const pl_type& pl) { ReducedGaussian::ReducedGaussian(const Spec& spec) : - ReducedGaussian(spec.get_long_vector("pl"), area::BoundingBox(spec)) {} + ReducedGaussian(spec.get_long_vector("pl"), area::BoundingBox(spec), projection::Rotation::make_from_spec(spec)) {} -ReducedGaussian::ReducedGaussian(const pl_type& pl, const area::BoundingBox& bbox) : - Reduced(bbox), +ReducedGaussian::ReducedGaussian(const pl_type& pl, const area::BoundingBox& bbox, projection::Rotation* rotation) : + Reduced(bbox, rotation), N_(calculate_n(pl)), pl_(pl), j_(0), @@ -48,8 +48,8 @@ ReducedGaussian::ReducedGaussian(const pl_type& pl, const area::BoundingBox& bbo } -ReducedGaussian::ReducedGaussian(size_t N, const area::BoundingBox& bbox) : - ReducedGaussian(util::reduced_octahedral_pl(N), bbox) {} +ReducedGaussian::ReducedGaussian(size_t N, const area::BoundingBox& bbox, projection::Rotation* rotation) : + ReducedGaussian(util::reduced_octahedral_pl(N), bbox, rotation) {} Grid::iterator ReducedGaussian::cbegin() const { diff --git a/src/eckit/geo/grid/ReducedGaussian.h b/src/eckit/geo/grid/ReducedGaussian.h index 791323fe9..6b74c807e 100644 --- a/src/eckit/geo/grid/ReducedGaussian.h +++ b/src/eckit/geo/grid/ReducedGaussian.h @@ -28,8 +28,8 @@ class ReducedGaussian : public Reduced { // -- Constructors explicit ReducedGaussian(const Spec&); - explicit ReducedGaussian(const pl_type&, const area::BoundingBox& = {}); - explicit ReducedGaussian(size_t N, const area::BoundingBox& = {}); + explicit ReducedGaussian(const pl_type&, const area::BoundingBox& = {}, projection::Rotation* = nullptr); + explicit ReducedGaussian(size_t N, const area::BoundingBox& = {}, projection::Rotation* = nullptr); // -- Methods diff --git a/src/eckit/geo/grid/RegularGaussian.cc b/src/eckit/geo/grid/RegularGaussian.cc index 51b51d2fa..b7495bd1c 100644 --- a/src/eckit/geo/grid/RegularGaussian.cc +++ b/src/eckit/geo/grid/RegularGaussian.cc @@ -25,13 +25,14 @@ namespace eckit::geo::grid { RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian(spec.get_unsigned("N"), - *std::unique_ptr(area::BoundingBox::make_from_spec(spec))) {} + *std::unique_ptr(area::BoundingBox::make_from_spec(spec)), + projection::Rotation::make_from_spec(spec)) {} -RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox) : +RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox, projection::Rotation* rotation) : Regular({range::RegularLongitude(4 * N, 0., 360.).make_range_cropped(bbox.west, bbox.east), range::GaussianLatitude(N, false).make_range_cropped(bbox.north, bbox.south)}, - bbox), + bbox, rotation), N_(N) { ASSERT(size() > 0); } diff --git a/src/eckit/geo/grid/RegularGaussian.h b/src/eckit/geo/grid/RegularGaussian.h index 55fa91288..372bdde1e 100644 --- a/src/eckit/geo/grid/RegularGaussian.h +++ b/src/eckit/geo/grid/RegularGaussian.h @@ -23,7 +23,7 @@ class RegularGaussian final : public Regular { // -- Constructors explicit RegularGaussian(const Spec&); - explicit RegularGaussian(size_t N, const area::BoundingBox& = {}); + explicit RegularGaussian(size_t N, const area::BoundingBox& = {}, projection::Rotation* = nullptr); // -- Methods diff --git a/src/eckit/geo/grid/RegularLL.cc b/src/eckit/geo/grid/RegularLL.cc index e1ebf6cf1..0fe43a945 100644 --- a/src/eckit/geo/grid/RegularLL.cc +++ b/src/eckit/geo/grid/RegularLL.cc @@ -31,31 +31,33 @@ static const std::string REGULAR_LL_PATTERN("(" POSITIVE_REAL ")/(" POSITIVE_REA RegularLL::RegularLL(const Spec& spec) : - RegularLL(Increments{spec}, area::BoundingBox{spec}, [&spec]() -> PointLonLat { - std::vector v(2); - if (spec.get("reference_lon", v[0]) && spec.get("reference_lat", v[1])) { - return {v[0], v[1]}; - } - - if (spec.get("reference_lonlat", v) && v.size() == 2) { - return {v[0], v[1]}; - } - - area::BoundingBox area{spec}; - return {area.west, area.south}; - }()) { + RegularLL(Increments{spec}, area::BoundingBox{spec}, projection::Rotation::make_from_spec(spec), + [&spec]() -> PointLonLat { + std::vector v(2); + if (spec.get("reference_lon", v[0]) && spec.get("reference_lat", v[1])) { + return {v[0], v[1]}; + } + + if (spec.get("reference_lonlat", v) && v.size() == 2) { + return {v[0], v[1]}; + } + + area::BoundingBox area{spec}; + return {area.west, area.south}; + }()) { ASSERT(size() > 0); } -RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox) : - RegularLL(inc, bbox, {bbox.south, bbox.west}) {} +RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, projection::Rotation* rotation) : + RegularLL(inc, bbox, rotation, {bbox.south, bbox.west}) {} -RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, const PointLonLat& ref) : +RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, projection::Rotation* rotation, + const PointLonLat& ref) : Regular({new range::RegularLongitude(inc.dx, bbox.west, bbox.east, ref.lon, 0.), new range::RegularLatitude(inc.dy, bbox.north, bbox.south, ref.lat, 0.)}, - bbox) { + bbox, rotation) { ASSERT(size() > 0); } diff --git a/src/eckit/geo/grid/RegularLL.h b/src/eckit/geo/grid/RegularLL.h index 5c6bfd1bf..c54c75f27 100644 --- a/src/eckit/geo/grid/RegularLL.h +++ b/src/eckit/geo/grid/RegularLL.h @@ -23,8 +23,8 @@ class RegularLL final : public Regular { // -- Constructors explicit RegularLL(const Spec&); - explicit RegularLL(const Increments&, const area::BoundingBox& = {}); - RegularLL(const Increments&, const area::BoundingBox&, const PointLonLat& ref); + explicit RegularLL(const Increments&, const area::BoundingBox& = {}, projection::Rotation* = nullptr); + RegularLL(const Increments&, const area::BoundingBox&, projection::Rotation*, const PointLonLat& ref); // -- Methods diff --git a/tests/geo/grid_regular_ll.cc b/tests/geo/grid_regular_ll.cc index 9b5a1b2b2..2b7168aa0 100644 --- a/tests/geo/grid_regular_ll.cc +++ b/tests/geo/grid_regular_ll.cc @@ -33,8 +33,8 @@ CASE("global") { EXPECT(grid2->size() == 5 * 10); - for (const auto& grid : - {RegularLL({1., 1.}, {89.5, 0.5, -89.5, 359.5}), RegularLL({1., 1.}, {90., 0., -90, 360.}, {0.5, 0.5})}) { + for (const auto& grid : {RegularLL({1., 1.}, {89.5, 0.5, -89.5, 359.5}), + RegularLL({1., 1.}, {90., 0., -90, 360.}, nullptr, {0.5, 0.5})}) { EXPECT(grid.nx() == 360); EXPECT(grid.ny() == 180); EXPECT(grid.size() == 360 * 180); From 3f8166f194579956776531c861421de58a1f0a68 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 29 Jun 2024 03:37:33 +0100 Subject: [PATCH 735/737] eckit::geo::Projection --- src/eckit/geo/projection/Rotation.cc | 66 ++++++++++++++++++---------- src/eckit/geo/projection/Rotation.h | 31 ++++++++++--- src/eckit/geo/util.h | 1 - 3 files changed, 67 insertions(+), 31 deletions(-) diff --git a/src/eckit/geo/projection/Rotation.cc b/src/eckit/geo/projection/Rotation.cc index d68acde3d..c0fe1a944 100644 --- a/src/eckit/geo/projection/Rotation.cc +++ b/src/eckit/geo/projection/Rotation.cc @@ -28,41 +28,30 @@ namespace eckit::geo::projection { static ProjectionBuilder PROJECTION("rotation"); -Rotation::Rotation() : Rotation(-90., 0., 0.) {} +Rotation::Rotation(const PointLonLat& p, double angle) : Rotation(p.lon, p.lat, angle) {} -Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : rotated_(true) { +Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : + south_pole_(PointLonLat::make(south_pole_lon, south_pole_lat)), angle_(angle), rotated_(true) { using M = maths::Matrix3; struct NonRotated final : Implementation { PointLonLat operator()(const PointLonLat& p) const override { return p; } - void fill_spec(spec::Custom& custom) const override {} }; struct RotationAngle final : Implementation { explicit RotationAngle(double angle) : angle_(angle) {} PointLonLat operator()(const PointLonLat& p) const override { return {p.lon + angle_, p.lat}; } - void fill_spec(spec::Custom& custom) const override { custom.set("rotation_angle", angle_); } const double angle_; }; struct RotationMatrix final : Implementation { - explicit RotationMatrix(M&& R) : RotationMatrix(std::move(R), 0, 0, 0) {} - RotationMatrix(M&& R, double south_pole_lon, double south_pole_lat, double angle) : - R_(R), south_pole_lon_(south_pole_lon), south_pole_lat_(south_pole_lat), angle_(angle) {} + explicit RotationMatrix(M&& R) : R_(R) {} PointLonLat operator()(const PointLonLat& p) const override { return geometry::UnitSphere::convertCartesianToSpherical( R_ * geometry::UnitSphere::convertSphericalToCartesian(p)); } - void fill_spec(spec::Custom& custom) const override { - custom.set("south_pole_lon", south_pole_lon_); - custom.set("south_pole_lat", south_pole_lat_); - custom.set("rotation_angle", angle_); - } const M R_; - const double south_pole_lon_; - const double south_pole_lat_; - const double angle_; }; const auto alpha = util::DEGREE_TO_RADIAN * angle; @@ -73,9 +62,9 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : const auto ct = std::cos(theta); const auto cp = std::cos(phi); - if (types::is_approximately_equal(ct, 1., util::EPS)) { - angle = PointLonLat::normalise_angle_to_minimum(angle - south_pole_lon, -180.); - rotated_ = !types::is_approximately_equal(angle, 0., util::EPS); + if (types::is_approximately_equal(ct, 1., PointLonLat::EPS * util::DEGREE_TO_RADIAN)) { + angle_ = PointLonLat::normalise_angle_to_minimum(angle_ - south_pole_lon, -PointLonLat::FLAT_ANGLE); + rotated_ = !types::is_approximately_equal(angle_, 0., PointLonLat::EPS); fwd_.reset(rotated_ ? static_cast(new RotationAngle(-angle)) : new NonRotated); inv_.reset(rotated_ ? static_cast(new RotationAngle(angle)) : new NonRotated); @@ -93,7 +82,7 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : // q = Rz Ry Ra p = [ cosφ sinφ ] [ cosϑ sinϑ ] [ cosα sinα ] p // [ -sinφ cosφ ] [ 1 ] [ -sinα cosα ] // [ 1 ] [ -sinϑ cosϑ ] [ 1 ] - fwd_ = std::make_unique(M{ca * cp * ct - sa * sp, sa * cp * ct + ca * sp, + fwd_ = std::make_shared(M{ca * cp * ct - sa * sp, sa * cp * ct + ca * sp, cp * st, // -sa * cp - ca * ct * sp, ca * cp - sa * ct * sp, -sp * st, // @@ -103,21 +92,50 @@ Rotation::Rotation(double south_pole_lon, double south_pole_lat, double angle) : // p = Ra Ry Rz q = [ cosα -sinα ] [ cosϑ -sinϑ ] [ cosφ -sinφ ] q // [ sinα cosα ] [ 1 ] [ sinφ cosφ ] // [ 1 ] [ sinϑ cosϑ ] [ 1 ] - inv_ = std::make_unique(M{ca * cp * ct - sa * sp, -sa * cp - ca * ct * sp, + inv_ = std::make_shared(M{ca * cp * ct - sa * sp, -sa * cp - ca * ct * sp, -ca * st, // sa * cp * ct + ca * sp, ca * cp - sa * ct * sp, -sa * st, // cp * st, -sp * st, ct}); + + angle_ = PointLonLat::normalise_angle_to_minimum(angle_, -PointLonLat::FLAT_ANGLE); } -Rotation::Rotation(const Spec& spec) : - Rotation(spec.get_double("south_pole_lon"), spec.get_double("south_pole_lat"), spec.get_double("rotation_angle", 0)) {} +Rotation* Rotation::make_from_spec(const Spec& spec) { + double angle = 0.; + spec.get("rotation_angle", angle); + + auto lon = SOUTH_POLE.lon; + auto lat = SOUTH_POLE.lat; + if (std::vector r{lon, lat}; spec.get("rotation", r)) { + ASSERT_MSG(r.size() == 2, "Rotation: expected 'rotation' as a list of size 2"); + lon = r[0]; + lat = r[1]; + } + else { + ASSERT_MSG(spec.get("south_pole_lon", lon) == spec.get("south_pole_lat", lat), + "Rotation: expected 'south_pole_lon' and 'south_pole_lat'"); + } + + auto* r = new Rotation{lon, lat, angle}; + if (!r->rotated()) { + delete r; + r = nullptr; + } + + return r; +} void Rotation::fill_spec(spec::Custom& custom) const { - fwd_->fill_spec(custom); - custom.set("projection", "rotation"); + if (!points_equal(SOUTH_POLE, south_pole_)) { + custom.set("rotation", std::vector{south_pole_.lon, south_pole_.lat}); + } + if (!types::is_approximately_equal(angle_, 0., PointLonLat::EPS)) { + custom.set("rotation_angle", angle_); + } + // custom.set("projection", "rotation"); // it's a common projection (?) } diff --git a/src/eckit/geo/projection/Rotation.h b/src/eckit/geo/projection/Rotation.h index 454d0cf8c..965cf1543 100644 --- a/src/eckit/geo/projection/Rotation.h +++ b/src/eckit/geo/projection/Rotation.h @@ -25,9 +25,22 @@ class Rotation : public Projection { public: // -- Constructors - Rotation(); - Rotation(double south_pole_lon, double south_pole_lat, double angle); - explicit Rotation(const Spec&); + explicit Rotation(const Spec& spec) : Rotation(*std::unique_ptr(make_from_spec(spec))) {} + + Rotation(const PointLonLat& = SOUTH_POLE, double angle = 0); + Rotation(double south_pole_lon, double south_pole_lat, double angle = 0); + + Rotation(const Rotation&) = default; + Rotation(Rotation&&) = default; + + // -- Destructor + + ~Rotation() override = default; + + // -- Operators + + Rotation& operator=(const Rotation&) = default; + Rotation& operator=(Rotation&&) = default; // -- Methods @@ -41,6 +54,10 @@ class Rotation : public Projection { inline Point fwd(const Point& p) const override { return fwd(std::get(p)); } inline Point inv(const Point& q) const override { return inv(std::get(q)); } + // -- Class methods + + [[nodiscard]] static Rotation* make_from_spec(const Spec&); + protected: // -- Overridden methods @@ -59,13 +76,15 @@ class Rotation : public Projection { void operator=(Implementation&&) = delete; virtual PointLonLat operator()(const PointLonLat&) const = 0; - virtual void fill_spec(spec::Custom&) const = 0; }; // -- Members - std::unique_ptr fwd_; - std::unique_ptr inv_; + std::shared_ptr fwd_; + std::shared_ptr inv_; + + PointLonLat south_pole_; + double angle_; bool rotated_; }; diff --git a/src/eckit/geo/util.h b/src/eckit/geo/util.h index e409edc91..9e4557217 100644 --- a/src/eckit/geo/util.h +++ b/src/eckit/geo/util.h @@ -32,7 +32,6 @@ namespace util { constexpr double DEGREE_TO_RADIAN = M_PI / 180.; constexpr double RADIAN_TO_DEGREE = M_1_PI * 180.; -constexpr double EPS = 1e-12; template From f2aeebfdadf98ca9b2ca35f3f0de3897f4b79499 Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Sat, 29 Jun 2024 08:37:45 +0100 Subject: [PATCH 736/737] eckit::geo::Grid --- src/eckit/geo/grid/Regular.cc | 21 +++++++++++++++++++-- src/eckit/geo/grid/Regular.h | 2 +- src/eckit/geo/grid/RegularGaussian.cc | 2 +- src/eckit/geo/grid/RegularLL.cc | 2 +- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/eckit/geo/grid/Regular.cc b/src/eckit/geo/grid/Regular.cc index 7f1f10486..60c3f559a 100644 --- a/src/eckit/geo/grid/Regular.cc +++ b/src/eckit/geo/grid/Regular.cc @@ -12,6 +12,8 @@ #include "eckit/geo/grid/Regular.h" +#include + #include "eckit/exception/Exceptions.h" #include "eckit/geo/iterator/Regular.h" #include "eckit/geo/spec/Custom.h" @@ -21,6 +23,21 @@ namespace eckit::geo::grid { +namespace { + + +area::BoundingBox make_bounding_box(const Range& lon, const Range& lat) { + auto n = std::max(lat.a(), lat.b()); + auto w = std::min(lon.a(), lon.b()); + auto s = std::min(lat.a(), lat.b()); + auto e = std::max(lon.a(), lon.b()); + return {n, w, s, e}; +} + + +} // namespace + + double Regular::dx() const { return x().increment(); } @@ -53,8 +70,8 @@ const Range& Regular::y() const { } -Regular::Regular(Ranges xy, const area::BoundingBox& bbox, Projection* projection) : - Grid(bbox, projection), x_(xy.first), y_(xy.second) { +Regular::Regular(Ranges xy, Projection* projection) : + Grid(make_bounding_box(*xy.first, *xy.second), projection), x_(xy.first), y_(xy.second) { ASSERT(x_ && x_->size() > 0); ASSERT(y_ && y_->size() > 0); } diff --git a/src/eckit/geo/grid/Regular.h b/src/eckit/geo/grid/Regular.h index 4dd97569b..ff0adc5d2 100644 --- a/src/eckit/geo/grid/Regular.h +++ b/src/eckit/geo/grid/Regular.h @@ -63,7 +63,7 @@ class Regular : public Grid { // -- Constructors - explicit Regular(Ranges, const area::BoundingBox& = {}, Projection* = nullptr); + explicit Regular(Ranges, Projection* = nullptr); // -- Overridden methods diff --git a/src/eckit/geo/grid/RegularGaussian.cc b/src/eckit/geo/grid/RegularGaussian.cc index b7495bd1c..0f4090399 100644 --- a/src/eckit/geo/grid/RegularGaussian.cc +++ b/src/eckit/geo/grid/RegularGaussian.cc @@ -32,7 +32,7 @@ RegularGaussian::RegularGaussian(const Spec& spec) : RegularGaussian::RegularGaussian(size_t N, const area::BoundingBox& bbox, projection::Rotation* rotation) : Regular({range::RegularLongitude(4 * N, 0., 360.).make_range_cropped(bbox.west, bbox.east), range::GaussianLatitude(N, false).make_range_cropped(bbox.north, bbox.south)}, - bbox, rotation), + rotation), N_(N) { ASSERT(size() > 0); } diff --git a/src/eckit/geo/grid/RegularLL.cc b/src/eckit/geo/grid/RegularLL.cc index 0fe43a945..aea5cfaae 100644 --- a/src/eckit/geo/grid/RegularLL.cc +++ b/src/eckit/geo/grid/RegularLL.cc @@ -57,7 +57,7 @@ RegularLL::RegularLL(const Increments& inc, const area::BoundingBox& bbox, proje const PointLonLat& ref) : Regular({new range::RegularLongitude(inc.dx, bbox.west, bbox.east, ref.lon, 0.), new range::RegularLatitude(inc.dy, bbox.north, bbox.south, ref.lat, 0.)}, - bbox, rotation) { + rotation) { ASSERT(size() > 0); } From 784b4dc6e2adb07e4f7f70512b6b71fbebfe313d Mon Sep 17 00:00:00 2001 From: Pedro Maciel Date: Tue, 2 Jul 2024 22:24:16 +0100 Subject: [PATCH 737/737] eckit::geo::Area --- src/eckit/geo/area/BoundingBox.cc | 3 +++ src/eckit/geo/area/BoundingBox.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/eckit/geo/area/BoundingBox.cc b/src/eckit/geo/area/BoundingBox.cc index d6853b99a..f859df3fc 100644 --- a/src/eckit/geo/area/BoundingBox.cc +++ b/src/eckit/geo/area/BoundingBox.cc @@ -100,6 +100,9 @@ BoundingBox* BoundingBox::make_from_area(value_type n, value_type w, value_type } +BoundingBox::BoundingBox(const Spec& spec) : BoundingBox(*std::unique_ptr(make_from_spec(spec))) {} + + BoundingBox::BoundingBox(double n, double w, double s, double e) : array{n, w, s, e} { // normalise east in [west, west + 2 pi[ auto a = PointLonLat::normalise_angle_to_minimum(e, w); diff --git a/src/eckit/geo/area/BoundingBox.h b/src/eckit/geo/area/BoundingBox.h index e737b4fb7..8a2c02490 100644 --- a/src/eckit/geo/area/BoundingBox.h +++ b/src/eckit/geo/area/BoundingBox.h @@ -36,7 +36,7 @@ class BoundingBox : public Area, protected std::array { // -- Constructors - explicit BoundingBox(const Spec& spec) : BoundingBox(*std::unique_ptr(make_from_spec(spec))) {} + explicit BoundingBox(const Spec&); BoundingBox(value_type north, value_type west, value_type south, value_type east);