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
00036
00037
00038
00039
00040 #include <cmath>
00041 #include <stdexcept>
00042 #include "auto_md.h"
00043 #include "check_input.h"
00044 #include "logic.h"
00045 #include "math_funcs.h"
00046 #include "physics_funcs.h"
00047 #include "ppath.h"
00048 #include "rte.h"
00049 #include "special_interp.h"
00050 #include "lin_alg.h"
00051
00052
00053
00054
00055
00056
00057
00058
00060
00072 void apply_y_unit(
00073 MatrixView iy,
00074 const String& y_unit,
00075 const Vector& f_grid )
00076 {
00077 assert( f_grid.nelem() == iy.nrows() );
00078
00079 if( y_unit == "1" )
00080 {}
00081
00082 else if( y_unit == "RJBT" )
00083 {
00084 for( Index iv=0; iv<f_grid.nelem(); iv++ )
00085 {
00086 const Numeric scfac = invrayjean( 1, f_grid[iv] );
00087 for( Index icol=0; icol<iy.ncols(); icol++ )
00088 {
00089 iy(iv,icol) *= scfac;
00090 }
00091 }
00092 }
00093
00094 else if( y_unit == "PlanckBT" )
00095 {
00096 for( Index iv=0; iv<f_grid.nelem(); iv++ )
00097 {
00098 for( Index icol=0; icol<iy.ncols(); icol++ )
00099 {
00100 iy(iv,icol) = invplanck( iy(iv,icol), f_grid[iv] );
00101 }
00102 }
00103 }
00104 else
00105 {
00106 ostringstream os;
00107 os << "Unknown option: y_unit = \"" << y_unit << "\"\n"
00108 << "Recognised choices are: \"1\", \"RJBT\" and \"PlanckBT\"";
00109 throw runtime_error( os.str() );
00110 }
00111
00112
00113 }
00114
00115
00116
00118
00130 void apply_y_unit_single(
00131 Vector& i,
00132 const String& y_unit,
00133 const Numeric& f )
00134 {
00135
00136 Vector f_grid(1,f);
00137
00138
00139 Matrix iy(1,i.nelem());
00140 iy(0,joker) = i;
00141
00142 apply_y_unit( iy, y_unit, f_grid );
00143
00144 i = iy(0,joker);
00145 }
00146
00147
00148
00150
00193 void get_radiative_background(
00194 Workspace& ws,
00195 Matrix& iy,
00196 Ppath& ppath,
00197 Index& ppath_array_index,
00198 ArrayOfPpath& ppath_array,
00199 ArrayOfTensor4& diy_dvmr,
00200 ArrayOfTensor4& diy_dt,
00201 const Agenda& ppath_step_agenda,
00202 const Agenda& rte_agenda,
00203 const Agenda& surface_prop_agenda,
00204 const Agenda& iy_space_agenda,
00205 const Agenda& iy_cloudbox_agenda,
00206 const Index& atmosphere_dim,
00207 const Vector& p_grid,
00208 const Vector& lat_grid,
00209 const Vector& lon_grid,
00210 const Tensor3& z_field,
00211 const Tensor3& t_field,
00212 const Tensor4& vmr_field,
00213 const Matrix& r_geoid,
00214 const Matrix& z_surface,
00215 const Index& cloudbox_on,
00216 const ArrayOfIndex& cloudbox_limits,
00217 const Vector& f_grid,
00218 const Index& stokes_dim,
00219 const Index& ppath_array_do,
00220 const ArrayOfIndex& rte_do_vmr_jacs,
00221 const Index& rte_do_t_jacs )
00222 {
00223
00224 const Index nf = f_grid.nelem();
00225 const Index np = ppath.np;
00226
00227
00228
00229
00230
00231
00232
00233
00234 Vector rte_pos;
00235 Vector rte_los;
00236 GridPos rte_gp_p;
00237 GridPos rte_gp_lat;
00238 GridPos rte_gp_lon;
00239 rte_pos.resize( atmosphere_dim );
00240 rte_pos = ppath.pos(np-1,Range(0,atmosphere_dim));
00241 rte_los.resize( ppath.los.ncols() );
00242 rte_los = ppath.los(np-1,joker);
00243 gridpos_copy( rte_gp_p, ppath.gp_p[np-1] );
00244 if( atmosphere_dim > 1 )
00245 { gridpos_copy( rte_gp_lat, ppath.gp_lat[np-1] ); }
00246 if( atmosphere_dim > 2 )
00247 { gridpos_copy( rte_gp_lon, ppath.gp_lon[np-1] ); }
00248
00249 out3 << "Radiative background: " << ppath.background << "\n";
00250
00251
00252
00253 switch ( ppath_what_background( ppath ) )
00254 {
00255
00256 case 1:
00257 {
00258 chk_not_empty( "iy_space_agenda", iy_space_agenda );
00259
00260 iy_space_agendaExecute( ws, iy, rte_pos, rte_los,
00261 iy_space_agenda );
00262
00263 if( iy.nrows() != nf || iy.ncols() != stokes_dim )
00264 {
00265 out1 << "expected size = [" << nf << "," << stokes_dim << "]\n";
00266 out1 << "iy size = [" << iy.nrows() << "," << iy.ncols()<< "]\n";
00267 throw runtime_error( "The size of *iy* returned from "
00268 "*iy_space_agenda* is not correct.");
00269 }
00270 }
00271 break;
00272
00273
00274 case 2:
00275 {
00276
00277
00278 chk_not_empty( "surface_prop_agenda", surface_prop_agenda );
00279
00280 Matrix surface_los;
00281 Tensor4 surface_rmatrix;
00282 Matrix surface_emission;
00283
00284 surface_prop_agendaExecute( ws, surface_emission, surface_los,
00285 surface_rmatrix, rte_pos, rte_los,
00286 rte_gp_p, rte_gp_lat, rte_gp_lon,
00287 surface_prop_agenda );
00288
00289
00290
00291 const Index nlos = surface_los.nrows();
00292 if( nlos )
00293 {
00294 if( surface_los.ncols() != rte_los.nelem() )
00295 throw runtime_error(
00296 "Number of columns in *surface_los* is not correct." );
00297 if( nlos != surface_rmatrix.nbooks() )
00298 throw runtime_error(
00299 "Mismatch in size of *surface_los* and *surface_rmatrix*." );
00300 if( surface_rmatrix.npages() != nf )
00301 throw runtime_error(
00302 "Mismatch in size of *surface_rmatrix* and *f_grid*." );
00303 if( surface_rmatrix.ncols() != stokes_dim ||
00304 surface_rmatrix.ncols() != stokes_dim )
00305 throw runtime_error(
00306 "Mismatch between size of *surface_rmatrix* and *stokes_dim*." );
00307 }
00308 if( surface_emission.ncols() != stokes_dim )
00309 throw runtime_error(
00310 "Mismatch between size of *surface_emission* and *stokes_dim*." );
00311 if( surface_emission.nrows() != nf )
00312 throw runtime_error(
00313 "Mismatch in size of *surface_emission* and f_grid*." );
00314
00315
00316
00317 Tensor3 I( nlos, nf, stokes_dim );
00318
00319
00320 if( nlos > 0 )
00321 {
00322
00323 Ppath pp_copy;
00324 ppath_init_structure( pp_copy, atmosphere_dim, ppath.np );
00325 ppath_copy( pp_copy, ppath );
00326
00327 const Index pai = ppath_array_index;
00328
00329 for( Index ilos=0; ilos<nlos; ilos++ )
00330 {
00331
00332 iy_calc( ws, iy, ppath, ppath_array_index, ppath_array,
00333 diy_dvmr, diy_dt, ppath_step_agenda, rte_agenda,
00334 iy_space_agenda, surface_prop_agenda, iy_cloudbox_agenda,
00335 atmosphere_dim, p_grid, lat_grid, lon_grid, z_field,
00336 t_field, vmr_field, r_geoid, z_surface, cloudbox_on,
00337 cloudbox_limits, rte_pos, surface_los(ilos,joker), f_grid,
00338 stokes_dim, ppath_array_do, rte_do_vmr_jacs, rte_do_t_jacs );
00339
00340 I(ilos,joker,joker) = iy;
00341
00342
00343
00344
00345
00346 const bool pol_r = true;
00347
00348 if( rte_do_vmr_jacs.nelem() )
00349 {
00350 for( Index iv=0; iv<nf; iv++ )
00351 {
00352 include_trans_in_diy_dq( diy_dvmr, iv, pol_r,
00353 surface_rmatrix(ilos,iv,joker,joker),
00354 ppath_array, ppath_array_index );
00355 }
00356 }
00357 if( rte_do_t_jacs )
00358 {
00359 for( Index iv=0; iv<nf; iv++ )
00360 {
00361 include_trans_in_diy_dq( diy_dt, iv, pol_r,
00362 surface_rmatrix(ilos,iv,joker,joker),
00363 ppath_array, ppath_array_index );
00364 }
00365 }
00366
00367
00368 ppath_array_index = pai;
00369 }
00370
00371
00372 ppath_init_structure( ppath, atmosphere_dim, pp_copy.np );
00373 ppath_copy( ppath, pp_copy );
00374 }
00375
00376
00377 surface_calc( iy, I, surface_los, surface_rmatrix, surface_emission );
00378 }
00379 break;
00380
00381
00382 case 3:
00383 {
00384
00385
00386 Ppath ppath_local;
00387 ppath_init_structure( ppath_local, atmosphere_dim, ppath.np );
00388 ppath_copy( ppath_local, ppath );
00389
00390 chk_not_empty( "iy_cloudbox_agenda", iy_cloudbox_agenda );
00391
00392 iy_cloudbox_agendaExecute( ws, iy, ppath_local,
00393 rte_pos, rte_los, rte_gp_p,
00394 rte_gp_lat, rte_gp_lon,
00395 iy_cloudbox_agenda );
00396
00397 if( iy.nrows() != nf || iy.ncols() != stokes_dim )
00398 {
00399 out1 << "expected size = [" << nf << "," << stokes_dim << "]\n";
00400 out1 << "iy size = [" << iy.nrows() << "," << iy.ncols()<< "]\n";
00401 throw runtime_error( "The size of *iy* returned from "
00402 "*iy_cloudbox_agenda* is not correct." );
00403 }
00404 }
00405 break;
00406
00407
00408 case 4:
00409 {
00410 chk_not_empty( "iy_cloudbox_agenda", iy_cloudbox_agenda );
00411
00412 iy_cloudbox_agendaExecute( ws, iy, ppath, rte_pos, rte_los, rte_gp_p,
00413 rte_gp_lat, rte_gp_lon, iy_cloudbox_agenda );
00414
00415 if( iy.nrows() != nf || iy.ncols() != stokes_dim )
00416 {
00417 out1 << "expected size = [" << nf << "," << stokes_dim << "]\n";
00418 out1 << "iy size = [" << iy.nrows() << "," << iy.ncols()<< "]\n";
00419 throw runtime_error( "The size of *iy* returned from "
00420 "*iy_cloudbox_agenda* is not correct." );
00421 }
00422 }
00423 break;
00424
00425
00426 default:
00427
00428 assert( false );
00429 }
00430 }
00431
00432
00433
00435
00455 void include_cumtrans_in_diy_dq(
00456 Tensor4& diy_dq,
00457 Matrix& trans,
00458 const Index& iv,
00459 const bool& any_trans_polarised,
00460 const Tensor3& ppath_transmissions )
00461 {
00462 const Index stokes_dim = diy_dq.ncols();
00463 const Index np = diy_dq.npages();
00464 const Index ng = diy_dq.nbooks();
00465
00466 if( any_trans_polarised )
00467 {
00468 Matrix mtmp( stokes_dim, stokes_dim );
00469 Vector vtmp( stokes_dim );
00470
00471
00472 id_mat( trans );
00473
00474 for( Index ip=0; ip<np-1; ip++ )
00475 {
00476 mtmp = trans;
00477 mult( trans, ppath_transmissions(ip,joker,joker), mtmp );
00478 for( Index ig=0; ig<ng; ig++ )
00479 {
00480 vtmp = diy_dq(ig,ip+1,iv,joker);
00481 mult( diy_dq(ig,ip+1,iv,joker), trans, vtmp );
00482 }
00483 }
00484 }
00485 else
00486 {
00487
00488 id_mat( trans );
00489
00490 for( Index ip=0; ip<np-1; ip++ )
00491 {
00492 for( Index is=0; is<stokes_dim; is++ )
00493 {
00494 trans(is,is) *= ppath_transmissions(ip,is,is);
00495 for( Index ig=0; ig<ng; ig++ )
00496 { diy_dq(ig,ip+1,iv,is) *= trans(is,is); }
00497 }
00498 }
00499 }
00500 }
00501
00502
00503
00505
00526 void include_trans_in_diy_dq(
00527 ArrayOfTensor4& diy_dq,
00528 const Index& iv,
00529 bool pol_trans,
00530 ConstMatrixView trans,
00531 const ArrayOfPpath& ppath_array,
00532 const Index& ppath_array_index )
00533 {
00534 const Index stokes_dim = diy_dq[0].ncols();
00535
00536 if( stokes_dim == 1 )
00537 { pol_trans = false; }
00538
00539 Index pai = ppath_array_index;
00540
00541 if( pol_trans )
00542 {
00543 for( Index ig=0; ig<diy_dq[pai].nbooks(); ig++ )
00544 {
00545 for( Index ip=0; ip<ppath_array[pai].np; ip++ )
00546 {
00547 const Vector vtmp = diy_dq[pai](ig,ip,iv,joker);
00548 mult( diy_dq[pai](ig,ip,iv,joker), trans, vtmp );
00549 }
00550 }
00551 }
00552 else
00553 {
00554 for( Index ig=0; ig<diy_dq[pai].nbooks(); ig++ )
00555 {
00556 for( Index ip=0; ip<ppath_array[pai].np; ip++ )
00557 {
00558 for( Index is=0; is<stokes_dim; is++ )
00559 { diy_dq[pai](ig,ip,iv,is) *= trans(is,is); }
00560 }
00561 }
00562 }
00563
00564 for( Index ia=0; ia<ppath_array[ppath_array_index].next_parts.nelem(); ia++ )
00565 {
00566 pai = ppath_array[ppath_array_index].next_parts[ia];
00567 include_trans_in_diy_dq( diy_dq, iv, pol_trans, trans, ppath_array, pai );
00568 }
00569 }
00570
00571
00572
00574
00622 void iy_calc( Workspace& ws,
00623 Matrix& iy,
00624 Ppath& ppath,
00625 Index& ppath_array_index,
00626 ArrayOfPpath& ppath_array,
00627 ArrayOfTensor4& diy_dvmr,
00628 ArrayOfTensor4& diy_dt,
00629 const Agenda& ppath_step_agenda,
00630 const Agenda& rte_agenda,
00631 const Agenda& iy_space_agenda,
00632 const Agenda& surface_prop_agenda,
00633 const Agenda& iy_cloudbox_agenda,
00634 const Index& atmosphere_dim,
00635 const Vector& p_grid,
00636 const Vector& lat_grid,
00637 const Vector& lon_grid,
00638 const Tensor3& z_field,
00639 const Tensor3& t_field,
00640 const Tensor4& vmr_field,
00641 const Matrix& r_geoid,
00642 const Matrix& z_surface,
00643 const Index& cloudbox_on,
00644 const ArrayOfIndex& cloudbox_limits,
00645 const Vector& pos,
00646 const Vector& los,
00647 const Vector& f_grid,
00648 const Index& stokes_dim,
00649 const Index& ppath_array_do,
00650 const ArrayOfIndex& rte_do_vmr_jacs,
00651 const Index& rte_do_t_jacs )
00652 {
00653
00654 const bool outside_cloudbox = true;
00655 ppath_calc( ws, ppath, ppath_step_agenda, atmosphere_dim, p_grid,
00656 lat_grid, lon_grid, z_field, r_geoid, z_surface,
00657 cloudbox_on, cloudbox_limits, pos, los, outside_cloudbox );
00658
00659 const Index np = ppath.np;
00660
00661
00662
00663 if( np > 1 )
00664 {
00665
00666 ppath.p.resize(np);
00667 Matrix itw_p(np,2);
00668 interpweights( itw_p, ppath.gp_p );
00669 itw2p( ppath.p, p_grid, ppath.gp_p, itw_p );
00670
00671
00672 ppath.t.resize(np);
00673 Matrix itw_field;
00674 interp_atmfield_gp2itw( itw_field, atmosphere_dim, p_grid, lat_grid,
00675 lon_grid, ppath.gp_p, ppath.gp_lat, ppath.gp_lon );
00676 interp_atmfield_by_itw( ppath.t, atmosphere_dim, p_grid, lat_grid,
00677 lon_grid, t_field, ppath.gp_p,
00678 ppath.gp_lat, ppath.gp_lon, itw_field );
00679
00680
00681 const Index ns = vmr_field.nbooks();
00682 ppath.vmr.resize(ns,np);
00683 for( Index is=0; is<ns; is++ )
00684 {
00685 interp_atmfield_by_itw( ppath.vmr(is, joker), atmosphere_dim,
00686 p_grid, lat_grid, lon_grid, vmr_field( is, joker, joker, joker ),
00687 ppath.gp_p, ppath.gp_lat, ppath.gp_lon, itw_field );
00688 }
00689 }
00690
00691
00692
00693 if( ppath_array_do )
00694 {
00695
00696
00697 if( ppath_array_index >= 0 )
00698 { ppath_array[ppath_array_index].next_parts.push_back(
00699 ppath_array.nelem() ); }
00700
00701
00702 ppath_array_index = ppath_array.nelem();
00703 ppath_array.push_back( ppath );
00704
00705
00706
00707 Index n = np;
00708 if( np == 1 )
00709 { n = 0; }
00710
00711 if( rte_do_vmr_jacs.nelem() )
00712 {
00713 diy_dvmr.push_back(
00714 Tensor4(rte_do_vmr_jacs.nelem(),n,f_grid.nelem(),stokes_dim,0.0) );
00715 }
00716 if( rte_do_t_jacs )
00717 {
00718 diy_dt.push_back( Tensor4(1,n,f_grid.nelem(),stokes_dim,0.0) );
00719 }
00720 }
00721
00722
00723
00724
00725 iy.resize(f_grid.nelem(),stokes_dim);
00726
00727 get_radiative_background( ws, iy, ppath, ppath_array_index,
00728 ppath_array, diy_dvmr, diy_dt, ppath_step_agenda, rte_agenda,
00729 surface_prop_agenda, iy_space_agenda, iy_cloudbox_agenda,
00730 atmosphere_dim, p_grid, lat_grid, lon_grid, z_field, t_field,
00731 vmr_field, r_geoid, z_surface, cloudbox_on, cloudbox_limits,
00732 f_grid, stokes_dim, ppath_array_do, rte_do_vmr_jacs,
00733 rte_do_t_jacs );
00734
00735
00736
00737
00738 if( np > 1 )
00739 {
00740 rte_agendaExecute( ws, iy, diy_dvmr, diy_dt, ppath,
00741 ppath_array, ppath_array_index,
00742 rte_do_vmr_jacs, rte_do_t_jacs,
00743 stokes_dim, f_grid, rte_agenda );
00744 }
00745 }
00746
00747
00748
00750
00753 void iy_calc_no_jacobian(
00754 Workspace& ws,
00755 Matrix& iy,
00756 Ppath& ppath,
00757 const Agenda& ppath_step_agenda,
00758 const Agenda& rte_agenda,
00759 const Agenda& iy_space_agenda,
00760 const Agenda& surface_prop_agenda,
00761 const Agenda& iy_cloudbox_agenda,
00762 const Index& atmosphere_dim,
00763 const Vector& p_grid,
00764 const Vector& lat_grid,
00765 const Vector& lon_grid,
00766 const Tensor3& z_field,
00767 const Tensor3& t_field,
00768 const Tensor4& vmr_field,
00769 const Matrix& r_geoid,
00770 const Matrix& z_surface,
00771 const Index& cloudbox_on,
00772 const ArrayOfIndex& cloudbox_limits,
00773 const Vector& pos,
00774 const Vector& los,
00775 const Vector& f_grid,
00776 const Index& stokes_dim )
00777 {
00778 ArrayOfIndex rte_do_vmr_jacs(0);
00779 ArrayOfTensor4 diy_dvmr(0);
00780 Index rte_do_t_jacs=0;
00781 ArrayOfTensor4 diy_dt(0);
00782 Index ppath_array_do = 0;
00783 ArrayOfPpath ppath_array(0);
00784 Index ppath_array_index=-1;
00785
00786 iy_calc( ws, iy, ppath,
00787 ppath_array_index, ppath_array, diy_dvmr, diy_dt,
00788 ppath_step_agenda, rte_agenda, iy_space_agenda, surface_prop_agenda,
00789 iy_cloudbox_agenda, atmosphere_dim, p_grid, lat_grid, lon_grid,
00790 z_field, t_field, vmr_field, r_geoid, z_surface, cloudbox_on,
00791 cloudbox_limits, pos, los, f_grid, stokes_dim,
00792 ppath_array_do,
00793 rte_do_vmr_jacs, rte_do_t_jacs );
00794 }
00795
00796
00797
00799
00843 void rte_step_std(
00844 VectorView stokes_vec,
00845 MatrixView trans_mat,
00846
00847 ConstMatrixView ext_mat_av,
00848 ConstVectorView abs_vec_av,
00849 ConstVectorView sca_vec_av,
00850 const Numeric& l_step,
00851 const Numeric& rte_planck_value )
00852 {
00853
00854 Index stokes_dim = stokes_vec.nelem();
00855
00856
00857 assert(is_size(trans_mat, stokes_dim, stokes_dim));
00858 assert(is_size(ext_mat_av, stokes_dim, stokes_dim));
00859 assert(is_size(abs_vec_av, stokes_dim));
00860 assert(is_size(sca_vec_av, stokes_dim));
00861 assert( rte_planck_value >= 0 );
00862 assert( l_step >= 0 );
00863 assert (!is_singular( ext_mat_av ));
00864
00865
00866
00867 bool unpol_abs_vec = true;
00868
00869 for (Index i = 1; i < stokes_dim; i++)
00870 if (abs_vec_av[i] != 0)
00871 unpol_abs_vec = false;
00872
00873 bool unpol_sca_vec = true;
00874
00875 for (Index i = 1; i < stokes_dim; i++)
00876 if (sca_vec_av[i] != 0)
00877 unpol_sca_vec = false;
00878
00879
00880
00881 if( stokes_dim == 1 )
00882 {
00883 trans_mat(0,0) = exp(-ext_mat_av(0,0) * l_step);
00884 stokes_vec[0] = stokes_vec[0] * trans_mat(0,0) +
00885 (abs_vec_av[0] * rte_planck_value + sca_vec_av[0]) /
00886 ext_mat_av(0,0) * (1 - trans_mat(0,0));
00887 }
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897 else if( is_diagonal(ext_mat_av) && unpol_abs_vec && unpol_sca_vec )
00898 {
00899 trans_mat = 0;
00900 trans_mat(0,0) = exp(-ext_mat_av(0,0) * l_step);
00901
00902
00903
00904
00905 stokes_vec[0] = stokes_vec[0] * trans_mat(0,0) +
00906 (abs_vec_av[0] * rte_planck_value + sca_vec_av[0]) /
00907 ext_mat_av(0,0) * (1 - trans_mat(0,0));
00908
00909
00910 for( Index i=1; i<stokes_dim; i++ )
00911 {
00912
00913 trans_mat(i,i) = trans_mat(0,0);
00914 stokes_vec[i] = stokes_vec[i] * trans_mat(i,i) +
00915 sca_vec_av[i] / ext_mat_av(i,i) * (1 - trans_mat(i,i));
00916 }
00917 }
00918
00919
00920
00921 else
00922 {
00923
00924
00925
00926 Matrix LU(stokes_dim, stokes_dim);
00927 ArrayOfIndex indx(stokes_dim);
00928 Vector b(stokes_dim);
00929 Vector x(stokes_dim);
00930 Matrix I(stokes_dim, stokes_dim);
00931
00932 Vector B_abs_vec(stokes_dim);
00933 B_abs_vec = abs_vec_av;
00934 B_abs_vec *= rte_planck_value;
00935
00936 for (Index i=0; i<stokes_dim; i++)
00937 b[i] = B_abs_vec[i] + sca_vec_av[i];
00938
00939
00940 ludcmp(LU, indx, ext_mat_av);
00941 lubacksub(x, LU, b, indx);
00942
00943 Matrix ext_mat_ds(stokes_dim, stokes_dim);
00944 ext_mat_ds = ext_mat_av;
00945 ext_mat_ds *= -l_step;
00946
00947 Index q = 10;
00948
00949
00950 matrix_exp( trans_mat, ext_mat_ds, q);
00951
00952 Vector term1(stokes_dim);
00953 Vector term2(stokes_dim);
00954
00955 id_mat(I);
00956 for(Index i=0; i<stokes_dim; i++)
00957 {
00958 for(Index j=0; j<stokes_dim; j++)
00959 LU(i,j) = I(i,j) - trans_mat(i,j);
00960
00961 }
00962 mult(term2, LU, x);
00963
00964
00965
00966
00967 mult( term1, trans_mat, stokes_vec );
00968
00969 for (Index i=0; i<stokes_dim; i++)
00970 stokes_vec[i] = term1[i] + term2[i];
00971 }
00972 }
00973
00974
00975
00977
00990 void rte_step_std_clearsky(
00991
00992 VectorView stokes_vec,
00993 MatrixView trans_mat,
00994
00995 const Vector& absorption,
00996 const Numeric& l_step,
00997 const Numeric& emission )
00998 {
00999
01000 Index stokes_dim = stokes_vec.nelem();
01001
01002
01003 assert( is_size( trans_mat, stokes_dim, stokes_dim ) );
01004 assert( emission >= 0 );
01005 assert( l_step >= 0 );
01006
01007
01008 const bool abs_polarised = false;
01009
01010
01011
01012 if( abs_polarised )
01013 {
01014
01015 assert( stokes_dim > 1 );
01016
01017 throw runtime_error( "Polarised absorption not yet handled.");
01018 }
01019
01020
01021
01022 else
01023 {
01024
01025 trans_mat = 0;
01026
01027
01028 trans_mat(0,0) = exp( -absorption.sum() * l_step );
01029 stokes_vec[0] = stokes_vec[0] * trans_mat(0,0) +
01030 emission * ( 1 - trans_mat(0,0) );
01031
01032
01033 for( Index i=1; i<stokes_dim; i++ )
01034 {
01035 trans_mat(i,i) = trans_mat(0,0);
01036 stokes_vec[i] *= trans_mat(i,i);
01037 }
01038
01039 }
01040 }
01041
01042
01043
01045
01069 void rte_std(Workspace& ws,
01070 Matrix& iy,
01071 Tensor4& ppath_transmissions,
01072 ArrayOfTensor4& diy_dvmr,
01073 ArrayOfTensor4& diy_dt,
01074 const Ppath& ppath,
01075 const ArrayOfPpath& ppath_array,
01076 const Index& ppath_array_index,
01077 const Vector& f_grid,
01078 const Index& stokes_dim,
01079 const Agenda& emission_agenda,
01080 const Agenda& abs_scalar_gas_agenda,
01081 const ArrayOfIndex& rte_do_vmr_jacs,
01082 const Index& rte_do_t_jacs,
01083 const bool& do_transmissions )
01084 {
01085
01086
01087
01088 const Index nf = f_grid.nelem();
01089 const Index np = ppath.np;
01090 const Index ns = ppath.vmr.nrows();
01091 const Index ng = rte_do_vmr_jacs.nelem();
01092 Vector rte_vmr_list(ns);
01093
01094
01095 Vector logp_ppath(np);
01096 transform( logp_ppath, log, ppath.p );
01097
01098
01099
01100 Index f_index = -1;
01101
01102
01103 Matrix trans(stokes_dim,stokes_dim);
01104 bool save_transmissions = false;
01105 bool any_abs_polarised = false;
01106
01107 if( do_transmissions || ng || rte_do_t_jacs )
01108 {
01109 save_transmissions = true;
01110 ppath_transmissions.resize(np-1,nf,stokes_dim,stokes_dim);
01111 }
01112
01113
01114
01115 Vector emission;
01116 Matrix abs_scalar_gas;
01117
01118
01119
01120
01121
01122
01123
01124 for( Index ip=np-1; ip>0; ip-- )
01125 {
01126
01127 Numeric rte_pressure = exp( 0.5 * ( logp_ppath[ip] + logp_ppath[ip-1] ) );
01128 Numeric rte_temperature = 0.5 * ( ppath.t[ip] + ppath.t[ip-1] );
01129 for( Index is=0; is<ns; is++ )
01130 { rte_vmr_list[is] = 0.5 * ( ppath.vmr(is,ip) + ppath.vmr(is, ip-1) );}
01131
01132
01133 emission_agendaExecute( ws, emission, rte_temperature, emission_agenda );
01134 abs_scalar_gas_agendaExecute( ws, abs_scalar_gas, f_index,
01135 rte_pressure, rte_temperature, rte_vmr_list, abs_scalar_gas_agenda );
01136
01137
01138
01139
01140 Numeric dt = 0.1;
01141 Vector emission2(0);
01142 Matrix abs_scalar_gas2(0,0);
01143
01144 if( rte_do_t_jacs )
01145 {
01146 emission_agendaExecute( ws, emission2, rte_temperature+dt,
01147 emission_agenda );
01148 abs_scalar_gas_agendaExecute( ws, abs_scalar_gas2, f_index,
01149 rte_pressure, rte_temperature+dt,
01150 rte_vmr_list, abs_scalar_gas_agenda );
01151 }
01152
01153
01154
01155 bool abs_polarised = false;
01156 if( abs_polarised )
01157 { any_abs_polarised = true; }
01158
01159
01160
01161 for( Index iv=0; iv<nf; iv++ )
01162 {
01163
01164 if( ng || rte_do_t_jacs )
01165 {
01166 if( abs_polarised )
01167 {}
01168 else
01169 {
01170 const Numeric tau = abs_scalar_gas(iv,joker).sum() *
01171 ppath.l_step[ip-1];
01172 const Numeric tr = exp( -tau );
01173
01174
01175 if( ng )
01176 {
01177 const Numeric cf = 0.5 * ppath.l_step[ip-1] * tr;
01178 const Numeric cf0 = cf * ( emission[iv] - iy(iv,0) );
01179
01180 for( Index ig=0; ig<ng; ig++ )
01181 {
01182 const Index is = rte_do_vmr_jacs[ig];
01183 const Numeric k = abs_scalar_gas(iv,is) /
01184 rte_vmr_list[is];
01185 Numeric w = cf0 * k;
01186
01187 diy_dvmr[ppath_array_index](ig,ip,iv,0) += w;
01188 diy_dvmr[ppath_array_index](ig,ip-1,iv,0) += w;
01189
01190
01191 for( Index s=1; s<stokes_dim; s++ )
01192 {
01193 w = -cf * k * iy(iv,s);
01194
01195 diy_dvmr[ppath_array_index](ig,ip,iv,s) += w;
01196 diy_dvmr[ppath_array_index](ig,ip-1,iv,s) += w;
01197 }
01198 }
01199 }
01200
01201
01202 if( rte_do_t_jacs )
01203 {
01204 const Numeric dtaudT = (abs_scalar_gas2(iv,joker).sum() *
01205 ppath.l_step[ip-1] - tau ) /
01206 ( 2.0 * dt );
01207 Numeric w = ( 1.0 -tr ) *
01208 ( emission2[iv] - emission[iv] ) / ( 2.0 * dt ) +
01209 tr * ( emission[iv] - iy(iv,0) ) * dtaudT;
01210
01211 diy_dt[ppath_array_index](0,ip,iv,0) += w;
01212 diy_dt[ppath_array_index](0,ip-1,iv,0) += w;
01213
01214
01215 for( Index s=1; s<stokes_dim; s++ )
01216 {
01217 w = -tr * iy(iv,s) * dtaudT;
01218
01219 diy_dvmr[ppath_array_index](0,ip,iv,s) += w;
01220 diy_dvmr[ppath_array_index](0,ip-1,iv,s) += w;
01221 }
01222 }
01223 }
01224 }
01225
01226
01227
01228
01229 rte_step_std_clearsky( iy(iv,joker), trans, abs_scalar_gas(iv,joker),
01230 ppath.l_step[ip-1], emission[iv] );
01231
01232 if( save_transmissions )
01233 { ppath_transmissions(ip-1,iv,joker,joker) = trans; }
01234 }
01235 }
01236
01237
01238
01239 if( ng || rte_do_t_jacs )
01240 {
01241 for( Index iv=0; iv<nf; iv++ )
01242 {
01243 if( ng )
01244 include_cumtrans_in_diy_dq( diy_dvmr[ppath_array_index], trans,
01245 iv, any_abs_polarised,
01246 ppath_transmissions(joker,iv,joker,joker) );
01247 if( rte_do_t_jacs )
01248 include_cumtrans_in_diy_dq( diy_dt[ppath_array_index], trans,
01249 iv, any_abs_polarised,
01250 ppath_transmissions(joker,iv,joker,joker) );
01251
01252 for( Index ia=0;
01253 ia<ppath_array[ppath_array_index].next_parts.nelem(); ia++ )
01254 {
01255 const Index pai = ppath_array[ppath_array_index].next_parts[ia];
01256 if( ng )
01257 include_trans_in_diy_dq( diy_dvmr, iv, any_abs_polarised,
01258 trans, ppath_array, pai );
01259 if( rte_do_t_jacs )
01260 include_trans_in_diy_dq( diy_dt, iv, any_abs_polarised,
01261 trans, ppath_array, pai );
01262 }
01263 }
01264 }
01265 }
01266
01267
01268
01270
01302 void rtecalc_check_input(
01303 Index& nf,
01304 Index& nmblock,
01305 Index& nza,
01306 Index& naa,
01307 Index& nblock,
01308 const Index& atmosphere_dim,
01309 const Vector& p_grid,
01310 const Vector& lat_grid,
01311 const Vector& lon_grid,
01312 const Tensor3& z_field,
01313 const Tensor3& t_field,
01314 const Matrix& r_geoid,
01315 const Matrix& z_surface,
01316 const Index& cloudbox_on,
01317 const ArrayOfIndex& cloudbox_limits,
01318 const Sparse& sensor_response,
01319 const Matrix& sensor_pos,
01320 const Matrix& sensor_los,
01321 const Vector& f_grid,
01322 const Index& stokes_dim,
01323 const Index& antenna_dim,
01324 const Vector& mblock_za_grid,
01325 const Vector& mblock_aa_grid,
01326 const String& y_unit,
01327 const String& jacobian_unit )
01328 {
01329
01330 nf = f_grid.nelem();
01331 nmblock = sensor_pos.nrows();
01332 nza = mblock_za_grid.nelem();
01333
01334
01335 naa = mblock_aa_grid.nelem();
01336 if( antenna_dim == 1 )
01337 { naa = 1; }
01338
01339
01340 nblock = sensor_response.nrows();
01341
01342
01343
01344 chk_if_in_range( "stokes_dim", stokes_dim, 1, 4 );
01345
01346
01347
01348 chk_if_in_range( "atmosphere_dim", atmosphere_dim, 1, 3 );
01349 chk_atm_grids( atmosphere_dim, p_grid, lat_grid, lon_grid );
01350 chk_atm_field( "z_field", z_field, atmosphere_dim, p_grid, lat_grid,
01351 lon_grid );
01352 chk_atm_field( "t_field", t_field, atmosphere_dim, p_grid, lat_grid,
01353 lon_grid );
01354
01355 chk_atm_surface( "r_geoid", r_geoid, atmosphere_dim, lat_grid,
01356 lon_grid );
01357 chk_atm_surface( "z_surface", z_surface, atmosphere_dim, lat_grid,
01358 lon_grid );
01359
01360
01361
01362 for( Index row=0; row<z_field.nrows(); row++ )
01363 {
01364 for( Index col=0; col<z_field.ncols(); col++ )
01365 {
01366 ostringstream os;
01367 os << "z_field (for latitude nr " << row << " and longitude nr "
01368 << col << ")";
01369 chk_if_increasing( os.str(), z_field(joker,row,col) );
01370 }
01371 }
01372
01373
01374
01375
01376 for( Index row=0; row<z_surface.nrows(); row++ )
01377 {
01378 for( Index col=0; col<z_surface.ncols(); col++ )
01379 {
01380 if( z_surface(row,col)<z_field(0,row,col) ||
01381 z_surface(row,col)>=z_field(z_field.npages()-1,row,col) )
01382 {
01383 ostringstream os;
01384 os << "The surface altitude (*z_surface*) cannot be outside "
01385 << "of the altitudes in *z_field*.";
01386 if( atmosphere_dim > 1 )
01387 os << "\nThis was found to be the case for:\n"
01388 << "latitude " << lat_grid[row];
01389 if( atmosphere_dim > 2 )
01390 os << "\nlongitude " << lon_grid[col];
01391 throw runtime_error( os.str() );
01392 }
01393 }
01394 }
01395
01396
01397
01398 chk_cloudbox( atmosphere_dim, p_grid, lat_grid, lon_grid,
01399 cloudbox_on, cloudbox_limits );
01400
01401
01402
01403 if( nf == 0 )
01404 throw runtime_error( "The frequency grid is empty." );
01405 chk_if_increasing( "f_grid", f_grid );
01406
01407
01408
01409 chk_if_in_range( "antenna_dim", antenna_dim, 1, 2 );
01410 if( nza == 0 )
01411 throw runtime_error( "The measurement block zenith angle grid is empty." );
01412 chk_if_increasing( "mblock_za_grid", mblock_za_grid );
01413 if( antenna_dim == 1 )
01414 {
01415 if( mblock_aa_grid.nelem() != 0 )
01416 throw runtime_error(
01417 "For antenna_dim = 1, the azimuthal angle grid must be empty." );
01418 }
01419 else
01420 {
01421 if( atmosphere_dim < 3 )
01422 throw runtime_error( "2D antennas (antenna_dim=2) can only be "
01423 "used with 3D atmospheres." );
01424 if( mblock_aa_grid.nelem() == 0 )
01425 throw runtime_error(
01426 "The measurement block azimuthal angle grid is empty." );
01427 chk_if_increasing( "mblock_aa_grid", mblock_aa_grid );
01428 }
01429
01430
01431
01432 if( sensor_response.ncols() != nf * nza * naa * stokes_dim )
01433 {
01434 ostringstream os;
01435 os << "The *sensor_response* matrix does not have the right size, \n"
01436 << "either the method *sensor_responseInit* has not been run \n"
01437 << "prior to the call to *RteCalc* or some of the other sensor\n"
01438 << "response methods has not been correctly configured.";
01439 throw runtime_error( os.str() );
01440 }
01441
01442
01443
01444
01445
01446 if( sensor_pos.ncols() != atmosphere_dim )
01447 throw runtime_error( "The number of columns of sensor_pos must be "
01448 "equal to the atmospheric dimensionality." );
01449 if( atmosphere_dim <= 2 && sensor_los.ncols() != 1 )
01450 throw runtime_error(
01451 "For 1D and 2D, sensor_los shall have one column." );
01452 if( atmosphere_dim == 3 && sensor_los.ncols() != 2 )
01453 throw runtime_error( "For 3D, sensor_los shall have two columns." );
01454 if( sensor_los.nrows() != nmblock )
01455 {
01456 ostringstream os;
01457 os << "The number of rows of sensor_pos and sensor_los must be "
01458 << "identical, but sensor_pos has " << nmblock << " rows,\n"
01459 << "while sensor_los has " << sensor_los.nrows() << " rows.";
01460 throw runtime_error( os.str() );
01461 }
01462
01463
01464
01465 if( !( y_unit=="1" || y_unit=="RJBT" || y_unit=="PlanckBT" ) )
01466 {
01467 ostringstream os;
01468 os << "Allowed options for *y_unit* are: ""1"", ""RJBT"", and "
01469 << """PlanckBT"".";
01470 throw runtime_error( os.str() );
01471 }
01472
01473
01474
01475 if( !( jacobian_unit=="1" || jacobian_unit=="RJBT" ||
01476 jacobian_unit=="-" ) )
01477 {
01478 ostringstream os;
01479 os << "Allowed options for *jacobian_unit* are: ""1"", ""RJBT"", and "
01480 << """-"".";
01481 throw runtime_error( os.str() );
01482 }
01483 }
01484
01485
01487
01504 void surface_calc(
01505 Matrix& iy,
01506 const Tensor3& I,
01507 const Matrix& surface_los,
01508 const Tensor4& surface_rmatrix,
01509 const Matrix& surface_emission )
01510 {
01511
01512 const Index nf = I.nrows();
01513 const Index stokes_dim = I.ncols();
01514 const Index nlos = surface_los.nrows();
01515
01516 iy = surface_emission;
01517
01518
01519
01520
01521
01522
01523
01524
01525 if( nlos > 0 )
01526 {
01527 for( Index ilos=0; ilos<nlos; ilos++ )
01528 {
01529 Vector rtmp(stokes_dim);
01530
01531 for( Index iv=0; iv<nf; iv++ )
01532 {
01533 mult( rtmp, surface_rmatrix(ilos,iv,joker,joker), I(ilos,iv,joker) );
01534 iy(iv,joker) += rtmp;
01535 }
01536 }
01537 }
01538 }
01539
01540
01541
01542
01543
01544