ARTS  2.0.49
sensor.cc
Go to the documentation of this file.
1 /* Copyright (C) 2003-2008 Mattias Ekström <ekstrom@rss.chalmers.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 
29 /*===========================================================================
30  === External declarations
31  ===========================================================================*/
32 
33 #include <cmath>
34 #include <list>
35 #include <stdexcept>
36 #include "arts.h"
37 #include "logic.h"
38 #include "matpackI.h"
39 #include "matpackII.h"
40 #include "messages.h"
41 #include "sorting.h"
42 #include "sensor.h"
43 
44 extern const Numeric PI;
45 extern const Numeric NAT_LOG_2;
46 extern const Index GFIELD1_F_GRID;
47 extern const Index GFIELD4_FIELD_NAMES;
48 extern const Index GFIELD4_F_GRID;
49 extern const Index GFIELD4_ZA_GRID;
50 extern const Index GFIELD4_AA_GRID;
51 
52 
53 
54 /*===========================================================================
55  === The functions (in alphabetical order)
56  ===========================================================================*/
57 
59 
79  Sparse& H,
80 #ifndef NDEBUG
81  const Index& antenna_dim,
82 #else
83  const Index& antenna_dim _U_,
84 #endif
85  ConstMatrixView antenna_los,
86  const GriddedField4& antenna_response,
87  ConstVectorView za_grid,
88  ConstVectorView f_grid,
89  const Index n_pol,
90  const Index do_norm )
91 {
92  // Number of input za and frequency angles
93  const Index n_za = za_grid.nelem();
94  const Index n_f = f_grid.nelem();
95 
96  // Calculate number of antenna beams
97  const Index n_ant = antenna_los.nrows();
98 
99  // Asserts for variables beside antenna_response
100  assert( antenna_dim == 1 );
101  assert( antenna_los.ncols() == antenna_dim );
102  assert( n_za >= 2 );
103  assert( n_pol >= 1 );
104  assert( do_norm >= 0 && do_norm <= 1 );
105 
106  // Extract antenna_response grids
107  const Index n_ar_pol =
108  antenna_response.get_string_grid(GFIELD4_FIELD_NAMES).nelem();
109  ConstVectorView aresponse_f_grid =
110  antenna_response.get_numeric_grid(GFIELD4_F_GRID);
111  ConstVectorView aresponse_za_grid =
112  antenna_response.get_numeric_grid(GFIELD4_ZA_GRID);
113  DEBUG_ONLY( const Index n_ar_aa =
114  antenna_response.get_numeric_grid(GFIELD4_AA_GRID).nelem(); )
115 
116  //
117  const Index n_ar_f = aresponse_f_grid.nelem();
118  const Index n_ar_za = aresponse_za_grid.nelem();
119  const Index pol_step = n_ar_pol > 1;
120 
121  // Asserts for antenna_response
122  assert( n_ar_pol == 1 || n_ar_pol == n_pol );
123  assert( n_ar_f );
124  assert( n_ar_za > 1 );
125  assert( n_ar_aa == 1 );
126 
127  // If response data extend outside za_grid is checked in
128  // sensor_integration_vector
129 
130  // Some size(s)
131  const Index nfpol = n_f * n_pol;
132 
133  // Resize H
134  H.resize( n_ant*nfpol, n_za*nfpol );
135 
136  // Storage vectors for response weights
137  Vector hrow( H.ncols(), 0.0 );
138  Vector hza( n_za, 0.0 );
139 
140  // Antenna response to apply (possibly obtained by frequency interpolation)
141  Vector aresponse( n_ar_za, 0.0 );
142 
143 
144  // Antenna beam loop
145  for( Index ia=0; ia<n_ant; ia++ )
146  {
147  Vector shifted_aresponse_za_grid = aresponse_za_grid;
148  shifted_aresponse_za_grid += antenna_los(ia,0);
149 
150  // Order of loops assumes that the antenna response more often
151  // changes with frequency than for polarisation
152 
153  // Frequency loop
154  for( Index f=0; f<n_f; f++ )
155  {
156 
157  // Polarisation loop
158  for( Index ip=0; ip<n_pol; ip++ )
159  {
160  // Determine antenna pattern to apply
161  //
162  // Interpolation needed only if response has a frequency grid
163  // New antenna for each loop of response changes with polarisation
164  //
165  Index new_antenna = 1;
166  //
167  if( n_ar_f > 1 )
168  {
169  // Interpolation (do this in "green way")
170  ArrayOfGridPos gp_f( 1 ), gp_za(n_za);
171  gridpos( gp_f, aresponse_f_grid, Vector(1,f_grid[f]) );
172  gridpos( gp_za, aresponse_za_grid, aresponse_za_grid );
173  Tensor3 itw( 1, n_za, 4 );
174  interpweights( itw, gp_f, gp_za );
175  Matrix aresponse_matrix(1,n_za);
176  interp( aresponse_matrix, itw,
177  antenna_response.data(ip,joker,joker,0), gp_f, gp_za );
178  aresponse = aresponse_matrix(0,joker);
179  }
180  else if( pol_step ) // Response changes with polarisation
181  {
182  aresponse = antenna_response.data(ip,0,joker,0);
183  }
184  else if( f == 0 ) // Same response for all f and polarisations
185  {
186  aresponse = antenna_response.data(0,0,joker,0);
187  }
188  else
189  {
190  new_antenna = 0;
191  }
192 
193  // Calculate response weights
194  if( new_antenna )
195  {
196  sensor_integration_vector( hza, aresponse,
197  shifted_aresponse_za_grid,
198  za_grid );
199  // Normalisation?
200  if( do_norm )
201  { hza /= hza.sum(); }
202  }
203 
204  // Put weights into H
205  //
206  const Index ii = f*n_pol + ip;
207  //
208  hrow[ Range(ii,n_za,nfpol) ] = hza;
209  //
210  H.insert_row( ia*nfpol+ii, hrow );
211  //
212  hrow = 0;
213  }
214  }
215  }
216 }
217 
218 
219 
221 
247  Sparse& H,
248 #ifndef NDEBUG
249  const Index& antenna_dim,
250 #else
251  const Index& antenna_dim _U_,
252 #endif
253  ConstMatrixView antenna_los,
254  const GriddedField4& antenna_response,
255  ConstVectorView za_grid,
256  ConstVectorView aa_grid,
257  ConstVectorView f_grid,
258  const Index n_pol,
259  const Index do_norm )
260 {
261  // Sizes
262  const Index n_f = f_grid.nelem();
263  const Index nfpol = n_f * n_pol;
264  const Index n_aa = aa_grid.nelem();
265  const Index n_za = za_grid.nelem();
266  const Index n_ant = antenna_los.nrows();
267  const Index n_ar_pol = antenna_response.data.nbooks();
268  const Index n_ar_f = antenna_response.data.npages();
269  const Index n_ar_za = antenna_response.data.nrows();
270 
271  // Asserts for variables beside antenna_response (not done in antenna1d_matrix)
272  assert( antenna_dim == 2 );
273  assert( n_aa >= 2 );
274  assert( do_norm >= 0 && do_norm <= 1 );
275 
276  // Make copy of antenna response suitable as input to antenna1d_matrix
277  //
278  GriddedField4 aresponse = antenna_response;
279  //
280  ConstVectorView response_aa_grid =
281  antenna_response.get_numeric_grid(GFIELD4_AA_GRID);
282  //
283  aresponse.resize( n_ar_pol, n_ar_f, n_ar_za, 1 );
284  aresponse.set_grid( GFIELD4_AA_GRID, Vector(1,0) );
285 
286  // Resize H
287  H.resize( n_ant*nfpol, n_aa*n_za*nfpol );
288 
289  // Loop antenna_los
290  for( Index il=0; il<n_ant; il++ )
291  {
292 
293  // Set up an ArrayOfVector that can hold all data for one antenna_los
294  ArrayOfVector hrows(nfpol);
295  for( Index row=0; row<nfpol; row++ )
296  {
297  hrows[row].resize(n_aa*n_za*nfpol);
298  hrows[row] = 0; // To get correct value for aa_grid
299  } // points outside response aa grid
300 
301  // Loop azimuth angles
302  for( Index ia=0; ia<n_aa; ia++ )
303  {
304  const Numeric aa_point = aa_grid[ia] - antenna_los(il,1);
305 
306  if( aa_point >= response_aa_grid[0] &&
307  aa_point <= last(response_aa_grid) )
308  {
309  // Interpolate antenna patterns to aa_grid[ia]
310  // Use grid position function to find weights
311  //
312  ArrayOfGridPos gp( 1 );
313  gridpos( gp, response_aa_grid, Vector(1,aa_point) );
314  //
315  for( Index i4=0; i4<n_ar_pol; i4++ )
316  {
317  for( Index i3=0; i3<n_ar_f; i3++ )
318  {
319  for( Index i2=0; i2<n_ar_za; i2++ )
320  {
321  aresponse.data(i4,i3,i2,0) =
322  gp[0].fd[1] * antenna_response.data(i4,i3,i2,gp[0].idx) +
323  gp[0].fd[0] * antenna_response.data(i4,i3,i2,gp[0].idx+1);
324  }
325  }
326  }
327 
328  // Find the aa width for present angle
329  //
330  // Lower and upper end of "coverage" for present aa angle
331  Numeric aa_low = response_aa_grid[0];
332  if( ia > 0 )
333  {
334  const Numeric aam = antenna_los(il,1) +
335  ( aa_grid[ia] + aa_grid[ia-1] ) / 2.0;
336  if( aam > aa_low )
337  { aa_low = aam; };
338  }
339  Numeric aa_high = last(response_aa_grid);
340  if( ia < n_aa-1 )
341  {
342  const Numeric aam = antenna_los(il,1) +
343  ( aa_grid[ia+1] + aa_grid[ia] ) / 2.0;
344  if( aam < aa_high )
345  { aa_high = aam; };
346  }
347  //
348  const Numeric aa_width = aa_high - aa_low;
349 
350  // Do 1D calculations
351  //
352  Sparse Hza;
353  //
354  antenna1d_matrix( Hza, 1, Matrix(1,1,antenna_los(il,0)),
355  aresponse, za_grid, f_grid, n_pol, 0 );
356 
357  for( Index row=0; row<nfpol; row++ )
358  {
359  for( Index iz=0; iz<n_za; iz++ )
360  {
361  for( Index i=0; i<nfpol; i++ )
362  {
363  hrows[row][(iz*n_aa+ia)*nfpol+i] =
364  aa_width * Hza(row,iz*nfpol+i);
365  }
366  }
367  }
368  } // if-statement
369  } // aa loop
370 
371  // Move results to H
372  for( Index row=0; row<nfpol; row++ )
373  {
374  if( do_norm )
375  {
376  hrows[row] /= hrows[row].sum();
377  }
378  H.insert_row( il*nfpol+row, hrows[row] );
379  }
380 
381  } // antenna_los loop
382 }
383 
384 
385 
387 
409  Vector& x,
410  Vector& y,
411  const Numeric& x0,
412  const Numeric& fwhm,
413  const Numeric& xwidth_si,
414  const Numeric& dx_si )
415 {
416  const Numeric si = fwhm / ( 2 * sqrt( 2 * NAT_LOG_2 ) );
417  const Numeric a = 1 / ( si * sqrt( 2 * PI ) );
418 
419  linspace( x, -si*xwidth_si, si*xwidth_si, si*dx_si );
420  const Index n = x.nelem();
421  y.resize( n );
422 
423  for( Index i=0; i<n; i++ )
424  y[i] = a * exp( -0.5 * pow((x[i]-x0)/si,2.0) );
425 }
426 
427 
428 
430 
456  Sparse& H,
457  Vector& f_mixer,
458  const Numeric& lo,
459  const GriddedField1& filter,
460  ConstVectorView f_grid,
461  const Index& n_pol,
462  const Index& n_sp,
463  const Index& do_norm )
464 {
465  // Frequency grid of for sideband response specification
466  ConstVectorView filter_grid = filter.get_numeric_grid(GFIELD1_F_GRID);
467 
468  DEBUG_ONLY( const Index nrp = filter.data.nelem(); )
469 
470  // Asserts
471  assert( lo > f_grid[0] );
472  assert( lo < last(f_grid) );
473  assert( filter_grid.nelem() == nrp );
474  assert( fabs(last(filter_grid)+filter_grid[0]) < 1e3 );
475  // If response data extend outside f_grid is checked in sensor_summation_vector
476 
477  // Find indices in f_grid where f_grid is just below and above the
478  // lo frequency.
479  /*
480  Index i_low = 0, i_high = f_grid.nelem()-1, i_mean;
481  while( i_high-i_low > 1 )
482  {
483  i_mean = (Index) (i_high+i_low)/2;
484  if (f_grid[i_mean]<lo)
485  {
486  i_low = i_mean;
487  }
488  else
489  {
490  i_high = i_mean;
491  }
492  }
493  if (f_grid[i_high]==lo)
494  {
495  i_high++;
496  }
497  const Numeric lim_low = max( lo-f_grid[i_low], f_grid[i_high]-lo );
498  */
499 
500  // Determine IF limits for new frequency grid
501  const Numeric lim_low = 0;
502  const Numeric lim_high = -filter_grid[0];
503 
504  // Convert sidebands to IF and use list to make a unique sorted
505  // vector, this sorted vector is f_mixer.
506  list<Numeric> l_mixer;
507  for( Index i=0; i<f_grid.nelem(); i++ )
508  {
509  if( fabs(f_grid[i]-lo)>=lim_low && fabs(f_grid[i]-lo)<=lim_high )
510  {
511  l_mixer.push_back(fabs(f_grid[i]-lo));
512  }
513  }
514  l_mixer.push_back(lim_high); // Not necessarily a point in f_grid
515  l_mixer.sort();
516  l_mixer.unique();
517  f_mixer.resize((Index) l_mixer.size());
518  Index e=0;
519  for (list<Numeric>::iterator li=l_mixer.begin(); li != l_mixer.end(); li++)
520  {
521  f_mixer[e] = *li;
522  e++;
523  }
524 
525  // Resize H
526  H.resize( f_mixer.nelem()*n_pol*n_sp, f_grid.nelem()*n_pol*n_sp );
527 
528  // Calculate the sensor summation vector and insert the values in the
529  // final matrix taking number of polarisations and zenith angles into
530  // account.
531  Vector row_temp( f_grid.nelem() );
532  Vector row_final( f_grid.nelem()*n_pol*n_sp );
533  //
534  Vector if_grid = f_grid;
535  if_grid -= lo;
536  //
537  for( Index i=0; i<f_mixer.nelem(); i++ )
538  {
539  sensor_summation_vector( row_temp, filter.data, filter_grid,
540  if_grid, f_mixer[i], -f_mixer[i] );
541 
542  // Normalise if flag is set
543  if (do_norm)
544  row_temp /= row_temp.sum();
545 
546  // Loop over number of polarisations
547  for (Index p=0; p<n_pol; p++)
548  {
549  // Loop over number of zenith angles/antennas
550  for (Index a=0; a<n_sp; a++)
551  {
552  // Distribute elements of row_temp to row_final.
553  row_final = 0.0;
554  row_final[Range(a*f_grid.nelem()*n_pol+p,f_grid.nelem(),n_pol)]
555  = row_temp;
556  H.insert_row(a*f_mixer.nelem()*n_pol+p+i*n_pol,row_final);
557  }
558  }
559  }
560 }
561 
562 
563 
565 
587  Vector& sensor_response_f,
588  ArrayOfIndex& sensor_response_pol,
589  Vector& sensor_response_za,
590  Vector& sensor_response_aa,
591  ConstVectorView sensor_response_f_grid,
592  const ArrayOfIndex& sensor_response_pol_grid,
593  ConstVectorView sensor_response_za_grid,
594  ConstVectorView sensor_response_aa_grid,
595  const Index za_aa_independent )
596 {
597  // Sizes
598  const Index nf = sensor_response_f_grid.nelem();
599  const Index npol = sensor_response_pol_grid.nelem();
600  const Index nza = sensor_response_za_grid.nelem();
601  Index naa = sensor_response_aa_grid.nelem();
602  Index empty_aa = 0;
603  //
604  if( naa == 0 )
605  {
606  empty_aa = 1;
607  naa = 1;
608  }
609  if( !za_aa_independent )
610  { naa = 1; }
611  //
612  const Index n = nf * npol * nza * naa;
613 
614  // Allocate
615  sensor_response_f.resize( n );
616  sensor_response_pol.resize( n );
617  sensor_response_za.resize( n );
618  if( empty_aa )
619  { sensor_response_aa.resize( 0 ); }
620  else
621  { sensor_response_aa.resize( n ); }
622 
623  // Fill
624  for( Index iaa=0; iaa<naa; iaa++ )
625  {
626  const Index i1 = iaa * nza * nf * npol;
627  //
628  for( Index iza=0; iza<nza; iza++ )
629  {
630  const Index i2 = i1 + iza * nf * npol;
631  //
632  for( Index ifr=0; ifr<nf; ifr++ )
633  {
634  const Index i3 = i2 + ifr * npol;
635  //
636  for( Index ip=0; ip<npol; ip++ )
637  {
638  const Index i = i3 + ip;
639  //
640  sensor_response_f[i] = sensor_response_f_grid[ifr];
641  sensor_response_pol[i] = sensor_response_pol_grid[ip];
642  sensor_response_za[i] = sensor_response_za_grid[iza];
643  if( !empty_aa )
644  {
645  if( za_aa_independent )
646  sensor_response_aa[i] = sensor_response_aa_grid[iaa];
647  else
648  sensor_response_aa[i] = sensor_response_aa_grid[iza];
649  }
650  }
651  }
652  }
653  }
654 }
655 
656 
657 
659 
684  VectorView h,
685  ConstVectorView f,
686  ConstVectorView x_f_in,
687  ConstVectorView x_g_in )
688 {
689  // Basic sizes
690  const Index nf = x_f_in.nelem();
691  const Index ng = x_g_in.nelem();
692 
693  // Asserts
694  assert( h.nelem() == ng );
695  assert( f.nelem() == nf );
696  assert( is_increasing( x_f_in ) );
697  assert( is_increasing( x_g_in ) || is_decreasing( x_g_in ) );
698  // More asserts below
699 
700  // Copy grids, handle reversed x_g and normalise to cover the range
701  // [0 1]. This is necessary to avoid numerical problems for
702  // frequency grids (e.g. experienced for a case with frequencies
703  // around 501 GHz).
704  //
705  Vector x_g = x_g_in;
706  Vector x_f = x_f_in;
707  Index xg_reversed = 0;
708  //
709  if( is_decreasing( x_g ) )
710  {
711  xg_reversed = 1;
712  Vector tmp = x_g[Range(ng-1,ng,-1)]; // Flip order
713  x_g = tmp;
714  }
715  //
716  assert( x_g[0] <= x_f[0] );
717  assert( x_g[ng-1] >= x_f[nf-1] );
718  //
719  const Numeric xmin = x_g[0];
720  const Numeric xmax = x_g[ng-1];
721  //
722  x_f -= xmin;
723  x_g -= xmin;
724  x_f /= xmax - xmin;
725  x_g /= xmax - xmin;
726 
727  //Create a reference grid vector, x_ref that containing the values
728  //of x_f and x_g strictly sorted. Only g points inside the f range
729  //are of concern.
730  list<Numeric> l_x;
731  for( Index it=0; it<nf; it++ )
732  l_x.push_back(x_f[it]);
733  for (Index it=0; it<ng; it++)
734  {
735  if( x_g[it]>x_f[0] && x_g[it]<x_f[x_f.nelem()-1] )
736  l_x.push_back(x_g[it]);
737  }
738 
739  l_x.sort();
740  l_x.unique();
741 
742  Vector x_ref(l_x.size());
743  Index e=0;
744  for (list<Numeric>::iterator li=l_x.begin(); li != l_x.end(); li++) {
745  x_ref[e] = *li;
746  e++;
747  }
748 
749  //Initiate output vector, with equal size as x_g, with zeros.
750  //Start calculations
751  h = 0.0;
752  Index i_f = 0;
753  Index i_g = 0;
754  //i = 0;
755  Numeric dx,a0,b0,c0,a1,b1,c1,x3,x2,x1;
756  //while( i_g < ng && i_f < x_f.nelem() ) {
757  for( Index i=0; i<x_ref.nelem()-1; i++ ) {
758  //Find for what index in x_g (which is the same as for h) and f
759  //calculation corresponds to
760  while( x_g[i_g+1] <= x_ref[i] ) {
761  i_g++;
762  }
763  while( x_f[i_f+1] <= x_ref[i] ) {
764  i_f++;
765  }
766 
767  //If x_ref[i] is out of x_f's range then that part of the integral
768  //is set to 0, so no calculations will be done
769  if( x_ref[i] >= x_f[0] && x_ref[i] < x_f[x_f.nelem()-1] ) {
770  //Product of steps in x_f and x_g
771  dx = (x_f[i_f+1] - x_f[i_f]) * (x_g[i_g+1] - x_g[i_g]);
772 
773  //Calculate a, b and c coefficients; h[i]=ax^3+bx^2+cx
774  a0 = (f[i_f] - f[i_f+1]) / 3;
775  b0 = (-f[i_f]*(x_g[i_g+1]+x_f[i_f+1])+f[i_f+1]*(x_g[i_g+1]+x_f[i_f]))
776  /2;
777  c0 = f[i_f]*x_f[i_f+1]*x_g[i_g+1]-f[i_f+1]*x_f[i_f]*x_g[i_g+1];
778 
779  a1 = -a0;
780  b1 = (f[i_f]*(x_g[i_g]+x_f[i_f+1])-f[i_f+1]*(x_g[i_g]+x_f[i_f]))/2;
781  c1 = -f[i_f]*x_f[i_f+1]*x_g[i_g]+f[i_f+1]*x_f[i_f]*x_g[i_g];
782 
783  x3 = pow(x_ref[i+1],3) - pow(x_ref[i],3);
784  x2 = pow(x_ref[i+1],2) - pow(x_ref[i],2);
785  x1 = x_ref[i+1]-x_ref[i];
786 
787  //Calculate h[i] and h[i+1] increment
788  h[i_g] += (a0*x3+b0*x2+c0*x1) / dx;
789  h[i_g+1] += (a1*x3+b1*x2+c1*x1) / dx;
790 
791  }
792  }
793 
794  // Flip back if x_g was decreasing
795  if( xg_reversed )
796  {
797  Vector tmp = h[Range(ng-1,ng,-1)]; // Flip order
798  h = tmp;
799  }
800 }
801 
802 
803 
805 
832  VectorView h,
833  ConstVectorView f,
834  ConstVectorView x_f,
835  ConstVectorView x_g,
836  const Numeric x1,
837  const Numeric x2 )
838 {
839  // Asserts
840  assert( h.nelem() == x_g.nelem() );
841  assert( f.nelem() == x_f.nelem() );
842  assert( x_g[0] <= x_f[0] );
843  assert( last(x_g) >= last(x_f) );
844  assert( x1 >= x_f[0] );
845  assert( x2 >= x_f[0] );
846  assert( x1 <= last(x_f) );
847  assert( x2 <= last(x_f) );
848 
849  // Determine grid positions for point 1 (both with respect to f and g grids)
850  // and interpolate response function.
851  ArrayOfGridPos gp1g(1), gp1f(1);
852  gridpos( gp1g, x_g, x1 );
853  gridpos( gp1f, x_f, x1 );
854  Matrix itw1(1,2);
855  interpweights( itw1, gp1f );
856  Numeric f1;
857  interp( f1, itw1, f, gp1f );
858 
859  // Same for point 2
860  ArrayOfGridPos gp2g(1), gp2f(1);
861  gridpos( gp2g, x_g, x2 );
862  gridpos( gp2f, x_f, x2 );
863  Matrix itw2(1,2);
864  interpweights( itw2, gp2f );
865  Numeric f2;
866  interp( f2, itw2, f, gp2f );
867 
868  //Initialise h at zero and store calculated weighting components
869  h = 0.0;
870  h[gp1g[0].idx] += f1 * gp1g[0].fd[1];
871  h[gp1g[0].idx+1] += f1 * gp1g[0].fd[0];
872  h[gp2g[0].idx] += f2 * gp2g[0].fd[1];
873  h[gp2g[0].idx+1] += f2 * gp2g[0].fd[0];
874 }
875 
876 
877 
879 
898  Sparse& H,
899  ConstVectorView ch_f,
900  const ArrayOfGriddedField1& ch_response,
901  ConstVectorView sensor_f,
902  const Index& n_pol,
903  const Index& n_sp,
904  const Index& do_norm )
905 {
906  // Check if matrix has one frequency column or one for every channel
907  // frequency
908  //
909  assert( ch_response.nelem()==1 || ch_response.nelem()==ch_f.nelem() );
910  //
911  Index freq_full = ch_response.nelem() > 1;
912 
913  // If response data extend outside sensor_f is checked in
914  // sensor_integration_vector
915 
916  // Reisze H
917  //
918  const Index nin_f = sensor_f.nelem();
919  const Index nout_f = ch_f.nelem();
920  const Index nin = n_sp * nin_f * n_pol;
921  const Index nout = n_sp * nout_f * n_pol;
922  //
923  H.resize( nout, nin );
924 
925  // Calculate the sensor integration vector and put values in the temporary
926  // vector, then copy vector to the transfer matrix
927  //
928  Vector ch_response_f;
929  Vector weights( nin_f );
930  Vector weights_long( nin, 0.0 );
931  //
932  for( Index ifr=0; ifr<nout_f; ifr++ )
933  {
934  const Index irp = ifr * freq_full;
935 
936  //The spectrometer response is shifted for each centre frequency step
937  ch_response_f = ch_response[irp].get_numeric_grid(GFIELD1_F_GRID);
938  ch_response_f += ch_f[ifr];
939 
940  // Call sensor_integration_vector and store it in the temp vector
941  sensor_integration_vector( weights, ch_response[irp].data,
942  ch_response_f, sensor_f );
943 
944  // Normalise if flag is set
945  if( do_norm )
946  weights /= weights.sum();
947 
948  // Loop over polarisation and spectra (viewing directions)
949  // Weights change only with frequency
950  for( Index sp=0; sp<n_sp; sp++ )
951  {
952  for( Index pol=0; pol<n_pol; pol++ )
953  {
954  // Distribute the compact weight vector into weight_long
955  weights_long[Range(sp*nin_f*n_pol+pol,nin_f,n_pol)] = weights;
956 
957  // Insert temp_long into H at the correct row
958  H.insert_row( sp*nout_f*n_pol + ifr*n_pol + pol, weights_long );
959 
960  // Reset weight_long to zero.
961  weights_long = 0.0;
962  }
963  }
964  }
965 }
966 
967 
968 // Functions by Stefan, needed for HIRS:
969 
970 
972 
1001  Vector& fmax,
1002  Index i,
1003  Index j)
1004 {
1005  const Index nf = fmin.nelem();
1006  assert(fmax.nelem()==nf);
1007  assert(i>=0 && i<nf);
1008  assert(j>=0 && j<nf);
1009  assert(fmin[i]<=fmin[j]);
1010  assert(i<j);
1011 
1012  // There are three cases to consider:
1013  // a) The two channels are separate: fmax[i] < fmin[j]
1014  // b) They overlap: fmax[i] >= fmin[j]
1015  // c) j is inside i: fmax[i] > fmax[j]
1016 
1017  // In the easiest case (a), we do not have to do anything.
1018  if (fmax[i] >= fmin[j])
1019  {
1020  // We are in case (b) or (c), so we know that we have to combine
1021  // the channels. The new minimum frequency is fmin[i]. The new
1022  // maximum frequency is the larger one of the two channels we
1023  // are combining:
1024  if (fmax[j] > fmax[i])
1025  fmax[i] = fmax[j];
1026 
1027  // We now have to kick out element j from both vectors.
1028 
1029  // Number of elements behind j:
1030  Index n_behind = nf-1 - j;
1031 
1032  Vector dummy = fmin;
1033  fmin.resize(nf-1);
1034  fmin[Range(0,j)] = dummy[Range(0,j)];
1035  if (n_behind > 0)
1036  fmin[Range(j,n_behind)] = dummy[Range(j+1,n_behind)];
1037 
1038  dummy = fmax;
1039  fmax.resize(nf-1);
1040  fmax[Range(0,j)] = dummy[Range(0,j)];
1041  if (n_behind > 0)
1042  fmax[Range(j,n_behind)] = dummy[Range(j+1,n_behind)];
1043 
1044  return true;
1045  }
1046 
1047  return false;
1048 }
1049 
1050 
1052 
1077  Vector& fmin,
1078  Vector& fmax,
1079  // Input:
1080  const Vector& f_backend,
1081  const ArrayOfGriddedField1& backend_channel_response,
1082  const Numeric& delta,
1083  const Verbosity& verbosity)
1084 {
1085  CREATE_OUT2
1086 
1087  // How many channels in total:
1088  const Index n_chan = f_backend.nelem();
1089 
1090  // Checks on input quantities:
1091 
1092  // There must be at least one channel.
1093  if (n_chan < 1)
1094  {
1095  ostringstream os;
1096  os << "There must be at least one channel.\n"
1097  << "(The vector *f_backend* must have at least one element.)";
1098  throw runtime_error(os.str());
1099  }
1100 
1101  // There must be a response function for each channel.
1102  if (n_chan != backend_channel_response.nelem())
1103  {
1104  ostringstream os;
1105  os << "Variables *f_backend_multi* and *backend_channel_response_multi*\n"
1106  << "must have same number of bands for each LO.";
1107  throw runtime_error(os.str());
1108  }
1109 
1110  // Frequency grids for response functions must be strictly increasing.
1111  for (Index i=0; i<n_chan; ++i)
1112  {
1113  // Frequency grid for this response function:
1114  const Vector& backend_f_grid = backend_channel_response[i].get_numeric_grid(0);
1115 
1116  if ( !is_increasing(backend_f_grid) )
1117  {
1118  ostringstream os;
1119  os << "The frequency grid for the backend channel response of\n"
1120  << "channel " << i << " is not strictly increasing.\n";
1121  os << "It is: " << backend_f_grid << "\n";
1122  throw runtime_error( os.str() );
1123  }
1124  }
1125 
1126 
1127  // Start the actual work.
1128 
1129  out2 << " Original channel characteristics:\n"
1130  << " min nominal max (all in Hz):\n";
1131 
1132  // Get a list of original channel boundaries:
1133  Vector fmin_orig(n_chan);
1134  Vector fmax_orig(n_chan);
1135  for (Index i=0; i<n_chan; ++i)
1136  {
1137  // Some handy shortcuts:
1138  const Vector& backend_f_grid = backend_channel_response[i].get_numeric_grid(0);
1139 // const Vector& backend_response = backend_channel_response[i];
1140  const Index nf = backend_f_grid.nelem();
1141 
1142 
1143  // We have to find the first and last frequency where the
1144  // response is actually different from 0. (No point in making
1145  // calculations for frequencies where the response is 0.)
1146 // Index j=0;
1147 // while (backend_response[j] <= 0) ++j;
1148 // Numeric bf_min = backend_f_grid[j];
1149 
1150 // j=nf-1;
1151 // while (backend_response[j] <= 0) --j;
1152 // Numeric bf_max = backend_f_grid[j];
1153  //
1154  // No, aparently the sensor part want values also where the
1155  // response is zero. So we simply take the grid boundaries here.
1156  Numeric bf_min = backend_f_grid[0];
1157  Numeric bf_max = backend_f_grid[nf-1];
1158 
1159 
1160  // We need to add a bit of extra margin at both sides,
1161  // otherwise there is a numerical problem in the sensor WSMs.
1162  //
1163  // PE 081003: The accuracy for me (double on 64 bit machine) appears to
1164  // be about 3 Hz. Select 1 MHz to have a clear margin. Hopefully OK
1165  // for other machines.
1166  //
1167  // SAB 2010-04-14: The approach with a constant delta does not seem to work
1168  // well in practice. What I do now is that I add a delta corresponding to a
1169  // fraction of the grid spacing. But that is done outside of this function.
1170  // So we set delta = 0 here.
1171  //
1172  // SAB 2010-05-03: Now we pass delta as a parameter (with a default value of 0).
1173 
1174  fmin_orig[i] = f_backend[i] + bf_min - delta;
1175  fmax_orig[i] = f_backend[i] + bf_max + delta;
1176 
1177  out2 << " " << fmin_orig[i]
1178  << " " << f_backend[i]
1179  << " " << fmax_orig[i] << "\n";
1180  }
1181 
1182  // The problem is that channels may be overlapping. In that case, we
1183  // want to create a frequency grid that covers their entire range,
1184  // but we do not want to duplicate any frequencies.
1185 
1186  // To make matters worse, one or even several channels may be
1187  // completely inside another very broad channel.
1188 
1189  // Sort channels by frequency:
1190  // Caveat: A channel may be higher in
1191  // characteristic frequency f_backend, but also wider, so that it
1192  // has a lower minimum frequency fmin_orig. (This is the case for
1193  // some HIRS channels.) We sort by the minimum frequency here, not
1194  // by f_backend. This is necessary for function
1195  // test_and_merge_two_channels to work correctly.
1196  ArrayOfIndex isorted;
1197  get_sorted_indexes (isorted, fmin_orig);
1198 
1199  fmin.resize(n_chan);
1200  fmax.resize(n_chan);
1201  for (Index i=0; i<n_chan; ++i)
1202  {
1203  fmin[i] = fmin_orig[isorted[i]];
1204  fmax[i] = fmax_orig[isorted[i]];
1205  }
1206 
1207  // We will be testing pairs of channels, and combine them if
1208  // possible. We have to test always only against the direct
1209  // neighbour. If that has no overlap, higher channels can not have
1210  // any either, due to the sorting by fmin.
1211  //
1212  // Note that fmin.nelem() changes, as the loop is
1213  // iterated. Nevertheless this is the correct stop condition.
1214  for (Index i=0; i<fmin.nelem()-1; ++i)
1215  {
1216  bool continue_checking = true;
1217  // The "i<fmin.nelem()" condition below is necessary, since
1218  // fmin.nelem() can decrease while the loop is executed, due to
1219  // merging.
1220  while (continue_checking && i<fmin.nelem()-1)
1221  {
1222  continue_checking =
1223  test_and_merge_two_channels(fmin, fmax, i, i+1);
1224 
1225  // Function returns true if merging has taken place.
1226  // In this case, we have to check again.
1227 
1228  }
1229  }
1230 
1231  out2 << " New channel characteristics:\n"
1232  << " min max (all in Hz):\n";
1233  for (Index i=0; i<fmin.nelem(); ++i)
1234  out2 << " " << fmin[i] << " " << fmax[i] << "\n";
1235 
1236 }
1237 
1238 
1239 
1240 
1241 
1242 
1243 
1244 //--- Stuff not yet updated --------------------------------------------------
1245 
1246 
1247 
1248 
1249 
1250 
1251 
1253 
1312 
Matrix
The Matrix class.
Definition: matpackI.h:767
GriddedField::get_string_grid
const ArrayOfString & get_string_grid(Index i) const
Get a string grid.
Definition: gridded_fields.cc:157
find_effective_channel_boundaries
void find_effective_channel_boundaries(Vector &fmin, Vector &fmax, const Vector &f_backend, const ArrayOfGriddedField1 &backend_channel_response, const Numeric &delta, const Verbosity &verbosity)
Calculate channel boundaries from instrument response functions.
Definition: sensor.cc:1076
sensor_aux_vectors
void sensor_aux_vectors(Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, ConstVectorView sensor_response_f_grid, const ArrayOfIndex &sensor_response_pol_grid, ConstVectorView sensor_response_za_grid, ConstVectorView sensor_response_aa_grid, const Index za_aa_independent)
sensor_aux_vectors
Definition: sensor.cc:586
Sparse::ncols
Index ncols() const
Returns the number of columns.
Definition: matpackII.cc:59
b0
#define b0
Definition: continua.cc:14105
gridpos
void gridpos(ArrayOfGridPos &gp, ConstVectorView old_grid, ConstVectorView new_grid, const Numeric &extpolfac)
Set up a grid position Array.
Definition: interpolation.cc:167
Tensor3
The Tensor3 class.
Definition: matpackIII.h:340
spectrometer_matrix
void spectrometer_matrix(Sparse &H, ConstVectorView ch_f, const ArrayOfGriddedField1 &ch_response, ConstVectorView sensor_f, const Index &n_pol, const Index &n_sp, const Index &do_norm)
spectrometer_matrix
Definition: sensor.cc:897
joker
const Joker joker
last
Numeric last(ConstVectorView x)
last
Definition: math_funcs.cc:183
interp
Numeric interp(ConstVectorView itw, ConstVectorView a, const GridPos &tc)
Red 1D Interpolate.
Definition: interpolation.cc:1000
sensor_integration_vector
void sensor_integration_vector(VectorView h, ConstVectorView f, ConstVectorView x_f_in, ConstVectorView x_g_in)
sensor_integration_vector
Definition: sensor.cc:683
Sparse
The Sparse class.
Definition: matpackII.h:55
Vector::resize
void resize(Index n)
Resize function.
Definition: matpackI.cc:771
GriddedField1::data
Vector data
Definition: gridded_fields.h:225
CREATE_OUT2
#define CREATE_OUT2
Definition: messages.h:207
GriddedField::get_numeric_grid
ConstVectorView get_numeric_grid(Index i) const
Get a numeric grid.
Definition: gridded_fields.cc:91
Sparse::insert_row
void insert_row(Index r, Vector v)
Insert row function.
Definition: matpackII.cc:303
antenna1d_matrix
void antenna1d_matrix(Sparse &H, const Index &antenna_dim, ConstMatrixView antenna_los, const GriddedField4 &antenna_response, ConstVectorView za_grid, ConstVectorView f_grid, const Index n_pol, const Index do_norm)
antenna1d_matrix
Definition: sensor.cc:78
dx
#define dx
Definition: continua.cc:14561
DEBUG_ONLY
#define DEBUG_ONLY(...)
Definition: arts.h:146
matpackI.h
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
get_sorted_indexes
void get_sorted_indexes(ArrayOfIndex &sorted, const T &data)
get_sorted_indexes
Definition: sorting.h:79
sensor.h
Sensor modelling functions.
test_and_merge_two_channels
bool test_and_merge_two_channels(Vector &fmin, Vector &fmax, Index i, Index j)
Test if two instrument channels overlap, and if so, merge them.
Definition: sensor.cc:1000
messages.h
Declarations having to do with the four output streams.
GFIELD4_ZA_GRID
const Index GFIELD4_ZA_GRID
_U_
#define _U_
Definition: config.h:158
ConstVectorView::nelem
Index nelem() const
Returns the number of elements.
Definition: matpackI.cc:175
VectorView
The VectorView class.
Definition: matpackI.h:373
ConstVectorView::sum
Numeric sum() const
The sum of all elements of a Vector.
Definition: matpackI.cc:181
sensor_summation_vector
void sensor_summation_vector(VectorView h, ConstVectorView f, ConstVectorView x_f, ConstVectorView x_g, const Numeric x1, const Numeric x2)
sensor_summation_vector
Definition: sensor.cc:831
Numeric
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
Verbosity
Definition: messages.h:50
ConstTensor4View::npages
Index npages() const
Returns the number of pages.
Definition: matpackIV.cc:66
GriddedField4
Definition: gridded_fields.h:328
ConstTensor4View::nbooks
Index nbooks() const
Returns the number of books.
Definition: matpackIV.cc:60
GriddedField4::resize
void resize(const GriddedField4 &gf)
Make this GriddedField4 the same size as the given one.
Definition: gridded_fields.h:356
ConstMatrixView
A constant view of a Matrix.
Definition: matpackI.h:591
GFIELD1_F_GRID
const Index GFIELD1_F_GRID
ConstTensor4View::nrows
Index nrows() const
Returns the number of rows.
Definition: matpackIV.cc:72
Sparse::resize
void resize(Index r, Index c)
Resize function.
Definition: matpackII.cc:516
Range
The range class.
Definition: matpackI.h:148
GriddedField::set_grid
void set_grid(Index i, const Vector &g)
Set a numeric grid.
Definition: gridded_fields.cc:223
antenna2d_simplified
void antenna2d_simplified(Sparse &H, const Index &antenna_dim, ConstMatrixView antenna_los, const GriddedField4 &antenna_response, ConstVectorView za_grid, ConstVectorView aa_grid, ConstVectorView f_grid, const Index n_pol, const Index do_norm)
antenna2d_simplified
Definition: sensor.cc:246
mixer_matrix
void mixer_matrix(Sparse &H, Vector &f_mixer, const Numeric &lo, const GriddedField1 &filter, ConstVectorView f_grid, const Index &n_pol, const Index &n_sp, const Index &do_norm)
mixer_matrix
Definition: sensor.cc:455
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.
GriddedField1
Definition: gridded_fields.h:189
matpackII.h
Header file for sparse matrices.
NAT_LOG_2
const Numeric NAT_LOG_2
GFIELD4_AA_GRID
const Index GFIELD4_AA_GRID
PI
const Numeric PI
Index
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
GFIELD4_F_GRID
const Index GFIELD4_F_GRID
linspace
void linspace(Vector &x, const Numeric start, const Numeric stop, const Numeric step)
linspace
Definition: math_funcs.cc:228
GriddedField4::data
Tensor4 data
Definition: gridded_fields.h:373
gaussian_response
void gaussian_response(Vector &x, Vector &y, const Numeric &x0, const Numeric &fwhm, const Numeric &xwidth_si, const Numeric &dx_si)
gaussian_response
Definition: sensor.cc:408
Vector
The Vector class.
Definition: matpackI.h:555
ConstVectorView
A constant view of a Vector.
Definition: matpackI.h:300
sorting.h
Contains sorting routines.
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
arts.h
The global header file for ARTS.
GFIELD4_FIELD_NAMES
const Index GFIELD4_FIELD_NAMES