ARTS  2.3.1285(git:92a29ea9-dirty)
interpolation_poly.cc
Go to the documentation of this file.
1 /* Copyright (C) 2012 Stefan Buehler <sbuehler(at)ltu.se>
2 
3  This program is free software; you can redistribute it and/or modify it
4  under the terms of the GNU General Public License as published by the
5  Free Software Foundation; either version 2, or (at your option) any
6  later version.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16  USA. */
17 
39 #include "interpolation_poly.h"
40 #include <cmath>
41 #include <iostream>
42 #include "arts_omp.h"
43 #include "check_input.h"
44 #include "interpolation.h"
45 #include "logic.h"
46 
48 
64 Index IMAX(Index a, Index b) { return a > b ? a : b; }
65 
67 
83 Index IMIN(Index a, Index b) { return a < b ? a : b; }
84 
85 // File-global constants:
86 
88 
99 DEBUG_ONLY(const Numeric sum_check_epsilon = 1e-6;)
100 
102 
121  ConstVectorView old_grid,
122  ConstVectorView new_grid,
123  const Index order,
124  const Numeric& extpolfac) {
125  // Number of points used in the interpolation (order + 1):
126  const Index m = order + 1;
127 
128  const Index n_old = old_grid.nelem();
129  const Index n_new = new_grid.nelem();
130 
131  // Since we need m interpolation points, the old grid must have a
132  // least m elements.
133  assert(n_old >= m);
134 
135  // Consistently with gridpos, the array size of gp has to be set
136  // outside. Here, we only assert that it is correct:
137  assert(is_size(gp, n_new));
138 
139  // First call the traditional gridpos to find the grid positions:
140  ArrayOfGridPos gp_trad(n_new);
141  if (n_old > 1) {
142  gridpos(gp_trad, old_grid, new_grid, extpolfac);
143  } else if (n_old == 1) {
144  // This case is not handled by traditional gridpos, but is ok for zero
145  // order interpolation, so we handle it explicitly here. Since there is
146  // only 1 point in the old grid, it is nearest neighbour to all
147  // interpolation points.
148  for (Index i = 0; i < n_new; ++i) {
149  gp_trad[i].idx = 0;
150  gp_trad[i].fd[0] = 0;
151  gp_trad[i].fd[1] = 1;
152  }
153  } else {
154  // We should never be here.
155  assert(false);
156  }
157 
158  for (Index s = 0; s < n_new; ++s) {
159  // Here we calculate the index of the first of the range of
160  // points used for interpolation. For linear interpolation this
161  // is identical to j. The idea for this expression is from
162  // Numerical Receipes (Chapter 3, section "after the hunt"), but
163  // there it is for 1-based arrays.
164  Index k;
165  if (m != 1) {
166  k = IMIN(IMAX(gp_trad[s].idx - (m - 1) / 2, 0), n_old - m);
167  } else {
168  // The above formula for k is not valid for m==1
169  // (nearest neighbour interpolation).
170  if (gp_trad[s].fd[0] <= 0.5)
171  k = gp_trad[s].idx;
172  else
173  k = gp_trad[s].idx + 1;
174 
175  // It is a matter of definition what we do with the exact fd==0.5 case.
176  // Here I arbitrarily decided to stick with the "left" point (smaller
177  // index). I believe this is consistent with the behaviour for m=3,
178  // where 2 points on the left and 1 point on the right is used. (So,
179  // we always prefer the left side.)
180  }
181 
182  // cout << "m: "<< m << ", k: " << k << endl;
183 
184  // Make gp[s].idx and gp[s].w the right size:
185  gp[s].idx.resize(m);
186  gp[s].w.resize(m);
187 
188  // Calculate w for each interpolation point. In the linear case
189  // these are just the fractional distances to each interpolation
190  // point. The w here correspond exactly to the terms in front of
191  // the yi in Numerical Recipes, 2nd edition, section 3.1,
192  // eq. 3.1.1.
193  for (Index i = 0; i < m; ++i) {
194  gp[s].idx[i] = k + i;
195 
196  // Numerical Recipes, 2nd edition, section 3.1, eq. 3.1.1.
197 
198  // Numerator:
199  Numeric num = 1;
200  for (Index j = 0; j < m; ++j)
201  if (j != i) num *= new_grid[s] - old_grid[k + j];
202 
203  // Denominator:
204  Numeric denom = 1;
205  for (Index j = 0; j < m; ++j)
206  if (j != i) denom *= old_grid[k + i] - old_grid[k + j];
207 
208  gp[s].w[i] = num / denom;
209  }
210 
211  // Debugging: Test if sum of all w is 1, as it should be:
212  // Numeric testsum = 0;
213  // for (Index i=0; i<m; ++i) testsum += gp[s].w[i];
214  // cout << "Testsum = " << testsum << endl;
215  }
216 }
217 
219 
242  ConstVectorView old_grid,
243  const Numeric& new_grid,
244  const Index order,
245  const Numeric& extpolfac) {
246  ArrayOfGridPosPoly agp(1);
247  gridpos_poly(agp, old_grid, new_grid, order, extpolfac);
248  gp = agp[0];
249 }
250 
252 
275 void gridpos_poly_longitudinal(const String& error_msg,
276  ArrayOfGridPosPoly& gp,
277  ConstVectorView old_grid,
278  ConstVectorView new_grid,
279  const Index order,
280  const Numeric& extpolfac) {
281  bool global_lons = is_lon_cyclic(old_grid);
282 
283  if (global_lons)
284  gridpos_poly_cyclic_longitudinal(gp, old_grid, new_grid, order, extpolfac);
285  else {
286  if (old_grid[0] >= new_grid[new_grid.nelem() - 1]) {
287  Vector shifted_old_grid = old_grid;
288  shifted_old_grid -= 360;
290  error_msg, shifted_old_grid, new_grid, order, extpolfac);
291 
292  gridpos_poly(gp, shifted_old_grid, new_grid, order, extpolfac);
293  } else if (old_grid[old_grid.nelem() - 1] <= new_grid[0]) {
294  Vector shifted_old_grid = old_grid;
295  shifted_old_grid += 360;
297  error_msg, shifted_old_grid, new_grid, order, extpolfac);
298  gridpos_poly(gp, shifted_old_grid, new_grid, order, extpolfac);
299  } else {
300  chk_interpolation_grids(error_msg, old_grid, new_grid, order, extpolfac);
301  gridpos_poly(gp, old_grid, new_grid, order, extpolfac);
302  }
303  }
304 }
305 
307 
327  ConstVectorView old_grid,
328  ConstVectorView new_grid,
329  const Index order,
330  const Numeric& extpolfac) {
331  assert(is_lon_cyclic(old_grid));
332 
333  Index new_n = old_grid.nelem() - 1;
334  ConstVectorView old_grid_n1 = old_grid[Range(0, new_n)];
335  Range r_left = Range(0, new_n);
336  Range r_right = Range(new_n * 2, new_n);
337 
338  Vector large_grid(new_n * 3);
339 
340  large_grid[r_left] = old_grid_n1;
341  large_grid[r_left] -= 360.;
342 
343  large_grid[Range(new_n, new_n)] = old_grid_n1;
344 
345  large_grid[r_right] = old_grid_n1;
346  large_grid[r_right] += 360.;
347 
348  gridpos_poly(gp, large_grid, new_grid, order, extpolfac);
349 
350  for (ArrayOfGridPosPoly::iterator itgp = gp.begin(); itgp != gp.end(); itgp++)
351  for (ArrayOfIndex::iterator iti = itgp->idx.begin(); iti != itgp->idx.end();
352  iti++)
353  *iti %= new_n;
354 }
355 
357 
381 void gridpos_poly_longitudinal(const String& error_msg,
382  GridPosPoly& gp,
383  ConstVectorView old_grid,
384  const Numeric& new_grid,
385  const Index order,
386  const Numeric& extpolfac) {
387  ArrayOfGridPosPoly agp(1);
389  error_msg, agp, old_grid, new_grid, order, extpolfac);
390  gp = agp[0];
391 }
392 
394 
418  ConstVectorView old_grid,
419  const Numeric& new_grid,
420  const Index order,
421  const Numeric& extpolfac) {
422  ArrayOfGridPosPoly agp(1);
423  gridpos_poly_cyclic_longitudinal(agp, old_grid, new_grid, order, extpolfac);
424  gp = agp[0];
425 }
426 
428 
442 #define LOOPW(x) for (ConstIterator1D x = t##x##begin; x != t##x##end; ++x)
443 
445 #define CACHEW(x) \
446  const ConstIterator1D t##x##begin = t##x.w.begin(); \
447  const ConstIterator1D t##x##end = t##x.w.end();
448 
450 
455 #define LOOPIDX(x) \
456  for (ArrayOfIndex::const_iterator x = t##x##begin; x != t##x##end; ++x)
457 
459 #define CACHEIDX(x) \
460  const ArrayOfIndex::const_iterator t##x##begin = t##x.idx.begin(); \
461  const ArrayOfIndex::const_iterator t##x##end = t##x.idx.end();
462 
464 
472 ostream& operator<<(ostream& os, const GridPosPoly& gp) {
473  os << "idx: " << gp.idx << "\n";
474  os << "w: " << gp.w << "\n";
475 
476  // cout << "Test iterator:\n";
477  // for (ArrayOfIndex::const_iterator x=gp.idx.begin(); x!=gp.idx.end(); ++x)
478  // cout << *x << ":";
479  // cout << "\n";
480 
481  return os;
482 }
483 
485 // Red Interpolation
487 
489 
502 void interpweights(VectorView itw, const GridPosPoly& tc) {
503  assert(is_size(itw, tc.w.nelem()));
504 
505  // Interpolation weights are stored in this order (l=lower
506  // u=upper, c=column):
507  // 1. l-c
508  // 2. u-c
509 
510  Index iti = 0;
511 
512  CACHEW(c)
513  LOOPW(c) {
514  itw.get(iti) = *c;
515  ++iti;
516  }
517 }
518 
520 
535  const GridPosPoly& tr,
536  const GridPosPoly& tc) {
537  assert(is_size(itw, tr.w.nelem() * tc.w.nelem()));
538  Index iti = 0;
539 
540  CACHEW(r)
541  CACHEW(c)
542  LOOPW(r)
543  LOOPW(c) {
544  itw.get(iti) = (*r) * (*c);
545  ++iti;
546  }
547 }
548 
550 
566  const GridPosPoly& tp,
567  const GridPosPoly& tr,
568  const GridPosPoly& tc) {
569  assert(is_size(itw, tp.w.nelem() * tr.w.nelem() * tc.w.nelem()));
570 
571  Index iti = 0;
572 
573  CACHEW(p)
574  CACHEW(r)
575  CACHEW(c)
576  LOOPW(p)
577  LOOPW(r)
578  LOOPW(c) {
579  itw.get(iti) = (*p) * (*r) * (*c);
580  ++iti;
581  }
582 }
583 
585 
602  const GridPosPoly& tb,
603  const GridPosPoly& tp,
604  const GridPosPoly& tr,
605  const GridPosPoly& tc) {
606  assert(
607  is_size(itw, tb.w.nelem() * tp.w.nelem() * tr.w.nelem() * tc.w.nelem()));
608 
609  Index iti = 0;
610 
611  CACHEW(b)
612  CACHEW(p)
613  CACHEW(r)
614  CACHEW(c)
615  LOOPW(b)
616  LOOPW(p)
617  LOOPW(r)
618  LOOPW(c) {
619  itw.get(iti) = (*b) * (*p) * (*r) * (*c);
620  ++iti;
621  }
622 }
623 
625 
643  const GridPosPoly& ts,
644  const GridPosPoly& tb,
645  const GridPosPoly& tp,
646  const GridPosPoly& tr,
647  const GridPosPoly& tc) {
648  assert(is_size(itw,
649  ts.w.nelem() * tb.w.nelem() * tp.w.nelem() * tr.w.nelem() *
650  tc.w.nelem()));
651 
652  Index iti = 0;
653 
654  CACHEW(s)
655  CACHEW(b)
656  CACHEW(p)
657  CACHEW(r)
658  CACHEW(c)
659  LOOPW(s)
660  LOOPW(b)
661  LOOPW(p)
662  LOOPW(r)
663  LOOPW(c) {
664  itw.get(iti) = (*s) * (*b) * (*p) * (*r) * (*c);
665  ++iti;
666  }
667 }
668 
670 
689  const GridPosPoly& tv,
690  const GridPosPoly& ts,
691  const GridPosPoly& tb,
692  const GridPosPoly& tp,
693  const GridPosPoly& tr,
694  const GridPosPoly& tc) {
695  assert(is_size(itw,
696  tv.w.nelem() * ts.w.nelem() * tb.w.nelem() * tp.w.nelem() *
697  tr.w.nelem() * tc.w.nelem()));
698 
699  Index iti = 0;
700 
701  CACHEW(v)
702  CACHEW(s)
703  CACHEW(b)
704  CACHEW(p)
705  CACHEW(r)
706  CACHEW(c)
707  LOOPW(v)
708  LOOPW(s)
709  LOOPW(b)
710  LOOPW(p)
711  LOOPW(r)
712  LOOPW(c) {
713  itw.get(iti) = (*v) * (*s) * (*b) * (*p) * (*r) * (*c);
714  ++iti;
715  }
716 }
717 
719 
735  assert(is_size(itw, tc.w.nelem()));
736 
737  // Check that interpolation weights are valid. The sum of all
738  // weights (last dimension) must always be approximately one.
739  assert(is_same_within_epsilon(itw.sum(), 1, sum_check_epsilon));
740 
741  // To store interpolated value:
742  Numeric tia = 0;
743 
744  Index iti = 0;
745  CACHEIDX(c)
746  LOOPIDX(c) {
747  tia += a.get(*c) * itw.get(iti);
748  ++iti;
749  }
750 
751  return tia;
752 }
753 
755 
772  ConstMatrixView a,
773  const GridPosPoly& tr,
774  const GridPosPoly& tc) {
775  assert(is_size(itw, tr.w.nelem() * tc.w.nelem()));
776 
777  // Check that interpolation weights are valid. The sum of all
778  // weights (last dimension) must always be approximately one.
779  assert(is_same_within_epsilon(itw.sum(), 1, sum_check_epsilon));
780 
781  // To store interpolated value:
782  Numeric tia = 0;
783 
784  Index iti = 0;
785  CACHEIDX(r)
786  CACHEIDX(c)
787  LOOPIDX(r)
788  LOOPIDX(c) {
789  tia += a.get(*r, *c) * itw.get(iti);
790  ++iti;
791  }
792 
793  return tia;
794 }
795 
797 
816  const GridPosPoly& tp,
817  const GridPosPoly& tr,
818  const GridPosPoly& tc) {
819  assert(is_size(itw, tp.w.nelem() * tr.w.nelem() * tc.w.nelem()));
820 
821  // Check that interpolation weights are valid. The sum of all
822  // weights (last dimension) must always be approximately one.
823  assert(is_same_within_epsilon(itw.sum(), 1, sum_check_epsilon));
824 
825  // To store interpolated value:
826  Numeric tia = 0;
827 
828  Index iti = 0;
829  CACHEIDX(p)
830  CACHEIDX(r)
831  CACHEIDX(c)
832  LOOPIDX(p)
833  LOOPIDX(r)
834  LOOPIDX(c) {
835  tia += a.get(*p, *r, *c) * itw.get(iti);
836  ++iti;
837  }
838 
839  return tia;
840 }
841 
843 
863  const GridPosPoly& tb,
864  const GridPosPoly& tp,
865  const GridPosPoly& tr,
866  const GridPosPoly& tc) {
867  assert(
868  is_size(itw, tb.w.nelem() * tp.w.nelem() * tr.w.nelem() * tc.w.nelem()));
869 
870  // Check that interpolation weights are valid. The sum of all
871  // weights (last dimension) must always be approximately one.
872  assert(is_same_within_epsilon(itw.sum(), 1, sum_check_epsilon));
873 
874  // To store interpolated value:
875  Numeric tia = 0;
876 
877  Index iti = 0;
878  CACHEIDX(b)
879  CACHEIDX(p)
880  CACHEIDX(r)
881  CACHEIDX(c)
882  LOOPIDX(b)
883  LOOPIDX(p)
884  LOOPIDX(r)
885  LOOPIDX(c) {
886  tia += a.get(*b, *p, *r, *c) * itw.get(iti);
887  ++iti;
888  }
889 
890  return tia;
891 }
892 
894 
915  const GridPosPoly& ts,
916  const GridPosPoly& tb,
917  const GridPosPoly& tp,
918  const GridPosPoly& tr,
919  const GridPosPoly& tc) {
920  assert(is_size(itw,
921  ts.w.nelem() * tb.w.nelem() * tp.w.nelem() * tr.w.nelem() *
922  tc.w.nelem()));
923 
924  // Check that interpolation weights are valid. The sum of all
925  // weights (last dimension) must always be approximately one.
926  assert(is_same_within_epsilon(itw.sum(), 1, sum_check_epsilon));
927 
928  // To store interpolated value:
929  Numeric tia = 0;
930 
931  Index iti = 0;
932  CACHEIDX(s)
933  CACHEIDX(b)
934  CACHEIDX(p)
935  CACHEIDX(r)
936  CACHEIDX(c)
937  LOOPIDX(s)
938  LOOPIDX(b)
939  LOOPIDX(p)
940  LOOPIDX(r)
941  LOOPIDX(c) {
942  tia += a.get(*s, *b, *p, *r, *c) * itw.get(iti);
943  ++iti;
944  }
945 
946  return tia;
947 }
948 
950 
972  const GridPosPoly& tv,
973  const GridPosPoly& ts,
974  const GridPosPoly& tb,
975  const GridPosPoly& tp,
976  const GridPosPoly& tr,
977  const GridPosPoly& tc) {
978  assert(is_size(itw,
979  tv.w.nelem() * ts.w.nelem() * tb.w.nelem() * tp.w.nelem() *
980  tr.w.nelem() * tc.w.nelem()));
981 
982  // Check that interpolation weights are valid. The sum of all
983  // weights (last dimension) must always be approximately one.
984  assert(is_same_within_epsilon(itw.sum(), 1, sum_check_epsilon));
985 
986  // To store interpolated value:
987  Numeric tia = 0;
988 
989  Index iti = 0;
990  CACHEIDX(v)
991  CACHEIDX(s)
992  CACHEIDX(b)
993  CACHEIDX(p)
994  CACHEIDX(r)
995  CACHEIDX(c)
996  LOOPIDX(v)
997  LOOPIDX(s)
998  LOOPIDX(b)
999  LOOPIDX(p)
1000  LOOPIDX(r)
1001  LOOPIDX(c) {
1002  tia += a.get(*v, *s, *b, *p, *r, *c) * itw.get(iti);
1003  ++iti;
1004  }
1005 
1006  return tia;
1007 }
1008 
1010 // Blue interpolation
1012 
1014 
1030  Index n = cgp.nelem();
1031  assert(is_size(itw, n, cgp[0].w.nelem()));
1032 
1033  // We have to loop all the points in the sequence:
1034  for (Index i = 0; i < n; ++i) {
1035  // Current grid positions:
1036  const GridPosPoly& tc = cgp[i];
1037 
1038  // Interpolation weights are stored in this order (l=lower
1039  // u=upper, c=column):
1040  // 1. l-c
1041  // 2. u-c
1042 
1043  Index iti = 0;
1044 
1045  // We could use a straight-forward for loop here:
1046  //
1047  // for ( Index c=1; c>=0; --c )
1048  // {
1049  // ti[iti] = tc.fd[c];
1050  // ++iti;
1051  // }
1052  //
1053  // However, it is slightly faster to use pointers (I tried it,
1054  // the speed gain is about 20%). So we should write something
1055  // like:
1056  //
1057  // for ( const Numeric* c=&tc.fd[1]; c>=&tc.fd[0]; --c )
1058  // {
1059  // ti[iti] = *c;
1060  // ++iti;
1061  // }
1062  //
1063  // For higher dimensions we have to nest these loops. To avoid
1064  // typos and safe typing, I use the LOOPW macro, which expands
1065  // to the for loop above. Note: NO SEMICOLON AFTER THE LOOPW
1066  // COMMAND!
1067 
1068  CACHEW(c)
1069  LOOPW(c) {
1070  itw.get(i, iti) = *c;
1071  ++iti;
1072  }
1073  }
1074 }
1075 
1077 
1099  const ArrayOfGridPosPoly& rgp,
1100  const ArrayOfGridPosPoly& cgp) {
1101  Index n = cgp.nelem();
1102  assert(is_size(rgp, n)); // rgp must have same size as cgp.
1103  assert(is_size(itw, n, rgp[0].w.nelem() * cgp[0].w.nelem()));
1104 
1105  // We have to loop all the points in the sequence:
1106  for (Index i = 0; i < n; ++i) {
1107  // Current grid positions:
1108  const GridPosPoly& tr = rgp[i];
1109  const GridPosPoly& tc = cgp[i];
1110 
1111  // Interpolation weights are stored in this order (l=lower
1112  // u=upper, r=row, c=column):
1113  // 1. l-r l-c
1114  // 2. l-r u-c
1115  // 3. u-r l-c
1116  // 4. u-r u-c
1117 
1118  Index iti = 0;
1119 
1120  CACHEW(r)
1121  CACHEW(c)
1122  LOOPW(r)
1123  LOOPW(c) {
1124  itw.get(i, iti) = (*r) * (*c);
1125  ++iti;
1126  }
1127  }
1128 }
1129 
1131 
1154  const ArrayOfGridPosPoly& pgp,
1155  const ArrayOfGridPosPoly& rgp,
1156  const ArrayOfGridPosPoly& cgp) {
1157  Index n = cgp.nelem();
1158  assert(is_size(pgp, n)); // pgp must have same size as cgp.
1159  assert(is_size(rgp, n)); // rgp must have same size as cgp.
1160  assert(
1161  is_size(itw, n, pgp[0].w.nelem() * rgp[0].w.nelem() * cgp[0].w.nelem()));
1162 
1163  // We have to loop all the points in the sequence:
1164  for (Index i = 0; i < n; ++i) {
1165  // Current grid positions:
1166  const GridPosPoly& tp = pgp[i];
1167  const GridPosPoly& tr = rgp[i];
1168  const GridPosPoly& tc = cgp[i];
1169 
1170  Index iti = 0;
1171  CACHEW(p)
1172  CACHEW(r)
1173  CACHEW(c)
1174  LOOPW(p)
1175  LOOPW(r)
1176  LOOPW(c) {
1177  itw.get(i, iti) = (*p) * (*r) * (*c);
1178  ++iti;
1179  }
1180  }
1181 }
1182 
1184 
1208  const ArrayOfGridPosPoly& bgp,
1209  const ArrayOfGridPosPoly& pgp,
1210  const ArrayOfGridPosPoly& rgp,
1211  const ArrayOfGridPosPoly& cgp) {
1212  Index n = cgp.nelem();
1213  assert(is_size(bgp, n)); // bgp must have same size as cgp.
1214  assert(is_size(pgp, n)); // pgp must have same size as cgp.
1215  assert(is_size(rgp, n)); // rgp must have same size as cgp.
1216  assert(is_size(itw,
1217  n,
1218  bgp[0].w.nelem() * pgp[0].w.nelem() * rgp[0].w.nelem() *
1219  cgp[0].w.nelem()));
1220 
1221  // We have to loop all the points in the sequence:
1222  for (Index i = 0; i < n; ++i) {
1223  // Current grid positions:
1224  const GridPosPoly& tb = bgp[i];
1225  const GridPosPoly& tp = pgp[i];
1226  const GridPosPoly& tr = rgp[i];
1227  const GridPosPoly& tc = cgp[i];
1228 
1229  Index iti = 0;
1230  CACHEW(b)
1231  CACHEW(p)
1232  CACHEW(r)
1233  CACHEW(c)
1234  LOOPW(b)
1235  LOOPW(p)
1236  LOOPW(r)
1237  LOOPW(c) {
1238  itw.get(i, iti) = (*b) * (*p) * (*r) * (*c);
1239  ++iti;
1240  }
1241  }
1242 }
1243 
1245 
1270  const ArrayOfGridPosPoly& sgp,
1271  const ArrayOfGridPosPoly& bgp,
1272  const ArrayOfGridPosPoly& pgp,
1273  const ArrayOfGridPosPoly& rgp,
1274  const ArrayOfGridPosPoly& cgp) {
1275  Index n = cgp.nelem();
1276  assert(is_size(sgp, n)); // sgp must have same size as cgp.
1277  assert(is_size(bgp, n)); // bgp must have same size as cgp.
1278  assert(is_size(pgp, n)); // pgp must have same size as cgp.
1279  assert(is_size(rgp, n)); // rgp must have same size as cgp.
1280  assert(is_size(itw,
1281  n,
1282  sgp[0].w.nelem() * bgp[0].w.nelem() * pgp[0].w.nelem() *
1283  rgp[0].w.nelem() * cgp[0].w.nelem()));
1284 
1285  // We have to loop all the points in the sequence:
1286  for (Index i = 0; i < n; ++i) {
1287  // Current grid positions:
1288  const GridPosPoly& ts = sgp[i];
1289  const GridPosPoly& tb = bgp[i];
1290  const GridPosPoly& tp = pgp[i];
1291  const GridPosPoly& tr = rgp[i];
1292  const GridPosPoly& tc = cgp[i];
1293 
1294  Index iti = 0;
1295  CACHEW(s)
1296  CACHEW(b)
1297  CACHEW(p)
1298  CACHEW(r)
1299  CACHEW(c)
1300  LOOPW(s)
1301  LOOPW(b)
1302  LOOPW(p)
1303  LOOPW(r)
1304  LOOPW(c) {
1305  itw.get(i, iti) = (*s) * (*b) * (*p) * (*r) * (*c);
1306  ++iti;
1307  }
1308  }
1309 }
1310 
1312 
1338  const ArrayOfGridPosPoly& vgp,
1339  const ArrayOfGridPosPoly& sgp,
1340  const ArrayOfGridPosPoly& bgp,
1341  const ArrayOfGridPosPoly& pgp,
1342  const ArrayOfGridPosPoly& rgp,
1343  const ArrayOfGridPosPoly& cgp) {
1344  Index n = cgp.nelem();
1345  assert(is_size(vgp, n)); // vgp must have same size as cgp.
1346  assert(is_size(sgp, n)); // sgp must have same size as cgp.
1347  assert(is_size(bgp, n)); // bgp must have same size as cgp.
1348  assert(is_size(pgp, n)); // pgp must have same size as cgp.
1349  assert(is_size(rgp, n)); // rgp must have same size as cgp.
1350  assert(is_size(itw,
1351  n,
1352  vgp[0].w.nelem() * sgp[0].w.nelem() * bgp[0].w.nelem() *
1353  pgp[0].w.nelem() * rgp[0].w.nelem() * cgp[0].w.nelem()));
1354 
1355  // We have to loop all the points in the sequence:
1356  for (Index i = 0; i < n; ++i) {
1357  // Current grid positions:
1358  const GridPosPoly& tv = vgp[i];
1359  const GridPosPoly& ts = sgp[i];
1360  const GridPosPoly& tb = bgp[i];
1361  const GridPosPoly& tp = pgp[i];
1362  const GridPosPoly& tr = rgp[i];
1363  const GridPosPoly& tc = cgp[i];
1364 
1365  Index iti = 0;
1366  CACHEW(v)
1367  CACHEW(s)
1368  CACHEW(b)
1369  CACHEW(p)
1370  CACHEW(r)
1371  CACHEW(c)
1372  LOOPW(v)
1373  LOOPW(s)
1374  LOOPW(b)
1375  LOOPW(p)
1376  LOOPW(r)
1377  LOOPW(c) {
1378  itw.get(i, iti) = (*v) * (*s) * (*b) * (*p) * (*r) * (*c);
1379  ++iti;
1380  }
1381  }
1382 }
1383 
1385 
1402  ConstMatrixView itw,
1403  ConstVectorView a,
1404  const ArrayOfGridPosPoly& cgp) {
1405  Index n = cgp.nelem();
1406  assert(is_size(ia, n)); // ia must have same size as cgp.
1407  assert(is_size(itw, n, cgp[0].w.nelem()));
1408 
1409  // Check that interpolation weights are valid. The sum of all
1410  // weights (last dimension) must always be approximately one. We
1411  // only check the first element.
1412  assert(
1413  is_same_within_epsilon(itw(0, Range(joker)).sum(), 1, sum_check_epsilon));
1414 
1415  // We have to loop all the points in the sequence:
1416  for (Index i = 0; i < n; ++i) {
1417  // Current grid positions:
1418  const GridPosPoly& tc = cgp[i];
1419 
1420  // Get handle to current element of output vector and initialize
1421  // it to zero:
1422  Numeric& tia = ia[i];
1423  tia = 0;
1424 
1425  Index iti = 0;
1426  CACHEIDX(c)
1427  LOOPIDX(c) {
1428  tia += a.get(*c) * itw.get(i, iti);
1429  ++iti;
1430  }
1431  }
1432 }
1433 
1435 
1457  ConstMatrixView itw,
1458  ConstMatrixView a,
1459  const ArrayOfGridPosPoly& rgp,
1460  const ArrayOfGridPosPoly& cgp) {
1461  Index n = cgp.nelem();
1462  assert(is_size(ia, n)); // ia must have same size as cgp.
1463  assert(is_size(rgp, n)); // rgp must have same size as cgp.
1464  assert(is_size(itw, n, rgp[0].w.nelem() * cgp[0].w.nelem()));
1465 
1466  // Check that interpolation weights are valid. The sum of all
1467  // weights (last dimension) must always be approximately one. We
1468  // only check the first element.
1469  assert(
1470  is_same_within_epsilon(itw(0, Range(joker)).sum(), 1, sum_check_epsilon));
1471 
1472  // We have to loop all the points in the sequence:
1473  for (Index i = 0; i < n; ++i) {
1474  // Current grid positions:
1475  const GridPosPoly& tr = rgp[i];
1476  const GridPosPoly& tc = cgp[i];
1477 
1478  // Get handle to current element of output vector and initialize
1479  // it to zero:
1480  Numeric& tia = ia[i];
1481  tia = 0;
1482 
1483  Index iti = 0;
1484  CACHEIDX(r)
1485  CACHEIDX(c)
1486  LOOPIDX(r)
1487  LOOPIDX(c) {
1488  tia += a.get(*r, *c) * itw.get(i, iti);
1489  ++iti;
1490  }
1491  }
1492 }
1493 
1495 
1518  ConstMatrixView itw,
1519  ConstTensor3View a,
1520  const ArrayOfGridPosPoly& pgp,
1521  const ArrayOfGridPosPoly& rgp,
1522  const ArrayOfGridPosPoly& cgp) {
1523  Index n = cgp.nelem();
1524  assert(is_size(ia, n)); // ia must have same size as cgp.
1525  assert(is_size(pgp, n)); // pgp must have same size as cgp.
1526  assert(is_size(rgp, n)); // rgp must have same size as cgp.
1527  assert(
1528  is_size(itw, n, pgp[0].w.nelem() * rgp[0].w.nelem() * cgp[0].w.nelem()));
1529 
1530  // Check that interpolation weights are valid. The sum of all
1531  // weights (last dimension) must always be approximately one. We
1532  // only check the first element.
1533  assert(
1534  is_same_within_epsilon(itw(0, Range(joker)).sum(), 1, sum_check_epsilon));
1535 
1536  // We have to loop all the points in the sequence:
1537  for (Index i = 0; i < n; ++i) {
1538  // Current grid positions:
1539  const GridPosPoly& tp = pgp[i];
1540  const GridPosPoly& tr = rgp[i];
1541  const GridPosPoly& tc = cgp[i];
1542 
1543  // Get handle to current element of output vector and initialize
1544  // it to zero:
1545  Numeric& tia = ia[i];
1546  tia = 0;
1547 
1548  Index iti = 0;
1549  CACHEIDX(p)
1550  CACHEIDX(r)
1551  CACHEIDX(c)
1552  LOOPIDX(p)
1553  LOOPIDX(r)
1554  LOOPIDX(c) {
1555  tia += a.get(*p, *r, *c) * itw.get(i, iti);
1556  ++iti;
1557  }
1558  }
1559 }
1560 
1562 
1586  ConstMatrixView itw,
1587  ConstTensor4View a,
1588  const ArrayOfGridPosPoly& bgp,
1589  const ArrayOfGridPosPoly& pgp,
1590  const ArrayOfGridPosPoly& rgp,
1591  const ArrayOfGridPosPoly& cgp) {
1592  Index n = cgp.nelem();
1593  assert(is_size(ia, n)); // ia must have same size as cgp.
1594  assert(is_size(bgp, n)); // bgp must have same size as cgp.
1595  assert(is_size(pgp, n)); // pgp must have same size as cgp.
1596  assert(is_size(rgp, n)); // rgp must have same size as cgp.
1597  assert(is_size(itw,
1598  n,
1599  bgp[0].w.nelem() * pgp[0].w.nelem() * rgp[0].w.nelem() *
1600  cgp[0].w.nelem()));
1601 
1602  // Check that interpolation weights are valid. The sum of all
1603  // weights (last dimension) must always be approximately one. We
1604  // only check the first element.
1605  assert(
1606  is_same_within_epsilon(itw(0, Range(joker)).sum(), 1, sum_check_epsilon));
1607 
1608  // We have to loop all the points in the sequence:
1609  for (Index i = 0; i < n; ++i) {
1610  // Current grid positions:
1611  const GridPosPoly& tb = bgp[i];
1612  const GridPosPoly& tp = pgp[i];
1613  const GridPosPoly& tr = rgp[i];
1614  const GridPosPoly& tc = cgp[i];
1615 
1616  // Get handle to current element of output vector and initialize
1617  // it to zero:
1618  Numeric& tia = ia[i];
1619  tia = 0;
1620 
1621  Index iti = 0;
1622  CACHEIDX(b)
1623  CACHEIDX(p)
1624  CACHEIDX(r)
1625  CACHEIDX(c)
1626  LOOPIDX(b)
1627  LOOPIDX(p)
1628  LOOPIDX(r)
1629  LOOPIDX(c) {
1630  tia += a.get(*b, *p, *r, *c) * itw.get(i, iti);
1631  ++iti;
1632  }
1633  }
1634 }
1635 
1637 
1662  ConstMatrixView itw,
1663  ConstTensor5View a,
1664  const ArrayOfGridPosPoly& sgp,
1665  const ArrayOfGridPosPoly& bgp,
1666  const ArrayOfGridPosPoly& pgp,
1667  const ArrayOfGridPosPoly& rgp,
1668  const ArrayOfGridPosPoly& cgp) {
1669  Index n = cgp.nelem();
1670  assert(is_size(ia, n)); // ia must have same size as cgp.
1671  assert(is_size(sgp, n)); // sgp must have same size as cgp.
1672  assert(is_size(bgp, n)); // bgp must have same size as cgp.
1673  assert(is_size(pgp, n)); // pgp must have same size as cgp.
1674  assert(is_size(rgp, n)); // rgp must have same size as cgp.
1675  assert(is_size(itw,
1676  n,
1677  sgp[0].w.nelem() * bgp[0].w.nelem() * pgp[0].w.nelem() *
1678  rgp[0].w.nelem() * cgp[0].w.nelem()));
1679 
1680  // Check that interpolation weights are valid. The sum of all
1681  // weights (last dimension) must always be approximately one. We
1682  // only check the first element.
1683  assert(
1684  is_same_within_epsilon(itw(0, Range(joker)).sum(), 1, sum_check_epsilon));
1685 
1686  // We have to loop all the points in the sequence:
1687  for (Index i = 0; i < n; ++i) {
1688  // Current grid positions:
1689  const GridPosPoly& ts = sgp[i];
1690  const GridPosPoly& tb = bgp[i];
1691  const GridPosPoly& tp = pgp[i];
1692  const GridPosPoly& tr = rgp[i];
1693  const GridPosPoly& tc = cgp[i];
1694 
1695  // Get handle to current element of output vector and initialize
1696  // it to zero:
1697  Numeric& tia = ia[i];
1698  tia = 0;
1699 
1700  Index iti = 0;
1701  CACHEIDX(s)
1702  CACHEIDX(b)
1703  CACHEIDX(p)
1704  CACHEIDX(r)
1705  CACHEIDX(c)
1706  LOOPIDX(s)
1707  LOOPIDX(b)
1708  LOOPIDX(p)
1709  LOOPIDX(r)
1710  LOOPIDX(c) {
1711  tia += a.get(*s, *b, *p, *r, *c) * itw.get(i, iti);
1712  ++iti;
1713  }
1714  }
1715 }
1716 
1718 
1744  ConstMatrixView itw,
1745  ConstTensor6View a,
1746  const ArrayOfGridPosPoly& vgp,
1747  const ArrayOfGridPosPoly& sgp,
1748  const ArrayOfGridPosPoly& bgp,
1749  const ArrayOfGridPosPoly& pgp,
1750  const ArrayOfGridPosPoly& rgp,
1751  const ArrayOfGridPosPoly& cgp) {
1752  Index n = cgp.nelem();
1753  assert(is_size(ia, n)); // ia must have same size as cgp.
1754  assert(is_size(vgp, n)); // vgp must have same size as cgp.
1755  assert(is_size(sgp, n)); // sgp must have same size as cgp.
1756  assert(is_size(bgp, n)); // bgp must have same size as cgp.
1757  assert(is_size(pgp, n)); // pgp must have same size as cgp.
1758  assert(is_size(rgp, n)); // rgp must have same size as cgp.
1759  assert(is_size(itw,
1760  n,
1761  vgp[0].w.nelem() * sgp[0].w.nelem() * bgp[0].w.nelem() *
1762  pgp[0].w.nelem() * rgp[0].w.nelem() * cgp[0].w.nelem()));
1763 
1764  // Check that interpolation weights are valid. The sum of all
1765  // weights (last dimension) must always be approximately one. We
1766  // only check the first element.
1767  assert(
1768  is_same_within_epsilon(itw(0, Range(joker)).sum(), 1, sum_check_epsilon));
1769 
1770  // We have to loop all the points in the sequence:
1771  for (Index i = 0; i < n; ++i) {
1772  // Current grid positions:
1773  const GridPosPoly& tv = vgp[i];
1774  const GridPosPoly& ts = sgp[i];
1775  const GridPosPoly& tb = bgp[i];
1776  const GridPosPoly& tp = pgp[i];
1777  const GridPosPoly& tr = rgp[i];
1778  const GridPosPoly& tc = cgp[i];
1779 
1780  // Get handle to current element of output vector and initialize
1781  // it to zero:
1782  Numeric& tia = ia[i];
1783  tia = 0;
1784 
1785  Index iti = 0;
1786  CACHEIDX(v)
1787  CACHEIDX(s)
1788  CACHEIDX(b)
1789  CACHEIDX(p)
1790  CACHEIDX(r)
1791  CACHEIDX(c)
1792  LOOPIDX(v)
1793  LOOPIDX(s)
1794  LOOPIDX(b)
1795  LOOPIDX(p)
1796  LOOPIDX(r)
1797  LOOPIDX(c) {
1798  tia += a.get(*v, *s, *b, *p, *r, *c) * itw.get(i, iti);
1799  ++iti;
1800  }
1801  }
1802 }
1803 
1805 // Green interpolation
1807 
1809 
1831  const ArrayOfGridPosPoly& rgp,
1832  const ArrayOfGridPosPoly& cgp) {
1833  Index nr = rgp.nelem();
1834  Index nc = cgp.nelem();
1835  assert(is_size(itw, nr, nc, rgp[0].w.nelem() * cgp[0].w.nelem()));
1836 
1837  // We have to loop all the points in the new grid:
1838  for (Index ir = 0; ir < nr; ++ir) {
1839  // Current grid position:
1840  const GridPosPoly& tr = rgp[ir];
1841  CACHEW(r)
1842 
1843  for (Index ic = 0; ic < nc; ++ic) {
1844  // Current grid position:
1845  const GridPosPoly& tc = cgp[ic];
1846  CACHEW(c)
1847 
1848  // Interpolation weights are stored in this order (l=lower
1849  // u=upper, r=row, c=column):
1850  // 1. l-r l-c
1851  // 2. l-r u-c
1852  // 3. u-r l-c
1853  // 4. u-r u-c
1854 
1855  Index iti = 0;
1856 
1857  LOOPW(r)
1858  LOOPW(c) {
1859  itw.get(ir, ic, iti) = (*r) * (*c);
1860  ++iti;
1861  }
1862  }
1863  }
1864 }
1865 
1867 
1890  const ArrayOfGridPosPoly& pgp,
1891  const ArrayOfGridPosPoly& rgp,
1892  const ArrayOfGridPosPoly& cgp) {
1893  Index np = pgp.nelem();
1894  Index nr = rgp.nelem();
1895  Index nc = cgp.nelem();
1896 
1897  assert(is_size(
1898  itw, np, nr, nc, pgp[0].w.nelem() * rgp[0].w.nelem() * cgp[0].w.nelem()));
1899 
1900  // We have to loop all the points in the new grid:
1901  for (Index ip = 0; ip < np; ++ip) {
1902  const GridPosPoly& tp = pgp[ip];
1903  CACHEW(p)
1904  for (Index ir = 0; ir < nr; ++ir) {
1905  const GridPosPoly& tr = rgp[ir];
1906  CACHEW(r)
1907  for (Index ic = 0; ic < nc; ++ic) {
1908  const GridPosPoly& tc = cgp[ic];
1909  CACHEW(c)
1910 
1911  Index iti = 0;
1912 
1913  LOOPW(p)
1914  LOOPW(r)
1915  LOOPW(c) {
1916  itw.get(ip, ir, ic, iti) = (*p) * (*r) * (*c);
1917  ++iti;
1918  }
1919  }
1920  }
1921  }
1922 }
1923 
1925 
1949  const ArrayOfGridPosPoly& bgp,
1950  const ArrayOfGridPosPoly& pgp,
1951  const ArrayOfGridPosPoly& rgp,
1952  const ArrayOfGridPosPoly& cgp) {
1953  Index nb = bgp.nelem();
1954  Index np = pgp.nelem();
1955  Index nr = rgp.nelem();
1956  Index nc = cgp.nelem();
1957 
1958  assert(is_size(itw,
1959  nb,
1960  np,
1961  nr,
1962  nc,
1963  bgp[0].w.nelem() * pgp[0].w.nelem() * rgp[0].w.nelem() *
1964  cgp[0].w.nelem()));
1965 
1966  // We have to loop all the points in the new grid:
1967  for (Index ib = 0; ib < nb; ++ib) {
1968  const GridPosPoly& tb = bgp[ib];
1969  CACHEW(b)
1970  for (Index ip = 0; ip < np; ++ip) {
1971  const GridPosPoly& tp = pgp[ip];
1972  CACHEW(p)
1973  for (Index ir = 0; ir < nr; ++ir) {
1974  const GridPosPoly& tr = rgp[ir];
1975  CACHEW(r)
1976  for (Index ic = 0; ic < nc; ++ic) {
1977  const GridPosPoly& tc = cgp[ic];
1978  CACHEW(c)
1979 
1980  Index iti = 0;
1981 
1982  LOOPW(b)
1983  LOOPW(p)
1984  LOOPW(r)
1985  LOOPW(c) {
1986  itw.get(ib, ip, ir, ic, iti) = (*b) * (*p) * (*r) * (*c);
1987  ++iti;
1988  }
1989  }
1990  }
1991  }
1992  }
1993 }
1994 
1996 
2021  const ArrayOfGridPosPoly& sgp,
2022  const ArrayOfGridPosPoly& bgp,
2023  const ArrayOfGridPosPoly& pgp,
2024  const ArrayOfGridPosPoly& rgp,
2025  const ArrayOfGridPosPoly& cgp) {
2026  Index ns = sgp.nelem();
2027  Index nb = bgp.nelem();
2028  Index np = pgp.nelem();
2029  Index nr = rgp.nelem();
2030  Index nc = cgp.nelem();
2031 
2032  assert(is_size(itw,
2033  ns,
2034  nb,
2035  np,
2036  nr,
2037  nc,
2038  sgp[0].w.nelem() * bgp[0].w.nelem() * pgp[0].w.nelem() *
2039  rgp[0].w.nelem() * cgp[0].w.nelem()));
2040 
2041  // We have to loop all the points in the new grid:
2042  for (Index is = 0; is < ns; ++is) {
2043  const GridPosPoly& ts = sgp[is];
2044  CACHEW(s)
2045  for (Index ib = 0; ib < nb; ++ib) {
2046  const GridPosPoly& tb = bgp[ib];
2047  CACHEW(b)
2048  for (Index ip = 0; ip < np; ++ip) {
2049  const GridPosPoly& tp = pgp[ip];
2050  CACHEW(p)
2051  for (Index ir = 0; ir < nr; ++ir) {
2052  const GridPosPoly& tr = rgp[ir];
2053  CACHEW(r)
2054  for (Index ic = 0; ic < nc; ++ic) {
2055  const GridPosPoly& tc = cgp[ic];
2056  CACHEW(c)
2057 
2058  Index iti = 0;
2059 
2060  LOOPW(s)
2061  LOOPW(b)
2062  LOOPW(p)
2063  LOOPW(r)
2064  LOOPW(c) {
2065  itw.get(is, ib, ip, ir, ic, iti) =
2066  (*s) * (*b) * (*p) * (*r) * (*c);
2067  ++iti;
2068  }
2069  }
2070  }
2071  }
2072  }
2073  }
2074 }
2075 
2077 
2103  const ArrayOfGridPosPoly& vgp,
2104  const ArrayOfGridPosPoly& sgp,
2105  const ArrayOfGridPosPoly& bgp,
2106  const ArrayOfGridPosPoly& pgp,
2107  const ArrayOfGridPosPoly& rgp,
2108  const ArrayOfGridPosPoly& cgp) {
2109  Index nv = vgp.nelem();
2110  Index ns = sgp.nelem();
2111  Index nb = bgp.nelem();
2112  Index np = pgp.nelem();
2113  Index nr = rgp.nelem();
2114  Index nc = cgp.nelem();
2115 
2116  assert(is_size(itw,
2117  nv,
2118  ns,
2119  nb,
2120  np,
2121  nr,
2122  nc,
2123  vgp[0].w.nelem() * sgp[0].w.nelem() * bgp[0].w.nelem() *
2124  pgp[0].w.nelem() * rgp[0].w.nelem() * cgp[0].w.nelem()));
2125 
2126  // We have to loop all the points in the new grid:
2127  for (Index iv = 0; iv < nv; ++iv) {
2128  const GridPosPoly& tv = vgp[iv];
2129  CACHEW(v)
2130  for (Index is = 0; is < ns; ++is) {
2131  const GridPosPoly& ts = sgp[is];
2132  CACHEW(s)
2133  for (Index ib = 0; ib < nb; ++ib) {
2134  const GridPosPoly& tb = bgp[ib];
2135  CACHEW(b)
2136  for (Index ip = 0; ip < np; ++ip) {
2137  const GridPosPoly& tp = pgp[ip];
2138  CACHEW(p)
2139  for (Index ir = 0; ir < nr; ++ir) {
2140  const GridPosPoly& tr = rgp[ir];
2141  CACHEW(r)
2142  for (Index ic = 0; ic < nc; ++ic) {
2143  const GridPosPoly& tc = cgp[ic];
2144  CACHEW(c)
2145 
2146  Index iti = 0;
2147 
2148  LOOPW(v)
2149  LOOPW(s)
2150  LOOPW(b)
2151  LOOPW(p)
2152  LOOPW(r)
2153  LOOPW(c) {
2154  itw.get(iv, is, ib, ip, ir, ic, iti) =
2155  (*v) * (*s) * (*b) * (*p) * (*r) * (*c);
2156  ++iti;
2157  }
2158  }
2159  }
2160  }
2161  }
2162  }
2163  }
2164 }
2165 
2167 
2189  ConstTensor3View itw,
2190  ConstMatrixView a,
2191  const ArrayOfGridPosPoly& rgp,
2192  const ArrayOfGridPosPoly& cgp) {
2193  Index nr = rgp.nelem();
2194  Index nc = cgp.nelem();
2195  assert(is_size(ia, nr, nc));
2196  assert(is_size(itw, nr, nc, rgp[0].w.nelem() * cgp[0].w.nelem()));
2197 
2198  // Check that interpolation weights are valid. The sum of all
2199  // weights (last dimension) must always be approximately one. We
2200  // only check the first element.
2201  assert(is_same_within_epsilon(
2202  itw(0, 0, Range(joker)).sum(), 1, sum_check_epsilon));
2203 
2204  // We have to loop all the points in the new grid:
2205  for (Index ir = 0; ir < nr; ++ir) {
2206  // Current grid position:
2207  const GridPosPoly& tr = rgp[ir];
2208  CACHEIDX(r)
2209 
2210  for (Index ic = 0; ic < nc; ++ic) {
2211  // Current grid position:
2212  const GridPosPoly& tc = cgp[ic];
2213  CACHEIDX(c)
2214 
2215  // Get handle to current element of output tensor and initialize
2216  // it to zero:
2217  Numeric& tia = ia(ir, ic);
2218  tia = 0;
2219 
2220  Index iti = 0;
2221  LOOPIDX(r)
2222  LOOPIDX(c) {
2223  tia += a.get(*r, *c) * itw.get(ir, ic, iti);
2224  ++iti;
2225  }
2226  }
2227  }
2228 }
2229 
2231 
2254  ConstTensor4View itw,
2255  ConstTensor3View a,
2256  const ArrayOfGridPosPoly& pgp,
2257  const ArrayOfGridPosPoly& rgp,
2258  const ArrayOfGridPosPoly& cgp) {
2259  Index np = pgp.nelem();
2260  Index nr = rgp.nelem();
2261  Index nc = cgp.nelem();
2262  assert(is_size(ia, np, nr, nc));
2263  assert(is_size(
2264  itw, np, nr, nc, pgp[0].w.nelem() * rgp[0].w.nelem() * cgp[0].w.nelem()));
2265 
2266  // Check that interpolation weights are valid. The sum of all
2267  // weights (last dimension) must always be approximately one. We
2268  // only check the first element.
2269  assert(is_same_within_epsilon(
2270  itw(0, 0, 0, Range(joker)).sum(), 1, sum_check_epsilon));
2271 
2272  // We have to loop all the points in the new grid:
2273  for (Index ip = 0; ip < np; ++ip) {
2274  const GridPosPoly& tp = pgp[ip];
2275  CACHEIDX(p);
2276  for (Index ir = 0; ir < nr; ++ir) {
2277  const GridPosPoly& tr = rgp[ir];
2278  CACHEIDX(r);
2279  for (Index ic = 0; ic < nc; ++ic) {
2280  // Current grid position:
2281  const GridPosPoly& tc = cgp[ic];
2282  CACHEIDX(c);
2283 
2284  // Get handle to current element of output tensor and
2285  // initialize it to zero:
2286  Numeric& tia = ia(ip, ir, ic);
2287  tia = 0;
2288 
2289  Index iti = 0;
2290  LOOPIDX(p)
2291  LOOPIDX(r)
2292  LOOPIDX(c) {
2293  tia += a.get(*p, *r, *c) * itw.get(ip, ir, ic, iti);
2294  ++iti;
2295  }
2296  }
2297  }
2298  }
2299 }
2300 
2302 
2326  ConstTensor5View itw,
2327  ConstTensor4View a,
2328  const ArrayOfGridPosPoly& bgp,
2329  const ArrayOfGridPosPoly& pgp,
2330  const ArrayOfGridPosPoly& rgp,
2331  const ArrayOfGridPosPoly& cgp) {
2332  Index nb = bgp.nelem();
2333  Index np = pgp.nelem();
2334  Index nr = rgp.nelem();
2335  Index nc = cgp.nelem();
2336  assert(is_size(ia, nb, np, nr, nc));
2337  assert(is_size(itw,
2338  nb,
2339  np,
2340  nr,
2341  nc,
2342  bgp[0].w.nelem() * pgp[0].w.nelem() * rgp[0].w.nelem() *
2343  cgp[0].w.nelem()));
2344 
2345  // Check that interpolation weights are valid. The sum of all
2346  // weights (last dimension) must always be approximately one. We
2347  // only check the first element.
2348  assert(is_same_within_epsilon(
2349  itw(0, 0, 0, 0, Range(joker)).sum(), 1, sum_check_epsilon));
2350 
2351  // We have to loop all the points in the new grid:
2352  for (Index ib = 0; ib < nb; ++ib) {
2353  const GridPosPoly& tb = bgp[ib];
2354  CACHEIDX(b);
2355  for (Index ip = 0; ip < np; ++ip) {
2356  const GridPosPoly& tp = pgp[ip];
2357  CACHEIDX(p);
2358  for (Index ir = 0; ir < nr; ++ir) {
2359  const GridPosPoly& tr = rgp[ir];
2360  CACHEIDX(r);
2361  for (Index ic = 0; ic < nc; ++ic) {
2362  // Current grid position:
2363  const GridPosPoly& tc = cgp[ic];
2364  CACHEIDX(c);
2365 
2366  // Get handle to current element of output tensor and
2367  // initialize it to zero:
2368  Numeric& tia = ia(ib, ip, ir, ic);
2369  tia = 0;
2370 
2371  Index iti = 0;
2372  LOOPIDX(b)
2373  LOOPIDX(p)
2374  LOOPIDX(r)
2375  LOOPIDX(c) {
2376  tia += a.get(*b, *p, *r, *c) * itw.get(ib, ip, ir, ic, iti);
2377  ++iti;
2378  }
2379  }
2380  }
2381  }
2382  }
2383 }
2384 
2386 
2411  ConstTensor6View itw,
2412  ConstTensor5View a,
2413  const ArrayOfGridPosPoly& sgp,
2414  const ArrayOfGridPosPoly& bgp,
2415  const ArrayOfGridPosPoly& pgp,
2416  const ArrayOfGridPosPoly& rgp,
2417  const ArrayOfGridPosPoly& cgp) {
2418  Index ns = sgp.nelem();
2419  Index nb = bgp.nelem();
2420  Index np = pgp.nelem();
2421  Index nr = rgp.nelem();
2422  Index nc = cgp.nelem();
2423  assert(is_size(ia, ns, nb, np, nr, nc));
2424  assert(is_size(itw,
2425  ns,
2426  nb,
2427  np,
2428  nr,
2429  nc,
2430  sgp[0].w.nelem() * bgp[0].w.nelem() * pgp[0].w.nelem() *
2431  rgp[0].w.nelem() * cgp[0].w.nelem()));
2432 
2433  // Check that interpolation weights are valid. The sum of all
2434  // weights (last dimension) must always be approximately one. We
2435  // only check the first element.
2436  assert(is_same_within_epsilon(
2437  itw(0, 0, 0, 0, 0, Range(joker)).sum(), 1, sum_check_epsilon));
2438 
2439  // We have to loop all the points in the new grid:
2440  for (Index is = 0; is < ns; ++is) {
2441  const GridPosPoly& ts = sgp[is];
2442  CACHEIDX(s);
2443  for (Index ib = 0; ib < nb; ++ib) {
2444  const GridPosPoly& tb = bgp[ib];
2445  CACHEIDX(b);
2446  for (Index ip = 0; ip < np; ++ip) {
2447  const GridPosPoly& tp = pgp[ip];
2448  CACHEIDX(p);
2449  for (Index ir = 0; ir < nr; ++ir) {
2450  const GridPosPoly& tr = rgp[ir];
2451  CACHEIDX(r);
2452  for (Index ic = 0; ic < nc; ++ic) {
2453  // Current grid position:
2454  const GridPosPoly& tc = cgp[ic];
2455  CACHEIDX(c);
2456 
2457  // Get handle to current element of output tensor and
2458  // initialize it to zero:
2459  Numeric& tia = ia(is, ib, ip, ir, ic);
2460  tia = 0;
2461 
2462  Index iti = 0;
2463  LOOPIDX(s)
2464  LOOPIDX(b)
2465  LOOPIDX(p)
2466  LOOPIDX(r)
2467  LOOPIDX(c) {
2468  tia +=
2469  a.get(*s, *b, *p, *r, *c) * itw.get(is, ib, ip, ir, ic, iti);
2470  ++iti;
2471  }
2472  }
2473  }
2474  }
2475  }
2476  }
2477 }
2478 
2480 
2506  ConstTensor7View itw,
2507  ConstTensor6View a,
2508  const ArrayOfGridPosPoly& vgp,
2509  const ArrayOfGridPosPoly& sgp,
2510  const ArrayOfGridPosPoly& bgp,
2511  const ArrayOfGridPosPoly& pgp,
2512  const ArrayOfGridPosPoly& rgp,
2513  const ArrayOfGridPosPoly& cgp) {
2514  Index nv = vgp.nelem();
2515  Index ns = sgp.nelem();
2516  Index nb = bgp.nelem();
2517  Index np = pgp.nelem();
2518  Index nr = rgp.nelem();
2519  Index nc = cgp.nelem();
2520  assert(is_size(ia, nv, ns, nb, np, nr, nc));
2521  assert(is_size(itw,
2522  nv,
2523  ns,
2524  nb,
2525  np,
2526  nr,
2527  nc,
2528  vgp[0].w.nelem() * sgp[0].w.nelem() * bgp[0].w.nelem() *
2529  pgp[0].w.nelem() * rgp[0].w.nelem() * cgp[0].w.nelem()));
2530 
2531  // Check that interpolation weights are valid. The sum of all
2532  // weights (last dimension) must always be approximately one. We
2533  // only check the first element.
2534  assert(is_same_within_epsilon(
2535  itw(0, 0, 0, 0, 0, 0, Range(joker)).sum(), 1, sum_check_epsilon));
2536 
2537  // We have to loop all the points in the new grid:
2538  for (Index iv = 0; iv < nv; ++iv) {
2539  const GridPosPoly& tv = vgp[iv];
2540  CACHEIDX(v);
2541  for (Index is = 0; is < ns; ++is) {
2542  const GridPosPoly& ts = sgp[is];
2543  CACHEIDX(s);
2544  for (Index ib = 0; ib < nb; ++ib) {
2545  const GridPosPoly& tb = bgp[ib];
2546  CACHEIDX(b);
2547  for (Index ip = 0; ip < np; ++ip) {
2548  const GridPosPoly& tp = pgp[ip];
2549  CACHEIDX(p);
2550  for (Index ir = 0; ir < nr; ++ir) {
2551  const GridPosPoly& tr = rgp[ir];
2552  CACHEIDX(r);
2553  for (Index ic = 0; ic < nc; ++ic) {
2554  // Current grid position:
2555  const GridPosPoly& tc = cgp[ic];
2556  CACHEIDX(c);
2557 
2558  // Get handle to current element of output tensor and
2559  // initialize it to zero:
2560  Numeric& tia = ia(iv, is, ib, ip, ir, ic);
2561  tia = 0;
2562 
2563  Index iti = 0;
2564  LOOPIDX(v)
2565  LOOPIDX(s)
2566  LOOPIDX(b)
2567  LOOPIDX(p)
2568  LOOPIDX(r)
2569  LOOPIDX(c) {
2570  tia += a.get(*v, *s, *b, *p, *r, *c) *
2571  itw.get(iv, is, ib, ip, ir, ic, iti);
2572  ++iti;
2573  }
2574  }
2575  }
2576  }
2577  }
2578  }
2579  }
2580 }
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
The VectorView class.
Definition: matpackI.h:610
bool is_lon_cyclic(ConstVectorView grid, const Numeric &epsilon)
Check if the given longitude grid is cyclic.
Definition: logic.cc:369
#define ns
The Tensor4View class.
Definition: matpackIV.h:284
Index nelem() const
Number of elements.
Definition: array.h:195
A constant view of a Tensor7.
Definition: matpackVII.h:147
The Tensor7View class.
Definition: matpackVII.h:1286
Numeric & get(Index n)
Get element implementation without assertions.
Definition: matpackI.h:638
Numeric get(Index v, Index s, Index b, Index p, Index r, Index c) const
Get element implementation without assertions.
Definition: matpackVI.h:550
The Vector class.
Definition: matpackI.h:860
The MatrixView class.
Definition: matpackI.h:1093
A constant view of a Tensor6.
Definition: matpackVI.h:149
Index IMIN(Index a, Index b)
Return the minimum of two integer numbers.
The range class.
Definition: matpackI.h:160
Numeric get(Index r, Index c) const
Get element implementation without assertions.
Definition: matpackI.h:1009
ostream & operator<<(ostream &os, const GridPosPoly &gp)
Output operator for GridPosPoly.
Numeric & get(Index v, Index s, Index b, Index p, Index r, Index c)
Get element implementation without assertions.
Definition: matpackVI.h:1015
cmplx FADDEEVA() w(cmplx z, double relerr)
Definition: Faddeeva.cc:680
The Tensor6View class.
Definition: matpackVI.h:621
Header file for interpolation.cc.
#define CACHEIDX(x)
Macro for caching begin and end iterators for interpolation index loops.
Index nelem() const
Returns the number of elements.
Definition: matpackI.cc:51
void chk_interpolation_grids(const String &which_interpolation, ConstVectorView old_grid, ConstVectorView new_grid, const Index order, const Numeric &extpolfac, const bool islog)
Check interpolation grids.
Definition: check_input.cc:989
A constant view of a Tensor4.
Definition: matpackIV.h:133
void interpweights(VectorView itw, const GridPosPoly &tc)
Red 1D interpolation weights.
void gridpos_poly_longitudinal(const String &error_msg, ArrayOfGridPosPoly &gp, ConstVectorView old_grid, ConstVectorView new_grid, const Index order, const Numeric &extpolfac)
Set up grid positions for higher order interpolation on longitudes.
#define DEBUG_ONLY(...)
Definition: debug.h:36
bool is_same_within_epsilon(const Numeric &a, const Numeric &b, const Numeric &epsilon)
Check, if two numbers agree within a given epsilon.
Definition: logic.cc:351
#define CACHEW(x)
Macro for caching begin and end iterators for interpolation weight loops.
Numeric sum() const
The sum of all elements of a Vector.
Definition: matpackI.cc:53
The Tensor3View class.
Definition: matpackIII.h:239
ArrayOfIndex idx
Numeric get(Index n) const
Get element implementation without assertions.
Definition: matpackI.h:514
Numeric & get(Index r, Index c)
Get element implementation without assertions.
Definition: matpackI.h:1118
#define LOOPW(x)
Macro for interpolation weight loops.
void gridpos(ArrayOfGridPos &gp, ConstVectorView old_grid, ConstVectorView new_grid, const Numeric &extpolfac)
Set up a grid position Array.
Numeric interp(ConstVectorView itw, ConstVectorView a, const GridPosPoly &tc)
Red 1D Interpolate.
A constant view of a Tensor5.
Definition: matpackV.h:143
const Joker joker
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
void gridpos_poly(ArrayOfGridPosPoly &gp, ConstVectorView old_grid, ConstVectorView new_grid, const Index order, const Numeric &extpolfac)
The maximum difference from 1 that we allow for a sum check.
Numeric & get(Index p, Index r, Index c)
Get element implementation without assertions.
Definition: matpackIII.h:275
void gridpos_poly_cyclic_longitudinal(ArrayOfGridPosPoly &gp, ConstVectorView old_grid, ConstVectorView new_grid, const Index order, const Numeric &extpolfac)
Set up grid positions for higher order interpolation.
The Tensor5View class.
Definition: matpackV.h:333
Header file for logic.cc.
#define LOOPIDX(x)
Macro for interpolation index loops.
Header file for interpolation_poly.cc.
Numeric & get(Index b, Index p, Index r, Index c)
Get element implementation without assertions.
Definition: matpackIV.h:348
Index IMAX(Index a, Index b)
Return the maximum of two integer numbers.
Numeric get(Index l, Index v, Index s, Index b, Index p, Index r, Index c) const
Get element implementation without assertions.
Definition: matpackVII.h:1211
A constant view of a Tensor3.
Definition: matpackIII.h:132
A constant view of a Vector.
Definition: matpackI.h:476
Numeric & get(Index s, Index b, Index p, Index r, Index c)
Get element implementation without assertions.
Definition: matpackV.h:431
A constant view of a Matrix.
Definition: matpackI.h:982
Numeric & get(Index l, Index v, Index s, Index b, Index p, Index r, Index c)
Get element implementation without assertions.
Definition: matpackVII.h:2308
Structure to store a grid position for higher order interpolation.
Numeric get(Index s, Index b, Index p, Index r, Index c) const
Get element implementation without assertions.
Definition: matpackV.h:265
bool is_size(ConstVectorView x, const Index &n)
Verifies that the size of x is l.
Definition: logic.cc:79
Header file for helper functions for OpenMP.
Numeric get(Index p, Index r, Index c) const
Get element implementation without assertions.
Definition: matpackIII.h:180
Numeric get(Index b, Index p, Index r, Index c) const
Get element implementation without assertions.
Definition: matpackIV.h:220