ARTS  2.0.49
interpolation.cc
Go to the documentation of this file.
1 /* Copyright (C) 2002-2008 Stefan Buehler <sbuehler@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 
40 #include <iostream>
41 #include <cmath>
42 #include "array.h"
43 #include "check_input.h"
44 #include "interpolation.h"
45 #include "logic.h"
46 
47 
48 
49 // File-global constants:
50 
52 
64 
65 
67 
76 const Numeric FD_TOL = 1e-3;
77 
78 
79 
80 
82 
91 #define LOOPIT(x) for ( const Numeric* x=&t##x.fd[1]; x>=&t##x.fd[0]; --x )
92 
93 
94 
95 
97 
105 ostream& operator<<(ostream& os, const GridPos& gp)
106 {
107  os << gp.idx << " " << gp.fd[0] << " " << gp.fd[1] << "\n";
108  return os;
109 }
110 
111 
113 
168  ConstVectorView old_grid,
169  ConstVectorView new_grid,
170  const Numeric& extpolfac )
171 {
172  const Index n_old = old_grid.nelem();
173  const Index n_new = new_grid.nelem();
174 
175  // Assert that gp has the right size:
176  assert( is_size(gp,n_new) );
177 
178  // Assert, that the old grid has more than one element
179  assert( 1 < n_old );
180 
181  // This function hast two parts, depending on whether old_grid is
182  // sorted in ascending or descending order. Maybe that's not too
183  // elegant, but it's the most efficient, because in this way there
184  // is no additional runtime overhead to handle both cases.
185 
186  // We use only the first two elements to decide how the grid is
187  // sorted. (The rest of the grid is checked later by an assert.)
188  // If both values are the same, we still assume the grid is
189  // ascending. However, this will lead to an assertion fail later on,
190  // because the grid has to be strictly sorted.
191  bool ascending = ( old_grid[0] <= old_grid[1] );
192 
193  if (ascending)
194  {
195  // So, old_grid should always be sorted in strictly ascending order.
196  // (No duplicate values.)
197  // Assert that this is so. This may depend on user input, however,
198  // inside this elementary function is not the place to check for
199  // that. There must be runtime checks on higher levels to insure
200  // that all grids are sorted. The assertion here is just as a last
201  // safety check.
202  assert( is_increasing(old_grid) );
203 
204  // Limits of extrapolation.
205  const Numeric og_min = old_grid[0] -
206  extpolfac * ( old_grid[1] - old_grid[0] );
207  const Numeric og_max = old_grid[n_old-1] +
208  extpolfac * ( old_grid[n_old-1] - old_grid[n_old-2] );
209 
210  // We will make no firm assumptions about the new grid. But the case
211  // that we have in mind is that it is either also sorted, or at
212  // least partially sorted, for example like this:
213  // 5 4 3 2 2.5 3 4
214  // This kind of sequence should be typical if we interpolate
215  // atmospheric fields along a limb propagation path.
216 
217  // Let's get some idea where the first point in the new grid is,
218  // relative to the old grid. We use linear interpolation between the
219  // maximum and the minimum of the old grid for this. (Taking
220  // into account the small allowed extrapolation.)
221  Numeric frac = (new_grid[0]-og_min)/(og_max-og_min);
222 
223  // We are not checking if the value of frac is reasonable,
224  // because there is another assertion below to catch the
225  // consequences.
226 
227  // Initialize current_position:
228  Index current_position = (Index) rint(frac*(Numeric)(n_old-2));
229 
230  // The above statement should satisfy
231  // 0 <= current_position <= n_old-2
232  // Assert that this is indeed the case.
233 // cout << "frac = " << frac << "\n";
234 // cout << "current_position = " << current_position << "\n";
235  assert( 0<= current_position );
236  assert( current_position <= n_old-2 );
237 
238  // The variables lower and upper are used to remember the value of
239  // the old grid at current_position and one above current_position:
240  Numeric lower = old_grid[current_position];
241  Numeric upper = old_grid[current_position+1];
242 
243  // Loop over all points in the new grid:
244  for ( Index i_new=0; i_new<n_new; ++i_new )
245  {
246  // Get a reference to the current element of gp:
247  GridPos& tgp = gp[i_new];
248  // And on the current value of the new grid:
249  const Numeric tng = new_grid[i_new];
250 
251  // Verify that the new grid is within the limits of
252  // extrapolation that we have defined by og_min and og_max:
253  assert( og_min <= tng );
254  assert( tng <= og_max );
255 
256 // cout << "lower / tng / upper = "
257 // << lower << " / "
258 // << tng << " / "
259 // << upper << "\n";
260 
261  // Is current_position too high?
262  // (The current_position>0 condition is there so that the position
263  // stays 0 for extrapolation.)
264  if ( tng < lower && current_position > 0 )
265  {
266  do
267  {
268  --current_position;
269  lower = old_grid[current_position];
270  }
271  while ( tng < lower && current_position > 0 );
272 
273  upper = old_grid[current_position+1];
274 
275  tgp.idx = current_position;
276  tgp.fd[0] = (tng-lower)/(upper-lower);
277  tgp.fd[1] = 1.0 - tgp.fd[0];
278  }
279  else
280  {
281  // Is it too low?
282  // (The current_position<n_old condition is there so
283  // that uppers stays n_old-1 for extrapolation.)
284  if ( tng >= upper && current_position < n_old-2 )
285  {
286  do
287  {
288  ++current_position;
289  upper = old_grid[current_position+1];
290  }
291  while ( tng >= upper && current_position < n_old-2 );
292 
293  lower = old_grid[current_position];
294 
295  tgp.idx = current_position;
296  tgp.fd[0] = (tng-lower)/(upper-lower);
297  tgp.fd[1] = 1.0 - tgp.fd[0];
298  }
299  else
300  {
301  // None of the other two conditions were true. That means:
302  // lower <= tng < upper. The current_position is still
303  // valid.
304 
305  // SAB 2010-04-28: Note that if a new grid point is exactly on
306  // top of an old grid point, then you are now guaranteed to get
307  // fd[0] = 0 and fd[1] = 1. (Except at the upper grid end.)
308 
309  tgp.idx = current_position;
310  tgp.fd[0] = (tng-lower)/(upper-lower);
311  tgp.fd[1] = 1.0 - tgp.fd[0];
312  }
313  }
314 
315 // cout << tgp.idx << " " << tgp.fd[0] << " " << tgp.fd[1] << endl;
316 
317  // Safety check to ensure the above promise:
318  assert(old_grid[tgp.idx]<=tng || tgp.idx==0);
319  }
320  }
321  else // if (ascending)
322  {
323  // Now we are in the "descending old grid" part. We do exactly
324  // the same as in the other part, just accounting for the
325  // different order of things. Comments here refer only to
326  // interesting differences from the ascending case. See that
327  // case for more general comments.
328 
329  // This time ensure strictly descending order:
330  assert( is_decreasing(old_grid) );
331 
332  // The max is now the first point, the min the last point!
333  // I think the sign is right here...
334  const Numeric og_max = old_grid[0] -
335  extpolfac * ( old_grid[1] - old_grid[0] );
336  const Numeric og_min = old_grid[n_old-1] +
337  extpolfac * ( old_grid[n_old-1] - old_grid[n_old-2] );
338 
339  // We have to take 1- here, because we are starting from the
340  // high end.
341  Numeric frac = 1 - (new_grid[0]-og_min)/(og_max-og_min);
342 
343  // We are not checking if the value of frac is reasonable,
344  // because there is another assertion below to catch the
345  // consequences.
346 
347  Index current_position = (Index) rint(frac*(Numeric)(n_old-2));
348 
349  // The above statement should satisfy
350  // 0 <= current_position <= n_old-2
351  // Assert that this is indeed the case.
352 // cout << "frac = " << frac << "\n";
353 // cout << "current_position = " << current_position << "\n";
354  assert( 0<= current_position );
355  assert( current_position <= n_old-2 );
356 
357  // Note, that old_grid[lower] has a higher numerical value than
358  // old_grid[upper]!
359  Numeric lower = old_grid[current_position];
360  Numeric upper = old_grid[current_position+1];
361 
362  for ( Index i_new=0; i_new<n_new; ++i_new )
363  {
364  GridPos& tgp = gp[i_new];
365  const Numeric tng = new_grid[i_new];
366 
367  // Verify that the new grid is within the limits of
368  // extrapolation that we have defined by og_min and og_max:
369  assert( og_min <= tng );
370  assert( tng <= og_max );
371 
372 // cout << "lower / tng / upper = "
373 // << lower << " / "
374 // << tng << " / "
375 // << upper << "\n";
376 
377  // Is current_position too high? (Sign of comparison changed
378  // compared to ascending case!)
379  if ( tng > lower && current_position > 0 )
380  {
381  do
382  {
383  --current_position;
384  lower = old_grid[current_position];
385  }
386  while ( tng > lower && current_position > 0 );
387 
388  upper = old_grid[current_position+1];
389 
390  tgp.idx = current_position;
391  tgp.fd[0] = (tng-lower)/(upper-lower);
392  tgp.fd[1] = 1.0 - tgp.fd[0];
393  }
394  else
395  {
396  // Is it too low? (Sign of comparison changed
397  // compared to ascending case!)
398  if ( tng <= upper && current_position < n_old-2 )
399  {
400  do
401  {
402  ++current_position;
403  upper = old_grid[current_position+1];
404  }
405  while ( tng <= upper && current_position < n_old-2 );
406 
407  lower = old_grid[current_position];
408 
409  tgp.idx = current_position;
410  tgp.fd[0] = (tng-lower)/(upper-lower);
411  tgp.fd[1] = 1.0 - tgp.fd[0];
412  }
413  else
414  {
415  // None of the other two conditions were true. That means:
416  // lower >= tng > upper. The current_position is still
417  // valid. (Note that upper and lower have switched
418  // place compared to the ascending case.)
419 
420  // SAB 2010-04-28: Note that if a new grid point is exactly on
421  // top of an old grid point, then you are now guaranteed to get
422  // fd[0] = 0 and fd[1] = 1. (Except at the upper grid end.)
423 
424  tgp.idx = current_position;
425  tgp.fd[0] = (tng-lower)/(upper-lower);
426  tgp.fd[1] = 1.0 - tgp.fd[0];
427  }
428  }
429 
430  // Safety check to ensure the above promise:
431  assert(old_grid[tgp.idx]>=tng || tgp.idx==0);
432  }
433  }
434 }
435 
436 
438 
459 void gridpos( GridPos& gp,
460  ConstVectorView old_grid,
461  const Numeric& new_grid,
462  const Numeric& extpolfac )
463 {
464  ArrayOfGridPos agp(1);
465  Vector v( 1, new_grid );
466  gridpos( agp, old_grid, v, extpolfac );
467  gridpos_copy( gp, agp[0] );
468 }
469 
470 
471 
473 
482 void gridpos_copy( GridPos& gp_new, const GridPos& gp_old )
483 {
484  gp_new.idx = gp_old.idx;
485  gp_new.fd[0] = gp_old.fd[0];
486  gp_new.fd[1] = gp_old.fd[1];
487 }
488 
489 
490 
492 
505 {
506  return ( Numeric(gp.idx) + gp.fd[0] );
507 }
508 
509 
510 
512 
525 {
526  // Catch values that "must" be wrong
527  assert( gp.fd[0] > -FD_TOL );
528  assert( gp.fd[0] < 1.0 + FD_TOL );
529  assert( gp.fd[1] > -FD_TOL );
530  assert( gp.fd[1] < 1.0 + FD_TOL );
531 
532  if( gp.fd[0] < 0.0 )
533  { gp.fd[0] = 0.0; gp.fd[1] = 1.0; }
534  else if( gp.fd[0] > 1.0 )
535  { gp.fd[0] = 1.0; gp.fd[1] = 0.0; }
536 
537  if( gp.fd[1] < 0.0 )
538  { gp.fd[1] = 0.0; gp.fd[0] = 1.0; }
539  else if( gp.fd[1] > 1.0 )
540  { gp.fd[1] = 1.0; gp.fd[0] = 0.0; }
541 }
542 
543 
544 
546 
568  GridPos& gp,
569  const Index& n )
570 {
571  assert( gp.idx >= 0 );
572 
573  // If fd=1, shift to grid index above
574  if( gp.fd[0] > 0.5 )
575  {
576  gp.idx += 1;
577  }
578  gp.fd[0] = 0;
579  gp.fd[1] = 1;
580 
581  assert( gp.idx < n );
582 
583  // End of complete grid range must be handled separately
584  if( gp.idx == n-1 )
585  {
586  gp.idx -= 1;
587  gp.fd[0] = 1;
588  gp.fd[1] = 0;
589  }
590 }
591 
592 
593 
595 
609  GridPos& gp,
610  const Index& ie )
611 {
612  if( gp.idx == ie )
613  {
614  assert( gp.fd[0] < 0.005 ); // To capture obviously bad cases
615  gp.idx -= 1;
616  gp.fd[0] = 1.0;
617  gp.fd[1] = 0.0;
618  }
619 }
620 
621 
623 
637  ArrayOfGridPos& gp,
638  const Index& ie )
639 {
640  for (Index i = 0; i < gp.nelem(); i++ )
641  {
642  if( gp[i].idx == ie )
643  {
644  assert( gp[i].fd[0] < 0.005 ); // To capture obviously bad cases
645  gp[i].idx -= 1;
646  gp[i].fd[0] = 1.0;
647  gp[i].fd[1] = 0.0;
648  }
649  }
650 }
651 
652 
653 
655 
666  const GridPos& gp,
667  const Index& i )
668 {
669  // Assume that gridpos_force_end_fd has been used. The expression 0==0 should
670  // be safer than 1==1.
671 
672  if( gp.idx == i && gp.fd[0] == 0 )
673  { return true; }
674  else if( gp.idx == i-1 && gp.fd[1] == 0 )
675  { return true; }
676 
677  return false;
678 }
679 
680 
681 
683 
702  const GridPos& gp,
703  const bool& upwards )
704 {
705  assert( gp.fd[0] >= 0 );
706  assert( gp.fd[1] >= 0 );
707 
708  // Not at a grid point
709  if( gp.fd[0] > 0 && gp.fd[1] > 0 )
710  {
711  return gp.idx;
712  }
713 
714  // Fractional distance 0
715  else if( gp.fd[0] == 0 )
716  {
717  if( upwards )
718  return gp.idx;
719  else
720  return gp.idx - 1;
721  }
722 
723  // Fractional distance 1
724  else
725  {
726  if( upwards )
727  return gp.idx + 1;
728  else
729  return gp.idx;
730  }
731 }
732 
733 
734 
735 
736 
737 
739 // Red Interpolation
741 
743 
757  const GridPos& tc )
758 {
759  assert(is_size(itw,2)); // We must store 2 interpolation
760  // weights.
761 
762  // Interpolation weights are stored in this order (l=lower
763  // u=upper, c=column):
764  // 1. l-c
765  // 2. u-c
766 
767  Index iti = 0;
768 
769  // We could use a straight-forward for loop here:
770  //
771  // for ( Index c=1; c>=0; --c )
772  // {
773  // ti[iti] = tc.fd[c];
774  // ++iti;
775  // }
776  //
777  // However, it is slightly faster to use pointers (I tried it,
778  // the speed gain is about 20%). So we should write something
779  // like:
780  //
781  // for ( const Numeric* c=&tc.fd[1]; c>=&tc.fd[0]; --c )
782  // {
783  // ti[iti] = *c;
784  // ++iti;
785  // }
786  //
787  // For higher dimensions we have to nest these loops. To avoid
788  // typos and safe typing, I use the LOOPIT macro, which expands
789  // to the for loop above. Note: NO SEMICOLON AFTER THE LOOPIT
790  // COMMAND!
791 
792  LOOPIT(c)
793  {
794  itw[iti] = *c;
795  ++iti;
796  }
797 }
798 
800 
815  const GridPos& tr,
816  const GridPos& tc )
817 {
818  assert(is_size(itw,4)); // We must store 4 interpolation
819  // weights.
820  Index iti = 0;
821 
822  LOOPIT(r)
823  LOOPIT(c)
824  {
825  itw[iti] = (*r) * (*c);
826  ++iti;
827  }
828 }
829 
831 
847  const GridPos& tp,
848  const GridPos& tr,
849  const GridPos& tc )
850 {
851  assert(is_size(itw,8)); // We must store 8 interpolation
852  // weights.
853  Index iti = 0;
854 
855  LOOPIT(p)
856  LOOPIT(r)
857  LOOPIT(c)
858  {
859  itw[iti] = (*p) * (*r) * (*c);
860  ++iti;
861  }
862 }
863 
865 
882  const GridPos& tb,
883  const GridPos& tp,
884  const GridPos& tr,
885  const GridPos& tc )
886 {
887  assert(is_size(itw,16)); // We must store 16 interpolation
888  // weights.
889  Index iti = 0;
890 
891  LOOPIT(b)
892  LOOPIT(p)
893  LOOPIT(r)
894  LOOPIT(c)
895  {
896  itw[iti] = (*b) * (*p) * (*r) * (*c);
897  ++iti;
898  }
899 }
900 
902 
920  const GridPos& ts,
921  const GridPos& tb,
922  const GridPos& tp,
923  const GridPos& tr,
924  const GridPos& tc )
925 {
926  assert(is_size(itw,32)); // We must store 32 interpolation
927  // weights.
928  Index iti = 0;
929 
930  LOOPIT(s)
931  LOOPIT(b)
932  LOOPIT(p)
933  LOOPIT(r)
934  LOOPIT(c)
935  {
936  itw[iti] = (*s) * (*b) * (*p) * (*r) * (*c);
937  ++iti;
938  }
939 }
940 
942 
961  const GridPos& tv,
962  const GridPos& ts,
963  const GridPos& tb,
964  const GridPos& tp,
965  const GridPos& tr,
966  const GridPos& tc )
967 {
968  assert(is_size(itw,64)); // We must store 64 interpolation
969  // weights.
970  Index iti = 0;
971 
972  LOOPIT(v)
973  LOOPIT(s)
974  LOOPIT(b)
975  LOOPIT(p)
976  LOOPIT(r)
977  LOOPIT(c)
978  {
979  itw[iti] = (*v) * (*s) * (*b) * (*p) * (*r) * (*c);
980  ++iti;
981  }
982 }
983 
985 
1001  ConstVectorView a,
1002  const GridPos& tc )
1003 {
1004  assert(is_size(itw,2)); // We need 2 interpolation
1005  // weights.
1006 
1007  // Check that interpolation weights are valid. The sum of all
1008  // weights (last dimension) must always be approximately one.
1009  assert( is_same_within_epsilon( itw.sum(),
1010  1,
1011  sum_check_epsilon ) );
1012 
1013  // To store interpolated value:
1014  Numeric tia = 0;
1015 
1016  Index iti = 0;
1017  for ( Index c=0; c<2; ++c )
1018  {
1019  tia += a[tc.idx+c] * itw[iti];
1020  ++iti;
1021  }
1022 
1023  return tia;
1024 }
1025 
1027 
1044  ConstMatrixView a,
1045  const GridPos& tr,
1046  const GridPos& tc )
1047 {
1048  assert(is_size(itw,4)); // We need 4 interpolation
1049  // weights.
1050 
1051  // Check that interpolation weights are valid. The sum of all
1052  // weights (last dimension) must always be approximately one.
1053  assert( is_same_within_epsilon( itw.sum(),
1054  1,
1055  sum_check_epsilon ) );
1056 
1057  // To store interpolated value:
1058  Numeric tia = 0;
1059 
1060  Index iti = 0;
1061  for ( Index r=0; r<2; ++r )
1062  for ( Index c=0; c<2; ++c )
1063  {
1064  tia += a(tr.idx+r,
1065  tc.idx+c) * itw[iti];
1066  ++iti;
1067  }
1068 
1069  return tia;
1070 }
1071 
1073 
1091  ConstTensor3View a,
1092  const GridPos& tp,
1093  const GridPos& tr,
1094  const GridPos& tc )
1095 {
1096  assert(is_size(itw,8)); // We need 8 interpolation
1097  // weights.
1098 
1099  // Check that interpolation weights are valid. The sum of all
1100  // weights (last dimension) must always be approximately one.
1101  assert( is_same_within_epsilon( itw.sum(),
1102  1,
1103  sum_check_epsilon ) );
1104 
1105  // To store interpolated value:
1106  Numeric tia = 0;
1107 
1108  Index iti = 0;
1109  for ( Index p=0; p<2; ++p )
1110  for ( Index r=0; r<2; ++r )
1111  for ( Index c=0; c<2; ++c )
1112  {
1113  tia += a(tp.idx+p,
1114  tr.idx+r,
1115  tc.idx+c) * itw[iti];
1116  ++iti;
1117  }
1118 
1119  return tia;
1120 }
1121 
1123 
1142  ConstTensor4View a,
1143  const GridPos& tb,
1144  const GridPos& tp,
1145  const GridPos& tr,
1146  const GridPos& tc )
1147 {
1148  assert(is_size(itw,16)); // We need 16 interpolation
1149  // weights.
1150 
1151  // Check that interpolation weights are valid. The sum of all
1152  // weights (last dimension) must always be approximately one.
1153  assert( is_same_within_epsilon( itw.sum(),
1154  1,
1155  sum_check_epsilon ) );
1156 
1157  // To store interpolated value:
1158  Numeric tia = 0;
1159 
1160  Index iti = 0;
1161  for ( Index b=0; b<2; ++b )
1162  for ( Index p=0; p<2; ++p )
1163  for ( Index r=0; r<2; ++r )
1164  for ( Index c=0; c<2; ++c )
1165  {
1166  tia += a(tb.idx+b,
1167  tp.idx+p,
1168  tr.idx+r,
1169  tc.idx+c) * itw[iti];
1170  ++iti;
1171  }
1172 
1173  return tia;
1174 }
1175 
1177 
1197  ConstTensor5View a,
1198  const GridPos& ts,
1199  const GridPos& tb,
1200  const GridPos& tp,
1201  const GridPos& tr,
1202  const GridPos& tc )
1203 {
1204  assert(is_size(itw,32)); // We need 32 interpolation
1205  // weights.
1206 
1207  // Check that interpolation weights are valid. The sum of all
1208  // weights (last dimension) must always be approximately one.
1209  assert( is_same_within_epsilon( itw.sum(),
1210  1,
1211  sum_check_epsilon ) );
1212 
1213  // To store interpolated value:
1214  Numeric tia = 0;
1215 
1216  Index iti = 0;
1217  for ( Index s=0; s<2; ++s )
1218  for ( Index b=0; b<2; ++b )
1219  for ( Index p=0; p<2; ++p )
1220  for ( Index r=0; r<2; ++r )
1221  for ( Index c=0; c<2; ++c )
1222  {
1223  tia += a(ts.idx+s,
1224  tb.idx+b,
1225  tp.idx+p,
1226  tr.idx+r,
1227  tc.idx+c) * itw[iti];
1228  ++iti;
1229  }
1230 
1231  return tia;
1232 }
1233 
1235 
1256  ConstTensor6View a,
1257  const GridPos& tv,
1258  const GridPos& ts,
1259  const GridPos& tb,
1260  const GridPos& tp,
1261  const GridPos& tr,
1262  const GridPos& tc )
1263 {
1264  assert(is_size(itw,64)); // We need 64 interpolation
1265  // weights.
1266 
1267  // Check that interpolation weights are valid. The sum of all
1268  // weights (last dimension) must always be approximately one.
1269  assert( is_same_within_epsilon( itw.sum(),
1270  1,
1271  sum_check_epsilon ) );
1272 
1273  // To store interpolated value:
1274  Numeric tia = 0;
1275 
1276  Index iti = 0;
1277  for ( Index v=0; v<2; ++v )
1278  for ( Index s=0; s<2; ++s )
1279  for ( Index b=0; b<2; ++b )
1280  for ( Index p=0; p<2; ++p )
1281  for ( Index r=0; r<2; ++r )
1282  for ( Index c=0; c<2; ++c )
1283  {
1284  tia += a(tv.idx+v,
1285  ts.idx+s,
1286  tb.idx+b,
1287  tp.idx+p,
1288  tr.idx+r,
1289  tc.idx+c) * itw[iti];
1290  ++iti;
1291  }
1292 
1293  return tia;
1294 }
1295 
1296 
1298 // Blue interpolation
1300 
1302 
1318  const ArrayOfGridPos& cgp )
1319 {
1320  Index n = cgp.nelem();
1321  assert(is_size(itw,n,2)); // We must store 2 interpolation
1322  // weights for each position.
1323 
1324  // We have to loop all the points in the sequence:
1325  for ( Index i=0; i<n; ++i )
1326  {
1327  // Current grid positions:
1328  const GridPos& tc = cgp[i];
1329 
1330  // Interpolation weights are stored in this order (l=lower
1331  // u=upper, c=column):
1332  // 1. l-c
1333  // 2. u-c
1334 
1335  Index iti = 0;
1336 
1337  // We could use a straight-forward for loop here:
1338  //
1339  // for ( Index c=1; c>=0; --c )
1340  // {
1341  // ti[iti] = tc.fd[c];
1342  // ++iti;
1343  // }
1344  //
1345  // However, it is slightly faster to use pointers (I tried it,
1346  // the speed gain is about 20%). So we should write something
1347  // like:
1348  //
1349  // for ( const Numeric* c=&tc.fd[1]; c>=&tc.fd[0]; --c )
1350  // {
1351  // ti[iti] = *c;
1352  // ++iti;
1353  // }
1354  //
1355  // For higher dimensions we have to nest these loops. To avoid
1356  // typos and safe typing, I use the LOOPIT macro, which expands
1357  // to the for loop above. Note: NO SEMICOLON AFTER THE LOOPIT
1358  // COMMAND!
1359 
1360  LOOPIT(c)
1361  {
1362  itw(i,iti) = *c;
1363  ++iti;
1364  }
1365  }
1366 }
1367 
1369 
1391  const ArrayOfGridPos& rgp,
1392  const ArrayOfGridPos& cgp )
1393 {
1394  Index n = cgp.nelem();
1395  assert(is_size(rgp,n)); // rgp must have same size as cgp.
1396  assert(is_size(itw,n,4)); // We must store 4 interpolation
1397  // weights for each position.
1398 
1399  // We have to loop all the points in the sequence:
1400  for ( Index i=0; i<n; ++i )
1401  {
1402  // Current grid positions:
1403  const GridPos& tr = rgp[i];
1404  const GridPos& tc = cgp[i];
1405 
1406  // Interpolation weights are stored in this order (l=lower
1407  // u=upper, r=row, c=column):
1408  // 1. l-r l-c
1409  // 2. l-r u-c
1410  // 3. u-r l-c
1411  // 4. u-r u-c
1412 
1413  Index iti = 0;
1414 
1415  LOOPIT(r)
1416  LOOPIT(c)
1417  {
1418  itw(i,iti) = (*r) * (*c);
1419  ++iti;
1420  }
1421  }
1422 }
1423 
1425 
1448  const ArrayOfGridPos& pgp,
1449  const ArrayOfGridPos& rgp,
1450  const ArrayOfGridPos& cgp )
1451 {
1452  Index n = cgp.nelem();
1453  assert(is_size(pgp,n)); // pgp must have same size as cgp.
1454  assert(is_size(rgp,n)); // rgp must have same size as cgp.
1455  assert(is_size(itw,n,8)); // We must store 8 interpolation
1456  // weights for each position.
1457 
1458  // We have to loop all the points in the sequence:
1459  for ( Index i=0; i<n; ++i )
1460  {
1461  // Current grid positions:
1462  const GridPos& tp = pgp[i];
1463  const GridPos& tr = rgp[i];
1464  const GridPos& tc = cgp[i];
1465 
1466  Index iti = 0;
1467  LOOPIT(p)
1468  LOOPIT(r)
1469  LOOPIT(c)
1470  {
1471  itw(i,iti) = (*p) * (*r) * (*c);
1472  ++iti;
1473  }
1474  }
1475 }
1476 
1478 
1502  const ArrayOfGridPos& bgp,
1503  const ArrayOfGridPos& pgp,
1504  const ArrayOfGridPos& rgp,
1505  const ArrayOfGridPos& cgp )
1506 {
1507  Index n = cgp.nelem();
1508  assert(is_size(bgp,n)); // bgp must have same size as cgp.
1509  assert(is_size(pgp,n)); // pgp must have same size as cgp.
1510  assert(is_size(rgp,n)); // rgp must have same size as cgp.
1511  assert(is_size(itw,n,16)); // We must store 16 interpolation
1512  // weights for each position.
1513 
1514  // We have to loop all the points in the sequence:
1515  for ( Index i=0; i<n; ++i )
1516  {
1517  // Current grid positions:
1518  const GridPos& tb = bgp[i];
1519  const GridPos& tp = pgp[i];
1520  const GridPos& tr = rgp[i];
1521  const GridPos& tc = cgp[i];
1522 
1523  Index iti = 0;
1524  LOOPIT(b)
1525  LOOPIT(p)
1526  LOOPIT(r)
1527  LOOPIT(c)
1528  {
1529  itw(i,iti) = (*b) * (*p) * (*r) * (*c);
1530  ++iti;
1531  }
1532  }
1533 }
1534 
1536 
1561  const ArrayOfGridPos& sgp,
1562  const ArrayOfGridPos& bgp,
1563  const ArrayOfGridPos& pgp,
1564  const ArrayOfGridPos& rgp,
1565  const ArrayOfGridPos& cgp )
1566 {
1567  Index n = cgp.nelem();
1568  assert(is_size(sgp,n)); // sgp must have same size as cgp.
1569  assert(is_size(bgp,n)); // bgp must have same size as cgp.
1570  assert(is_size(pgp,n)); // pgp must have same size as cgp.
1571  assert(is_size(rgp,n)); // rgp must have same size as cgp.
1572  assert(is_size(itw,n,32)); // We must store 32 interpolation
1573  // weights for each position.
1574 
1575  // We have to loop all the points in the sequence:
1576  for ( Index i=0; i<n; ++i )
1577  {
1578  // Current grid positions:
1579  const GridPos& ts = sgp[i];
1580  const GridPos& tb = bgp[i];
1581  const GridPos& tp = pgp[i];
1582  const GridPos& tr = rgp[i];
1583  const GridPos& tc = cgp[i];
1584 
1585  Index iti = 0;
1586  LOOPIT(s)
1587  LOOPIT(b)
1588  LOOPIT(p)
1589  LOOPIT(r)
1590  LOOPIT(c)
1591  {
1592  itw(i,iti) = (*s) * (*b) * (*p) * (*r) * (*c);
1593  ++iti;
1594  }
1595  }
1596 }
1597 
1599 
1625  const ArrayOfGridPos& vgp,
1626  const ArrayOfGridPos& sgp,
1627  const ArrayOfGridPos& bgp,
1628  const ArrayOfGridPos& pgp,
1629  const ArrayOfGridPos& rgp,
1630  const ArrayOfGridPos& cgp )
1631 {
1632  Index n = cgp.nelem();
1633  assert(is_size(vgp,n)); // vgp must have same size as cgp.
1634  assert(is_size(sgp,n)); // sgp must have same size as cgp.
1635  assert(is_size(bgp,n)); // bgp must have same size as cgp.
1636  assert(is_size(pgp,n)); // pgp must have same size as cgp.
1637  assert(is_size(rgp,n)); // rgp must have same size as cgp.
1638  assert(is_size(itw,n,64)); // We must store 64 interpolation
1639  // weights for each position.
1640 
1641  // We have to loop all the points in the sequence:
1642  for ( Index i=0; i<n; ++i )
1643  {
1644  // Current grid positions:
1645  const GridPos& tv = vgp[i];
1646  const GridPos& ts = sgp[i];
1647  const GridPos& tb = bgp[i];
1648  const GridPos& tp = pgp[i];
1649  const GridPos& tr = rgp[i];
1650  const GridPos& tc = cgp[i];
1651 
1652  Index iti = 0;
1653  LOOPIT(v)
1654  LOOPIT(s)
1655  LOOPIT(b)
1656  LOOPIT(p)
1657  LOOPIT(r)
1658  LOOPIT(c)
1659  {
1660  itw(i,iti) = (*v) * (*s) * (*b) * (*p) * (*r) * (*c);
1661  ++iti;
1662  }
1663  }
1664 }
1665 
1667 
1684  ConstMatrixView itw,
1685  ConstVectorView a,
1686  const ArrayOfGridPos& cgp)
1687 {
1688  Index n = cgp.nelem();
1689  assert(is_size(ia,n)); // ia must have same size as cgp.
1690  assert(is_size(itw,n,2)); // We need 2 interpolation
1691  // weights for each position.
1692 
1693  // Check that interpolation weights are valid. The sum of all
1694  // weights (last dimension) must always be approximately one. We
1695  // only check the first element.
1696  assert( is_same_within_epsilon( itw(0,Range(joker)).sum(),
1697  1,
1698  sum_check_epsilon ) );
1699 
1700  // We have to loop all the points in the sequence:
1701  for ( Index i=0; i<n; ++i )
1702  {
1703  // Current grid positions:
1704  const GridPos& tc = cgp[i];
1705 
1706  // Get handle to current element of output vector and initialize
1707  // it to zero:
1708  Numeric& tia = ia[i];
1709  tia = 0;
1710 
1711  Index iti = 0;
1712  for ( Index c=0; c<2; ++c )
1713  {
1714  tia += a[tc.idx+c] * itw(i,iti);
1715  ++iti;
1716  }
1717  }
1718 }
1719 
1721 
1743  ConstMatrixView itw,
1744  ConstMatrixView a,
1745  const ArrayOfGridPos& rgp,
1746  const ArrayOfGridPos& cgp)
1747 {
1748  Index n = cgp.nelem();
1749  assert(is_size(ia,n)); // ia must have same size as cgp.
1750  assert(is_size(rgp,n)); // rgp must have same size as cgp.
1751  assert(is_size(itw,n,4)); // We need 4 interpolation
1752  // weights for each position.
1753 
1754  // Check that interpolation weights are valid. The sum of all
1755  // weights (last dimension) must always be approximately one. We
1756  // only check the first element.
1757  assert( is_same_within_epsilon( itw(0,Range(joker)).sum(),
1758  1,
1759  sum_check_epsilon ) );
1760 
1761  // We have to loop all the points in the sequence:
1762  for ( Index i=0; i<n; ++i )
1763  {
1764  // Current grid positions:
1765  const GridPos& tr = rgp[i];
1766  const GridPos& tc = cgp[i];
1767 
1768  // Get handle to current element of output vector and initialize
1769  // it to zero:
1770  Numeric& tia = ia[i];
1771  tia = 0;
1772 
1773  Index iti = 0;
1774  for ( Index r=0; r<2; ++r )
1775  for ( Index c=0; c<2; ++c )
1776  {
1777  tia += a(tr.idx+r,
1778  tc.idx+c) * itw(i,iti);
1779  ++iti;
1780  }
1781  }
1782 }
1783 
1785 
1808  ConstMatrixView itw,
1809  ConstTensor3View a,
1810  const ArrayOfGridPos& pgp,
1811  const ArrayOfGridPos& rgp,
1812  const ArrayOfGridPos& cgp)
1813 {
1814  Index n = cgp.nelem();
1815  assert(is_size(ia,n)); // ia must have same size as cgp.
1816  assert(is_size(pgp,n)); // pgp must have same size as cgp.
1817  assert(is_size(rgp,n)); // rgp must have same size as cgp.
1818  assert(is_size(itw,n,8)); // We need 8 interpolation
1819  // weights for each position.
1820 
1821  // Check that interpolation weights are valid. The sum of all
1822  // weights (last dimension) must always be approximately one. We
1823  // only check the first element.
1824  assert( is_same_within_epsilon( itw(0,Range(joker)).sum(),
1825  1,
1826  sum_check_epsilon ) );
1827 
1828  // We have to loop all the points in the sequence:
1829  for ( Index i=0; i<n; ++i )
1830  {
1831  // Current grid positions:
1832  const GridPos& tp = pgp[i];
1833  const GridPos& tr = rgp[i];
1834  const GridPos& tc = cgp[i];
1835 
1836  // Get handle to current element of output vector and initialize
1837  // it to zero:
1838  Numeric& tia = ia[i];
1839  tia = 0;
1840 
1841  Index iti = 0;
1842  for ( Index p=0; p<2; ++p )
1843  for ( Index r=0; r<2; ++r )
1844  for ( Index c=0; c<2; ++c )
1845  {
1846  tia += a(tp.idx+p,
1847  tr.idx+r,
1848  tc.idx+c) * itw(i,iti);
1849  ++iti;
1850  }
1851  }
1852 }
1853 
1855 
1879  ConstMatrixView itw,
1880  ConstTensor4View a,
1881  const ArrayOfGridPos& bgp,
1882  const ArrayOfGridPos& pgp,
1883  const ArrayOfGridPos& rgp,
1884  const ArrayOfGridPos& cgp)
1885 {
1886  Index n = cgp.nelem();
1887  assert(is_size(ia,n)); // ia must have same size as cgp.
1888  assert(is_size(bgp,n)); // bgp must have same size as cgp.
1889  assert(is_size(pgp,n)); // pgp must have same size as cgp.
1890  assert(is_size(rgp,n)); // rgp must have same size as cgp.
1891  assert(is_size(itw,n,16)); // We need 16 interpolation
1892  // weights for each position.
1893 
1894  // Check that interpolation weights are valid. The sum of all
1895  // weights (last dimension) must always be approximately one. We
1896  // only check the first element.
1897  assert( is_same_within_epsilon( itw(0,Range(joker)).sum(),
1898  1,
1899  sum_check_epsilon ) );
1900 
1901  // We have to loop all the points in the sequence:
1902  for ( Index i=0; i<n; ++i )
1903  {
1904  // Current grid positions:
1905  const GridPos& tb = bgp[i];
1906  const GridPos& tp = pgp[i];
1907  const GridPos& tr = rgp[i];
1908  const GridPos& tc = cgp[i];
1909 
1910  // Get handle to current element of output vector and initialize
1911  // it to zero:
1912  Numeric& tia = ia[i];
1913  tia = 0;
1914 
1915  Index iti = 0;
1916  for ( Index b=0; b<2; ++b )
1917  for ( Index p=0; p<2; ++p )
1918  for ( Index r=0; r<2; ++r )
1919  for ( Index c=0; c<2; ++c )
1920  {
1921  tia += a(tb.idx+b,
1922  tp.idx+p,
1923  tr.idx+r,
1924  tc.idx+c) * itw(i,iti);
1925  ++iti;
1926  }
1927  }
1928 }
1929 
1931 
1956  ConstMatrixView itw,
1957  ConstTensor5View a,
1958  const ArrayOfGridPos& sgp,
1959  const ArrayOfGridPos& bgp,
1960  const ArrayOfGridPos& pgp,
1961  const ArrayOfGridPos& rgp,
1962  const ArrayOfGridPos& cgp)
1963 {
1964  Index n = cgp.nelem();
1965  assert(is_size(ia,n)); // ia must have same size as cgp.
1966  assert(is_size(sgp,n)); // sgp must have same size as cgp.
1967  assert(is_size(bgp,n)); // bgp must have same size as cgp.
1968  assert(is_size(pgp,n)); // pgp must have same size as cgp.
1969  assert(is_size(rgp,n)); // rgp must have same size as cgp.
1970  assert(is_size(itw,n,32)); // We need 32 interpolation
1971  // weights for each position.
1972 
1973  // Check that interpolation weights are valid. The sum of all
1974  // weights (last dimension) must always be approximately one. We
1975  // only check the first element.
1976  assert( is_same_within_epsilon( itw(0,Range(joker)).sum(),
1977  1,
1978  sum_check_epsilon ) );
1979 
1980  // We have to loop all the points in the sequence:
1981  for ( Index i=0; i<n; ++i )
1982  {
1983  // Current grid positions:
1984  const GridPos& ts = sgp[i];
1985  const GridPos& tb = bgp[i];
1986  const GridPos& tp = pgp[i];
1987  const GridPos& tr = rgp[i];
1988  const GridPos& tc = cgp[i];
1989 
1990  // Get handle to current element of output vector and initialize
1991  // it to zero:
1992  Numeric& tia = ia[i];
1993  tia = 0;
1994 
1995  Index iti = 0;
1996  for ( Index s=0; s<2; ++s )
1997  for ( Index b=0; b<2; ++b )
1998  for ( Index p=0; p<2; ++p )
1999  for ( Index r=0; r<2; ++r )
2000  for ( Index c=0; c<2; ++c )
2001  {
2002  tia += a(ts.idx+s,
2003  tb.idx+b,
2004  tp.idx+p,
2005  tr.idx+r,
2006  tc.idx+c) * itw(i,iti);
2007  ++iti;
2008  }
2009  }
2010 }
2011 
2013 
2039  ConstMatrixView itw,
2040  ConstTensor6View a,
2041  const ArrayOfGridPos& vgp,
2042  const ArrayOfGridPos& sgp,
2043  const ArrayOfGridPos& bgp,
2044  const ArrayOfGridPos& pgp,
2045  const ArrayOfGridPos& rgp,
2046  const ArrayOfGridPos& cgp)
2047 {
2048  Index n = cgp.nelem();
2049  assert(is_size(ia,n)); // ia must have same size as cgp.
2050  assert(is_size(vgp,n)); // vgp must have same size as cgp.
2051  assert(is_size(sgp,n)); // sgp must have same size as cgp.
2052  assert(is_size(bgp,n)); // bgp must have same size as cgp.
2053  assert(is_size(pgp,n)); // pgp must have same size as cgp.
2054  assert(is_size(rgp,n)); // rgp must have same size as cgp.
2055  assert(is_size(itw,n,64)); // We need 64 interpolation
2056  // weights for each position.
2057 
2058  // Check that interpolation weights are valid. The sum of all
2059  // weights (last dimension) must always be approximately one. We
2060  // only check the first element.
2061  assert( is_same_within_epsilon( itw(0,Range(joker)).sum(),
2062  1,
2063  sum_check_epsilon ) );
2064 
2065  // We have to loop all the points in the sequence:
2066  for ( Index i=0; i<n; ++i )
2067  {
2068  // Current grid positions:
2069  const GridPos& tv = vgp[i];
2070  const GridPos& ts = sgp[i];
2071  const GridPos& tb = bgp[i];
2072  const GridPos& tp = pgp[i];
2073  const GridPos& tr = rgp[i];
2074  const GridPos& tc = cgp[i];
2075 
2076  // Get handle to current element of output vector and initialize
2077  // it to zero:
2078  Numeric& tia = ia[i];
2079  tia = 0;
2080 
2081  Index iti = 0;
2082  for ( Index v=0; v<2; ++v )
2083  for ( Index s=0; s<2; ++s )
2084  for ( Index b=0; b<2; ++b )
2085  for ( Index p=0; p<2; ++p )
2086  for ( Index r=0; r<2; ++r )
2087  for ( Index c=0; c<2; ++c )
2088  {
2089  tia += a(tv.idx+v,
2090  ts.idx+s,
2091  tb.idx+b,
2092  tp.idx+p,
2093  tr.idx+r,
2094  tc.idx+c) * itw(i,iti);
2095  ++iti;
2096  }
2097  }
2098 }
2099 
2101 // Green interpolation
2103 
2105 
2127  const ArrayOfGridPos& rgp,
2128  const ArrayOfGridPos& cgp )
2129 {
2130  Index nr = rgp.nelem();
2131  Index nc = cgp.nelem();
2132  assert(is_size(itw,nr,nc,4)); // We must store 4 interpolation
2133  // weights for each position.
2134 
2135  // We have to loop all the points in the new grid:
2136  for ( Index ir=0; ir<nr; ++ir )
2137  {
2138  // Current grid position:
2139  const GridPos& tr = rgp[ir];
2140 
2141  for ( Index ic=0; ic<nc; ++ic )
2142  {
2143  // Current grid position:
2144  const GridPos& tc = cgp[ic];
2145 
2146  // Interpolation weights are stored in this order (l=lower
2147  // u=upper, r=row, c=column):
2148  // 1. l-r l-c
2149  // 2. l-r u-c
2150  // 3. u-r l-c
2151  // 4. u-r u-c
2152 
2153  Index iti = 0;
2154 
2155  LOOPIT(r)
2156  LOOPIT(c)
2157  {
2158  itw(ir,ic,iti) = (*r) * (*c);
2159  ++iti;
2160  }
2161  }
2162  }
2163 }
2164 
2166 
2189  const ArrayOfGridPos& pgp,
2190  const ArrayOfGridPos& rgp,
2191  const ArrayOfGridPos& cgp )
2192 {
2193  Index np = pgp.nelem();
2194  Index nr = rgp.nelem();
2195  Index nc = cgp.nelem();
2196  // We must store 8 interpolation weights for each position:
2197  assert(is_size(itw,np,nr,nc,8));
2198 
2199  // We have to loop all the points in the new grid:
2200  for ( Index ip=0; ip<np; ++ip )
2201  {
2202  const GridPos& tp = pgp[ip];
2203  for ( Index ir=0; ir<nr; ++ir )
2204  {
2205  const GridPos& tr = rgp[ir];
2206  for ( Index ic=0; ic<nc; ++ic )
2207  {
2208  const GridPos& tc = cgp[ic];
2209 
2210  Index iti = 0;
2211 
2212  LOOPIT(p)
2213  LOOPIT(r)
2214  LOOPIT(c)
2215  {
2216  itw(ip,ir,ic,iti) =
2217  (*p) * (*r) * (*c);
2218  ++iti;
2219  }
2220  }
2221  }
2222  }
2223 }
2224 
2226 
2250  const ArrayOfGridPos& bgp,
2251  const ArrayOfGridPos& pgp,
2252  const ArrayOfGridPos& rgp,
2253  const ArrayOfGridPos& cgp )
2254 {
2255  Index nb = bgp.nelem();
2256  Index np = pgp.nelem();
2257  Index nr = rgp.nelem();
2258  Index nc = cgp.nelem();
2259  // We must store 16 interpolation weights for each position:
2260  assert(is_size(itw,nb,np,nr,nc,16));
2261 
2262  // We have to loop all the points in the new grid:
2263  for ( Index ib=0; ib<nb; ++ib )
2264  {
2265  const GridPos& tb = bgp[ib];
2266  for ( Index ip=0; ip<np; ++ip )
2267  {
2268  const GridPos& tp = pgp[ip];
2269  for ( Index ir=0; ir<nr; ++ir )
2270  {
2271  const GridPos& tr = rgp[ir];
2272  for ( Index ic=0; ic<nc; ++ic )
2273  {
2274  const GridPos& tc = cgp[ic];
2275 
2276  Index iti = 0;
2277 
2278  LOOPIT(b)
2279  LOOPIT(p)
2280  LOOPIT(r)
2281  LOOPIT(c)
2282  {
2283  itw(ib,ip,ir,ic,iti) =
2284  (*b) * (*p) * (*r) * (*c);
2285  ++iti;
2286  }
2287  }
2288  }
2289  }
2290  }
2291 }
2292 
2294 
2319  const ArrayOfGridPos& sgp,
2320  const ArrayOfGridPos& bgp,
2321  const ArrayOfGridPos& pgp,
2322  const ArrayOfGridPos& rgp,
2323  const ArrayOfGridPos& cgp )
2324 {
2325  Index ns = sgp.nelem();
2326  Index nb = bgp.nelem();
2327  Index np = pgp.nelem();
2328  Index nr = rgp.nelem();
2329  Index nc = cgp.nelem();
2330  // We must store 32 interpolation weights for each position:
2331  assert(is_size(itw,ns,nb,np,nr,nc,32));
2332 
2333  // We have to loop all the points in the new grid:
2334  for ( Index is=0; is<ns; ++is )
2335  {
2336  const GridPos& ts = sgp[is];
2337  for ( Index ib=0; ib<nb; ++ib )
2338  {
2339  const GridPos& tb = bgp[ib];
2340  for ( Index ip=0; ip<np; ++ip )
2341  {
2342  const GridPos& tp = pgp[ip];
2343  for ( Index ir=0; ir<nr; ++ir )
2344  {
2345  const GridPos& tr = rgp[ir];
2346  for ( Index ic=0; ic<nc; ++ic )
2347  {
2348  const GridPos& tc = cgp[ic];
2349 
2350  Index iti = 0;
2351 
2352  LOOPIT(s)
2353  LOOPIT(b)
2354  LOOPIT(p)
2355  LOOPIT(r)
2356  LOOPIT(c)
2357  {
2358  itw(is,ib,ip,ir,ic,iti) =
2359  (*s) * (*b) * (*p) * (*r) * (*c);
2360  ++iti;
2361  }
2362  }
2363  }
2364  }
2365  }
2366  }
2367 }
2368 
2370 
2396  const ArrayOfGridPos& vgp,
2397  const ArrayOfGridPos& sgp,
2398  const ArrayOfGridPos& bgp,
2399  const ArrayOfGridPos& pgp,
2400  const ArrayOfGridPos& rgp,
2401  const ArrayOfGridPos& cgp )
2402 {
2403  Index nv = vgp.nelem();
2404  Index ns = sgp.nelem();
2405  Index nb = bgp.nelem();
2406  Index np = pgp.nelem();
2407  Index nr = rgp.nelem();
2408  Index nc = cgp.nelem();
2409  // We must store 64 interpolation weights for each position:
2410  assert(is_size(itw,nv,ns,nb,np,nr,nc,64));
2411 
2412  // We have to loop all the points in the new grid:
2413  for ( Index iv=0; iv<nv; ++iv )
2414  {
2415  const GridPos& tv = vgp[iv];
2416  for ( Index is=0; is<ns; ++is )
2417  {
2418  const GridPos& ts = sgp[is];
2419  for ( Index ib=0; ib<nb; ++ib )
2420  {
2421  const GridPos& tb = bgp[ib];
2422  for ( Index ip=0; ip<np; ++ip )
2423  {
2424  const GridPos& tp = pgp[ip];
2425  for ( Index ir=0; ir<nr; ++ir )
2426  {
2427  const GridPos& tr = rgp[ir];
2428  for ( Index ic=0; ic<nc; ++ic )
2429  {
2430  const GridPos& tc = cgp[ic];
2431 
2432  Index iti = 0;
2433 
2434  LOOPIT(v)
2435  LOOPIT(s)
2436  LOOPIT(b)
2437  LOOPIT(p)
2438  LOOPIT(r)
2439  LOOPIT(c)
2440  {
2441  itw(iv,is,ib,ip,ir,ic,iti) =
2442  (*v) * (*s) * (*b) * (*p) * (*r) * (*c);
2443  ++iti;
2444  }
2445  }
2446  }
2447  }
2448  }
2449  }
2450  }
2451 }
2452 
2454 
2476  ConstTensor3View itw,
2477  ConstMatrixView a,
2478  const ArrayOfGridPos& rgp,
2479  const ArrayOfGridPos& cgp)
2480 {
2481  Index nr = rgp.nelem();
2482  Index nc = cgp.nelem();
2483  assert(is_size(ia,nr,nc));
2484  assert(is_size(itw,nr,nc,4)); // We need 4 interpolation
2485  // weights for each position.
2486 
2487  // Check that interpolation weights are valid. The sum of all
2488  // weights (last dimension) must always be approximately one. We
2489  // only check the first element.
2490  assert( is_same_within_epsilon( itw(0,0,Range(joker)).sum(),
2491  1,
2492  sum_check_epsilon ) );
2493 
2494  // We have to loop all the points in the new grid:
2495  for ( Index ir=0; ir<nr; ++ir )
2496  {
2497  // Current grid position:
2498  const GridPos& tr = rgp[ir];
2499 
2500  for ( Index ic=0; ic<nc; ++ic )
2501  {
2502  // Current grid position:
2503  const GridPos& tc = cgp[ic];
2504 
2505  // Get handle to current element of output tensor and initialize
2506  // it to zero:
2507  Numeric& tia = ia(ir,ic);
2508  tia = 0;
2509 
2510  Index iti = 0;
2511  for ( Index r=0; r<2; ++r )
2512  for ( Index c=0; c<2; ++c )
2513  {
2514  tia += a(tr.idx+r,
2515  tc.idx+c) * itw(ir,ic,iti);
2516  ++iti;
2517  }
2518  }
2519  }
2520 }
2521 
2523 
2546  ConstTensor4View itw,
2547  ConstTensor3View a,
2548  const ArrayOfGridPos& pgp,
2549  const ArrayOfGridPos& rgp,
2550  const ArrayOfGridPos& cgp)
2551 {
2552  Index np = pgp.nelem();
2553  Index nr = rgp.nelem();
2554  Index nc = cgp.nelem();
2555  assert(is_size(ia,
2556  np,nr,nc));
2557  assert(is_size(itw,
2558  np,nr,nc,
2559  8));
2560 
2561  // Check that interpolation weights are valid. The sum of all
2562  // weights (last dimension) must always be approximately one. We
2563  // only check the first element.
2564  assert( is_same_within_epsilon( itw(0,0,0,Range(joker)).sum(),
2565  1,
2566  sum_check_epsilon ) );
2567 
2568  // We have to loop all the points in the new grid:
2569  for ( Index ip=0; ip<np; ++ip )
2570  {
2571  const GridPos& tp = pgp[ip];
2572  for ( Index ir=0; ir<nr; ++ir )
2573  {
2574  const GridPos& tr = rgp[ir];
2575  for ( Index ic=0; ic<nc; ++ic )
2576  {
2577  // Current grid position:
2578  const GridPos& tc = cgp[ic];
2579 
2580  // Get handle to current element of output tensor and
2581  // initialize it to zero:
2582  Numeric& tia = ia(ip,ir,ic);
2583  tia = 0;
2584 
2585  Index iti = 0;
2586  for ( Index p=0; p<2; ++p )
2587  for ( Index r=0; r<2; ++r )
2588  for ( Index c=0; c<2; ++c )
2589  {
2590  tia += a(tp.idx+p,
2591  tr.idx+r,
2592  tc.idx+c) * itw(ip,ir,ic,
2593  iti);
2594  ++iti;
2595  }
2596  }
2597  }
2598  }
2599 }
2600 
2602 
2626  ConstTensor5View itw,
2627  ConstTensor4View a,
2628  const ArrayOfGridPos& bgp,
2629  const ArrayOfGridPos& pgp,
2630  const ArrayOfGridPos& rgp,
2631  const ArrayOfGridPos& cgp)
2632 {
2633  Index nb = bgp.nelem();
2634  Index np = pgp.nelem();
2635  Index nr = rgp.nelem();
2636  Index nc = cgp.nelem();
2637  assert(is_size(ia,
2638  nb,np,nr,nc));
2639  assert(is_size(itw,
2640  nb,np,nr,nc,
2641  16));
2642 
2643  // Check that interpolation weights are valid. The sum of all
2644  // weights (last dimension) must always be approximately one. We
2645  // only check the first element.
2646  assert( is_same_within_epsilon( itw(0,0,0,0,Range(joker)).sum(),
2647  1,
2648  sum_check_epsilon ) );
2649 
2650  // We have to loop all the points in the new grid:
2651  for ( Index ib=0; ib<nb; ++ib )
2652  {
2653  const GridPos& tb = bgp[ib];
2654  for ( Index ip=0; ip<np; ++ip )
2655  {
2656  const GridPos& tp = pgp[ip];
2657  for ( Index ir=0; ir<nr; ++ir )
2658  {
2659  const GridPos& tr = rgp[ir];
2660  for ( Index ic=0; ic<nc; ++ic )
2661  {
2662  // Current grid position:
2663  const GridPos& tc = cgp[ic];
2664 
2665  // Get handle to current element of output tensor and
2666  // initialize it to zero:
2667  Numeric& tia = ia(ib,ip,ir,ic);
2668  tia = 0;
2669 
2670  Index iti = 0;
2671  for ( Index b=0; b<2; ++b )
2672  for ( Index p=0; p<2; ++p )
2673  for ( Index r=0; r<2; ++r )
2674  for ( Index c=0; c<2; ++c )
2675  {
2676  tia += a(tb.idx+b,
2677  tp.idx+p,
2678  tr.idx+r,
2679  tc.idx+c) * itw(ib,ip,ir,ic,
2680  iti);
2681  ++iti;
2682  }
2683  }
2684  }
2685  }
2686  }
2687 }
2688 
2690 
2715  ConstTensor6View itw,
2716  ConstTensor5View a,
2717  const ArrayOfGridPos& sgp,
2718  const ArrayOfGridPos& bgp,
2719  const ArrayOfGridPos& pgp,
2720  const ArrayOfGridPos& rgp,
2721  const ArrayOfGridPos& cgp)
2722 {
2723  Index ns = sgp.nelem();
2724  Index nb = bgp.nelem();
2725  Index np = pgp.nelem();
2726  Index nr = rgp.nelem();
2727  Index nc = cgp.nelem();
2728  assert(is_size(ia,
2729  ns,nb,np,nr,nc));
2730  assert(is_size(itw,
2731  ns,nb,np,nr,nc,
2732  32));
2733 
2734  // Check that interpolation weights are valid. The sum of all
2735  // weights (last dimension) must always be approximately one. We
2736  // only check the first element.
2737  assert( is_same_within_epsilon( itw(0,0,0,0,0,Range(joker)).sum(),
2738  1,
2739  sum_check_epsilon ) );
2740 
2741  // We have to loop all the points in the new grid:
2742  for ( Index is=0; is<ns; ++is )
2743  {
2744  const GridPos& ts = sgp[is];
2745  for ( Index ib=0; ib<nb; ++ib )
2746  {
2747  const GridPos& tb = bgp[ib];
2748  for ( Index ip=0; ip<np; ++ip )
2749  {
2750  const GridPos& tp = pgp[ip];
2751  for ( Index ir=0; ir<nr; ++ir )
2752  {
2753  const GridPos& tr = rgp[ir];
2754  for ( Index ic=0; ic<nc; ++ic )
2755  {
2756  // Current grid position:
2757  const GridPos& tc = cgp[ic];
2758 
2759  // Get handle to current element of output tensor and
2760  // initialize it to zero:
2761  Numeric& tia = ia(is,ib,ip,ir,ic);
2762  tia = 0;
2763 
2764  Index iti = 0;
2765  for ( Index s=0; s<2; ++s )
2766  for ( Index b=0; b<2; ++b )
2767  for ( Index p=0; p<2; ++p )
2768  for ( Index r=0; r<2; ++r )
2769  for ( Index c=0; c<2; ++c )
2770  {
2771  tia += a(ts.idx+s,
2772  tb.idx+b,
2773  tp.idx+p,
2774  tr.idx+r,
2775  tc.idx+c) * itw(is,ib,ip,ir,ic,
2776  iti);
2777  ++iti;
2778  }
2779  }
2780  }
2781  }
2782  }
2783  }
2784 }
2785 
2787 
2813  ConstTensor7View itw,
2814  ConstTensor6View a,
2815  const ArrayOfGridPos& vgp,
2816  const ArrayOfGridPos& sgp,
2817  const ArrayOfGridPos& bgp,
2818  const ArrayOfGridPos& pgp,
2819  const ArrayOfGridPos& rgp,
2820  const ArrayOfGridPos& cgp)
2821 {
2822  Index nv = vgp.nelem();
2823  Index ns = sgp.nelem();
2824  Index nb = bgp.nelem();
2825  Index np = pgp.nelem();
2826  Index nr = rgp.nelem();
2827  Index nc = cgp.nelem();
2828  assert(is_size(ia,
2829  nv,ns,nb,np,nr,nc));
2830  assert(is_size(itw,
2831  nv,ns,nb,np,nr,nc,
2832  64));
2833 
2834  // Check that interpolation weights are valid. The sum of all
2835  // weights (last dimension) must always be approximately one. We
2836  // only check the first element.
2837  assert( is_same_within_epsilon( itw(0,0,0,0,0,0,Range(joker)).sum(),
2838  1,
2839  sum_check_epsilon ) );
2840 
2841  // We have to loop all the points in the new grid:
2842  for ( Index iv=0; iv<nv; ++iv )
2843  {
2844  const GridPos& tv = vgp[iv];
2845  for ( Index is=0; is<ns; ++is )
2846  {
2847  const GridPos& ts = sgp[is];
2848  for ( Index ib=0; ib<nb; ++ib )
2849  {
2850  const GridPos& tb = bgp[ib];
2851  for ( Index ip=0; ip<np; ++ip )
2852  {
2853  const GridPos& tp = pgp[ip];
2854  for ( Index ir=0; ir<nr; ++ir )
2855  {
2856  const GridPos& tr = rgp[ir];
2857  for ( Index ic=0; ic<nc; ++ic )
2858  {
2859  // Current grid position:
2860  const GridPos& tc = cgp[ic];
2861 
2862  // Get handle to current element of output tensor and
2863  // initialize it to zero:
2864  Numeric& tia = ia(iv,is,ib,ip,ir,ic);
2865  tia = 0;
2866 
2867  Index iti = 0;
2868  for ( Index v=0; v<2; ++v )
2869  for ( Index s=0; s<2; ++s )
2870  for ( Index b=0; b<2; ++b )
2871  for ( Index p=0; p<2; ++p )
2872  for ( Index r=0; r<2; ++r )
2873  for ( Index c=0; c<2; ++c )
2874  {
2875  tia += a(tv.idx+v,
2876  ts.idx+s,
2877  tb.idx+b,
2878  tp.idx+p,
2879  tr.idx+r,
2880  tc.idx+c) * itw(iv,is,ib,ip,ir,ic,
2881  iti);
2882  ++iti;
2883  }
2884  }
2885  }
2886  }
2887  }
2888  }
2889  }
2890 }
2891 
2892 
2894 
2910  ConstVectorView y,
2911  const Numeric& x_i,
2912  const GridPos& gp)
2913 {
2914  Index N_x = x.nelem();
2915 
2916  assert(N_x == y.nelem());
2917  assert(N_x > 2);
2918 
2919  Vector xa(4), ya(4);
2920  Numeric y_int;
2921  Numeric dy_int;
2922  y_int = 0.;
2923 
2924  // 1 - polynomial interpolation (3 points) with grid position search
2925  // 2 - polynomial interpolation (3 points) without grid position search
2926  // 3 - polynomial interpolation (4 points)
2927 
2928  Index interp_method = 1;
2929 
2930  if (interp_method == 1)
2931  {
2932 
2933  // Pick out three points for interpolation
2934  if((gp.fd[0] <= 0.5 && gp.idx > 0) || gp.idx == N_x-2 )
2935  {
2936  xa[0] = x[gp.idx - 1];
2937  xa[1] = x[gp.idx];
2938  xa[2] = x[gp.idx + 1];
2939 
2940  ya[0] = y[gp.idx - 1];
2941  ya[1] = y[gp.idx];
2942  ya[2] = y[gp.idx + 1];
2943  }
2944 
2945  else if((gp.fd[0] > 0.5 && gp.idx < N_x-2) || gp.idx == 0 )
2946  {
2947  xa[0] = x[gp.idx];
2948  xa[1] = x[gp.idx + 1];
2949  xa[2] = x[gp.idx + 2];
2950 
2951  ya[0] = y[gp.idx];
2952  ya[1] = y[gp.idx + 1];
2953  ya[2] = y[gp.idx + 2];
2954  }
2955 
2956  else if(gp.idx == N_x-1)
2957  {
2958  xa[0] = x[N_x - 2];
2959  xa[1] = x[N_x - 1];
2960  xa[2] = x[N_x];
2961 
2962  ya[0] = y[N_x - 2];
2963  ya[1] = y[N_x - 1];
2964  ya[2] = y[N_x];
2965  }
2966  else
2967  {
2968  assert(false);
2969  arts_exit();
2970  }
2971 
2972  polint(y_int, dy_int, xa, ya, 3, x_i);
2973 
2974  }
2975 
2976  else if (interp_method == 2)
2977  {
2978  if( gp.idx == 0 )
2979  {
2980  xa[0] = x[gp.idx];
2981  xa[1] = x[gp.idx + 1];
2982  xa[2] = x[gp.idx + 2];
2983 
2984  ya[0] = y[gp.idx];
2985  ya[1] = y[gp.idx + 1];
2986  ya[2] = y[gp.idx + 2];
2987  }
2988  else if(gp.idx == N_x-1)
2989  {
2990  xa[0] = x[gp.idx - 2];
2991  xa[1] = x[gp.idx - 1];
2992  xa[2] = x[gp.idx];
2993 
2994  ya[0] = y[gp.idx - 2];
2995  ya[1] = y[gp.idx - 1];
2996  ya[2] = y[gp.idx];
2997  }
2998  else
2999  {
3000  xa[0] = x[gp.idx - 1];
3001  xa[1] = x[gp.idx];
3002  xa[2] = x[gp.idx + 1];
3003 
3004  ya[0] = y[gp.idx - 1];
3005  ya[1] = y[gp.idx];
3006  ya[2] = y[gp.idx + 1];
3007  }
3008 
3009  // Polinominal interpolation, n = 3
3010  polint(y_int, dy_int, xa, ya, 3, x_i);
3011  }
3012 
3013  else if (interp_method == 3)
3014  {
3015  // Take 4 points
3016  if( gp.idx == 0 )
3017  {
3018  xa[0] = - x[gp.idx + 1];
3019  xa[1] = x[gp.idx + 0];
3020  xa[2] = x[gp.idx + 1];
3021  xa[3] = x[gp.idx + 2];
3022 
3023  ya[0] = y[gp.idx + 1];
3024  ya[1] = y[gp.idx + 0];
3025  ya[2] = y[gp.idx + 1];
3026  ya[3] = y[gp.idx + 2];
3027  }
3028  else if(gp.idx == N_x-1)
3029  {
3030  xa[0] = x[gp.idx - 1];
3031  xa[1] = x[gp.idx - 0];
3032  xa[2] = 2*x[gp.idx] - x[gp.idx-1];
3033  xa[3] = 2*x[gp.idx] - x[gp.idx-2];
3034 
3035  ya[0] = y[gp.idx - 1];
3036  ya[1] = y[gp.idx - 0];
3037  ya[2] = y[gp.idx - 1];
3038  ya[3] = y[gp.idx - 2];
3039  }
3040  else if(gp.idx == N_x-2)
3041  {
3042  xa[0] = x[gp.idx - 2];
3043  xa[1] = x[gp.idx - 1];
3044  xa[2] = x[gp.idx ];
3045  xa[3] = x[gp.idx + 1];
3046 
3047  ya[0] = y[gp.idx - 2];
3048  ya[1] = y[gp.idx - 1];
3049  ya[2] = y[gp.idx];
3050  ya[3] = y[gp.idx + 1];
3051  }
3052  else
3053  {
3054  xa[0] = x[gp.idx - 1];
3055  xa[1] = x[gp.idx];
3056  xa[2] = x[gp.idx + 1];
3057  xa[3] = x[gp.idx + 2];
3058 
3059  ya[0] = y[gp.idx - 1];
3060  ya[1] = y[gp.idx];
3061  ya[2] = y[gp.idx + 1];
3062  ya[3] = y[gp.idx + 2];
3063  }
3064  // Polinominal interpolation, n = 4
3065  polint(y_int, dy_int, xa, ya, 4, x_i);
3066  }
3067 
3068 
3069  return y_int;
3070 }
3071 
3072 
3073 
3074 
3076 
3095 void polint(Numeric& y_int,
3096  Numeric& dy_int,
3097  ConstVectorView xa,
3098  ConstVectorView ya,
3099  const Index& n,
3100  const Numeric& x)
3101 {
3102  Index ns = 1;
3103  Numeric den, dif, dift, ho, hp, w;
3104 
3105  dif = abs(x-xa[0]);
3106 
3107  Vector c(n);
3108  Vector d(n);
3109 
3110  // Find the index of the closest table entry
3111  for(Index i=0; i<n; i++)
3112  {
3113  if( (dift = abs(x-xa[i])) < dif)
3114  {
3115  ns = i;
3116  dif = dift;
3117  }
3118  // Initialize c and d
3119  c[i] = ya[i];
3120  d[i] = ya[i];
3121  }
3122  // Initial approximation to y
3123  y_int = ya[ns--];
3124 
3125  for(Index m=1; m<n; m++)
3126  {
3127  for(Index i=0; i < n-m; i++)
3128  {
3129  ho = xa[i] - x;
3130  hp = xa[i+m] - x;
3131  w = c[i+1] - d[i];
3132  den = ho-hp;
3133  // This error occurs when two input xa's are identical.
3134  assert(den != 0.);
3135  den = w/den;
3136  d[i] = hp * den;
3137  c[i] = ho * den;
3138  }
3139  y_int += (dy_int = (2*(ns+1) < (n-m) ? c[ns+1] : d[ns--] ));
3140  }
3141 }
3142 
3143 
3144 
3145 
Tensor7View
The Tensor7View class.
Definition: matpackVII.h:779
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:421
MatrixView
The MatrixView class.
Definition: matpackI.h:668
gridpos_copy
void gridpos_copy(GridPos &gp_new, const GridPos &gp_old)
gridpos_copy
Definition: interpolation.cc:482
interp_poly
Numeric interp_poly(ConstVectorView x, ConstVectorView y, const Numeric &x_i, const GridPos &gp)
Polynomial interpolation.
Definition: interpolation.cc:2909
gridpos
void gridpos(ArrayOfGridPos &gp, ConstVectorView old_grid, ConstVectorView new_grid, const Numeric &extpolfac)
Set up a grid position Array.
Definition: interpolation.cc:167
is_gridpos_at_index_i
bool is_gridpos_at_index_i(const GridPos &gp, const Index &i)
is_gridpos_at_index_i
Definition: interpolation.cc:665
gridpos_check_fd
void gridpos_check_fd(GridPos &gp)
gridpos_check_fd
Definition: interpolation.cc:524
ConstTensor7View
A constant view of a Tensor7.
Definition: matpackVII.h:169
FD_TOL
const Numeric FD_TOL
Allowed tolerance for fractional distance values.
Definition: interpolation.cc:76
joker
const Joker joker
interpolation.h
Header file for interpolation.cc.
interp
Numeric interp(ConstVectorView itw, ConstVectorView a, const GridPos &tc)
Red 1D Interpolate.
Definition: interpolation.cc:1000
fractional_gp
Numeric fractional_gp(const GridPos &gp)
fractional_gp
Definition: interpolation.cc:504
GridPos::fd
Numeric fd[2]
Definition: interpolation.h:76
array.h
This file contains the definition of Array.
is_size
bool is_size(ConstVectorView x, const Index &n)
Verifies that the size of x is l.
Definition: logic.cc:90
ConstTensor4View
A constant view of a Tensor4.
Definition: matpackIV.h:149
Tensor3View
The Tensor3View class.
Definition: matpackIII.h:234
Array< GridPos >
is_decreasing
bool is_decreasing(ConstVectorView x)
Checks if a vector is sorted in reversed order and is strictly decreasing.
Definition: logic.cc:303
operator<<
ostream & operator<<(ostream &os, const GridPos &gp)
Output operator for GridPos.
Definition: interpolation.cc:105
gridpos_upperend_check
void gridpos_upperend_check(GridPos &gp, const Index &ie)
gridpos_upperend_check
Definition: interpolation.cc:608
abs
#define abs(x)
Definition: continua.cc:13094
ConstVectorView::nelem
Index nelem() const
Returns the number of elements.
Definition: matpackI.cc:175
VectorView
The VectorView class.
Definition: matpackI.h:373
ns
#define ns
Definition: continua.cc:14564
polint
void polint(Numeric &y_int, Numeric &dy_int, ConstVectorView xa, ConstVectorView ya, const Index &n, const Numeric &x)
Polynomial interpolation.
Definition: interpolation.cc:3095
ConstVectorView::sum
Numeric sum() const
The sum of all elements of a Vector.
Definition: matpackI.cc:181
ConstTensor6View
A constant view of a Tensor6.
Definition: matpackVI.h:167
Numeric
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
Tensor5View
The Tensor5View class.
Definition: matpackV.h:278
gridpos_force_end_fd
void gridpos_force_end_fd(GridPos &gp, const Index &n)
gridpos_force_end_fd
Definition: interpolation.cc:567
ConstMatrixView
A constant view of a Matrix.
Definition: matpackI.h:591
Range
The range class.
Definition: matpackI.h:148
GridPos
Structure to store a grid position.
Definition: interpolation.h:74
LOOPIT
#define LOOPIT(x)
Macro for interpolation weight loops.
Definition: interpolation.cc:91
gridpos2gridrange
Index gridpos2gridrange(const GridPos &gp, const bool &upwards)
gridpos2gridrange
Definition: interpolation.cc:701
is_increasing
bool is_increasing(ConstVectorView x)
Checks if a vector is sorted and strictly increasing.
Definition: logic.cc:258
logic.h
Header file for logic.cc.
ConstTensor3View
A constant view of a Tensor3.
Definition: matpackIII.h:147
Tensor4View
The Tensor4View class.
Definition: matpackIV.h:245
GridPos::idx
Index idx
Definition: interpolation.h:75
Index
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
arts_exit
void arts_exit(int status)
This is the exit function of ARTS.
Definition: arts.cc:42
check_input.h
sum_check_epsilon
const Numeric sum_check_epsilon
The maximum difference from 1 that we allow for a sum check.
Definition: interpolation.cc:63
Vector
The Vector class.
Definition: matpackI.h:555
ConstVectorView
A constant view of a Vector.
Definition: matpackI.h:300
Array::nelem
Index nelem() const
Number of elements.
Definition: array.h:172
interpweights
void interpweights(VectorView itw, const GridPos &tc)
Red 1D interpolation weights.
Definition: interpolation.cc:756
ConstTensor5View
A constant view of a Tensor5.
Definition: matpackV.h:160
Tensor6View
The Tensor6View class.
Definition: matpackVI.h:450