eccodes/src/grib_iterator_class_gaussian.c

224 lines
6.3 KiB
C
Raw Normal View History

2013-03-25 12:04:10 +00:00
/*
2020-01-28 14:32:34 +00:00
* (C) Copyright 2005- ECMWF.
2013-03-25 12:04:10 +00:00
*
* This software is licensed under the terms of the Apache Licence Version 2.0
* which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
*
* In applying this licence, ECMWF does not 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 <math.h>
/*
This is used by make_class.pl
START_CLASS_DEF
CLASS = iterator
SUPER = grib_iterator_class_regular
IMPLEMENTS = init
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*);
2020-01-22 13:10:59 +00:00
static int init (grib_iterator* i,grib_handle*,grib_arguments*);
2020-01-22 13:10:59 +00:00
typedef struct grib_iterator_gaussian{
grib_iterator it;
2020-01-22 13:10:59 +00:00
/* Members defined in gen */
long carg;
const char* missingValue;
/* Members defined in regular */
double *las;
double *los;
long Ni;
long Nj;
2020-01-22 13:10:59 +00:00
long iScansNegatively;
long isRotated;
double angleOfRotation;
double southPoleLat;
double southPoleLon;
long jPointsAreConsecutive;
long disableUnrotate;
/* Members defined in gaussian */
2013-03-25 12:04:10 +00:00
} grib_iterator_gaussian;
extern grib_iterator_class* grib_iterator_class_regular;
static grib_iterator_class _grib_iterator_class_gaussian = {
&grib_iterator_class_regular, /* super */
"gaussian", /* name */
sizeof(grib_iterator_gaussian),/* size of instance */
0, /* inited */
&init_class, /* init_class */
&init, /* constructor */
0, /* destructor */
0, /* Next Value */
0, /* Previous Value */
0, /* Reset the counter */
0, /* has next values */
2013-03-25 12:04:10 +00:00
};
grib_iterator_class* grib_iterator_class_gaussian = &_grib_iterator_class_gaussian;
static void init_class(grib_iterator_class* c)
{
c->next = (*(c->super))->next;
c->previous = (*(c->super))->previous;
c->reset = (*(c->super))->reset;
c->has_next = (*(c->super))->has_next;
2013-03-25 12:04:10 +00:00
}
/* END_CLASS_IMP */
2022-10-19 15:30:45 +00:00
static void binary_search_gaussian_latitudes(const double xx[], const unsigned long n, double x, long* j);
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
static int init(grib_iterator* i, grib_handle* h, grib_arguments* args)
{
2013-07-23 16:21:08 +00:00
grib_iterator_gaussian* self = (grib_iterator_gaussian*)i;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
double* lats;
double laf; /* latitude of first point in degrees */
double lal; /* latitude of last point in degrees */
long trunc; /* number of parallels between a pole and the equator */
2022-10-19 15:30:45 +00:00
long lai = 0;
2020-01-22 13:10:59 +00:00
long jScansPositively = 0;
2022-10-19 15:30:45 +00:00
int size = 0;
2013-07-23 16:21:08 +00:00
double start;
long istart = 0;
2022-10-19 15:30:45 +00:00
int ret = GRIB_SUCCESS;
2020-01-22 13:10:59 +00:00
const char* latofirst = grib_arguments_get_name(h, args, self->carg++);
const char* latoflast = grib_arguments_get_name(h, args, self->carg++);
const char* numtrunc = grib_arguments_get_name(h, args, self->carg++);
const char* s_jScansPositively = grib_arguments_get_name(h, args, self->carg++);
if ((ret = grib_get_double_internal(h, latofirst, &laf)))
return ret;
if ((ret = grib_get_double_internal(h, latoflast, &lal)))
return ret;
if ((ret = grib_get_long_internal(h, numtrunc, &trunc)))
return ret;
if ((ret = grib_get_long_internal(h, s_jScansPositively, &jScansPositively)))
2013-07-23 16:21:08 +00:00
return ret;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
start = laf;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
size = trunc * 2;
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
lats = (double*)grib_context_malloc(h->context, size * sizeof(double));
2013-03-25 12:04:10 +00:00
2013-07-23 16:21:08 +00:00
ret = grib_get_gaussian_latitudes(trunc, lats);
2013-03-25 12:04:10 +00:00
2020-01-22 13:10:59 +00:00
if (ret != GRIB_SUCCESS) {
grib_context_log(h->context, GRIB_LOG_ERROR, "error %d calculating gaussian points", ret);
2013-07-23 16:21:08 +00:00
return ret;
}
2016-02-09 18:00:49 +00:00
/*
for(loi=(trunc*2)-1;loi>=0;loi--)
if(fabs(lats[loi] - lal) < glatPrecision) break;
for(j=(trunc*2)-1;j>0;j--) {
if(fabs(lats[j] - laf) < glatPrecision) break;
}
2016-02-09 18:00:49 +00:00
*/
2013-03-25 12:04:10 +00:00
2022-10-19 15:30:45 +00:00
binary_search_gaussian_latitudes(lats, size-1, start, &istart);
Assert(istart >= 0);
Assert(istart < size);
2013-03-25 12:04:10 +00:00
2013-07-23 16:21:08 +00:00
if (jScansPositively) {
2020-03-14 13:07:01 +00:00
for (lai = 0; lai < self->Nj; lai++) {
DebugAssert(istart >= 0);
2013-07-23 16:21:08 +00:00
self->las[lai] = lats[istart--];
if (istart<0) istart=size-1;
2013-07-23 16:21:08 +00:00
}
2020-01-22 13:10:59 +00:00
}
else {
2020-03-14 13:07:01 +00:00
for (lai = 0; lai < self->Nj; lai++) {
2013-07-23 16:21:08 +00:00
self->las[lai] = lats[istart++];
2020-01-22 13:10:59 +00:00
if (istart > size - 1)
istart = 0;
2013-07-23 16:21:08 +00:00
}
2013-03-25 12:04:10 +00:00
}
2020-01-22 13:10:59 +00:00
grib_context_free(h->context, lats);
2013-03-25 12:04:10 +00:00
2013-07-23 16:21:08 +00:00
return ret;
2013-03-25 12:04:10 +00:00
}
2022-10-19 15:30:45 +00:00
#define EPSILON 1e-3
2022-10-18 16:43:20 +00:00
/* Note: the argument 'n' is NOT the size of the 'xx' array but its LAST index i.e. size of xx - 1 */
2022-10-19 15:30:45 +00:00
static void binary_search_gaussian_latitudes(const double array[], const unsigned long n, double x, long* j)
2013-03-25 12:04:10 +00:00
{
2022-10-19 15:30:45 +00:00
unsigned long low = 0;
unsigned long high = n;
unsigned long mid;
const int descending = (array[n] < array[0]);
Assert(descending); /* Gaussian latitudes should be in descending order */
while (low <= high) {
mid = (high + low) / 2;
if (fabs(x - array[mid]) < EPSILON) {
*j = mid;
return;
}
2022-10-19 15:30:45 +00:00
if (x < array[mid])
low = mid + 1;
else
high = mid - 1;
}
*j = -1; /* Not found */
}
#if 0
static void binary_search_old(const double xx[], const unsigned long n, double x, long* j)
{
/*This routine works only on descending ordered arrays*/
2020-01-22 13:10:59 +00:00
unsigned long ju, jm, jl;
jl = 0;
ju = n;
if (fabs(x - xx[0]) < EPSILON) {
*j = 0;
return;
}
if (fabs(x - xx[n]) < EPSILON) {
*j = n;
return;
}
2020-01-22 13:10:59 +00:00
while (ju - jl > 1) {
jm = (ju + jl) >> 1;
if (fabs(x - xx[jm]) < EPSILON) {
/* found something close enough. We're done */
2020-01-22 13:10:59 +00:00
*j = jm;
return;
}
2020-01-22 13:10:59 +00:00
if (x < xx[jm])
jl = jm;
else
ju = jm;
2013-07-23 16:21:08 +00:00
}
2020-01-22 13:10:59 +00:00
*j = jl;
2013-03-25 12:04:10 +00:00
}
2022-10-19 15:30:45 +00:00
#endif