IODA Bundle
RegionCache.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 1996-2012 ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation nor
8  * does it submit to any jurisdiction.
9  */
10 
12 #include "eckit/thread/ThreadSingleton.h"
13 
14 using namespace eckit;
15 
16 namespace odc {
17 namespace sql {
18 namespace function {
19 
20 static ThreadSingleton<VectorRegionCache> region_cache_;
21 
22 double mfmod(double x, double y) {
23  double a = x / y;
24  return (a - int(a)) * y;
25 }
26 
27 
28 RegionCache::RegionCache() :
29  nboxes_(0), resol_(0), nbands_(0), latband_(0), midlat_(0), loncnt_(0), sum_loncnt_(0), stlon_(0), deltalon_(0) {}
30 
31 
33 
35  return region_cache_.instance();
36 }
37 
38 
39 double RegionCache::get_resol(const double& nval) {
40  return -1;
41 }
42 
43 int RegionCache::interval_bsearch(const double& key, const int& n, const double x[/* with n+1 elements */],
44  const double* delta, /* if present, only x[0] will be used */
45  const double& add, const double& sign /* +1 forward and -1 for reverse search */)
46 
47 {
48  const double eps = 1.0e-7;
49  double Delta = delta ? *delta : 0;
50  bool wrap_around = (delta && add != 0) ? true : false;
51  double halfDelta = Delta / 2;
52  double x0 = x[0] + halfDelta;
53  double Key = wrap_around ? sign * mfmod(key + halfDelta + add, add) : sign * (key + halfDelta);
54  int lo = 0, hi = n - 1;
55  while (lo <= hi) {
56  int k = (lo + hi) / 2;
57  double xk = wrap_around ? sign * mfmod(x0 + k * Delta + add, add) : sign * (x[k] + halfDelta);
58  if (wrap_around && k > 0 && std::abs(xk) < eps)
59  xk = add;
60  if (Key < xk) {
61  // Search the lower section
62  hi = k - 1;
63  }
64  else {
65  int kp1 = k + 1;
66  double xkp1 = wrap_around ? sign * mfmod(x0 + kp1 * Delta + add, add) : sign * (x[kp1] + halfDelta);
67  if (wrap_around && std::abs(xkp1) < eps)
68  xkp1 = add;
69  if (Key > xkp1) {
70  // Search the upper section
71  lo = kp1;
72  }
73  else {
74  // The interval has been found
75  return k;
76  }
77  }
78  }
79  return -1;
80 }
81 
82 
83 int RegionCache::find_lonbox(const int& jb, const double& lon, double* midlon, double* leftlon, double* rightlon) {
84  const double three_sixty = 360;
85  double mid = 0; // odb::MDI::realMDI();
86  double left = 0; // odb::MDI::realMDI();
87  double right = 0; // odb::MDI::realMDI();
88  int boxid = -1;
89  if (jb >= 0 && jb < *nbands_) {
90  double Lon = mfmod(lon + three_sixty, three_sixty);
91  double deltalon = deltalon_[jb];
92  if (last_->boxid >= 0) {
93  int k = last_->lonbox;
94  double startlon = stlon_[jb] + k * deltalon;
95  double endlon = stlon_[jb] + (k + 1) * deltalon;
96  startlon = mfmod(startlon + three_sixty, three_sixty);
97  endlon = mfmod(endlon + three_sixty, three_sixty);
98  if (endlon >= startlon) {
99  if (Lon >= startlon && Lon < endlon)
100  boxid = last_->boxid;
101  }
102  else {
103  if ((Lon >= 0 && Lon < endlon) || (Lon >= startlon && Lon < three_sixty))
104  boxid = last_->boxid;
105  }
106  }
107 
108  if (boxid == -1) {
109  const double* stlon = &stlon_[jb];
110  int loncnt = loncnt_[jb];
111  int lonbox = interval_bsearch(lon, loncnt, stlon, &deltalon, three_sixty, +1);
112  if (lonbox != -1) {
113  int k = lonbox;
114  left = (*stlon) + k * deltalon;
115  mid = (*stlon) + (k + 0.5) * deltalon;
116  right = (*stlon) + (k + 1) * deltalon;
117 
118  last_->left = left = mfmod(left + three_sixty, three_sixty);
119  last_->mid = mid = mfmod(mid + three_sixty, three_sixty);
120  last_->right = right = mfmod(right + three_sixty, three_sixty);
121 
122  last_->jb = jb;
123  last_->lonbox = k;
124  last_->boxid = boxid = sum_loncnt_[jb] + k;
125  }
126  }
127  else {
128  left = last_->left;
129  mid = last_->mid;
130  right = last_->right;
131  }
132  }
133  if (midlon) {
134  const double one_eighty = 180;
135  if (mid > one_eighty)
136  mid -= three_sixty;
137  *midlon = mid;
138  }
139  if (leftlon)
140  *leftlon = left;
141  if (rightlon)
142  *rightlon = right;
143  return boxid;
144 }
145 
146 int RegionCache::find_latband(const double& lat) {
147  int jb;
148  int lastjb = last_->jb;
149  if (lastjb >= 0 &&
150  /* Note: In the following we go from N->S pole, not S->N ==> thus the minus sign!! */
151  -lat >= -latband_[lastjb] && -lat < -latband_[lastjb + 1]) {
152  jb = lastjb;
153  }
154  else if (lastjb == *nbands_ - 1 && lat == latband_[lastjb + 1]) {
155  /* Exactly at the South pole */
156  jb = lastjb;
157  }
158  else {
159  jb = interval_bsearch(lat, *nbands_, latband_, NULL, 0, -1);
160  if (jb != -1) {
161  // New latitude band found
162  last_->jb = jb;
163  // Don't know anything about the final box numbers yet
164  last_->lonbox = -1;
165  last_->boxid = -1;
166  }
167  }
168 
169  return jb;
170 }
171 
172 
173 double RegionCache::get_midlat(const double& resol, const double& lat) {
174  double res = 0; // odb::MDI::realMDI(); // should be initialised to missing
175  get_cache(resol);
176  int jb = find_latband(lat);
177  if (jb >= 0 && jb < *nbands_) {
178  res = midlat_[jb];
179  }
180  return res;
181 }
182 
183 
184 double RegionCache::get_midlon(const double& resol, const double& lat, const double& lon) {
185  double res = 0; // odb::MDI::realMDI(); // should be initialised to missing
186  get_cache(resol);
187  int jb = find_latband(lat);
188  int boxid = find_lonbox(jb, lon, &res, NULL, NULL);
189  boxid = boxid;
190 
191  return res;
192 }
193 
194 
195 void RegionCache::get_cache(const double& nval) {
196  double resol = get_resol(nval);
197  bool cache_save = true;
198  int n = resol;
199  // We need to check whether it was already done for this resolution
200  VectorRegionCache::const_iterator it_cache = instance().begin();
201 
202  while (it_cache != instance().end() && cache_save) {
203  RegionCache* cache = const_cast<RegionCache*>(*it_cache);
204  if (resol == *(cache->resol_)) {
205  cache_save = false; // not need to do it because we have it already!
206  kind_ = cache->kind_;
207  resol_ = cache->resol_;
208  nbands_ = cache->nbands_;
209  latband_ = cache->latband_;
210  midlat_ = cache->midlat_;
211  loncnt_ = cache->loncnt_;
212  stlon_ = cache->stlon_;
213  deltalon_ = cache->deltalon_;
214  nboxes_ = cache->nboxes_;
215  sum_loncnt_ = cache->sum_loncnt_;
216  last_ = cache->last_;
217  }
218  else {
219  ++it_cache;
220  }
221  }
222  if (cache_save)
223  create_cache(resol, n);
224 }
225 
226 void RegionCache::create_cache(const double& resol, const int& n) {
227  // to be overloaded because it is specific to the grid
228 }
229 
230 
231 void RegionCache::put_cache(const RegionCacheKind& kind, const double& resol, const int& nb, double latband[],
232  double midlat[], double stlon[], double deltalon[], int loncnt[]) {
233  VectorRegionCache* p = &(region_cache_.instance());
234  int nelm = p->size();
235  p->resize(nelm + 1);
236  p->at(nelm) = new RegionCache;
237  p->at(nelm)->kind_ = new RegionCacheKind;
238  *(p->at(nelm)->kind_) = kind;
239  p->at(nelm)->resol_ = new double;
240  *(p->at(nelm)->resol_) = resol;
241  p->at(nelm)->nbands_ = new int;
242  *(p->at(nelm)->nbands_) = nb;
243  resol_ = p->at(nelm)->resol_;
244  nbands_ = p->at(nelm)->nbands_;
245  kind_ = p->at(nelm)->kind_;
246  p->at(nelm)->latband_ = latband;
247  p->at(nelm)->midlat_ = midlat;
248  p->at(nelm)->loncnt_ = loncnt;
249  p->at(nelm)->stlon_ = stlon;
250  p->at(nelm)->deltalon_ = deltalon;
251  latband_ = latband;
252  midlat_ = midlat;
253  loncnt_ = loncnt;
254  stlon_ = stlon;
255  deltalon_ = deltalon;
256 
257  {
258  int jb, sum = 0;
259  p->at(nelm)->sum_loncnt_ = new int[nb];
260  for (jb = 0; jb < nb; jb++) {
261  p->at(nelm)->sum_loncnt_[jb] = sum;
262  sum += loncnt[jb];
263  }
264  p->at(nelm)->nboxes_ = new int;
265  *(p->at(nelm)->nboxes_) = sum;
266  nboxes_ = p->at(nelm)->nboxes_;
267  sum_loncnt_ = p->at(nelm)->sum_loncnt_;
268  }
269  p->at(nelm)->last_ = new Last;
270  p->at(nelm)->last_->jb = -1;
271  p->at(nelm)->last_->lonbox = -1;
272  p->at(nelm)->last_->boxid = -1;
273  last_ = p->at(nelm)->last_;
274 }
275 
276 } // namespace function
277 } // namespace sql
278 } // namespace odc
double get_midlon(const double &, const double &, const double &)
Definition: RegionCache.cc:184
static VectorRegionCache & instance()
Definition: RegionCache.cc:34
virtual double get_resol(const double &val)
Definition: RegionCache.cc:39
int interval_bsearch(const double &, const int &, const double[], const double *, const double &, const double &)
Definition: RegionCache.cc:43
void get_cache(const double &)
Definition: RegionCache.cc:195
void put_cache(const RegionCacheKind &kind, const double &, const int &, double[], double[], double[], double[], int[])
Definition: RegionCache.cc:231
virtual void create_cache(const double &, const int &)
Definition: RegionCache.cc:226
int find_latband(const double &)
Definition: RegionCache.cc:146
double get_midlat(const double &, const double &)
Definition: RegionCache.cc:173
int find_lonbox(const int &, const double &, double *, double *, double *)
Definition: RegionCache.cc:83
double mfmod(double x, double y)
Definition: RegionCache.cc:22
std::vector< RegionCache * > VectorRegionCache
Definition: RegionCache.h:39
static ThreadSingleton< VectorRegionCache > region_cache_
Definition: RegionCache.cc:20
Definition: ColumnInfo.h:23