ARTS  2.0.49
m_sensor.cc
Go to the documentation of this file.
1 /* Copyright (C) 2003-2009
2  Patrick Eriksson <Patrick.Eriksson@chalmers.se>
3  Stefan Buehler <sbuehler(at)ltu.se>
4 
5  This program is free software; you can redistribute it and/or modify it
6  under the terms of the GNU General Public License as published by the
7  Free Software Foundation; either version 2, or (at your option) any
8  later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18  USA. */
19 
20 
21 
22 /*===========================================================================
23  === File description
24  ===========================================================================*/
25 
39 /*===========================================================================
40  === External declarations
41  ===========================================================================*/
42 
43 #include <cmath>
44 #include <stdexcept>
45 #include <string>
46 #include "arts.h"
47 #include "check_input.h"
48 #include "interpolation_poly.h"
49 #include "math_funcs.h"
50 #include "messages.h"
51 #include "ppath.h"
52 #include "special_interp.h"
53 #include "xml_io.h"
54 #include "sensor.h"
55 #include "make_vector.h"
56 #include "sorting.h"
57 #include "auto_md.h"
58 
59 extern const Numeric PI;
60 extern const Index GFIELD1_F_GRID;
61 extern const Index GFIELD4_FIELD_NAMES;
62 extern const Index GFIELD4_F_GRID;
63 extern const Index GFIELD4_ZA_GRID;
64 extern const Index GFIELD4_AA_GRID;
65 
66 
67 /*===========================================================================
68  === The functions (in alphabetical order)
69  ===========================================================================*/
70 
71 /* Workspace method: Doxygen documentation will be auto-generated */
72 void AntennaConstantGaussian1D(Index& antenna_dim,
73  Vector& mblock_za_grid,
74  Vector& mblock_aa_grid,
75  GriddedField4& r,
76  Matrix& antenna_los,
77  const Index& n_za_grid,
78  const Numeric& fwhm,
79  const Numeric& xwidth_si,
80  const Numeric& dx_si,
81  const Verbosity& verbosity)
82 {
83  AntennaSet1D( antenna_dim, mblock_aa_grid, verbosity );
84  antenna_responseGaussian( r, fwhm, xwidth_si, dx_si, verbosity );
85 
86  antenna_los.resize(1,1);
87  antenna_los(0,0) = 0.0;
88 
89  // za grid for response
91  const Index nr = r_za_grid.nelem();
92 
93  // Cumulative sum of response
94  Vector cumsum(nr);
95  cumsum[0] = r.data(0,0,0,0);
96  for( Index i=1; i<nr; i++ )
97  { cumsum[i] = cumsum[i-1] + r.data(0,0,i,0); }
98 
99  // Equally spaced vector between end points of cumulative sum
100  Vector csp;
101  nlinspace( csp, cumsum[0], cumsum[nr-1], n_za_grid );
102 
103  // Get mblock_za_grid by interpolation
104  mblock_za_grid.resize(n_za_grid);
105  ArrayOfGridPos gp(n_za_grid);
106  gridpos( gp, cumsum, csp );
107  Matrix itw(n_za_grid,2);
108  interpweights( itw, gp );
109  interp( mblock_za_grid, itw, r_za_grid, gp );
110 }
111 
112 
113 
114 /* Workspace method: Doxygen documentation will be auto-generated */
116  Matrix& sensor_los,
117  Matrix& antenna_los,
118  Index& antenna_dim,
119  Vector& mblock_za_grid,
120  Vector& mblock_aa_grid,
121  const Index& atmosphere_dim,
122  const Verbosity& verbosity)
123 {
124  // Sizes
125  const Index nmblock = sensor_pos.nrows();
126  const Index nant = antenna_los.nrows();
127 
128  // Input checks
129  chk_if_in_range( "atmosphere_dim", atmosphere_dim, 1, 3 );
130  chk_if_in_range( "antenna_dim", antenna_dim, 1, 2 );
131  //
132  if( sensor_pos.ncols() != atmosphere_dim )
133  throw runtime_error( "The number of columns of sensor_pos must be "
134  "equal to the atmospheric dimensionality." );
135  if( atmosphere_dim <= 2 && sensor_los.ncols() != 1 )
136  throw runtime_error(
137  "For 1D and 2D, sensor_los shall have one column." );
138  if( atmosphere_dim == 3 && sensor_los.ncols() != 2 )
139  throw runtime_error( "For 3D, sensor_los shall have two columns." );
140  if( sensor_los.nrows() != nmblock )
141  {
142  ostringstream os;
143  os << "The number of rows of sensor_pos and sensor_los must be "
144  << "identical, but sensor_pos has " << nmblock << " rows,\n"
145  << "while sensor_los has " << sensor_los.nrows() << " rows.";
146  throw runtime_error( os.str() );
147  }
148  if( antenna_dim == 2 && atmosphere_dim < 3 )
149  {
150  throw runtime_error(
151  "If *antenna_dim* is 2, *atmosphere_dim* must be 3." );
152  }
153  if( antenna_dim != antenna_los.ncols() )
154  {
155  throw runtime_error(
156  "The number of columns of *antenna_los* must be *antenna_dim*.\n" );
157  }
158 
159  // Claculate new sensor_pos and sensor_los
160  const Matrix pos_copy = sensor_pos;
161  const Matrix los_copy = sensor_los;
162  //
163  sensor_pos.resize( nmblock*nant, pos_copy.ncols() );
164  sensor_los.resize( nmblock*nant, los_copy.ncols() );
165  //
166  for( Index ib=0; ib<nmblock; ib++ )
167  {
168  for( Index ia=0; ia<nant; ia++ )
169  {
170  const Index i = ib*nant + ia;
171 
172  sensor_pos(i,joker) = pos_copy(ib,joker);
173  sensor_los(i,joker) = los_copy(ib,joker);
174 
175  sensor_los(i,0) += antenna_los(ia,0);
176  if( antenna_dim == 2 )
177  sensor_los(i,1) += antenna_los(ia,1);
178  }
179  }
180 
181  // Set other variables
182  AntennaOff( antenna_dim, mblock_za_grid, mblock_aa_grid, verbosity );
183  //
184  antenna_los.resize( 1, 1 );
185  antenna_los = 0;
186 }
187 
188 
189 
190 /* Workspace method: Doxygen documentation will be auto-generated */
191 void AntennaOff(// WS Output:
192  Index& antenna_dim,
193  Vector& mblock_za_grid,
194  Vector& mblock_aa_grid,
195  const Verbosity& verbosity)
196 {
198 
199  out2 << " Sets the antenna dimensionality to 1.\n";
200  antenna_dim = 1;
201 
202  out2 << " Sets *mblock_za_grid* to have length 1 with value 0.\n";
203  mblock_za_grid.resize(1);
204  mblock_za_grid[0] = 0;
205 
206  out2 << " Sets *mblock_aa_grid* to be an empty vector.\n";
207  mblock_aa_grid.resize(0);
208 }
209 
210 
211 
212 /* Workspace method: Doxygen documentation will be auto-generated */
213 void AntennaSet1D(// WS Output:
214  Index& antenna_dim,
215  Vector& mblock_aa_grid,
216  const Verbosity& verbosity)
217 {
220 
221  out2 << " Sets the antenna dimensionality to 1.\n";
222  out3 << " antenna_dim = 1\n";
223  out3 << " mblock_aa_grid is set to be an empty vector\n";
224  antenna_dim = 1;
225  mblock_aa_grid.resize(0);
226 }
227 
228 
229 
230 /* Workspace method: Doxygen documentation will be auto-generated */
231 void AntennaSet2D(// WS Output:
232  Index& antenna_dim,
233  // WS Input:
234  const Index& atmosphere_dim,
235  const Verbosity& verbosity)
236 {
239 
240  if( atmosphere_dim != 3 )
241  throw runtime_error("Antenna dimensionality 2 is only allowed when the "
242  "atmospheric dimensionality is 3." );
243  out2 << " Sets the antenna dimensionality to 1.\n";
244  out3 << " antenna_dim = 2\n";
245  antenna_dim = 2;
246 }
247 
248 
249 
250 /* Workspace method: Doxygen documentation will be auto-generated */
252  const Numeric& fwhm,
253  const Numeric& xwidth_si,
254  const Numeric& dx_si,
255  const Verbosity&)
256 {
257  Vector x, y;
258  gaussian_response( x, y, 0, fwhm, xwidth_si, dx_si );
259 
260  r.set_name( "Antenna response" );
261 
262  r.set_grid_name( 0, "Polarisation" );
263  r.set_grid( 0, MakeArray<String>( "NaN" ) );
264 
265  r.set_grid_name( 1, "Frequency" );
266  r.set_grid( 1, Vector(1,-999) );
267 
268  r.set_grid_name( 2, "Zenith angle" );
269  r.set_grid( 2, x );
270 
271  r.set_grid_name( 3, "Azimuth angle" );
272  r.set_grid( 3, Vector(1,0) );
273 
274  const Index n = y.nelem();
275  r.data.resize( 1, 1, n, 1 );
276  r.data(0,0,joker,0) = y;
277 }
278 
279 
280 
281 /* Workspace method: Doxygen documentation will be auto-generated */
283  const Numeric& resolution,
284  const Verbosity&)
285 {
286  r.resize( 1 );
287  r[0].set_name( "Backend channel response function" );
288 
289  Vector x(2);
290 
291  r[0].set_grid_name( 0, "Frequency" );
292  x[1] = resolution / 2.0;
293  x[0] = -x[1];
294  r[0].set_grid( 0, x );
295 
296  r[0].data.resize( 2 );
297  r[0].data[0] = 1/ resolution;
298  r[0].data[1] = r[0].data[0];
299 }
300 
301 
302 
303 /* Workspace method: Doxygen documentation will be auto-generated */
305  const Numeric& fwhm,
306  const Numeric& xwidth_si,
307  const Numeric& dx_si,
308  const Verbosity&)
309 {
310  r.resize( 1 );
311  Vector x, y;
312 
313  gaussian_response( x, y, 0, fwhm, xwidth_si, dx_si );
314 
315  r[0].set_name( "Backend channel response function" );
316 
317  r[0].set_grid_name( 0, "Frequency" );
318  r[0].set_grid( 0, x );
319 
320  const Index n = y.nelem();
321  r[0].data.resize( n );
322  for( Index i=0; i<n; i++ )
323  r[0].data[i] = y[i];
324 }
325 
326 
327 
328 /* Workspace method: Doxygen documentation will be auto-generated */
329 void f_gridFromSensorAMSU(// WS Output:
330  Vector& f_grid,
331  // WS Input:
332  const Vector& lo,
333  const ArrayOfVector& f_backend,
334  const ArrayOfArrayOfGriddedField1& backend_channel_response,
335  // Control Parameters:
336  const Numeric& spacing,
337  const Verbosity& verbosity)
338 {
341 
342  // Find out how many channels we have in total:
343  // f_backend is an array of vectors, containing the band frequencies for each Mixer.
344  Index n_chan = 0;
345  for (Index i=0; i<f_backend.nelem(); ++i)
346  for (Index s=0; s<f_backend[i].nelem(); ++s)
347  ++n_chan;
348 
349  // Checks on input quantities:
350 
351  // There must be at least one channel:
352  if (n_chan < 1)
353  {
354  ostringstream os;
355  os << "There must be at least one channel.\n"
356  << "(The vector *lo* must have at least one element.)";
357  throw runtime_error(os.str());
358  }
359 
360  // Is number of LOs consistent in all input variables?
361  if ( (f_backend.nelem() != lo.nelem()) ||
362  (backend_channel_response.nelem() != lo.nelem()) )
363  {
364  ostringstream os;
365  os << "Variables *lo_multi*, *f_backend_multi* and *backend_channel_response_multi*\n"
366  << "must have same number of elements (number of LOs).";
367  throw runtime_error(os.str());
368  }
369 
370  // Is number of bands consistent for each LO?
371  for (Index i=0; i<f_backend.nelem(); ++i)
372  if (f_backend[i].nelem() != backend_channel_response[i].nelem())
373  {
374  ostringstream os;
375  os << "Variables *f_backend_multi* and *backend_channel_response_multi*\n"
376  << "must have same number of bands for each LO.";
377  throw runtime_error(os.str());
378  }
379 
380  // Start the actual work.
381 
382  // We construct the necessary input for function find_effective_channel_boundaries,
383  // which will identify channel boundaries, taking care of overlaping channels.
384 
385  // A "flat" vector of nominal band frequencies (two for each AMSU channel):
386  Vector f_backend_flat(2*n_chan);
387 
388  // A "flat" list of channel response functions (two for each AMSU channel)
389  ArrayOfGriddedField1 backend_channel_response_flat(2*n_chan);
390 
391  // Counts position inside the flat arrays during construction:
392  Index j=0;
393 
394  for (Index i=0; i<f_backend.nelem(); ++i)
395  for (Index s=0; s<f_backend[i].nelem(); ++s)
396  {
397  const GriddedField1& this_grid = backend_channel_response[i][s];
398  const Numeric this_f_backend = f_backend[i][s];
399 
400  // Signal sideband:
401  f_backend_flat[j] = this_f_backend;
402  backend_channel_response_flat[j] = this_grid;
403  j++;
404 
405  // Image sideband:
406  Numeric offset = this_f_backend - lo[i];
407  Numeric f_image = lo[i] - offset;
408  f_backend_flat[j] = f_image;
409  backend_channel_response_flat[j] = this_grid;
410  j++;
411  }
412 
413  // We build up a total list of absolute frequency ranges for
414  // both signal and image sidebands:
415  Vector fmin(2*n_chan), fmax(2*n_chan);
416 
417  // We have to add some additional margin at the band edges,
418  // otherwise the instrument functions are not happy. Define
419  // this in terms of the grid spacing:
420  Numeric delta = 1*spacing;
421 
422  // Call subfunction to do the actual work of merging overlapping
423  // channels and identifying channel boundaries:
425  fmax,
426  f_backend_flat,
427  backend_channel_response_flat,
428  delta, verbosity);
429 
430  // Create f_grid_array. This is an array of Numeric, so that we
431  // can use the STL push_back function.
432  ArrayOfNumeric f_grid_array;
433 
434  for (Index i=0; i<fmin.nelem(); ++i)
435  {
436  // Band width:
437  const Numeric bw = fmax[i] - fmin[i];
438 
439  // How many grid intervals do I need?
440  const Numeric npf = ceil(bw/spacing);
441 
442  // How many grid points to store? - Number of grid intervals
443  // plus 1.
444  const Index npi = (Index) npf + 1;
445 
446  // What is the actual grid spacing inside the band?
447  const Numeric gs = bw/npf;
448 
449  // Create the grid for this band:
450  Vector grid(fmin[i], npi, gs);
451 
452  out3 << " Band range " << i << ": " << grid << "\n";
453 
454  // Append to f_grid_array:
455  f_grid_array.reserve(f_grid_array.nelem()+npi);
456  for (Index s=0; s<npi; ++s)
457  f_grid_array.push_back(grid[s]);
458  }
459 
460  // Copy result to output vector:
461  f_grid = f_grid_array;
462 
463  out2 << " Total number of frequencies in f_grid: " << f_grid.nelem() << "\n";
464  // cout << "f_grid: " << f_grid << "\n";
465 }
466 
467 /* Workspace method: Doxygen documentation will be auto-generated */
468 void f_gridFromSensorHIRS(// WS Output:
469  Vector& f_grid,
470  // WS Input:
471  const Vector& f_backend,
472  const ArrayOfGriddedField1& backend_channel_response,
473  // Control Parameters:
474  const Numeric& spacing,
475  const Verbosity& verbosity)
476 {
479 
480  // Check input
481  if (spacing <= 0) {
482  ostringstream os;
483  os << "Expected positive spacing. Found spacing to be: "
484  << spacing << "\n";
485  throw runtime_error(os.str());
486  }
487  // Call subfunction to get channel boundaries. Also does input
488  // consistency checking for us.
489  Vector fmin, fmax;
490 
491  // We have to add some additional margin at the band edges,
492  // otherwise the instrument functions are not happy. Define
493  // this in terms of the grid spacing:
494  Numeric delta = 1*spacing;
495 
497  fmax,
498  f_backend,
499  backend_channel_response,
500  delta, verbosity);
501 
502  // Ok, now we just have to create a frequency grid for each of the
503  // fmin/fmax ranges.
504 
505  // Create f_grid_array. This is an array of Numeric, so that we
506  // can use the STL push_back function.
507  ArrayOfNumeric f_grid_array;
508 
509  for (Index i=0; i<fmin.nelem(); ++i)
510  {
511  // Band width:
512  const Numeric bw = fmax[i] - fmin[i];
513 
514  // How many grid intervals do I need?
515  const Numeric npf = ceil(bw/spacing);
516 
517  // How many grid points to store? - Number of grid intervals
518  // plus 1.
519  const Index npi = (Index) npf + 1;
520 
521  // What is the actual grid spacing inside the band?
522  const Numeric gs = bw/npf;
523 
524  // Create the grid for this band:
525  Vector grid(fmin[i], npi, gs);
526 
527  out3 << " Band range " << i << ": " << grid << "\n";
528 
529  // Append to f_grid_array:
530  f_grid_array.reserve(f_grid_array.nelem()+npi);
531  for (Index s=0; s<npi; ++s)
532  f_grid_array.push_back(grid[s]);
533  }
534 
535  // Copy result to output vector:
536  f_grid = f_grid_array;
537 
538  out2 << " Total number of frequencies in f_grid: " << f_grid.nelem() << "\n";
539 
540 }
541 
542 
543 /* Workspace method: Doxygen documentation will be auto-generated */
544 void sensor_responseAntenna(// WS Output:
545  Sparse& sensor_response,
546  Vector& sensor_response_f,
547  ArrayOfIndex& sensor_response_pol,
548  Vector& sensor_response_za,
549  Vector& sensor_response_aa,
550  Vector& sensor_response_za_grid,
551  Vector& sensor_response_aa_grid,
552  // WS Input:
553  const Vector& sensor_response_f_grid,
554  const ArrayOfIndex& sensor_response_pol_grid,
555  const Index& atmosphere_dim,
556  const Index& antenna_dim,
557  const Matrix& antenna_los,
558  const GriddedField4& antenna_response,
559  const Index& sensor_norm,
560  const Verbosity& verbosity)
561 {
563 
564  // Basic checks
565  chk_if_in_range( "atmosphere_dim", atmosphere_dim, 1, 3 );
566  chk_if_in_range( "antenna_dim", antenna_dim, 1, 2 );
567  chk_if_bool( "sensor_norm", sensor_norm );
568 
569  // Some sizes
570  const Index nf = sensor_response_f_grid.nelem();
571  const Index npol = sensor_response_pol_grid.nelem();
572  const Index nza = sensor_response_za_grid.nelem();
573  const Index naa = max( Index(1), sensor_response_aa_grid.nelem() );
574  const Index nin = nf * npol * nza * naa;
575 
576  // Initialise a output stream for runtime errors and a flag for errors
577  ostringstream os;
578  bool error_found = false;
579 
580 
581  // Check that sensor_response variables are consistent in size
582  if( sensor_response_f.nelem() != nin )
583  {
584  os << "Inconsistency in size between *sensor_response_f* and the sensor\n"
585  << "grid variables (sensor_response_f_grid etc.).\n";
586  error_found = true;
587  }
588  if( sensor_response.nrows() != nin )
589  {
590  os << "The sensor block response matrix *sensor_response* does not have\n"
591  << "right size compared to the sensor grid variables\n"
592  << "(sensor_response_f_grid etc.).\n";
593  error_found = true;
594  }
595 
596 
597  // Checks related to antenna dimension
598  if( antenna_dim == 2 && atmosphere_dim < 3 )
599  {
600  os << "If *antenna_dim* is 2, *atmosphere_dim* must be 3.\n";
601  error_found = true;
602  }
603  if( antenna_dim == 1 && sensor_response_aa_grid.nelem() )
604  {
605  os << "If *antenna_dim* is 1, *sensor_response_aa_grid* (and\n"
606  << "*mblock_aa_grid*) must be empty.";
607  error_found = true;
608  }
609 
610 
611  // Check of antenna_los
612  if( antenna_dim != antenna_los.ncols() )
613  {
614  os << "The number of columns of *antenna_los* must be *antenna_dim*.\n";
615  error_found = true;
616  }
617  // We allow angles in antenna_los to be unsorted
618 
619 
620  // Checks of antenna_response polarisation dimension
621  //
622  const Index lpolgrid =
623  antenna_response.get_string_grid(GFIELD4_FIELD_NAMES).nelem();
624  //
625  if( lpolgrid != 1 && lpolgrid != npol )
626  {
627  os << "The number of polarisation in *antenna_response* must be 1 or be\n"
628  << "equal to the number of polarisations used (determined by\n"
629  << "*stokes_dim* or *sensor_pol*).\n";
630  error_found = true;
631  }
632 
633 
634  // Checks of antenna_response frequency dimension
635  //
636  ConstVectorView aresponse_f_grid =
637  antenna_response.get_numeric_grid(GFIELD4_F_GRID);
638  //
639  chk_if_increasing( "f_grid of antenna_response", aresponse_f_grid );
640  //
641  Numeric f_dlow = 0.0;
642  Numeric f_dhigh = 0.0;
643  //
644  f_dlow = min(sensor_response_f_grid) - aresponse_f_grid[0];
645  f_dhigh = last(aresponse_f_grid) - max(sensor_response_f_grid);
646  //
647  if( aresponse_f_grid.nelem() > 1 )
648  {
649  if( f_dlow < 0 )
650  {
651  os << "The frequency grid of *antenna_response is too narrow. It must\n"
652  << "cover all considered frequencies (*f_grid*), if the length\n"
653  << "is > 1. The grid needs to be expanded with "<<-f_dlow<<" Hz in\n"
654  << "the lower end.\n";
655  error_found = true;
656  }
657  if( f_dhigh < 0 )
658  {
659  os << "The frequency grid of *antenna_response is too narrow. It must\n"
660  << "cover all considered frequencies (*f_grid*), if the length\n"
661  << "is > 1. The grid needs to be expanded with "<<-f_dhigh<<" Hz in\n"
662  << "the upper end.\n";
663  error_found = true;
664  }
665  }
666 
667 
668  // Checks of antenna_response za dimension
669  //
670  ConstVectorView aresponse_za_grid =
671  antenna_response.get_numeric_grid(GFIELD4_ZA_GRID);
672  //
673  chk_if_increasing( "za_grid of *antenna_response*", aresponse_za_grid );
674  //
675  if( aresponse_za_grid.nelem() < 2 )
676  {
677  os << "The zenith angle grid of *antenna_response* must have >= 2 values.\n";
678  error_found = true;
679 
680  }
681  //
682  // Check if the relative grid added to the antena_los za angles
683  // outside sensor_response_za_grid.
684  //
685  Numeric za_dlow = 0.0;
686  Numeric za_dhigh = 0.0;
687  //
688  za_dlow = min(antenna_los(joker,0)) + aresponse_za_grid[0] -
689  min(sensor_response_za_grid);
690  za_dhigh = max(sensor_response_za_grid) - ( max(antenna_los(joker,0)) +
691  last(aresponse_za_grid) );
692  //
693  if( za_dlow < 0 )
694  {
695  os << "The WSV *sensor_response_za_grid* is too narrow. It should be\n"
696  << "expanded with "<<-za_dlow<<" deg in the lower end. This change\n"
697  << "should be probably applied to *mblock_za_grid*.\n";
698  error_found = true;
699  }
700  if( za_dhigh < 0 )
701  {
702  os << "The WSV *sensor_response_za_grid* is too narrow. It should be\n"
703  << "expanded with "<<-za_dhigh<<" deg in the higher end. This change\n"
704  << "should be probably applied to *mblock_za_grid*.\n";
705  error_found = true;
706  }
707 
708 
709  // Checks of antenna_response aa dimension
710  //
711  ConstVectorView aresponse_aa_grid =
712  antenna_response.get_numeric_grid(GFIELD4_AA_GRID);
713  //
714  if( antenna_dim == 1 )
715  {
716  if( aresponse_aa_grid.nelem() != 1 )
717  {
718  os << "The azimuthal dimension of *antenna_response* must be 1 if\n"
719  << "*antenna_dim* equals 1.\n";
720  error_found = true;
721  }
722  }
723  else
724  {
725  chk_if_increasing( "aa_grid of antenna_response", aresponse_aa_grid );
726  //
727  if( aresponse_za_grid.nelem() < 2 )
728  {
729  os << "The zenith angle grid of *antenna_response* must have >= 2\n"
730  << "values.\n";
731  error_found = true;
732  }
733  // Check if the relative grid added to the antena_los aa angles
734  // outside sensor_response_aa_grid.
735  //
736  Numeric aa_dlow = 0.0;
737  Numeric aa_dhigh = 0.0;
738  //
739  aa_dlow = min(antenna_los(joker,1)) + aresponse_aa_grid[0] -
740  min(sensor_response_aa_grid);
741  aa_dhigh = max(sensor_response_aa_grid) - ( max(antenna_los(joker,1)) +
742  last(aresponse_aa_grid) );
743  //
744  if( aa_dlow < 0 )
745  {
746  os << "The WSV *sensor_response_aa_grid* is too narrow. It should be\n"
747  << "expanded with "<<-aa_dlow<<" deg in the lower end. This change\n"
748  << "should be probably applied to *mblock_aa_grid*.\n";
749  error_found = true;
750  }
751  if( aa_dhigh < 0 )
752  {
753  os << "The WSV *sensor_response_aa_grid* is too narrow. It should be\n"
754  << "expanded with "<<-aa_dhigh<<" deg in the higher end. This change\n"
755  << "should be probably applied to *mblock_aa_grid*.\n";
756  error_found = true;
757  }
758  }
759 
760 
761  // If errors where found throw runtime_error with the collected error
762  // message.
763  if (error_found)
764  throw runtime_error(os.str());
765 
766 
767 
768  // Call the core function
769  //
770  Sparse hantenna;
771  //
772  if( antenna_dim == 1 )
773  antenna1d_matrix( hantenna, antenna_dim, antenna_los, antenna_response,
774  sensor_response_za_grid, sensor_response_f_grid,
775  npol, sensor_norm );
776  else
777  antenna2d_simplified( hantenna, antenna_dim, antenna_los, antenna_response,
778  sensor_response_za_grid, sensor_response_aa_grid,
779  sensor_response_f_grid, npol, sensor_norm );
780 
781  // Here we need a temporary sparse that is copy of the sensor_response
782  // sparse matrix. We need it since the multiplication function can not
783  // take the same object as both input and output.
784  Sparse htmp = sensor_response;
785  sensor_response.resize( hantenna.nrows(), htmp.ncols());
786  mult( sensor_response, hantenna, htmp );
787 
788  // Some extra output.
789  out3 << " Size of *sensor_response*: " << sensor_response.nrows()
790  << "x" << sensor_response.ncols() << "\n";
791 
792  // Update sensor_response_za_grid
793  sensor_response_za_grid = antenna_los(joker,0);
794 
795  // Update sensor_response_aa_grid
796  if( antenna_dim == 2 )
797  sensor_response_aa_grid = antenna_los(joker,1);
798 
799  // Set aux variables
800  sensor_aux_vectors( sensor_response_f, sensor_response_pol,
801  sensor_response_za, sensor_response_aa,
802  sensor_response_f_grid, sensor_response_pol_grid,
803  sensor_response_za_grid, sensor_response_aa_grid, 0 );
804 }
805 
806 
807 
808 
809 
810 /* Workspace method: Doxygen documentation will be auto-generated */
811 void sensor_responseBackend(// WS Output:
812  Sparse& sensor_response,
813  Vector& sensor_response_f,
814  ArrayOfIndex& sensor_response_pol,
815  Vector& sensor_response_za,
816  Vector& sensor_response_aa,
817  Vector& sensor_response_f_grid,
818  // WS Input:
819  const ArrayOfIndex& sensor_response_pol_grid,
820  const Vector& sensor_response_za_grid,
821  const Vector& sensor_response_aa_grid,
822  const Vector& f_backend,
823  const ArrayOfGriddedField1& backend_channel_response,
824  const Index& sensor_norm,
825  const Verbosity& verbosity)
826 {
828 
829  // Some sizes
830  const Index nf = sensor_response_f_grid.nelem();
831  const Index npol = sensor_response_pol_grid.nelem();
832  const Index nza = sensor_response_za_grid.nelem();
833  const Index naa = sensor_response_aa_grid.nelem();
834  const Index nin = nf * npol * nza;
835  // Note that there is no distinction between za and aa grids after the antenna
836 
837  // Initialise an output stream for runtime errors and a flag for errors
838  ostringstream os;
839  bool error_found = false;
840 
841  // Check that sensor_response variables are consistent in size
842  if( sensor_response_f.nelem() != nin )
843  {
844  os << "Inconsistency in size between *sensor_response_f* and the sensor\n"
845  << "grid variables (sensor_response_f_grid etc.).\n";
846  error_found = true;
847  }
848  if( naa && naa != nza )
849  {
850  os << "Incorrect size of *sensor_response_aa_grid*.\n";
851  error_found = true;
852  }
853  if( sensor_response.nrows() != nin )
854  {
855  os << "The sensor block response matrix *sensor_response* does not have\n"
856  << "right size compared to the sensor grid variables\n"
857  << "(sensor_response_f_grid etc.).\n";
858  error_found = true;
859  }
860 
861  // We allow f_backend to be unsorted, but must be inside sensor_response_f_grid
862  if( min(f_backend) < min(sensor_response_f_grid) )
863  {
864  os << "At least one value in *f_backend* (" << min(f_backend)
865  << ") below range\ncovered by *sensor_response_f_grid* ("
866  << min(sensor_response_f_grid) << ").\n";
867  error_found = true;
868  }
869  if( max(f_backend) > max(sensor_response_f_grid) )
870  {
871  os << "At least one value in *f_backend* (" << max(f_backend)
872  << ") above range\ncovered by *sensor_response_f_grid* ("
873  << max(sensor_response_f_grid) << ").\n";
874  error_found = true;
875  }
876 
877  // Check number of columns in backend_channel_response
878  //
879  const Index nrp = backend_channel_response.nelem();
880  //
881  if( nrp != 1 && nrp != f_backend.nelem() )
882  {
883  os << "The WSV *backend_channel_response* must have 1 or n elements,\n"
884  << "where n is the length of *f_backend*.\n";
885  error_found = true;
886  }
887 
888  // If errors where found throw runtime_error with the collected error
889  // message (before error message gets too long).
890  if( error_found )
891  throw runtime_error(os.str());
892 
893  Numeric f_dlow = 0.0;
894  Numeric f_dhigh = 0.0;
895 
896  for( Index i=0; i<nrp; i++ )
897  {
898  ConstVectorView bchr_f_grid =
899  backend_channel_response[i].get_numeric_grid(GFIELD1_F_GRID);
900 
901  if( bchr_f_grid.nelem() != backend_channel_response[i].data.nelem() )
902  {
903  os << "Mismatch in size of grid and data in element " << i
904  << "\nof *sideband_response*.\n";
905  error_found = true;
906  }
907 
908  if( !is_increasing( bchr_f_grid ) )
909  {
910  os << "The frequency grid of element " << i
911  << " in *backend_channel_response*\nis not strictly increasing.\n";
912  error_found = true;
913  }
914 
915  // Check if the relative grid added to the channel frequencies expands
916  // outside sensor_response_f_grid.
917  //
918  Numeric f1 = f_backend[i] + bchr_f_grid[0] - min(sensor_response_f_grid);
919  Numeric f2 = (max(sensor_response_f_grid) -
920  f_backend[i]) - last(bchr_f_grid);
921  //
922  f_dlow = min( f_dlow, f1 );
923  f_dhigh = min( f_dhigh, f2 );
924  }
925 
926  if( f_dlow < 0 )
927  {
928  os << "The WSV *sensor_response_f_grid* is too narrow. It should be\n"
929  << "expanded with "<<-f_dlow<<" Hz in the lower end. This change\n"
930  << "should be applied to either *f_grid* or the sensor part in\n"
931  << "front of *sensor_responseBackend*.\n";
932  error_found = true;
933  }
934  if( f_dhigh < 0 )
935  {
936  os << "The WSV *sensor_response_f_grid* is too narrow. It should be\n"
937  << "expanded with "<<-f_dhigh<<" Hz in the higher end. This change\n"
938  << "should be applied to either *f_grid* or the sensor part in\n"
939  << "front of *sensor_responseBackend*.\n";
940  error_found = true;
941  }
942 
943  // If errors where found throw runtime_error with the collected error
944  // message.
945  if (error_found)
946  throw runtime_error(os.str());
947 
948 
949  // Call the core function
950  //
951  Sparse hbackend;
952  //
953  spectrometer_matrix( hbackend, f_backend, backend_channel_response,
954  sensor_response_f_grid, npol, nza, sensor_norm );
955 
956  // Here we need a temporary sparse that is copy of the sensor_response
957  // sparse matrix. We need it since the multiplication function can not
958  // take the same object as both input and output.
959  Sparse htmp = sensor_response;
960  sensor_response.resize( hbackend.nrows(), htmp.ncols());
961  mult( sensor_response, hbackend, htmp );
962 
963  // Some extra output.
964  out3 << " Size of *sensor_response*: " << sensor_response.nrows()
965  << "x" << sensor_response.ncols() << "\n";
966 
967  // Update sensor_response_f_grid
968  sensor_response_f_grid = f_backend;
969 
970  // Set aux variables
971  sensor_aux_vectors( sensor_response_f, sensor_response_pol,
972  sensor_response_za, sensor_response_aa,
973  sensor_response_f_grid, sensor_response_pol_grid,
974  sensor_response_za_grid, sensor_response_aa_grid, 0 );
975 }
976 
977 
978 
979 /* Workspace method: Doxygen documentation will be auto-generated */
981  Vector& sensor_response_f,
982  ArrayOfIndex& sensor_response_pol,
983  Vector& sensor_response_za,
984  Vector& sensor_response_aa,
985  Vector& sensor_response_f_grid,
986  const ArrayOfIndex& sensor_response_pol_grid,
987  const Vector& sensor_response_za_grid,
988  const Vector& sensor_response_aa_grid,
989  const Vector& f_backend,
990  const ArrayOfGriddedField1& backend_channel_response,
991  const Index& sensor_norm,
992  const Numeric& df1,
993  const Numeric& df2,
994  const Verbosity& verbosity)
995 {
996  // All needed checks are done in sensor_responseBackend
997 
998  Sparse H1=sensor_response, H2=sensor_response;
999 
1000  // Some needed vectors
1001  Vector f_backend_shifted;
1002  Vector fdummy=sensor_response_f, fdummy_grid=sensor_response_f_grid;
1003 
1004  // Cycle 1
1005  f_backend_shifted = f_backend;
1006  f_backend_shifted += df1;
1007  //
1008  sensor_responseBackend(H1, fdummy, sensor_response_pol,
1009  sensor_response_za, sensor_response_aa,
1010  fdummy_grid, sensor_response_pol_grid,
1011  sensor_response_za_grid, sensor_response_aa_grid,
1012  f_backend_shifted, backend_channel_response,
1013  sensor_norm, verbosity);
1014  // Cycle 2
1015  f_backend_shifted = f_backend;
1016  f_backend_shifted += df2;
1017  //
1018  sensor_responseBackend(H2, sensor_response_f, sensor_response_pol,
1019  sensor_response_za, sensor_response_aa,
1020  sensor_response_f_grid, sensor_response_pol_grid,
1021  sensor_response_za_grid, sensor_response_aa_grid,
1022  f_backend_shifted, backend_channel_response,
1023  sensor_norm, verbosity);
1024 
1025  // Total response
1026  sub( sensor_response, H2, H1 );
1027 
1028  // sensor_response_f_grid shall be f_backend
1029  sensor_response_f_grid = f_backend;
1030 
1031  // Set aux variables
1032  sensor_aux_vectors( sensor_response_f, sensor_response_pol,
1033  sensor_response_za, sensor_response_aa,
1034  sensor_response_f_grid, sensor_response_pol_grid,
1035  sensor_response_za_grid, sensor_response_aa_grid, 0 );
1036 }
1037 
1038 
1039 
1040 /* Workspace method: Doxygen documentation will be auto-generated */
1042  Sparse& sensor_response,
1043  Vector& sensor_response_f,
1044  ArrayOfIndex& sensor_response_pol,
1045  Vector& sensor_response_za,
1046  Vector& sensor_response_aa,
1047  Vector& sensor_response_za_grid,
1048  Vector& sensor_response_aa_grid,
1049  // WS Input:
1050  const Vector& sensor_response_f_grid,
1051  const ArrayOfIndex& sensor_response_pol_grid,
1052  const Numeric& w1,
1053  const Numeric& w2,
1054  const Verbosity& verbosity)
1055 {
1056  CREATE_OUT3
1057 
1058  if( sensor_response_za_grid.nelem() != 2 )
1059  throw runtime_error(
1060  "This method requires that the number of observation directions is 2." );
1061 
1062  if( sensor_response_pol_grid.nelem() != 1 )
1063  throw runtime_error(
1064  "This method handles (so far) only single polarisation cases." );
1065 
1066  const Index n = sensor_response_f_grid.nelem();
1067 
1068  // Form H matrix representing beam switching
1069  Sparse Hbswitch( n, 2*n );
1070  Vector hrow( 2*n, 0.0 );
1071  //
1072  for( Index i=0; i<n; i++ )
1073  {
1074  hrow[i] = w1;
1075  hrow[i+n] = w2;
1076  //
1077  Hbswitch.insert_row( i, hrow );
1078  //
1079  hrow = 0;
1080  }
1081 
1082  // Here we need a temporary sparse that is copy of the sensor_response
1083  // sparse matrix. We need it since the multiplication function can not
1084  // take the same object as both input and output.
1085  Sparse Htmp = sensor_response;
1086  sensor_response.resize( Hbswitch.nrows(), Htmp.ncols() );
1087  mult( sensor_response, Hbswitch, Htmp );
1088 
1089  // Some extra output.
1090  out3 << " Size of *sensor_response*: " << sensor_response.nrows()
1091  << "x" << sensor_response.ncols() << "\n";
1092 
1093  // Update sensor_response_za_grid
1094  const Numeric za = sensor_response_za_grid[1];
1095  sensor_response_za_grid.resize(1);
1096  sensor_response_za_grid[0] = za;
1097 
1098  // Update sensor_response_aa_grid
1099  if( sensor_response_aa_grid.nelem() > 0 )
1100  {
1101  const Numeric aa = sensor_response_aa_grid[1];
1102  sensor_response_aa_grid.resize(1);
1103  sensor_response_aa_grid[0] = aa;
1104  }
1105 
1106  // Set aux variables
1107  sensor_aux_vectors( sensor_response_f, sensor_response_pol,
1108  sensor_response_za, sensor_response_aa,
1109  sensor_response_f_grid, sensor_response_pol_grid,
1110  sensor_response_za_grid, sensor_response_aa_grid, 0 );
1111 }
1112 
1113 
1114 
1115 /* Workspace method: Doxygen documentation will be auto-generated */
1117  Sparse& sensor_response,
1118  Vector& sensor_response_f,
1119  ArrayOfIndex& sensor_response_pol,
1120  Vector& sensor_response_za,
1121  Vector& sensor_response_aa,
1122  Vector& sensor_response_f_grid,
1123  // WS Input:
1124  const ArrayOfIndex& sensor_response_pol_grid,
1125  const Vector& sensor_response_za_grid,
1126  const Vector& sensor_response_aa_grid,
1127  const Verbosity& verbosity)
1128 {
1129  CREATE_OUT3
1130 
1131  if( sensor_response_za_grid.nelem() != 1 )
1132  throw runtime_error(
1133  "This method requires that the number of observation directions is 1." );
1134 
1135  if( sensor_response_pol_grid.nelem() != 1 )
1136  throw runtime_error(
1137  "This method handles (so far) only single polarisation cases." );
1138 
1139  const Index n = sensor_response_f_grid.nelem();
1140  const Index n2 = n/2;
1141 
1142  if( sensor_response.nrows() != n )
1143  throw runtime_error( "Assumptions of method are not fulfilled, "
1144  "considering number of rows in *sensor_response* "
1145  "and length of *sensor_response_f_grid*." );
1146 
1147  if( !is_multiple(n,2) )
1148  throw runtime_error( "There is an odd number of total frequencies, "
1149  "which is not consistent with the assumptions of "
1150  "the method." );
1151 
1152 
1153  // Form H matrix representing frequency switching
1154  Sparse Hbswitch( n2, n );
1155  Vector hrow( n, 0.0 );
1156  //
1157  for( Index i=0; i<n2; i++ )
1158  {
1159  hrow[i] = -1;
1160  hrow[i+n2] = 1;
1161  //
1162  Hbswitch.insert_row( i, hrow );
1163  //
1164  hrow = 0;
1165  }
1166 
1167  // Here we need a temporary sparse that is copy of the sensor_response
1168  // sparse matrix. We need it since the multiplication function can not
1169  // take the same object as both input and output.
1170  Sparse Htmp = sensor_response;
1171  sensor_response.resize( Hbswitch.nrows(), Htmp.ncols() );
1172  mult( sensor_response, Hbswitch, Htmp );
1173 
1174  // Some extra output.
1175  out3 << " Size of *sensor_response*: " << sensor_response.nrows()
1176  << "x" << sensor_response.ncols() << "\n";
1177 
1178  // Update sensor_response_f_grid
1179  const Vector f = sensor_response_f_grid;
1180  sensor_response_f_grid.resize(n2);
1181  sensor_response_f_grid = f[Range(n2,n2)];
1182 
1183  // Set aux variables
1184  sensor_aux_vectors( sensor_response_f, sensor_response_pol,
1185  sensor_response_za, sensor_response_aa,
1186  sensor_response_f_grid, sensor_response_pol_grid,
1187  sensor_response_za_grid, sensor_response_aa_grid, 0 );
1188 }
1189 
1190 
1191 
1192 /* Workspace method: Doxygen documentation will be auto-generated */
1193 void sensor_responseIF2RF(// WS Output:
1194  Vector& sensor_response_f,
1195  Vector& sensor_response_f_grid,
1196  // WS Input:
1197  const Numeric& lo,
1198  const String& sideband_mode,
1199  const Verbosity&)
1200 {
1201  // Check that frequencies are not too high. This might be a floating limit.
1202  // For this we use the variable f_lim, given in Hz.
1203  Numeric f_lim = 30e9;
1204  if( max(sensor_response_f_grid) > f_lim )
1205  throw runtime_error( "The frequencies seem to already be given in RF." );
1206 
1207 
1208  // Lower band
1209  if( sideband_mode == "lower" )
1210  {
1211  sensor_response_f *= -1;
1212  sensor_response_f_grid *= -1;
1213  sensor_response_f += lo;
1214  sensor_response_f_grid += lo;
1215  }
1216 
1217  // Upper band
1218  else if( sideband_mode=="upper" )
1219  {
1220  sensor_response_f += lo;
1221  sensor_response_f_grid += lo;
1222  }
1223 
1224  // Unknown option
1225  else
1226  {
1227  throw runtime_error(
1228  "Only allowed options for *sideband _mode* are \"lower\" and \"upper\"." );
1229  }
1230 }
1231 
1232 
1233 
1234 /* Workspace method: Doxygen documentation will be auto-generated */
1236  Sparse& sensor_response,
1237  Vector& sensor_response_f,
1238  ArrayOfIndex& sensor_response_pol,
1239  Vector& sensor_response_za,
1240  Vector& sensor_response_aa,
1241  const Index& imblock,
1242  const ArrayOfSparse& sensor_response_array,
1243  const ArrayOfVector& sensor_response_f_array,
1244  const ArrayOfArrayOfIndex& sensor_response_pol_array,
1245  const ArrayOfVector& sensor_response_za_array,
1246  const ArrayOfVector& sensor_response_aa_array,
1247  const ArrayOfIndex& sensor_response_index,
1248  const Verbosity& )
1249 {
1250  // Checks
1251  //
1252  const Index na = sensor_response_array.nelem();
1253  //
1254  if( sensor_response_f_array.nelem() != na ||
1255  sensor_response_pol_array.nelem() != na ||
1256  sensor_response_za_array.nelem() != na ||
1257  sensor_response_aa_array.nelem() != na )
1258  {
1259  throw runtime_error( "All arrays (sensor_response_X_array) must have "
1260  "the same length." );
1261  }
1262  if( imblock >= sensor_response_index.nelem() )
1263  {
1264  throw runtime_error( "The given *imblock* is too high with respect "
1265  "to the length of *sensor_response_index*." );
1266  }
1267 
1268  // Determine index
1269  const Index i = sensor_response_index[imblock];
1270 
1271  if( i >= na )
1272  {
1273  throw runtime_error( "The index extracted from *sensor_response_index* "
1274  "is too high with respect to the length of "
1275  "*sensor_response_array*." );
1276  }
1277 
1278  // Extract data
1279  sensor_response = sensor_response_array[i];
1280  sensor_response_f = sensor_response_f_array[i];
1281  sensor_response_pol = sensor_response_pol_array[i];
1282  sensor_response_za = sensor_response_za_array[i];
1283  sensor_response_aa = sensor_response_aa_array[i];
1284 }
1285 
1286 
1287 
1288 /* Workspace method: Doxygen documentation will be auto-generated */
1289 void sensor_responseFillFgrid(// WS Output:
1290  Sparse& sensor_response,
1291  Vector& sensor_response_f,
1292  ArrayOfIndex& sensor_response_pol,
1293  Vector& sensor_response_za,
1294  Vector& sensor_response_aa,
1295  Vector& sensor_response_f_grid,
1296  // WS Input:
1297  const ArrayOfIndex& sensor_response_pol_grid,
1298  const Vector& sensor_response_za_grid,
1299  const Vector& sensor_response_aa_grid,
1300  const Index& polyorder,
1301  const Index& nfill,
1302  const Verbosity& verbosity)
1303 {
1304  CREATE_OUT3
1305 
1306  // Some sizes
1307  const Index nf = sensor_response_f_grid.nelem();
1308  const Index npol = sensor_response_pol_grid.nelem();
1309  const Index nza = sensor_response_za_grid.nelem();
1310  const Index naa = max( Index(1), sensor_response_aa_grid.nelem() );
1311  const Index nin = nf * npol * nza * naa;
1312 
1313  // Initialise a output stream for runtime errors and a flag for errors
1314  ostringstream os;
1315  bool error_found = false;
1316 
1317  // Check that sensor_response variables are consistent in size
1318  if( sensor_response_f.nelem() != nin )
1319  {
1320  os << "Inconsistency in size between *sensor_response_f* and the sensor\n"
1321  << "grid variables (sensor_response_f_grid etc.).\n";
1322  error_found = true;
1323  }
1324  if( sensor_response.nrows() != nin )
1325  {
1326  os << "The sensor block response matrix *sensor_response* does not have\n"
1327  << "right size compared to the sensor grid variables\n"
1328  << "(sensor_response_f_grid etc.).\n";
1329  error_found = true;
1330  }
1331 
1332  // Check polyorder and nfill
1333  if( polyorder < 2 || polyorder > 7 )
1334  {
1335  os << "Accepted range for *polyorder* is [3,7].\n";
1336  error_found = true;
1337  }
1338  if( nfill < 1 )
1339  {
1340  os << "The argument *nfill* must be > 1.\n";
1341  error_found = true;
1342  }
1343 
1344  // If errors where found throw runtime_error with the collected error
1345  // message.
1346  if (error_found)
1347  throw runtime_error(os.str());
1348 
1349 
1350  // New frequency grid
1351  //
1352  const Index n1 = nfill+1;
1353  const Index n2 = nfill+2;
1354  const Index nnew = (nf-1)*n1 + 1;
1355  //
1356  Vector fnew( nnew );
1357  //
1358  for( Index i=0; i<nf-1; i++ )
1359  {
1360  Vector fp(n2);
1361  nlinspace( fp, sensor_response_f_grid[i], sensor_response_f_grid[i+1], n2 );
1362  fnew[Range(i*n1,n2)] = fp;
1363  }
1364 
1365  // Find interpolation weights
1366  //
1367  ArrayOfGridPosPoly gp( nnew );
1368  Matrix itw( nnew, polyorder+1 );
1369  //
1370  gridpos_poly( gp, sensor_response_f_grid, fnew, polyorder );
1371  interpweights( itw, gp );
1372 
1373  // Set up H for this part
1374  //
1375  Sparse hpoly( nnew * npol * nza * naa, nin );
1376  Vector hrow( nin, 0.0 );
1377  Index row = 0;
1378  //
1379  for( Index iza=0; iza<nza; iza++ )
1380  {
1381  for( Index iaa=0; iaa<naa; iaa++ )
1382  {
1383  for( Index iv=0; iv<nnew; iv++ )
1384  {
1385  for( Index ip=0; ip<npol; ip++ )
1386  {
1387  const Index col0 = (iza*naa+iaa)*nf*npol;
1388  for( Index i=0; i<gp[iv].idx.nelem(); i++ )
1389  {
1390  const Numeric w = gp[iv].w[i];
1391  if( abs(w) > 1e-5 )
1392  {
1393  hrow[col0+gp[iv].idx[i]*npol+ip] = w;
1394  }
1395  }
1396  hpoly.insert_row( row, hrow );
1397  for( Index i=0; i<gp[iv].idx.nelem(); i++ )
1398  { hrow[col0+gp[iv].idx[i]*npol+ip] = 0; }
1399  row += 1;
1400  }
1401  }
1402  }
1403  }
1404 
1405  // Here we need a temporary sparse that is copy of the sensor_response
1406  // sparse matrix. We need it since the multiplication function can not
1407  // take the same object as both input and output.
1408  Sparse htmp = sensor_response;
1409  sensor_response.resize( hpoly.nrows(), htmp.ncols());
1410  mult( sensor_response, hpoly, htmp );
1411 
1412  // Some extra output.
1413  out3 << " Size of *sensor_response*: " << sensor_response.nrows()
1414  << "x" << sensor_response.ncols() << "\n";
1415 
1416  // Update sensor_response_za_grid
1417  sensor_response_f_grid = fnew;
1418 
1419  // Set aux variables
1420  sensor_aux_vectors( sensor_response_f, sensor_response_pol,
1421  sensor_response_za, sensor_response_aa,
1422  sensor_response_f_grid, sensor_response_pol_grid,
1423  sensor_response_za_grid, sensor_response_aa_grid, 1 );
1424 }
1425 
1426 
1427 
1428 /* Workspace method: Doxygen documentation will be auto-generated */
1429 void sensor_responseInit(// WS Output:
1430  Sparse& sensor_response,
1431  Vector& sensor_response_f,
1432  ArrayOfIndex& sensor_response_pol,
1433  Vector& sensor_response_za,
1434  Vector& sensor_response_aa,
1435  Vector& sensor_response_f_grid,
1436  ArrayOfIndex& sensor_response_pol_grid,
1437  Vector& sensor_response_za_grid,
1438  Vector& sensor_response_aa_grid,
1439  // WS Input:
1440  const Vector& f_grid,
1441  const Vector& mblock_za_grid,
1442  const Vector& mblock_aa_grid,
1443  const Index& antenna_dim,
1444  const Index& atmosphere_dim,
1445  const Index& stokes_dim,
1446  const Index& sensor_norm,
1447  const Verbosity& verbosity)
1448 {
1449  CREATE_OUT2
1450  CREATE_OUT3
1451 
1452  // Check input
1453 
1454  // Basic variables
1455  chk_if_in_range( "stokes_dim", stokes_dim, 1, 4 );
1456  chk_if_in_range( "antenna_dim", antenna_dim, 1, 2 );
1457  chk_if_bool( "sensor_norm", sensor_norm );
1458 
1459  // f_grid (could in fact be decreasing, but an increasing grid is
1460  // demanded in other parts).
1461  chk_if_increasing( "f_grid", f_grid );
1462 
1463  // mblock_za_grid
1464  if( mblock_za_grid.nelem() == 0 )
1465  throw runtime_error( "The measurement block zenith angle grid is empty." );
1466  if( !is_increasing(mblock_za_grid) && !is_decreasing(mblock_za_grid) )
1467  throw runtime_error(
1468  "The WSV *mblock_za_grid* must be strictly increasing or decreasing." );
1469 
1470  // mblock_aa_grid
1471  if( antenna_dim == 1 )
1472  {
1473  if( mblock_aa_grid.nelem() != 0 )
1474  throw runtime_error(
1475  "For antenna_dim = 1, the azimuthal angle grid must be empty." );
1476  }
1477  else
1478  {
1479  if( atmosphere_dim < 3 )
1480  throw runtime_error( "2D antennas (antenna_dim=2) can only be "
1481  "used with 3D atmospheres." );
1482  if( mblock_aa_grid.nelem() == 0 )
1483  {
1484  ostringstream os;
1485  os << "The measurement block azimuthal angle grid is empty despite"
1486  << "a 2D antenna pattern is flagged (*antenna_dim*).";
1487  throw runtime_error( os.str() );
1488  }
1489  if( !is_increasing(mblock_aa_grid) && !is_decreasing(mblock_aa_grid) )
1490  throw runtime_error(
1491  "The WSV *mblock_aa_grid* must be strictly increasing or decreasing." );
1492  }
1493 
1494 
1495  // Set grid variables
1496  sensor_response_f_grid = f_grid;
1497  sensor_response_za_grid = mblock_za_grid;
1498  sensor_response_aa_grid = mblock_aa_grid;
1499  //
1500  sensor_response_pol_grid.resize(stokes_dim);
1501  //
1502  for( Index is=0; is<stokes_dim; is++ )
1503  {
1504  sensor_response_pol_grid[is] = is + 1;
1505  }
1506 
1507 
1508  // Set aux variables
1509  sensor_aux_vectors( sensor_response_f, sensor_response_pol,
1510  sensor_response_za, sensor_response_aa,
1511  sensor_response_f_grid, sensor_response_pol_grid,
1512  sensor_response_za_grid, sensor_response_aa_grid, 1 );
1513 
1514  //Set response matrix to identity matrix
1515  //
1516  const Index n = sensor_response_f.nelem();
1517  //
1518  out2 << " Initialising *sensor_reponse* as a identity matrix.\n";
1519  out3 << " Size of *sensor_response*: " << n << "x" << n << "\n";
1520  //
1521  sensor_response.make_I( n, n );
1522 }
1523 
1524 
1525 /* Workspace method: Doxygen documentation will be auto-generated */
1526 void sensorOff(// WS Output:
1527  Sparse& sensor_response,
1528  Vector& sensor_response_f,
1529  ArrayOfIndex& sensor_response_pol,
1530  Vector& sensor_response_za,
1531  Vector& sensor_response_aa,
1532  Vector& sensor_response_f_grid,
1533  ArrayOfIndex& sensor_response_pol_grid,
1534  Vector& sensor_response_za_grid,
1535  Vector& sensor_response_aa_grid,
1536  Index& antenna_dim,
1537  Vector& mblock_za_grid,
1538  Vector& mblock_aa_grid,
1539  const Index& atmosphere_dim,
1540  const Index& stokes_dim,
1541  const Vector& f_grid,
1542  const Verbosity& verbosity)
1543 {
1544  // Checks are done in sensor_responseInit.
1545 
1546  AntennaOff( antenna_dim, mblock_za_grid, mblock_aa_grid, verbosity );
1547 
1548  // Dummy variables
1549  Index sensor_norm = 1;
1550 
1551  sensor_responseInit( sensor_response, sensor_response_f,
1552  sensor_response_pol, sensor_response_za, sensor_response_aa,
1553  sensor_response_f_grid, sensor_response_pol_grid,
1554  sensor_response_za_grid, sensor_response_aa_grid, f_grid,
1555  mblock_za_grid, mblock_aa_grid, antenna_dim, atmosphere_dim,
1556  stokes_dim, sensor_norm, verbosity );
1557 }
1558 
1559 
1560 
1561 /* Workspace method: Doxygen documentation will be auto-generated */
1562 void sensor_responseMixer(// WS Output:
1563  Sparse& sensor_response,
1564  Vector& sensor_response_f,
1565  ArrayOfIndex& sensor_response_pol,
1566  Vector& sensor_response_za,
1567  Vector& sensor_response_aa,
1568  Vector& sensor_response_f_grid,
1569  // WS Input:
1570  const ArrayOfIndex& sensor_response_pol_grid,
1571  const Vector& sensor_response_za_grid,
1572  const Vector& sensor_response_aa_grid,
1573  const Numeric& lo,
1574  const GriddedField1& sideband_response,
1575  const Index& sensor_norm,
1576  const Verbosity& verbosity)
1577 {
1578  CREATE_OUT3
1579 
1580  // Some sizes
1581  const Index nf = sensor_response_f_grid.nelem();
1582  const Index npol = sensor_response_pol_grid.nelem();
1583  const Index nza = sensor_response_za_grid.nelem();
1584  const Index naa = sensor_response_aa_grid.nelem();
1585  const Index nin = nf * npol * nza;
1586  // Note that there is no distinction between za and aa grids after the antenna
1587 
1588  // Frequency grid of for sideband response specification
1589  ConstVectorView sbresponse_f_grid =
1590  sideband_response.get_numeric_grid(GFIELD1_F_GRID);
1591 
1592  // Initialise a output stream for runtime errors and a flag for errors
1593  ostringstream os;
1594  bool error_found = false;
1595 
1596  // Check that sensor_response variables are consistent in size
1597  if( sensor_response_f.nelem() != nin )
1598  {
1599  os << "Inconsistency in size between *sensor_response_f* and the sensor\n"
1600  << "grid variables (sensor_response_f_grid etc.).\n";
1601  error_found = true;
1602  }
1603  if( naa && naa != nza )
1604  {
1605  os << "Incorrect size of *sensor_response_aa_grid*.\n";
1606  error_found = true;
1607  }
1608  if( sensor_response.nrows() != nin )
1609  {
1610  os << "The sensor block response matrix *sensor_response* does not have\n"
1611  << "right size compared to the sensor grid variables\n"
1612  << "(sensor_response_f_grid etc.).\n";
1613  error_found = true;
1614  }
1615 
1616  // Check that the lo frequency is within the sensor_response_f_grid
1617  if( lo <= sensor_response_f_grid[0] || lo >= last(sensor_response_f_grid) )
1618  {
1619  os << "The given local oscillator frequency is outside the sensor\n"
1620  << "frequency grid. It must be within the *sensor_response_f_grid*.\n";
1621  error_found = true;
1622  }
1623 
1624  // Checks of sideband_response, partly in combination with lo
1625  if( sbresponse_f_grid.nelem() != sideband_response.data.nelem() )
1626  {
1627  os << "Mismatch in size of grid and data in *sideband_response*.\n";
1628  error_found = true;
1629  }
1630  if( sbresponse_f_grid.nelem() < 2 )
1631  {
1632  os << "At least two data points must be specified in "
1633  << "*sideband_response*.\n";
1634  error_found = true;
1635  }
1636  if( !is_increasing( sbresponse_f_grid ) )
1637  {
1638  os << "The frequency grid of *sideband_response* must be strictly\n"
1639  << "increasing.\n";
1640  error_found = true;
1641  }
1642  if( fabs(last(sbresponse_f_grid)+sbresponse_f_grid[0]) > 1e3 )
1643  {
1644  os << "The end points of the *sideband_response* frequency grid must be\n"
1645  << "symmetrically placed around 0. That is, the grid shall cover a\n"
1646  << "a range that can be written as [-df,df]. \n";
1647  error_found = true;
1648  }
1649 
1650  // Check that response function does not extend outside sensor_response_f_grid
1651  Numeric df_high = lo + last(sbresponse_f_grid) - last(sensor_response_f_grid);
1652  Numeric df_low = sensor_response_f_grid[0] - lo - sbresponse_f_grid[0];
1653  if( df_high > 0 && df_low > 0 )
1654  {
1655  os << "The *sensor_response_f* grid must be extended by at least\n"
1656  << df_low << " Hz in the lower end and " << df_high << " Hz in the\n"
1657  << "upper end to cover frequency range set by *sideband_response*\n"
1658  << "and *lo*. Or can the frequency grid of *sideband_response* be\n"
1659  << "decreased?";
1660  error_found = true;
1661  }
1662  else if( df_high > 0 )
1663  {
1664  os << "The *sensor_response_f* grid must be extended by at " << df_high
1665  << " Hz\nin the upper end to cover frequency range set by\n"
1666  << "*sideband_response* and *lo*. Or can the frequency grid of\n"
1667  << "*sideband_response* be decreased?";
1668  error_found = true;
1669  }
1670  else if( df_low > 0 )
1671  {
1672  os << "The *sensor_response_f* grid must be extended by at " << df_low
1673  << " Hz\nin the lower end to cover frequency range set by\n"
1674  << "*sideband_response* and *lo*. Or can the frequency grid of\n"
1675  << "*sideband_response* be decreased?";
1676  error_found = true;
1677  }
1678 
1679  // If errors where found throw runtime_error with the collected error
1680  // message.
1681  if (error_found)
1682  throw runtime_error(os.str());
1683 
1684 
1685  //Call the core function
1686  //
1687  Sparse hmixer;
1688  Vector f_mixer;
1689  //
1690  mixer_matrix( hmixer, f_mixer, lo, sideband_response,
1691  sensor_response_f_grid, npol, nza, sensor_norm );
1692 
1693  // Here we need a temporary sparse that is copy of the sensor_response
1694  // sparse matrix. We need it since the multiplication function can not
1695  // take the same object as both input and output.
1696  Sparse htmp = sensor_response;
1697  sensor_response.resize( hmixer.nrows(), htmp.ncols() );
1698  mult( sensor_response, hmixer, htmp );
1699 
1700  // Some extra output.
1701  out3 << " Size of *sensor_response*: " << sensor_response.nrows()
1702  << "x" << sensor_response.ncols() << "\n";
1703 
1704  // Update sensor_response_f_grid
1705  sensor_response_f_grid = f_mixer;
1706 
1707  // Set aux variables
1708  sensor_aux_vectors( sensor_response_f, sensor_response_pol,
1709  sensor_response_za, sensor_response_aa,
1710  sensor_response_f_grid, sensor_response_pol_grid,
1711  sensor_response_za_grid, sensor_response_aa_grid, 0 );
1712 }
1713 
1714 
1715 
1717  Sparse& sensor_response,
1718  Vector& sensor_response_f,
1719  ArrayOfIndex& sensor_response_pol,
1720  Vector& sensor_response_za,
1721  Vector& sensor_response_aa,
1722  Vector& sensor_response_f_grid,
1723  // WS Input:
1724  const ArrayOfIndex& sensor_response_pol_grid,
1725  const Vector& sensor_response_za_grid,
1726  const Vector& sensor_response_aa_grid,
1727  const Vector& lo_multi,
1728  const ArrayOfGriddedField1& sideband_response_multi,
1729  const ArrayOfString& sideband_mode_multi,
1730  const ArrayOfVector& f_backend_multi,
1731  const ArrayOfArrayOfGriddedField1& backend_channel_response_multi,
1732  const Index& sensor_norm,
1733  const Verbosity& verbosity)
1734 {
1735  // Some sizes
1736  const Index nf = sensor_response_f_grid.nelem();
1737  const Index npol = sensor_response_pol_grid.nelem();
1738  const Index nza = sensor_response_za_grid.nelem();
1739  const Index naa = sensor_response_aa_grid.nelem();
1740  const Index nin = nf * npol * nza;
1741  // Note that there is no distinction between za and aa grids after the antenna
1742  const Index nlo = lo_multi.nelem();
1743 
1744  // Initialise a output stream for runtime errors and a flag for errors
1745  ostringstream os;
1746  bool error_found = false;
1747 
1748  // Check that sensor_response variables are consistent in size
1749  if( sensor_response_f.nelem() != nin )
1750  {
1751  os << "Inconsistency in size between *sensor_response_f* and the sensor\n"
1752  << "grid variables (sensor_response_f_grid etc.).\n";
1753  error_found = true;
1754  }
1755  if( naa && naa != nza )
1756  {
1757  os << "Incorrect size of *sensor_response_aa_grid*.\n";
1758  error_found = true;
1759  }
1760  if( sensor_response.nrows() != nin )
1761  {
1762  os << "The sensor block response matrix *sensor_response* does not have\n"
1763  << "right size compared to the sensor grid variables\n"
1764  << "(sensor_response_f_grid etc.).\n";
1765  error_found = true;
1766  }
1767 
1768  // Check that response data are consistent with respect to number of
1769  // mixer/reciever chains.
1770  if( sideband_response_multi.nelem() != nlo )
1771  {
1772  os << "Inconsistency in length between *lo_mixer* and "
1773  << "*sideband_response_multi*.\n";
1774  error_found = true;
1775  }
1776  if( sideband_mode_multi.nelem() != nlo )
1777  {
1778  os << "Inconsistency in length between *lo_mixer* and "
1779  << "*sideband_mode_multi*.\n";
1780  error_found = true;
1781  }
1782  if( f_backend_multi.nelem() != nlo )
1783  {
1784  os << "Inconsistency in length between *lo_mixer* and "
1785  << "*f_backend_multi*.\n";
1786  error_found = true;
1787  }
1788  if( backend_channel_response_multi.nelem() != nlo )
1789  {
1790  os << "Inconsistency in length between *lo_mixer* and "
1791  << "*backend_channel_response_multi*.\n";
1792  error_found = true;
1793  }
1794 
1795  // If errors where found throw runtime_error with the collected error
1796  // message. Data for each mixer and reciever chain are checked below.
1797  if (error_found)
1798  throw runtime_error(os.str());
1799 
1800 
1801  // Variables for data to be appended
1802  Array<Sparse> sr;
1803  ArrayOfVector srfgrid;
1804  ArrayOfIndex cumsumf(nlo+1,0);
1805 
1806  for( Index ilo=0; ilo<nlo; ilo++ )
1807  {
1808  // Copies of variables that will be changed, but must be
1809  // restored for next loop
1810  Sparse sr1 = sensor_response;
1811  Vector srf1 = sensor_response_f;
1812  ArrayOfIndex srpol1 = sensor_response_pol;
1813  Vector srza1 = sensor_response_za;
1814  Vector sraa1 = sensor_response_aa;
1815  Vector srfgrid1 = sensor_response_f_grid;
1816 
1817  // Call single reciever methods. Try/catch for improved error message.
1818  try
1819  {
1820  sensor_responseMixer(sr1, srf1, srpol1, srza1, sraa1, srfgrid1,
1821  sensor_response_pol_grid,
1822  sensor_response_za_grid,
1823  sensor_response_aa_grid,
1824  lo_multi[ilo],
1825  sideband_response_multi[ilo],
1826  sensor_norm,
1827  verbosity);
1828 
1829  sensor_responseIF2RF(srf1, srfgrid1,
1830  lo_multi[ilo],
1831  sideband_mode_multi[ilo],
1832  verbosity);
1833 
1834  sensor_responseBackend(sr1, srf1, srpol1, srza1, sraa1, srfgrid1,
1835  sensor_response_pol_grid,
1836  sensor_response_za_grid,
1837  sensor_response_aa_grid,
1838  f_backend_multi[ilo],
1839  backend_channel_response_multi[ilo],
1840  sensor_norm, verbosity);
1841  }
1842  catch( runtime_error e )
1843  {
1844  ostringstream os2;
1845  os2 << "Error when dealing with receiver/mixer chain (1-based index) "
1846  << ilo+1 << ":\n" << e.what();
1847  throw runtime_error(os2.str());
1848  }
1849 
1850  // Store in temporary arrays
1851  sr.push_back( sr1 );
1852  srfgrid.push_back( srfgrid1 );
1853  //
1854  cumsumf[ilo+1] = cumsumf[ilo] + srfgrid1.nelem();
1855  }
1856 
1857  // Append data to create sensor_response_f_grid
1858  //
1859  const Index nfnew = cumsumf[nlo];
1860  sensor_response_f_grid.resize( nfnew );
1861  //
1862  for( Index ilo=0; ilo<nlo; ilo++ )
1863  {
1864  for( Index i=0; i<srfgrid[ilo].nelem(); i++ )
1865  {
1866  sensor_response_f_grid[cumsumf[ilo]+i] = srfgrid[ilo][i];
1867  }
1868  }
1869 
1870  // Append data to create total sensor_response
1871  //
1872  const Index ncols = sr[0].ncols();
1873  const Index npolnew = sensor_response_pol_grid.nelem();
1874  const Index nfpolnew = nfnew * npolnew;
1875  //
1876  sensor_response.resize( nza*nfpolnew, ncols );
1877  //
1878  Vector dummy( ncols, 0.0 );
1879  //
1880  for( Index ilo=0; ilo<nlo; ilo++ )
1881  {
1882  const Index nfpolthis = (cumsumf[ilo+1]-cumsumf[ilo]) * npolnew;
1883 
1884  assert( sr[ilo].nrows() == nza*nfpolthis );
1885  assert( sr[ilo].ncols() == ncols );
1886 
1887  for( Index iz=0; iz<nza; iz++ )
1888  {
1889  for( Index i=0; i<nfpolthis; i++ )
1890  {
1891  // "Poor mans" transfer of a row from one sparse to another
1892  for( Index ic=0; ic<ncols; ic++ )
1893  { dummy[ic] = sr[ilo](iz*nfpolthis+i,ic); }
1894 
1895  sensor_response.insert_row( iz*nfpolnew+cumsumf[ilo]*npolnew+i,
1896  dummy );
1897  }
1898  }
1899  }
1900 
1901  // Set aux variables
1902  sensor_aux_vectors( sensor_response_f, sensor_response_pol,
1903  sensor_response_za, sensor_response_aa,
1904  sensor_response_f_grid, sensor_response_pol_grid,
1905  sensor_response_za_grid, sensor_response_aa_grid, 0 );
1906 }
1907 
1908 
1909 
1910 /* Workspace method: Doxygen documentation will be auto-generated */
1912  Sparse& sensor_response,
1913  Vector& sensor_response_f,
1914  ArrayOfIndex& sensor_response_pol,
1915  Vector& sensor_response_za,
1916  Vector& sensor_response_aa,
1917  ArrayOfIndex& sensor_response_pol_grid,
1918  // WS Input:
1919  const Vector& sensor_response_f_grid,
1920  const Vector& sensor_response_za_grid,
1921  const Vector& sensor_response_aa_grid,
1922  const Index& stokes_dim,
1923  const String& y_unit,
1924  const ArrayOfIndex& sensor_pol,
1925  const Verbosity&)
1926 {
1927  // Vectors for extracting polarisation components
1928  //
1929  ArrayOfVector pv(10);
1930  //
1931  Numeric w = 0.5;
1932  if( y_unit == "PlanckBT" || y_unit == "RJBT" )
1933  { w = 1.0; }
1934  //
1935  pv[0] = MakeVector( 1 ); // I
1936  pv[1] = MakeVector( 0, 1 ); // Q
1937  pv[2] = MakeVector( 0, 0, 1 ); // U
1938  pv[3] = MakeVector( 0, 0, 0, 1 ); // V
1939  pv[4] = MakeVector( w, w ); // Iv
1940  pv[5] = MakeVector( w, -w ); // Ih
1941  pv[6] = MakeVector( w, 0, w ); // I+45
1942  pv[7] = MakeVector( w, 0, -w ); // I-45
1943  pv[8] = MakeVector( w, 0, 0, w ); // Irhc
1944  pv[9] = MakeVector( w, 0, 0, -w ); // Ilhc
1945 
1946  // Some sizes
1947  const Index nnew = sensor_pol.nelem();
1948  const Index nf = sensor_response_f_grid.nelem();
1949  const Index npol = sensor_response_pol_grid.nelem();
1950  const Index nza = sensor_response_za_grid.nelem();
1951 
1952  // Initialise an output stream for runtime errors and a flag for errors
1953  ostringstream os;
1954  bool error_found = false;
1955 
1956  // For this method, the za and aa can be both "independent" and "dependent".
1957  // The size of sensor_response resolves this
1958  //
1959  bool za_aa_independent = true;
1960  //
1961  const Index naa = max( Index(1), sensor_response_aa_grid.nelem() );
1962  Index nfz = nf * nza;
1963  Index nin = nfz *npol;
1964  //
1965  if( sensor_response.nrows() == nin )
1966  { za_aa_independent = false; }
1967  else if( sensor_response.nrows() == nin*naa )
1968  { nfz *= naa; nin *= naa; }
1969  else
1970  {
1971  os << "The sensor block response matrix *sensor_response* does not have\n"
1972  << "right size compared to the sensor grid variables\n"
1973  << "(sensor_response_f_grid etc.).\n";
1974  error_found = true;
1975  }
1976 
1977  // Check that sensor_response variables are consistent in size
1978  if( sensor_response_f.nelem() != nin )
1979  {
1980  os << "Inconsistency in size between *sensor_response_f* and the sensor\n"
1981  << "grid variables (sensor_response_f_grid etc.).\n";
1982  error_found = true;
1983  }
1984  if( naa && naa != nza )
1985  {
1986  os << "Incorrect size of *sensor_response_aa_grid*.\n";
1987  error_found = true;
1988  }
1989  if( npol != stokes_dim )
1990  {
1991  os << "Number of input polarisation does not match *stokes_dim*.\n";
1992  error_found = true;
1993  }
1994  if( nnew == 0 )
1995  {
1996  os << "The WSV *sensor_pol* can not be empty.\n";
1997  error_found = true;
1998  }
1999  // If errors where found throw runtime_error with the collected error
2000  // message (before it gets too long)
2001  if( error_found )
2002  throw runtime_error(os.str());
2003 
2004  // Check polarisation data more in detail
2005  for( Index i=0; i<npol && !error_found; i++ )
2006  {
2007  if( sensor_response_pol_grid[i] != i+1 )
2008  {
2009  os << "The input polarisations must be I, Q, U and V (up to "
2010  << "stokes_dim). It seems that input data are for other "
2011  << "polarisation components.";
2012  error_found = true;
2013  }
2014  }
2015  for( Index i=0; i<nnew && !error_found; i++ )
2016  {
2017  if( sensor_pol[i] < 1 || sensor_pol[i] > 10 )
2018  {
2019  os <<
2020  "The elements of *sensor_pol* must be inside the range [1,10].\n";
2021  error_found = true;
2022  }
2023  }
2024  // If errors where found throw runtime_error with the collected error
2025  // message (before it gets too long)
2026  if( error_found )
2027  throw runtime_error(os.str());
2028 
2029  for( Index i=0; i<nnew && !error_found; i++ )
2030  {
2031  if( pv[sensor_pol[i]-1].nelem() > stokes_dim )
2032  {
2033  os << "You have selected an output polarisation that is not covered "
2034  << "by present value of *stokes_dim* (the later has to be "
2035  << "increased).";
2036  error_found = true;
2037  }
2038  }
2039  // If errors where found throw runtime_error with the collected error
2040  // message
2041  if( error_found )
2042  throw runtime_error(os.str());
2043 
2044  // Form H matrix representing polarisation response
2045  //
2046  Sparse Hpol( nfz*nnew, nin );
2047  Vector hrow( nin, 0.0 );
2048  Index row = 0;
2049  //
2050  for( Index i=0; i<nfz; i++ )
2051  {
2052  Index col = i*npol;
2053  for( Index in=0; in<nnew; in++ )
2054  {
2055  Index p = sensor_pol[in] - 1;
2056  //
2057  for( Index iv=0; iv<pv[p].nelem(); iv++ )
2058  { hrow[col+iv] = pv[p][iv]; }
2059  //
2060  Hpol.insert_row( row, hrow );
2061  //
2062  hrow = 0;
2063  row += 1;
2064  }
2065  }
2066 
2067  // Here we need a temporary sparse that is copy of the sensor_response
2068  // sparse matrix. We need it since the multiplication function can not
2069  // take the same object as both input and output.
2070  Sparse Htmp = sensor_response;
2071  sensor_response.resize( Hpol.nrows(), Htmp.ncols());
2072  mult( sensor_response, Hpol, Htmp );
2073 
2074  // Update sensor_response_pol_grid
2075  sensor_response_pol_grid = sensor_pol;
2076 
2077  // Set aux variables
2078  sensor_aux_vectors( sensor_response_f, sensor_response_pol,
2079  sensor_response_za, sensor_response_aa,
2080  sensor_response_f_grid, sensor_response_pol_grid,
2081  sensor_response_za_grid, sensor_response_aa_grid,
2082  za_aa_independent );
2083 }
2084 
2085 
2086 
2087 void sensor_responseSimpleAMSU(// WS Output:
2088  Vector& f_grid,
2089  Index& antenna_dim,
2090  Vector& mblock_za_grid,
2091  Vector& mblock_aa_grid,
2092  Sparse& sensor_response,
2093  Vector& sensor_response_f,
2094  ArrayOfIndex& sensor_response_pol,
2095  Vector& sensor_response_za,
2096  Vector& sensor_response_aa,
2097  Vector& sensor_response_f_grid,
2098  ArrayOfIndex& sensor_response_pol_grid,
2099  Vector& sensor_response_za_grid,
2100  Vector& sensor_response_aa_grid,
2101  Index& sensor_norm,
2102  // WS Input:
2103  const Index& atmosphere_dim,
2104  const Index& stokes_dim,
2105  const Matrix& sensor_description_amsu,
2106  // WS Generic Input:
2107  const Numeric& spacing,
2108  const Verbosity& verbosity)
2109 {
2110  // Check that sensor_description_amsu has the right dimension:
2111  if ( 3 != sensor_description_amsu.ncols() )
2112  {
2113  ostringstream os;
2114  os << "Input variable sensor_description_amsu must have three columns, but it has "
2115  << sensor_description_amsu.ncols() << ".";
2116  throw runtime_error( os.str() );
2117  }
2118 
2119  // Number of instrument channels:
2120  const Index n = sensor_description_amsu.nrows();
2121 
2122  // The meaning of the columns in sensor_description_amsu is:
2123  // LO frequency, channel center offset from LO, channel width.
2124  // (All in Hz.)
2125  ConstVectorView lo_multi = sensor_description_amsu(Range(joker),0);
2126  ConstVectorView offset = sensor_description_amsu(Range(joker),1);
2127  ConstVectorView width = sensor_description_amsu(Range(joker),2);
2128 
2129  // Channel frequencies:
2130  ArrayOfVector f_backend_multi(n);
2131  for (Index i=0; i<n; ++i) {
2132  Vector& f = f_backend_multi[i];
2133  f.resize(1);
2134  f[0] = lo_multi[i] + offset[i];
2135  }
2136 
2137  // Construct channel response
2138  ArrayOfArrayOfGriddedField1 backend_channel_response_multi(n);
2139  for (Index i=0; i<n; ++i) {
2140  backend_channel_response_multi[i].resize(1);
2141  GriddedField1& r = backend_channel_response_multi[i][0];
2142  r.set_name("Backend channel response function");
2143  r.resize(2);
2144 
2145  // Frequency range:
2146  Vector f(2);
2147  f[0] = - 0.5 * width[i];
2148  f[1] = + 0.5 * width[i];
2149  r.set_grid_name(0, "Frequency");
2150  r.set_grid(0,f);
2151 
2152  // Response:
2153  r.data[0] = 1;
2154  r.data[1] = 1;
2155  }
2156 
2157  // Construct sideband response:
2158  ArrayOfGriddedField1 sideband_response_multi(n);
2159  for (Index i=0; i<n; ++i) {
2160  GriddedField1& r = sideband_response_multi[i];
2161  r.set_name("Sideband response function");
2162  r.resize(2);
2163 
2164  // Frequency range:
2165  Vector f(2);
2166  f[0] = - (offset[i] + 0.5*width[i]);
2167  f[1] = + (offset[i] + 0.5*width[i]);
2168  r.set_grid_name(0, "Frequency");
2169  r.set_grid(0,f);
2170 
2171  // Response:
2172  r.data[0] = 0.5;
2173  r.data[1] = 0.5;
2174  }
2175 
2176  // Set sideband mode:
2177  ArrayOfString sideband_mode_multi(n,"upper");
2178 
2179  // We want to automatically normalize the sensor response data, so set sensor_norm to 1:
2180  sensor_norm = 1;
2181 
2182  // Now the rest is just to use some workspace methods:
2183  // ---------------------------------------------------
2184 
2185  f_gridFromSensorAMSU(f_grid, lo_multi,
2186  f_backend_multi, backend_channel_response_multi,
2187  spacing, verbosity);
2188 
2189  AntennaOff(antenna_dim, mblock_za_grid, mblock_aa_grid, verbosity);
2190 
2191  sensor_responseInit(sensor_response,
2192  sensor_response_f, sensor_response_pol,
2193  sensor_response_za, sensor_response_aa,
2194  sensor_response_f_grid,
2195  sensor_response_pol_grid,
2196  sensor_response_za_grid,
2197  sensor_response_aa_grid, f_grid, mblock_za_grid,
2198  mblock_aa_grid, antenna_dim, atmosphere_dim,
2199  stokes_dim, sensor_norm,
2200  verbosity);
2201 
2202  sensor_responseMultiMixerBackend(sensor_response, sensor_response_f,
2203  sensor_response_pol,
2204  sensor_response_za,
2205  sensor_response_aa,
2206  sensor_response_f_grid,
2207  sensor_response_pol_grid,
2208  sensor_response_za_grid,
2209  sensor_response_aa_grid, lo_multi,
2210  sideband_response_multi,
2211  sideband_mode_multi,
2212  f_backend_multi,
2213  backend_channel_response_multi,
2214  sensor_norm,
2215  verbosity);
2216 
2217 }
2218 
2219 // Declare select functions needed by WMRFSelectChannels:
2220 
2221 void Select(// WS Generic Output:
2222  Vector& needles,
2223  // WS Generic Input:
2224  const Vector& haystack,
2225  const ArrayOfIndex& needleind,
2226  const Verbosity& verbosity);
2227 
2228 template< class T >
2229 void Select(// WS Generic Output:
2230  Array<T>& needles,
2231  // WS Generic Input:
2232  const Array<T>& haystack,
2233  const ArrayOfIndex& needleind,
2234  const Verbosity& verbosity);
2235 
2236 void Select(// WS Generic Output:
2237  Sparse& needles,
2238  // WS Generic Input:
2239  const Sparse& haystack,
2240  const ArrayOfIndex& needleind,
2241  const Verbosity& verbosity);
2242 
2243 /* Workspace method: Doxygen documentation will be auto-generated */
2244 void WMRFSelectChannels(// WS Output:
2245  Vector& f_grid,
2246  Sparse& wmrf_weights,
2247  Vector& f_backend,
2248  // WS Input:
2249  const ArrayOfIndex& wmrf_channels,
2250  const Verbosity& verbosity)
2251 {
2252  CREATE_OUT2
2253  CREATE_OUT3
2254 
2255  // For error messages:
2256  ostringstream os;
2257 
2258  // Some checks of input parameters:
2259 
2260  // wmrf_weights must have same number of rows as f_backend, and same
2261  // number of columns as f_grid.
2262  if ( (wmrf_weights.nrows() != f_backend.nelem()) ||
2263  (wmrf_weights.ncols() != f_grid.nelem()) )
2264  {
2265  os << "The WSV *wmrf_weights* must have same number of rows as\n"
2266  << "*f_backend*, and same number of columns as *f_grid*.\n"
2267  << "wmrf_weights.nrows() = " << wmrf_weights.nrows() << "\n"
2268  << "f_backend.nelem() = " << f_backend.nelem() << "\n"
2269  << "wmrf_weights.ncols() = " << wmrf_weights.ncols() << "\n"
2270  << "f_grid.nelem() = " << f_grid.nelem();
2271  throw runtime_error(os.str());
2272  }
2273 
2274  // wmrf_channels must be strictly increasing (no repetitions).
2275  chk_if_increasing("wmrf_channels", wmrf_channels);
2276 
2277  // All selected channels must be within the original set of
2278  // channels.
2279  if ( min(wmrf_channels)<0 )
2280  {
2281  os << "Min(wmrf_channels) must be >= 0, but it is "
2282  << min(wmrf_channels) << ".";
2283  }
2284  if ( max(wmrf_channels)>=f_backend.nelem() )
2285  {
2286  os << "Max(wmrf_channels) must be less than the total number of channels.\n"
2287  << "(We use zero-based indexing!)\n"
2288  << "The actual value you have is "
2289  << max(wmrf_channels) << ".";
2290  }
2291 
2292  if (wmrf_channels.nelem()==f_backend.nelem())
2293  {
2294  // No channels to be removed, I can return the original grid.
2295  out2 << " Retaining all channels.\n";
2296  }
2297  else
2298  {
2299  out2 << " Reducing number of channels from "
2300  << f_backend.nelem() << " to " << wmrf_channels.nelem() << ".\n";
2301  }
2302 
2303 
2304  // Now the real work starts:
2305 
2306  // 1. Remove unwanted channels from f_backend:
2307  Select(f_backend, f_backend, wmrf_channels, verbosity);
2308 
2309  // 2. Remove unwanted channels from wmrf_weights. (We also have to
2310  // do something about the frequency dimension of wmrf_weights, but
2311  // we'll do that later.)
2312  Select(wmrf_weights, wmrf_weights, wmrf_channels, verbosity);
2313 
2314  // 3. Identify, which frequencies are still needed, and which are
2315  // now obsolete. We store the still needed frequencies in an
2316  // ArrayOfIndex.
2317 
2318  // Create f_grid_array. We do not store the frequencies themselves,
2319  // but the indices of the frequencies to use.
2320  ArrayOfIndex selection;
2321  // Make sure that selection does not have to be reallocated along
2322  // the way. (This is purely to improve performance a bit.)
2323  selection.reserve(f_grid.nelem());
2324 
2325  // Go through f_grid, and check for each frequency whether it is in
2326  // the set of WMRF frequencies for any of the channels.
2327  assert( wmrf_weights.nrows() == f_backend.nelem() );
2328  assert( wmrf_weights.ncols() == f_grid.nelem() );
2329  for (Index fi=0; fi<wmrf_weights.ncols(); ++fi)
2330  {
2331  Index i;
2332  for (i=0; i<wmrf_weights.nrows(); ++i)
2333  {
2334  if ( wmrf_weights(i,fi) != 0 )
2335  {
2336  selection.push_back(fi);
2337  break;
2338  }
2339  }
2340  if (i==wmrf_weights.nrows())
2341  {
2342  out3 << " The frequency with index " << fi
2343  << " is not used by any channel.\n";
2344  }
2345  }
2346 
2347  if (selection.nelem()==f_grid.nelem())
2348  {
2349  // No frequencies were removed, I can return the original grid.
2350  out2 << " No unnecessary frequencies, leaving f_grid untouched.\n";
2351  }
2352  else if (selection.nelem() == 0)
2353  {
2354  throw runtime_error("No frequencies found for any selected channels.\n");
2355  }
2356  else
2357  {
2358  out2 << " Reducing number of frequency grid points from "
2359  << f_grid.nelem() << " to " << selection.nelem() << ".\n";
2360  }
2361 
2362  // 4. Select the right frequencies in f_grid:
2363  Select(f_grid, f_grid, selection, verbosity);
2364 
2365  // 5. Select the right frequencies in wmrf_weights. This is a bit
2366  // tricky, since Select works on the row dimension. So we have to
2367  // take the transpose.
2368  Sparse wt(wmrf_weights.ncols(), wmrf_weights.nrows());
2369  transpose(wt, wmrf_weights);
2370  Select(wt, wt, selection, verbosity);
2371  wmrf_weights.resize(wt.ncols(), wt.nrows());
2372  transpose(wmrf_weights, wt);
2373 }
2374 
2375 
2376 /* Workspace method: Doxygen documentation will be auto-generated */
2377 void sensor_responseWMRF(// WS Output:
2378  Sparse& sensor_response,
2379  Vector& sensor_response_f,
2380  ArrayOfIndex& sensor_response_pol,
2381  Vector& sensor_response_za,
2382  Vector& sensor_response_aa,
2383  Vector& sensor_response_f_grid,
2384  // WS Input:
2385  const ArrayOfIndex& sensor_response_pol_grid,
2386  const Vector& sensor_response_za_grid,
2387  const Vector& sensor_response_aa_grid,
2388  const Sparse& wmrf_weights,
2389  const Vector& f_backend,
2390  const Verbosity& verbosity)
2391 {
2392  CREATE_OUT3
2393 
2394  // Some sizes
2395  const Index nf = sensor_response_f_grid.nelem();
2396  const Index npol = sensor_response_pol_grid.nelem();
2397  const Index nza = sensor_response_za_grid.nelem();
2398  const Index naa = sensor_response_aa_grid.nelem();
2399  const Index nin = nf * npol * nza;
2400  // Note that there is no distinction between za and aa grids after the antenna
2401 
2402  // Initialise output stream for runtime errors and a flag for errors
2403  ostringstream os;
2404  bool error_found = false;
2405 
2406  // Check that sensor_response variables are consistent in size
2407  if( sensor_response_f.nelem() != nin )
2408  {
2409  os << "Inconsistency in size between *sensor_response_f* and the sensor\n"
2410  << "grid variables (sensor_response_f_grid etc.).\n";
2411  error_found = true;
2412  }
2413  if( naa && naa != nza )
2414  {
2415  os << "Incorrect size of *sensor_response_aa_grid*.\n";
2416  error_found = true;
2417  }
2418  if( sensor_response.nrows() != nin )
2419  {
2420  os << "The sensor block response matrix *sensor_response* does not have\n"
2421  << "right size compared to the sensor grid variables\n"
2422  << "(sensor_response_f_grid etc.).\n";
2423  error_found = true;
2424  }
2425 
2426  if (nin == 0)
2427  {
2428  os << "One of f_grid, pol_grid, za_grid are empty. Sizes are: ("
2429  << nf << ", " << npol << ", " << nza << ")" << "\n";
2430  error_found = true;
2431  }
2432  else // Finding the minimum or maximum will result in assertion if empty
2433  {
2434  // We allow f_backend to be unsorted, but must be inside sensor_response_f_grid
2435  if( min(f_backend) < min(sensor_response_f_grid) )
2436  {
2437  os << "At least one value in *f_backend* (" << min(f_backend)
2438  << ") below range\ncovered by *sensor_response_f_grid* ("
2439  << min(sensor_response_f_grid) << ").\n";
2440  error_found = true;
2441  }
2442  if( max(f_backend) > max(sensor_response_f_grid) )
2443  {
2444  os << "At least one value in *f_backend* (" << max(f_backend)
2445  << ") above range\ncovered by *sensor_response_f_grid* ("
2446  << max(sensor_response_f_grid) << ").\n";
2447  error_found = true;
2448  }
2449  }
2450 
2451  // Check number of rows in WMRF weight matrix
2452  //
2453  const Index nrw = wmrf_weights.nrows();
2454  //
2455  if( nrw != f_backend.nelem() )
2456  {
2457  os << "The WSV *wmrf_weights* must have as many rows\n"
2458  << "as *f_backend* has elements.\n"
2459  << "wmrf_weights.nrows() = " << nrw << "\n"
2460  << "f_backend.nelem() = " << f_backend.nelem() << "\n";
2461  error_found = true;
2462  }
2463 
2464  // Check number of columns in WMRF weight matrix
2465  //
2466  const Index ncw = wmrf_weights.ncols();
2467  //
2468  if( ncw != sensor_response_f_grid.nelem() )
2469  {
2470  os << "The WSV *wmrf_weights* must have as many columns\n"
2471  << "as *sensor_response_f_grid* has elements.\n"
2472  << "wmrf_weights.ncols() = " << ncw << "\n"
2473  << "sensor_response_f_grid.nelem() = " << sensor_response_f_grid.nelem() << "\n";
2474  error_found = true;
2475  }
2476 
2477  // If errors where found throw runtime_error with the collected error
2478  // message (before error message gets too long).
2479  if( error_found )
2480  throw runtime_error(os.str());
2481 
2482 
2483  // Ok, now the actual work.
2484 
2485  // Here we need a temporary sparse that is copy of the sensor_response
2486  // sparse matrix. We need it since the multiplication function can not
2487  // take the same object as both input and output.
2488  Sparse htmp = sensor_response;
2489  sensor_response.resize( wmrf_weights.nrows(), htmp.ncols());
2490  mult( sensor_response, wmrf_weights, htmp );
2491 
2492  // Some extra output.
2493  out3 << " Size of *sensor_response*: " << sensor_response.nrows()
2494  << "x" << sensor_response.ncols() << "\n";
2495 
2496  // Update sensor_response_f_grid
2497  sensor_response_f_grid = f_backend;
2498 
2499  // Set aux variables
2500  sensor_aux_vectors( sensor_response_f, sensor_response_pol,
2501  sensor_response_za, sensor_response_aa,
2502  sensor_response_f_grid, sensor_response_pol_grid,
2503  sensor_response_za_grid, sensor_response_aa_grid, 0 );
2504 
2505 }
2506 
2507 
2508 /* Workspace method: Doxygen documentation will be auto-generated */
2510  ArrayOfSparse& sensor_response_array,
2511  ArrayOfVector& sensor_response_f_array,
2512  ArrayOfArrayOfIndex& sensor_response_pol_array,
2513  ArrayOfVector& sensor_response_za_array,
2514  ArrayOfVector& sensor_response_aa_array,
2515  const Sparse& sensor_response,
2516  const Vector& sensor_response_f,
2517  const ArrayOfIndex& sensor_response_pol,
2518  const Vector& sensor_response_za,
2519  const Vector& sensor_response_aa,
2520  const Verbosity& )
2521 {
2522  // The output arrays all have length 1
2523  sensor_response_array.resize(1);
2524  sensor_response_f_array.resize(1);
2525  sensor_response_pol_array.resize(1);
2526  sensor_response_za_array.resize(1);
2527  sensor_response_aa_array.resize(1);
2528 
2529  // Put in the non-array data
2530  sensor_response_array[0] = sensor_response;
2531  sensor_response_f_array[0] = sensor_response_f;
2532  sensor_response_pol_array[0] = sensor_response_pol;
2533  sensor_response_za_array[0] = sensor_response_za;
2534  sensor_response_aa_array[0] = sensor_response_aa;
2535 }
2536 
2537 
2538 
2539 
2540 
2541 
2542 
2543 
2544 
2545 
2546 
2547 
2548 
2549 //--- Stuff to be updated ----------------------------------------------------
2550 
2551 
2552 /* Workspace method: Doxygen documentation will be auto-generated
2553 void sensor_responsePolarisation(// WS Output:
2554  Sparse& sensor_response,
2555  Index& sensor_response_pol,
2556  // WS Input:
2557  const Matrix& sensor_pol,
2558  const Vector& sensor_response_za,
2559  const Vector& sensor_response_aa,
2560  const Vector& sensor_response_f,
2561  const Index& stokes_dim,
2562  const Verbosity& verbosity)
2563 {
2564  CREATE_OUT2
2565  CREATE_OUT3
2566 
2567  Index n_aa;
2568  if( sensor_response_aa.nelem()==0 )
2569  n_aa = 1;
2570  else
2571  n_aa = sensor_response_aa.nelem();
2572  Index n_f_a = sensor_response_f.nelem()*sensor_response_za.nelem()*n_aa;
2573 
2574  // Check that the initial sensor_response has the right size.
2575  if( sensor_response.nrows() != sensor_response_pol*n_f_a ) {
2576  ostringstream os;
2577  os << "The sensor block response matrix *sensor_response* does not have\n"
2578  << "the right size. Check that at least *sensor_responseInit* has been\n"
2579  << "run prior to this method.\n";
2580  throw runtime_error(os.str());
2581  }
2582 
2583  // Check that sensor_pol and stokes_dim are consistent??
2584  if ( sensor_pol.ncols()!=stokes_dim ) {
2585  ostringstream os;
2586  os << "The number of columns in *sensor_pol* does not match *stokes_dim*.";
2587  throw runtime_error(os.str());
2588  }
2589 
2592  // if( sensor_pol.nrows()==sensor_pol.ncols() ) {
2593  // bool is_I = true;
2594  // for( Index it=0; it<stokes_dim; it++ ) {
2595  // for( Index jt=0; jt<stokes_dim; jt++ ) {
2596  // if( it==jt && sensor_pol(it,jt)!=1 )
2597  // is_I = false;
2598  // else if( it!=jt && sensor_pol(it,jt)!=0 )
2599  // is_I = false;
2600  // }
2601  // }
2602  // if( is_I ) {
2603  // ostringstream os;
2604  // os << "The matrix *sensor_pol* is an identity matrix and this method is\n"
2605  // << "therfor unnecessary.";
2606  // throw runtime_error(os.str());
2607  // }
2608  //}
2609 
2612  //bool input_error = false;
2613  //for( Index it=0; it<sensor_pol.nrows(); it++ ) {
2614  // if( sensor_pol(it,1)!=1 )
2615  // input_error = true;
2616  // Numeric row_sum = 0.0;
2617  // for( Index jt=1; jt<sensor_pol.ncols(); jt++ )
2618  // row_sum += pow(sensor_pol(it,jt),2.0);
2619  // if( row_sum!=1.0 )
2620  // input_error = true;
2621  //}
2622  //if( input_error ) {
2623  // ostringstream os;
2624  // os << "The elements in *sensor_pol* are not correct. The first element\n"
2625  // << "has to be 1 and the sum of the squares of the following should\n"
2626  // << "also be 1.";
2627  // throw runtime_error(os.str());
2628  //}
2629 
2630 
2631  // Output to the user.
2632  out2 << " Calculating the polarisation response using *sensor_pol*.\n";
2633 
2634  // Call to calculating function
2635  Sparse pol_response( sensor_pol.nrows()*n_f_a, stokes_dim*n_f_a );
2636  polarisation_matrix( pol_response, sensor_pol,
2637  sensor_response_f.nelem(), sensor_response_za.nelem(), stokes_dim );
2638 
2639  // Multiply with sensor_response
2640  Sparse tmp = sensor_response;
2641  sensor_response.resize( sensor_pol.nrows()*n_f_a, tmp.ncols());
2642  mult( sensor_response, pol_response, tmp);
2643 
2644  // Some extra output.
2645  out3 << " Size of *sensor_response*: " << sensor_response.nrows()
2646  << "x" << sensor_response.ncols() << "\n";
2647 
2648  // Update sensor_response variable
2649  sensor_response_pol = sensor_pol.nrows();
2650 }
2651 */
2652 
2653 
2654 
2655 /* Workspace method: Doxygen documentation will be auto-generated
2656 void sensor_responseRotation(// WS Output:
2657  Sparse& sensor_response,
2658  // WS Input:
2659  const Vector& sensor_rot,
2660  const Matrix& antenna_los,
2661  const Index& antenna_dim,
2662  const Index& stokes_dim,
2663  const Vector& sensor_response_f,
2664  const Vector& sensor_response_za,
2665  const Verbosity& verbosity)
2666 {
2667  CREATE_OUT2
2668  CREATE_OUT3
2669 
2670  // Check that at least 3 stokes components are simulated. This since no 2
2671  // and 3 are weighted together.
2672  if( stokes_dim<3 ) {
2673  ostringstream os;
2674  os << "For a rotating sensor *stokes_dim* has to be at least 3.";
2675  throw runtime_error(os.str());
2676  }
2677 
2678  // Check that the antenna dimension and the columns of antenna_los is ok.
2679  if( antenna_dim!=antenna_los.ncols() ) {
2680  ostringstream os;
2681  os << "The antenna line-of-sight is not defined in consistency with the\n"
2682  << "antenna dimension. The number of columns in *antenna_los* should be\n"
2683  << "equal to *antenna_dim*";
2684  throw runtime_error(os.str());
2685  }
2686 
2687  // Check that the incoming sensor response matrix has the right size. Here
2688  // we use *stokes_dim* instead of *sensor_response_pol* since this function
2689  // should be used on the 'raw' stokes components. Also check that a antenna
2690  // response has been run prior to this method.
2691  // NOTE: Here we test that sensor_response_za has the same length as
2692  // antenna_los number of rows. Because for 1D, 2D and 3D cases the zenith
2693  // angles are allways represented (so far).
2694  Index n = stokes_dim*antenna_los.nrows()*sensor_response_f.nelem();
2695  if( sensor_response.nrows()!=n ||
2696  sensor_response_za.nelem()!=antenna_los.nrows() ) {
2697  ostringstream os;
2698  os << "A sensor_response antenna function has to be run prior to\n"
2699  << "*sensor_responseRotation*.";
2700  throw runtime_error(os.str());
2701  }
2702 
2703  // Check the size of *sensor_rot* vs. the number rows of *antenna_los*.
2704  if( sensor_rot.nelem()!=1 && sensor_rot.nelem()!=antenna_los.nrows() ) {
2705  ostringstream os;
2706  os << "The size of *sensor_rot* and number of rows in *antenna_los* has\n"
2707  << "to be equal.";
2708  throw runtime_error(os.str());
2709  }
2710 
2711  // Output to the user.
2712  out2 << " Calculating the rotation response with rotation from "
2713  << "*sensor_rot*.\n";
2714 
2715  // Setup L-matrix, iterate through rotation and insert in sensor_response
2716  Sparse rot_resp( n, n);
2717  rotation_matrix(rot_resp, sensor_rot, sensor_response_f.nelem(),
2718  stokes_dim );
2719 
2720  // Multiply with sensor_response
2721  Sparse tmp = sensor_response;
2722  sensor_response.resize( n, tmp.ncols());
2723  mult( sensor_response, rot_resp, tmp);
2724 
2725  // Some extra output.
2726  out3 << " Size of *sensor_response*: " << sensor_response.nrows()
2727  << "x" << sensor_response.ncols() << "\n";
2728 
2729 }
2730 */
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
sensor_responseAntenna
void sensor_responseAntenna(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, Vector &sensor_response_za_grid, Vector &sensor_response_aa_grid, const Vector &sensor_response_f_grid, const ArrayOfIndex &sensor_response_pol_grid, const Index &atmosphere_dim, const Index &antenna_dim, const Matrix &antenna_los, const GriddedField4 &antenna_response, const Index &sensor_norm, const Verbosity &verbosity)
WORKSPACE METHOD: sensor_responseAntenna.
Definition: m_sensor.cc:544
backend_channel_responseFlat
void backend_channel_responseFlat(ArrayOfGriddedField1 &r, const Numeric &resolution, const Verbosity &)
WORKSPACE METHOD: backend_channel_responseFlat.
Definition: m_sensor.cc:282
GriddedField::set_grid_name
void set_grid_name(Index i, const String &s)
Set grid name.
Definition: gridded_fields.h:161
Tensor4::resize
void resize(Index b, Index p, Index r, Index c)
Resize function.
Definition: matpackIV.cc:1404
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
auto_md.h
f_gridFromSensorAMSU
void f_gridFromSensorAMSU(Vector &f_grid, const Vector &lo, const ArrayOfVector &f_backend, const ArrayOfArrayOfGriddedField1 &backend_channel_response, const Numeric &spacing, const Verbosity &verbosity)
WORKSPACE METHOD: f_gridFromSensorAMSU.
Definition: m_sensor.cc:329
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
chk_if_increasing
void chk_if_increasing(const String &x_name, const ArrayOfIndex &x)
chk_if_increasing
Definition: check_input.cc:126
gridpos
void gridpos(ArrayOfGridPos &gp, ConstVectorView old_grid, ConstVectorView new_grid, const Numeric &extpolfac)
Set up a grid position Array.
Definition: interpolation.cc:167
sensorOff
void sensorOff(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, Vector &sensor_response_f_grid, ArrayOfIndex &sensor_response_pol_grid, Vector &sensor_response_za_grid, Vector &sensor_response_aa_grid, Index &antenna_dim, Vector &mblock_za_grid, Vector &mblock_aa_grid, const Index &atmosphere_dim, const Index &stokes_dim, const Vector &f_grid, const Verbosity &verbosity)
WORKSPACE METHOD: sensorOff.
Definition: m_sensor.cc:1526
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
chk_if_bool
void chk_if_bool(const String &x_name, const Index &x)
chk_if_bool
Definition: check_input.cc:67
antenna_responseGaussian
void antenna_responseGaussian(GriddedField4 &r, const Numeric &fwhm, const Numeric &xwidth_si, const Numeric &dx_si, const Verbosity &)
WORKSPACE METHOD: antenna_responseGaussian.
Definition: m_sensor.cc:251
Sparse::make_I
void make_I(Index r, Index c)
Make Identity matrix.
Definition: matpackII.cc:474
joker
const Joker joker
AntennaOff
void AntennaOff(Index &antenna_dim, Vector &mblock_za_grid, Vector &mblock_aa_grid, const Verbosity &verbosity)
WORKSPACE METHOD: AntennaOff.
Definition: m_sensor.cc:191
GFIELD1_F_GRID
const Index GFIELD1_F_GRID
AntennaMultiBeamsToPencilBeams
void AntennaMultiBeamsToPencilBeams(Matrix &sensor_pos, Matrix &sensor_los, Matrix &antenna_los, Index &antenna_dim, Vector &mblock_za_grid, Vector &mblock_aa_grid, const Index &atmosphere_dim, const Verbosity &verbosity)
WORKSPACE METHOD: AntennaMultiBeamsToPencilBeams.
Definition: m_sensor.cc:115
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
GFIELD4_ZA_GRID
const Index GFIELD4_ZA_GRID
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
ConstMatrixView::nrows
Index nrows() const
Returns the number of rows.
Definition: matpackI.cc:796
CREATE_OUT2
#define CREATE_OUT2
Definition: messages.h:207
sensor_responseMultiMixerBackend
void sensor_responseMultiMixerBackend(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, Vector &sensor_response_f_grid, const ArrayOfIndex &sensor_response_pol_grid, const Vector &sensor_response_za_grid, const Vector &sensor_response_aa_grid, const Vector &lo_multi, const ArrayOfGriddedField1 &sideband_response_multi, const ArrayOfString &sideband_mode_multi, const ArrayOfVector &f_backend_multi, const ArrayOfArrayOfGriddedField1 &backend_channel_response_multi, const Index &sensor_norm, const Verbosity &verbosity)
WORKSPACE METHOD: sensor_responseMultiMixerBackend.
Definition: m_sensor.cc:1716
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
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
GFIELD4_FIELD_NAMES
const Index GFIELD4_FIELD_NAMES
sensor.h
Sensor modelling functions.
sensor_responseIF2RF
void sensor_responseIF2RF(Vector &sensor_response_f, Vector &sensor_response_f_grid, const Numeric &lo, const String &sideband_mode, const Verbosity &)
WORKSPACE METHOD: sensor_responseIF2RF.
Definition: m_sensor.cc:1193
mult
void mult(VectorView y, const ConstMatrixView &M, const ConstVectorView &x)
Matrix Vector multiplication.
Definition: matpackI.cc:1607
CREATE_OUT3
#define CREATE_OUT3
Definition: messages.h:208
messages.h
Declarations having to do with the four output streams.
ConstMatrixView::ncols
Index ncols() const
Returns the number of columns.
Definition: matpackI.cc:802
my_basic_string
The implementation for String, the ARTS string class.
Definition: mystring.h:62
abs
#define abs(x)
Definition: continua.cc:13094
sensor_responseBackend
void sensor_responseBackend(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, Vector &sensor_response_f_grid, const ArrayOfIndex &sensor_response_pol_grid, const Vector &sensor_response_za_grid, const Vector &sensor_response_aa_grid, const Vector &f_backend, const ArrayOfGriddedField1 &backend_channel_response, const Index &sensor_norm, const Verbosity &verbosity)
WORKSPACE METHOD: sensor_responseBackend.
Definition: m_sensor.cc:811
sensor_responseFillFgrid
void sensor_responseFillFgrid(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, Vector &sensor_response_f_grid, const ArrayOfIndex &sensor_response_pol_grid, const Vector &sensor_response_za_grid, const Vector &sensor_response_aa_grid, const Index &polyorder, const Index &nfill, const Verbosity &verbosity)
WORKSPACE METHOD: sensor_responseFillFgrid.
Definition: m_sensor.cc:1289
sub
void sub(Sparse &A, const Sparse &B, const Sparse &C)
Sparse - Sparse subtraction.
Definition: matpackII.cc:1023
ConstVectorView::nelem
Index nelem() const
Returns the number of elements.
Definition: matpackI.cc:175
sensor_responseBeamSwitching
void sensor_responseBeamSwitching(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, Vector &sensor_response_za_grid, Vector &sensor_response_aa_grid, const Vector &sensor_response_f_grid, const ArrayOfIndex &sensor_response_pol_grid, const Numeric &w1, const Numeric &w2, const Verbosity &verbosity)
WORKSPACE METHOD: sensor_responseBeamSwitching.
Definition: m_sensor.cc:1041
sensor_response_arraySingle
void sensor_response_arraySingle(ArrayOfSparse &sensor_response_array, ArrayOfVector &sensor_response_f_array, ArrayOfArrayOfIndex &sensor_response_pol_array, ArrayOfVector &sensor_response_za_array, ArrayOfVector &sensor_response_aa_array, const Sparse &sensor_response, const Vector &sensor_response_f, const ArrayOfIndex &sensor_response_pol, const Vector &sensor_response_za, const Vector &sensor_response_aa, const Verbosity &)
WORKSPACE METHOD: sensor_response_arraySingle.
Definition: m_sensor.cc:2509
Numeric
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
Verbosity
Definition: messages.h:50
GriddedField4
Definition: gridded_fields.h:328
GriddedField::set_name
void set_name(const String &s)
Set name of this gridded field.
Definition: gridded_fields.h:169
math_funcs.h
PI
const Numeric PI
transpose
ConstMatrixView transpose(ConstMatrixView m)
Const version of transpose.
Definition: matpackI.cc:1689
make_vector.h
The class MakeVector is a special kind of Vector that can be initialized explicitly from one or more ...
Matrix::resize
void resize(Index r, Index c)
Resize function.
Definition: matpackI.cc:1549
max
#define max(a, b)
Definition: continua.cc:13097
interpolation_poly.h
Header file for interpolation_poly.cc.
nlinspace
void nlinspace(Vector &x, const Numeric start, const Numeric stop, const Index n)
nlinspace
Definition: math_funcs.cc:261
MakeVector
Definition: make_vector.h:42
Sparse::resize
void resize(Index r, Index c)
Resize function.
Definition: matpackII.cc:516
sensor_responseSimpleAMSU
void sensor_responseSimpleAMSU(Vector &f_grid, Index &antenna_dim, Vector &mblock_za_grid, Vector &mblock_aa_grid, Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, Vector &sensor_response_f_grid, ArrayOfIndex &sensor_response_pol_grid, Vector &sensor_response_za_grid, Vector &sensor_response_aa_grid, Index &sensor_norm, const Index &atmosphere_dim, const Index &stokes_dim, const Matrix &sensor_description_amsu, const Numeric &spacing, const Verbosity &verbosity)
WORKSPACE METHOD: sensor_responseSimpleAMSU.
Definition: m_sensor.cc:2087
Range
The range class.
Definition: matpackI.h:148
GFIELD4_AA_GRID
const Index GFIELD4_AA_GRID
Select
void Select(Vector &needles, const Vector &haystack, const ArrayOfIndex &needleind, const Verbosity &verbosity)
Definition: m_select.h:72
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
ppath.h
Propagation path structure and functions.
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
sensor_responseBackendFrequencySwitching
void sensor_responseBackendFrequencySwitching(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, Vector &sensor_response_f_grid, const ArrayOfIndex &sensor_response_pol_grid, const Vector &sensor_response_za_grid, const Vector &sensor_response_aa_grid, const Vector &f_backend, const ArrayOfGriddedField1 &backend_channel_response, const Index &sensor_norm, const Numeric &df1, const Numeric &df2, const Verbosity &verbosity)
WORKSPACE METHOD: sensor_responseBackendFrequencySwitching.
Definition: m_sensor.cc:980
is_increasing
bool is_increasing(ConstVectorView x)
Checks if a vector is sorted and strictly increasing.
Definition: logic.cc:258
Sparse::nrows
Index nrows() const
Returns the number of rows.
Definition: matpackII.cc:53
is_multiple
bool is_multiple(const Index &x, const Index &y)
Checks if an integer is a multiple of another integer.
Definition: logic.cc:73
sensor_responseWMRF
void sensor_responseWMRF(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, Vector &sensor_response_f_grid, const ArrayOfIndex &sensor_response_pol_grid, const Vector &sensor_response_za_grid, const Vector &sensor_response_aa_grid, const Sparse &wmrf_weights, const Vector &f_backend, const Verbosity &verbosity)
WORKSPACE METHOD: sensor_responseWMRF.
Definition: m_sensor.cc:2377
sensor_responseFromArrayData
void sensor_responseFromArrayData(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, const Index &imblock, const ArrayOfSparse &sensor_response_array, const ArrayOfVector &sensor_response_f_array, const ArrayOfArrayOfIndex &sensor_response_pol_array, const ArrayOfVector &sensor_response_za_array, const ArrayOfVector &sensor_response_aa_array, const ArrayOfIndex &sensor_response_index, const Verbosity &)
WORKSPACE METHOD: sensor_responseFromArrayData.
Definition: m_sensor.cc:1235
AntennaSet1D
void AntennaSet1D(Index &antenna_dim, Vector &mblock_aa_grid, const Verbosity &verbosity)
WORKSPACE METHOD: AntennaSet1D.
Definition: m_sensor.cc:213
min
#define min(a, b)
Definition: continua.cc:13096
AntennaConstantGaussian1D
void AntennaConstantGaussian1D(Index &antenna_dim, Vector &mblock_za_grid, Vector &mblock_aa_grid, GriddedField4 &r, Matrix &antenna_los, const Index &n_za_grid, const Numeric &fwhm, const Numeric &xwidth_si, const Numeric &dx_si, const Verbosity &verbosity)
WORKSPACE METHOD: AntennaConstantGaussian1D.
Definition: m_sensor.cc:72
GriddedField1
Definition: gridded_fields.h:189
special_interp.h
Header file for special_interp.cc.
GriddedField1::resize
void resize(const GriddedField1 &gf)
Make this GriddedField1 the same size as the given one.
Definition: gridded_fields.h:211
MakeArray
Explicit construction of Arrays.
Definition: make_array.h:52
Index
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
chk_if_in_range
void chk_if_in_range(const String &x_name, const Index &x, const Index &x_low, const Index &x_high)
chk_if_in_range
Definition: check_input.cc:95
backend_channel_responseGaussian
void backend_channel_responseGaussian(ArrayOfGriddedField1 &r, const Numeric &fwhm, const Numeric &xwidth_si, const Numeric &dx_si, const Verbosity &)
WORKSPACE METHOD: backend_channel_responseGaussian.
Definition: m_sensor.cc:304
check_input.h
gridpos_poly
void gridpos_poly(ArrayOfGridPosPoly &gp, ConstVectorView old_grid, ConstVectorView new_grid, const Index order, const Numeric &extpolfac)
Set up grid positions for higher order interpolation.
Definition: interpolation_poly.cc:124
sensor_responsePolarisation
void sensor_responsePolarisation(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, ArrayOfIndex &sensor_response_pol_grid, const Vector &sensor_response_f_grid, const Vector &sensor_response_za_grid, const Vector &sensor_response_aa_grid, const Index &stokes_dim, const String &y_unit, const ArrayOfIndex &sensor_pol, const Verbosity &)
WORKSPACE METHOD: sensor_responsePolarisation.
Definition: m_sensor.cc:1911
GriddedField4::data
Tensor4 data
Definition: gridded_fields.h:373
AntennaSet2D
void AntennaSet2D(Index &antenna_dim, const Index &atmosphere_dim, const Verbosity &verbosity)
WORKSPACE METHOD: AntennaSet2D.
Definition: m_sensor.cc:231
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
f_gridFromSensorHIRS
void f_gridFromSensorHIRS(Vector &f_grid, const Vector &f_backend, const ArrayOfGriddedField1 &backend_channel_response, const Numeric &spacing, const Verbosity &verbosity)
WORKSPACE METHOD: f_gridFromSensorHIRS.
Definition: m_sensor.cc:468
sorting.h
Contains sorting routines.
sensor_responseMixer
void sensor_responseMixer(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, Vector &sensor_response_f_grid, const ArrayOfIndex &sensor_response_pol_grid, const Vector &sensor_response_za_grid, const Vector &sensor_response_aa_grid, const Numeric &lo, const GriddedField1 &sideband_response, const Index &sensor_norm, const Verbosity &verbosity)
WORKSPACE METHOD: sensor_responseMixer.
Definition: m_sensor.cc:1562
Array::nelem
Index nelem() const
Number of elements.
Definition: array.h:172
GFIELD4_F_GRID
const Index GFIELD4_F_GRID
interpweights
void interpweights(VectorView itw, const GridPos &tc)
Red 1D interpolation weights.
Definition: interpolation.cc:756
sensor_responseInit
void sensor_responseInit(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, Vector &sensor_response_f_grid, ArrayOfIndex &sensor_response_pol_grid, Vector &sensor_response_za_grid, Vector &sensor_response_aa_grid, const Vector &f_grid, const Vector &mblock_za_grid, const Vector &mblock_aa_grid, const Index &antenna_dim, const Index &atmosphere_dim, const Index &stokes_dim, const Index &sensor_norm, const Verbosity &verbosity)
WORKSPACE METHOD: sensor_responseInit.
Definition: m_sensor.cc:1429
arts.h
The global header file for ARTS.
sensor_responseFrequencySwitching
void sensor_responseFrequencySwitching(Sparse &sensor_response, Vector &sensor_response_f, ArrayOfIndex &sensor_response_pol, Vector &sensor_response_za, Vector &sensor_response_aa, Vector &sensor_response_f_grid, const ArrayOfIndex &sensor_response_pol_grid, const Vector &sensor_response_za_grid, const Vector &sensor_response_aa_grid, const Verbosity &verbosity)
WORKSPACE METHOD: sensor_responseFrequencySwitching.
Definition: m_sensor.cc:1116
xml_io.h
This file contains basic functions to handle XML data files.
WMRFSelectChannels
void WMRFSelectChannels(Vector &f_grid, Sparse &wmrf_weights, Vector &f_backend, const ArrayOfIndex &wmrf_channels, const Verbosity &verbosity)
WORKSPACE METHOD: WMRFSelectChannels.
Definition: m_sensor.cc:2244