00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00039
00040
00041
00042
00043 #include <cmath>
00044 #include <stdexcept>
00045 #include <string>
00046 #include "arts.h"
00047 #include "auto_md.h"
00048 #include "check_input.h"
00049 #include "math_funcs.h"
00050 #include "messages.h"
00051 #include "ppath.h"
00052 #include "special_interp.h"
00053 #include "xml_io.h"
00054 #include "sensor.h"
00055 #include "make_vector.h"
00056 #include "sorting.h"
00057
00058 extern const Numeric PI;
00059 extern const Index GFIELD1_F_GRID;
00060 extern const Index GFIELD4_FIELD_NAMES;
00061 extern const Index GFIELD4_F_GRID;
00062 extern const Index GFIELD4_ZA_GRID;
00063 extern const Index GFIELD4_AA_GRID;
00064
00065
00066
00067
00068
00069
00070
00071
00072 void AntennaOff(
00073
00074 Index& antenna_dim,
00075 Vector& mblock_za_grid,
00076 Vector& mblock_aa_grid )
00077 {
00078 out2 << " Sets the antenna dimensionality to 1.\n";
00079 antenna_dim = 1;
00080
00081 out2 << " Sets *mblock_za_grid* to have length 1 with value 0.\n";
00082 mblock_za_grid.resize(1);
00083 mblock_za_grid[0] = 0;
00084
00085 out2 << " Sets *mblock_aa_grid* to be an empty vector.\n";
00086 mblock_aa_grid.resize(0);
00087 }
00088
00089
00090
00091
00092 void AntennaSet1D(
00093
00094 Index& antenna_dim,
00095 Vector& mblock_aa_grid )
00096 {
00097 out2 << " Sets the antenna dimensionality to 1.\n";
00098 out3 << " antenna_dim = 1\n";
00099 out3 << " mblock_aa_grid is set to be an empty vector\n";
00100 antenna_dim = 1;
00101 mblock_aa_grid.resize(0);
00102 }
00103
00104
00105
00106
00107 void AntennaSet2D(
00108
00109 Index& antenna_dim,
00110
00111 const Index& atmosphere_dim )
00112 {
00113 if( atmosphere_dim != 3 )
00114 throw runtime_error("Antenna dimensionality 2 is only allowed when the "
00115 "atmospheric dimensionality is 3." );
00116 out2 << " Sets the antenna dimensionality to 1.\n";
00117 out3 << " antenna_dim = 2\n";
00118 antenna_dim = 2;
00119 }
00120
00121
00122
00123
00124 void f_gridFromSensorAMSU(
00125 Vector& f_grid,
00126
00127 const Vector& lo,
00128 const ArrayOfVector& f_backend,
00129 const ArrayOfArrayOfGField1& backend_channel_response,
00130
00131 const Numeric& spacing)
00132 {
00133
00134
00135 Index n_chan = 0;
00136 for (Index i=0; i<f_backend.nelem(); ++i)
00137 for (Index s=0; s<f_backend[i].nelem(); ++s)
00138 ++n_chan;
00139
00140
00141
00142
00143 if (n_chan < 1)
00144 {
00145 ostringstream os;
00146 os << "There must be at least one channel.\n"
00147 << "(The vector *lo* must have at least one element.)";
00148 throw runtime_error(os.str());
00149 }
00150
00151
00152 if ( (f_backend.nelem() != lo.nelem()) ||
00153 (backend_channel_response.nelem() != lo.nelem()) )
00154 {
00155 ostringstream os;
00156 os << "Variables *lo_multi*, *f_backend_multi* and *backend_channel_response_multi*\n"
00157 << "must have same number of elements (number of LOs).";
00158 throw runtime_error(os.str());
00159 }
00160
00161
00162 for (Index i=0; i<f_backend.nelem(); ++i)
00163 if (f_backend[i].nelem() != backend_channel_response[i].nelem())
00164 {
00165 ostringstream os;
00166 os << "Variables *f_backend_multi* and *backend_channel_response_multi*\n"
00167 << "must have same number of bands for each LO.";
00168 throw runtime_error(os.str());
00169 }
00170
00171
00172
00173
00174
00175 Vector fabs_min(2*n_chan), fabs_max(2*n_chan);
00176 Index ifabs=0;
00177 for (Index i=0; i<f_backend.nelem(); ++i)
00178 for (Index s=0; s<f_backend[i].nelem(); ++s)
00179 {
00180 ConstVectorView this_grid = backend_channel_response[i][s].get_numeric_grid(0);
00181 const Numeric this_f_backend = f_backend[i][s];
00182
00183
00184
00185
00186
00187
00188 const Numeric delta = 5e3;
00189
00190
00191 fabs_min[ifabs] = this_f_backend + this_grid[0] - delta;
00192 fabs_max[ifabs] = this_f_backend + this_grid[this_grid.nelem()-1] + delta;
00193 ++ifabs;
00194
00195
00196 Numeric offset = this_f_backend - lo[i];
00197 Numeric f_image = lo[i] - offset;
00198
00199 fabs_min[ifabs] = f_image + this_grid[0] - delta;
00200 fabs_max[ifabs] = f_image + this_grid[this_grid.nelem()-1] + delta;
00201 ++ifabs;
00202 }
00203
00204
00205
00206
00207
00208 for (Index i=1; i<fabs_min.nelem(); ++i)
00209 {
00210 for (Index s=0; s<i; ++s)
00211 {
00212
00213
00214 if (((fabs_min[i]>=fabs_min[s]) && (fabs_min[i]<=fabs_max[s])) ||
00215 ((fabs_max[i]>=fabs_min[s]) && (fabs_max[i]<=fabs_max[s])) )
00216 {
00217 ostringstream os;
00218 os << "Your instrument bands overlap. This case it not (yet) handled.";
00219 throw runtime_error(os.str());
00220 }
00221 }
00222 }
00223
00224
00225
00226 ArrayOfNumeric f_grid_unsorted;
00227 for (Index i=0; i<fabs_min.nelem(); ++i)
00228 {
00229
00230 const Numeric bw = fabs_max[i] - fabs_min[i];
00231
00232
00233 const Numeric npf = ceil(bw/spacing);
00234
00235
00236
00237 const Index npi = (Index) npf + 1;
00238
00239
00240 const Numeric gs = bw/npf;
00241
00242
00243 Vector grid(fabs_min[i], npi, gs);
00244
00245 out3 << " Band range " << i << ": " << grid << "\n";
00246
00247
00248 f_grid_unsorted.reserve(f_grid_unsorted.nelem()+npi);
00249 for (Index s=0; s<npi; ++s)
00250 f_grid_unsorted.push_back(grid[s]);
00251 }
00252
00253
00254 f_grid.resize(f_grid_unsorted.nelem());
00255 ArrayOfIndex si;
00256 get_sorted_indexes(si, f_grid_unsorted);
00257 for (Index i=0; i<f_grid_unsorted.nelem(); ++i)
00258 f_grid[i] = f_grid_unsorted[si[i]];
00259
00260
00261
00262
00263
00264
00265
00266 }
00267
00269
00297 bool test_and_merge_two_channels(Vector& fmin,
00298 Vector& fmax,
00299 Index i,
00300 Index j)
00301 {
00302 const Index nf = fmin.nelem();
00303 assert(fmax.nelem()==nf);
00304 assert(i>=0 && i<nf);
00305 assert(j>=0 && j<nf);
00306 assert(fmin[i]<=fmin[j]);
00307 assert(i<j);
00308
00309
00310
00311
00312
00313
00314
00315 if (fmax[i] >= fmin[j])
00316 {
00317
00318
00319
00320
00321 if (fmax[j] > fmax[i])
00322 fmax[i] = fmax[j];
00323
00324
00325
00326
00327 Index n_behind = nf-1 - j;
00328
00329 Vector dummy = fmin;
00330 fmin.resize(nf-1);
00331 fmin[Range(0,j)] = dummy[Range(0,j)];
00332 if (n_behind > 0)
00333 fmin[Range(j,n_behind)] = dummy[Range(j+1,n_behind)];
00334
00335 dummy = fmax;
00336 fmax.resize(nf-1);
00337 fmax[Range(0,j)] = dummy[Range(0,j)];
00338 if (n_behind > 0)
00339 fmax[Range(j,n_behind)] = dummy[Range(j+1,n_behind)];
00340
00341 return true;
00342 }
00343
00344 return false;
00345 }
00346
00347
00348
00349 void f_gridFromSensorHIRS(
00350 Vector& f_grid,
00351
00352 const Vector& f_backend,
00353 const ArrayOfGField1& backend_channel_response,
00354
00355 const Numeric& spacing)
00356 {
00357
00358 const Index n_chan = f_backend.nelem();
00359
00360
00361
00362
00363 if (n_chan < 1)
00364 {
00365 ostringstream os;
00366 os << "There must be at least one channel.\n"
00367 << "(The vector *f_backend* must have at least one element.)";
00368 throw runtime_error(os.str());
00369 }
00370
00371
00372 if (n_chan != backend_channel_response.nelem())
00373 {
00374 ostringstream os;
00375 os << "Variables *f_backend_multi* and *backend_channel_response_multi*\n"
00376 << "must have same number of bands for each LO.";
00377 throw runtime_error(os.str());
00378 }
00379
00380
00381 for (Index i=0; i<n_chan; ++i)
00382 {
00383
00384 const Vector& backend_f_grid = backend_channel_response[i].get_numeric_grid(0);
00385
00386 if ( !is_increasing(backend_f_grid) )
00387 {
00388 ostringstream os;
00389 os << "The frequency grid for the backend channel response of\n"
00390 << "channel " << i << " is not strictly increasing.\n";
00391 os << "It is: " << backend_f_grid << "\n";
00392 throw runtime_error( os.str() );
00393 }
00394 }
00395
00396
00397
00398
00399 out2 << " Original channel characteristics:\n"
00400 << " min nominal max (all in Hz):\n";
00401
00402
00403 Vector fmin_orig(n_chan);
00404 Vector fmax_orig(n_chan);
00405 for (Index i=0; i<n_chan; ++i)
00406 {
00407
00408 const Vector& backend_f_grid = backend_channel_response[i].get_numeric_grid(0);
00409
00410 const Index nf = backend_f_grid.nelem();
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426 Numeric bf_min = backend_f_grid[0];
00427 Numeric bf_max = backend_f_grid[nf-1];
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437 const Numeric delta = 1e6;
00438
00439 fmin_orig[i] = f_backend[i] + bf_min - delta;
00440 fmax_orig[i] = f_backend[i] + bf_max + delta;
00441
00442 out2 << " " << fmin_orig[i]
00443 << " " << f_backend[i]
00444 << " " << fmax_orig[i] << "\n";
00445 }
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461 ArrayOfIndex isorted;
00462 get_sorted_indexes (isorted, fmin_orig);
00463
00464 Vector fmin(n_chan), fmax(n_chan);
00465 for (Index i=0; i<n_chan; ++i)
00466 {
00467 fmin[i] = fmin_orig[isorted[i]];
00468 fmax[i] = fmax_orig[isorted[i]];
00469 }
00470
00471
00472
00473
00474
00475
00476
00477
00478 for (Index i=0; i<fmin.nelem()-1; ++i)
00479 {
00480 bool continue_checking = true;
00481
00482
00483
00484 while (continue_checking && i<fmin.nelem()-1)
00485 {
00486
00487 continue_checking =
00488 test_and_merge_two_channels(fmin, fmax, i, i+1);
00489
00490
00491
00492
00493 }
00494 }
00495
00496 out2 << " New channel characteristics:\n"
00497 << " min max (all in Hz):\n";
00498 for (Index i=0; i<fmin.nelem(); ++i)
00499 out2 << " " << fmin[i] << " " << fmax[i] << "\n";
00500
00501
00502
00503
00504
00505
00506
00507 ArrayOfNumeric f_grid_array;
00508
00509 for (Index i=0; i<fmin.nelem(); ++i)
00510 {
00511
00512 const Numeric bw = fmax[i] - fmin[i];
00513
00514
00515 const Numeric npf = ceil(bw/spacing);
00516
00517
00518
00519 const Index npi = (Index) npf + 1;
00520
00521
00522 const Numeric gs = bw/npf;
00523
00524
00525 Vector grid(fmin[i], npi, gs);
00526
00527 out3 << " Band range " << i << ": " << grid << "\n";
00528
00529
00530 f_grid_array.reserve(f_grid_array.nelem()+npi);
00531 for (Index s=0; s<npi; ++s)
00532 f_grid_array.push_back(grid[s]);
00533 }
00534
00535
00536 f_grid = f_grid_array;
00537
00538 out2 << " Total number of frequencies in f_grid: " << f_grid.nelem() << "\n";
00539
00540 }
00541
00542
00543
00544
00545 void sensorOff(
00546
00547 Sparse& sensor_response,
00548 Vector& sensor_response_f,
00549 ArrayOfIndex& sensor_response_pol,
00550 Vector& sensor_response_za,
00551 Vector& sensor_response_aa,
00552 Vector& sensor_response_f_grid,
00553 ArrayOfIndex& sensor_response_pol_grid,
00554 Vector& sensor_response_za_grid,
00555 Vector& sensor_response_aa_grid,
00556 Index& antenna_dim,
00557 Vector& mblock_za_grid,
00558 Vector& mblock_aa_grid,
00559 const Index& atmosphere_dim,
00560 const Index& stokes_dim,
00561 const Vector& f_grid )
00562 {
00563
00564
00565 AntennaOff( antenna_dim, mblock_za_grid, mblock_aa_grid );
00566
00567
00568 Index sensor_norm = 1;
00569
00570 sensor_responseInit( sensor_response, sensor_response_f,
00571 sensor_response_pol, sensor_response_za, sensor_response_aa,
00572 sensor_response_f_grid, sensor_response_pol_grid,
00573 sensor_response_za_grid, sensor_response_aa_grid, f_grid,
00574 mblock_za_grid, mblock_aa_grid, antenna_dim, atmosphere_dim,
00575 stokes_dim, sensor_norm );
00576 }
00577
00578
00579
00580
00581 void sensor_responseAntenna(
00582
00583 Sparse& sensor_response,
00584 Vector& sensor_response_f,
00585 ArrayOfIndex& sensor_response_pol,
00586 Vector& sensor_response_za,
00587 Vector& sensor_response_aa,
00588 Vector& sensor_response_za_grid,
00589 Vector& sensor_response_aa_grid,
00590
00591 const Vector& sensor_response_f_grid,
00592 const ArrayOfIndex& sensor_response_pol_grid,
00593 const Index& atmosphere_dim,
00594 const Index& antenna_dim,
00595 const Matrix& antenna_los,
00596 const GField4& antenna_response,
00597 const Index& sensor_norm )
00598 {
00599
00600 chk_if_in_range( "atmosphere_dim", atmosphere_dim, 1, 3 );
00601 chk_if_in_range( "antenna_dim", antenna_dim, 1, 2 );
00602 chk_if_bool( "sensor_norm", sensor_norm );
00603
00604
00605
00606 const Index nf = sensor_response_f_grid.nelem();
00607 const Index npol = sensor_response_pol_grid.nelem();
00608 const Index nza = sensor_response_za_grid.nelem();
00609 const Index naa = max( Index(1), sensor_response_aa_grid.nelem() );
00610 const Index nin = nf * npol * nza * naa;
00611
00612
00613
00614 ostringstream os;
00615 bool error_found = false;
00616
00617
00618
00619 if( sensor_response_f.nelem() != nin )
00620 {
00621 os << "Inconsistency in size between *sensor_response_f* and the sensor\n"
00622 << "grid variables (sensor_response_f_grid etc.).\n";
00623 error_found = true;
00624 }
00625 if( sensor_response.nrows() != nin )
00626 {
00627 os << "The sensor block response matrix *sensor_response* does not have\n"
00628 << "right size compared to the sensor grid variables\n"
00629 << "(sensor_response_f_grid etc.).\n";
00630 error_found = true;
00631 }
00632
00633
00634
00635 if( antenna_dim == 2 && atmosphere_dim < 3 )
00636 {
00637 os << "If *antenna_dim* is 2, *atmosphere_dim* must be 3.\n";
00638 error_found = true;
00639 }
00640 if( antenna_dim == 1 && sensor_response_aa_grid.nelem() )
00641 {
00642 os << "If *antenna_dim* is 1, *sensor_response_aa_grid* (and\n"
00643 << "*mblock_aa_grid*) must be empty.";
00644 error_found = true;
00645 }
00646
00647
00648
00649 if( antenna_dim != antenna_los.ncols() )
00650 {
00651 os << "The number of columns of *antenna_los* must be *antenna_dim*.\n";
00652 error_found = true;
00653 }
00654
00655
00656
00657
00658
00659 const Index lpolgrid =
00660 antenna_response.get_string_grid(GFIELD4_FIELD_NAMES).nelem();
00661
00662 if( lpolgrid != 1 && lpolgrid != npol )
00663 {
00664 os << "The number of polarisation in *antenna_response* must be 1 or be\n"
00665 << "equal to the number of polarisations used (determined by\n"
00666 << "*stokes_dim* or *sensor_pol*).\n";
00667 error_found = true;
00668 }
00669
00670
00671
00672
00673 ConstVectorView aresponse_f_grid =
00674 antenna_response.get_numeric_grid(GFIELD4_F_GRID);
00675
00676 chk_if_increasing( "f_grid of antenna_response", aresponse_f_grid );
00677
00678 Numeric f_dlow = 0.0;
00679 Numeric f_dhigh = 0.0;
00680
00681 f_dlow = min(sensor_response_f_grid) - aresponse_f_grid[0];
00682 f_dhigh = last(aresponse_f_grid) - max(sensor_response_f_grid);
00683
00684 if( aresponse_f_grid.nelem() == 1 )
00685 {
00686 if( f_dlow > 0 || f_dhigh > 0 )
00687 {
00688 os << "The frequency grid of *antenna_response has a single value. In \n"
00689 << "this case, the grid frequency point must be inside the range\n"
00690 << "of considered frequencies (*f_grid*).\n";
00691 error_found = true;
00692 }
00693 }
00694 else
00695 {
00696
00697 if( f_dlow < 0 )
00698 {
00699 os << "The frequency grid of *antenna_response is too narrow. It must\n"
00700 << "cover all considered frequencies (*f_grid*), if the length\n"
00701 << "is > 1. The grid needs to be expanded with "<<-f_dlow<<" Hz in\n"
00702 << "the lower end.\n";
00703 error_found = true;
00704 }
00705 if( f_dhigh < 0 )
00706 {
00707 os << "The frequency grid of *antenna_response is too narrow. It must\n"
00708 << "cover all considered frequencies (*f_grid*), if the length\n"
00709 << "is > 1. The grid needs to be expanded with "<<-f_dhigh<<" Hz in\n"
00710 << "the upper end.\n";
00711 error_found = true;
00712 }
00713 }
00714
00715
00716
00717
00718 ConstVectorView aresponse_za_grid =
00719 antenna_response.get_numeric_grid(GFIELD4_ZA_GRID);
00720
00721 chk_if_increasing( "za_grid of *antenna_response*", aresponse_za_grid );
00722
00723 if( aresponse_za_grid.nelem() < 2 )
00724 {
00725 os << "The zenith angle grid of *antenna_response* must have >= 2 values.\n";
00726 error_found = true;
00727
00728 }
00729
00730
00731
00732
00733 Numeric za_dlow = 0.0;
00734 Numeric za_dhigh = 0.0;
00735
00736 za_dlow = min(antenna_los(joker,0)) + aresponse_za_grid[0] -
00737 min(sensor_response_za_grid);
00738 za_dhigh = max(sensor_response_za_grid) - ( max(antenna_los(joker,0)) +
00739 last(aresponse_za_grid) );
00740
00741 if( za_dlow < 0 )
00742 {
00743 os << "The WSV *sensor_response_za_grid* is too narrow. It should be\n"
00744 << "expanded with "<<-za_dlow<<" deg in the lower end. This change\n"
00745 << "should be probably applied to *mblock_za_grid*.\n";
00746 error_found = true;
00747 }
00748 if( za_dhigh < 0 )
00749 {
00750 os << "The WSV *sensor_response_za_grid* is too narrow. It should be\n"
00751 << "expanded with "<<-za_dhigh<<" deg in the higher end. This change\n"
00752 << "should be probably applied to *mblock_za_grid*.\n";
00753 error_found = true;
00754 }
00755
00756
00757
00758
00759 ConstVectorView aresponse_aa_grid =
00760 antenna_response.get_numeric_grid(GFIELD4_AA_GRID);
00761
00762 if( antenna_dim == 1 )
00763 {
00764 if( aresponse_aa_grid.nelem() != 1 )
00765 {
00766 os << "The azimuthal dimension of *antenna_response* must be 1 if\n"
00767 << "*antenna_dim* equals 1.\n";
00768 error_found = true;
00769 }
00770 }
00771 else
00772 {
00773 chk_if_increasing( "aa_grid of antenna_response", aresponse_aa_grid );
00774
00775 if( aresponse_za_grid.nelem() < 2 )
00776 {
00777 os << "The zenith angle grid of *antenna_response* must have >= 2\n"
00778 << "values.\n";
00779 error_found = true;
00780 }
00781
00782
00783
00784 Numeric aa_dlow = 0.0;
00785 Numeric aa_dhigh = 0.0;
00786
00787 aa_dlow = min(antenna_los(joker,1)) + aresponse_aa_grid[0] -
00788 min(sensor_response_aa_grid);
00789 aa_dhigh = max(sensor_response_aa_grid) - ( max(antenna_los(joker,1)) +
00790 last(aresponse_aa_grid) );
00791
00792 if( aa_dlow < 0 )
00793 {
00794 os << "The WSV *sensor_response_aa_grid* is too narrow. It should be\n"
00795 << "expanded with "<<-aa_dlow<<" deg in the lower end. This change\n"
00796 << "should be probably applied to *mblock_aa_grid*.\n";
00797 error_found = true;
00798 }
00799 if( f_dhigh < 0 )
00800 {
00801 os << "The WSV *sensor_response_aa_grid* is too narrow. It should be\n"
00802 << "expanded with "<<-aa_dhigh<<" deg in the higher end. This change\n"
00803 << "should be probably applied to *mblock_aa_grid*.\n";
00804 error_found = true;
00805 }
00806 }
00807
00808
00809
00810
00811 if (error_found)
00812 throw runtime_error(os.str());
00813
00814
00815
00816
00817
00818 Sparse hantenna;
00819
00820 if( antenna_dim == 1 )
00821 antenna1d_matrix( hantenna, antenna_dim, antenna_los, antenna_response,
00822 sensor_response_za_grid, sensor_response_f_grid,
00823 npol, sensor_norm );
00824 else
00825 throw runtime_error( "2D antenna cases are not yet handled." );
00826
00827
00828
00829
00830 Sparse htmp = sensor_response;
00831 sensor_response.resize( hantenna.nrows(), htmp.ncols());
00832 mult( sensor_response, hantenna, htmp );
00833
00834
00835 out3 << " Size of *sensor_response*: " << sensor_response.nrows()
00836 << "x" << sensor_response.ncols() << "\n";
00837
00838
00839 sensor_response_za_grid = antenna_los(joker,0);
00840
00841
00842 if( antenna_dim == 2 )
00843 sensor_response_aa_grid = antenna_los(joker,1);
00844
00845
00846 sensor_aux_vectors( sensor_response_f, sensor_response_pol,
00847 sensor_response_za, sensor_response_aa,
00848 sensor_response_f_grid, sensor_response_pol_grid,
00849 sensor_response_za_grid, sensor_response_aa_grid );
00850 }
00851
00852
00853
00854
00855
00856
00857 void sensor_responseBackend(
00858
00859 Sparse& sensor_response,
00860 Vector& sensor_response_f,
00861 ArrayOfIndex& sensor_response_pol,
00862 Vector& sensor_response_za,
00863 Vector& sensor_response_aa,
00864 Vector& sensor_response_f_grid,
00865
00866 const ArrayOfIndex& sensor_response_pol_grid,
00867 const Vector& sensor_response_za_grid,
00868 const Vector& sensor_response_aa_grid,
00869 const Vector& f_backend,
00870 const ArrayOfGField1& backend_channel_response,
00871 const Index& sensor_norm )
00872 {
00873
00874 const Index nf = sensor_response_f_grid.nelem();
00875 const Index npol = sensor_response_pol_grid.nelem();
00876 const Index nza = sensor_response_za_grid.nelem();
00877 const Index naa = sensor_response_aa_grid.nelem();
00878 const Index nin = nf * npol * nza;
00879
00880
00881
00882 ostringstream os;
00883 bool error_found = false;
00884
00885
00886 if( sensor_response_f.nelem() != nin )
00887 {
00888 os << "Inconsistency in size between *sensor_response_f* and the sensor\n"
00889 << "grid variables (sensor_response_f_grid etc.).\n";
00890 error_found = true;
00891 }
00892 if( naa && naa != nza )
00893 {
00894 os << "Incorrect size of *sensor_response_aa_grid*.\n";
00895 error_found = true;
00896 }
00897 if( sensor_response.nrows() != nin )
00898 {
00899 os << "The sensor block response matrix *sensor_response* does not have\n"
00900 << "right size compared to the sensor grid variables\n"
00901 << "(sensor_response_f_grid etc.).\n";
00902 error_found = true;
00903 }
00904
00905
00906 if( min(f_backend) < min(sensor_response_f_grid) )
00907 {
00908 os << "At least one value in *f_backend* (" << min(f_backend)
00909 << ") below range\ncovered by *sensor_response_f_grid* ("
00910 << min(sensor_response_f_grid) << ").\n";
00911 error_found = true;
00912 }
00913 if( max(f_backend) > max(sensor_response_f_grid) )
00914 {
00915 os << "At least one value in *f_backend* (" << max(f_backend)
00916 << ") above range\ncovered by *sensor_response_f_grid* ("
00917 << max(sensor_response_f_grid) << ").\n";
00918 error_found = true;
00919 }
00920
00921
00922
00923 const Index nrp = backend_channel_response.nelem();
00924
00925 if( nrp != 1 && nrp != f_backend.nelem() )
00926 {
00927 os << "The WSV *backend_channel_response* must have 1 or n elements,\n"
00928 << "where n is the length of *f_backend*.\n";
00929 error_found = true;
00930 }
00931
00932
00933
00934 if( error_found )
00935 throw runtime_error(os.str());
00936
00937 Numeric f_dlow = 0.0;
00938 Numeric f_dhigh = 0.0;
00939
00940 for( Index i=0; i<nrp; i++ )
00941 {
00942 ConstVectorView bchr_f_grid =
00943 backend_channel_response[i].get_numeric_grid(GFIELD1_F_GRID);
00944
00945 if( bchr_f_grid.nelem() != backend_channel_response[i].nelem() )
00946 {
00947 os << "Mismatch in size of grid and data in element " << i
00948 << "\nof *sideband_response*.\n";
00949 error_found = true;
00950 }
00951
00952 if( !is_increasing( bchr_f_grid ) )
00953 {
00954 os << "The frequency grid of element " << i
00955 << " in *backend_channel_response*\nis not strictly increasing.\n";
00956 error_found = true;
00957 }
00958
00959
00960
00961
00962 Numeric f1 = f_backend[i] + bchr_f_grid[0] - min(sensor_response_f_grid);
00963 Numeric f2 = (max(sensor_response_f_grid) -
00964 f_backend[i]) - last(bchr_f_grid);
00965
00966 f_dlow = min( f_dlow, f1 );
00967 f_dhigh = min( f_dhigh, f2 );
00968 if( f_dlow < 0 )
00969 {
00970 cout << i << "\n";
00971 cout << f1 << "\n";
00972 cout << min(sensor_response_f_grid) << "\n";
00973 cout << f_backend[i] << "\n";
00974 cout << bchr_f_grid[0] << "\n";
00975 }
00976 }
00977
00978 if( f_dlow < 0 )
00979 {
00980 os << "The WSV *sensor_response_f_grid* is too narrow. It should be\n"
00981 << "expanded with "<<-f_dlow<<" Hz in the lower end. This change\n"
00982 << "should be applied to either *f_grid* or the sensor part in\n"
00983 << "front of *sensor_responseBackend*.\n";
00984 error_found = true;
00985 }
00986 if( f_dhigh < 0 )
00987 {
00988 os << "The WSV *sensor_response_f_grid* is too narrow. It should be\n"
00989 << "expanded with "<<-f_dhigh<<" Hz in the higher end. This change\n"
00990 << "should be applied to either *f_grid* or the sensor part in\n"
00991 << "front of *sensor_responseBackend*.\n";
00992 error_found = true;
00993 }
00994
00995
00996
00997 if (error_found)
00998 throw runtime_error(os.str());
00999
01000
01001
01002
01003 Sparse hbackend;
01004
01005 spectrometer_matrix( hbackend, f_backend, backend_channel_response,
01006 sensor_response_f_grid, npol, nza, sensor_norm );
01007
01008
01009
01010
01011 Sparse htmp = sensor_response;
01012 sensor_response.resize( hbackend.nrows(), htmp.ncols());
01013 mult( sensor_response, hbackend, htmp );
01014
01015
01016 out3 << " Size of *sensor_response*: " << sensor_response.nrows()
01017 << "x" << sensor_response.ncols() << "\n";
01018
01019
01020 sensor_response_f_grid = f_backend;
01021
01022
01023 sensor_aux_vectors( sensor_response_f, sensor_response_pol,
01024 sensor_response_za, sensor_response_aa,
01025 sensor_response_f_grid, sensor_response_pol_grid,
01026 sensor_response_za_grid, sensor_response_aa_grid );
01027 }
01028
01029
01030
01031
01032 void sensor_responseBeamSwitching(
01033
01034 Sparse& sensor_response,
01035 Vector& sensor_response_f,
01036 ArrayOfIndex& sensor_response_pol,
01037 Vector& sensor_response_za,
01038 Vector& sensor_response_aa,
01039 Vector& sensor_response_za_grid,
01040 Vector& sensor_response_aa_grid,
01041
01042 const Vector& sensor_response_f_grid,
01043 const ArrayOfIndex& sensor_response_pol_grid,
01044 const Numeric& w1,
01045 const Numeric& w2 )
01046 {
01047 if( sensor_response_za_grid.nelem() != 2 )
01048 throw runtime_error(
01049 "This method requires that the number of observation directions is 2." );
01050
01051 if( sensor_response_pol_grid.nelem() != 1 )
01052 throw runtime_error(
01053 "This method handles (so far) only single polarisation cases." );
01054
01055 const Index n = sensor_response_f_grid.nelem();
01056
01057
01058 Sparse Hbswitch(n,2*n);
01059 Vector hrow( 2*n, 0.0 );
01060
01061 for( Index i=0; i<n; i++ )
01062 {
01063 hrow[i] = w1;
01064 hrow[i+n] = w2;
01065
01066 Hbswitch.insert_row( i, hrow );
01067
01068 hrow = 0;
01069 }
01070
01071
01072
01073
01074 Sparse Htmp = sensor_response;
01075 sensor_response.resize( Hbswitch.nrows(), Htmp.ncols());
01076 mult( sensor_response, Hbswitch, Htmp );
01077
01078
01079 out3 << " Size of *sensor_response*: " << sensor_response.nrows()
01080 << "x" << sensor_response.ncols() << "\n";
01081
01082
01083 const Numeric za = sensor_response_za_grid[1];
01084 sensor_response_za_grid.resize(1);
01085 sensor_response_za_grid[0] = za;
01086
01087
01088 if( sensor_response_aa_grid.nelem() > 0 )
01089 {
01090 const Numeric aa = sensor_response_aa_grid[1];
01091 sensor_response_aa_grid.resize(1);
01092 sensor_response_za_grid[0] = aa;
01093 }
01094
01095
01096 sensor_aux_vectors( sensor_response_f, sensor_response_pol,
01097 sensor_response_za, sensor_response_aa,
01098 sensor_response_f_grid, sensor_response_pol_grid,
01099 sensor_response_za_grid, sensor_response_aa_grid );
01100 }
01101
01102
01103
01104
01105 void sensor_responseIF2RF(
01106
01107 Vector& sensor_response_f,
01108 Vector& sensor_response_f_grid,
01109
01110 const Numeric& lo,
01111 const String& sideband_mode )
01112 {
01113
01114
01115 Numeric f_lim = 30e9;
01116 if( max(sensor_response_f_grid) > f_lim )
01117 throw runtime_error( "The frequencies seem to already be given in RF." );
01118
01119
01120
01121 if( sideband_mode == "lower" )
01122 {
01123 sensor_response_f *= -1;
01124 sensor_response_f_grid *= -1;
01125 sensor_response_f += lo;
01126 sensor_response_f_grid += lo;
01127 }
01128
01129
01130 else if( sideband_mode=="upper" )
01131 {
01132 sensor_response_f += lo;
01133 sensor_response_f_grid += lo;
01134 }
01135
01136
01137 else
01138 {
01139 throw runtime_error(
01140 "Only allowed options for *sideband _mode* are \"lower\" and \"upper\"." );
01141 }
01142 }
01143
01144
01145
01146
01147 void sensor_responseInit(
01148
01149 Sparse& sensor_response,
01150 Vector& sensor_response_f,
01151 ArrayOfIndex& sensor_response_pol,
01152 Vector& sensor_response_za,
01153 Vector& sensor_response_aa,
01154 Vector& sensor_response_f_grid,
01155 ArrayOfIndex& sensor_response_pol_grid,
01156 Vector& sensor_response_za_grid,
01157 Vector& sensor_response_aa_grid,
01158
01159 const Vector& f_grid,
01160 const Vector& mblock_za_grid,
01161 const Vector& mblock_aa_grid,
01162 const Index& antenna_dim,
01163 const Index& atmosphere_dim,
01164 const Index& stokes_dim,
01165 const Index& sensor_norm )
01166 {
01167
01168
01169
01170 chk_if_in_range( "stokes_dim", stokes_dim, 1, 4 );
01171 chk_if_in_range( "antenna_dim", antenna_dim, 1, 2 );
01172 chk_if_bool( "sensor_norm", sensor_norm );
01173
01174
01175
01176 chk_if_increasing( "f_grid", f_grid );
01177
01178
01179 if( mblock_za_grid.nelem() == 0 )
01180 throw runtime_error( "The measurement block zenith angle grid is empty." );
01181 if( !is_increasing(mblock_za_grid) && !is_decreasing(mblock_za_grid) )
01182 throw runtime_error(
01183 "The WSV *mblock_za_grid* must be strictly increasing or decreasing." );
01184
01185
01186 if( antenna_dim == 1 )
01187 {
01188 if( mblock_aa_grid.nelem() != 0 )
01189 throw runtime_error(
01190 "For antenna_dim = 1, the azimuthal angle grid must be empty." );
01191 }
01192 else
01193 {
01194 if( atmosphere_dim < 3 )
01195 throw runtime_error( "2D antennas (antenna_dim=2) can only be "
01196 "used with 3D atmospheres." );
01197 if( mblock_aa_grid.nelem() == 0 )
01198 {
01199 ostringstream os;
01200 os << "The measurement block azimuthal angle grid is empty despite"
01201 << "a 2D antenna pattern is flagged (*antenna_dim*).";
01202 throw runtime_error( os.str() );
01203 }
01204 if( !is_increasing(mblock_za_grid) && !is_decreasing(mblock_za_grid) )
01205 throw runtime_error(
01206 "The WSV *mblock_aa_grid* must be strictly increasing or decreasing." );
01207 }
01208
01209
01210
01211 sensor_response_f_grid = f_grid;
01212 sensor_response_za_grid = mblock_za_grid;
01213 sensor_response_aa_grid = mblock_aa_grid;
01214
01215 sensor_response_pol_grid.resize(stokes_dim);
01216
01217 for( Index is=0; is<stokes_dim; is++ )
01218 {
01219 sensor_response_pol_grid[is] = is + 1;
01220 }
01221
01222
01223
01224 sensor_aux_vectors( sensor_response_f, sensor_response_pol,
01225 sensor_response_za, sensor_response_aa,
01226 sensor_response_f_grid, sensor_response_pol_grid,
01227 sensor_response_za_grid, sensor_response_aa_grid );
01228
01229
01230
01231 const Index n = sensor_response_f.nelem();
01232
01233 out2 << " Initialising *sensor_reponse* as a identity matrix.\n";
01234 out3 << " Size of *sensor_response*: " << n << "x" << n << "\n";
01235
01236 sensor_response.make_I( n, n );
01237 }
01238
01239
01240
01241
01242 void sensor_responseMixer(
01243
01244 Sparse& sensor_response,
01245 Vector& sensor_response_f,
01246 ArrayOfIndex& sensor_response_pol,
01247 Vector& sensor_response_za,
01248 Vector& sensor_response_aa,
01249 Vector& sensor_response_f_grid,
01250
01251 const ArrayOfIndex& sensor_response_pol_grid,
01252 const Vector& sensor_response_za_grid,
01253 const Vector& sensor_response_aa_grid,
01254 const Numeric& lo,
01255 const GField1& sideband_response,
01256 const Index& sensor_norm )
01257 {
01258
01259 const Index nf = sensor_response_f_grid.nelem();
01260 const Index npol = sensor_response_pol_grid.nelem();
01261 const Index nza = sensor_response_za_grid.nelem();
01262 const Index naa = sensor_response_aa_grid.nelem();
01263 const Index nin = nf * npol * nza;
01264
01265
01266
01267 ConstVectorView sbresponse_f_grid =
01268 sideband_response.get_numeric_grid(GFIELD1_F_GRID);
01269
01270
01271 ostringstream os;
01272 bool error_found = false;
01273
01274
01275 if( sensor_response_f.nelem() != nin )
01276 {
01277 os << "Inconsistency in size between *sensor_response_f* and the sensor\n"
01278 << "grid variables (sensor_response_f_grid etc.).\n";
01279 error_found = true;
01280 }
01281 if( naa && naa != nza )
01282 {
01283 os << "Incorrect size of *sensor_response_aa_grid*.\n";
01284 error_found = true;
01285 }
01286 if( sensor_response.nrows() != nin )
01287 {
01288 os << "The sensor block response matrix *sensor_response* does not have\n"
01289 << "right size compared to the sensor grid variables\n"
01290 << "(sensor_response_f_grid etc.).\n";
01291 error_found = true;
01292 }
01293
01294
01295 if( lo <= sensor_response_f_grid[0] || lo >= last(sensor_response_f_grid) )
01296 {
01297 os << "The given local oscillator frequency is outside the sensor\n"
01298 << "frequency grid. It must be within the *sensor_response_f_grid*.\n";
01299 error_found = true;
01300 }
01301
01302
01303 if( sbresponse_f_grid.nelem() != sideband_response.nelem() )
01304 {
01305 os << "Mismatch in size of grid and data in *sideband_response*.\n";
01306 error_found = true;
01307 }
01308 if( sbresponse_f_grid.nelem() < 2 )
01309 {
01310 os << "At least two data points must be specified in "
01311 << "*sideband_response*.\n";
01312 error_found = true;
01313 }
01314 if( !is_increasing( sbresponse_f_grid ) )
01315 {
01316 os << "The frequency grid of *sideband_response* must be strictly\n"
01317 << "increasing.\n";
01318 error_found = true;
01319 }
01320 if( fabs(last(sbresponse_f_grid)+sbresponse_f_grid[0]) > 1e3 )
01321 {
01322 os << "The end points of the *sideband_response* frequency grid must be\n"
01323 << "symmetrically placed around 0. That is, the grid shall cover a\n"
01324 << "a range that can be written as [-df,df]. \n";
01325 error_found = true;
01326 }
01327
01328
01329 Numeric df_high = lo + last(sbresponse_f_grid) - last(sensor_response_f_grid);
01330 Numeric df_low = sensor_response_f_grid[0] - lo - sbresponse_f_grid[0];
01331 if( df_high > 0 && df_low > 0 )
01332 {
01333 os << "The *sensor_response_f* grid must be extended by at least\n"
01334 << df_low << " Hz in the lower end and " << df_high << " Hz in the\n"
01335 << "upper end to cover frequency range set by *sideband_response*\n"
01336 << "and *lo*. Or can the frequency grid of *sideband_response* be\n"
01337 << "decreased?";
01338 error_found = true;
01339 }
01340 else if( df_high > 0 )
01341 {
01342 os << "The *sensor_response_f* grid must be extended by at " << df_high
01343 << " Hz\nin the upper end to cover frequency range set by\n"
01344 << "*sideband_response* and *lo*. Or can the frequency grid of\n"
01345 << "*sideband_response* be decreased?";
01346 error_found = true;
01347 }
01348 else if( df_low > 0 )
01349 {
01350 os << "The *sensor_response_f* grid must be extended by at " << df_low
01351 << " Hz\nin the lower end to cover frequency range set by\n"
01352 << "*sideband_response* and *lo*. Or can the frequency grid of\n"
01353 << "*sideband_response* be decreased?";
01354 error_found = true;
01355 }
01356
01357
01358
01359 if (error_found)
01360 throw runtime_error(os.str());
01361
01362
01363
01364
01365 Sparse hmixer;
01366 Vector f_mixer;
01367
01368 mixer_matrix( hmixer, f_mixer, lo, sideband_response,
01369 sensor_response_f_grid, npol, nza, sensor_norm );
01370
01371
01372
01373
01374 Sparse htmp = sensor_response;
01375 sensor_response.resize( hmixer.nrows(), htmp.ncols() );
01376 mult( sensor_response, hmixer, htmp );
01377
01378
01379 out3 << " Size of *sensor_response*: " << sensor_response.nrows()
01380 << "x" << sensor_response.ncols() << "\n";
01381
01382
01383 sensor_response_f_grid = f_mixer;
01384
01385
01386 sensor_aux_vectors( sensor_response_f, sensor_response_pol,
01387 sensor_response_za, sensor_response_aa,
01388 sensor_response_f_grid, sensor_response_pol_grid,
01389 sensor_response_za_grid, sensor_response_aa_grid );
01390 }
01391
01392
01393
01394 void sensor_responseMultiMixerBackend(
01395
01396 Sparse& sensor_response,
01397 Vector& sensor_response_f,
01398 ArrayOfIndex& sensor_response_pol,
01399 Vector& sensor_response_za,
01400 Vector& sensor_response_aa,
01401 Vector& sensor_response_f_grid,
01402
01403 const ArrayOfIndex& sensor_response_pol_grid,
01404 const Vector& sensor_response_za_grid,
01405 const Vector& sensor_response_aa_grid,
01406 const Vector& lo_multi,
01407 const ArrayOfGField1& sideband_response_multi,
01408 const ArrayOfString& sideband_mode_multi,
01409 const ArrayOfVector& f_backend_multi,
01410 const ArrayOfArrayOfGField1& backend_channel_response_multi,
01411 const Index& sensor_norm )
01412 {
01413
01414 const Index nf = sensor_response_f_grid.nelem();
01415 const Index npol = sensor_response_pol_grid.nelem();
01416 const Index nza = sensor_response_za_grid.nelem();
01417 const Index naa = sensor_response_aa_grid.nelem();
01418 const Index nin = nf * npol * nza;
01419
01420 const Index nlo = lo_multi.nelem();
01421
01422
01423 ostringstream os;
01424 bool error_found = false;
01425
01426
01427 if( sensor_response_f.nelem() != nin )
01428 {
01429 os << "Inconsistency in size between *sensor_response_f* and the sensor\n"
01430 << "grid variables (sensor_response_f_grid etc.).\n";
01431 error_found = true;
01432 }
01433 if( naa && naa != nza )
01434 {
01435 os << "Incorrect size of *sensor_response_aa_grid*.\n";
01436 error_found = true;
01437 }
01438 if( sensor_response.nrows() != nin )
01439 {
01440 os << "The sensor block response matrix *sensor_response* does not have\n"
01441 << "right size compared to the sensor grid variables\n"
01442 << "(sensor_response_f_grid etc.).\n";
01443 error_found = true;
01444 }
01445
01446
01447
01448 if( sideband_response_multi.nelem() != nlo )
01449 {
01450 os << "Inconsistency in length between *lo_mixer* and "
01451 << "*sideband_response_multi*.\n";
01452 error_found = true;
01453 }
01454 if( sideband_mode_multi.nelem() != nlo )
01455 {
01456 os << "Inconsistency in length between *lo_mixer* and "
01457 << "*sideband_mode_multi*.\n";
01458 error_found = true;
01459 }
01460 if( f_backend_multi.nelem() != nlo )
01461 {
01462 os << "Inconsistency in length between *lo_mixer* and "
01463 << "*f_backend_multi*.\n";
01464 error_found = true;
01465 }
01466 if( backend_channel_response_multi.nelem() != nlo )
01467 {
01468 os << "Inconsistency in length between *lo_mixer* and "
01469 << "*backend_channel_response_multi*.\n";
01470 error_found = true;
01471 }
01472
01473
01474
01475 if (error_found)
01476 throw runtime_error(os.str());
01477
01478
01479
01480 Array<Sparse> sr;
01481 ArrayOfVector srfgrid;
01482 Index ntot = 0, nftot = 0;
01483
01484 for( Index ilo=0; ilo<nlo; ilo++ )
01485 {
01486
01487
01488 Sparse sr1 = sensor_response;
01489 Vector srf1 = sensor_response_f;
01490 ArrayOfIndex srpol1 = sensor_response_pol;
01491 Vector srza1 = sensor_response_za;
01492 Vector sraa1 = sensor_response_aa;
01493 Vector srfgrid1 = sensor_response_f_grid;
01494
01495
01496 try
01497 {
01498 sensor_responseMixer( sr1, srf1, srpol1, srza1, sraa1, srfgrid1,
01499 sensor_response_pol_grid,
01500 sensor_response_za_grid,
01501 sensor_response_aa_grid,
01502 lo_multi[ilo],
01503 sideband_response_multi[ilo],
01504 sensor_norm );
01505
01506 sensor_responseIF2RF( srf1, srfgrid1,
01507 lo_multi[ilo],
01508 sideband_mode_multi[ilo] );
01509
01510 sensor_responseBackend( sr1, srf1, srpol1, srza1, sraa1, srfgrid1,
01511 sensor_response_pol_grid,
01512 sensor_response_za_grid,
01513 sensor_response_aa_grid,
01514 f_backend_multi[ilo],
01515 backend_channel_response_multi[ilo],
01516 sensor_norm );
01517 }
01518 catch( runtime_error e )
01519 {
01520 ostringstream os2;
01521 os2 << "Error when dealing with receiver/mixer chain (1-based index) "
01522 << ilo+1 << ":\n" << e.what();
01523 throw runtime_error(os2.str());
01524 }
01525
01526
01527 sr.push_back( sr1 );
01528 srfgrid.push_back( srfgrid1 );
01529
01530 ntot += sr1.nrows();
01531 nftot += srfgrid1.nelem();
01532 }
01533
01534
01535
01536 const Index ncols = sr[0].ncols();
01537 Index row0 = 0, if0 = 0;
01538 Vector dummy( ncols, 0.0 );
01539
01540 sensor_response.resize( ntot, ncols );
01541 sensor_response_f_grid.resize( nftot );
01542
01543 for( Index ilo=0; ilo<nlo; ilo++ )
01544 {
01545 for( Index row=0; row<sr[ilo].nrows(); row++ )
01546 {
01547
01548 for( Index ic=0; ic<ncols; ic++ )
01549 { dummy[ic] = sr[ilo](row,ic); }
01550
01551 sensor_response.insert_row( row0+row, dummy );
01552 }
01553 row0 += sr[ilo].nrows();
01554
01555 for( Index i=0; i<srfgrid[ilo].nelem(); i++ )
01556 {
01557 sensor_response_f_grid[if0+i] = srfgrid[ilo][i];
01558 }
01559 if0 += srfgrid[ilo].nelem();
01560 }
01561
01562
01563 sensor_aux_vectors( sensor_response_f, sensor_response_pol,
01564 sensor_response_za, sensor_response_aa,
01565 sensor_response_f_grid, sensor_response_pol_grid,
01566 sensor_response_za_grid, sensor_response_aa_grid );
01567 }
01568
01569
01570
01571
01572
01573
01574
01575
01576
01577
01578
01579
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592
01593
01594
01595
01596
01597
01598
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608
01609
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01669
01670
01671
01672
01673
01674
01675
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685
01686
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746