00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00026 #include <algorithm>
00027 #include <map>
00028 #include <limits>
00029
00030 #include "auto_md.h"
00031 #include "arts.h"
00032 #include "messages.h"
00033 #include "gas_abs_lookup.h"
00034 #include "agenda_class.h"
00035 #include "check_input.h"
00036 #include "matpackV.h"
00037 #include "physics_funcs.h"
00038 #include "math_funcs.h"
00039 #include "make_vector.h"
00040 #include "arts_omp.h"
00041 #include "interpolation_poly.h"
00042
00043 extern const Index GFIELD4_FIELD_NAMES;
00044 extern const Index GFIELD4_P_GRID;
00045
00046
00047
00048 void abs_lookupInit(GasAbsLookup& )
00049 {
00050
00051
00052
00053 out2 << " Created an empty gas absorption lookup table.\n";
00054 }
00055
00056
00057
00058 void abs_lookupCreate(
00059 GasAbsLookup& abs_lookup,
00060 Index& abs_lookup_is_adapted,
00061
00062 const ArrayOfArrayOfSpeciesTag& abs_species,
00063 const ArrayOfArrayOfLineRecord& abs_lines_per_species,
00064 const ArrayOfLineshapeSpec& abs_lineshape,
00065 const ArrayOfArrayOfSpeciesTag& abs_nls,
00066 const Vector& f_grid,
00067 const Vector& abs_p,
00068 const Matrix& abs_vmrs,
00069 const Vector& abs_t,
00070 const Vector& abs_t_pert,
00071 const Vector& abs_nls_pert,
00072 const Vector& abs_n2,
00073 const ArrayOfString& abs_cont_names,
00074 const ArrayOfString& abs_cont_models,
00075 const ArrayOfVector& abs_cont_parameters )
00076 {
00077
00078
00079 int omp_nested_original = arts_omp_get_nested();
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 Matrix these_abs_coef;
00091
00092
00093 ArrayOfMatrix abs_xsec_per_species;
00094
00095
00096
00097 const Index n_species = abs_species.nelem();
00098 const Index n_nls = abs_nls.nelem();
00099 const Index n_f_grid = f_grid.nelem();
00100 const Index n_p_grid = abs_p.nelem();
00101 const Index n_t_pert = abs_t_pert.nelem();
00102 const Index n_nls_pert = abs_nls_pert.nelem();
00103
00104
00105
00106
00107 Matrix this_vmr(1,n_p_grid);
00108 Vector abs_h2o(n_p_grid);
00109 Vector this_t;
00110
00111
00112
00113 ArrayOfArrayOfSpeciesTag this_species(1);
00114 ArrayOfArrayOfLineRecord these_lines(1);
00115 ArrayOfLineshapeSpec this_lineshape(1);
00116
00117
00118 Vector these_nls_pert;
00119 Vector these_t_pert;
00120
00121
00122
00123 const Index h2o_index
00124 = find_first_species_tg( abs_species,
00125 species_index_from_species_name("H2O") );
00126
00127 if ( h2o_index < 0 )
00128 {
00129
00130
00131
00132 if (n_nls>0)
00133 {
00134 ostringstream os;
00135 os << "If you have nonlinear species, at least one\n"
00136 << "species must be a H2O species.";
00137 throw runtime_error( os.str() );
00138 }
00139 else
00140 {
00141 out2 << " You have no H2O species. Absorption continua will not work.\n"
00142 << " You should get a runtime error if you try them anyway.\n";
00143 }
00144 }
00145
00146
00147 if ( 0==n_species ||
00148 0==n_f_grid ||
00149 0==n_p_grid )
00150 {
00151 ostringstream os;
00152 os << "One of the required input variables is empty:\n"
00153 << "abs_species.nelem() = " << n_species << ",\n"
00154 << "f_grid.nelem() = " << n_f_grid << ",\n"
00155 << "abs_p.nelem() = " << n_p_grid << ".";
00156 throw runtime_error( os.str() );
00157 }
00158
00159
00160
00161
00162 ArrayOfIndex abs_nls_idx;
00163 for (Index i=0; i<n_nls; ++i)
00164 {
00165 Index s;
00166 for (s=0; s<n_species; ++s)
00167 {
00168 if (abs_nls[i]==abs_species[s])
00169 {
00170 abs_nls_idx.push_back(s);
00171 break;
00172 }
00173 }
00174 if (s==n_species)
00175 {
00176 ostringstream os;
00177 os << "Did not find *abs_nls* tag group \""
00178 << get_tag_group_name(abs_nls[i])
00179 << "\" in *abs_species*.";
00180 throw runtime_error( os.str() );
00181 }
00182 }
00183
00184
00185 if ( !is_unique(abs_nls_idx) )
00186 {
00187 ostringstream os;
00188 os << "The variable *abs_nls* must not have duplicate species.\n"
00189 << "Value of *abs_nls*: " << abs_nls_idx;
00190 throw runtime_error( os.str() );
00191 }
00192
00193
00194 if (abs_lines_per_species.nelem() != abs_species.nelem())
00195 {
00196 ostringstream os;
00197 os << "Dimensions of *abs_species* and *abs_lines_per_species* must match.";
00198 throw runtime_error( os.str() );
00199 }
00200
00201
00202 chk_size( "abs_vmrs",
00203 abs_vmrs,
00204 n_species,
00205 n_p_grid );
00206
00207
00208 chk_size( "abs_t",
00209 abs_t,
00210 n_p_grid );
00211
00212
00213 if ( ( (0==n_nls) && (0!=n_nls_pert) ) ||
00214 ( (0!=n_nls) && (0==n_nls_pert) ) )
00215 {
00216 ostringstream os;
00217 os << "You have to set both abs_nls and abs_nls_pert, or none.";
00218 throw runtime_error( os.str() );
00219 }
00220
00221
00222
00223 ArrayOfIndex non_linear(n_species,0);
00224 for ( Index s=0; s<n_nls; ++s )
00225 {
00226 non_linear[abs_nls_idx[s]] = 1;
00227 }
00228
00229
00230
00231 abs_lookup.species = abs_species;
00232 abs_lookup.nonlinear_species = abs_nls_idx;
00233 abs_lookup.f_grid = f_grid;
00234 abs_lookup.p_grid = abs_p;
00235 abs_lookup.vmrs_ref = abs_vmrs;
00236 abs_lookup.t_ref = abs_t;
00237 abs_lookup.t_pert = abs_t_pert;
00238 abs_lookup.nls_pert = abs_nls_pert;
00239
00240
00241 abs_lookup.log_p_grid.resize(n_p_grid);
00242 transform( abs_lookup.log_p_grid, log, abs_lookup.p_grid );
00243
00244
00245
00246 {
00247 Index a,b,c,d;
00248
00249 if ( 0 == n_t_pert ) a = 1;
00250 else a = n_t_pert;
00251
00252 b = n_species + n_nls * ( n_nls_pert - 1 );
00253
00254 c = n_f_grid;
00255
00256 d = n_p_grid;
00257
00258 abs_lookup.xsec.resize( a, b, c, d );
00259 }
00260
00261
00262
00263
00264 if ( 0!=n_t_pert)
00265 {
00266 out2 << " With temperature perturbations.\n";
00267 these_t_pert.resize(n_t_pert);
00268 these_t_pert = abs_t_pert;
00269 }
00270 else
00271 {
00272 out2 << " No temperature perturbations.\n";
00273 these_t_pert.resize(1);
00274 these_t_pert = 0;
00275
00276
00277
00278
00279
00280 arts_omp_set_nested(1);
00281 }
00282
00283 const Index these_t_pert_nelem = these_t_pert.nelem();
00284
00285
00286
00287
00288
00289 for ( Index i=0,spec=0; i<n_species; ++i )
00290 {
00291
00292
00293
00294 out2 << " Doing species " << i+1 << " of " << n_species << ": "
00295 << abs_species[i] << ".\n";
00296
00297
00298 this_species[0].resize(abs_species[i].nelem());
00299 this_species[0] = abs_species[i];
00300
00301
00302 these_lines[0].resize(abs_lines_per_species[i].nelem());
00303 these_lines[0] = abs_lines_per_species[i];
00304
00305
00306
00307
00308 if (1==abs_lineshape.nelem())
00309 this_lineshape[0] = abs_lineshape[0];
00310 else
00311 this_lineshape[0] = abs_lineshape[i];
00312
00313
00314
00315
00316 if ( non_linear[i] )
00317 {
00318 out2 << " This is a species with H2O VMR perturbations.\n";
00319 these_nls_pert.resize(n_nls_pert);
00320 these_nls_pert = abs_nls_pert;
00321 }
00322 else
00323 {
00324 these_nls_pert.resize(1);
00325 these_nls_pert = 1;
00326 }
00327
00328
00329 for ( Index s=0; s<these_nls_pert.nelem(); ++s,++spec )
00330 {
00331
00332
00333
00334 if ( non_linear[i] )
00335 {
00336 out2 << " Doing H2O VMR variant " << s+1 << " of " << n_nls_pert << ": "
00337 << abs_nls_pert[s] << ".\n";
00338 }
00339
00340
00341 this_vmr(0,joker) = abs_vmrs(i,joker);
00342 if ( i==h2o_index )
00343 {
00344
00345 this_vmr(0,joker) *= these_nls_pert[s];
00346 }
00347
00348
00349
00350
00351
00352
00353
00354 if ( h2o_index == -1 )
00355 {
00356
00357 abs_h2o.resize(1);
00358 abs_h2o = -1;
00359 }
00360 else
00361 {
00362
00363 abs_h2o = abs_vmrs(h2o_index, joker);
00364 abs_h2o *= these_nls_pert[s];
00365 }
00366
00367
00368
00369
00370
00371
00372
00373 #pragma omp parallel private(this_t, abs_xsec_per_species)
00374 #pragma omp for
00375 for ( Index j=0; j<these_t_pert_nelem; ++j )
00376 {
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 try
00393 {
00394 if ( 0!=n_t_pert )
00395 {
00396 out3 << " Doing temperature variant " << j+1
00397 << " of " << n_t_pert << ": "
00398 << these_t_pert[j] << ".\n";
00399 }
00400
00401
00402 this_t = abs_lookup.t_ref;
00403 this_t += these_t_pert[j];
00404
00405
00406
00407
00408 abs_xsec_per_speciesInit( abs_xsec_per_species, this_species,
00409 f_grid, abs_p );
00410
00411 abs_xsec_per_speciesAddLines( abs_xsec_per_species,
00412 this_species,
00413 f_grid,
00414 abs_p,
00415 this_t,
00416 abs_h2o,
00417 this_vmr,
00418 these_lines,
00419 this_lineshape );
00420
00421 abs_xsec_per_speciesAddConts( abs_xsec_per_species,
00422 this_species,
00423 f_grid,
00424 abs_p,
00425 this_t,
00426 abs_n2,
00427 abs_h2o,
00428 this_vmr,
00429 abs_cont_names,
00430 abs_cont_parameters,
00431 abs_cont_models);
00432
00433
00434
00435 for ( Index p=0; p<n_p_grid; ++p )
00436 {
00437 abs_lookup.xsec( j, spec, Range(joker), p )
00438 = abs_xsec_per_species[0](Range(joker),p);
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458 }
00459 }
00460 catch (runtime_error e)
00461 {
00462 exit_or_rethrow(e.what());
00463 }
00464 }
00465 }
00466 }
00467
00468
00469
00470 abs_lookup_is_adapted = 1;
00471
00472
00473 arts_omp_set_nested(omp_nested_original);
00474 }
00475
00476
00478
00495 void find_nonlinear_continua(ArrayOfIndex& cont,
00496 const ArrayOfArrayOfSpeciesTag& abs_species)
00497 {
00498 cont.resize(0);
00499
00500
00501
00502
00503
00504
00505 for ( Index i=0; i<abs_species.nelem(); ++i )
00506 {
00507 extern const Array<SpeciesRecord> species_data;
00508
00509
00510 for ( Index s=0; s<abs_species[i].nelem(); ++s )
00511 {
00512
00513
00514
00515 if ( abs_species[i][s].Isotope() <
00516 species_data[abs_species[i][s].Species()].Isotope().nelem() )
00517 {
00518
00519 if ( 0 >
00520 species_data[abs_species[i][s].Species()].Isotope()[abs_species[i][s].Isotope()].Abundance() )
00521 {
00522 const String thisname = abs_species[i][s].Name();
00523
00524 out3 << " Continuum tag: " << thisname;
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539 if ( species_index_from_species_name("H2O")==abs_species[i][s].Species() ||
00540 "N2-"==thisname.substr(0,3) ||
00541 "CO2-"==thisname.substr(0,4) ||
00542 "O2-CIA"==thisname.substr(0,6) ||
00543 "O2-v0v"==thisname.substr(0,6) ||
00544 "O2-v1v"==thisname.substr(0,6) )
00545 {
00546 out3 << " --> not added.\n";
00547 break;
00548 }
00549
00550
00551 if ( "O2-"==thisname.substr(0,3) )
00552 {
00553 cont.push_back(i);
00554 out3 << " --> added to abs_nls.\n";
00555 break;
00556 }
00557
00558
00559
00560
00561 out3 << " --> unknown.\n";
00562 throw runtime_error("I don't know whether this tag uses h2o_abs or not.\n"
00563 "Cannot set abs_nls automatically.");
00564 }
00565 }
00566 }
00567 }
00568 }
00569
00570
00572
00580 void choose_abs_nls(ArrayOfArrayOfSpeciesTag& abs_nls,
00581 const ArrayOfArrayOfSpeciesTag& abs_species)
00582 {
00583 abs_nls.resize(0);
00584
00585
00586 Index next_h2o = 0;
00587 while (-1 != (next_h2o =
00588 find_next_species_tg(abs_species,
00589 species_index_from_species_name("H2O"),
00590 next_h2o)))
00591 {
00592 abs_nls.push_back(abs_species[next_h2o]);
00593 ++next_h2o;
00594 }
00595
00596
00597
00598 ArrayOfIndex cont;
00599 find_nonlinear_continua(cont, abs_species);
00600
00601
00602 for (Index i=0; i<cont.nelem(); ++i)
00603 {
00604 abs_nls.push_back(abs_species[cont[i]]);
00605 }
00606
00607 out2 << " Species marked for nonlinear treatment:\n";
00608 for (Index i=0; i<abs_nls.nelem(); ++i)
00609 {
00610 out2 << " ";
00611 for (Index j=0; j<abs_nls[i].nelem(); ++j)
00612 {
00613 if (j!=0) out2 << ", ";
00614 out2 << abs_nls[i][j].Name();
00615 }
00616 out2 << "\n";
00617 }
00618 }
00619
00620
00622
00635 void choose_abs_t_pert(Vector& abs_t_pert,
00636 ConstVectorView abs_t,
00637 ConstVectorView tmin,
00638 ConstVectorView tmax,
00639 const Numeric& step,
00640 const Index& p_interp_order,
00641 const Index& t_interp_order)
00642 {
00643
00644
00645
00646
00647
00648
00649
00650 Numeric mindev = 1e9;
00651 Numeric maxdev = -1e9;
00652
00653 Vector the_grid(0,abs_t.nelem(),1);
00654 for (Index i=0; i<the_grid.nelem(); ++i)
00655 {
00656 GridPosPoly gp;
00657 gridpos_poly(gp, the_grid, (Numeric)i, p_interp_order);
00658
00659 for (Index j=0; j<gp.idx.nelem(); ++j)
00660 {
00661
00662
00663
00664
00665
00666
00667 Numeric delta_min = tmin[i] - abs_t[gp.idx[j]] - 10;
00668 Numeric delta_max = tmax[i] - abs_t[gp.idx[j]] + 10;
00669
00670 if ( delta_min < mindev ) mindev = delta_min;
00671 if ( delta_max > maxdev ) maxdev = delta_max;
00672 }
00673 }
00674
00675 out3 << " abs_t_pert: mindev/maxdev : " << mindev << " / " << maxdev << "\n";
00676
00677
00678
00679
00680 Index div = t_interp_order;
00681 Numeric effective_step;
00682 do
00683 {
00684 effective_step = (maxdev-mindev)/(Numeric)div;
00685 ++div;
00686 }
00687 while (effective_step > step);
00688
00689 abs_t_pert = Vector(mindev, div, effective_step);
00690
00691 out2 << " abs_t_pert: " << abs_t_pert[0] << " K to " << abs_t_pert[abs_t_pert.nelem()-1]
00692 << " K in steps of " << effective_step
00693 << " K (" << abs_t_pert.nelem() << " grid points)\n";
00694 }
00695
00696
00698
00711 void choose_abs_nls_pert(Vector& abs_nls_pert,
00712 ConstVectorView refprof,
00713 ConstVectorView minprof,
00714 ConstVectorView maxprof,
00715 const Numeric& step,
00716 const Index& p_interp_order,
00717 const Index& nls_interp_order)
00718 {
00719
00720
00721
00722
00723
00724
00725
00726 Numeric mindev = 0;
00727 Numeric maxdev = -1e9;
00728
00729
00730
00731
00732 Vector the_grid(0,refprof.nelem(),1);
00733 for (Index i=0; i<the_grid.nelem(); ++i)
00734 {
00735
00736
00737
00738
00739
00740 GridPosPoly gp;
00741 gridpos_poly(gp, the_grid, (Numeric)i, p_interp_order);
00742
00743 for (Index j=0; j<gp.idx.nelem(); ++j)
00744 {
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756 Numeric delta_min = minprof[i] / refprof[gp.idx[j]];
00757 Numeric delta_max = 2*maxprof[i] / refprof[gp.idx[j]];
00758
00759 if ( delta_min < mindev ) mindev = delta_min;
00760 if ( delta_max > maxdev ) maxdev = delta_max;
00761 }
00762 }
00763
00764 out3 << " abs_nls_pert: mindev/maxdev : " << mindev << " / " << maxdev << "\n";
00765
00766 bool allownegative = false;
00767 if (mindev<0)
00768 {
00769 out2 << " Warning: I am getting a negative fractional distance to the H2O\n"
00770 << " reference profile. Some of your H2O fields may contain negative values.\n"
00771 << " Will allow negative values also for abs_nls_pert.\n";
00772 allownegative = true;
00773 }
00774
00775 if (!allownegative)
00776 {
00777 mindev = 0;
00778 out3 << " Adjusted mindev : " << mindev << "\n";
00779 }
00780
00781
00782
00783
00784 Index div = nls_interp_order;
00785 Numeric effective_step;
00786 do
00787 {
00788 effective_step = (maxdev-mindev)/(Numeric)div;
00789 ++div;
00790 }
00791 while (effective_step > step);
00792
00793 abs_nls_pert = Vector(mindev, div, effective_step);
00794
00795
00796
00797 if (allownegative)
00798 {
00799 VectorInsertGridPoints(abs_nls_pert, abs_nls_pert, MakeVector(0));
00800 out2 << " I am including also 0 in the abs_nls_pert, because it is a turning \n"
00801 << " point. Consider to use a higher abs_nls_interp_order, for example 4.\n";
00802 }
00803
00804 out2 << " abs_nls_pert: " << abs_nls_pert[0] << " to " << abs_nls_pert[abs_nls_pert.nelem()-1]
00805 << " (fractional units) in steps of " << abs_nls_pert[1]-abs_nls_pert[0]
00806 << " (" << abs_nls_pert.nelem() << " grid points)\n";
00807
00808 }
00809
00810
00811
00812 void abs_lookupSetup(
00813 Vector& abs_p,
00814 Vector& abs_t,
00815 Vector& abs_t_pert,
00816 Matrix& abs_vmrs,
00817 ArrayOfArrayOfSpeciesTag& abs_nls,
00818 Vector& abs_nls_pert,
00819
00820 const Index& atmosphere_dim,
00821 const Vector& p_grid,
00822 const Vector& lat_grid,
00823 const Vector& lon_grid,
00824 const Tensor3& t_field,
00825 const Tensor4& vmr_field,
00826 const ArrayOfArrayOfSpeciesTag& abs_species,
00827 const Index& abs_p_interp_order,
00828 const Index& abs_t_interp_order,
00829 const Index& abs_nls_interp_order,
00830
00831 const Numeric& p_step10,
00832 const Numeric& t_step,
00833 const Numeric& h2o_step)
00834 {
00835
00836
00837
00838 const Numeric p_step = log(pow(10.0, p_step10));
00839
00840
00841
00842
00843
00844
00845
00846
00847
00848 chk_atm_grids(atmosphere_dim, p_grid, lat_grid, lon_grid);
00849
00850 if (p_grid.nelem()<2)
00851 {
00852 ostringstream os;
00853 os << "You need at least two pressure levels.";
00854 throw runtime_error( os.str() );
00855 }
00856
00857
00858 chk_atm_field("t_field", t_field, atmosphere_dim,
00859 p_grid, lat_grid, lon_grid);
00860
00861
00862 chk_atm_field("vmr_field", vmr_field, atmosphere_dim,
00863 abs_species.nelem(), p_grid, lat_grid, lon_grid);
00864
00865
00866 if ( p_step <= 0 || t_step <= 0 || h2o_step <= 0 )
00867 {
00868 ostringstream os;
00869 os << "The keyword arguments p_step, t_step, and h2o_step must be >0.";
00870 throw runtime_error( os.str() );
00871 }
00872
00873
00874
00875
00876
00877 Vector log_p_grid(p_grid.nelem());
00878 transform(log_p_grid, log, p_grid);
00879
00880
00881
00882
00883
00884
00885
00886 ArrayOfNumeric log_abs_p_a;
00887
00888
00889
00890
00891
00892
00893
00894 log_abs_p_a.push_back(log_p_grid[0]);
00895
00896 for (Index i=1; i<log_p_grid.nelem(); ++i)
00897 {
00898 const Numeric dp = log_p_grid[i-1] - log_p_grid[i];
00899
00900 const Numeric dp_by_p_step = dp/p_step;
00901
00902
00903
00904 const Index n = (Index) ceil(dp_by_p_step);
00905
00906
00907
00908
00909
00910 const Numeric ddp = dp/(Numeric)n;
00911
00912
00913 for (Index j=1; j<=n; ++j)
00914 log_abs_p_a.push_back(log_p_grid[i-1] - (Numeric)j*ddp);
00915 }
00916
00917
00918
00919 Vector log_abs_p(log_abs_p_a.nelem());
00920 for (Index i=0; i<log_abs_p_a.nelem(); ++i)
00921 log_abs_p[i] = log_abs_p_a[i];
00922
00923
00924 abs_p.resize(log_abs_p.nelem());
00925 transform(abs_p, exp, log_abs_p);
00926
00927
00928 if (abs_p.nelem()<abs_p_interp_order+1)
00929 {
00930 ostringstream os;
00931 os << "Your pressure grid does not have enough levels for the desired interpolation order.";
00932 throw runtime_error( os.str() );
00933 }
00934
00935
00936
00937
00938
00939 ArrayOfGridPos gp(log_abs_p.nelem());
00940 gridpos(gp, log_p_grid, log_abs_p);
00941
00942
00943 Matrix itw(gp.nelem(),2);
00944 interpweights(itw,gp);
00945
00946
00947
00948
00949 if (1==atmosphere_dim)
00950 {
00951
00952
00953 abs_t.resize(log_abs_p.nelem());
00954 interp(abs_t,
00955 itw,
00956 t_field(joker,0,0),
00957 gp);
00958
00959
00960 abs_t_pert.resize(0);
00961
00962
00963
00964 abs_vmrs.resize(abs_species.nelem(), log_abs_p.nelem());
00965 for (Index i=0; i<abs_species.nelem(); ++i)
00966 interp(abs_vmrs(i,joker),
00967 itw,
00968 vmr_field(i,joker,0,0),
00969 gp);
00970
00971
00972 abs_nls.resize(0);
00973
00974
00975 abs_nls_pert.resize(0);
00976 }
00977 else
00978 {
00979
00980
00981
00982 choose_abs_nls(abs_nls, abs_species);
00983
00984
00985
00986
00987
00988
00989
00990
00991 Vector tmin(p_grid.nelem());
00992 Vector tmax(p_grid.nelem());
00993 Vector tmean(p_grid.nelem());
00994
00995 for (Index i=0; i<p_grid.nelem(); ++i)
00996 {
00997 tmin[i] = min(t_field(i,joker,joker));
00998 tmax[i] = max(t_field(i,joker,joker));
00999 tmean[i] = mean(t_field(i,joker,joker));
01000 }
01001
01002
01003
01004
01005
01006
01007
01008 Matrix vmrmean(abs_species.nelem(), p_grid.nelem());
01009 for (Index s=0; s<abs_species.nelem(); ++s)
01010 for (Index i=0; i<p_grid.nelem(); ++i)
01011 {
01012 vmrmean(s,i) = mean(vmr_field(s,i,joker,joker));
01013 }
01014
01015
01016
01017
01018
01019 Vector h2omin(p_grid.nelem());
01020 Vector h2omax(p_grid.nelem());
01021 const Index h2o_index
01022 = find_first_species_tg( abs_species,
01023 species_index_from_species_name("H2O") );
01024
01025
01026
01027
01028
01029 if (0<abs_nls.nelem())
01030 {
01031
01032 if (h2o_index<0)
01033 {
01034 ostringstream os;
01035 os << "Some of your species require nonlinear treatment,\n"
01036 << "but you have no H2O species.";
01037 throw runtime_error( os.str() );
01038 }
01039
01040 for (Index i=0; i<p_grid.nelem(); ++i)
01041 {
01042 h2omin[i] = min(vmr_field(h2o_index,i,joker,joker));
01043 h2omax[i] = max(vmr_field(h2o_index,i,joker,joker));
01044 }
01045
01046
01047
01048
01049
01050 }
01051
01052
01053
01054
01055
01056
01057 abs_t.resize(log_abs_p.nelem());
01058 interp(abs_t,
01059 itw,
01060 tmean,
01061 gp);
01062
01063
01064 choose_abs_t_pert(abs_t_pert, tmean, tmin, tmax, t_step, abs_p_interp_order, abs_t_interp_order);
01065
01066
01067
01068
01069 abs_vmrs.resize(abs_species.nelem(), log_abs_p.nelem());
01070 for (Index i=0; i<abs_species.nelem(); ++i)
01071 interp(abs_vmrs(i,joker),
01072 itw,
01073 vmrmean(i,joker),
01074 gp);
01075
01076 if (0<abs_nls.nelem())
01077 {
01078
01079 choose_abs_nls_pert(abs_nls_pert,
01080 vmrmean(h2o_index, joker),
01081 h2omin,
01082 h2omax,
01083 h2o_step,
01084 abs_p_interp_order,
01085 abs_nls_interp_order);
01086 }
01087 else
01088 {
01089
01090 abs_nls_pert.resize(0);
01091 }
01092
01093
01094 }
01095 }
01096
01097
01098
01099 void abs_lookupSetupBatch(
01100 Vector& abs_p,
01101 Vector& abs_t,
01102 Vector& abs_t_pert,
01103 Matrix& abs_vmrs,
01104 ArrayOfArrayOfSpeciesTag& abs_nls,
01105 Vector& abs_nls_pert,
01106
01107 const ArrayOfArrayOfSpeciesTag& abs_species,
01108 const ArrayOfGField4& batch_fields,
01109 const Index& abs_p_interp_order,
01110 const Index& abs_t_interp_order,
01111 const Index& abs_nls_interp_order,
01112
01113 const Numeric& p_step10,
01114 const Numeric& t_step,
01115 const Numeric& h2o_step,
01116 const Vector& extremes)
01117 {
01118
01119
01120
01121 const Numeric p_step = log(pow(10.0, p_step10));
01122
01123
01124
01125
01126
01127
01128
01129
01130 choose_abs_nls(abs_nls, abs_species);
01131
01132
01133 Numeric maxp=batch_fields[0].get_numeric_grid(GFIELD4_P_GRID)[0];
01134 Numeric minp=batch_fields[0].get_numeric_grid(GFIELD4_P_GRID)[batch_fields[0].get_numeric_grid(GFIELD4_P_GRID).nelem()-1];
01135 for (Index i=0; i<batch_fields.nelem(); ++i)
01136 {
01137 if (maxp < batch_fields[i].get_numeric_grid(GFIELD4_P_GRID)[0])
01138 maxp = batch_fields[i].get_numeric_grid(GFIELD4_P_GRID)[0];
01139 if (minp > batch_fields[i].get_numeric_grid(GFIELD4_P_GRID)[batch_fields[i].get_numeric_grid(GFIELD4_P_GRID).nelem()-1])
01140 minp = batch_fields[i].get_numeric_grid(GFIELD4_P_GRID)[batch_fields[i].get_numeric_grid(GFIELD4_P_GRID).nelem()-1];
01141 }
01142
01143
01144 if (maxp==minp)
01145 {
01146 ostringstream os;
01147 os << "You need at least two pressure levels.";
01148 throw runtime_error( os.str() );
01149 }
01150
01151
01152
01153
01154
01155
01156
01157 Index np = (Index) ceil((log(maxp)-log(minp))/p_step)+1;
01158
01159
01160
01161
01162 if (np < abs_p_interp_order+1)
01163 np = abs_p_interp_order+1;
01164
01165 Vector log_abs_p(log(maxp), np, -p_step);
01166 log_abs_p[np-1] = log(minp);
01167
01168 abs_p.resize(np);
01169 transform(abs_p, exp, log_abs_p);
01170 out2 << " abs_p: " << abs_p[0] << " Pa to " << abs_p[np-1]
01171 << " Pa in log10 steps of " << p_step10
01172 << " (" << np << " grid points)\n";
01173
01174
01175
01176
01177 Index n_variables = batch_fields[0].nbooks();
01178
01179
01180
01181
01182
01183 Matrix datamin (n_variables, np, numeric_limits<Numeric>::max());
01184 Matrix datamax (n_variables, np, numeric_limits<Numeric>::min());
01185
01186 Matrix datamean (n_variables, np, 0);
01187 Vector mean_norm(np,0);
01188
01189
01190
01191
01192
01193
01194 Numeric mint=+1e99;
01195 Numeric maxt=-1e99;
01196 Numeric minh2o=+1e99;
01197 Numeric maxh2o=-1e99;
01198
01199 for (Index i=0; i<batch_fields.nelem(); ++i)
01200 {
01201
01202
01203 if (batch_fields[i].get_string_grid(GFIELD4_FIELD_NAMES)
01204 != batch_fields[0].get_string_grid(GFIELD4_FIELD_NAMES))
01205 throw runtime_error("All fields in the batch must have the same field names.");
01206
01207
01208
01209 if ("T" != batch_fields[i].get_string_grid(GFIELD4_FIELD_NAMES)[0])
01210 {
01211 ostringstream os;
01212 os << "The first variable in the compact atmospheric state must be \"T\",\n"
01213 << "but yours is: " << batch_fields[i].get_string_grid(GFIELD4_FIELD_NAMES)[0];
01214 throw runtime_error( os.str() );
01215 }
01216
01217 if ("H2O" != batch_fields[i].get_string_grid(GFIELD4_FIELD_NAMES)[2])
01218 {
01219 ostringstream os;
01220 os << "The third variable in the compact atmospheric state must be \"H2O\",\n"
01221 << "but yours is: " << batch_fields[i].get_string_grid(GFIELD4_FIELD_NAMES)[0];
01222 throw runtime_error( os.str() );
01223 }
01224
01225
01226 const Vector& p_grid = batch_fields[i].get_numeric_grid(GFIELD4_P_GRID);
01227 const Tensor4& data = batch_fields[i];
01228
01229
01230
01231
01232
01233
01234
01235 for (Index ip=0; ip<data.npages(); ++ip)
01236 for (Index ilat=0; ilat<data.nrows(); ++ilat)
01237 for (Index ilon=0; ilon<data.ncols(); ++ilon)
01238 {
01239
01240 if (data(0,ip,ilat,ilon) < mint) mint = data(0,ip,ilat,ilon);
01241 if (data(0,ip,ilat,ilon) > maxt) maxt = data(0,ip,ilat,ilon);
01242
01243 if (data(2,ip,ilat,ilon) < minh2o) minh2o = data(2,ip,ilat,ilon);
01244 if (data(2,ip,ilat,ilon) > maxh2o) maxh2o = data(2,ip,ilat,ilon);
01245 }
01246
01247
01248
01249
01250
01251 Vector log_p_grid(p_grid.nelem());
01252 transform(log_p_grid, log, p_grid);
01253
01254
01255
01256
01257
01258
01259
01260 const Numeric eps_bottom = (log_p_grid[0]-log_p_grid[1])/2.1;
01261 Index first_p=0;
01262 while (log_abs_p[first_p] > log_p_grid[0]+eps_bottom) ++first_p;
01263
01264 const Numeric eps_top = (log_p_grid[log_p_grid.nelem()-2]-log_p_grid[log_p_grid.nelem()-1])/2.1;
01265 Index last_p=log_abs_p.nelem()-1;
01266 while (log_abs_p[last_p] < log_p_grid[log_p_grid.nelem()-1]-eps_top) --last_p;
01267
01268 const Index extent_p = last_p - first_p + 1;
01269
01270
01271
01272
01273
01274
01275 ConstVectorView active_log_abs_p = log_abs_p[Range(first_p, extent_p)];
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285 ArrayOfGridPos gp(active_log_abs_p.nelem());
01286 gridpos(gp, log_p_grid, active_log_abs_p);
01287
01288
01289
01290
01291
01292
01293 Matrix itw(gp.nelem(),2);
01294 interpweights(itw,gp);
01295
01296
01297
01298
01299 Tensor4 data_interp(data.nbooks(),
01300 active_log_abs_p.nelem(),
01301 data.nrows(),
01302 data.ncols());
01303
01304 for (Index lo=0; lo<data.ncols(); ++lo)
01305 for (Index la=0; la<data.nrows(); ++la)
01306 for (Index fi=0; fi<data.nbooks(); ++fi)
01307 interp(data_interp(fi, joker, la, lo),
01308 itw,
01309 data(fi, joker, la, lo),
01310 gp);
01311
01312
01313
01314
01315
01316
01317
01318 for (Index lo=0; lo<data_interp.ncols(); ++lo)
01319 for (Index la=0; la<data_interp.nrows(); ++la)
01320 {
01321 for (Index fi=0; fi<data_interp.nbooks(); ++fi)
01322 {
01323 if (1!=fi)
01324 for (Index pr=0; pr<data_interp.npages(); ++pr)
01325 {
01326 if (0==fi || 2==fi)
01327
01328 {
01329 if (data_interp(fi, pr, la, lo) < datamin(fi, first_p+pr))
01330 datamin(fi, first_p+pr) = data_interp(fi, pr, la, lo);
01331 if (data_interp(fi, pr, la, lo) > datamax(fi, first_p+pr))
01332 datamax(fi, first_p+pr) = data_interp(fi, pr, la, lo);
01333 }
01334
01335 datamean(fi, first_p+pr) += data_interp(fi, pr, la, lo);
01336 }
01337 }
01338
01339
01340
01341
01342
01343
01344 mean_norm[Range(first_p, extent_p)] += 1;
01345 }
01346 }
01347
01348 out2 << " Global statistics:\n"
01349 << " min(p) / max(p) [Pa]: " << minp << " / " << maxp << "\n"
01350 << " min(T) / max(T) [K]: " << mint << " / " << maxt << "\n"
01351 << " min(H2O) / max(H2O) [VMR]: " << minh2o << " / " << maxh2o << "\n";
01352
01353
01354
01355 assert(np==mean_norm.nelem());
01356 for (Index fi=0; fi<datamean.nrows(); ++fi)
01357 if (1!=fi)
01358 for (Index pi=0; pi<np; ++pi)
01359 {
01360
01361
01362
01363 if (0<mean_norm[pi])
01364 datamean(fi,pi) /= mean_norm[pi];
01365 else
01366 {
01367 ostringstream os;
01368 os << "No data at pressure level " << pi+1
01369 << " of "<< np << " (" << abs_p[pi] << " hPa).";
01370 throw runtime_error( os.str() );
01371 }
01372 }
01373
01374
01375
01376
01377
01378 assert(log_abs_p.nelem()==np);
01379 Matrix smooth_datamean(datamean.nrows(), datamean.ncols(), 0);
01380 for (Index i=0; i<np; ++i)
01381 {
01382 GridPosPoly gp;
01383 gridpos_poly(gp, log_abs_p, log_abs_p[i], abs_p_interp_order);
01384
01385
01386
01387
01388
01389 for (Index fi=0; fi<datamean.nrows(); ++fi)
01390 if (1!=fi)
01391 {
01392 for (Index j=0; j<gp.idx.nelem(); ++j)
01393 {
01394 smooth_datamean(fi,i) += datamean(fi,gp.idx[j]);
01395 }
01396 smooth_datamean(fi,i) /= (Numeric)gp.idx.nelem();
01397 }
01398
01399
01400
01401 }
01402
01403
01404
01405
01406
01407
01408 for (Index i=0; i<np; ++i)
01409 {
01410
01411 assert("H2O" == batch_fields[0].get_string_grid(GFIELD4_FIELD_NAMES)[2]);
01412
01413
01414 Numeric& mean_h2o = smooth_datamean(2,i);
01415 Numeric& max_h2o = datamax(2,i);
01416 if (mean_h2o <= 0)
01417 {
01418 mean_h2o = 1e-9;
01419 max_h2o = 1e-9;
01420 out3 << " H2O profile contained zero values, adjusted to 1e-9.\n";
01421 }
01422 }
01423
01424
01425 abs_t.resize(np);
01426 abs_t = smooth_datamean(0,joker);
01427
01428
01429
01430
01431
01432 assert(abs_species.nelem()==smooth_datamean.nrows()-2);
01433 abs_vmrs.resize(abs_species.nelem(), np);
01434 abs_vmrs = smooth_datamean(Range(2,abs_species.nelem()),joker);
01435
01436
01437
01438 ConstVectorView tmin = datamin(0,joker);
01439 ConstVectorView tmax = datamax(0,joker);
01440 choose_abs_t_pert(abs_t_pert, abs_t, tmin, tmax, t_step, abs_p_interp_order, abs_t_interp_order);
01441
01442
01443
01444 ConstVectorView h2omin = datamin(2,joker);
01445 ConstVectorView h2omax = datamax(2,joker);
01446 choose_abs_nls_pert(abs_nls_pert, abs_vmrs(0,joker), h2omin, h2omax, h2o_step, abs_p_interp_order, abs_nls_interp_order);
01447
01448
01449
01450 if (0!=extremes.nelem())
01451 {
01452
01453 if (4!=extremes.nelem())
01454 {
01455 ostringstream os;
01456 os << "There must be exactly 4 elements in extremes:\n"
01457 << "min(abs_t_pert), max(abs_t_pert), min(abs_nls_pert), max(abs_nls_pert)";
01458 throw runtime_error( os.str() );
01459 }
01460
01461
01462 if (extremes[0] < abs_t_pert[0])
01463 {
01464 Vector dummy = abs_t_pert;
01465 abs_t_pert.resize(abs_t_pert.nelem()+1);
01466 abs_t_pert[0] = extremes[0];
01467 abs_t_pert[Range(1,dummy.nelem())] = dummy;
01468 out2 << " Added min extreme value for abs_t_pert: "
01469 << abs_t_pert[0] << "\n";
01470 }
01471
01472
01473 if (extremes[1] > abs_t_pert[abs_t_pert.nelem()-1])
01474 {
01475 Vector dummy = abs_t_pert;
01476 abs_t_pert.resize(abs_t_pert.nelem()+1);
01477 abs_t_pert[Range(0,dummy.nelem())] = dummy;
01478 abs_t_pert[abs_t_pert.nelem()-1] = extremes[1];
01479 out2 << " Added max extreme value for abs_t_pert: "
01480 << abs_t_pert[abs_t_pert.nelem()-1] << "\n";
01481 }
01482
01483
01484 if (extremes[2] < abs_nls_pert[0])
01485 {
01486 Vector dummy = abs_nls_pert;
01487 abs_nls_pert.resize(abs_nls_pert.nelem()+1);
01488 abs_nls_pert[0] = extremes[2];
01489 abs_nls_pert[Range(1,dummy.nelem())] = dummy;
01490 out2 << " Added min extreme value for abs_nls_pert: "
01491 << abs_nls_pert[0] << "\n";
01492 }
01493
01494
01495 if (extremes[3] > abs_nls_pert[abs_nls_pert.nelem()-1])
01496 {
01497 Vector dummy = abs_nls_pert;
01498 abs_nls_pert.resize(abs_nls_pert.nelem()+1);
01499 abs_nls_pert[Range(0,dummy.nelem())] = dummy;
01500 abs_nls_pert[abs_nls_pert.nelem()-1] = extremes[3];
01501 out2 << " Added max extreme value for abs_nls_pert: "
01502 << abs_nls_pert[abs_nls_pert.nelem()-1] << "\n";
01503 }
01504 }
01505 }
01506
01507
01508 void abs_lookupSetupWide(
01509 Vector& abs_p,
01510 Vector& abs_t,
01511 Vector& abs_t_pert,
01512 Matrix& abs_vmrs,
01513 ArrayOfArrayOfSpeciesTag& abs_nls,
01514 Vector& abs_nls_pert,
01515
01516 const ArrayOfArrayOfSpeciesTag& abs_species,
01517 const Index& abs_p_interp_order,
01518 const Index& abs_t_interp_order,
01519 const Index& abs_nls_interp_order,
01520
01521 const Numeric& p_min,
01522 const Numeric& p_max,
01523 const Numeric& p_step10,
01524 const Numeric& t_min,
01525 const Numeric& t_max,
01526 const Numeric& h2o_min,
01527 const Numeric& h2o_max)
01528 {
01529
01530
01531
01532 const Numeric p_step = log(pow(10.0, p_step10));
01533
01534
01535 choose_abs_nls(abs_nls, abs_species);
01536
01537
01538
01539
01540
01541
01542
01543
01544 Index np = (Index) ceil((log(p_max)-log(p_min))/p_step)+1;
01545
01546
01547
01548
01549 if (np < abs_p_interp_order+1)
01550 np = abs_p_interp_order+1;
01551
01552 Vector log_abs_p(log(p_max), np, -p_step);
01553
01554 abs_p.resize(np);
01555 transform(abs_p, exp, log_abs_p);
01556 out2 << " abs_p: " << abs_p[0] << " Pa to " << abs_p[np-1]
01557 << " Pa in log10 steps of " << p_step10
01558 << " (" << np << " grid points)\n";
01559
01560
01561
01562
01563
01564
01565
01566 Numeric t_ref = (t_min + t_max) / 2;
01567
01568 abs_t.resize(np);
01569 abs_t = t_ref;
01570
01571
01572
01573 Vector min_prof(np), max_prof(np);
01574 min_prof = t_min;
01575 max_prof = t_max;
01576
01577
01578 choose_abs_t_pert(abs_t_pert,
01579 abs_t, min_prof, max_prof, 100,
01580 abs_p_interp_order, abs_t_interp_order);
01581
01582
01583
01584
01585
01586
01587
01588 Numeric h2o_ref = 1e-6;
01589
01590
01591
01592
01593
01594 abs_vmrs.resize(abs_species.nelem(), np);
01595 abs_vmrs = 0;
01596
01597
01598
01599
01600 const Index o2_index
01601 = find_first_species_tg( abs_species,
01602 species_index_from_species_name("O2") );
01603 if (o2_index>=0)
01604 {
01605 abs_vmrs(o2_index, joker) = 0.2095;
01606 }
01607
01608 const Index n2_index
01609 = find_first_species_tg( abs_species,
01610 species_index_from_species_name("N2") );
01611 if (n2_index>=0)
01612 {
01613 abs_vmrs(n2_index, joker) = 0.7808;
01614 }
01615
01616
01617
01618 const Index h2o_index
01619 = find_first_species_tg( abs_species,
01620 species_index_from_species_name("H2O") );
01621
01622
01623
01624 if (0<abs_nls.nelem())
01625 {
01626 if (h2o_index<0)
01627 {
01628 ostringstream os;
01629 os << "Some of your species require nonlinear treatment,\n"
01630 << "but you have no H2O species.";
01631 throw runtime_error( os.str() );
01632 }
01633
01634
01635 abs_vmrs(h2o_index, joker) = h2o_ref;
01636
01637
01638
01639
01640
01641 min_prof = h2o_min;
01642 max_prof = h2o_max;
01643
01644
01645 choose_abs_nls_pert(abs_nls_pert,
01646 abs_vmrs(h2o_index, joker),
01647 min_prof,
01648 max_prof,
01649 1e99,
01650 abs_p_interp_order,
01651 abs_nls_interp_order);
01652 }
01653 else
01654 {
01655 out1 << " WARNING:\n"
01656 << " You have no species that require H2O variations.\n"
01657 << " This case might work, but it has never been tested.\n"
01658 << " Please test it, then remove this warning.\n";
01659 }
01660 }
01661
01662
01663
01664 void abs_speciesAdd(
01665 ArrayOfArrayOfSpeciesTag& abs_species,
01666
01667 const ArrayOfString& names)
01668 {
01669
01670 Index n_gs = abs_species.nelem();
01671
01672
01673 ArrayOfSpeciesTag temp;
01674
01675
01676
01677 for ( Index i=0; i<names.nelem(); ++i )
01678 {
01679 array_species_tag_from_string( temp, names[i] );
01680 abs_species.push_back(temp);
01681 }
01682
01683
01684 out3 << " Added tag groups:";
01685 for ( Index i=n_gs; i<abs_species.nelem(); ++i )
01686 {
01687 out3 << "\n " << i << ":";
01688 for ( Index s=0; s<abs_species[i].nelem(); ++s )
01689 {
01690 out3 << " " << abs_species[i][s].Name();
01691 }
01692 }
01693 out3 << '\n';
01694 }
01695
01696
01697
01698 void abs_speciesAdd2(
01699 Workspace& ws,
01700 ArrayOfArrayOfSpeciesTag& abs_species,
01701 ArrayOfRetrievalQuantity& jq,
01702 Agenda& jacobian_agenda,
01703
01704 const Matrix& jac,
01705 const Index& atmosphere_dim,
01706 const Vector& p_grid,
01707 const Vector& lat_grid,
01708 const Vector& lon_grid,
01709
01710 const Vector& rq_p_grid,
01711 const Vector& rq_lat_grid,
01712 const Vector& rq_lon_grid,
01713
01714 const String& species,
01715 const String& method,
01716 const String& mode,
01717 const Numeric& dx)
01718 {
01719
01720 ArrayOfSpeciesTag tags;
01721 array_species_tag_from_string( tags, species );
01722 abs_species.push_back( tags );
01723
01724
01725 out3 << " Appended tag group:";
01726 out3 << "\n " << abs_species.nelem()-1 << ":";
01727 for ( Index s=0; s<tags.nelem(); ++s )
01728 {
01729 out3 << " " << tags[s].Name();
01730 }
01731 out3 << '\n';
01732
01733
01734 jacobianAddAbsSpecies( ws, jq, jacobian_agenda, jac, atmosphere_dim,
01735 p_grid, lat_grid, lon_grid, rq_p_grid, rq_lat_grid,
01736 rq_lon_grid, species, method, mode, dx);
01737 }
01738
01739
01740
01741 void abs_speciesInit( ArrayOfArrayOfSpeciesTag& abs_species )
01742 {
01743 abs_species.resize(0);
01744 }
01745
01746
01747
01748 void SpeciesSet(
01749 ArrayOfArrayOfSpeciesTag& abs_species,
01750
01751 const ArrayOfString& names)
01752 {
01753 abs_species.resize(names.nelem());
01754
01755
01756
01757
01758
01759 for ( Index i=0; i<names.nelem(); ++i )
01760 {
01761
01762
01763 array_species_tag_from_string( abs_species[i], names[i] );
01764 }
01765
01766
01767 out3 << " Defined tag groups: ";
01768 for ( Index i=0; i<abs_species.nelem(); ++i )
01769 {
01770 out3 << "\n " << i << ":";
01771 for ( Index s=0; s<abs_species[i].nelem(); ++s )
01772 {
01773 out3 << " " << abs_species[i][s].Name();
01774 }
01775 }
01776 out3 << '\n';
01777 }
01778
01779
01780
01781 void abs_lookupAdapt( GasAbsLookup& abs_lookup,
01782 Index& abs_lookup_is_adapted,
01783 const ArrayOfArrayOfSpeciesTag& abs_species,
01784 const Vector& f_grid)
01785 {
01786 abs_lookup.Adapt( abs_species, f_grid );
01787 abs_lookup_is_adapted = 1;
01788 }
01789
01790
01791
01792 void abs_scalar_gasExtractFromLookup( Matrix& abs_scalar_gas,
01793 const GasAbsLookup& abs_lookup,
01794 const Index& abs_lookup_is_adapted,
01795 const Index& abs_p_interp_order,
01796 const Index& abs_t_interp_order,
01797 const Index& abs_nls_interp_order,
01798 const Index& f_index,
01799 const Numeric& a_pressure,
01800 const Numeric& a_temperature,
01801 const Vector& a_vmr_list)
01802 {
01803
01804 if ( 1!=abs_lookup_is_adapted )
01805 throw runtime_error("Gas absorption lookup table must be adapted,\n"
01806 "use method abs_lookupAdapt.");
01807
01808
01809
01810
01811 abs_lookup.Extract( abs_scalar_gas,
01812 abs_p_interp_order,
01813 abs_t_interp_order,
01814 abs_nls_interp_order,
01815 f_index,
01816 a_pressure,
01817 a_temperature,
01818 a_vmr_list );
01819 }
01820
01821
01822
01823 void abs_fieldCalc(Workspace& ws,
01824
01825 Tensor5& asg_field,
01826
01827 const Agenda& sga_agenda,
01828 const Index& f_index,
01829 const Vector& f_grid,
01830 const Index& atmosphere_dim,
01831 const Vector& p_grid,
01832 const Vector& lat_grid,
01833 const Vector& lon_grid,
01834 const Tensor3& t_field,
01835 const Tensor4& vmr_field )
01836 {
01837 Matrix asg;
01838 Vector a_vmr_list;
01839
01840
01841 const Index n_species = vmr_field.nbooks();
01842
01843
01844 const Index n_frequencies = f_grid.nelem();
01845
01846
01847 const Index n_pressures = p_grid.nelem();
01848
01849
01850 const Index n_latitudes = max( Index(1), lat_grid.nelem() );
01851
01852
01853 const Index n_longitudes = max( Index(1), lon_grid.nelem() );
01854
01855
01856 chk_atm_grids( atmosphere_dim,
01857 p_grid,
01858 lat_grid,
01859 lon_grid );
01860
01861
01862 chk_atm_field( "t_field",
01863 t_field,
01864 atmosphere_dim,
01865 p_grid,
01866 lat_grid,
01867 lon_grid );
01868
01869
01870
01871
01872 chk_atm_field( "vmr_field",
01873 vmr_field,
01874 atmosphere_dim,
01875 n_species,
01876 p_grid,
01877 lat_grid,
01878 lon_grid );
01879
01880
01881 Index f_extent;
01882
01883 if ( f_index < 0 )
01884 {
01885
01886
01887 f_extent = n_frequencies;
01888 }
01889 else
01890 {
01891
01892
01893
01894 if ( f_index >= n_frequencies )
01895 {
01896 ostringstream os;
01897 os << "The frequency index f_index points to a frequency outside"
01898 << "the frequency grid. (f_index = " << f_index
01899 << ", n_frequencies = " << n_frequencies << ")";
01900 throw runtime_error( os.str() );
01901 }
01902
01903 f_extent = 1;
01904 }
01905
01906
01907
01908
01909 out2 << " Creating field with dimensions:\n"
01910 << " " << n_species << " gas species,\n"
01911 << " " << f_extent << " frequencies,\n"
01912 << " " << n_pressures << " pressures,\n"
01913 << " " << n_latitudes << " latitudes,\n"
01914 << " " << n_longitudes << " longitudes.\n";
01915
01916 asg_field.resize( n_species,
01917 f_extent,
01918 n_pressures,
01919 n_latitudes,
01920 n_longitudes );
01921
01922
01923 out2 << " Agenda output is suppressed, use reporting\n"
01924 <<" level 4 if you want to see it.\n";
01925
01926
01927
01928 Workspace l_ws (ws);
01929 Agenda l_sga_agenda (sga_agenda);
01930
01931
01932 #pragma omp parallel private(asg, a_vmr_list) firstprivate(l_ws,l_sga_agenda)
01933 #pragma omp for
01934 for ( Index ipr=0; ipr<n_pressures; ++ipr )
01935 {
01936
01937
01938 try
01939 {
01940 Numeric a_pressure = p_grid[ipr];
01941
01942 out3 << " p_grid[" << ipr << "] = " << a_pressure << "\n";
01943
01944 for ( Index ila=0; ila<n_latitudes; ++ila )
01945 for ( Index ilo=0; ilo<n_longitudes; ++ilo )
01946 {
01947 Numeric a_temperature = t_field( ipr, ila, ilo );
01948 a_vmr_list = vmr_field( Range(joker),
01949 ipr, ila, ilo );
01950
01951
01952
01953
01954 abs_scalar_gas_agendaExecute(l_ws,
01955 asg,
01956 f_index, a_pressure,
01957 a_temperature, a_vmr_list,
01958 l_sga_agenda);
01959
01960
01961
01962 if ( n_species != asg.ncols() )
01963 {
01964 ostringstream os;
01965 os << "The number of gas species in vmr_field is "
01966 << n_species << ",\n"
01967 << "but the number of species returned by the agenda is "
01968 << asg.ncols() << ".";
01969 throw runtime_error( os.str() );
01970 }
01971
01972
01973
01974 if ( f_extent != asg.nrows() )
01975 {
01976 ostringstream os;
01977 os << "The number of frequencies desired is "
01978 << n_frequencies << ",\n"
01979 << "but the number of frequencies returned by the agenda is "
01980 << asg.nrows() << ".";
01981 throw runtime_error( os.str() );
01982 }
01983
01984
01985
01986
01987
01988
01989 asg_field( Range(joker),
01990 Range(joker),
01991 ipr, ila, ilo ) = transpose( asg );
01992
01993 }
01994 }
01995 catch (runtime_error e)
01996 {
01997 exit_or_rethrow(e.what());
01998 }
01999 }
02000 }
02001
02002
02003
02004 void f_gridFromGasAbsLookup(
02005 Vector& f_grid,
02006 const GasAbsLookup& abs_lookup )
02007 {
02008 abs_lookup.GetFgrid( f_grid );
02009 }
02010
02011
02012
02013 void p_gridFromGasAbsLookup(
02014 Vector& p_grid,
02015 const GasAbsLookup& abs_lookup )
02016 {
02017 abs_lookup.GetPgrid( p_grid );
02018 }
02019
02020
02022
02044 Numeric calc_lookup_error(
02045 const GasAbsLookup& al,
02046 const Index& abs_p_interp_order,
02047 const Index& abs_t_interp_order,
02048 const Index& abs_nls_interp_order,
02049 const bool ignore_errors,
02050
02051 const Vector& abs_n2,
02052 const ArrayOfArrayOfLineRecord& abs_lines_per_species,
02053 const ArrayOfLineshapeSpec& abs_lineshape,
02054 const ArrayOfString& abs_cont_names,
02055 const ArrayOfString& abs_cont_models,
02056 const ArrayOfVector& abs_cont_parameters,
02057
02058 const Numeric& local_p,
02059 const Numeric& local_t,
02060 const Vector& local_vmrs)
02061 {
02062
02063
02064
02065
02066 Matrix sga_tab;
02067 Matrix sga_lbl;
02068
02069
02070
02071 try
02072 {
02073
02074
02075 al.Extract(sga_tab,
02076 abs_p_interp_order,
02077 abs_t_interp_order,
02078 abs_nls_interp_order,
02079 -1,
02080 local_p,
02081 local_t,
02082 local_vmrs );
02083 }
02084 catch (runtime_error x)
02085 {
02086
02087
02088
02089 if (ignore_errors)
02090 return -1;
02091 else
02092 throw runtime_error(x.what());
02093 }
02094
02095
02096
02097
02098 const Index n_f = sga_tab.nrows();
02099
02100
02101 Vector abs_tab(n_f);
02102 Vector abs_lbl(n_f);
02103 Vector abs_rel_diff(n_f);
02104
02105
02106 for (Index i=0; i<n_f; ++i)
02107 abs_tab[i] = sga_tab(i,joker).sum();
02108
02109
02110
02111
02112 abs_scalar_gasCalcLBL( sga_lbl,
02113 al.f_grid,
02114 al.species,
02115 abs_n2,
02116 abs_lines_per_species,
02117 abs_lineshape,
02118 abs_cont_names,
02119 abs_cont_models,
02120 abs_cont_parameters,
02121 -1,
02122 local_p,
02123 local_t,
02124 local_vmrs );
02125
02126
02127 for (Index i=0; i<n_f; ++i)
02128 abs_lbl[i] = sga_lbl(i,joker).sum();
02129
02130
02131
02132
02133 assert(abs_tab.nelem()==n_f);
02134 assert(abs_lbl.nelem()==n_f);
02135 assert(abs_rel_diff.nelem()==n_f);
02136 for (Index i=0; i<n_f; ++i)
02137 {
02138
02139 abs_rel_diff[i] = fabs( (abs_tab[i] - abs_lbl[i]) / abs_lbl[i] * 100);
02140 }
02141
02142
02143 Numeric max_abs_rel_diff = max(abs_rel_diff);
02144
02145
02146
02147 return max_abs_rel_diff;
02148
02149 }
02150
02151
02152
02153 void abs_lookupTestAccuracy(
02154 const GasAbsLookup& abs_lookup,
02155 const Index& abs_lookup_is_adapted,
02156 const Index& abs_p_interp_order,
02157 const Index& abs_t_interp_order,
02158 const Index& abs_nls_interp_order,
02159 const Vector& abs_n2,
02160 const ArrayOfArrayOfLineRecord& abs_lines_per_species,
02161 const ArrayOfLineshapeSpec& abs_lineshape,
02162 const ArrayOfString& abs_cont_names,
02163 const ArrayOfString& abs_cont_models,
02164 const ArrayOfVector& abs_cont_parameters )
02165 {
02166 const GasAbsLookup& al = abs_lookup;
02167
02168
02169 if ( 1!=abs_lookup_is_adapted )
02170 throw runtime_error("Gas absorption lookup table must be adapted,\n"
02171 "use method abs_lookupAdapt.");
02172
02173
02174
02175 const Index n_nls = al.nonlinear_species.nelem();
02176 const Index n_species = al.species.nelem();
02177
02178 const Index n_p = al.log_p_grid.nelem();
02179
02180 if ( n_nls <= 0 )
02181 {
02182 ostringstream os;
02183 os << "This function currently works only with lookup tables\n"
02184 << "containing nonlinear species.";
02185 throw runtime_error( os.str() );
02186 }
02187
02188
02189
02190
02191 Index h2o_index = -1;
02192 if (n_nls>0)
02193 {
02194 h2o_index = find_first_species_tg( al.species,
02195 species_index_from_species_name("H2O") );
02196
02197
02198
02199
02200
02201 if ( h2o_index == -1 )
02202 {
02203 ostringstream os;
02204 os << "With nonlinear species, at least one species must be a H2O species.";
02205 throw runtime_error( os.str() );
02206 }
02207 }
02208
02209
02210
02211
02212 Vector inbet_t_pert(al.t_pert.nelem()-1);
02213 for (Index i=0; i<inbet_t_pert.nelem(); ++i)
02214 inbet_t_pert[i] = (al.t_pert[i]+al.t_pert[i+1])/2.0;
02215
02216
02217
02218
02219 Numeric err_t = -999;
02220
02221 #pragma omp parallel
02222 #pragma omp for
02223 for (Index pi=0; pi<n_p; ++pi)
02224 for (Index ti=0; ti<inbet_t_pert.nelem(); ++ti)
02225 {
02226
02227
02228
02229 Numeric local_p = al.p_grid[pi];
02230
02231
02232 Numeric local_t = al.t_ref[pi] + inbet_t_pert[ti];
02233
02234
02235 Vector local_vmrs = al.vmrs_ref(joker, pi);
02236
02237
02238
02239
02240 local_vmrs[h2o_index] *= al.nls_pert[0];
02241
02242 Numeric max_abs_rel_diff =
02243 calc_lookup_error(
02244 al,
02245 abs_p_interp_order,
02246 abs_t_interp_order,
02247 abs_nls_interp_order,
02248 true,
02249
02250 abs_n2,
02251 abs_lines_per_species,
02252 abs_lineshape,
02253 abs_cont_names,
02254 abs_cont_models,
02255 abs_cont_parameters,
02256
02257 local_p,
02258 local_t,
02259 local_vmrs );
02260
02261
02262
02263
02264
02265 #pragma omp critical
02266 {
02267 if (max_abs_rel_diff > err_t)
02268 err_t = max_abs_rel_diff;
02269 }
02270
02271 }
02272
02273
02274
02275
02276
02277 Vector inbet_nls_pert(al.nls_pert.nelem()-1);
02278 for (Index i=0; i<inbet_nls_pert.nelem(); ++i)
02279 inbet_nls_pert[i] = (al.nls_pert[i]+al.nls_pert[i+1])/2.0;
02280
02281
02282
02283
02284 Numeric err_nls = -999;
02285
02286 #pragma omp parallel
02287 #pragma omp for
02288 for (Index pi=0; pi<n_p; ++pi)
02289 for (Index ni=0; ni<inbet_nls_pert.nelem(); ++ni)
02290 {
02291
02292
02293
02294 Numeric local_p = al.p_grid[pi];
02295
02296
02297
02298
02299
02300
02301
02302 Numeric local_t = al.t_ref[pi] + al.t_pert[0];
02303
02304
02305 Vector local_vmrs = al.vmrs_ref(joker, pi);
02306
02307
02308 local_vmrs[h2o_index] *= inbet_nls_pert[ni];
02309
02310 Numeric max_abs_rel_diff =
02311 calc_lookup_error(
02312 al,
02313 abs_p_interp_order,
02314 abs_t_interp_order,
02315 abs_nls_interp_order,
02316 true,
02317
02318 abs_n2,
02319 abs_lines_per_species,
02320 abs_lineshape,
02321 abs_cont_names,
02322 abs_cont_models,
02323 abs_cont_parameters,
02324
02325 local_p,
02326 local_t,
02327 local_vmrs );
02328
02329
02330
02331 #pragma omp critical
02332 {
02333 if (max_abs_rel_diff > err_nls)
02334 err_nls = max_abs_rel_diff;
02335 }
02336
02337 }
02338
02339
02340
02341
02342
02343
02344
02345
02346 Vector inbet_p_grid(n_p-1);
02347 Vector inbet_t_ref(n_p-1);
02348 Matrix inbet_vmrs_ref(n_species, n_p-1);
02349 for (Index i=0; i<inbet_p_grid.nelem(); ++i)
02350 {
02351 inbet_p_grid[i] = exp((al.log_p_grid[i]+al.log_p_grid[i+1])/2.0);
02352 inbet_t_ref[i] = (al.t_ref[i]+al.t_ref[i+1])/2.0;
02353 for (Index j=0; j<n_species; ++j)
02354 inbet_vmrs_ref(j,i) = (al.vmrs_ref(j,i)+al.vmrs_ref(j,i+1))/2.0;
02355 }
02356
02357
02358
02359
02360 Numeric err_p = -999;
02361
02362 #pragma omp parallel
02363 #pragma omp for
02364 for (Index pi=0; pi<n_p-1; ++pi)
02365 {
02366
02367
02368
02369 Numeric local_p = inbet_p_grid[pi];
02370
02371
02372
02373
02374
02375
02376
02377 Numeric local_t = inbet_t_ref[pi] + al.t_pert[0];
02378
02379
02380 Vector local_vmrs = inbet_vmrs_ref(joker, pi);
02381
02382
02383
02384
02385 local_vmrs[h2o_index] *= al.nls_pert[0];
02386
02387 Numeric max_abs_rel_diff =
02388 calc_lookup_error(
02389 al,
02390 abs_p_interp_order,
02391 abs_t_interp_order,
02392 abs_nls_interp_order,
02393 true,
02394
02395 abs_n2,
02396 abs_lines_per_species,
02397 abs_lineshape,
02398 abs_cont_names,
02399 abs_cont_models,
02400 abs_cont_parameters,
02401
02402 local_p,
02403 local_t,
02404 local_vmrs );
02405
02406
02407
02408 #pragma omp critical
02409 {
02410 if (max_abs_rel_diff > err_p)
02411 err_p = max_abs_rel_diff;
02412 }
02413 }
02414
02415
02416
02417
02418
02419
02420
02421 Numeric err_tot = -999;
02422
02423 #pragma omp parallel
02424 #pragma omp for
02425 for (Index pi=0; pi<n_p-1; ++pi)
02426 for (Index ti=0; ti<inbet_t_pert.nelem(); ++ti)
02427 for (Index ni=0; ni<inbet_nls_pert.nelem(); ++ni)
02428 {
02429
02430
02431
02432 Numeric local_p = inbet_p_grid[pi];
02433
02434
02435 Numeric local_t = inbet_t_ref[pi] + inbet_t_pert[ti];
02436
02437
02438 Vector local_vmrs = inbet_vmrs_ref(joker, pi);
02439
02440
02441 local_vmrs[h2o_index] *= inbet_nls_pert[ni];
02442
02443 Numeric max_abs_rel_diff =
02444 calc_lookup_error(
02445 al,
02446 abs_p_interp_order,
02447 abs_t_interp_order,
02448 abs_nls_interp_order,
02449 true,
02450
02451 abs_n2,
02452 abs_lines_per_species,
02453 abs_lineshape,
02454 abs_cont_names,
02455 abs_cont_models,
02456 abs_cont_parameters,
02457
02458 local_p,
02459 local_t,
02460 local_vmrs );
02461
02462
02463
02464 #pragma omp critical
02465 {
02466 if (max_abs_rel_diff > err_tot)
02467 {
02468 err_tot = max_abs_rel_diff;
02469
02470 cout << "New max error: pi, ti, ni, err_tot:\n"
02471 << pi << ", " << ti << ", " << ni << ", " << err_tot << "\n";
02472 }
02473 }
02474 }
02475
02476
02477 out2 << " Max. of absolute value of relative error in percent:\n"
02478 << " Note: Unless you have constant reference profiles, the\n"
02479 << " pressure interpolation error will have other errors mixed in.\n"
02480 << " Temperature interpolation: " << err_t << "%\n"
02481 << " H2O (NLS) interpolation: " << err_nls << "%\n"
02482 << " Pressure interpolation: " << err_p << "%\n"
02483 << " Total error: " << err_tot << "%\n";
02484
02485
02486
02487
02488
02489
02490
02491
02492
02493
02494
02495
02496
02497
02498
02499 }