IODA Bundle
RggRegionCache.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 
11 #include <cmath>
12 #include <cstring>
13 #include <fstream>
14 
15 #include "eckit/config/Resource.h"
16 #include "eckit/filesystem/PathName.h"
17 #include "eckit/log/Log.h"
19 
20 using namespace eckit;
21 
22 namespace odc {
23 namespace sql {
24 namespace function {
25 
26 RggRegionCache::RggRegionCache() : RegionCache() {}
27 
29 
30 double RggRegionCache::get_resol(const double& nval) {
31  return nval;
32 }
33 
34 /// Reads F90 namelist file $ODB_RTABLE_PATH/rtablel_2<xxxx>
35 /// to find out how many latitude bands there are (must be xxxx+1)
36 /// and how many longitudes boxes per latband there are */
37 int* RggRegionCache::read_rtablel_2_file(const int& Txxxx, int* NRGRI_len, int* Nlons) {
38  int* NRGRI = NULL;
39  int nb = 0;
40  int nlons = 0;
41  int nexp = Txxxx + 1; /* Expect this many latitude bands */
42 
43  std::string rtable_file;
44  std::stringstream sr;
45  sr.width(3);
46  sr.setf(std::ios_base::right, std::ios_base::adjustfield);
47  sr.fill('0');
48 
49  // I use an environment variable; changing DHSHOME does not work...
50  PathName fpath = Resource<PathName>("$ODB_RTABLE_PATH", "~/odb/include");
51  sr << Txxxx;
52  rtable_file = fpath + "/rtablel_2" + sr.str();
53 
54  Log::info() << " gaussian grid table = " << rtable_file << std::endl;
55  std::ifstream input(rtable_file.c_str());
56  if (input) {
57  NRGRI = new int[nexp];
58  char line[1024];
59  // char *lb;
60  // char *rb;
61  // char *eq;
62  while (input.getline(line, sizeof(line) - 1)) {
63  char* lb = strchr(line, '(');
64  char* rb = lb ? strchr(line, ')') : NULL;
65  char* eq = rb ? strchr(line, '=') : NULL;
66  if (lb && rb && rb) {
67  if (lb < rb && rb < eq) {
68  char* comma = strchr(line, ',');
69  int id = 0;
70  int npts = 0;
71  if (comma && eq < comma)
72  *comma = '\0';
73  ++lb;
74  *rb = '\0';
75  ++eq;
76  id = atoi(lb) - 1;
77  npts = atoi(eq);
78  if (id >= 0 && id < nexp && npts > 0) {
79  NRGRI[id] = npts;
80  nlons += npts;
81  }
82  }
83  }
84  }
85  nb = nexp;
86  }
87  else {
88  Log::info() << "read_rtablel_2_file(): Unsupported resolution Txxxx = " << Txxxx
89  << " or $ODB_RTABLE_PATH not defined" << std::endl;
90  }
91 
92  if (NRGRI_len)
93  *NRGRI_len = nb;
94  if (Nlons)
95  *Nlons = nlons;
96 
97  return NRGRI;
98 }
99 
100 /// compute knum zeros, or if knum>50, knum approximate zeros of the
101 /// bessel function J0.
102 ///
103 /// pbes - array, imensione knum, to receive the values
104 /// knum - number of zeros requeste.
105 ///
106 /// Method:
107 /// -------
108 /// The first 50 values are obtained from a lookup table.
109 /// Any additional values requested are interpolated.
110 ///
111 void RggRegionCache::bsslzr(double pbes[], const int& knum) {
112  int inum;
113 
114  double zapi, zpi;
115 
116  double zbes[50];
117 
118  zbes[0] = 2.4048255577e0;
119  zbes[1] = 5.5200781103e0;
120  zbes[2] = 8.6537279129e0;
121  zbes[3] = 11.7915344391e0;
122  zbes[4] = 14.9309177086e0;
123  zbes[5] = 18.0710639679e0;
124  zbes[6] = 21.2116366299e0;
125  zbes[7] = 24.3524715308e0;
126  zbes[8] = 27.4934791320e0;
127  zbes[9] = 30.6346064684e0;
128  zbes[10] = 33.7758202136e0;
129  zbes[11] = 36.9170983537e0;
130  zbes[12] = 40.0584257646e0;
131  zbes[13] = 43.1997917132e0;
132  zbes[14] = 46.3411883717e0;
133  zbes[15] = 49.4826098974e0;
134  zbes[16] = 52.6240518411e0;
135  zbes[17] = 55.7655107550e0;
136  zbes[18] = 58.9069839261e0;
137  zbes[19] = 62.0484691902e0;
138  zbes[20] = 65.1899648002e0;
139  zbes[21] = 68.3314693299e0;
140  zbes[22] = 71.4729816036e0;
141  zbes[23] = 74.6145006437e0;
142  zbes[24] = 77.7560256304e0;
143  zbes[25] = 80.8975558711e0;
144  zbes[26] = 84.0390907769e0;
145  zbes[27] = 87.1806298436e0;
146  zbes[28] = 90.3221726372e0;
147  zbes[29] = 93.4637187819e0;
148  zbes[30] = 96.6052679510e0;
149  zbes[31] = 99.7468198587e0;
150  zbes[32] = 102.8883742542e0;
151  zbes[33] = 106.0299309165e0;
152  zbes[34] = 109.1714896498e0;
153  zbes[35] = 112.3130502805e0;
154  zbes[36] = 115.4546126537e0;
155  zbes[37] = 118.5961766309e0;
156  zbes[38] = 121.7377420880e0;
157  zbes[39] = 124.8793089132e0;
158  zbes[40] = 128.0208770059e0;
159  zbes[41] = 131.1624462752e0;
160  zbes[42] = 134.3040166383e0;
161  zbes[43] = 137.4455880203e0;
162  zbes[44] = 140.5871603528e0;
163  zbes[45] = 143.7287335737e0;
164  zbes[46] = 146.8703076258e0;
165  zbes[47] = 150.0118824570e0;
166  zbes[48] = 153.1534580192e0;
167  zbes[49] = 156.2950342685e0;
168 
169  //
170  // 1. Extract values from look up table.
171  //
172  zapi = 2.0e0 * asin(1.0e0);
173  inum = std::min(knum, 50);
174 
175  for (int j = 0; j < inum; j++)
176  pbes[j] = zbes[j];
177 
178  //
179  // 2. Interpolate remaining values
180  //
181  if (knum > 50) {
182  zpi = zapi;
183  for (int j = 50; j < knum; j++)
184  pbes[j] = pbes[j - 1] + zpi;
185  }
186 }
187 
188 
189 /// gauaw - compute abscissas and weights for gaussian integration
190 int RggRegionCache::gauaw(double pa[], double pw[], const int& k) {
191  double zeps = 1e-14;
192  double zpi, zc, zxz, zkm2, zkm1, zfn, zkmrk, zsp, zvsp;
193  double zpk = 0;
194  int ifk, ikk, /*js,*/ iter, jn, il;
195  int iret;
196 
197  // ------------------------------------------------------------------
198  // 1. set constants and find zeros of bessel function.
199 
200  iret = 0;
201  zpi = 2.0e0 * asin(1.0e0);
202  zc = (1.0e0 - pow((2.0e0 / zpi), 2)) * 0.25e0;
203  ifk = k;
204  ikk = k / 2;
205 
206  bsslzr(pa, ikk);
207 
208  bool cont = true;
209  for (int js = 0; js < ikk; js++) {
210  zxz = cos(pa[js] / sqrt(pow((ifk + 0.5e0), 2) + zc));
211  iter = 0;
212  cont = true;
213  do {
214  // ------------------------------------------------------------------
215  // 2. Compute abscissas an weights.
216 
217  // 2.1 set values for next iteration.
218 
219  zkm2 = 1.0e0;
220  zkm1 = zxz;
221  ++iter;
222  if (iter > 10) {
223  cont = false;
224  iret = 10;
225  }
226  else {
227  // 2.2 Computation of the legendre polynomial.
228  for (jn = 2; jn <= k; jn++) {
229  zfn = jn;
230  zpk = ((2.0e0 * zfn - 1.0e0) * zxz * zkm1 - (zfn - 1.0e0) * zkm2) / zfn;
231  zkm2 = zkm1;
232  zkm1 = zpk;
233  }
234 
235  zkm1 = zkm2;
236  zkmrk = (ifk * (zkm1 - zxz * zpk)) / (1.0e0 - zxz * zxz);
237  zsp = zpk / zkmrk;
238  zxz = zxz - zsp;
239  zvsp = fabs(zsp);
240  if (zvsp <= zeps)
241  cont = false;
242  }
243 
244  } while (cont);
245 
246  // 2.3 Abscissas and weights.
247  if (iter <= 10) {
248  pa[js] = zxz;
249  pw[js] = (2.0e0 * (1.0e0 - zxz * zxz)) / pow((ifk * zkm1), 2);
250 
251  // 2.4 odd k computation of weight at the equator
252  if (k != ikk * 2) {
253  pa[ikk] = 0.0e0;
254  zpk = 2.0e0 / (ifk * ifk);
255  for (jn = 2; jn <= k; jn += 2) {
256  zfn = jn;
257  zpk = zpk * zfn * zfn / pow((zfn - 1.0e0), 2);
258  }
259  pw[ikk] = zpk;
260  }
261  else {
262  for (jn = 0; jn < ikk; jn++) {
263  il = k - jn - 1;
264  pa[il] = -pa[jn];
265  pw[il] = pw[jn];
266  }
267  }
268  }
269  }
270  return iret;
271 }
272 
273 void RggRegionCache::create_cache(const double& resol, const int& n) {
274  // nothing done for this resolution
275  int ndgl = n + 1; // Number of latitude bands i.e. "nb"
276  int nlons = 0;
277  int* loncnt = read_rtablel_2_file(n, &ndgl, &nlons);
278  double* latband = NULL;
279  double* midlat = NULL;
280  double* stlon = NULL;
281  double* deltalon = NULL;
282  double* zlmu = NULL;
283  double* zw = NULL;
284  double* zlatedge = NULL;
285  const double zfact = piconst::recip_pi_over_180;
286  double zfact2 = ((double)45) / atan((double)1);
287  int ii, iequator = ndgl / 2;
288 
289  zlmu = new double[ndgl];
290  zw = new double[ndgl];
291 
292  gauaw(zlmu, zw, ndgl);
293 
294  midlat = zlmu;
295  for (ii = 0; ii < ndgl; ii++)
296  midlat[ii] = zfact2 * asin(zlmu[ii]);
297 
298  zlatedge = new double[ndgl + 1];
299  zlatedge[0] = piconst::half_pi;
300  for (ii = 0; ii < ndgl / 2; ii++)
301  zlatedge[ii + 1] = asin(std::max(-1.0, std::min(1.0, sin(zlatedge[ii]) - zw[ii])));
302 
303  delete[] zw;
304 
305  zlatedge[iequator] = 0;
306 
307  for (ii = iequator + 1; ii < ndgl + 1; ii++)
308  zlatedge[ii] = -zlatedge[ndgl - ii];
309 
310  latband = new double[ndgl + 1];
311 
312  for (ii = 0; ii < ndgl + 1; ii++)
313  latband[ii] = zfact * zlatedge[ii];
314 
315  delete[] zlatedge;
316 
317  // Starting longitudes, deltalon's
318 
319  stlon = new double[ndgl];
320  deltalon = new double[ndgl];
321 
322  {
323  int cnt;
324  const double three_sixty = 360;
325  for (ii = 0; ii < ndgl; ii++) {
326  cnt = loncnt[ii];
327  double delta = three_sixty / cnt;
328  deltalon[ii] = delta;
329  stlon[ii] = -delta / 2;
330  }
331  }
332 
333  // Store in cache
334  // double rgg_resol = (deltalon[iequator] + deltalon[iequator+1])/2;
336  RegionCache::put_cache(kind, resol, ndgl, latband, midlat, stlon, deltalon, loncnt);
337 }
338 
339 } // namespace function
340 } // namespace sql
341 } // namespace odc
void put_cache(const RegionCacheKind &kind, const double &, const int &, double[], double[], double[], double[], int[])
Definition: RegionCache.cc:231
int * read_rtablel_2_file(const int &, int *, int *)
virtual void create_cache(const double &, const int &)
int gauaw(double[], double[], const int &)
gauaw - compute abscissas and weights for gaussian integration
void bsslzr(double[], const int &)
virtual double get_resol(const double &val)
constexpr double recip_pi_over_180
Definition: piconst.h:30
constexpr double half_pi
Definition: piconst.h:26
Definition: ColumnInfo.h:23