ARTS  2.0.49
m_abs_lookup.cc
Go to the documentation of this file.
1 /* Copyright (C) 2002-2008 Stefan Buehler <sbuehler@ltu.se>
2 
3  This program is free software; you can redistribute it and/or
4  modify it under the terms of the GNU General Public License as
5  published by the Free Software Foundation; either version 2 of the
6  License, or (at your option) any later version.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
16  USA. */
17 
26 #include <algorithm>
27 #include <map>
28 #include <limits>
29 
30 #include "auto_md.h"
31 #include "arts.h"
32 #include "messages.h"
33 #include "gas_abs_lookup.h"
34 #include "agenda_class.h"
35 #include "check_input.h"
36 #include "matpackV.h"
37 #include "physics_funcs.h"
38 #include "math_funcs.h"
39 #include "make_vector.h"
40 #include "arts_omp.h"
41 #include "interpolation_poly.h"
42 #include "rng.h"
43 
44 extern const Index GFIELD4_FIELD_NAMES;
45 extern const Index GFIELD4_P_GRID;
46 
47 
48 /* Workspace method: Doxygen documentation will be auto-generated */
49 void abs_lookupInit(GasAbsLookup& /* x */, const Verbosity& verbosity)
50 {
51  ArtsOut2 out2(verbosity);
52  // Nothing to do here.
53  // That means, we rely on the default constructor.
54 
55  out2 << " Created an empty gas absorption lookup table.\n";
56 }
57 
58 
59 /* Workspace method: Doxygen documentation will be auto-generated */
60 void abs_lookupCreate(// WS Output:
61  GasAbsLookup& abs_lookup,
62  Index& abs_lookup_is_adapted,
63  // WS Input:
64  const ArrayOfArrayOfSpeciesTag& abs_species,
65  const ArrayOfArrayOfLineRecord& abs_lines_per_species,
66  const ArrayOfLineshapeSpec& abs_lineshape,
67  const ArrayOfArrayOfSpeciesTag& abs_nls,
68  const Vector& f_grid,
69  const Vector& abs_p,
70  const Matrix& abs_vmrs,
71  const Vector& abs_t,
72  const Vector& abs_t_pert,
73  const Vector& abs_nls_pert,
74  const Vector& abs_n2,
75  const ArrayOfString& abs_cont_names,
76  const ArrayOfString& abs_cont_models,
77  const ArrayOfVector& abs_cont_parameters,
78  const Verbosity& verbosity)
79 {
82 
83  // We need this to restore the original setting of omp_nested at the
84  // end.
85  int omp_nested_original = arts_omp_get_nested();
86 
87  // We will be calling an absorption agenda one species at a
88  // time. This is better than doing all simultaneously, because is
89  // saves memory and allows for consistent treatment of nonlinear
90  // species. But it means we need local copies of species, line list,
91  // and line shapes for agenda communication.
92 
93  // 1. Output of absorption calculations:
94 
95  // Absorption coefficients:
96  Matrix these_abs_coef;
97 
98  // Absorption cross sections per tag group.
99  ArrayOfMatrix abs_xsec_per_species;
100 
101 
102  // 2. Determine various important sizes:
103  const Index n_species = abs_species.nelem(); // Number of abs species
104  const Index n_nls = abs_nls.nelem(); // Number of nonlinear species
105  const Index n_f_grid = f_grid.nelem(); // Number of frequency grid points
106  const Index n_p_grid = abs_p.nelem(); // Number of presure grid points
107  const Index n_t_pert = abs_t_pert.nelem(); // Number of temp. perturbations
108  const Index n_nls_pert = abs_nls_pert.nelem(); // Number of VMR pert. for NLS
109 
110  // 3. Input to absorption calculations:
111 
112  // Absorption vmrs and temperature:
113  Matrix this_vmr(1,n_p_grid);
114  Vector abs_h2o(n_p_grid);
115  Vector this_t; // Has same dimension, but is
116  // initialized by assignment later.
117 
118  // Species list, lines, and line shapes, all with only 1 element:
119  ArrayOfArrayOfSpeciesTag this_species(1);
120  ArrayOfArrayOfLineRecord these_lines(1);
121  ArrayOfLineshapeSpec this_lineshape(1);
122 
123  // Local copy of nls_pert and t_pert:
124  Vector these_nls_pert; // Is resized every time when used
125  Vector these_t_pert; // Is resized later on
126 
127  // 4. Checks of input parameter correctness:
128 
129  const Index h2o_index
130  = find_first_species_tg( abs_species,
132 
133  if ( h2o_index < 0 )
134  {
135  // If there are nonlinear species, then at least one species must be
136  // H2O. We will use that to set h2o_abs, and to perturb in the case
137  // of nonlinear species.
138  if (n_nls>0)
139  {
140  ostringstream os;
141  os << "If you have nonlinear species, at least one\n"
142  << "species must be a H2O species.";
143  throw runtime_error( os.str() );
144  }
145  else
146  {
147  out2 << " You have no H2O species. Absorption continua will not work.\n"
148  << " You should get a runtime error if you try them anyway.\n";
149  }
150  }
151 
152  // abs_species, f_grid, and p_grid should not be empty:
153  if ( 0==n_species ||
154  0==n_f_grid ||
155  0==n_p_grid )
156  {
157  ostringstream os;
158  os << "One of the required input variables is empty:\n"
159  << "abs_species.nelem() = " << n_species << ",\n"
160  << "f_grid.nelem() = " << n_f_grid << ",\n"
161  << "abs_p.nelem() = " << n_p_grid << ".";
162  throw runtime_error( os.str() );
163  }
164 
165  // Set up the index array abs_nls from the tag array
166  // abs_nls. Give an error message if these
167  // tags are not included in abs_species.
168  ArrayOfIndex abs_nls_idx;
169  for (Index i=0; i<n_nls; ++i)
170  {
171  Index s;
172  for (s=0; s<n_species; ++s)
173  {
174  if (abs_nls[i]==abs_species[s])
175  {
176  abs_nls_idx.push_back(s);
177  break;
178  }
179  }
180  if (s==n_species)
181  {
182  ostringstream os;
183  os << "Did not find *abs_nls* tag group \""
184  << get_tag_group_name(abs_nls[i])
185  << "\" in *abs_species*.";
186  throw runtime_error( os.str() );
187  }
188  }
189 
190  // Furthermore abs_nls_idx must not contain duplicate values:
191  if ( !is_unique(abs_nls_idx) )
192  {
193  ostringstream os;
194  os << "The variable *abs_nls* must not have duplicate species.\n"
195  << "Value of *abs_nls*: " << abs_nls_idx;
196  throw runtime_error( os.str() );
197  }
198 
199  // abs_lines_per_species must match abs_species:
200  if (abs_lines_per_species.nelem() != abs_species.nelem())
201  {
202  ostringstream os;
203  os << "Dimensions of *abs_species* and *abs_lines_per_species* must match. "
204  << "*abs_species*: " << abs_species.nelem() << " elements. "
205  << "*abs_lines_per_species*: " << abs_lines_per_species.nelem() << " elements.";
206  throw runtime_error( os.str() );
207  }
208 
209  // VMR matrix must match species list and pressure levels:
210  chk_size( "abs_vmrs",
211  abs_vmrs,
212  n_species,
213  n_p_grid );
214 
215  // Temperature vector must match number of pressure levels:
216  chk_size( "abs_t",
217  abs_t,
218  n_p_grid );
219 
220  // abs_nls_pert should only be not-empty if we have nonlinear species:
221  if ( ( (0==n_nls) && (0!=n_nls_pert) ) ||
222  ( (0!=n_nls) && (0==n_nls_pert) ) )
223  {
224  ostringstream os;
225  os << "You have to set both abs_nls and abs_nls_pert, or none.";
226  throw runtime_error( os.str() );
227  }
228 
229 
230  // 4.a Set up a logical array for the nonlinear species.
231  ArrayOfIndex non_linear(n_species,0);
232  for ( Index s=0; s<n_nls; ++s )
233  {
234  non_linear[abs_nls_idx[s]] = 1;
235  }
236 
237 
238  // 5. Set general lookup table properties:
239  abs_lookup.species = abs_species; // Species list
240  abs_lookup.nonlinear_species = abs_nls_idx; // Nonlinear species (e.g., H2O, O2)
241  abs_lookup.f_grid = f_grid; // Frequency grid
242  abs_lookup.p_grid = abs_p; // Pressure grid
243  abs_lookup.vmrs_ref = abs_vmrs;
244  abs_lookup.t_ref = abs_t;
245  abs_lookup.t_pert = abs_t_pert;
246  abs_lookup.nls_pert = abs_nls_pert;
247 
248  // 5.a. Set log_p_grid:
249  abs_lookup.log_p_grid.resize(n_p_grid);
250  transform( abs_lookup.log_p_grid, log, abs_lookup.p_grid );
251 
252 
253  // 6. Create abs_lookup.xsec with the right dimensions:
254  {
255  Index a,b,c,d;
256 
257  if ( 0 == n_t_pert ) a = 1;
258  else a = n_t_pert;
259 
260  b = n_species + n_nls * ( n_nls_pert - 1 );
261 
262  c = n_f_grid;
263 
264  d = n_p_grid;
265 
266  abs_lookup.xsec.resize( a, b, c, d );
267  }
268 
269  // 6.a. Set up these_t_pert. This is done so that we can use the
270  // same loop over the perturbations, independent of
271  // whether we have temperature perturbations or not.
272  if ( 0!=n_t_pert)
273  {
274  out2 << " With temperature perturbations.\n";
275  these_t_pert.resize(n_t_pert);
276  these_t_pert = abs_t_pert;
277  }
278  else
279  {
280  out2 << " No temperature perturbations.\n";
281  these_t_pert.resize(1);
282  these_t_pert = 0;
283 
284  // In this case, we also want to enable nested parallel
285  // execution. Normally, it is the loop over the temperature
286  // perturbations that is parallel, but in this case that one is
287  // trivial.
289  }
290 
291  const Index these_t_pert_nelem = these_t_pert.nelem();
292 
293 
294  // 7. Now we have to fill abs_lookup.xsec with the right values!
295 
296  // Loop species:
297  for ( Index i=0,spec=0; i<n_species; ++i )
298  {
299  // spec is the index for the second dimension of abs_lookup.xsec.
300 
301  // Prepare absorption agenda input for this species:
302  out2 << " Doing species " << i+1 << " of " << n_species << ": "
303  << abs_species[i] << ".\n";
304 
305  // Get a dummy list of tag groups with only the current element:
306  this_species[0].resize(abs_species[i].nelem());
307  this_species[0] = abs_species[i];
308 
309  // List of lines:
310  these_lines[0].resize(abs_lines_per_species[i].nelem());
311  these_lines[0] = abs_lines_per_species[i];
312 
313  // List of lineshapes. This requires special treatment: If there
314  // is only 1 lineshape given, the same lineshape should be used
315  // for all species.
316  if (1==abs_lineshape.nelem())
317  this_lineshape[0] = abs_lineshape[0];
318  else
319  this_lineshape[0] = abs_lineshape[i];
320 
321  // Set up these_nls_pert. This is done so that we can use the
322  // same loop over the perturbations, independent of
323  // whether we have nonlinear species or not.
324  if ( non_linear[i] )
325  {
326  out2 << " This is a species with H2O VMR perturbations.\n";
327  these_nls_pert.resize(n_nls_pert);
328  these_nls_pert = abs_nls_pert;
329  }
330  else
331  {
332  these_nls_pert.resize(1);
333  these_nls_pert = 1;
334  }
335 
336  // Loop these_nls_pert:
337  for ( Index s=0; s<these_nls_pert.nelem(); ++s,++spec )
338  {
339  // Remember, spec is the index for the second dimension of
340  // abs_lookup.xsec
341 
342  if ( non_linear[i] )
343  {
344  out2 << " Doing H2O VMR variant " << s+1 << " of " << n_nls_pert << ": "
345  << abs_nls_pert[s] << ".\n";
346  }
347 
348  // VMR for this species:
349  this_vmr(0,joker) = abs_vmrs(i,joker);
350  if ( i==h2o_index )
351  {
352  // out3 << " Species is main H2O species.\n";
353  this_vmr(0,joker) *= these_nls_pert[s]; // Add perturbation
354  }
355 
356  // For abs_h2o, we can always add the perturbations (it will
357  // not make a difference if the species itself is also H2O).
358  // Attention, we need to treat here also the case that there
359  // is no H2O species. We will then set abs_h2o to
360  // -1. Absorption routines that do not really need abs_h2o
361  // will still run.
362  if ( h2o_index == -1 )
363  {
364  // The case without H2O species.
365  abs_h2o.resize(1);
366  abs_h2o = -1;
367  }
368  else
369  {
370  // The normal case.
371  abs_h2o = abs_vmrs(h2o_index, joker);
372  abs_h2o *= these_nls_pert[s]; // Add perturbation
373  }
374 
375  // Loop temperature perturbations
376  // ------------------------------
377 
378  // We use a parallel for loop for this.
379 
380  // There is something strange here: abs_lookup seems to be
381  // "shared" by default, although I have set default(none). I
382  // suspect that the reason for this behavior is that
383  // abs_lookup is a return by reference parameter of this
384  // function. Anyway, shared is the correct setting for
385  // abs_lookup, so there is no problem.
386 
387 /*#pragma omp parallel for \
388  if(!arts_omp_in_parallel() \
389  && these_t_pert_nelem>=arts_omp_get_max_threads()) \
390  default(none) \
391  shared(these_t_pert, out3, this_species, \
392  this_lineshape, these_lines, this_vmr, abs_h2o, \
393  joker, spec, abs_lookup, abs_p, f_grid, \
394  abs_cont_models, abs_cont_parameters, abs_cont_names, \
395  abs_n2) \
396  private(this_t, abs_xsec_per_species) */
397 #pragma omp parallel for \
398  if(!arts_omp_in_parallel() \
399  && these_t_pert_nelem>=arts_omp_get_max_threads()) \
400  private(this_t, abs_xsec_per_species)
401  for ( Index j=0; j<these_t_pert_nelem; ++j )
402  {
403  // The try block here is necessary to correctly handle
404  // exceptions inside the parallel region.
405  try
406  {
407  if ( 0!=n_t_pert )
408  {
409  // We first prepare the output in a string here,
410  // so that we can write it to out3 with a single
411  // operation. This avoids messy output from
412  // multiple threads.
413  ostringstream os;
414 
415  os << " Doing temperature variant " << j+1
416  << " of " << n_t_pert << ": "
417  << these_t_pert[j] << ".\n";
418 
419  out3 << os.str();
420  }
421 
422  // Create perturbed temperature profile:
423  this_t = abs_lookup.t_ref;
424  this_t += these_t_pert[j];
425 
426  // The sequence of function calls here is inspired from
427  // abs_coefCalcSaveMemory.
428 
429  abs_xsec_per_speciesInit( abs_xsec_per_species, this_species,
430  f_grid, abs_p, verbosity );
431 
432  abs_xsec_per_speciesAddLines( abs_xsec_per_species,
433  this_species,
434  f_grid,
435  abs_p,
436  this_t,
437  abs_h2o,
438  this_vmr,
439  these_lines,
440  this_lineshape,
441  verbosity);
442 
443  abs_xsec_per_speciesAddConts( abs_xsec_per_species,
444  this_species,
445  f_grid,
446  abs_p,
447  this_t,
448  abs_n2,
449  abs_h2o,
450  this_vmr,
451  abs_cont_names,
452  abs_cont_parameters,
453  abs_cont_models,
454  verbosity);
455 
456  // Store in the right place:
457  // Loop through all altitudes
458  for ( Index p=0; p<n_p_grid; ++p )
459  {
460  abs_lookup.xsec( j, spec, Range(joker), p )
461  = abs_xsec_per_species[0](Range(joker),p);
462 
463  // There used to be a division by the number density
464  // n here. This is no longer necessary, since
465  // abs_xsec_per_species now contains true absorption
466  // cross sections.
467 
468  // IMPORTANT: There was a bug in my old Matlab
469  // function "create_lookup.m" to generate the lookup
470  // table. (The number density was always the
471  // reference one, and did not change for different
472  // temperatures.) Patricks Atmlab function
473  // "arts_abstable_from_arts1.m" did *not* have this bug.
474 
475  // Calculate the number density for the given pressure and
476  // temperature:
477  // n = n0*T0/p0 * p/T or n = p/kB/t, ideal gas law
478  // const Numeric n = number_density( abs_lookup.p_grid[p],
479  // this_t[p] );
480  // abs_lookup.xsec( j, spec, Range(joker), p ) /= n;
481  }
482  } // end of try block
483  catch (runtime_error e)
484  {
486  exit_or_rethrow(e.what(), out0);
487  }
488  } // end of parallel for loop
489  }
490  }
491 
492  // Set the abs_lookup_is_adapted flag. After all, the table fits the
493  // current frequency grid and species selection.
494  abs_lookup_is_adapted = 1;
495 
496  // Reset the omp_nested state to original value:
497  arts_omp_set_nested(omp_nested_original);
498 }
499 
500 
502 
520  const ArrayOfArrayOfSpeciesTag& abs_species,
521  const Verbosity& verbosity)
522 {
524 
525  cont.resize(0);
526 
527  // This is quite complicated, unfortunately. The approach here
528  // is copied from abs_xsec_per_speciesAddConts. For explanation,
529  // see there.
530 
531  // Loop tag groups:
532  for ( Index i=0; i<abs_species.nelem(); ++i )
533  {
534  extern const Array<SpeciesRecord> species_data;
535 
536  // Loop tags in tag group
537  for ( Index s=0; s<abs_species[i].nelem(); ++s )
538  {
539 
540  // Check if this is a specific isotope, or "all". ("all" is
541  // not a continuum tag.)
542  if ( abs_species[i][s].Isotope() <
543  species_data[abs_species[i][s].Species()].Isotope().nelem() )
544  {
545  // Continuum tags have isotope ratio -1
546  if ( 0 >
547  species_data[abs_species[i][s].Species()].Isotope()[abs_species[i][s].Isotope()].Abundance() )
548  {
549  const String thisname = abs_species[i][s].Name();
550  // Ok, now we know this is a continuum tag.
551  out3 << " Continuum tag: " << thisname;
552 
553  // Check whether we want nonlinear treatment for
554  // this or not. We have three classes of continua:
555  // 1. Those that we know do not require it
556  // 2. Those that we know require h2o_abs
557  // 3. Those for which we do not know
558 
559  // The list here is not at all perfect, just a first
560  // guess. If you need particular models, you better
561  // check that the right thing is done with your model.
562 
563  // 1. Continua known to not use h2o_abs
564  // We take also H2O itself here, since this is
565  // handled separately
566  if ( species_index_from_species_name("H2O")==abs_species[i][s].Species() ||
567  "N2-"==thisname.substr(0,3) ||
568  "CO2-"==thisname.substr(0,4) ||
569  "O2-CIA"==thisname.substr(0,6) ||
570  "O2-v0v"==thisname.substr(0,6) ||
571  "O2-v1v"==thisname.substr(0,6) )
572  {
573  out3 << " --> not added.\n";
574  break;
575  }
576 
577  // 2. Continua known to use h2o_abs
578  if ( "O2-"==thisname.substr(0,3) )
579  {
580  cont.push_back(i);
581  out3 << " --> added to abs_nls.\n";
582  break;
583  }
584 
585  // If we get here, then the tag was neither in the
586  // posivitive nor in the negative list. We through a
587  // runtime error.
588  out3 << " --> unknown.\n";
589  throw runtime_error("I don't know whether this tag uses h2o_abs or not.\n"
590  "Cannot set abs_nls automatically.");
591  }
592  }
593  }
594  }
595 }
596 
597 
599 
608  const ArrayOfArrayOfSpeciesTag& abs_species,
609  const Verbosity& verbosity)
610 {
612 
613  abs_nls.resize(0);
614 
615  // Add all H2O species as non-linear:
616  Index next_h2o = 0;
617  while (-1 != (next_h2o =
618  find_next_species_tg(abs_species,
620  next_h2o)))
621  {
622  abs_nls.push_back(abs_species[next_h2o]);
623  ++next_h2o;
624  }
625 
626  // Certain continuum models also depend on abs_h2o. There is a
627  // helper function that contains a list of these.
628  ArrayOfIndex cont;
629  find_nonlinear_continua(cont, abs_species, verbosity);
630 
631  // Add these to abs_nls:
632  for (Index i=0; i<cont.nelem(); ++i)
633  {
634  abs_nls.push_back(abs_species[cont[i]]);
635  }
636 
637  out2 << " Species marked for nonlinear treatment:\n";
638  for (Index i=0; i<abs_nls.nelem(); ++i)
639  {
640  out2 << " ";
641  for (Index j=0; j<abs_nls[i].nelem(); ++j)
642  {
643  if (j!=0) out2 << ", ";
644  out2 << abs_nls[i][j].Name();
645  }
646  out2 << "\n";
647  }
648 }
649 
650 
652 
665 void choose_abs_t_pert(Vector& abs_t_pert,
666  ConstVectorView abs_t,
667  ConstVectorView tmin,
668  ConstVectorView tmax,
669  const Numeric& step,
670  const Index& p_interp_order,
671  const Index& t_interp_order,
672  const Verbosity& verbosity)
673 {
676 
677  // The code to find out the range for perturbation is a bit
678  // complicated. The problem is that, since we use higher order
679  // interpolation for p, we may require temperatures well outside the
680  // local min/max range at the reference level. We solve this by
681  // really looking at the min/max range for those levels required by
682  // the p_interp_order.
683 
684  Numeric mindev = 1e9;
685  Numeric maxdev = -1e9;
686 
687  Vector the_grid(0,abs_t.nelem(),1);
688  for (Index i=0; i<the_grid.nelem(); ++i)
689  {
690  GridPosPoly gp;
691  gridpos_poly(gp, the_grid, (Numeric)i, p_interp_order);
692 
693  for (Index j=0; j<gp.idx.nelem(); ++j)
694  {
695  // Our pressure grid for the lookup table may be coarser than
696  // the original one for the batch cases. This may lead to max/min
697  // values in the original data that exceed those we assumed
698  // above. We add some extra margin here to account for
699  // that. (The margin is +-10K)
700 
701  Numeric delta_min = tmin[i] - abs_t[gp.idx[j]] - 10;
702  Numeric delta_max = tmax[i] - abs_t[gp.idx[j]] + 10;
703 
704  if ( delta_min < mindev ) mindev = delta_min;
705  if ( delta_max > maxdev ) maxdev = delta_max;
706  }
707  }
708 
709  out3 << " abs_t_pert: mindev/maxdev : " << mindev << " / " << maxdev << "\n";
710 
711  // We divide the interval between mindev and maxdev, so that the
712  // steps are of size *step* or smaller. But we also need at least
713  // *t_interp_order*+1 points.
714  Index div = t_interp_order;
715  Numeric effective_step;
716  do
717  {
718  effective_step = (maxdev-mindev)/(Numeric)div;
719  ++div;
720  }
721  while (effective_step > step);
722 
723  abs_t_pert = Vector(mindev, div, effective_step);
724 
725  out2 << " abs_t_pert: " << abs_t_pert[0] << " K to " << abs_t_pert[abs_t_pert.nelem()-1]
726  << " K in steps of " << effective_step
727  << " K (" << abs_t_pert.nelem() << " grid points)\n";
728 }
729 
730 
732 
745 void choose_abs_nls_pert(Vector& abs_nls_pert,
746  ConstVectorView refprof,
747  ConstVectorView minprof,
748  ConstVectorView maxprof,
749  const Numeric& step,
750  const Index& p_interp_order,
751  const Index& nls_interp_order,
752  const Verbosity& verbosity)
753 {
756 
757  // The code to find out the range for perturbation is a bit
758  // complicated. The problem is that, since we use higher order
759  // interpolation for p, we may require humidities well outside the
760  // local min/max range at the reference level. We solve this by
761  // really looking at the min/max range for those levels required by
762  // the p_interp_order.
763 
764  Numeric mindev = 0;
765  Numeric maxdev = -1e9;
766 
767  // mindev is set to zero from the start, since we always want to
768  // include 0.
769 
770  Vector the_grid(0,refprof.nelem(),1);
771  for (Index i=0; i<the_grid.nelem(); ++i)
772  {
773 // cout << "!!!!!! i = " << i << "\n";
774 // cout << " min/ref/max = " << minprof[i] << " / "
775 // << refprof[i] << " / "
776 // << maxprof[i] << "\n";
777 
778  GridPosPoly gp;
779  gridpos_poly(gp, the_grid, (Numeric)i, p_interp_order);
780 
781  for (Index j=0; j<gp.idx.nelem(); ++j)
782  {
783 // cout << "!!!!!! j = " << j << "\n";
784 // cout << " ref[j] = " << refprof[gp.idx[j]] << " ";
785 // cout << " minfrac[j] = " << minprof[i] / refprof[gp.idx[j]] << " ";
786 // cout << " maxfrac[j] = " << maxprof[i] / refprof[gp.idx[j]] << " \n";
787 
788  // Our pressure grid for the lookup table may be coarser than
789  // the original one for the batch cases. This may lead to max/min
790  // values in the original data that exceed those we assumed
791  // above. We add some extra margin to the max value here to account for
792  // that. (The margin is a factor of 2.)
793 
794  Numeric delta_min = minprof[i] / refprof[gp.idx[j]];
795  Numeric delta_max = 2*maxprof[i] / refprof[gp.idx[j]];
796 
797  if ( delta_min < mindev ) mindev = delta_min;
798  if ( delta_max > maxdev ) maxdev = delta_max;
799  }
800  }
801 
802  out3 << " abs_nls_pert: mindev/maxdev : " << mindev << " / " << maxdev << "\n";
803 
804  bool allownegative = false;
805  if (mindev<0)
806  {
807  out2 << " Warning: I am getting a negative fractional distance to the H2O\n"
808  << " reference profile. Some of your H2O fields may contain negative values.\n"
809  << " Will allow negative values also for abs_nls_pert.\n";
810  allownegative = true;
811  }
812 
813  if (!allownegative)
814  {
815  mindev = 0;
816  out3 << " Adjusted mindev : " << mindev << "\n";
817  }
818 
819  // We divide the interval between mindev and maxdev, so that the
820  // steps are of size *step* or smaller. But we also need at least
821  // *nls_interp_order*+1 points.
822  Index div = nls_interp_order;
823  Numeric effective_step;
824  do
825  {
826  effective_step = (maxdev-mindev)/(Numeric)div;
827  ++div;
828  }
829  while (effective_step > step);
830 
831  abs_nls_pert = Vector(mindev, div, effective_step);
832 
833  // If there are negative values, we also add 0. The reason for this
834  // is that 0 is a turning point.
835  if (allownegative)
836  {
837  VectorInsertGridPoints(abs_nls_pert, abs_nls_pert, MakeVector(0), verbosity);
838  out2 << " I am including also 0 in the abs_nls_pert, because it is a turning \n"
839  << " point. Consider to use a higher abs_nls_interp_order, for example 4.\n";
840  }
841 
842  out2 << " abs_nls_pert: " << abs_nls_pert[0] << " to " << abs_nls_pert[abs_nls_pert.nelem()-1]
843  << " (fractional units) in steps of " << abs_nls_pert[1]-abs_nls_pert[0]
844  << " (" << abs_nls_pert.nelem() << " grid points)\n";
845 
846 }
847 
848 
849 /* Workspace method: Doxygen documentation will be auto-generated */
850 void abs_lookupSetup(// WS Output:
851  Vector& abs_p,
852  Vector& abs_t,
853  Vector& abs_t_pert,
854  Matrix& abs_vmrs,
855  ArrayOfArrayOfSpeciesTag& abs_nls,
856  Vector& abs_nls_pert,
857  // WS Input:
858  const Index& atmosphere_dim,
859  const Vector& p_grid,
860  const Vector& lat_grid,
861  const Vector& lon_grid,
862  const Tensor3& t_field,
863  const Tensor4& vmr_field,
864  const ArrayOfArrayOfSpeciesTag& abs_species,
865  const Index& abs_p_interp_order,
866  const Index& abs_t_interp_order,
867  const Index& abs_nls_interp_order,
868  // Control Parameters:
869  const Numeric& p_step10,
870  const Numeric& t_step,
871  const Numeric& h2o_step,
872  const Verbosity& verbosity)
873 {
874  // For consistency with other code around arts (e.g., correlation
875  // lengths in atmlab), p_step is given as log10(p[Pa]). However, we
876  // convert it here to the natural log:
877  const Numeric p_step = log(pow(10.0, p_step10));
878 
879  // Checks on input parameters:
880 
881  // We don't actually need lat_grid and lon_grid, but we have them as
882  // input variables, so that we can use the standard functions to
883  // check atmospheric fields and grids. A bit cheesy, but I don't
884  // want to program all the checks explicitly.
885 
886  // Check grids:
887  chk_atm_grids(atmosphere_dim, p_grid, lat_grid, lon_grid);
888 
889  if (p_grid.nelem()<2)
890  {
891  ostringstream os;
892  os << "You need at least two pressure levels.";
893  throw runtime_error( os.str() );
894  }
895 
896  // Check T field:
897  chk_atm_field("t_field", t_field, atmosphere_dim,
898  p_grid, lat_grid, lon_grid);
899 
900  // Check VMR field (and abs_species):
901  chk_atm_field("vmr_field", vmr_field, atmosphere_dim,
902  abs_species.nelem(), p_grid, lat_grid, lon_grid);
903 
904  // Check the keyword arguments:
905  if ( p_step <= 0 || t_step <= 0 || h2o_step <= 0 )
906  {
907  ostringstream os;
908  os << "The keyword arguments p_step, t_step, and h2o_step must be >0.";
909  throw runtime_error( os.str() );
910  }
911 
912  // Ok, all input parameters seem to be reasonable.
913 
914 
915  // We will need the log of the pressure grid:
916  Vector log_p_grid(p_grid.nelem());
917  transform(log_p_grid, log, p_grid);
918 
919  // const Numeric epsilon = 0.01 * p_step; // This is the epsilon that
920  // // we use for comparing p grid spacings.
921 
922  // Construct abs_p
923  // ---------------
924 
925  ArrayOfNumeric log_abs_p_a; // We take log_abs_p_a as an array of
926  // Numeric, so that we can easily
927  // build it up by appending new elements to the end.
928 
929  // Check whether there are pressure levels that are further apart
930  // (in log(p)) than p_step, and insert additional levels if
931  // necessary:
932 
933  log_abs_p_a.push_back(log_p_grid[0]);
934 
935  for (Index i=1; i<log_p_grid.nelem(); ++i)
936  {
937  const Numeric dp = log_p_grid[i-1] - log_p_grid[i]; // The grid is descending.
938 
939  const Numeric dp_by_p_step = dp/p_step;
940  // cout << "dp_by_p_step: " << dp_by_p_step << "\n";
941 
942  // How many times does p_step fit into dp?
943  const Index n = (Index) ceil(dp_by_p_step);
944  // n is the number of intervals that we want to have in the
945  // new grid. The number of additional points to insert is
946  // n-1. But we have to insert the original point as well.
947  // cout << n << "\n";
948 
949  const Numeric ddp = dp/(Numeric)n;
950  // cout << "ddp: " << ddp << "\n";
951 
952  for (Index j=1; j<=n; ++j)
953  log_abs_p_a.push_back(log_p_grid[i-1] - (Numeric)j*ddp);
954  }
955 
956  // Copy to a proper vector, we need this also later for
957  // interpolation:
958  Vector log_abs_p(log_abs_p_a.nelem());
959  for (Index i=0; i<log_abs_p_a.nelem(); ++i)
960  log_abs_p[i] = log_abs_p_a[i];
961 
962  // Copy the new grid to abs_p, removing the log:
963  abs_p.resize(log_abs_p.nelem());
964  transform(abs_p, exp, log_abs_p);
965 
966  // Check that abs_p has enough points for the interpolation order
967  if (abs_p.nelem()<abs_p_interp_order+1)
968  {
969  ostringstream os;
970  os << "Your pressure grid does not have enough levels for the desired interpolation order.";
971  throw runtime_error( os.str() );
972  }
973 
974  // We will also have to interpolate T and VMR profiles to the new
975  // pressure grid. We interpolate in log(p), as usual in ARTS.
976 
977  // Grid positions:
978  ArrayOfGridPos gp(log_abs_p.nelem());
979  gridpos(gp, log_p_grid, log_abs_p);
980 
981  // Interpolation weights:
982  Matrix itw(gp.nelem(),2);
983  interpweights(itw,gp);
984 
985 
986  // In the 1D case the lookup table is just a lookup table in
987  // pressure. We treat this simple case first.
988  if (1==atmosphere_dim)
989  {
990  // Reference temperature,
991  // interpolate abs_t from t_field:
992  abs_t.resize(log_abs_p.nelem());
993  interp(abs_t,
994  itw,
995  t_field(joker,0,0),
996  gp);
997 
998  // Temperature perturbations:
999  abs_t_pert.resize(0);
1000 
1001  // Reference VMR profiles,
1002  // interpolate abs_vmrs from vmr_field:
1003  abs_vmrs.resize(abs_species.nelem(), log_abs_p.nelem());
1004  for (Index i=0; i<abs_species.nelem(); ++i)
1005  interp(abs_vmrs(i,joker),
1006  itw,
1007  vmr_field(i,joker,0,0),
1008  gp);
1009 
1010  // Species for which H2O VMR is perturbed:
1011  abs_nls.resize(0);
1012 
1013  // H2O VMR perturbations:
1014  abs_nls_pert.resize(0);
1015  }
1016  else
1017  {
1018  // 2D or 3D case. We have to set up T and nonlinear species variations.
1019 
1020  // Make an intelligent choice for the nonlinear species.
1021  choose_abs_nls(abs_nls, abs_species, verbosity);
1022 
1023  // Now comes a part where we analyse the atmospheric fields.
1024  // We need to find the max, min, and mean profile for
1025  // temperature and VMRs.
1026  // We do this on the original p grid, not on the refined p
1027  // grid, to be more efficient.
1028 
1029  // Temperature:
1030  Vector tmin(p_grid.nelem());
1031  Vector tmax(p_grid.nelem());
1032  Vector tmean(p_grid.nelem());
1033 
1034  for (Index i=0; i<p_grid.nelem(); ++i)
1035  {
1036  tmin[i] = min(t_field(i,joker,joker));
1037  tmax[i] = max(t_field(i,joker,joker));
1038  tmean[i] = mean(t_field(i,joker,joker));
1039  }
1040 
1041 // cout << "Tmin: " << tmin << "\n";
1042 // cout << "Tmax: " << tmax << "\n";
1043 // cout << "Tmean: " << tmean << "\n";
1044 
1045  // Calculate mean profiles of all species. (We need all for abs_vmrs
1046  // not only H2O.)
1047  Matrix vmrmean(abs_species.nelem(), p_grid.nelem());
1048  for (Index s=0; s<abs_species.nelem(); ++s)
1049  for (Index i=0; i<p_grid.nelem(); ++i)
1050  {
1051  vmrmean(s,i) = mean(vmr_field(s,i,joker,joker));
1052  }
1053 
1054  // If there are NLS, determine H2O statistics:
1055 
1056  // We have to define these here, outside the if block, because
1057  // we need the values later.
1058  Vector h2omin(p_grid.nelem());
1059  Vector h2omax(p_grid.nelem());
1060  const Index h2o_index
1061  = find_first_species_tg( abs_species,
1063  // We need this inside the if clauses for nonlinear species
1064  // treatment. The function returns "-1" if there is no H2O
1065  // species. There is a check for that in the next if block, with
1066  // an appropriate runtime error.
1067 
1068  if (0<abs_nls.nelem())
1069  {
1070  // Check if there really is a H2O species.
1071  if (h2o_index<0)
1072  {
1073  ostringstream os;
1074  os << "Some of your species require nonlinear treatment,\n"
1075  << "but you have no H2O species.";
1076  throw runtime_error( os.str() );
1077  }
1078 
1079  for (Index i=0; i<p_grid.nelem(); ++i)
1080  {
1081  h2omin[i] = min(vmr_field(h2o_index,i,joker,joker));
1082  h2omax[i] = max(vmr_field(h2o_index,i,joker,joker));
1083  }
1084 
1085 // cout << "H2Omin: " << h2omin << "\n";
1086 // cout << "H2Omax: " << h2omax << "\n";
1087 // cout << "H2Omean: " << vmrmean(h2o_index,joker) << "\n";
1088 
1089  }
1090 
1091 
1092  // Interpolate in pressure, set abs_t, abs_vmr...
1093 
1094  // Reference temperature,
1095  // interpolate abs_t from tmean:
1096  abs_t.resize(log_abs_p.nelem());
1097  interp(abs_t,
1098  itw,
1099  tmean,
1100  gp);
1101 
1102  // Temperature perturbations:
1103  choose_abs_t_pert(abs_t_pert, tmean, tmin, tmax, t_step,
1104  abs_p_interp_order, abs_t_interp_order,
1105  verbosity);
1106 // cout << "abs_t_pert: " << abs_t_pert << "\n";
1107 
1108  // Reference VMR profiles,
1109  // interpolate abs_vmrs from vmrmean:
1110  abs_vmrs.resize(abs_species.nelem(), log_abs_p.nelem());
1111  for (Index i=0; i<abs_species.nelem(); ++i)
1112  interp(abs_vmrs(i,joker),
1113  itw,
1114  vmrmean(i,joker),
1115  gp);
1116 
1117  if (0<abs_nls.nelem())
1118  {
1119  // Construct abs_nls_pert:
1120  choose_abs_nls_pert(abs_nls_pert,
1121  vmrmean(h2o_index, joker),
1122  h2omin,
1123  h2omax,
1124  h2o_step,
1125  abs_p_interp_order,
1126  abs_nls_interp_order,
1127  verbosity);
1128  }
1129  else
1130  {
1131  // Empty abs_nls_pert:
1132  abs_nls_pert.resize(0);
1133  }
1134 // cout << "abs_nls_pert: " << abs_nls_pert << "\n";
1135 
1136  }
1137 }
1138 
1139 
1140 /* Workspace method: Doxygen documentation will be auto-generated */
1141 void abs_lookupSetupBatch(// WS Output:
1142  Vector& abs_p,
1143  Vector& abs_t,
1144  Vector& abs_t_pert,
1145  Matrix& abs_vmrs,
1146  ArrayOfArrayOfSpeciesTag& abs_nls,
1147  Vector& abs_nls_pert,
1148  // WS Input:
1149  const ArrayOfArrayOfSpeciesTag& abs_species,
1150  const ArrayOfGriddedField4& batch_fields,
1151  const Index& abs_p_interp_order,
1152  const Index& abs_t_interp_order,
1153  const Index& abs_nls_interp_order,
1154  // Control Parameters:
1155  const Numeric& p_step10,
1156  const Numeric& t_step,
1157  const Numeric& h2o_step,
1158  const Vector& extremes,
1159  const Verbosity& verbosity)
1160 {
1161  CREATE_OUT2
1162  CREATE_OUT3
1163 
1164  // For consistency with other code around arts (e.g., correlation
1165  // lengths in atmlab), p_step is given as log10(p[Pa]). However, we
1166  // convert it here to the natural log:
1167  const Numeric p_step = log(pow(10.0, p_step10));
1168 
1169  // Derive field, where abs_species profiles start
1170  // (in batch_fields, first 2 are T and z, then we have an unknown number of
1171  // part_species fields, followed by N fields corresponding to the N entries in
1172  // abs_species)
1173  const Index indoff = batch_fields[0].data.nbooks()-abs_species.nelem();
1174 // cout << "abs species start at column " << indoff << ", i.e.,\n"
1175 // << indoff-2 << " particle related columns are present\n";
1176 
1177  // Derive which abs_species is H2O (required for nonlinear species handling)
1178  // returns -1 if no H2O present
1179  const Index h2o_index = find_first_species_tg( abs_species,
1181 // cout << "The " << h2o_index+1 << ". species in abs_species is H2O\n";
1182 // cout << "That is, H2O is expected to be the " << indoff+h2o_index
1183 // << ". column of the atmospheric fields\n";
1184 
1185  // Check that the field names in batch_fields are good. (We check
1186  // only the first field in the batch.)
1187  {
1188  ostringstream os;
1189  bool bail = false;
1190 
1191  const ArrayOfString field_names = batch_fields[0].get_string_grid(0);
1192 
1193  ArrayOfString species_names(abs_species.nelem());
1194  for (Index i=0; i<abs_species.nelem(); ++i)
1195  species_names[i] = get_species_name(abs_species[i]);
1196 
1197  // First simply check dimensions of abs_species and field_names
1198  if (field_names.nelem() < 3)
1199  {
1200  os << "Atmospheric states in batch_fields must have at\n"
1201  << "least three fields: T, z, and at least one species.";
1202  throw runtime_error( os.str() );
1203  }
1204 
1205  if (abs_species.nelem() < 1)
1206  {
1207  os << "At least one absorption species needs to be defined "
1208  << "in abs_species.";
1209  throw runtime_error( os.str() );
1210  }
1211 
1212 /*
1213  if (abs_species.nelem() != field_names.nelem()-2)
1214  {
1215  os << "Dimension of fields in batch_fields does not match that of abs_species.\n"
1216  << "(First two fields must be T and z, rest must match absorption species.)\n"
1217  << "Field names: " << field_names << "\n"
1218  << "Absorption species: " << species_names;
1219  throw runtime_error( os.str() );
1220  }
1221 */
1222  // field_names.nelem = 2(T,z) + M(part_species) + N(abs_species)
1223  // but we don't know M, so we can only check whether we have at least
1224  // N+2 (abs_species+T+z) atmospheric fields
1225  if (abs_species.nelem() > field_names.nelem()-2)
1226  {
1227  os << "Dimension of fields in batch_fields does not match that of abs_species.\n"
1228  << "(First two fields must be T and z, the N last fields must match the\n"
1229  << "absorption species, where N is the number of species as defined in abs_species.)\n"
1230  << "Field names: " << field_names << "\n"
1231  << "Absorption species: " << species_names;
1232  throw runtime_error( os.str() );
1233  }
1234 
1235  os << "The consistency check of the first compact atmospheric state in\n"
1236  << "batch_fields has shown one or more errors:\n";
1237 
1238  // First field must be T:
1239  if ("T" != field_names[0])
1240  {
1241  os << "The first field name must be T.\n";
1242  bail = true;
1243  }
1244 
1245  // Second field must be z:
1246  if ("z" != field_names[1])
1247  {
1248  os << "The second field name must be z.\n";
1249  bail = true;
1250  }
1251 
1252  // One of the abs_species has to be H2O
1253  // (ideally that should be checked later, when we know whether there are
1254  // nonlinear species present. however, currently batch mode REQUIRES H2O to
1255  // be present, so we check that immediately)
1256  if (h2o_index < 0)
1257  {
1258  os << "One of the atmospheric fields must be H2O.\n";
1259  bail = true;
1260  }
1261 
1262  // The other fields must match abs_species:
1263  bool wrong_species = false;
1264  for (Index i=0; i<abs_species.nelem(); ++i)
1265  if (field_names[indoff+i] != species_names[i])
1266  wrong_species = true;
1267 
1268  if (wrong_species)
1269  {
1270  os << "The " << abs_species.nelem() << " last field names must "
1271  << "match the absorption species in\n"
1272  << "abs_species, which are:\n"
1273  << species_names << "\n";
1274  bail = true;
1275  }
1276 
1277  os << "Your field names are:\n"
1278  << field_names;
1279 
1280  if (bail) throw runtime_error( os.str() );
1281  }
1282 
1283  // FIXME: Adjustment of min/max values for Jacobian perturbations is still missing.
1284 
1285  // Make an intelligent choice for the nonlinear species.
1286  choose_abs_nls(abs_nls, abs_species, verbosity);
1287 
1288  // Find out maximum and minimum pressure.
1289  Numeric maxp=batch_fields[0].get_numeric_grid(GFIELD4_P_GRID)[0];
1290  Numeric minp=batch_fields[0].get_numeric_grid(GFIELD4_P_GRID)[batch_fields[0].get_numeric_grid(GFIELD4_P_GRID).nelem()-1];
1291  for (Index i=0; i<batch_fields.nelem(); ++i)
1292  {
1293  if (maxp < batch_fields[i].get_numeric_grid(GFIELD4_P_GRID)[0])
1294  maxp = batch_fields[i].get_numeric_grid(GFIELD4_P_GRID)[0];
1295  if (minp > batch_fields[i].get_numeric_grid(GFIELD4_P_GRID)[batch_fields[i].get_numeric_grid(GFIELD4_P_GRID).nelem()-1])
1296  minp = batch_fields[i].get_numeric_grid(GFIELD4_P_GRID)[batch_fields[i].get_numeric_grid(GFIELD4_P_GRID).nelem()-1];
1297  }
1298  // cout << " minp/maxp: " << minp << " / " << maxp << "\n";
1299 
1300  if (maxp==minp)
1301  {
1302  ostringstream os;
1303  os << "You need at least two pressure levels.";
1304  throw runtime_error( os.str() );
1305  }
1306 
1307  // We construct the pressure grid as follows:
1308  // - Everything is done in log(p).
1309  // - Start with maxp and go down in steps of p_step until we are <= minp.
1310  // - Adjust the final pressure value to be exactly minp, otherwise
1311  // we have problems in getting min, max, and mean values for this
1312  // point later.
1313  Index np = (Index) ceil((log(maxp)-log(minp))/p_step)+1;
1314  // The +1 above has to be there because we must include also both
1315  // grid end points.
1316 
1317  // If np is too small for the interpolation order, we increase it:
1318  if (np < abs_p_interp_order+1)
1319  np = abs_p_interp_order+1;
1320 
1321  Vector log_abs_p(log(maxp), np, -p_step);
1322  log_abs_p[np-1] = log(minp);
1323 
1324  abs_p.resize(np);
1325  transform(abs_p, exp, log_abs_p);
1326  out2 << " abs_p: " << abs_p[0] << " Pa to " << abs_p[np-1]
1327  << " Pa in log10 steps of " << p_step10
1328  << " (" << np << " grid points)\n";
1329 
1330  // Now we have to determine the statistics of T and VMRs, we need
1331  // profiles of min, max, and mean of these, on the abs_p grid.
1332 
1333 // Index n_variables = batch_fields[0].data.nbooks();
1334  // we will do statistics for data fields excluding the part_species fields
1335  Index n_variables = 2+abs_species.nelem();
1336 
1337  // The first dimension of datamin, datamax, and datamean is the
1338  // variable (T,Z,H2O,O3,...). The second dimension is pressure. We
1339  // assume all elements of the batch have the same variables.
1340 
1341  Matrix datamin (n_variables, np, numeric_limits<Numeric>::max());
1342  Matrix datamax (n_variables, np, numeric_limits<Numeric>::min());
1343  // The limits here are from the header file <limits>
1344  Matrix datamean (n_variables, np, 0);
1345  Vector mean_norm(np,0); // Divide by this to get mean.
1346 
1347 
1348  // We will loop over all batch cases to analyze the statistics and
1349  // calculate reference profiles. As a little side project, we will
1350  // also calculate the absolute min and max of temperature and
1351  // humidity. This is handy as input to abs_lookupSetupWide.
1352  Numeric mint=+1e99;
1353  Numeric maxt=-1e99;
1354  Numeric minh2o=+1e99;
1355  Numeric maxh2o=-1e99;
1356 
1357  for (Index i=0; i<batch_fields.nelem(); ++i)
1358  {
1359  // Check that really each case has the same variables (see
1360  // comment above.)
1361  if (batch_fields[i].get_string_grid(GFIELD4_FIELD_NAMES)
1362  != batch_fields[0].get_string_grid(GFIELD4_FIELD_NAMES))
1363  throw runtime_error("All fields in the batch must have the same field names.");
1364 
1365  // Check that the first field is indeed T
1366  if ("T" != batch_fields[i].get_string_grid(GFIELD4_FIELD_NAMES)[0])
1367  {
1368  ostringstream os;
1369  os << "The first variable in the compact atmospheric state must be \"T\",\n"
1370  << "but yours is: " << batch_fields[i].get_string_grid(GFIELD4_FIELD_NAMES)[0];
1371  throw runtime_error( os.str() );
1372  }
1373 
1374  // Check that field h2o_index+indoff is indeed H2O:
1375  if ("H2O" !=
1376  batch_fields[i].get_string_grid(GFIELD4_FIELD_NAMES)[indoff+h2o_index])
1377  {
1378  ostringstream os;
1379  os << "According to abs_species setting the " << indoff+h2o_index
1380  << ". variable in the compact\n"
1381  << "atmospheric state is supposed to be \"H2O\",\n"
1382  << "but yours is: "
1383  << batch_fields[i].get_string_grid(GFIELD4_FIELD_NAMES)[indoff+h2o_index];
1384  throw runtime_error( os.str() );
1385  }
1386 
1387  // Create convenient handles:
1388  const Vector& p_grid = batch_fields[i].get_numeric_grid(GFIELD4_P_GRID);
1389  const Tensor4& data = batch_fields[i].data;
1390 
1391  // Update our global max/min values for T and H2O:
1392 
1393  // We have to loop over pressure, latitudes, and longitudes
1394  // here. The dimensions of data are:
1395  // data[N_fields][N_p][N_lat][N_lon]
1396 
1397  for (Index ip=0; ip<data.npages(); ++ip)
1398  for (Index ilat=0; ilat<data.nrows(); ++ilat)
1399  for (Index ilon=0; ilon<data.ncols(); ++ilon)
1400  {
1401  // Field 0 is temperature:
1402  if (data(0,ip,ilat,ilon) < mint) mint = data(0,ip,ilat,ilon);
1403  if (data(0,ip,ilat,ilon) > maxt) maxt = data(0,ip,ilat,ilon);
1404  // Field indoff+h2o_index is H2O:
1405  if (data(indoff+h2o_index,ip,ilat,ilon) < minh2o)
1406  { minh2o = data(indoff+h2o_index,ip,ilat,ilon); }
1407  if (data(indoff+h2o_index,ip,ilat,ilon) > maxh2o)
1408  { maxh2o = data(indoff+h2o_index,ip,ilat,ilon); }
1409  }
1410 
1411  // Interpolate the current batch fields to the abs_p grid. We
1412  // have to do this for each batch case, since the grids could
1413  // all be different.
1414 
1415  Vector log_p_grid(p_grid.nelem());
1416  transform(log_p_grid, log, p_grid);
1417 
1418  // There is a catch here: We can only use the part of abs_p that
1419  // is inside the current pressure grid p_grid, otherwise we
1420  // would have to extrapolate.
1421  // The eps_bottom and eps_top account for the little bit of
1422  // extrapolation that is allowed.
1423 
1424  const Numeric eps_bottom = (log_p_grid[0]-log_p_grid[1])/2.1;
1425  Index first_p=0;
1426  while (log_abs_p[first_p] > log_p_grid[0]+eps_bottom) ++first_p;
1427 
1428  const Numeric eps_top = (log_p_grid[log_p_grid.nelem()-2]-log_p_grid[log_p_grid.nelem()-1])/2.1;
1429  Index last_p=log_abs_p.nelem()-1;
1430  while (log_abs_p[last_p] < log_p_grid[log_p_grid.nelem()-1]-eps_top) --last_p;
1431 
1432  const Index extent_p = last_p - first_p + 1;
1433 
1434  // This was too complicated to get right:
1435  // const Index first_p = (Index) round ( (log_abs_p[0] - log_p_grid[0]) / p_step);
1436  // const Index extent_p = (Index) round ( (log_abs_p[first_p] - log_p_grid[log_p_grid.nelem()-1]) / p_step) + 1;
1437 
1438 
1439  ConstVectorView active_log_abs_p = log_abs_p[Range(first_p, extent_p)];
1440 
1441 // cout << "first_p / last_p / extent_p : " << first_p << " / " << last_p << " / " << extent_p << "\n";
1442 // cout << "log_p_grid: " << log_p_grid << "\n";
1443 // cout << "log_abs_p: " << log_abs_p << "\n";
1444 // cout << "active_log_abs_p: " << active_log_abs_p << "\n";
1445 // cout << "=============================================================\n";
1446 // arts_exit();
1447 
1448  // Grid positions:
1449  ArrayOfGridPos gp(active_log_abs_p.nelem());
1450  gridpos(gp, log_p_grid, active_log_abs_p);
1451  // gridpos(gp, log_p_grid, active_log_abs_p, 100);
1452  // We allow much more extrapolation here than normal (0.5 is
1453  // normal). If we do not do this, then we get problems for
1454  // p_grids that are much finer than abs_p.
1455 
1456  // Interpolation weights:
1457  Matrix itw(gp.nelem(),2);
1458  interpweights(itw,gp);
1459 
1460  // We have to loop over fields, latitudes, and longitudes here, doing the
1461  // pressure interpolation for all. The dimensions of data are:
1462  // data[N_fields][N_p][N_lat][N_lon]
1463  // For data_interp we reduce data by the particle related fields, i.e.,
1464  // the ones in between the first two and the last N=abs_species.nelem().
1465 // Tensor4 data_interp(data.nbooks(),
1466  Tensor4 data_interp(n_variables,
1467  active_log_abs_p.nelem(),
1468  data.nrows(),
1469  data.ncols());
1470 
1471  for (Index lo=0; lo<data.ncols(); ++lo)
1472  for (Index la=0; la<data.nrows(); ++la)
1473  {
1474 // for (Index fi=0; fi<data.nbooks(); ++fi)
1475  // we have to handle T/z and abs_species parts separately since they
1476  // can have part_species in between, which we want to ignore
1477  for (Index fi=0; fi<2; ++fi)
1478  interp(data_interp(fi, joker, la, lo),
1479  itw,
1480  data(fi, joker, la, lo),
1481  gp);
1482  for (Index fi=indoff; fi<data.nbooks(); ++fi)
1483  interp(data_interp(fi-indoff+2, joker, la, lo),
1484  itw,
1485  data(fi, joker, la, lo),
1486  gp);
1487  }
1488 
1489  // Now update our datamin, datamax, and datamean variables.
1490  // We need the min and max only for the T and H2O profile,
1491  // not for others. But we need the mean for all. We are just
1492  // hopping over the case that we do not need below. This is not
1493  // very clean, but efficient. And it avoids handling all the
1494  // different cases explicitly.
1495  for (Index lo=0; lo<data_interp.ncols(); ++lo)
1496  for (Index la=0; la<data_interp.nrows(); ++la)
1497  {
1498  for (Index fi=0; fi<data_interp.nbooks(); ++fi)
1499  {
1500  if (1!=fi) // We skip the z field, which we do not need
1501  for (Index pr=0; pr<data_interp.npages(); ++pr)
1502  {
1503  // Min and max only needed for T and H2o
1504  if (0==fi || (h2o_index+2)==fi)
1505  {
1506  if (data_interp(fi, pr, la, lo) < datamin(fi, first_p+pr))
1507  datamin(fi, first_p+pr) = data_interp(fi, pr, la, lo);
1508  if (data_interp(fi, pr, la, lo) > datamax(fi, first_p+pr))
1509  datamax(fi, first_p+pr) = data_interp(fi, pr, la, lo);
1510  }
1511 
1512  datamean(fi, first_p+pr) += data_interp(fi, pr, la, lo);
1513  }
1514  }
1515 
1516  // The mean_norm is actually a bit tricky. It depends on
1517  // pressure, since different numbers of cases contribute
1518  // to the mean for different pressures. At the very eges
1519  // of the grid, typically only a single case contributes.
1520 
1521  mean_norm[Range(first_p, extent_p)] += 1;
1522  }
1523  }
1524 
1525  out2 << " Global statistics:\n"
1526  << " min(p) / max(p) [Pa]: " << minp << " / " << maxp << "\n"
1527  << " min(T) / max(T) [K]: " << mint << " / " << maxt << "\n"
1528  << " min(H2O) / max(H2O) [VMR]: " << minh2o << " / " << maxh2o << "\n";
1529 
1530 
1531  // Divide mean by mean_norm to get the mean:
1532  assert(np==mean_norm.nelem());
1533  for (Index fi=0; fi<datamean.nrows(); ++fi)
1534  if (1!=fi) // We skip the z field, which we do not need
1535  for (Index pi=0; pi<np; ++pi)
1536  {
1537  // We do this in an explicit loop here, since we have to
1538  // check whether there really were data points to calculate
1539  // the mean at each level.
1540  if (0<mean_norm[pi])
1541  datamean(fi,pi) /= mean_norm[pi];
1542  else
1543  {
1544  ostringstream os;
1545  os << "No data at pressure level " << pi+1
1546  << " of "<< np << " (" << abs_p[pi] << " hPa).";
1547  throw runtime_error( os.str() );
1548  }
1549  }
1550 
1551  // If we do higher order pressure interpolation, then we should
1552  // smooth the reference profiles with a boxcar filter of width
1553  // p_interp_order+1. Otherwise we get numerical problems if there
1554  // are any sharp spikes in the reference profiles.
1555  assert(log_abs_p.nelem()==np);
1556  Matrix smooth_datamean(datamean.nrows(), datamean.ncols(), 0);
1557  for (Index i=0; i<np; ++i)
1558  {
1559  GridPosPoly gp;
1560  gridpos_poly(gp, log_abs_p, log_abs_p[i], abs_p_interp_order);
1561 
1562  // We do this in practice by using the indices returned by
1563  // gridpos_poly. We simply take a mean over all points that
1564  // would be used in the interpolation.
1565 
1566  for (Index fi=0; fi<datamean.nrows(); ++fi)
1567  if (1!=fi) // We skip the z field, which we do not need
1568  {
1569  for (Index j=0; j<gp.idx.nelem(); ++j)
1570  {
1571  smooth_datamean(fi,i) += datamean(fi,gp.idx[j]);
1572  }
1573  smooth_datamean(fi,i) /= (Numeric)gp.idx.nelem();
1574  }
1575 // cout << "H2O-raw / H2O-smooth: "
1576 // << datamean(h2o_index+2,i) << " / "
1577 // << smooth_datamean(h2o_index+2,i) << "\n";
1578  }
1579 
1580  // There is another complication: If the (smoothed) mean for the H2O
1581  // reference profile is 0, then we have to adjust both mean and max
1582  // value to a non-zero number, otherwise the reference profile will
1583  // be zero, and we will get numerical problems later on when we
1584  // divide by the reference value. So, we set it here to 1e-9.
1585  for (Index i=0; i<np; ++i)
1586  {
1587  // Assert that really H2O has index h2o_index+indoff in the VMR field list
1588  assert("H2O" ==
1589  batch_fields[0].get_string_grid(GFIELD4_FIELD_NAMES)[indoff+h2o_index]);
1590 
1591  // Find mean and max H2O for this level:
1592  Numeric& mean_h2o = smooth_datamean(h2o_index+2,i);
1593  Numeric& max_h2o = datamax(h2o_index+2,i);
1594  if (mean_h2o <= 0)
1595  {
1596  mean_h2o = 1e-9;
1597  max_h2o = 1e-9;
1598  out3 << " H2O profile contained zero values, adjusted to 1e-9.\n";
1599  }
1600  }
1601 
1602  // Set abs_t:
1603  abs_t.resize(np);
1604  abs_t = smooth_datamean(0,joker);
1605  // cout << "abs_t: " << abs_t << "\n\n";
1606  // cout << "tmin: " << datamin(0,joker) << "\n\n";
1607  // cout << "tmax: " << datamax(0,joker) << "\n";
1608 
1609  // Set abs_vmrs:
1610  assert(abs_species.nelem()==smooth_datamean.nrows()-2);
1611  abs_vmrs.resize(abs_species.nelem(), np);
1612  abs_vmrs = smooth_datamean(Range(2,abs_species.nelem()),joker);
1613  // cout << "\n\nabs_vmrs: " << abs_vmrs << "\n\n";
1614 
1615  // Construct abs_t_pert:
1616  ConstVectorView tmin = datamin(0,joker);
1617  ConstVectorView tmax = datamax(0,joker);
1618  choose_abs_t_pert(abs_t_pert, abs_t, tmin, tmax, t_step, abs_p_interp_order, abs_t_interp_order,
1619  verbosity);
1620  // cout << "abs_t_pert: " << abs_t_pert << "\n";
1621 
1622  // Construct abs_nls_pert:
1623  ConstVectorView h2omin = datamin(h2o_index+2,joker);
1624  ConstVectorView h2omax = datamax(h2o_index+2,joker);
1625  choose_abs_nls_pert(abs_nls_pert, abs_vmrs(h2o_index,joker),
1626  h2omin, h2omax, h2o_step,
1627  abs_p_interp_order, abs_nls_interp_order,
1628  verbosity);
1629  // cout << "abs_nls_pert: " << abs_nls_pert << "\n";
1630 
1631  // Append the explicitly given user extreme values, if necessary:
1632  if (0!=extremes.nelem())
1633  {
1634  // There must be 4 values in this case: t_min, t_max, h2o_min, h2o_max
1635  if (4!=extremes.nelem())
1636  {
1637  ostringstream os;
1638  os << "There must be exactly 4 elements in extremes:\n"
1639  << "min(abs_t_pert), max(abs_t_pert), min(abs_nls_pert), max(abs_nls_pert)";
1640  throw runtime_error( os.str() );
1641  }
1642 
1643  // t_min:
1644  if (extremes[0] < abs_t_pert[0])
1645  {
1646  Vector dummy = abs_t_pert;
1647  abs_t_pert.resize(abs_t_pert.nelem()+1);
1648  abs_t_pert[0] = extremes[0];
1649  abs_t_pert[Range(1,dummy.nelem())] = dummy;
1650  out2 << " Added min extreme value for abs_t_pert: "
1651  << abs_t_pert[0] << "\n";
1652  }
1653 
1654  // t_max:
1655  if (extremes[1] > abs_t_pert[abs_t_pert.nelem()-1])
1656  {
1657  Vector dummy = abs_t_pert;
1658  abs_t_pert.resize(abs_t_pert.nelem()+1);
1659  abs_t_pert[Range(0,dummy.nelem())] = dummy;
1660  abs_t_pert[abs_t_pert.nelem()-1] = extremes[1];
1661  out2 << " Added max extreme value for abs_t_pert: "
1662  << abs_t_pert[abs_t_pert.nelem()-1] << "\n";
1663  }
1664 
1665  // nls_min:
1666  if (extremes[2] < abs_nls_pert[0])
1667  {
1668  Vector dummy = abs_nls_pert;
1669  abs_nls_pert.resize(abs_nls_pert.nelem()+1);
1670  abs_nls_pert[0] = extremes[2];
1671  abs_nls_pert[Range(1,dummy.nelem())] = dummy;
1672  out2 << " Added min extreme value for abs_nls_pert: "
1673  << abs_nls_pert[0] << "\n";
1674  }
1675 
1676  // nls_max:
1677  if (extremes[3] > abs_nls_pert[abs_nls_pert.nelem()-1])
1678  {
1679  Vector dummy = abs_nls_pert;
1680  abs_nls_pert.resize(abs_nls_pert.nelem()+1);
1681  abs_nls_pert[Range(0,dummy.nelem())] = dummy;
1682  abs_nls_pert[abs_nls_pert.nelem()-1] = extremes[3];
1683  out2 << " Added max extreme value for abs_nls_pert: "
1684  << abs_nls_pert[abs_nls_pert.nelem()-1] << "\n";
1685  }
1686  }
1687 }
1688 
1689 
1690 void abs_lookupSetupWide(// WS Output:
1691  Vector& abs_p,
1692  Vector& abs_t,
1693  Vector& abs_t_pert,
1694  Matrix& abs_vmrs,
1695  ArrayOfArrayOfSpeciesTag& abs_nls,
1696  Vector& abs_nls_pert,
1697  // WS Input:
1698  const ArrayOfArrayOfSpeciesTag& abs_species,
1699  const Index& abs_p_interp_order,
1700  const Index& abs_t_interp_order,
1701  const Index& abs_nls_interp_order,
1702  // Control Parameters:
1703  const Numeric& p_min,
1704  const Numeric& p_max,
1705  const Numeric& p_step10,
1706  const Numeric& t_min,
1707  const Numeric& t_max,
1708  const Numeric& h2o_min,
1709  const Numeric& h2o_max,
1710  const Verbosity& verbosity)
1711 {
1712  CREATE_OUT2
1713 
1714  // For consistency with other code around arts (e.g., correlation
1715  // lengths in atmlab), p_step is given as log10(p[Pa]). However, we
1716  // convert it here to the natural log:
1717  const Numeric p_step = log(pow(10.0, p_step10));
1718 
1719  // Make an intelligent choice for the nonlinear species.
1720  choose_abs_nls(abs_nls, abs_species, verbosity);
1721 
1722  // 1. Fix pressure grid abs_p
1723  // --------------------------
1724 
1725  // We construct the pressure grid as follows:
1726  // - Everything is done in log(p).
1727  // - Start with p_max and go down in steps of p_step until we are <= p_min.
1728 
1729  Index np = (Index) ceil((log(p_max)-log(p_min))/p_step)+1;
1730  // The +1 above has to be there because we must include also both
1731  // grid end points.
1732 
1733  // If np is too small for the interpolation order, we increase it:
1734  if (np < abs_p_interp_order+1)
1735  np = abs_p_interp_order+1;
1736 
1737  Vector log_abs_p(log(p_max), np, -p_step);
1738 
1739  abs_p.resize(np);
1740  transform(abs_p, exp, log_abs_p);
1741  out2 << " abs_p: " << abs_p[0] << " Pa to " << abs_p[np-1]
1742  << " Pa in log10 steps of " << p_step10
1743  << " (" << np << " grid points)\n";
1744 
1745 
1746  // 2. Fix reference temperature profile abs_t and temperature perturbations
1747  // ------------------------------------------------------------------------
1748 
1749  // We simply take a constant reference profile.
1750 
1751  Numeric t_ref = (t_min + t_max) / 2;
1752 
1753  abs_t.resize(np);
1754  abs_t = t_ref; // Assign same value to all elements.
1755 
1756  // We have to make vectors out of t_min and t_max, so we can use
1757  // them in the choose_abs_t_pert function call:
1758  Vector min_prof(np), max_prof(np);
1759  min_prof = t_min;
1760  max_prof = t_max;
1761 
1762  // Chose temperature perturbations:
1763  choose_abs_t_pert(abs_t_pert,
1764  abs_t, min_prof, max_prof, 20,
1765  abs_p_interp_order, abs_t_interp_order,
1766  verbosity);
1767 
1768 
1769  // 3. Fix reference H2O profile and abs_nls_pert
1770  // ---------------------------------------------
1771 
1772  // We take a constant reference profile of 1000ppm (=1e-3)
1773 
1774  Numeric h2o_ref = 1e-3;
1775 
1776  // We have to assign this value to all pressures of the H2O profile,
1777  // and 0 to all other profiles.
1778 
1779  // abs_vmrs has dimension [n_species, np].
1780  abs_vmrs.resize(abs_species.nelem(), np);
1781  abs_vmrs = 0;
1782 
1783  // We look for O2 and N2, and assign constant values to them.
1784  // The values are from Wallace&Hobbs, 2nd edition.
1785 
1786  const Index o2_index
1787  = find_first_species_tg( abs_species,
1789  if (o2_index>=0)
1790  {
1791  abs_vmrs(o2_index, joker) = 0.2095;
1792  }
1793 
1794  const Index n2_index
1795  = find_first_species_tg( abs_species,
1797  if (n2_index>=0)
1798  {
1799  abs_vmrs(n2_index, joker) = 0.7808;
1800  }
1801 
1802 
1803  // Which species is H2O?
1804  const Index h2o_index
1805  = find_first_species_tg( abs_species,
1807 
1808  // The function returns "-1" if there is no H2O
1809  // species.
1810  if (0<abs_nls.nelem())
1811  {
1812  if (h2o_index<0)
1813  {
1814  ostringstream os;
1815  os << "Some of your species require nonlinear treatment,\n"
1816  << "but you have no H2O species.";
1817  throw runtime_error( os.str() );
1818  }
1819 
1820  // Assign constant reference value to all H2O levels:
1821  abs_vmrs(h2o_index, joker) = h2o_ref;
1822 
1823  // We have to make vectors out of h2o_min and h2o_max, so we can use
1824  // them in the choose_abs_nls_pert function call.
1825  // We re-use the vectors min_prof and max_prof that we have
1826  // defined above.
1827  min_prof = h2o_min;
1828  max_prof = h2o_max;
1829 
1830  // Construct abs_nls_pert:
1831  choose_abs_nls_pert(abs_nls_pert,
1832  abs_vmrs(h2o_index, joker),
1833  min_prof,
1834  max_prof,
1835  1e99,
1836  abs_p_interp_order,
1837  abs_nls_interp_order,
1838  verbosity);
1839  }
1840  else
1841  {
1842  CREATE_OUT1
1843  out1 << " WARNING:\n"
1844  << " You have no species that require H2O variations.\n"
1845  << " This case might work, but it has never been tested.\n"
1846  << " Please test it, then remove this warning.\n";
1847  }
1848 }
1849 
1850 
1851 /* Workspace method: Doxygen documentation will be auto-generated */
1852 void abs_speciesAdd(// WS Output:
1853  ArrayOfArrayOfSpeciesTag& abs_species,
1854  // Control Parameters:
1855  const ArrayOfString& names,
1856  const Verbosity& verbosity)
1857 {
1858  CREATE_OUT3
1859 
1860  // Size of initial array
1861  Index n_gs = abs_species.nelem();
1862 
1863  // Temporary ArrayOfSpeciesTag
1865 
1866  // Each element of the array of Strings names defines one tag
1867  // group. Let's work through them one by one.
1868  for ( Index i=0; i<names.nelem(); ++i )
1869  {
1870  array_species_tag_from_string( temp, names[i] );
1871  abs_species.push_back(temp);
1872  }
1873 
1874  // Print list of tag groups to the most verbose output stream:
1875  out3 << " Added tag groups:";
1876  for ( Index i=n_gs; i<abs_species.nelem(); ++i )
1877  {
1878  out3 << "\n " << i << ":";
1879  for ( Index s=0; s<abs_species[i].nelem(); ++s )
1880  {
1881  out3 << " " << abs_species[i][s].Name();
1882  }
1883  }
1884  out3 << '\n';
1885 }
1886 
1887 
1888 /* Workspace method: Doxygen documentation will be auto-generated */
1889 void abs_speciesAdd2(// WS Output:
1890  Workspace& ws,
1891  ArrayOfArrayOfSpeciesTag& abs_species,
1893  Agenda& jacobian_agenda,
1894  // WS Input:
1895  const Index& atmosphere_dim,
1896  const Vector& p_grid,
1897  const Vector& lat_grid,
1898  const Vector& lon_grid,
1899  // WS Generic Input:
1900  const Vector& rq_p_grid,
1901  const Vector& rq_lat_grid,
1902  const Vector& rq_lon_grid,
1903  // Control Parameters:
1904  const String& species,
1905  const String& method,
1906  const String& mode,
1907  const Numeric& dx,
1908  const Verbosity& verbosity)
1909 {
1910  CREATE_OUT3
1911 
1912  // Add species to *abs_species*
1913  ArrayOfSpeciesTag tags;
1914  array_species_tag_from_string( tags, species );
1915  abs_species.push_back( tags );
1916 
1917  // Print list of added tag group to the most verbose output stream:
1918  out3 << " Appended tag group:";
1919  out3 << "\n " << abs_species.nelem()-1 << ":";
1920  for ( Index s=0; s<tags.nelem(); ++s )
1921  {
1922  out3 << " " << tags[s].Name();
1923  }
1924  out3 << '\n';
1925 
1926  // Do retrieval part
1927  jacobianAddAbsSpecies( ws, jq, jacobian_agenda, atmosphere_dim,
1928  p_grid, lat_grid, lon_grid, rq_p_grid, rq_lat_grid,
1929  rq_lon_grid, species, method, mode, dx,
1930  verbosity);
1931 }
1932 
1933 
1934 /* Workspace method: Doxygen documentation will be auto-generated */
1936  const Verbosity&)
1937 {
1938  abs_species.resize(0);
1939 }
1940 
1941 
1942 /* Workspace method: Doxygen documentation will be auto-generated */
1943 void SpeciesSet(// WS Generic Output:
1944  ArrayOfArrayOfSpeciesTag& abs_species,
1945  // Control Parameters:
1946  const ArrayOfString& names,
1947  const Verbosity& verbosity)
1948 {
1949  CREATE_OUT3
1950 
1951  abs_species.resize(names.nelem());
1952 
1953  //cout << "Names: " << names << "\n";
1954 
1955  // Each element of the array of Strings names defines one tag
1956  // group. Let's work through them one by one.
1957  for ( Index i=0; i<names.nelem(); ++i )
1958  {
1959  // This part has now been moved to array_species_tag_from_string.
1960  // Call this function.
1961  array_species_tag_from_string( abs_species[i], names[i] );
1962  }
1963 
1964  // Print list of tag groups to the most verbose output stream:
1965  out3 << " Defined tag groups: ";
1966  for ( Index i=0; i<abs_species.nelem(); ++i )
1967  {
1968  out3 << "\n " << i << ":";
1969  for ( Index s=0; s<abs_species[i].nelem(); ++s )
1970  {
1971  out3 << " " << abs_species[i][s].Name();
1972  }
1973  }
1974  out3 << '\n';
1975 }
1976 
1977 
1978 /* Workspace method: Doxygen documentation will be auto-generated */
1979 void abs_lookupAdapt( GasAbsLookup& abs_lookup,
1980  Index& abs_lookup_is_adapted,
1981  const ArrayOfArrayOfSpeciesTag& abs_species,
1982  const Vector& f_grid,
1983  const Verbosity& verbosity)
1984 {
1985  abs_lookup.Adapt( abs_species, f_grid, verbosity );
1986  abs_lookup_is_adapted = 1;
1987 }
1988 
1989 
1990 /* Workspace method: Doxygen documentation will be auto-generated */
1992  const GasAbsLookup& abs_lookup,
1993  const Index& abs_lookup_is_adapted,
1994  const Index& abs_p_interp_order,
1995  const Index& abs_t_interp_order,
1996  const Index& abs_nls_interp_order,
1997  const Index& f_index,
1998  const Numeric& a_pressure,
1999  const Numeric& a_temperature,
2000  const Vector& a_vmr_list,
2001  const Numeric& a_doppler,
2002  const Numeric& extpolfac,
2003  const Verbosity& verbosity)
2004 {
2005  CREATE_OUT3
2006 
2007  // Check if the table has been adapted:
2008  if ( 1!=abs_lookup_is_adapted )
2009  throw runtime_error("Gas absorption lookup table must be adapted,\n"
2010  "use method abs_lookupAdapt.");
2011 
2012  // The function we are going to call here is one of the few helper
2013  // functions that adjust the size of their output argument
2014  // automatically.
2015  abs_lookup.Extract( abs_scalar_gas,
2016  abs_p_interp_order,
2017  abs_t_interp_order,
2018  abs_nls_interp_order,
2019  f_index,
2020  a_pressure,
2021  a_temperature,
2022  a_vmr_list );
2023 
2024  // Apply Doppler shift, if necessary.
2025  if (0==a_doppler)
2026  {
2027  out3 << " Doppler shift: None\n";
2028  }
2029  else
2030  {
2031  ostringstream os;
2032  os << " Doppler shift: " << a_doppler << " Hz\n";
2033  out3 << os.str();
2034 
2035  // Get original lookup table frequency grid.
2036  const Vector& f_grid_original = abs_lookup.GetFgrid();
2037  const Index n_f_grid = f_grid_original.nelem();
2038 
2039  // Apply f_index, if necessary.
2040  Index f_start, f_extent;
2041  if ( f_index < 0 )
2042  {
2043  // This means we have extracted for all frequencies.
2044 
2045  f_start = 0;
2046  f_extent = n_f_grid;
2047  }
2048  else
2049  {
2050  // This means we have extracted only for one frequency.
2051 
2052  // Check that f_index is inside f_grid:
2053  // (Only an assert here, since abs_lookup.Extract(), which
2054  // we have called above, does exactly the same but gives a
2055  // runtime error.)
2056  assert ( f_index < n_f_grid );
2057 
2058  f_start = f_index;
2059  f_extent = 1;
2060  }
2061  const Range f_range(f_start,f_extent);
2062  ConstVectorView f_grid_original_view = f_grid_original[f_range];
2063 
2064  // Get shifted frequency grid.
2065  Vector f_shifted = f_grid_original_view;
2066  f_shifted -= a_doppler;
2067 
2068  // Check that the shifted grid is within extpolfac of the original grid.
2069  chk_interpolation_grids("Absorption from original frequency grid "
2070  "to Doppler-shifted frequency grid",
2071  f_grid_original_view,
2072  f_shifted,
2073  1,
2074  extpolfac );
2075 
2076  // Grid positions.
2077  ArrayOfGridPos gp(f_shifted.nelem());
2078  gridpos(gp,f_grid_original_view,f_shifted,extpolfac);
2079 
2080  // Weights.
2081  Matrix itw(gp.nelem(),2);
2082  interpweights(itw,gp);
2083 
2084  // Do interpolation.
2085  Vector abs_interpolated(abs_scalar_gas.nrows());
2086  // The vector temporarily holds interpolated absorption for each gas species.
2087  for (Index i=0; i<abs_scalar_gas.ncols(); ++i)
2088  {
2089  interp(abs_interpolated,
2090  itw,
2091  abs_scalar_gas(Range(joker),i),
2092  gp);
2093  // Copy interpolated absorption to abs_scalar_gas.
2094  abs_scalar_gas(Range(joker),i) = abs_interpolated;
2095  }
2096 
2097  }
2098 }
2099 
2100 
2101 /* Workspace method: Doxygen documentation will be auto-generated */
2103  // WS Output:
2104  Tensor5& asg_field,
2105  // WS Input:
2106  const Agenda& sga_agenda,
2107  const Index& f_index,
2108  const Vector& f_grid,
2109  const Index& atmosphere_dim,
2110  const Vector& p_grid,
2111  const Vector& lat_grid,
2112  const Vector& lon_grid,
2113  const Tensor3& t_field,
2114  const Tensor4& vmr_field,
2115  // WS Generic Input:
2116  const Vector& doppler,
2117  const Verbosity& verbosity)
2118 {
2119  CREATE_OUT2
2120  CREATE_OUT3
2121 
2122  Matrix asg;
2123  Vector a_vmr_list;
2124 
2125  // Get the number of species from the leading dimension of vmr_field:
2126  const Index n_species = vmr_field.nbooks();
2127 
2128  // Number of frequencies:
2129  const Index n_frequencies = f_grid.nelem();
2130 
2131  // Number of pressure levels:
2132  const Index n_pressures = p_grid.nelem();
2133 
2134  // Number of latitude grid points (must be at least one):
2135  const Index n_latitudes = max( Index(1), lat_grid.nelem() );
2136 
2137  // Number of longitude grid points (must be at least one):
2138  const Index n_longitudes = max( Index(1), lon_grid.nelem() );
2139 
2140  // Check grids:
2141  chk_atm_grids( atmosphere_dim,
2142  p_grid,
2143  lat_grid,
2144  lon_grid );
2145 
2146  // Check if t_field is ok:
2147  chk_atm_field( "t_field",
2148  t_field,
2149  atmosphere_dim,
2150  p_grid,
2151  lat_grid,
2152  lon_grid );
2153 
2154  // Check if vmr_field is ok.
2155  // (Actually, we are not checking the first dimension, since
2156  // n_species has been set from this.)
2157  chk_atm_field( "vmr_field",
2158  vmr_field,
2159  atmosphere_dim,
2160  n_species,
2161  p_grid,
2162  lat_grid,
2163  lon_grid );
2164 
2165  // Check that doppler is empty or matches p_grid
2166  if (0!=doppler.nelem() && p_grid.nelem()!=doppler.nelem())
2167  {
2168  ostringstream os;
2169  os << "Variable doppler must either be empty, or match the dimension of "
2170  << "p_grid.";
2171  throw runtime_error( os.str() );
2172  }
2173 
2174  // We also set the start and extent for the frequency loop.
2175  Index f_extent;
2176 
2177  if ( f_index < 0 )
2178  {
2179  // This means we should extract for all frequencies.
2180 
2181  f_extent = n_frequencies;
2182  }
2183  else
2184  {
2185  // This means we should extract only for one frequency.
2186 
2187  // Make sure that f_index is inside f_grid:
2188  if ( f_index >= n_frequencies )
2189  {
2190  ostringstream os;
2191  os << "The frequency index f_index points to a frequency outside"
2192  << "the frequency grid. (f_index = " << f_index
2193  << ", n_frequencies = " << n_frequencies << ")";
2194  throw runtime_error( os.str() );
2195  }
2196 
2197  f_extent = 1;
2198  }
2199 
2200  // Resize output field.
2201  // The dimension in lat and lon must be at least one, even if these
2202  // grids are empty.
2203  out2 << " Creating field with dimensions:\n"
2204  << " " << n_species << " gas species,\n"
2205  << " " << f_extent << " frequencies,\n"
2206  << " " << n_pressures << " pressures,\n"
2207  << " " << n_latitudes << " latitudes,\n"
2208  << " " << n_longitudes << " longitudes.\n";
2209 
2210  asg_field.resize( n_species,
2211  f_extent,
2212  n_pressures,
2213  n_latitudes,
2214  n_longitudes );
2215 
2216 
2217  // We have to make a local copy of the Workspace and the agendas because
2218  // only non-reference types can be declared firstprivate in OpenMP
2219  Workspace l_ws (ws);
2220  Agenda l_sga_agenda (sga_agenda);
2221 
2222 
2223  // Now we have to loop all points in the atmosphere:
2224 /*#pragma omp parallel for \
2225  if(!arts_omp_in_parallel() && n_pressures>=arts_omp_get_max_threads()) \
2226  default(none) \
2227  shared(out3, joker, f_extent, p_grid, t_field, vmr_field, f_index, \
2228  asg_field) \
2229  firstprivate(l_ws, l_sga_agenda) \
2230  private(asg, a_vmr_list) */
2231 #pragma omp parallel for \
2232  if(!arts_omp_in_parallel() && n_pressures>=arts_omp_get_max_threads()) \
2233  firstprivate(l_ws, l_sga_agenda) \
2234  private(asg, a_vmr_list)
2235  for ( Index ipr=0; ipr<n_pressures; ++ipr ) // Pressure: ipr
2236  {
2237  // The try block here is necessary to correctly handle
2238  // exceptions inside the parallel region.
2239  try
2240  {
2241  Numeric a_pressure = p_grid[ipr];
2242 
2243  Numeric a_doppler = 0;
2244  if (0!=doppler.nelem()) a_doppler = doppler[ipr];
2245 
2246  {
2247  ostringstream os;
2248  os << " p_grid[" << ipr << "] = " << a_pressure << "\n";
2249  out3 << os.str();
2250  }
2251 
2252  for ( Index ila=0; ila<n_latitudes; ++ila ) // Latitude: ila
2253  for ( Index ilo=0; ilo<n_longitudes; ++ilo ) // Longitude: ilo
2254  {
2255  Numeric a_temperature = t_field( ipr, ila, ilo );
2256  a_vmr_list = vmr_field( Range(joker),
2257  ipr, ila, ilo );
2258 
2259  // Execute agenda to calculate local absorption.
2260  // Agenda input: f_index, a_pressure, a_temperature, a_vmr_list
2261  // Agenda output: asg
2263  asg,
2264  f_index, a_doppler, a_pressure,
2265  a_temperature, a_vmr_list,
2266  l_sga_agenda);
2267 
2268  // Verify, that the number of species in asg is
2269  // constistent with vmr_field:
2270  if ( n_species != asg.ncols() )
2271  {
2272  ostringstream os;
2273  os << "The number of gas species in vmr_field is "
2274  << n_species << ",\n"
2275  << "but the number of species returned by the agenda is "
2276  << asg.ncols() << ".";
2277  throw runtime_error( os.str() );
2278  }
2279 
2280  // Verify, that the number of frequencies in asg is
2281  // constistent with f_extent:
2282  if ( f_extent != asg.nrows() )
2283  {
2284  ostringstream os;
2285  os << "The number of frequencies desired is "
2286  << n_frequencies << ",\n"
2287  << "but the number of frequencies returned by the agenda is "
2288  << asg.nrows() << ".";
2289  throw runtime_error( os.str() );
2290  }
2291 
2292  // Store the result in output field.
2293  // We have to transpose asg, because the dimensions of the
2294  // two variables are:
2295  // asg_field: [ abs_species, f_grid, p_grid, lat_grid, lon_grid]
2296  // asg: [ f_grid, abs_species ]
2297  asg_field( Range(joker),
2298  Range(joker),
2299  ipr, ila, ilo ) = transpose( asg );
2300 
2301  }
2302  }
2303  catch (runtime_error e)
2304  {
2305  CREATE_OUT0
2306  exit_or_rethrow(e.what(), out0);
2307  }
2308  }
2309 }
2310 
2311 
2312 /* Workspace method: Doxygen documentation will be auto-generated */
2314  Vector& f_grid,
2315  const GasAbsLookup& abs_lookup,
2316  const Verbosity&)
2317 {
2318  const Vector& lookup_f_grid = abs_lookup.GetFgrid();
2319  f_grid.resize(lookup_f_grid.nelem());
2320  f_grid = lookup_f_grid;
2321 }
2322 
2323 
2324 /* Workspace method: Doxygen documentation will be auto-generated */
2326  const GasAbsLookup& abs_lookup,
2327  const Verbosity&)
2328 {
2329  const Vector& lookup_p_grid = abs_lookup.GetPgrid();
2330  p_grid.resize(lookup_p_grid.nelem());
2331  p_grid = lookup_p_grid;
2332 }
2333 
2334 
2336 
2358 Numeric calc_lookup_error(// Parameters for lookup table:
2359  const GasAbsLookup& al,
2360  const Index& abs_p_interp_order,
2361  const Index& abs_t_interp_order,
2362  const Index& abs_nls_interp_order,
2363  const bool ignore_errors,
2364  // Parameters for LBL:
2365  const Vector& abs_n2,
2366  const ArrayOfArrayOfLineRecord& abs_lines_per_species,
2367  const ArrayOfLineshapeSpec& abs_lineshape,
2368  const ArrayOfString& abs_cont_names,
2369  const ArrayOfString& abs_cont_models,
2370  const ArrayOfVector& abs_cont_parameters,
2371  // Parameters for both:
2372  const Numeric& local_p,
2373  const Numeric& local_t,
2374  const Vector& local_vmrs,
2375  const Verbosity& verbosity)
2376 {
2377  // Allocate some matrices. I also tried allocating these (and the
2378  // vectors below) outside, but there was no significant speed
2379  // advantage. (I guess the LBL calculation is expensive enough to
2380  // make the extra time of allocation here insignificant.)
2381  Matrix sga_tab; // Absorption, dimension [n_f_grid,n_species]:
2382  Matrix sga_lbl;
2383 
2384  // Do lookup table first:
2385 
2386  try
2387  {
2388  // Absorption, dimension [n_f_grid,n_species]:
2389  // Output variable: sga_tab
2390  al.Extract(sga_tab,
2391  abs_p_interp_order,
2392  abs_t_interp_order,
2393  abs_nls_interp_order,
2394  -1,
2395  local_p,
2396  local_t,
2397  local_vmrs );
2398  }
2399  catch (runtime_error x)
2400  {
2401  // If ignore_errors is set to true, then we mark this case for
2402  // skipping, and ignore the exceptions.
2403  // Otherwise, we re-throw the exception.
2404  if (ignore_errors)
2405  return -1;
2406  else
2407  throw runtime_error(x.what());
2408  }
2409 
2410 
2411  // Get number of frequencies. (We cannot do this earlier, since we
2412  // get it from the output of al.Extract.)
2413  const Index n_f = sga_tab.nrows();
2414 
2415  // Allocate some vectors with this dimension:
2416  Vector abs_tab(n_f);
2417  Vector abs_lbl(n_f);
2418  Vector abs_rel_diff(n_f);
2419 
2420  // Sum up for all species, to get total absorption:
2421  for (Index i=0; i<n_f; ++i)
2422  abs_tab[i] = sga_tab(i,joker).sum();
2423 
2424 
2425  // Now get absorption line-by-line.
2426 
2427  abs_scalar_gasCalcLBL( sga_lbl,
2428  al.f_grid,
2429  al.species,
2430  abs_n2,
2431  abs_lines_per_species,
2432  abs_lineshape,
2433  abs_cont_names,
2434  abs_cont_models,
2435  abs_cont_parameters,
2436  -1,
2437  local_p,
2438  local_t,
2439  local_vmrs,
2440  0,
2441  verbosity);
2442  // Last argument above is the Doppler shift (usually
2443  // rte_doppler). Should be zero in this case.
2444 
2445  // Sum up for all species, to get total absorption:
2446  for (Index i=0; i<n_f; ++i)
2447  abs_lbl[i] = sga_lbl(i,joker).sum();
2448 
2449 
2450  // Ok. What we have to compare is abs_tab and abs_lbl.
2451 
2452  assert(abs_tab.nelem()==n_f);
2453  assert(abs_lbl.nelem()==n_f);
2454  assert(abs_rel_diff.nelem()==n_f);
2455  for (Index i=0; i<n_f; ++i)
2456  {
2457  // Absolute value of relative difference in percent:
2458  abs_rel_diff[i] = fabs( (abs_tab[i] - abs_lbl[i]) / abs_lbl[i] * 100);
2459  }
2460 
2461  // Maximum of this:
2462  Numeric max_abs_rel_diff = max(abs_rel_diff);
2463 
2464  // cout << "ma " << max_abs_rel_diff << "\n";
2465 
2466  return max_abs_rel_diff;
2467 
2468 }
2469 
2470 
2471 /* Workspace method: Doxygen documentation will be auto-generated */
2472 void abs_lookupTestAccuracy(// WS Input:
2473  const GasAbsLookup& abs_lookup,
2474  const Index& abs_lookup_is_adapted,
2475  const Index& abs_p_interp_order,
2476  const Index& abs_t_interp_order,
2477  const Index& abs_nls_interp_order,
2478  const Vector& abs_n2,
2479  const ArrayOfArrayOfLineRecord& abs_lines_per_species,
2480  const ArrayOfLineshapeSpec& abs_lineshape,
2481  const ArrayOfString& abs_cont_names,
2482  const ArrayOfString& abs_cont_models,
2483  const ArrayOfVector& abs_cont_parameters,
2484  const Verbosity& verbosity)
2485 {
2486  CREATE_OUT2
2487 
2488  const GasAbsLookup& al = abs_lookup;
2489 
2490  // Check if the table has been adapted:
2491  if ( 1!=abs_lookup_is_adapted )
2492  throw runtime_error("Gas absorption lookup table must be adapted,\n"
2493  "use method abs_lookupAdapt.");
2494 
2495 
2496  // Some important sizes:
2497  const Index n_nls = al.nonlinear_species.nelem();
2498  const Index n_species = al.species.nelem();
2499  // const Index n_f = al.f_grid.nelem();
2500  const Index n_p = al.log_p_grid.nelem();
2501 
2502  if ( n_nls <= 0 )
2503  {
2504  ostringstream os;
2505  os << "This function currently works only with lookup tables\n"
2506  << "containing nonlinear species.";
2507  throw runtime_error( os.str() );
2508  }
2509 
2510  // If there are nonlinear species, then at least one species must be
2511  // H2O. We will use that to perturb in the case of nonlinear
2512  // species.
2513  Index h2o_index = -1;
2514  if (n_nls>0)
2515  {
2516  h2o_index = find_first_species_tg( al.species,
2518 
2519  // This is a runtime error, even though it would be more logical
2520  // for it to be an assertion, since it is an internal check on
2521  // the table. The reason is that it is somewhat awkward to check
2522  // for this in other places.
2523  if ( h2o_index == -1 )
2524  {
2525  ostringstream os;
2526  os << "With nonlinear species, at least one species must be a H2O species.";
2527  throw runtime_error( os.str() );
2528  }
2529  }
2530 
2531 
2532  // Check temperature interpolation
2533 
2534  Vector inbet_t_pert(al.t_pert.nelem()-1);
2535  for (Index i=0; i<inbet_t_pert.nelem(); ++i)
2536  inbet_t_pert[i] = (al.t_pert[i]+al.t_pert[i+1])/2.0;
2537 
2538  // To store the temperature error, which we define as the maximum of
2539  // the absolute value of the relative difference between LBL and
2540  // lookup table, in percent.
2541  Numeric err_t = -999;
2542 
2543 /*#pragma omp parallel for \
2544  if(!arts_omp_in_parallel()) \
2545  default(none) \
2546  shared(inbet_t_pert, joker, h2o_index, err_t, al, abs_cont_parameters, \
2547  abs_cont_models, abs_cont_names, abs_lineshape, \
2548  abs_lines_per_species, abs_n2, abs_nls_interp_order, \
2549  abs_t_interp_order, abs_p_interp_order) */
2550 #pragma omp parallel for \
2551  if(!arts_omp_in_parallel())
2552  for (Index pi=0; pi<n_p; ++pi)
2553  for (Index ti=0; ti<inbet_t_pert.nelem(); ++ti)
2554  {
2555  // Find local conditions:
2556 
2557  // Pressure:
2558  Numeric local_p = al.p_grid[pi];
2559 
2560  // Temperature:
2561  Numeric local_t = al.t_ref[pi] + inbet_t_pert[ti];
2562 
2563  // VMRs:
2564  Vector local_vmrs = al.vmrs_ref(joker, pi);
2565 
2566  // Watch out, the table probably does not have an absorption
2567  // value for exactly the reference H2O profile. We multiply
2568  // with the first perturbation.
2569  local_vmrs[h2o_index] *= al.nls_pert[0];
2570 
2571  Numeric max_abs_rel_diff =
2572  calc_lookup_error(// Parameters for lookup table:
2573  al,
2574  abs_p_interp_order,
2575  abs_t_interp_order,
2576  abs_nls_interp_order,
2577  true, // ignore errors
2578  // Parameters for LBL:
2579  abs_n2,
2580  abs_lines_per_species,
2581  abs_lineshape,
2582  abs_cont_names,
2583  abs_cont_models,
2584  abs_cont_parameters,
2585  // Parameters for both:
2586  local_p,
2587  local_t,
2588  local_vmrs,
2589  verbosity);
2590 
2591  // cout << "ma " << max_abs_rel_diff << "\n";
2592 
2593  //Critical directive here is necessary, because all threads
2594  //access the same variable.
2595 #pragma omp critical
2596  {
2597  if (max_abs_rel_diff > err_t)
2598  err_t = max_abs_rel_diff;
2599  }
2600 
2601  } // end parallel for loop
2602 
2603 
2604 
2605  // Check H2O interpolation
2606 
2607  Vector inbet_nls_pert(al.nls_pert.nelem()-1);
2608  for (Index i=0; i<inbet_nls_pert.nelem(); ++i)
2609  inbet_nls_pert[i] = (al.nls_pert[i]+al.nls_pert[i+1])/2.0;
2610 
2611  // To store the H2O error, which we define as the maximum of
2612  // the absolute value of the relative difference between LBL and
2613  // lookup table, in percent.
2614  Numeric err_nls = -999;
2615 
2616 /*#pragma omp parallel for \
2617  if(!arts_omp_in_parallel()) \
2618  default(none) \
2619  shared(inbet_nls_pert, joker, h2o_index, err_nls, al, \
2620  abs_cont_parameters, abs_cont_models, abs_cont_names, \
2621  abs_lineshape, abs_lines_per_species, abs_n2, \
2622  abs_nls_interp_order, abs_t_interp_order, abs_p_interp_order) */
2623 #pragma omp parallel for \
2624  if(!arts_omp_in_parallel())
2625  for (Index pi=0; pi<n_p; ++pi)
2626  for (Index ni=0; ni<inbet_nls_pert.nelem(); ++ni)
2627  {
2628  // Find local conditions:
2629 
2630  // Pressure:
2631  Numeric local_p = al.p_grid[pi];
2632 
2633  // Temperature:
2634 
2635  // Watch out, the table probably does not have an absorption
2636  // value for exactly the reference temperature. We add
2637  // the first perturbation.
2638 
2639  Numeric local_t = al.t_ref[pi] + al.t_pert[0];
2640 
2641  // VMRs:
2642  Vector local_vmrs = al.vmrs_ref(joker, pi);
2643 
2644  // Now we have to modify the H2O VMR according to nls_pert:
2645  local_vmrs[h2o_index] *= inbet_nls_pert[ni];
2646 
2647  Numeric max_abs_rel_diff =
2648  calc_lookup_error(// Parameters for lookup table:
2649  al,
2650  abs_p_interp_order,
2651  abs_t_interp_order,
2652  abs_nls_interp_order,
2653  true, // ignore errors
2654  // Parameters for LBL:
2655  abs_n2,
2656  abs_lines_per_species,
2657  abs_lineshape,
2658  abs_cont_names,
2659  abs_cont_models,
2660  abs_cont_parameters,
2661  // Parameters for both:
2662  local_p,
2663  local_t,
2664  local_vmrs,
2665  verbosity);
2666 
2667  //Critical directive here is necessary, because all threads
2668  //access the same variable.
2669 #pragma omp critical
2670  {
2671  if (max_abs_rel_diff > err_nls)
2672  err_nls = max_abs_rel_diff;
2673  }
2674 
2675  } // end parallel for loop
2676 
2677 
2678  // Check pressure interpolation
2679 
2680  // IMPORTANT: This does not test the pure pressure interpolation,
2681  // unless we have constant reference profiles for T and
2682  // H2O. Otherwise we have T and H2O interpolation mixed in.
2683 
2684  Vector inbet_p_grid(n_p-1);
2685  Vector inbet_t_ref(n_p-1);
2686  Matrix inbet_vmrs_ref(n_species, n_p-1);
2687  for (Index i=0; i<inbet_p_grid.nelem(); ++i)
2688  {
2689  inbet_p_grid[i] = exp((al.log_p_grid[i]+al.log_p_grid[i+1])/2.0);
2690  inbet_t_ref[i] = (al.t_ref[i]+al.t_ref[i+1])/2.0;
2691  for (Index j=0; j<n_species; ++j)
2692  inbet_vmrs_ref(j,i) = (al.vmrs_ref(j,i)+al.vmrs_ref(j,i+1))/2.0;
2693  }
2694 
2695  // To store the interpolation error, which we define as the maximum of
2696  // the absolute value of the relative difference between LBL and
2697  // lookup table, in percent.
2698  Numeric err_p = -999;
2699 
2700 /*#pragma omp parallel for \
2701  if(!arts_omp_in_parallel()) \
2702  default(none) \
2703  shared(inbet_p_grid, inbet_t_ref, joker, inbet_vmrs_ref, h2o_index, \
2704  err_p, al, abs_cont_parameters, abs_cont_models, \
2705  abs_cont_names, abs_lineshape, abs_lines_per_species, abs_n2, \
2706  abs_nls_interp_order, abs_t_interp_order, abs_p_interp_order) */
2707 #pragma omp parallel for \
2708  if(!arts_omp_in_parallel())
2709  for (Index pi=0; pi<n_p-1; ++pi)
2710  {
2711  // Find local conditions:
2712 
2713  // Pressure:
2714  Numeric local_p = inbet_p_grid[pi];
2715 
2716  // Temperature:
2717 
2718  // Watch out, the table probably does not have an absorption
2719  // value for exactly the reference temperature. We add
2720  // the first perturbation.
2721 
2722  Numeric local_t = inbet_t_ref[pi] + al.t_pert[0];
2723 
2724  // VMRs:
2725  Vector local_vmrs = inbet_vmrs_ref(joker, pi);
2726 
2727  // Watch out, the table probably does not have an absorption
2728  // value for exactly the reference H2O profile. We multiply
2729  // with the first perturbation.
2730  local_vmrs[h2o_index] *= al.nls_pert[0];
2731 
2732  Numeric max_abs_rel_diff =
2733  calc_lookup_error(// Parameters for lookup table:
2734  al,
2735  abs_p_interp_order,
2736  abs_t_interp_order,
2737  abs_nls_interp_order,
2738  true, // ignore errors
2739  // Parameters for LBL:
2740  abs_n2,
2741  abs_lines_per_species,
2742  abs_lineshape,
2743  abs_cont_names,
2744  abs_cont_models,
2745  abs_cont_parameters,
2746  // Parameters for both:
2747  local_p,
2748  local_t,
2749  local_vmrs,
2750  verbosity);
2751 
2752  //Critical directive here is necessary, because all threads
2753  //access the same variable.
2754 #pragma omp critical
2755  {
2756  if (max_abs_rel_diff > err_p)
2757  err_p = max_abs_rel_diff;
2758  }
2759  }
2760 
2761 
2762  // Check total error
2763 
2764  // To store the interpolation error, which we define as the maximum of
2765  // the absolute value of the relative difference between LBL and
2766  // lookup table, in percent.
2767  Numeric err_tot = -999;
2768 
2769 /*#pragma omp parallel for \
2770  if(!arts_omp_in_parallel()) \
2771  default(none) \
2772  shared(inbet_t_pert, inbet_nls_pert, inbet_p_grid, \
2773  inbet_t_ref, joker, inbet_vmrs_ref, h2o_index, err_tot, \
2774  abs_cont_parameters, abs_cont_models, abs_cont_names, \
2775  abs_lineshape, abs_lines_per_species, abs_n2, \
2776  abs_nls_interp_order, abs_t_interp_order, abs_p_interp_order, \
2777  al) */
2778 #pragma omp parallel for \
2779  if(!arts_omp_in_parallel())
2780  for (Index pi=0; pi<n_p-1; ++pi)
2781  for (Index ti=0; ti<inbet_t_pert.nelem(); ++ti)
2782  for (Index ni=0; ni<inbet_nls_pert.nelem(); ++ni)
2783  {
2784  // Find local conditions:
2785 
2786  // Pressure:
2787  Numeric local_p = inbet_p_grid[pi];
2788 
2789  // Temperature:
2790  Numeric local_t = inbet_t_ref[pi] + inbet_t_pert[ti];
2791 
2792  // VMRs:
2793  Vector local_vmrs = inbet_vmrs_ref(joker, pi);
2794 
2795  // Multiply with perturbation.
2796  local_vmrs[h2o_index] *= inbet_nls_pert[ni];
2797 
2798  Numeric max_abs_rel_diff =
2799  calc_lookup_error(// Parameters for lookup table:
2800  al,
2801  abs_p_interp_order,
2802  abs_t_interp_order,
2803  abs_nls_interp_order,
2804  true, // ignore errors
2805  // Parameters for LBL:
2806  abs_n2,
2807  abs_lines_per_species,
2808  abs_lineshape,
2809  abs_cont_names,
2810  abs_cont_models,
2811  abs_cont_parameters,
2812  // Parameters for both:
2813  local_p,
2814  local_t,
2815  local_vmrs,
2816  verbosity);
2817 
2818  //Critical directive here is necessary, because all threads
2819  //access the same variable.
2820 #pragma omp critical
2821  {
2822  if (max_abs_rel_diff > err_tot)
2823  {
2824  err_tot = max_abs_rel_diff;
2825 
2826 // cout << "New max error: pi, ti, ni, err_tot:\n"
2827 // << pi << ", " << ti << ", " << ni << ", " << err_tot << "\n";
2828  }
2829  }
2830  }
2831 
2832 
2833  out2 << " Max. of absolute value of relative error in percent:\n"
2834  << " Note: Unless you have constant reference profiles, the\n"
2835  << " pressure interpolation error will have other errors mixed in.\n"
2836  << " Temperature interpolation: " << err_t << "%\n"
2837  << " H2O (NLS) interpolation: " << err_nls << "%\n"
2838  << " Pressure interpolation: " << err_p << "%\n"
2839  << " Total error: " << err_tot << "%\n";
2840 
2841  // Check pressure interpolation
2842 
2843 // assert(p_grid.nelem()==log_p_grid.nelem()); // Make sure that log_p_grid is initialized.
2844 // Vector inbet_log_p_grid(log_p_grid.nelem()-1)
2845 // for (Index i=0; i<log_p_grid.nelem()-1; ++i)
2846 // {
2847 // inbet_log_p_grid[i] = (log_p_grid[i]+log_p_grid[i+1])/2.0;
2848 // }
2849 
2850 // for (Index pi=0; pi<inbet_log_p_grid.nelem(); ++pi)
2851 // {
2852 // for (Index pt=0; pt<)
2853 // }
2854 
2855 }
2856 
2857 /* Workspace method: Doxygen documentation will be auto-generated */
2858 void abs_lookupTestAccMC(// WS Input:
2859  const GasAbsLookup& abs_lookup,
2860  const Index& abs_lookup_is_adapted,
2861  const Index& abs_p_interp_order,
2862  const Index& abs_t_interp_order,
2863  const Index& abs_nls_interp_order,
2864  const Vector& abs_n2,
2865  const ArrayOfArrayOfLineRecord& abs_lines_per_species,
2866  const ArrayOfLineshapeSpec& abs_lineshape,
2867  const ArrayOfString& abs_cont_names,
2868  const ArrayOfString& abs_cont_models,
2869  const ArrayOfVector& abs_cont_parameters,
2870  const Index& mc_seed,
2871  const Verbosity& verbosity)
2872 {
2873  CREATE_OUT2
2874  CREATE_OUT3
2875 
2876  const GasAbsLookup& al = abs_lookup;
2877 
2878  // Check if the table has been adapted:
2879  if ( 1!=abs_lookup_is_adapted )
2880  throw runtime_error("Gas absorption lookup table must be adapted,\n"
2881  "use method abs_lookupAdapt.");
2882 
2883 
2884  // Some important sizes:
2885  const Index n_nls = al.nonlinear_species.nelem();
2886  const Index n_species = al.species.nelem();
2887 
2888  if ( n_nls <= 0 )
2889  {
2890  ostringstream os;
2891  os << "This function currently works only with lookup tables\n"
2892  << "containing nonlinear species.";
2893  throw runtime_error( os.str() );
2894  }
2895 
2896  // If there are nonlinear species, then at least one species must be
2897  // H2O. We will use that to perturb in the case of nonlinear
2898  // species.
2899  Index h2o_index = -1;
2900  if (n_nls>0)
2901  {
2902  h2o_index = find_first_species_tg( al.species,
2904 
2905  // This is a runtime error, even though it would be more logical
2906  // for it to be an assertion, since it is an internal check on
2907  // the table. The reason is that it is somewhat awkward to check
2908  // for this in other places.
2909  if ( h2o_index == -1 )
2910  {
2911  ostringstream os;
2912  os << "With nonlinear species, at least one species must be a H2O species.";
2913  throw runtime_error( os.str() );
2914  }
2915  }
2916 
2917  // How many MC cases to run between each convergence check.
2918  // (It is important for parallelization that this is not too small.)
2919  const Index chunksize = 100;
2920 
2921  //Random Number generator:
2922  Rng rng;
2923  rng.seed(mc_seed, verbosity);
2924  // rng.draw() will draw a double from the uniform distribution [0,1).
2925 
2926  // (Log) Pressure range:
2927  const Numeric lp_max = al.log_p_grid[0];
2928  const Numeric lp_min = al.log_p_grid[al.log_p_grid.nelem()-1];
2929 
2930  // T perturbation range (additive):
2931  const Numeric dT_min = al.t_pert[0];
2932  const Numeric dT_max = al.t_pert[al.t_pert.nelem()-1];
2933 
2934  // H2O perturbation range (scaling):
2935  const Numeric dh2o_min = al.nls_pert[0];
2936  const Numeric dh2o_max = al.nls_pert[al.nls_pert.nelem()-1];
2937 
2938  // We are creating all random numbers for the chunk beforehand, to avoid the
2939  // problem that random number generators in different threads would need
2940  // different seeds to produce independent random numbers.
2941  // (I prefer this solution to the one of having the rng inside the threads,
2942  // because it ensures that the result does not depend on the the number of CPUs.)
2943  Vector rand_lp(chunksize);
2944  Vector rand_dT(chunksize);
2945  Vector rand_dh2o(chunksize);
2946 
2947  // Store the errors for one chunk:
2948  Vector max_abs_rel_diff(chunksize);
2949 
2950  // Flag to break our MC calculation loop eventually
2951  bool keep_looping=true;
2952 
2953  // Total mean and standard deviation. (Is updated after each chunk.)
2954  Numeric total_mean;
2955  Numeric total_std;
2956  Index N_chunk = 0;
2957  while (keep_looping)
2958  {
2959  ++N_chunk;
2960 
2961  for (Index i=0; i<chunksize; ++i)
2962  {
2963  // A random pressure, temperature perturbation, and H2O perturbation,
2964  // all with flat PDF between min and max:
2965  rand_lp[i] = rng.draw()*(lp_max-lp_min) + lp_min;
2966  rand_dT[i] = rng.draw()*(dT_max-dT_min) + dT_min;
2967  rand_dh2o[i] = rng.draw()*(dh2o_max-dh2o_min) + dh2o_min;
2968  }
2969 
2970  for (Index i=0; i<chunksize; ++i)
2971  {
2972  // The pressure we work with here:
2973  const Numeric this_lp = rand_lp[i];
2974 
2975  // Now we have to interpolate t_ref and vmrs_ref to this
2976  // pressure, so that we can apply the dT and dh2o perturbations.
2977 
2978  // Pressure grid positions:
2979  ArrayOfGridPosPoly pgp(1);
2980  gridpos_poly(pgp,
2981  al.log_p_grid,
2982  this_lp,
2983  abs_p_interp_order );
2984 
2985  // Pressure interpolation weights:
2986  Vector pitw;
2987  pitw.resize(abs_p_interp_order+1);
2988  interpweights(pitw,pgp[0]);
2989 
2990  // Interpolated temperature:
2991  const Numeric this_t_ref = interp(pitw,
2992  al.t_ref,
2993  pgp[0]);
2994 
2995  // Interpolated VMRs:
2996  Vector these_vmrs(n_species);
2997  for (Index j=0; j<n_species; ++j)
2998  {
2999  these_vmrs[j] = interp(pitw,
3000  al.vmrs_ref(j,Range(joker)),
3001  pgp[0]);
3002  }
3003 
3004  // Now get the actual p, T and H2O values:
3005  const Numeric this_p = exp(this_lp);
3006  const Numeric this_t = this_t_ref + rand_dT[i];
3007  these_vmrs[h2o_index] *= rand_dh2o[i];
3008 
3009  // cout << "p, T, H2O: " << this_p << ", " << this_t << ", " << these_vmrs[h2o_index] << "\n";
3010 
3011  // Get error between table and LBL calculation for these conditions:
3012 
3013  max_abs_rel_diff[i] = calc_lookup_error(// Parameters for lookup table:
3014  al,
3015  abs_p_interp_order,
3016  abs_t_interp_order,
3017  abs_nls_interp_order,
3018  true, // ignore errors
3019  // Parameters for LBL:
3020  abs_n2,
3021  abs_lines_per_species,
3022  abs_lineshape,
3023  abs_cont_names,
3024  abs_cont_models,
3025  abs_cont_parameters,
3026  // Parameters for both:
3027  this_p,
3028  this_t,
3029  these_vmrs,
3030  verbosity);
3031  // cout << "max_abs_rel_diff[" << i << "] = " << max_abs_rel_diff[i] << "\n";
3032 
3033  }
3034 
3035  // Calculate Mean of the last batch.
3036 
3037  // Total number of valid points in the chunk (not counting negative values,
3038  // which result from failed calculations at the edges of the table.)
3039  Index N=0;
3040  // Mean (initially sum of all values):
3041  Numeric mean = 0;
3042  for (Index i=0; i<chunksize; ++i)
3043  {
3044  const Numeric x = max_abs_rel_diff[i];
3045  if (x > 0)
3046  {
3047  ++N;
3048  mean += x;
3049  }
3050  // else
3051  // {
3052  // cout << "Negative value ignored.\n";
3053  // }
3054  }
3055  // Calculate mean by dividing sum by number of valid points:
3056  mean = mean / (Numeric)N;
3057 
3058  // Now calculate standard deviation:
3059 
3060  // Variance (initially sum of squared differences)
3061  Numeric variance = 0;
3062  for (Index i=0; i<chunksize; ++i)
3063  {
3064  const Numeric x = max_abs_rel_diff[i];
3065  if (x > 0)
3066  {
3067  variance += (x - mean) * (x - mean);
3068  }
3069  }
3070  // Divide by N to really calculate variance:
3071  variance = variance / (Numeric)N;
3072 
3073  // cout << "Mean = " << mean << " Std = " << std_dev << "\n";
3074 
3075  if (N_chunk==1)
3076  {
3077  total_mean = mean;
3078  total_std = sqrt(variance);
3079  }
3080  else
3081  {
3082  const Numeric old_mean = total_mean;
3083 
3084  // This formula assimilates the new chunk mean into the total mean:
3085  total_mean = (total_mean*((Numeric)(N_chunk-1)) + mean) / (Numeric)N_chunk;
3086 
3087  // Do the same for the standard deviation.
3088  // First get rid of the square root:
3089  total_std = total_std * total_std;
3090  // Now multiply with old normalisation:
3091  total_std *= (Numeric)(N_chunk-1);
3092  // Now add the new sigma
3093  total_std += variance;
3094  // Divide by the new normalisation:
3095  total_std /= (Numeric)N_chunk;
3096  // And finally take the square root:
3097  total_std = sqrt(total_std);
3098 
3099  // Stop the chunk loop if desired accuracy has been reached.
3100  // We take 1% here, no point in trying to be more accurate!
3101  if (abs(total_mean-old_mean) < total_mean/100) keep_looping = false;
3102  }
3103 
3104  // cout << " Chunk " << N_chunk << ": Mean estimate = " << total_mean
3105  // << " Std estimate = " << total_std << "\n";
3106 
3107  out3 << " Chunk " << N_chunk << ": Mean estimate = " << total_mean
3108  << " Std estimate = " << total_std << "\n";
3109 
3110  } // End of "keep_looping" loop that runs over the chunks
3111 
3112  out2 << " Mean relative error: " << total_mean << "%\n"
3113  << " Standard deviation: " << total_std << "%\n";
3114 
3115 }
Matrix
The Matrix class.
Definition: matpackI.h:767
GasAbsLookup::GetPgrid
const Vector & GetPgrid() const
Definition: gas_abs_lookup.cc:1072
transform
void transform(VectorView y, double(&my_func)(double), ConstVectorView x)
A generic transform function for vectors, which can be used to implement mathematical functions opera...
Definition: matpackI.cc:1728
species_index_from_species_name
Index species_index_from_species_name(String name)
Return species index for given species name.
Definition: abs_species_tags.cc:452
Tensor4::resize
void resize(Index b, Index p, Index r, Index c)
Resize function.
Definition: matpackIV.cc:1404
abs_xsec_per_speciesAddLines
void abs_xsec_per_speciesAddLines(ArrayOfMatrix &abs_xsec_per_species, const ArrayOfArrayOfSpeciesTag &tgs, const Vector &f_grid, const Vector &abs_p, const Vector &abs_t, const Vector &abs_h2o, const Matrix &abs_vmrs, const ArrayOfArrayOfLineRecord &abs_lines_per_species, const ArrayOfLineshapeSpec &abs_lineshape, const Verbosity &verbosity)
WORKSPACE METHOD: abs_xsec_per_speciesAddLines.
Definition: m_abs.cc:1484
GasAbsLookup::GetFgrid
const Vector & GetFgrid() const
Definition: gas_abs_lookup.cc:1066
choose_abs_t_pert
void choose_abs_t_pert(Vector &abs_t_pert, ConstVectorView abs_t, ConstVectorView tmin, ConstVectorView tmax, const Numeric &step, const Index &p_interp_order, const Index &t_interp_order, const Verbosity &verbosity)
Chose the temperature perturbations abs_t_pert.
Definition: m_abs_lookup.cc:665
auto_md.h
GasAbsLookup::nonlinear_species
ArrayOfIndex nonlinear_species
The species tags with non-linear treatment.
Definition: gas_abs_lookup.h:167
GFIELD4_P_GRID
const Index GFIELD4_P_GRID
abs_lookupTestAccMC
void abs_lookupTestAccMC(const GasAbsLookup &abs_lookup, const Index &abs_lookup_is_adapted, const Index &abs_p_interp_order, const Index &abs_t_interp_order, const Index &abs_nls_interp_order, const Vector &abs_n2, const ArrayOfArrayOfLineRecord &abs_lines_per_species, const ArrayOfLineshapeSpec &abs_lineshape, const ArrayOfString &abs_cont_names, const ArrayOfString &abs_cont_models, const ArrayOfVector &abs_cont_parameters, const Index &mc_seed, const Verbosity &verbosity)
WORKSPACE METHOD: abs_lookupTestAccMC.
Definition: m_abs_lookup.cc:2858
array_species_tag_from_string
void array_species_tag_from_string(ArrayOfSpeciesTag &tags, const String &names)
Converts a String to ArrayOfSpeciesTag.
Definition: abs_species_tags.cc:509
gridpos
void gridpos(ArrayOfGridPos &gp, ConstVectorView old_grid, ConstVectorView new_grid, const Numeric &extpolfac)
Set up a grid position Array.
Definition: interpolation.cc:167
abs_scalar_gas_agendaExecute
void abs_scalar_gas_agendaExecute(Workspace &ws, Matrix &abs_scalar_gas, const Index f_index, const Numeric rte_doppler, const Numeric rte_pressure, const Numeric rte_temperature, const Vector &rte_vmr_list, const Agenda &input_agenda)
Definition: auto_md.cc:9032
Tensor3
The Tensor3 class.
Definition: matpackIII.h:340
abs_lookupSetupBatch
void abs_lookupSetupBatch(Vector &abs_p, Vector &abs_t, Vector &abs_t_pert, Matrix &abs_vmrs, ArrayOfArrayOfSpeciesTag &abs_nls, Vector &abs_nls_pert, const ArrayOfArrayOfSpeciesTag &abs_species, const ArrayOfGriddedField4 &batch_fields, const Index &abs_p_interp_order, const Index &abs_t_interp_order, const Index &abs_nls_interp_order, const Numeric &p_step10, const Numeric &t_step, const Numeric &h2o_step, const Vector &extremes, const Verbosity &verbosity)
WORKSPACE METHOD: abs_lookupSetupBatch.
Definition: m_abs_lookup.cc:1141
abs_speciesInit
void abs_speciesInit(ArrayOfArrayOfSpeciesTag &abs_species, const Verbosity &)
WORKSPACE METHOD: abs_speciesInit.
Definition: m_abs_lookup.cc:1935
spec
void spec(Array< SpeciesRecord >::iterator &is, Array< IsotopeRecord >::iterator &ii, String name)
Define partition function coefficients lookup data.
Definition: partition_function_data.cc:693
joker
const Joker joker
p_gridFromGasAbsLookup
void p_gridFromGasAbsLookup(Vector &p_grid, const GasAbsLookup &abs_lookup, const Verbosity &)
WORKSPACE METHOD: p_gridFromGasAbsLookup.
Definition: m_abs_lookup.cc:2325
f_gridFromGasAbsLookup
void f_gridFromGasAbsLookup(Vector &f_grid, const GasAbsLookup &abs_lookup, const Verbosity &)
WORKSPACE METHOD: f_gridFromGasAbsLookup.
Definition: m_abs_lookup.cc:2313
interp
Numeric interp(ConstVectorView itw, ConstVectorView a, const GridPos &tc)
Red 1D Interpolate.
Definition: interpolation.cc:1000
abs_speciesAdd
void abs_speciesAdd(ArrayOfArrayOfSpeciesTag &abs_species, const ArrayOfString &names, const Verbosity &verbosity)
WORKSPACE METHOD: abs_speciesAdd.
Definition: m_abs_lookup.cc:1852
choose_abs_nls
void choose_abs_nls(ArrayOfArrayOfSpeciesTag &abs_nls, const ArrayOfArrayOfSpeciesTag &abs_species, const Verbosity &verbosity)
Choose species for abs_nls.
Definition: m_abs_lookup.cc:607
Rng::seed
void seed(unsigned long int n, const Verbosity &verbosity)
Definition: rng.cc:72
Vector::resize
void resize(Index n)
Resize function.
Definition: matpackI.cc:771
exit_or_rethrow
void exit_or_rethrow(const String &m, ArtsOut &out)
Exit ARTS or re-throw error.
Definition: arts.cc:98
abs_lookupInit
void abs_lookupInit(GasAbsLookup &, const Verbosity &verbosity)
WORKSPACE METHOD: abs_lookupInit.
Definition: m_abs_lookup.cc:49
ConstMatrixView::nrows
Index nrows() const
Returns the number of rows.
Definition: matpackI.cc:796
get_tag_group_name
String get_tag_group_name(const ArrayOfSpeciesTag &tg)
Return the name of a tag group as a string.
Definition: abs_species_tags.cc:314
CREATE_OUT2
#define CREATE_OUT2
Definition: messages.h:207
temp
#define temp
Definition: continua.cc:13409
Tensor4
The Tensor4 class.
Definition: matpackIV.h:375
GFIELD4_FIELD_NAMES
const Index GFIELD4_FIELD_NAMES
CREATE_OUT1
#define CREATE_OUT1
Definition: messages.h:206
Agenda
The Agenda class.
Definition: agenda_class.h:44
arts_omp_get_nested
int arts_omp_get_nested()
Wrapper for omp_get_nested.
Definition: arts_omp.cc:102
GasAbsLookup
An absorption lookup table.
Definition: gas_abs_lookup.h:44
dx
#define dx
Definition: continua.cc:14561
abs_lookupSetupWide
void abs_lookupSetupWide(Vector &abs_p, Vector &abs_t, Vector &abs_t_pert, Matrix &abs_vmrs, ArrayOfArrayOfSpeciesTag &abs_nls, Vector &abs_nls_pert, const ArrayOfArrayOfSpeciesTag &abs_species, const Index &abs_p_interp_order, const Index &abs_t_interp_order, const Index &abs_nls_interp_order, const Numeric &p_min, const Numeric &p_max, const Numeric &p_step10, const Numeric &t_min, const Numeric &t_max, const Numeric &h2o_min, const Numeric &h2o_max, const Verbosity &verbosity)
WORKSPACE METHOD: abs_lookupSetupWide.
Definition: m_abs_lookup.cc:1690
rng.h
Defines the Rng random number generator class.
Array
This can be used to make arrays out of anything.
Definition: array.h:103
Rng::draw
double draw()
Definition: rng.cc:120
agenda_class.h
Declarations for agendas.
CREATE_OUT3
#define CREATE_OUT3
Definition: messages.h:208
CREATE_OUT0
#define CREATE_OUT0
Definition: messages.h:205
Tensor5::resize
void resize(Index s, Index b, Index p, Index r, Index c)
Resize function.
Definition: matpackV.cc:2435
abs_xsec_per_speciesAddConts
void abs_xsec_per_speciesAddConts(ArrayOfMatrix &abs_xsec_per_species, const ArrayOfArrayOfSpeciesTag &tgs, const Vector &f_grid, const Vector &abs_p, const Vector &abs_t, const Vector &abs_n2, const Vector &abs_h2o, const Matrix &abs_vmrs, const ArrayOfString &abs_cont_names, const ArrayOfVector &abs_cont_parameters, const ArrayOfString &abs_cont_models, const Verbosity &verbosity)
WORKSPACE METHOD: abs_xsec_per_speciesAddConts.
Definition: m_abs.cc:1715
abs_lookupTestAccuracy
void abs_lookupTestAccuracy(const GasAbsLookup &abs_lookup, const Index &abs_lookup_is_adapted, const Index &abs_p_interp_order, const Index &abs_t_interp_order, const Index &abs_nls_interp_order, const Vector &abs_n2, const ArrayOfArrayOfLineRecord &abs_lines_per_species, const ArrayOfLineshapeSpec &abs_lineshape, const ArrayOfString &abs_cont_names, const ArrayOfString &abs_cont_models, const ArrayOfVector &abs_cont_parameters, const Verbosity &verbosity)
WORKSPACE METHOD: abs_lookupTestAccuracy.
Definition: m_abs_lookup.cc:2472
species_data
Array< SpeciesRecord > species_data
Definition: species_data.cc:40
messages.h
Declarations having to do with the four output streams.
ConstMatrixView::ncols
Index ncols() const
Returns the number of columns.
Definition: matpackI.cc:802
GridPosPoly
Structure to store a grid position for higher order interpolation.
Definition: interpolation_poly.h:64
my_basic_string
The implementation for String, the ARTS string class.
Definition: mystring.h:62
abs
#define abs(x)
Definition: continua.cc:13094
VectorInsertGridPoints
void VectorInsertGridPoints(Vector &og, const Vector &ingrid, const Vector &points, const Verbosity &verbosity)
WORKSPACE METHOD: VectorInsertGridPoints.
Definition: m_basic_types.cc:720
choose_abs_nls_pert
void choose_abs_nls_pert(Vector &abs_nls_pert, ConstVectorView refprof, ConstVectorView minprof, ConstVectorView maxprof, const Numeric &step, const Index &p_interp_order, const Index &nls_interp_order, const Verbosity &verbosity)
Chose the H2O perturbations abs_nls_pert.
Definition: m_abs_lookup.cc:745
ConstVectorView::nelem
Index nelem() const
Returns the number of elements.
Definition: matpackI.cc:175
GasAbsLookup::t_ref
Vector t_ref
The reference temperature profile [K].
Definition: gas_abs_lookup.h:198
find_first_species_tg
Index find_first_species_tg(const ArrayOfArrayOfSpeciesTag &tgs, const Index &spec)
Find first occurrence of species in tag groups.
Definition: abs_species_tags.cc:393
physics_funcs.h
mean
Numeric mean(const ConstVectorView &x)
Mean function, vector version.
Definition: matpackI.cc:1862
get_species_name
String get_species_name(const ArrayOfSpeciesTag &tg)
Return the species of a tag group as a string.
Definition: abs_species_tags.cc:349
ConstTensor4View::ncols
Index ncols() const
Returns the number of columns.
Definition: matpackIV.cc:78
GasAbsLookup::f_grid
Vector f_grid
The frequency grid [Hz].
Definition: gas_abs_lookup.h:171
GasAbsLookup::p_grid
Vector p_grid
The pressure grid for the table [Pa].
Definition: gas_abs_lookup.h:175
GridPosPoly::idx
ArrayOfIndex idx
Definition: interpolation_poly.h:67
SpeciesSet
void SpeciesSet(ArrayOfArrayOfSpeciesTag &abs_species, const ArrayOfString &names, const Verbosity &verbosity)
WORKSPACE METHOD: SpeciesSet.
Definition: m_abs_lookup.cc:1943
Numeric
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
Verbosity
Definition: messages.h:50
ConstTensor4View::npages
Index npages() const
Returns the number of pages.
Definition: matpackIV.cc:66
chk_atm_field
void chk_atm_field(const String &x_name, ConstTensor3View x, const Index &dim, ConstVectorView p_grid, ConstVectorView lat_grid, ConstVectorView lon_grid)
chk_atm_field (simple fields)
Definition: check_input.cc:683
ConstTensor4View::nbooks
Index nbooks() const
Returns the number of books.
Definition: matpackIV.cc:60
math_funcs.h
GasAbsLookup::nls_pert
Vector nls_pert
The vector of perturbations for the VMRs of the nonlinear species.
Definition: gas_abs_lookup.h:227
transpose
ConstMatrixView transpose(ConstMatrixView m)
Const version of transpose.
Definition: matpackI.cc:1689
abs_lookupSetup
void abs_lookupSetup(Vector &abs_p, Vector &abs_t, Vector &abs_t_pert, Matrix &abs_vmrs, ArrayOfArrayOfSpeciesTag &abs_nls, Vector &abs_nls_pert, const Index &atmosphere_dim, const Vector &p_grid, const Vector &lat_grid, const Vector &lon_grid, const Tensor3 &t_field, const Tensor4 &vmr_field, const ArrayOfArrayOfSpeciesTag &abs_species, const Index &abs_p_interp_order, const Index &abs_t_interp_order, const Index &abs_nls_interp_order, const Numeric &p_step10, const Numeric &t_step, const Numeric &h2o_step, const Verbosity &verbosity)
WORKSPACE METHOD: abs_lookupSetup.
Definition: m_abs_lookup.cc:850
make_vector.h
The class MakeVector is a special kind of Vector that can be initialized explicitly from one or more ...
GasAbsLookup::xsec
Tensor4 xsec
Absorption cross sections.
Definition: gas_abs_lookup.h:261
find_nonlinear_continua
void find_nonlinear_continua(ArrayOfIndex &cont, const ArrayOfArrayOfSpeciesTag &abs_species, const Verbosity &verbosity)
Find continuum species in abs_species.
Definition: m_abs_lookup.cc:519
arts_omp_set_nested
void arts_omp_set_nested(int i)
Wrapper for omp_set_nested.
Definition: arts_omp.cc:124
Matrix::resize
void resize(Index r, Index c)
Resize function.
Definition: matpackI.cc:1549
jacobianAddAbsSpecies
void jacobianAddAbsSpecies(Workspace &ws, ArrayOfRetrievalQuantity &jq, Agenda &jacobian_agenda, const Index &atmosphere_dim, const Vector &p_grid, const Vector &lat_grid, const Vector &lon_grid, const Vector &rq_p_grid, const Vector &rq_lat_grid, const Vector &rq_lon_grid, const String &species, const String &method, const String &mode, const Numeric &dx, const Verbosity &verbosity)
WORKSPACE METHOD: jacobianAddAbsSpecies.
Definition: m_jacobian.cc:180
max
#define max(a, b)
Definition: continua.cc:13097
interpolation_poly.h
Header file for interpolation_poly.cc.
Tensor5
The Tensor5 class.
Definition: matpackV.h:443
ConstTensor4View::nrows
Index nrows() const
Returns the number of rows.
Definition: matpackIV.cc:72
N
#define N
Definition: rng.cc:195
MakeVector
Definition: make_vector.h:42
GasAbsLookup::species
ArrayOfArrayOfSpeciesTag species
The species tags for which the table is valid.
Definition: gas_abs_lookup.h:158
Range
The range class.
Definition: matpackI.h:148
matpackV.h
abs_lookupCreate
void abs_lookupCreate(GasAbsLookup &abs_lookup, Index &abs_lookup_is_adapted, const ArrayOfArrayOfSpeciesTag &abs_species, const ArrayOfArrayOfLineRecord &abs_lines_per_species, const ArrayOfLineshapeSpec &abs_lineshape, const ArrayOfArrayOfSpeciesTag &abs_nls, const Vector &f_grid, const Vector &abs_p, const Matrix &abs_vmrs, const Vector &abs_t, const Vector &abs_t_pert, const Vector &abs_nls_pert, const Vector &abs_n2, const ArrayOfString &abs_cont_names, const ArrayOfString &abs_cont_models, const ArrayOfVector &abs_cont_parameters, const Verbosity &verbosity)
WORKSPACE METHOD: abs_lookupCreate.
Definition: m_abs_lookup.cc:60
chk_atm_grids
void chk_atm_grids(const Index &dim, ConstVectorView p_grid, ConstVectorView lat_grid, ConstVectorView lon_grid)
chk_atm_grids
Definition: check_input.cc:603
min
#define min(a, b)
Definition: continua.cc:13096
Rng
Definition: rng.h:569
GasAbsLookup::Extract
void Extract(Matrix &sga, const Index &p_interp_order, const Index &t_interp_order, const Index &h2o_interp_order, const Index &f_index, const Numeric &p, const Numeric &T, ConstVectorView abs_vmrs) const
Extract scalar gas absorption coefficients from the lookup table.
Definition: gas_abs_lookup.cc:517
Workspace
Workspace class.
Definition: workspace_ng.h:47
GasAbsLookup::log_p_grid
Vector log_p_grid
The natural log of the pressure grid.
Definition: gas_abs_lookup.h:183
GasAbsLookup::Adapt
void Adapt(const ArrayOfArrayOfSpeciesTag &current_species, ConstVectorView current_f_grid, const Verbosity &verbosity)
Adapt lookup table to current calculation.
Definition: gas_abs_lookup.cc:120
abs_lookupAdapt
void abs_lookupAdapt(GasAbsLookup &abs_lookup, Index &abs_lookup_is_adapted, const ArrayOfArrayOfSpeciesTag &abs_species, const Vector &f_grid, const Verbosity &verbosity)
WORKSPACE METHOD: abs_lookupAdapt.
Definition: m_abs_lookup.cc:1979
chk_size
void chk_size(const String &x_name, ConstVectorView x, const Index &c)
Runtime check for size of Vector.
Definition: check_input.cc:911
Index
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
find_next_species_tg
Index find_next_species_tg(const ArrayOfArrayOfSpeciesTag &tgs, const Index &spec, const Index &start)
Find next occurrence of species in tag groups.
Definition: abs_species_tags.cc:417
ArtsOut2
Definition: messages.h:144
abs_scalar_gasExtractFromLookup
void abs_scalar_gasExtractFromLookup(Matrix &abs_scalar_gas, const GasAbsLookup &abs_lookup, const Index &abs_lookup_is_adapted, const Index &abs_p_interp_order, const Index &abs_t_interp_order, const Index &abs_nls_interp_order, const Index &f_index, const Numeric &a_pressure, const Numeric &a_temperature, const Vector &a_vmr_list, const Numeric &a_doppler, const Numeric &extpolfac, const Verbosity &verbosity)
WORKSPACE METHOD: abs_scalar_gasExtractFromLookup.
Definition: m_abs_lookup.cc:1991
check_input.h
gridpos_poly
void gridpos_poly(ArrayOfGridPosPoly &gp, ConstVectorView old_grid, ConstVectorView new_grid, const Index order, const Numeric &extpolfac)
Set up grid positions for higher order interpolation.
Definition: interpolation_poly.cc:124
GasAbsLookup::vmrs_ref
Matrix vmrs_ref
The reference VMR profiles.
Definition: gas_abs_lookup.h:193
is_unique
bool is_unique(const ArrayOfIndex &x)
Checks if an ArrayOfIndex is unique, i.e., has no duplicate values.
Definition: logic.cc:330
abs_speciesAdd2
void abs_speciesAdd2(Workspace &ws, ArrayOfArrayOfSpeciesTag &abs_species, ArrayOfRetrievalQuantity &jq, Agenda &jacobian_agenda, const Index &atmosphere_dim, const Vector &p_grid, const Vector &lat_grid, const Vector &lon_grid, const Vector &rq_p_grid, const Vector &rq_lat_grid, const Vector &rq_lon_grid, const String &species, const String &method, const String &mode, const Numeric &dx, const Verbosity &verbosity)
WORKSPACE METHOD: abs_speciesAdd2.
Definition: m_abs_lookup.cc:1889
GasAbsLookup::t_pert
Vector t_pert
The vector of temperature perturbations [K].
Definition: gas_abs_lookup.h:212
Vector
The Vector class.
Definition: matpackI.h:555
arts_omp.h
Header file for helper functions for OpenMP.
calc_lookup_error
Numeric calc_lookup_error(const GasAbsLookup &al, const Index &abs_p_interp_order, const Index &abs_t_interp_order, const Index &abs_nls_interp_order, const bool ignore_errors, const Vector &abs_n2, const ArrayOfArrayOfLineRecord &abs_lines_per_species, const ArrayOfLineshapeSpec &abs_lineshape, const ArrayOfString &abs_cont_names, const ArrayOfString &abs_cont_models, const ArrayOfVector &abs_cont_parameters, const Numeric &local_p, const Numeric &local_t, const Vector &local_vmrs, const Verbosity &verbosity)
Compare lookup and LBL calculation.
Definition: m_abs_lookup.cc:2358
ConstVectorView
A constant view of a Vector.
Definition: matpackI.h:300
Array::nelem
Index nelem() const
Number of elements.
Definition: array.h:172
interpweights
void interpweights(VectorView itw, const GridPos &tc)
Red 1D interpolation weights.
Definition: interpolation.cc:756
abs_xsec_per_speciesInit
void abs_xsec_per_speciesInit(ArrayOfMatrix &abs_xsec_per_species, const ArrayOfArrayOfSpeciesTag &tgs, const Vector &f_grid, const Vector &abs_p, const Verbosity &verbosity)
WORKSPACE METHOD: abs_xsec_per_speciesInit.
Definition: m_abs.cc:1451
gas_abs_lookup.h
Declarations for the gas absorption lookup table.
abs_scalar_gasCalcLBL
void abs_scalar_gasCalcLBL(Matrix &abs_scalar_gas, const Vector &f_grid, const ArrayOfArrayOfSpeciesTag &abs_species, const Vector &abs_n2, const ArrayOfArrayOfLineRecord &abs_lines_per_species, const ArrayOfLineshapeSpec &abs_lineshape, const ArrayOfString &abs_cont_names, const ArrayOfString &abs_cont_models, const ArrayOfVector &abs_cont_parameters, const Index &f_index, const Numeric &rte_pressure, const Numeric &rte_temperature, const Vector &rte_vmr_list, const Numeric &rte_doppler, const Verbosity &verbosity)
WORKSPACE METHOD: abs_scalar_gasCalcLBL.
Definition: m_abs.cc:2080
arts.h
The global header file for ARTS.
chk_interpolation_grids
void chk_interpolation_grids(const String &which_interpolation, ConstVectorView old_grid, ConstVectorView new_grid, const Index order, const Numeric &extpolfac)
Check interpolation grids.
Definition: check_input.cc:390
abs_fieldCalc
void abs_fieldCalc(Workspace &ws, Tensor5 &asg_field, const Agenda &sga_agenda, const Index &f_index, const Vector &f_grid, const Index &atmosphere_dim, const Vector &p_grid, const Vector &lat_grid, const Vector &lon_grid, const Tensor3 &t_field, const Tensor4 &vmr_field, const Vector &doppler, const Verbosity &verbosity)
WORKSPACE METHOD: abs_fieldCalc.
Definition: m_abs_lookup.cc:2102