00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00037
00038
00039
00040
00041 #include <cmath>
00042 #include <string>
00043 #include "arts.h"
00044 #include "auto_md.h"
00045 #include "check_input.h"
00046 #include "math_funcs.h"
00047 #include "messages.h"
00048 #include "jacobian.h"
00049 #include "rte.h"
00050 #include "absorption.h"
00051 #include "physics_funcs.h"
00052
00053 extern const String ABSSPECIES_MAINTAG;
00054 extern const String POINTING_MAINTAG;
00055 extern const String POLYFIT_MAINTAG;
00056 extern const String TEMPERATURE_MAINTAG;
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071 void jacobianCalc(
00072 Workspace& ws,
00073 Matrix& jacobian,
00074 const Agenda& jacobian_agenda,
00075 const ArrayOfArrayOfIndex& jacobian_indices )
00076 {
00077
00078
00079 if( jacobian.ncols() == 0 )
00080 {
00081 ostringstream os;
00082 os << "The Jacobian matrix has not been properly initialised.\n"
00083 << "The WSM jacobianClose has to be called prior to jacobianCalc.\n";
00084 throw runtime_error(os.str());
00085 }
00086
00087
00088 ArrayOfIndex last_ind = jacobian_indices[jacobian_indices.nelem()-1];
00089 if( jacobian.ncols()-1!=last_ind[1] )
00090 {
00091 ostringstream os;
00092 os << "There are more retrieval quantities in *jacobian_quantities*\n"
00093 << "than in *jacobian*. After calling jacobianClose no more\n"
00094 << "quantities can be added.";
00095 throw runtime_error(os.str());
00096 }
00097
00098
00099 out2 << " Calculating *jacobian*.\n";
00100
00101
00102 if( jacobian_agenda.nelem() > 0 )
00103 jacobian_agendaExecute( ws, jacobian, jacobian_agenda );
00104 }
00105
00106
00107
00108
00109 void jacobianClose(
00110 Matrix& jacobian,
00111 ArrayOfArrayOfIndex& jacobian_indices,
00112 const ArrayOfRetrievalQuantity& jacobian_quantities,
00113 const Matrix& sensor_pos,
00114 const Sparse& sensor_response )
00115 {
00116
00117 if( jacobian.nrows() != 0 && jacobian.ncols() != 0 )
00118 {
00119 ostringstream os;
00120 os << "The Jacobian matrix has not been initialised, or calculations\n"
00121 << "have alread been performed.";
00122 throw runtime_error(os.str());
00123 }
00124
00125
00126 if( jacobian_quantities.nelem() == 0 )
00127 throw runtime_error(
00128 "No retrieval quantities has been added to *jacobian_quantities*." );
00129
00130
00131 if( sensor_pos.nrows() == 0 )
00132 {
00133 ostringstream os;
00134 os << "The number of rows in *sensor_pos* is zero, i.e. no measurement\n"
00135 << "blocks has been defined. This has to be done before calling\n"
00136 << "jacobianClose.";
00137 throw runtime_error(os.str());
00138 }
00139 if( sensor_response.nrows() == 0 )
00140 {
00141 ostringstream os;
00142 os << "The sensor has either to be defined or turned off before calling\n"
00143 << "jacobianClose.";
00144 throw runtime_error(os.str());
00145 }
00146
00147
00148 Index nrows = sensor_pos.nrows() * sensor_response.nrows();
00149 Index ncols = 0;
00150
00151 for( Index it=0; it<jacobian_quantities.nelem(); it++ )
00152 {
00153
00154 ArrayOfIndex indices(2);
00155 indices[0] = ncols;
00156
00157
00158 Index cols = 1;
00159 ArrayOfVector grids = jacobian_quantities[it].Grids();
00160 for( Index jt=0; jt<grids.nelem(); jt++ )
00161 { cols *= grids[jt].nelem(); }
00162
00163
00164 indices[1] = ncols + cols - 1;
00165 jacobian_indices.push_back( indices );
00166
00167 ncols += cols;
00168 }
00169
00170
00171 jacobian.resize( nrows, ncols );
00172 jacobian = 0;
00173 }
00174
00175
00176
00177
00178 void jacobianInit(
00179 Matrix& jacobian,
00180 ArrayOfRetrievalQuantity& jacobian_quantities,
00181 ArrayOfArrayOfIndex& jacobian_indices,
00182 Agenda& jacobian_agenda )
00183 {
00184 jacobian.resize(0,0);
00185 jacobian_quantities.resize(0);
00186 jacobian_indices.resize(0);
00187 jacobian_agenda = Agenda();
00188 jacobian_agenda.set_name( "jacobian_agenda" );
00189 }
00190
00191
00192
00193
00194 void jacobianOff(
00195 Matrix& jacobian,
00196 ArrayOfRetrievalQuantity& jacobian_quantities,
00197 ArrayOfArrayOfIndex& jacobian_indices,
00198 String& jacobian_unit )
00199 {
00200 Agenda dummy;
00201
00202 jacobianInit( jacobian, jacobian_quantities, jacobian_indices, dummy );
00203
00204 jacobian_unit = "-";
00205 }
00206
00207
00208
00209
00210 void jacobianUnit(
00211 Matrix& jacobian,
00212 const String& jacobian_unit,
00213 const String& y_unit,
00214 const Vector& y_f )
00215 {
00216 String j_unit = jacobian_unit;
00217
00218 if ( jacobian_unit == "-" )
00219 { j_unit = y_unit; }
00220
00221 try
00222 {
00223 ybatchUnit( jacobian, j_unit, y_f );
00224 }
00225 catch( runtime_error )
00226 {
00227 ostringstream os;
00228 os << "Unknown option: jacobian_unit = \"" << j_unit << "\"\n"
00229 << "Recognised choices are: \"-\", \"1\", \"RJBT\" and \"PlanckBT\"";
00230 throw runtime_error( os.str() );
00231 }
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 void jacobianAddAbsSpecies(
00244 Workspace& ws,
00245 ArrayOfRetrievalQuantity& jq,
00246 Agenda& jacobian_agenda,
00247 const Matrix& J,
00248 const Index& atmosphere_dim,
00249 const Vector& p_grid,
00250 const Vector& lat_grid,
00251 const Vector& lon_grid,
00252 const Vector& rq_p_grid,
00253 const Vector& rq_lat_grid,
00254 const Vector& rq_lon_grid,
00255 const String& species,
00256 const String& method,
00257 const String& mode,
00258 const Numeric& dx )
00259 {
00260
00261
00262 if( J.nrows()!=0 && J.ncols()!=0 )
00263 {
00264 ostringstream os;
00265 os << "The Jacobian matrix is not initialised correctly or closed.\n"
00266 << "New retrieval quantities can not be added at this point.";
00267 throw runtime_error(os.str());
00268 }
00269
00270
00271
00272 ArrayOfVector grids(atmosphere_dim);
00273 {
00274 ostringstream os;
00275 if( !check_retrieval_grids( grids, os, p_grid, lat_grid, lon_grid,
00276 rq_p_grid, rq_lat_grid, rq_lon_grid,
00277 "retrieval pressure grid",
00278 "retrieval latitude grid",
00279 "retrievallongitude_grid",
00280 atmosphere_dim ) )
00281 throw runtime_error(os.str());
00282 }
00283
00284
00285 bool analytical;
00286 if( method == "perturbation" )
00287 { analytical = 0; }
00288 else if( method == "analytical" )
00289 { analytical = 1; }
00290 else
00291 {
00292 ostringstream os;
00293 os << "The method for absorption species retrieval can only be "
00294 << "\"analytical\"\n or \"perturbation\".";
00295 throw runtime_error(os.str());
00296 }
00297
00298
00299 if( mode != "vmr" && mode != "nd" && mode != "rel" )
00300 {
00301 throw runtime_error(
00302 "The retrieval mode can only be \"vmr\", \"nd\" or \"rel\"." );
00303 }
00304
00305
00306 for( Index it=0; it<jq.nelem(); it++ )
00307 {
00308 if( jq[it].MainTag() == ABSSPECIES_MAINTAG && jq[it].Subtag() == species )
00309 {
00310 ostringstream os;
00311 os << "The gas species:\n" << species << "\nis already included in "
00312 << "*jacobian_quantities*.";
00313 throw runtime_error(os.str());
00314 }
00315 }
00316
00317
00318 RetrievalQuantity rq = RetrievalQuantity();
00319 rq.MainTag( ABSSPECIES_MAINTAG );
00320 rq.Subtag( species );
00321 rq.Mode( mode );
00322 rq.Analytical( analytical );
00323 rq.Perturbation( dx );
00324 rq.Grids( grids );
00325
00326
00327 jq.push_back( rq );
00328
00329
00330 if( analytical )
00331 {
00332 out3 << " Calculations done by semi-analytical expressions.\n";
00333 }
00334 else
00335 {
00336 out2 << " Adding absorption species: " << species
00337 << " to *jacobian_quantities*\n" << " and *jacobian_agenda*\n";
00338 out3 << " Calculations done by perturbation, size " << dx
00339 << " " << mode << ".\n";
00340
00341 jacobian_agenda.append( ws, "jacobianCalcAbsSpecies", species );
00342 }
00343 }
00344
00345
00346
00347
00348 void jacobianCalcAbsSpecies(
00349 Workspace& ws,
00350 Matrix& J,
00351 const Agenda& jacobian_y_agenda,
00352 const ArrayOfRetrievalQuantity& jq,
00353 const ArrayOfArrayOfIndex& jacobian_indices,
00354 const Index& atmosphere_dim,
00355 const Vector& p_grid,
00356 const Vector& lat_grid,
00357 const Vector& lon_grid,
00358 const ArrayOfArrayOfSpeciesTag& abs_species,
00359 const Tensor4& vmr_field,
00360 const Tensor3& t_field,
00361 const Tensor4& pnd_field,
00362 const Matrix& sensor_los,
00363 const Vector& y,
00364 const String& species )
00365 {
00366
00367 RetrievalQuantity rq;
00368 ArrayOfIndex ji;
00369 Index it, pertmode;
00370
00371
00372
00373 bool found = false;
00374 for( Index n=0; n<jq.nelem() && !found; n++ )
00375 {
00376 if( jq[n].MainTag() == ABSSPECIES_MAINTAG && jq[n].Subtag() == species )
00377 {
00378 found = true;
00379 rq = jq[n];
00380 ji = jacobian_indices[n];
00381 }
00382 }
00383 if( !found )
00384 {
00385 ostringstream os;
00386 os << "There is no gas species retrieval quantities defined for:\n"
00387 << species;
00388 throw runtime_error(os.str());
00389 }
00390
00391 if( rq.Analytical() )
00392 {
00393 ostringstream os;
00394 os << "This WSM handles only perturbation calculations.\n"
00395 << "Are you using the method manually? This method should normally be\n"
00396 << "used through *jacobianCalc*.";
00397 throw runtime_error(os.str());
00398 }
00399
00400
00401 it = ji[0];
00402 ArrayOfVector jg = rq.Grids();
00403
00404
00405
00406
00407 if( rq.Mode()=="rel" )
00408 pertmode = 0;
00409 else
00410 pertmode = 1;
00411
00412
00413
00414
00415 ArrayOfGridPos p_gp, lat_gp, lon_gp;
00416 Index j_p = jg[0].nelem();
00417 Index j_lat = 1;
00418 Index j_lon = 1;
00419
00420 get_perturbation_gridpos( p_gp, p_grid, jg[0], true );
00421
00422 if( atmosphere_dim >= 2 )
00423 {
00424 j_lat = jg[1].nelem();
00425 get_perturbation_gridpos( lat_gp, lat_grid, jg[1], false );
00426 if( atmosphere_dim == 3 )
00427 {
00428 j_lon = jg[2].nelem();
00429 get_perturbation_gridpos( lon_gp, lon_grid, jg[2], false );
00430 }
00431 }
00432
00433
00434 out2 << " Calculating retrieval quantity " << rq << "\n";
00435
00436
00437 ArrayOfSpeciesTag tags;
00438 array_species_tag_from_string( tags, species );
00439 Index si = chk_contains( "species", abs_species, tags );
00440
00441
00442 Tensor3 nd_field( t_field.npages(), t_field.nrows(), t_field.ncols(), 1.0 );
00443 if( rq.Mode()=="nd" )
00444 calc_nd_field( nd_field, p_grid, t_field );
00445
00446
00447 Vector yp;
00448
00449
00450 for( Index lon_it=0; lon_it<j_lon; lon_it++ )
00451 {
00452 for( Index lat_it=0; lat_it<j_lat; lat_it++ )
00453 {
00454 for (Index p_it=0; p_it<j_p; p_it++)
00455 {
00456
00457
00458
00459 Range p_range = Range(0,0);
00460 Range lat_range = Range(0,0);
00461 Range lon_range = Range(0,0);
00462
00463 get_perturbation_range( p_range, p_it, j_p);
00464
00465 if( atmosphere_dim>=2 )
00466 {
00467 get_perturbation_range( lat_range, lat_it, j_lat );
00468 if( atmosphere_dim == 3 )
00469 {
00470 get_perturbation_range( lon_range, lon_it, j_lon);
00471 }
00472 }
00473
00474
00475 Tensor4 vmr_p = vmr_field;
00476
00477
00478
00479 if( rq.Mode() == "nd" )
00480 vmr_p(si,joker,joker,joker) *= nd_field;
00481
00482
00483
00484
00485 switch (atmosphere_dim)
00486 {
00487 case 1:
00488 {
00489
00490 perturbation_field_1d( vmr_p(si,joker,lat_it,lon_it),
00491 p_gp, jg[0].nelem()+2, p_range,
00492 rq.Perturbation(), pertmode );
00493 break;
00494 }
00495 case 2:
00496 {
00497
00498 perturbation_field_2d( vmr_p(si,joker,joker,lon_it),
00499 p_gp, lat_gp, jg[0].nelem()+2,
00500 jg[1].nelem()+2, p_range, lat_range,
00501 rq.Perturbation(), pertmode );
00502 break;
00503 }
00504 case 3:
00505 {
00506
00507 perturbation_field_3d( vmr_p(si,joker,joker,joker),
00508 p_gp, lat_gp, lon_gp, jg[0].nelem()+2,
00509 jg[1].nelem()+2, jg[2].nelem()+2,
00510 p_range, lat_range, lon_range,
00511 rq.Perturbation(), pertmode );
00512 break;
00513 }
00514 }
00515
00516
00517 if (rq.Mode()=="nd")
00518 vmr_p(si,joker,joker,joker) /= nd_field;
00519
00520
00521 out2 << " Calculating perturbed spectra no. " << it+1 << " of "
00522 << ji[1]+1 << "\n";
00523
00524
00525 jacobian_y_agendaExecute( ws, yp, vmr_p, t_field, pnd_field,
00526 sensor_los, jacobian_y_agenda );
00527
00528
00529 for( Index y_it=0; y_it<y.nelem(); y_it++ )
00530 { J(y_it,it) = ( yp[y_it] - y[y_it] ) / rq.Perturbation(); }
00531
00532
00533 it++;
00534 }
00535 }
00536 }
00537 }
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547 void jacobianAddPointing(
00548 Workspace& ws,
00549 ArrayOfRetrievalQuantity& jq,
00550 Agenda& jacobian_agenda,
00551 const Matrix& J,
00552 const Matrix& sensor_pos,
00553 const Vector& sensor_time,
00554 const Numeric& dza,
00555 const Index& poly_order )
00556 {
00557
00558
00559 if( J.nrows()!=0 && J.ncols()!=0 )
00560 {
00561 ostringstream os;
00562 os << "The Jacobian matrix is not initialised correctly or closed.\n"
00563 << "New retrieval quantities can not be added at this point.";
00564 throw runtime_error(os.str());
00565 }
00566
00567
00568 if( poly_order < -1 )
00569 throw runtime_error(
00570 "The polynomial order has to be positive or -1 for gitter." );
00571
00572
00573 String subtag = "za offset";
00574 String mode = "abs" ;
00575
00576
00577
00578 for( Index it=0; it<jq.nelem(); it++ )
00579 {
00580 if( jq[it].MainTag() == POINTING_MAINTAG )
00581 {
00582 ostringstream os;
00583 os << "Polynomial baseline fit is already included in\n"
00584 << "*jacobian_quantities*.";
00585 throw runtime_error(os.str());
00586 }
00587 }
00588
00589
00590
00591 for( Index it=0; it<jq.nelem(); it++ )
00592 {
00593 if (jq[it].MainTag()== POINTING_MAINTAG && jq[it].Subtag() == subtag )
00594 {
00595 ostringstream os;
00596 os << "A zenith angle pointing offset is already included in\n"
00597 << "*jacobian_quantities*.";
00598 throw runtime_error(os.str());
00599 }
00600 }
00601
00602
00603 if( sensor_time.nelem() != sensor_pos.nrows() )
00604 {
00605 ostringstream os;
00606 os << "The WSV *sensor_time* must be defined for every "
00607 << "measurement block.\n";
00608 throw runtime_error(os.str());
00609 }
00610
00611
00612 if( poly_order > sensor_time.nelem()-1 )
00613 { throw runtime_error(
00614 "The polynomial order can not be >= length of *sensor_time*." ); }
00615
00616
00617 RetrievalQuantity rq = RetrievalQuantity();
00618 rq.MainTag( POINTING_MAINTAG );
00619 rq.Subtag( subtag );
00620 rq.Mode( mode );
00621 rq.Analytical( 0 );
00622 rq.Perturbation( dza );
00623
00624
00625
00626 Vector grid(0,poly_order+1,1);
00627 if( poly_order == -1 )
00628 {
00629 grid.resize(sensor_pos.nrows());
00630 grid = -1.0;
00631 }
00632 ArrayOfVector grids(1,grid);
00633 rq.Grids(grids);
00634
00635
00636 jq.push_back( rq );
00637
00638
00639 jacobian_agenda.append( ws, "jacobianCalcPointing", "" );
00640 }
00641
00642
00643
00644
00645 void jacobianCalcPointing(
00646 Workspace& ws,
00647 Matrix& J,
00648 const Agenda& jacobian_y_agenda,
00649 const ArrayOfRetrievalQuantity& jq,
00650 const ArrayOfArrayOfIndex& jacobian_indices,
00651 const Tensor4& vmr_field,
00652 const Tensor3& t_field,
00653 const Tensor4& pnd_field,
00654 const Matrix& sensor_los,
00655 const Vector& sensor_time,
00656 const Vector& y )
00657 {
00658
00659 RetrievalQuantity rq;
00660 ArrayOfIndex ji;
00661
00662
00663
00664 bool found = false;
00665 for( Index n=0; n<jq.nelem() && !found; n++ )
00666 {
00667 if( jq[n].MainTag() == POINTING_MAINTAG && jq[n].Subtag() == "za offset" )
00668 {
00669 found = true;
00670 rq = jq[n];
00671 ji = jacobian_indices[n];
00672 }
00673 }
00674 if( !found )
00675 {
00676 throw runtime_error(
00677 "There is no pointing offset retrieval quantities defined.\n");
00678 }
00679
00680
00681
00682 chk_if_increasing( "sensor_time", sensor_time );
00683
00684 if( sensor_time.nelem() != sensor_los.nrows() )
00685 {
00686 ostringstream os;
00687 os << "The WSV *sensor_time* must be defined for every "
00688 << "measurement block.\n";
00689 throw runtime_error(os.str());
00690 }
00691
00692
00693 assert( rq.Mode()=="abs" );
00694
00695
00696
00697
00698 const Index ly = y.nelem();
00699 Vector dydx(ly);
00700 {
00701 Vector yp;
00702 Matrix sensor_los_pert = sensor_los;
00703 sensor_los_pert(joker,0) += rq.Perturbation();
00704
00705 jacobian_y_agendaExecute( ws, yp, vmr_field, t_field, pnd_field,
00706 sensor_los_pert, jacobian_y_agenda );
00707
00708
00709
00710 for( Index i=0; i<ly; i++ )
00711 {
00712 dydx[i] = ( yp[i] - y[i] ) / rq.Perturbation();
00713 }
00714 }
00715
00716
00717
00718
00719 Index nb = sensor_los.nrows();
00720 Index lb = y.nelem() / nb;
00721 Index lg = rq.Grids()[0].nelem();
00722 Index it = ji[0];
00723
00724
00725 assert( nb*lb == y.nelem() );
00726
00727
00728 if( rq.Grids()[0][0] == -1 )
00729 {
00730 assert( lg == nb );
00731
00732 Index iy = 0;
00733
00734 for( Index b=0; b<nb; b++ )
00735 {
00736 assert( rq.Grids()[0][b] == -1 );
00737 for( Index dummy=0; dummy<lb; dummy++ )
00738 {
00739 J(iy,it) = dydx[iy];
00740 iy++;
00741 }
00742 it++;
00743 }
00744 }
00745
00746
00747 else
00748 {
00749 Vector w;
00750 for( Index c=0; c<lg; c++ )
00751 {
00752 assert( Numeric(c) == rq.Grids()[0][c] );
00753
00754 polynomial_basis_func( w, sensor_time, c );
00755
00756 Index iy = 0;
00757
00758 for( Index b=0; b<nb; b++ )
00759 {
00760 for( Index dummy=0; dummy<lb; dummy++ )
00761 {
00762 J(iy,it) = w[b] * dydx[iy];
00763 iy++;
00764 }
00765 }
00766 it++;
00767 }
00768 }
00769 }
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780 void jacobianAddPolyfit(
00781 Workspace& ws,
00782 ArrayOfRetrievalQuantity& jq,
00783 Agenda& jacobian_agenda,
00784 const Matrix& J,
00785 const ArrayOfIndex& sensor_response_pol_grid,
00786 const Vector& sensor_response_f_grid,
00787 const Vector& sensor_response_za_grid,
00788 const Matrix& sensor_pos,
00789 const Index& poly_order,
00790 const Index& no_pol_variation,
00791 const Index& no_za_variation,
00792 const Index& no_mblock_variation )
00793 {
00794
00795
00796 if( J.nrows()!=0 && J.ncols()!=0 )
00797 {
00798 ostringstream os;
00799 os << "The Jacobian matrix is not initialised correctly or closed.\n"
00800 << "New retrieval quantities can not be added at this point.";
00801 throw runtime_error(os.str());
00802 }
00803
00804
00805 if( poly_order < 0 )
00806 throw runtime_error(
00807 "The polynomial order has to be >= 0.");
00808
00809
00810 if( poly_order > sensor_response_f_grid.nelem() - 1 )
00811 {
00812 ostringstream os;
00813 os << "The polynomial order can not exceed the length of\n"
00814 << "*sensor_response_f_grid* -1.";
00815 throw runtime_error(os.str());
00816 }
00817
00818
00819
00820 for( Index it=0; it<jq.nelem(); it++ )
00821 {
00822 if( jq[it].MainTag() == POLYFIT_MAINTAG )
00823 {
00824 ostringstream os;
00825 os << "Polynomial baseline fit is already included in\n"
00826 << "*jacobian_quantities*.";
00827 throw runtime_error(os.str());
00828 }
00829 }
00830
00831
00832
00833
00834
00835
00836
00837
00838
00839 ArrayOfVector grids(4);
00840
00841 if( no_pol_variation )
00842 grids[1] = Vector(1,1);
00843 else
00844 grids[1] = Vector(0,sensor_response_pol_grid.nelem(),1);
00845 if( no_za_variation )
00846 grids[2] = Vector(1,1);
00847 else
00848 grids[2] = Vector(0,sensor_response_za_grid.nelem(),1);
00849 if( no_mblock_variation )
00850 grids[3] = Vector(1,1);
00851 else
00852 grids[3] = Vector(0,sensor_pos.nrows(),1);
00853
00854
00855 RetrievalQuantity rq = RetrievalQuantity();
00856 rq.MainTag( POLYFIT_MAINTAG );
00857 rq.Mode( "" );
00858 rq.Analytical( 1 );
00859 rq.Perturbation( 0 );
00860
00861
00862
00863 for( Index i=0; i<=poly_order; i++ )
00864 {
00865 ostringstream sstr;
00866 sstr << "Coefficient " << i;
00867 rq.Subtag( sstr.str() );
00868
00869
00870 grids[0] = Vector(1,(Numeric)i);
00871 rq.Grids( grids );
00872
00873
00874 jq.push_back( rq );
00875
00876
00877 jacobian_agenda.append( ws, "jacobianCalcPolyfit", i );
00878 }
00879 }
00880
00881
00882
00883
00884 void jacobianCalcPolyfit(
00885 Matrix& J,
00886 const ArrayOfRetrievalQuantity& jq,
00887 const ArrayOfArrayOfIndex& jacobian_indices,
00888 const ArrayOfIndex& sensor_response_pol_grid,
00889 const Vector& sensor_response_f_grid,
00890 const Vector& sensor_response_za_grid,
00891 const Matrix& sensor_pos,
00892 const Index& poly_coeff )
00893 {
00894
00895 RetrievalQuantity rq;
00896 ArrayOfIndex ji;
00897 bool found = false;
00898 Index iq;
00899 ostringstream sstr;
00900 sstr << "Coefficient " << poly_coeff;
00901 for( iq=0; iq<jq.nelem() && !found; iq++ )
00902 {
00903 if( jq[iq].MainTag() == POLYFIT_MAINTAG &&
00904 jq[iq].Subtag() == sstr.str() )
00905 {
00906 found = true;
00907 break;
00908 }
00909 }
00910 if( !found )
00911 {
00912 throw runtime_error(
00913 "There is no polynomial baseline fit retrieval quantities defined.\n");
00914 }
00915
00916
00917
00918
00919
00920 const Index nf = sensor_response_f_grid.nelem();
00921 const Index npol = sensor_response_pol_grid.nelem();
00922 const Index nza = sensor_response_za_grid.nelem();
00923 const Index nblock = sensor_pos.nrows();
00924
00925 if( nf*npol*nza*nblock != J.nrows() )
00926 {
00927 throw runtime_error(
00928 "Sensor grids have changed since *jacobianAddPolyfit* was called.\n");
00929 }
00930
00931
00932
00933 Vector w;
00934
00935 polynomial_basis_func( w, sensor_response_f_grid, poly_coeff );
00936
00937
00938
00939 ArrayOfVector jg = jq[iq].Grids();
00940
00941 const Index n1 = jg[1].nelem();
00942 const Index n2 = jg[2].nelem();
00943 const Index n3 = jg[3].nelem();
00944
00945 for( Index b=0; b<nblock; b++ )
00946 {
00947 const Index row0 = b*nf*npol*nza;
00948 Index col0 = jacobian_indices[iq][0];
00949 if( n3 > 1 )
00950 { col0 += b*n2*n1; }
00951
00952 for( Index v=0; v<jg[2].nelem(); v++ )
00953 {
00954 const Index row1 = row0 + v*nf*npol;
00955 Index col1 = col0;
00956 if( n2 > 1 )
00957 { col1 += v*n1; }
00958
00959 for( Index p=0; p<nza; p++ )
00960 {
00961 const Index row2 = row1 + p;
00962 Index col2 = col1;
00963 if( n1 > 1 )
00964 { col2 += p; }
00965 for( Index f=0; f<nf; f++ )
00966 {
00967 J(row2+f*npol,col2) = w[f];
00968 }
00969 }
00970 }
00971 }
00972 }
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983 void jacobianAddTemperature(
00984 Workspace& ws,
00985 ArrayOfRetrievalQuantity& jq,
00986 Agenda& jacobian_agenda,
00987 const Matrix& J,
00988 const Index& atmosphere_dim,
00989 const Vector& p_grid,
00990 const Vector& lat_grid,
00991 const Vector& lon_grid,
00992 const Vector& rq_p_grid,
00993 const Vector& rq_lat_grid,
00994 const Vector& rq_lon_grid,
00995 const String& hse,
00996 const String& method,
00997 const Numeric& dx )
00998 {
00999
01000
01001 if( J.nrows()!=0 && J.ncols()!=0 )
01002 {
01003 ostringstream os;
01004 os << "The Jacobian matrix is not initialised correctly or closed.\n"
01005 << "New retrieval quantities can not be added at this point.";
01006 throw runtime_error(os.str());
01007 }
01008
01009
01010
01011 ArrayOfVector grids(atmosphere_dim);
01012 {
01013 ostringstream os;
01014 if( !check_retrieval_grids( grids, os, p_grid, lat_grid, lon_grid,
01015 rq_p_grid, rq_lat_grid, rq_lon_grid,
01016 "retrieval pressure grid",
01017 "retrieval latitude grid",
01018 "retrievallongitude_grid",
01019 atmosphere_dim ) )
01020 throw runtime_error(os.str());
01021 }
01022
01023
01024 bool analytical;
01025 if( method == "perturbation" )
01026 { analytical = 0; }
01027 else if( method == "analytical" )
01028 { analytical = 1; }
01029 else
01030 {
01031 ostringstream os;
01032 os << "The method for atmospheric temperature retrieval can only be "
01033 << "\"analytical\"\n or \"perturbation\".";
01034 throw runtime_error(os.str());
01035 }
01036
01037
01038 String subtag;
01039 if( hse == "on" )
01040 {
01041 subtag = "HSE on";
01042 ostringstream os;
01043 os << "The keyword for hydrostatic equilibrium can so far only be set to\n"
01044 << "\"off\"\n";
01045 throw runtime_error(os.str());
01046 }
01047 else if( hse == "off" )
01048 {
01049 subtag = "HSE off";
01050 }
01051 else
01052 {
01053 ostringstream os;
01054 os << "The keyword for hydrostatic equilibrium can only be set to\n"
01055 << "\"on\" or \"off\"\n";
01056 throw runtime_error(os.str());
01057 }
01058
01059
01060 if( method == "analytical" && hse == "on" )
01061 {
01062 ostringstream os;
01063 os << "Hydrostatic equilibrium can only be included for perturbation\n"
01064 << "calculations.";
01065 throw runtime_error(os.str());
01066 }
01067
01068
01069
01070 for (Index it=0; it<jq.nelem(); it++)
01071 {
01072 if( jq[it].MainTag() == "Temperature" )
01073 {
01074 ostringstream os;
01075 os << "Temperature is already included in *jacobian_quantities*.";
01076 throw runtime_error(os.str());
01077 }
01078 }
01079
01080
01081 RetrievalQuantity rq = RetrievalQuantity();
01082 rq.MainTag( TEMPERATURE_MAINTAG );
01083 rq.Subtag( subtag );
01084 rq.Mode( "abs" );
01085 rq.Analytical( analytical );
01086 rq.Perturbation( dx );
01087 rq.Grids( grids );
01088
01089
01090 jq.push_back( rq );
01091
01092 if( analytical )
01093 {
01094 out3 << " Calculations done by semi-analytical expression.\n";
01095 }
01096 else
01097 {
01098 out3 << " Calculations done by perturbations, of size " << dx << ".\n";
01099
01100 jacobian_agenda.append( ws, "jacobianCalcTemperature", "" );
01101 }
01102 }
01103
01104
01105
01106
01107 void jacobianCalcTemperature(
01108 Workspace& ws,
01109 Matrix& J,
01110 const Agenda& jacobian_y_agenda,
01111 const ArrayOfRetrievalQuantity& jq,
01112 const ArrayOfArrayOfIndex& jacobian_indices,
01113 const Index& atmosphere_dim,
01114 const Vector& p_grid,
01115 const Vector& lat_grid,
01116 const Vector& lon_grid,
01117 const Tensor4& vmr_field,
01118 const Tensor3& t_field,
01119 const Tensor4& pnd_field,
01120 const Matrix& sensor_los,
01121 const Vector& y )
01122 {
01123
01124 RetrievalQuantity rq;
01125 ArrayOfIndex ji;
01126 Index it;
01127
01128
01129
01130 bool found = false;
01131 for( Index n=0; n<jq.nelem() && !found; n++ )
01132 {
01133 if( jq[n].MainTag() == TEMPERATURE_MAINTAG )
01134 {
01135 found = true;
01136 rq = jq[n];
01137 ji = jacobian_indices[n];
01138 }
01139 }
01140 if( !found )
01141 {
01142 ostringstream os;
01143 os << "There is no temperature retrieval quantities defined.\n";
01144 throw runtime_error(os.str());
01145 }
01146
01147
01148 assert( rq.Subtag()=="HSE off" );
01149
01150
01151 it = ji[0];
01152 ArrayOfVector jg = rq.Grids();
01153
01154
01155 const Index pertmode = 1;
01156
01157
01158
01159
01160 ArrayOfGridPos p_gp, lat_gp, lon_gp;
01161 Index j_p = jg[0].nelem();
01162 Index j_lat = 1;
01163 Index j_lon = 1;
01164
01165 get_perturbation_gridpos( p_gp, p_grid, jg[0], true );
01166
01167 if( atmosphere_dim >= 2 )
01168 {
01169 j_lat = jg[1].nelem();
01170 get_perturbation_gridpos( lat_gp, lat_grid, jg[1], false );
01171 if( atmosphere_dim == 3 )
01172 {
01173 j_lon = jg[2].nelem();
01174 get_perturbation_gridpos( lon_gp, lon_grid, jg[2], false );
01175 }
01176 }
01177
01178
01179 out2 << " Calculating retrieval quantity " << rq << "\n";
01180
01181
01182 Vector yp;
01183
01184
01185 for( Index lon_it=0; lon_it<j_lon; lon_it++ )
01186 {
01187 for( Index lat_it=0; lat_it<j_lat; lat_it++ )
01188 {
01189 for( Index p_it=0; p_it<j_p; p_it++ )
01190 {
01191
01192 Tensor3 t_p = t_field;
01193
01194
01195
01196
01197 Range p_range = Range(0,0);
01198 Range lat_range = Range(0,0);
01199 Range lon_range = Range(0,0);
01200 get_perturbation_range( p_range, p_it, j_p );
01201 if( atmosphere_dim >= 2 )
01202 {
01203 get_perturbation_range( lat_range, lat_it, j_lat );
01204 if( atmosphere_dim == 3 )
01205 {
01206 get_perturbation_range( lon_range, lon_it, j_lon );
01207 }
01208 }
01209
01210
01211
01212
01213 switch (atmosphere_dim)
01214 {
01215 case 1:
01216 {
01217
01218 perturbation_field_1d( t_p(joker,lat_it,lon_it),
01219 p_gp, jg[0].nelem()+2, p_range,
01220 rq.Perturbation(), pertmode );
01221 break;
01222 }
01223 case 2:
01224 {
01225
01226 perturbation_field_2d( t_p(joker,joker,lon_it),
01227 p_gp, lat_gp, jg[0].nelem()+2,
01228 jg[1].nelem()+2, p_range, lat_range,
01229 rq.Perturbation(), pertmode );
01230 break;
01231 }
01232 case 3:
01233 {
01234
01235 perturbation_field_3d( t_p(joker,joker,joker),
01236 p_gp, lat_gp, lon_gp, jg[0].nelem()+2,
01237 jg[1].nelem()+2, jg[2].nelem()+2,
01238 p_range, lat_range, lon_range,
01239 rq.Perturbation(), pertmode );
01240 break;
01241 }
01242 }
01243
01244
01245 out2 << " Calculating perturbed spectra no. " << it+1 << " of "
01246 << ji[1]+1 << "\n";
01247
01248
01249 jacobian_y_agendaExecute( ws, yp, vmr_field, t_p, pnd_field,
01250 sensor_los, jacobian_y_agenda );
01251
01252
01253 for( Index y_it=0; y_it<y.nelem(); y_it++ )
01254 { J(y_it,it) = ( yp[y_it] - y[y_it] ) / rq.Perturbation(); }
01255
01256
01257 it++;
01258 }
01259 }
01260 }
01261 }
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528
01529
01530
01531
01532
01533
01534
01535
01536
01537
01538
01539
01540
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550
01551
01552
01553
01554
01555
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
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
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
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