ARTS  2.4.0(git:4fb77825)
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 }
Tensor7View
The Tensor7View class.
Definition: matpackVII.h:1286
is_same_within_epsilon
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
ConstTensor7View::get
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
IMIN
Index IMIN(Index a, Index b)
Return the minimum of two integer numbers.
Definition: interpolation_poly.cc:83
MatrixView
The MatrixView class.
Definition: matpackI.h:1093
operator<<
ostream & operator<<(ostream &os, const GridPosPoly &gp)
Output operator for GridPosPoly.
Definition: interpolation_poly.cc:472
w
Complex w(Complex z) noexcept
The Faddeeva function.
Definition: linefunctions.cc:42
ConstTensor5View::get
Numeric get(Index s, Index b, Index p, Index r, Index c) const
Get element implementation without assertions.
Definition: matpackV.h:265
gridpos
void gridpos(ArrayOfGridPos &gp, ConstVectorView old_grid, ConstVectorView new_grid, const Numeric &extpolfac)
Set up a grid position Array.
Definition: interpolation.cc:156
ConstTensor7View
A constant view of a Tensor7.
Definition: matpackVII.h:147
joker
const Joker joker
interpolation.h
Header file for interpolation.cc.
chk_interpolation_grids
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
DEBUG_ONLY
#define DEBUG_ONLY(...)
Definition: debug.h:36
ConstTensor4View::get
Numeric get(Index b, Index p, Index r, Index c) const
Get element implementation without assertions.
Definition: matpackIV.h:220
interpweights
void interpweights(VectorView itw, const GridPosPoly &tc)
Red 1D interpolation weights.
Definition: interpolation_poly.cc:502
ConstVectorView::get
Numeric get(Index n) const
Get element implementation without assertions.
Definition: matpackI.h:514
ConstMatrixView::get
Numeric get(Index r, Index c) const
Get element implementation without assertions.
Definition: matpackI.h:1009
MatrixView::get
Numeric & get(Index r, Index c)
Get element implementation without assertions.
Definition: matpackI.h:1118
is_size
bool is_size(ConstVectorView x, const Index &n)
Verifies that the size of x is l.
Definition: logic.cc:79
LOOPW
#define LOOPW(x)
Macro for interpolation weight loops.
Definition: interpolation_poly.cc:442
ConstTensor4View
A constant view of a Tensor4.
Definition: matpackIV.h:133
Tensor3View
The Tensor3View class.
Definition: matpackIII.h:239
CACHEW
#define CACHEW(x)
Macro for caching begin and end iterators for interpolation weight loops.
Definition: interpolation_poly.cc:445
Array< GridPosPoly >
ConstTensor6View::get
Numeric get(Index v, Index s, Index b, Index p, Index r, Index c) const
Get element implementation without assertions.
Definition: matpackVI.h:550
Tensor6View::get
Numeric & get(Index v, Index s, Index b, Index p, Index r, Index c)
Get element implementation without assertions.
Definition: matpackVI.h:1015
gridpos_poly_cyclic_longitudinal
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.
Definition: interpolation_poly.cc:326
gridpos_poly_longitudinal
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.
Definition: interpolation_poly.cc:275
GridPosPoly
Structure to store a grid position for higher order interpolation.
Definition: interpolation_poly.h:64
my_basic_string< char >
ConstVectorView::nelem
Index nelem() const
Returns the number of elements.
Definition: matpackI.cc:51
VectorView
The VectorView class.
Definition: matpackI.h:610
CACHEIDX
#define CACHEIDX(x)
Macro for caching begin and end iterators for interpolation index loops.
Definition: interpolation_poly.cc:459
IMAX
Index IMAX(Index a, Index b)
Return the maximum of two integer numbers.
Definition: interpolation_poly.cc:64
GridPosPoly::idx
ArrayOfIndex idx
Definition: interpolation_poly.h:67
ConstVectorView::sum
Numeric sum() const
The sum of all elements of a Vector.
Definition: matpackI.cc:53
ConstTensor6View
A constant view of a Tensor6.
Definition: matpackVI.h:149
Numeric
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
Tensor5View
The Tensor5View class.
Definition: matpackV.h:333
Tensor4View::get
Numeric & get(Index b, Index p, Index r, Index c)
Get element implementation without assertions.
Definition: matpackIV.h:348
LOOPIDX
#define LOOPIDX(x)
Macro for interpolation index loops.
Definition: interpolation_poly.cc:455
is_lon_cyclic
bool is_lon_cyclic(ConstVectorView grid, const Numeric &epsilon)
Check if the given longitude grid is cyclic.
Definition: logic.cc:369
interpolation_poly.h
Header file for interpolation_poly.cc.
Tensor5View::get
Numeric & get(Index s, Index b, Index p, Index r, Index c)
Get element implementation without assertions.
Definition: matpackV.h:431
ConstMatrixView
A constant view of a Matrix.
Definition: matpackI.h:982
ConstTensor3View::get
Numeric get(Index p, Index r, Index c) const
Get element implementation without assertions.
Definition: matpackIII.h:180
Range
The range class.
Definition: matpackI.h:160
logic.h
Header file for logic.cc.
Tensor7View::get
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
ConstTensor3View
A constant view of a Tensor3.
Definition: matpackIII.h:132
Tensor4View
The Tensor4View class.
Definition: matpackIV.h:284
Tensor3View::get
Numeric & get(Index p, Index r, Index c)
Get element implementation without assertions.
Definition: matpackIII.h:275
VectorView::get
Numeric & get(Index n)
Get element implementation without assertions.
Definition: matpackI.h:638
GridPosPoly::w
Vector w
Definition: interpolation_poly.h:70
interp
Numeric interp(ConstVectorView itw, ConstVectorView a, const GridPosPoly &tc)
Red 1D Interpolate.
Definition: interpolation_poly.cc:734
Index
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
check_input.h
gridpos_poly
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.
Definition: interpolation_poly.cc:120
Vector
The Vector class.
Definition: matpackI.h:860
arts_omp.h
Header file for helper functions for OpenMP.
ConstVectorView
A constant view of a Vector.
Definition: matpackI.h:476
Array::nelem
Index nelem() const
Number of elements.
Definition: array.h:195
ConstTensor5View
A constant view of a Tensor5.
Definition: matpackV.h:143
Tensor6View
The Tensor6View class.
Definition: matpackVI.h:621
ns
#define ns
Definition: legacy_continua.cc:22183