ARTS  2.3.1285(git:92a29ea9-dirty)
m_checked.cc
Go to the documentation of this file.
1 /* Copyright (C) 2013
2  Patrick Eriksson <Patrick.Eriksson@chalmers.se>
3  Stefan Buehler <sbuehler(at)ltu.se>
4 
5  This program is free software; you can redistribute it and/or modify it
6  under the terms of the GNU General Public License as published by the
7  Free Software Foundation; either version 2, or (at your option) any
8  later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18  USA. */
19 
20 /*===========================================================================
21  === File description
22  ===========================================================================*/
23 
35 #include "arts.h"
36 #include "auto_md.h"
37 #include "cloudbox.h"
38 #include "matpackI.h"
39 
40 extern const Numeric DEG2RAD;
41 extern const Numeric LAT_LON_MIN;
42 
43 /* Workspace method: Doxygen documentation will be auto-generated */
45  Index& abs_xsec_agenda_checked,
46  // WS Input:
47  const ArrayOfArrayOfSpeciesTag& abs_species,
48  const Agenda& abs_xsec_agenda,
49  const Verbosity&) {
50  bool needs_lines = false;
51  bool needs_continua = false;
52  bool needs_cia = false;
53  bool needs_hxsec = false;
54 
55  for (Index sp = 0; sp < abs_species.nelem(); sp++) {
56  for (Index tgs = 0; tgs < abs_species[sp].nelem(); tgs++) {
57  switch (abs_species[sp][tgs].Type()) {
59  needs_lines = true;
60  break;
62  break;
64  needs_continua = true;
65  break;
67  needs_cia = true;
68  break;
70  break;
72  break;
74  needs_hxsec = true;
75  break;
76  default:
77  ostringstream os;
78  os << "Unknown species type: " << abs_species[sp][tgs].Type();
79  throw runtime_error(os.str());
80  break;
81  }
82  }
83  }
84 
85  if (needs_lines and
86  not(abs_xsec_agenda.has_method("abs_xsec_per_speciesAddLines"))) {
87  throw runtime_error(
88  "*abs_species* contains line species but *abs_xsec_agenda*\n"
89  "does not contain *abs_xsec_per_speciesAddLines*.");
90  }
91 
92  if (needs_continua &&
93  !abs_xsec_agenda.has_method("abs_xsec_per_speciesAddConts")) {
94  throw runtime_error(
95  "*abs_species* contains continuum species but *abs_xsec_agenda*\n"
96  "does not contain *abs_xsec_per_speciesAddConts*.");
97  }
98 
99  if (needs_cia && !abs_xsec_agenda.has_method("abs_xsec_per_speciesAddCIA")) {
100  throw runtime_error(
101  "*abs_species* contains CIA species but *abs_xsec_agenda*\n"
102  "does not contain *abs_xsec_per_speciesAddCIA*.");
103  }
104 
105  if (needs_hxsec &&
106  !abs_xsec_agenda.has_method("abs_xsec_per_speciesAddHitranXsec")) {
107  throw runtime_error(
108  "*abs_species* contains HITRAN xsec species but *abs_xsec_agenda*\n"
109  "does not contain *abs_xsec_per_speciesAddHitranXsec*.");
110  }
111 
112  if (find_first_species_tg(abs_species, SpeciesTag("O2-MPM2020")) >= 0) {
113  if (not abs_xsec_agenda.has_method("abs_xsec_per_speciesAddPredefinedO2MPM2020")) {
114  throw runtime_error(
115  "*abs_species contains \"O2-MPM2020\" but *abs_xsec_agenda*\n"
116  "does not contain *abs_xsec_per_speciesAddPredefinedO2MPM2020*.");
117  }
118  }
119 
120  // If here, all OK
121  abs_xsec_agenda_checked = 1;
122 }
123 
124 /* Workspace method: Doxygen documentation will be auto-generated */
125 void atmfields_checkedCalc(Index& atmfields_checked,
126  const Index& atmosphere_dim,
127  const Vector& p_grid,
128  const Vector& lat_grid,
129  const Vector& lon_grid,
130  const ArrayOfArrayOfSpeciesTag& abs_species,
131  const Tensor3& t_field,
132  const Tensor4& vmr_field,
133  const Tensor3& wind_u_field,
134  const Tensor3& wind_v_field,
135  const Tensor3& wind_w_field,
136  const Tensor3& mag_u_field,
137  const Tensor3& mag_v_field,
138  const Tensor3& mag_w_field,
139  const SpeciesAuxData& partition_functions,
140  const Index& abs_f_interp_order,
141  const Index& negative_vmr_ok,
142  const Index& bad_partition_functions_ok,
143  const Verbosity&) {
144  // Consistency between dim, grids and atmospheric fields/surfaces
145  chk_if_in_range("atmosphere_dim", atmosphere_dim, 1, 3);
146  chk_atm_grids(atmosphere_dim, p_grid, lat_grid, lon_grid);
147  chk_atm_field("t_field", t_field, atmosphere_dim, p_grid, lat_grid, lon_grid);
148  chk_atm_field("vmr_field",
149  vmr_field,
150  atmosphere_dim,
151  abs_species.nelem(),
152  p_grid,
153  lat_grid,
154  lon_grid);
155 
156  // More for vmr_field.
157  if (!negative_vmr_ok && abs_species.nelem() && min(vmr_field) < 0)
158  throw runtime_error("All values in *vmr_field* must be >= 0.");
159 
160  // More for t_field.
161  if (min(t_field) <= 0)
162  throw runtime_error("All temperatures in *t_field* must be > 0.");
163 
164  // Winds
165  if (wind_w_field.npages() > 0) {
166  chk_atm_field("wind_w_field",
167  wind_w_field,
168  atmosphere_dim,
169  p_grid,
170  lat_grid,
171  lon_grid);
172  }
173  if (atmosphere_dim < 3 && wind_v_field.npages() > 0) {
174  chk_atm_field("wind_v_field",
175  wind_v_field,
176  atmosphere_dim,
177  p_grid,
178  lat_grid,
179  lon_grid);
180  }
181  if (atmosphere_dim > 2) {
182  if (wind_u_field.npages() > 0) {
183  if (wind_v_field.npages() > 0) {
184  bool chk_poles = false;
185  chk_atm_field("wind_u_field",
186  wind_u_field,
187  atmosphere_dim,
188  p_grid,
189  lat_grid,
190  lon_grid,
191  chk_poles);
192  chk_atm_field("wind_v_field",
193  wind_v_field,
194  atmosphere_dim,
195  p_grid,
196  lat_grid,
197  lon_grid,
198  chk_poles);
199  chk_atm_vecfield_lat90("wind_v_field",
200  wind_v_field,
201  "wind_u_field",
202  wind_u_field,
203  atmosphere_dim,
204  lat_grid);
205  } else {
206  chk_atm_field("wind_u_field",
207  wind_u_field,
208  atmosphere_dim,
209  p_grid,
210  lat_grid,
211  lon_grid);
212  }
213  } else {
214  if (wind_v_field.npages() > 0) {
215  chk_atm_field("wind_v_field",
216  wind_v_field,
217  atmosphere_dim,
218  p_grid,
219  lat_grid,
220  lon_grid);
221  }
222  }
223  }
224 
225  // If any of the wind fields exist, abs_f_interp_order must not be zero.
226  if (wind_u_field.npages() > 0 || wind_v_field.npages() > 0 ||
227  wind_w_field.npages() > 0) {
228  if (abs_f_interp_order == 0) {
229  ostringstream os;
230  os << "You have a wind field set, but abs_f_interp_order zero.\n"
231  << "This is not allowed. Though abs_f_interp_order only is\n"
232  << "required and has an effect if absorption lookup tables\n"
233  << "are used, for safety reasons you also have to set it >0\n"
234  << "in case of on-the-fly absorption.";
235  throw runtime_error(os.str());
236  }
237  }
238 
239  // Magnetic field
240  if (mag_w_field.npages() > 0) {
241  chk_atm_field("mag_w_field (vertical magfield component)",
242  mag_w_field,
243  atmosphere_dim,
244  p_grid,
245  lat_grid,
246  lon_grid);
247  }
248  if (mag_u_field.npages() > 0) {
249  if (mag_v_field.npages() > 0) {
250  bool chk_poles = false;
251  chk_atm_field("mag_v_field",
252  mag_v_field,
253  atmosphere_dim,
254  p_grid,
255  lat_grid,
256  lon_grid,
257  chk_poles);
258  chk_atm_field("mag_u_field",
259  mag_u_field,
260  atmosphere_dim,
261  p_grid,
262  lat_grid,
263  lon_grid,
264  chk_poles);
265  chk_atm_vecfield_lat90("mag_v_field",
266  mag_v_field,
267  "mag_u_field",
268  mag_u_field,
269  atmosphere_dim,
270  lat_grid);
271  } else {
272  chk_atm_field("mag_u_field",
273  mag_u_field,
274  atmosphere_dim,
275  p_grid,
276  lat_grid,
277  lon_grid);
278  }
279  } else {
280  if (mag_v_field.npages() > 0) {
281  chk_atm_field("mag_v_field",
282  mag_v_field,
283  atmosphere_dim,
284  p_grid,
285  lat_grid,
286  lon_grid);
287  }
288  }
289 
290  if (partition_functions.nspecies()) {
291  // Partition functions have partition functions and finding their temperature limits?
292  Numeric min_T = 0, max_T = 1e6; //1 MK is max tested
293  for (Index ii = 0; ii < partition_functions.nspecies(); ii++)
294  for (Index jj = 0; jj < partition_functions.nisotopologues(ii); jj++) {
295  // Test if species is important at all (maybe, since code is unclear; will at worst cause failures later on in the program)
296  bool test_spec = false;
297  for (auto& as : abs_species)
298  for (auto& s : as)
299  if (s.Species() == ii and s.Isotopologue() == jj) test_spec = true;
300  if (not test_spec) continue;
301 
302  ArrayOfGriddedField1 part_fun;
303  switch (partition_functions.getParamType(ii, jj)) {
305  part_fun = partition_functions.getParam(ii, jj);
306  if (part_fun.nelem() == 2) {
307  if (part_fun[1].data.nelem() == 2 &&
308  part_fun[0].data.nelem() > 1) {
309  if (part_fun[1].data[0] > min_T) min_T = part_fun[1].data[0];
310  if (part_fun[1].data[1] < max_T) max_T = part_fun[1].data[1];
311  } else
312  throw std::runtime_error(
313  "Bad coefficient parameter in partition_function.\n");
314  } else
315  throw std::runtime_error(
316  "Bad coefficient parameter in partition_function.\n");
317  break;
318 
320  part_fun = partition_functions.getParam(ii, jj);
321  if (part_fun.nelem() == 3) {
322  if (part_fun[2].data.nelem() == 2 &&
323  (part_fun[1].data.nelem() == part_fun[0].data.nelem())) {
324  if (part_fun[2].data[0] > min_T) min_T = part_fun[2].data[0];
325  if (part_fun[2].data[1] < max_T) max_T = part_fun[2].data[1];
326  } else
327  throw std::runtime_error(
328  "Bad coefficient parameter in partition_function.\n");
329  } else
330  throw std::runtime_error(
331  "Bad coefficient parameter in partition_function.\n");
332  break;
333 
335  part_fun = partition_functions.getParam(ii, jj);
336  if (part_fun.nelem() == 1) {
337  if (part_fun[0].data.nelem() > 1) {
338  if (part_fun[0].get_numeric_grid(0)[0] > min_T)
339  min_T = part_fun[0].get_numeric_grid(0)[0];
340  if (part_fun[0].get_numeric_grid(
341  0)[part_fun[0].data.nelem() - 1] < max_T)
342  max_T = part_fun[0].get_numeric_grid(
343  0)[part_fun[0].data.nelem() - 1];
344  } else
345  throw std::runtime_error(
346  "Bad t_field parameter in partition_function.\n");
347  } else
348  throw std::runtime_error(
349  "Bad t_field parameter in partition_function.\n");
350  break;
351 
352  default:
353  throw std::runtime_error(
354  "Bad parameter type in partition_functions.\n");
355  break;
356  }
357  }
358 
359  // Check that partition functions are OK if not explicitly turned off
360  if (!bad_partition_functions_ok) {
361  for (Index ii = 0; ii < t_field.npages(); ii++)
362  for (Index jj = 0; jj < t_field.nrows(); jj++)
363  for (Index kk = 0; kk < t_field.ncols(); kk++) {
364  if (min_T > t_field(ii, jj, kk) || max_T < t_field(ii, jj, kk)) {
365  ostringstream os;
366  os << "There are bad partition functions in your setup.\n"
367  << "Minimum temperature for defined partition functions is: "
368  << min_T
369  << " K.\nMaximum temperature for defined partition functions is: "
370  << max_T << " K\nThere is a t_field entry of "
371  << t_field(ii, jj, kk) << " K.\n";
372  throw std::runtime_error(os.str());
373  }
374  }
375  }
376  }
377 
378  // If here, all OK
379  atmfields_checked = 1;
380 }
381 
382 /* Workspace method: Doxygen documentation will be auto-generated */
383 void atmgeom_checkedCalc(Index& atmgeom_checked,
384  const Index& atmosphere_dim,
385  const Vector& p_grid,
386  const Vector& lat_grid,
387  const Vector& lon_grid,
388  const Tensor3& z_field,
389  const Vector& refellipsoid,
390  const Matrix& z_surface,
391  const Vector& lat_true,
392  const Vector& lon_true,
393  const Verbosity&) {
394  // A repetition from atmfields_checked, but we do this to make the two parts
395  // independent (the other option would be to demand atmfields_checkec == 1)
396  chk_if_in_range("atmosphere_dim", atmosphere_dim, 1, 3);
397  chk_atm_grids(atmosphere_dim, p_grid, lat_grid, lon_grid);
398 
399  // *refellipsoid*
400  if (refellipsoid.nelem() != 2)
401  throw runtime_error(
402  "The WSV *refellispoid* must be a vector of "
403  "length 2*.");
404  if (refellipsoid[0] <= 0)
405  throw runtime_error(
406  "The first element of *refellipsoid* must "
407  "be > 0.");
408  if (refellipsoid[1] < 0 || refellipsoid[1] > 1)
409  throw runtime_error(
410  "The second element of *refellipsoid* must be "
411  "inside [0,1].");
412  if (atmosphere_dim == 1 && refellipsoid[1] != 0)
413  throw runtime_error(
414  "For 1D, the second element of *refellipsoid* "
415  "(the eccentricity) must be 0.");
416 
417  chk_atm_field("z_field", z_field, atmosphere_dim, p_grid, lat_grid, lon_grid);
418  chk_atm_surface("z_surface", z_surface, atmosphere_dim, lat_grid, lon_grid);
419 
420  // Check that z_field has strictly increasing pages.
421  for (Index row = 0; row < z_field.nrows(); row++) {
422  for (Index col = 0; col < z_field.ncols(); col++) {
423  ostringstream os;
424  os << "z_field (for latitude nr " << row << " and longitude nr " << col
425  << ")";
426  chk_if_increasing(os.str(), z_field(joker, row, col));
427  }
428  }
429 
430  // Check that there is no gap between the surface and lowest pressure
431  // level
432  // (A copy of this code piece is found in z_fieldFromHSE. Make this to an
433  // internal function if used in more places.)
434  for (Index row = 0; row < z_surface.nrows(); row++) {
435  for (Index col = 0; col < z_surface.ncols(); col++) {
436  if (z_surface(row, col) < z_field(0, row, col) ||
437  z_surface(row, col) >= z_field(z_field.npages() - 1, row, col)) {
438  ostringstream os;
439  os << "The surface altitude (*z_surface*) cannot be outside\n"
440  << "of the altitudes in *z_field*.\n"
441  << "z_surface: " << z_surface(row, col) << "\n"
442  << "min of z_field: " << z_field(0, row, col) << "\n"
443  << "max of z_field: " << z_field(z_field.npages() - 1, row, col)
444  << "\n";
445  if (atmosphere_dim > 1)
446  os << "\nThis was found to be the case for:\n"
447  << "latitude " << lat_grid[row];
448  if (atmosphere_dim > 2) os << "\nlongitude " << lon_grid[col];
449  throw runtime_error(os.str());
450  }
451  }
452  }
453 
454  // lat/lon true
455  if (atmosphere_dim < 3 && (lat_true.nelem() || lon_true.nelem())) {
456  if (atmosphere_dim == 1) {
457  if (lat_true.nelem() != 1)
458  throw runtime_error("For 1D, *lat_true* must have length 1.");
459  if (lon_true.nelem() != 1)
460  throw runtime_error("For 1D, *lon_true* must have length 1.");
461  } else if (atmosphere_dim == 2) {
462  if (lat_true.nelem() != lat_grid.nelem())
463  throw runtime_error(
464  "For 2D, *lat_true* must have same length as *lat_grid*.");
465  if (lon_true.nelem() != lat_grid.nelem())
466  throw runtime_error(
467  "For 2D, *lon_true* must have same length as *lat_grid*.");
468  }
469  if (lon_true.nelem() != lat_true.nelem())
470  throw runtime_error(
471  "If *lat_true* is set, also *lon_true* must be "
472  "set (and have the same length).");
473  if (min(lat_true) < -90 || max(lat_true) > 90)
474  throw runtime_error("Values in *lat_true* must be inside [-90,90].");
475  if (min(lon_true) < -180 || max(lon_true) > 360)
476  throw runtime_error("Values in *lon_true* must be inside [-180,360].");
477  }
478 
479  // If here, all OK
480  atmgeom_checked = 1;
481 }
482 
483 /* Workspace method: Doxygen documentation will be auto-generated */
484 void cloudbox_checkedCalc(Index& cloudbox_checked,
485  const Index& atmfields_checked,
486  const Index& atmosphere_dim,
487  const Vector& p_grid,
488  const Vector& lat_grid,
489  const Vector& lon_grid,
490  const Tensor3& z_field,
491  const Matrix& z_surface,
492  const Tensor3& wind_u_field,
493  const Tensor3& wind_v_field,
494  const Tensor3& wind_w_field,
495  const Index& cloudbox_on,
496  const ArrayOfIndex& cloudbox_limits,
497  const Tensor4& pnd_field,
498  const ArrayOfTensor4& dpnd_field_dx,
499  const ArrayOfRetrievalQuantity& jacobian_quantities,
500  const ArrayOfArrayOfSingleScatteringData& scat_data,
501  const ArrayOfString& scat_species,
502  const Matrix& particle_masses,
503  const ArrayOfArrayOfSpeciesTag& abs_species,
504  const Index& negative_pnd_ok,
505  const Verbosity&) {
506  if (atmfields_checked != 1)
507  throw runtime_error(
508  "The atmospheric fields must be flagged to have "
509  "passed a consistency check (atmfields_checked=1).");
510 
511  chk_if_bool("cloudbox_on", cloudbox_on);
512 
513  if (cloudbox_on) {
514  // Winds, must be empty variables (i.e. no winds allowed)
515  {
516  ostringstream ow;
517  ow << "The scattering methods are not (yet?) handling winds. For this\n"
518  << "reason, the WSVs for wind fields must all be empty with an\n."
519  << "active cloudbox.";
520  if (!wind_w_field.empty() || !wind_v_field.empty() ||
521  !wind_u_field.empty()) {
522  throw runtime_error(ow.str());
523  }
524  }
525 
526  // no "particles" in abs_species if cloudbox is on (they act on the same
527  // scat_data! and there is no good reason to have some particles as
528  // abs-only, if we anyway do a scattering calculation.).
529  Index has_absparticles = 0;
530  for (Index sp = 0; sp < abs_species.nelem() && has_absparticles < 1; sp++) {
531  if (abs_species[sp][0].Type() == SpeciesTag::TYPE_PARTICLES) {
532  has_absparticles = 1;
533  }
534  }
535  if (has_absparticles) {
536  throw runtime_error(
537  "For scattering calculations (cloudbox is on),"
538  "abs_species is not allowed to contain\n"
539  "'particles' (absorbing-only particles)!");
540  }
541 
542  // Cloudbox limits
543  if (cloudbox_limits.nelem() != atmosphere_dim * 2) {
544  ostringstream os;
545  os << "The array *cloudbox_limits* has incorrect length.\n"
546  << "For atmospheric dim. = " << atmosphere_dim
547  << " the length shall be " << atmosphere_dim * 2 << " but it is "
548  << cloudbox_limits.nelem() << ".";
549  throw runtime_error(os.str());
550  }
551  if (cloudbox_limits[1] <= cloudbox_limits[0] || cloudbox_limits[0] < 0 ||
552  cloudbox_limits[1] >= p_grid.nelem()) {
553  ostringstream os;
554  os << "Incorrect value(s) for cloud box pressure limit(s) found."
555  << "\nValues are either out of range or upper limit is not "
556  << "greater than lower limit.\nWith present length of "
557  << "*p_grid*, OK values are 0 - " << p_grid.nelem() - 1
558  << ".\nThe pressure index limits are set to " << cloudbox_limits[0]
559  << " - " << cloudbox_limits[1] << ".";
560  throw runtime_error(os.str());
561  }
562 
563  Index nlat = 1, nlon = 1;
564 
565  if (atmosphere_dim > 1) {
566  nlat = lat_grid.nelem();
567  if (cloudbox_limits[3] <= cloudbox_limits[2] || cloudbox_limits[2] < 1 ||
568  cloudbox_limits[3] >= nlat - 1) {
569  ostringstream os;
570  os << "Incorrect value(s) for cloud box latitude limit(s) found."
571  << "\nValues are either out of range or upper limit is not "
572  << "greater than lower limit.\nWith present length of "
573  << "*lat_grid*, OK values are 1 - " << nlat - 2
574  << ".\nThe latitude index limits are set to " << cloudbox_limits[2]
575  << " - " << cloudbox_limits[3] << ".";
576  throw runtime_error(os.str());
577  }
578  if ((lat_grid[cloudbox_limits[2]] - lat_grid[0] < LAT_LON_MIN) &&
579  (atmosphere_dim == 2 || (atmosphere_dim == 3 && lat_grid[0] > -90))) {
580  ostringstream os;
581  os << "Too small distance between cloudbox and lower end of "
582  << "latitude grid.\n"
583  << "This distance must be " << LAT_LON_MIN << " degrees.\n"
584  << "Cloudbox ends at " << lat_grid[cloudbox_limits[2]]
585  << " and latitude grid starts at " << lat_grid[0] << ".";
586  throw runtime_error(os.str());
587  }
588  if ((lat_grid[nlat - 1] - lat_grid[cloudbox_limits[3]] < LAT_LON_MIN) &&
589  (atmosphere_dim == 2 ||
590  (atmosphere_dim == 3 && lat_grid[nlat - 1] < 90))) {
591  ostringstream os;
592  os << "Too small distance between cloudbox and upper end of "
593  << "latitude grid.\n"
594  << "This distance must be " << LAT_LON_MIN << " degrees.\n"
595  << "Cloudbox ends at " << lat_grid[cloudbox_limits[3]]
596  << " and latitude grid ends at " << lat_grid[nlat - 1] << ".";
597  throw runtime_error(os.str());
598  }
599  }
600 
601  if (atmosphere_dim > 2) {
602  nlon = lon_grid.nelem();
603  if (cloudbox_limits[5] <= cloudbox_limits[4] || cloudbox_limits[4] < 1 ||
604  cloudbox_limits[5] >= nlon - 1) {
605  ostringstream os;
606  os << "Incorrect value(s) for cloud box longitude limit(s) found"
607  << ".\nValues are either out of range or upper limit is not "
608  << "greater than lower limit.\nWith present length of "
609  << "*lon_grid*, OK values are 1 - " << nlon - 2
610  << ".\nThe longitude limits are set to " << cloudbox_limits[4]
611  << " - " << cloudbox_limits[5] << ".";
612  throw runtime_error(os.str());
613  }
614  if (lon_grid[nlon - 1] - lon_grid[0] < 360) {
615  const Numeric latmax = max(abs(lat_grid[cloudbox_limits[2]]),
616  abs(lat_grid[cloudbox_limits[3]]));
617  const Numeric lfac = 1 / cos(DEG2RAD * latmax);
618  if (lon_grid[cloudbox_limits[4]] - lon_grid[0] < LAT_LON_MIN / lfac) {
619  ostringstream os;
620  os << "Too small distance between cloudbox and lower end of"
621  << "the longitude\ngrid. This distance must here be "
622  << LAT_LON_MIN / lfac << " degrees.";
623  throw runtime_error(os.str());
624  }
625  if (lon_grid[nlon - 1] - lon_grid[cloudbox_limits[5]] <
626  LAT_LON_MIN / lfac) {
627  ostringstream os;
628  os << "Too small distance between cloudbox and upper end of"
629  << "the longitude\ngrid. This distance must here be "
630  << LAT_LON_MIN / lfac << " degrees.";
631  throw runtime_error(os.str());
632  }
633  }
634  }
635 
636  // Check with respect to z_surface
637  for (Index o = 0; o < nlon; o++) {
638  for (Index a = 0; a < nlat; a++) {
639  if (z_field(cloudbox_limits[1], a, o) <= z_surface(a, o))
640  throw runtime_error(
641  "The upper vertical limit of the cloudbox must be above "
642  "the surface altitude (for all latitudes and longitudes).");
643  }
644  }
645 
646  // Check pnd_field
647  //
648  const Index np = TotalNumberOfElements(scat_data);
649  // Dummy variables to mimic grids of correct size
650  Vector g1(cloudbox_limits[1] - cloudbox_limits[0] + 1), g2(0), g3(0);
651  if (atmosphere_dim > 1) {
652  g2.resize(cloudbox_limits[3] - cloudbox_limits[2] + 1);
653  }
654  if (atmosphere_dim > 2) {
655  g3.resize(cloudbox_limits[5] - cloudbox_limits[4] + 1);
656  }
657 
658  chk_atm_field("pnd_field", pnd_field, atmosphere_dim, np, g1, g2, g3);
659 
660  if (!negative_pnd_ok && min(pnd_field) < 0)
661  throw runtime_error("Negative values in *pnd_field* not allowed.");
662 
663  // No non-zero pnd at lower boundary unless lower boundary is at or below
664  // surface
665  for (Index a = 0; a < g2.nelem(); a++) {
666  for (Index o = 0; o < g3.nelem(); o++) {
667  if (max(pnd_field(joker, 0, a, o)) > 0 &&
668  z_field(cloudbox_limits[0], a, o) > z_surface(a, o))
669  throw runtime_error(
670  "A non-zero value found in *pnd_field* at the"
671  " lower altitude limit of the cloudbox (but the "
672  "position is not at or below the surface altitude).");
673  }
674  }
675 
676  // No non-zero pnd at upper boundary unless upper boundary is top of
677  // atmosphere
678  if (cloudbox_limits[1] != p_grid.nelem() - 1)
679  if (max(pnd_field(joker, g1.nelem() - 1, joker, joker)) > 0)
680  throw runtime_error(
681  "A non-zero value found in *pnd_field* at "
682  "upper altitude limit of the cloudbox.");
683  if (atmosphere_dim >= 2) {
684  if (max(pnd_field(joker, joker, 0, joker)) > 0)
685  throw runtime_error(
686  "A non-zero value found in *pnd_field* at "
687  "lower latitude limit of the cloudbox.");
688  if (max(pnd_field(joker, joker, g2.nelem() - 1, joker)) > 0)
689  throw runtime_error(
690  "A non-zero value found in *pnd_field* at "
691  "upper latitude limit of the cloudbox.");
692  }
693  if (atmosphere_dim == 3) {
694  if (max(pnd_field(joker, joker, joker, 0)) > 0)
695  throw runtime_error(
696  "A non-zero value found in *pnd_field* at "
697  "lower longitude limit of the cloudbox.");
698  if (max(pnd_field(joker, joker, joker, g3.nelem() - 1)) > 0)
699  throw runtime_error(
700  "A non-zero value found in *pnd_field* at "
701  "upper longitude limit of the cloudbox.");
702  }
703 
704  // And dpnd_field_dx
705  if (dpnd_field_dx.nelem() != jacobian_quantities.nelem())
706  throw runtime_error(
707  "Size of *dpnd_field_dx* inconsistent with number "
708  "of *jacobian_quantities*.");
709 
710  // Check semi-mandatory variables, that are allowed to be empty
711  //
712 
713  // scat_species:
714  if (scat_species.nelem() > 0)
715  if (scat_species.nelem() != scat_data.nelem()) {
716  ostringstream os;
717  os << "Number of scattering species specified by scat_species does\n"
718  << "not agree with number of scattering species in scat_data:\n"
719  << "scat_species has " << scat_species.nelem()
720  << " entries, while scat_data has " << scat_data.nelem() << ".";
721  throw runtime_error(os.str());
722  }
723 
724  // particle_masses:
725  if (!particle_masses.empty()) {
726  if (particle_masses.nrows() != np)
727  throw runtime_error(
728  "The WSV *particle_masses* must either be "
729  "empty or have a row size matching the "
730  "length of *scat_data*.");
731  if (min(particle_masses) < 0)
732  throw runtime_error("All values in *particles_masses* must be >= 0.");
733  }
734  }
735 
736  // If here, all OK
737  cloudbox_checked = 1;
738 }
739 
740 /* Workspace method: Doxygen documentation will be auto-generated */
741 void scat_data_checkedCalc(Index& scat_data_checked,
742  const ArrayOfArrayOfSingleScatteringData& scat_data,
743  const Vector& f_grid,
744  const Numeric& dfrel_threshold,
745  const String& check_level,
746  const Numeric& sca_mat_threshold,
747  const Verbosity& verbosity)
748 // FIXME: when we allow K, a, Z to be on different f and T grids, their use in
749 // the scatt solvers needs to be reviewed again and adapted to this!
750 {
751  // Prevent the user from producing nonsense by using too much freedom in
752  // setting the single freq validity threshold...
753  if (dfrel_threshold > 0.5) {
754  ostringstream os;
755  os << "*dfrel_threshold* too large (max. allowed: 0.5, your's: "
756  << dfrel_threshold << ").";
757  throw runtime_error(os.str());
758  }
759 
760  // freq range of calc covered?
761  if (f_grid.empty()) throw runtime_error("The frequency grid is empty.");
762  if (f_grid.nelem() > 1) chk_if_increasing("f_grid", f_grid);
763 
764  Index nf = f_grid.nelem();
765  Index N_ss = scat_data.nelem();
766  for (Index i_ss = 0; i_ss < N_ss; i_ss++) {
767  Index N_se = scat_data[i_ss].nelem();
768  for (Index i_se = 0; i_se < N_se; i_se++) {
769  // For each scattering element (se) check that se's f_grid is either
770  // identical to f_grid or contains a single entry only. In the latter
771  // case, the f/f_grid-ratio (equv. to a size parameter ratio) not allowed
772  // to exceed the dfrel_threshold.
773  Index nf_se = scat_data[i_ss][i_se].f_grid.nelem();
774  if (nf_se != 1) {
775  if (nf_se != nf) {
776  ostringstream os;
777  os << "*scat_data* must have either one or *f_grid* (=" << nf
778  << ") frequency entries,\n"
779  << "but scattering element #" << i_se << " in scattering species #"
780  << i_ss << " has " << nf_se << ".";
781  throw runtime_error(os.str());
782  } else {
783  for (Index f = 0; f < nf_se; f++) {
785  scat_data[i_ss][i_se].f_grid[f], f_grid[f], 0.5e-9)) {
786  ostringstream os;
787  os << "*scat_data* frequency grid has to be identical to *f_grid*\n"
788  << "(or contain only a single entry),\n"
789  << "but scattering element #" << i_se
790  << " in scattering species #" << i_ss
791  << " deviates for f_index " << f << ".";
792  throw runtime_error(os.str());
793  }
794  }
795  }
796  } else {
797  if ((abs(1. - scat_data[i_ss][i_se].f_grid[0] / f_grid[0]) >
798  dfrel_threshold) or
799  (abs(1. - scat_data[i_ss][i_se].f_grid[0] / f_grid[nf - 1]) >
800  dfrel_threshold)) {
801  ostringstream os;
802  os << "Frequency entry (f=" << scat_data[i_ss][i_se].f_grid[0]
803  << "Hz) of scattering element #" << i_se << "\n"
804  << "in scattering species #" << i_ss << " is too far (>"
805  << dfrel_threshold * 1e2 << "%) from one or more\n"
806  << "of the f_grid limits (fmin=" << f_grid[0]
807  << "Hz, fmax=" << f_grid[nf - 1] << "Hz).";
808  throw runtime_error(os.str());
809  }
810  }
811 
812  // check that the freq dimension of sca_mat, ext_mat, and abs_vec is
813  // either ssd.f_grid.nelem() or 1 (FIXME: so far, being freq dim !=
814  // ssd.f_grid.nelem() switched off, as usage in scatt solvers so far
815  // doesn't allow this. see FIXME at start.).
816  {
817  ostringstream bs1, bs2;
818  bs1 << "Frequency dimension of ";
819  //bs2 << " must be either one or ssd.f_grid.nelem() (=" << nf_se << "),\n"
820  bs2 << " must be ssd.f_grid.nelem() (=" << nf_se << "),\n"
821  << "but scattering element #" << i_se << " in scattering species #"
822  << i_ss << " is ";
823  Index nf_sd = scat_data[i_ss][i_se].pha_mat_data.nlibraries();
824  if (nf_sd != nf_se) //&& nf_sd != 1)
825  {
826  ostringstream os;
827  os << bs1.str() << "pha_mat_data" << bs2.str() << nf_se << ".";
828  throw runtime_error(os.str());
829  }
830  nf_sd = scat_data[i_ss][i_se].ext_mat_data.nshelves();
831  if (nf_sd != nf_se) //&& nf_sd != 1)
832  {
833  ostringstream os;
834  os << bs1.str() << "ext_mat_data" << bs2.str() << nf_se << ".";
835  throw runtime_error(os.str());
836  }
837  nf_sd = scat_data[i_ss][i_se].abs_vec_data.nshelves();
838  if (nf_sd != nf_se) //&& nf_sd != 1)
839  {
840  ostringstream os;
841  os << bs1.str() << "abs_vec_data" << bs2.str() << nf_se << ".";
842  throw runtime_error(os.str());
843  }
844  }
845 
846  // check that the temp dimension of K and a is ssd.T_grid.nelem(). For Z
847  // it might be ssd.T_grid.nelem() or 1.
848  {
849  ostringstream bs1, bs2;
850  Index nt_se = scat_data[i_ss][i_se].T_grid.nelem();
851  bs1 << "Temperature dimension of ";
852  //bs2 << " must be either one or ssd.T_grid.nelem(),\n"
853  bs2 << " must be ssd.T_grid.nelem() (=" << nt_se << "),\n"
854  << "but for scattering element #" << i_se
855  << " in scattering species #" << i_ss << " it is ";
856  Index nt_sd = scat_data[i_ss][i_se].pha_mat_data.nvitrines();
857  if (nt_sd != nt_se and nt_sd != 1) {
858  ostringstream os;
859  os << bs1.str() << "pha_mat_data" << bs2.str() << nt_sd << ".";
860  throw runtime_error(os.str());
861  }
862  nt_sd = scat_data[i_ss][i_se].ext_mat_data.nbooks();
863  if (nt_sd != nt_se) // no need to check for 1 here. since if it is 1,
864  // also T_grid.nelem need to be 1
865  {
866  ostringstream os;
867  os << bs1.str() << "ext_mat_data" << bs2.str() << nt_se << ".";
868  throw runtime_error(os.str());
869  }
870  nt_sd = scat_data[i_ss][i_se].abs_vec_data.nbooks();
871  if (nt_sd != nt_se) {
872  ostringstream os;
873  os << bs1.str() << "abs_vec_data" << bs2.str() << nt_se << ".";
874  throw runtime_error(os.str());
875  }
876  }
877  }
878  }
879 
880  if (check_level.toupper() != "NONE") {
881  // handing over to scat_dataCheck which checks whether
882  // 1) scat_data containing any NaN?
883  // 2) any negative values in Z11, K11, or a1?
884  // 3) sca_mat norm sufficiently good (int(Z11)~=K11-a1?)
885  // 1) & 2) always done
886  // 3) only done if scat_data_check_level is "all"
887  scat_dataCheck(scat_data, check_level, sca_mat_threshold, verbosity);
888  }
889 
890  // If here, all OK
891  scat_data_checked = 1;
892 }
893 
894 /* Workspace method: Doxygen documentation will be auto-generated */
895 void lbl_checkedCalc(Index& lbl_checked,
896  const ArrayOfArrayOfAbsorptionLines& abs_lines_per_species,
897  const ArrayOfArrayOfSpeciesTag& abs_species,
898  const SpeciesAuxData& isotopologue_ratios,
899  const SpeciesAuxData& partition_functions,
900  const Verbosity&)
901 {
902  checkIsotopologueRatios(abs_species, isotopologue_ratios);
903  checkPartitionFunctions(abs_species, partition_functions);
904 
905  lbl_checked = false;
906 
907  if (abs_lines_per_species.nelem() not_eq abs_species.nelem()) {
909  os << "abs_lines_per_species and abs_species must have same length.\n"
910  << "Instead len(abs_lines_per_species) = "
911  << abs_lines_per_species.nelem()
912  << " and len(abs_species) = "
913  << abs_species.nelem()
914  << '\n';
915  throw std::runtime_error(os.str());
916  }
917 
918  for (Index i=0; i<abs_species.nelem(); i++) {
919  auto& specs = abs_species[i];
920  auto& lines = abs_lines_per_species[i];
921 
922  if (not specs.nelem()) {
923  if (not lines.nelem()) {
924  continue;
925  } else {
926  throw std::runtime_error("Lines for non-existent species discovered!\n");
927  }
928  }
929 
930  const bool any_zeeman = std::any_of(specs.cbegin(), specs.cend(), [](auto& x){return x.Type() == SpeciesTag::TYPE_ZEEMAN;});
931  if (any_zeeman and (not std::all_of(specs.cbegin(), specs.cend(), [](auto& x){return x.Type() == SpeciesTag::TYPE_ZEEMAN;}))) {
933  os << "Zeeman species found but not all sub-species tags support Zeeman effect.\n";
934  os << "Offending tag: " << specs << '\n';
935  throw std::runtime_error(os.str());
936  }
937 
938  if (any_zeeman) {
939  for (auto& band: lines) {
940  for (Index k=0; k<band.NumLines(); k++) {
941  auto Fu = band.UpperQuantumNumber(k, QuantumNumberType::F);
942  auto Fl = band.LowerQuantumNumber(k, QuantumNumberType::F);
943  auto Ju = band.UpperQuantumNumber(k, QuantumNumberType::J);
944  auto Jl = band.LowerQuantumNumber(k, QuantumNumberType::J);
945  auto Ze = band.Line(k).Zeeman();
946  if (Fu.isUndefined() and Ju.isUndefined()) {
947  throw std::runtime_error("Bad upper state F(s) or J(s).\n");
948  } else if (Fl.isUndefined() and Jl.isUndefined()) {
949  throw std::runtime_error("Bad lower state F(s) or J(s).\n");
950  } else if (not is_wigner3_ready(Fu.isUndefined() ? Ju : Fu)) {
951  throw std::runtime_error("Bad Wigner numbers for lower state F or J. Try increasing the Wigner memory allocation.\n");
952  } else if (not is_wigner3_ready(Fl.isUndefined() ? Jl : Fl)) {
953  throw std::runtime_error("Bad Wigner numbers for lower state F or J. Try increasing the Wigner memory allocation.\n");
954  } else if (Ze.gu() == 0 ? false : not std::isnormal(Ze.gu())) {
955  throw std::runtime_error("Bad value(s) in the upper Zeeman data not allowed when modeling Zeeman effect.\n");
956  } else if (Ze.gl() == 0 ? false : not std::isnormal(Ze.gl())) {
957  throw std::runtime_error("Bad value(s) in the lower Zeeman data not allowed when modeling Zeeman effect.\n");
958  }
959  }
960  }
961  } else /*if (not any any_zeeman)*/ {
962  }
963 
964  // Checks per band
965  for (auto& band: lines) {
966  if (band.Mirroring() not_eq Absorption::MirroringType::Manual and std::any_of(band.AllLines().cbegin(), band.AllLines().cend(), [](auto& x){return x.F0() <= 0;})) {
967  throw std::runtime_error("Negative or zero frequency in non-Manual mirrored band.\n");
968  }
969  }
970  }
971 
972  lbl_checked = true;
973 }
974 
975 /* Workspace method: Doxygen documentation will be auto-generated */
977  Workspace& ws _U_,
978  Index& propmat_clearsky_agenda_checked,
979  // WS Input:
980  const ArrayOfArrayOfSpeciesTag& abs_species,
981  const Agenda& propmat_clearsky_agenda,
982  const Verbosity&) {
983  bool needs_lines = false;
984  bool needs_zeeman = false;
985  bool needs_continua = false;
986  bool needs_cia = false;
987  //bool needs_free_electrons = false;
988  bool needs_particles = false;
989  bool needs_hxsec = false;
990 
991  for (Index sp = 0; sp < abs_species.nelem(); sp++) {
992  for (Index tgs = 0; tgs < abs_species[sp].nelem(); tgs++) {
993  switch (abs_species[sp][tgs].Type()) {
995  needs_lines = true;
996  break;
998  needs_zeeman = true;
999  break;
1001  needs_continua = true;
1002  break;
1003  case SpeciesTag::TYPE_CIA:
1004  needs_cia = true;
1005  break;
1007  break;
1009  needs_particles = true;
1010  break;
1012  needs_hxsec = true;
1013  break;
1014  default:
1015  ostringstream os;
1016  os << "Unknown species type: " << abs_species[sp][tgs].Type();
1017  throw runtime_error(os.str());
1018  break;
1019  }
1020  }
1021  }
1022 
1023  if ((needs_lines || needs_continua || needs_cia || needs_hxsec) &&
1024  !(propmat_clearsky_agenda.has_method("propmat_clearskyAddOnTheFly") ||
1025  propmat_clearsky_agenda.has_method("propmat_clearskyAddFromLookup"))) {
1026  throw runtime_error(
1027  "*abs_species* contains line species, CIA species, "
1028  "hitran xsec species or continua but *propmat_clearsky_agenda*\n"
1029  "does not contain *propmat_clearskyAddOnTheFly* nor "
1030  "*propmat_clearskyAddFromLookup*.");
1031  }
1032 
1033  if (needs_zeeman and
1034  not propmat_clearsky_agenda.has_method("propmat_clearskyAddZeeman")) {
1035  throw runtime_error(
1036  "*abs_species* contains Zeeman species but *propmat_clearsky_agenda*\n"
1037  "does not contain *propmat_clearskyAddZeeman*.");
1038  }
1039  /*
1040  if (needs_free_electrons
1041  && !propmat_clearsky_agenda.has_method("propmat_clearskyAddFaraday"))
1042  {
1043  throw runtime_error("*abs_species* contains free electrons but *propmat_clearsky_agenda*\n"
1044  "does not contain *propmat_clearskyAddFaraday*.");
1045  }
1046 */
1047  if (needs_particles &&
1048  !(propmat_clearsky_agenda.has_method("propmat_clearskyAddParticles") ||
1049  propmat_clearsky_agenda.has_method("propmat_clearskyAddParticles2"))) {
1050  throw runtime_error(
1051  "*abs_species* contains particles but *propmat_clearsky_agenda*\n"
1052  "does not contain *propmat_clearskyAddParticles*.");
1053  }
1054 
1055  propmat_clearsky_agenda_checked = 1;
1056 }
1057 
1058 /* Workspace method: Doxygen documentation will be auto-generated */
1059 void sensor_checkedCalc(Index& sensor_checked,
1060  const Index& atmosphere_dim,
1061  const Index& stokes_dim,
1062  const Vector& f_grid,
1063  const Matrix& sensor_pos,
1064  const Matrix& sensor_los,
1065  const Matrix& transmitter_pos,
1066  const Matrix& mblock_dlos_grid,
1067  const Sparse& sensor_response,
1068  const Vector& sensor_response_f,
1069  const ArrayOfIndex& sensor_response_pol,
1070  const Matrix& sensor_response_dlos,
1071  const Verbosity&) {
1072  // Some sizes
1073  const Index nf = f_grid.nelem();
1074  const Index nlos = mblock_dlos_grid.nrows();
1075  const Index n1y = sensor_response.nrows();
1076  const Index nmblock = sensor_pos.nrows();
1077  const Index niyb = nf * nlos * stokes_dim;
1078 
1079  // Sensor position and LOS.
1080  //
1081  if (!is_increasing(f_grid))
1082  throw runtime_error("*f_grid* must be a strictly increasing vector.");
1083 
1084  // Sensor position and LOS.
1085  //
1086  if (sensor_pos.empty())
1087  throw runtime_error("*sensor_pos* is empty. This is not allowed.");
1088  if (sensor_los.empty())
1089  throw runtime_error("*sensor_los* is empty. This is not allowed.");
1090  //
1091  if (sensor_pos.ncols() != atmosphere_dim)
1092  throw runtime_error(
1093  "The number of columns of sensor_pos must be "
1094  "equal to the atmospheric dimensionality.");
1095  if (atmosphere_dim <= 2 && sensor_los.ncols() != 1)
1096  throw runtime_error("For 1D and 2D, sensor_los shall have one column.");
1097  if (atmosphere_dim == 3 && sensor_los.ncols() != 2)
1098  throw runtime_error("For 3D, sensor_los shall have two columns.");
1099  if (sensor_los.nrows() != nmblock) {
1100  ostringstream os;
1101  os << "The number of rows of sensor_pos and sensor_los must be "
1102  << "identical, but sensor_pos has " << nmblock << " rows,\n"
1103  << "while sensor_los has " << sensor_los.nrows() << " rows.";
1104  throw runtime_error(os.str());
1105  }
1106  if (max(sensor_los(joker, 0)) > 180)
1107  throw runtime_error(
1108  "First column of *sensor_los* is not allowed to have values above 180.");
1109  if (atmosphere_dim == 2) {
1110  if (min(sensor_los(joker, 0)) < -180)
1111  throw runtime_error(
1112  "For atmosphere_dim = 2, first column of "
1113  "*sensor_los* is not allowed to have values below -180.");
1114  } else {
1115  if (min(sensor_los(joker, 0)) < 0)
1116  throw runtime_error(
1117  "For atmosphere_dim != 2, first column of "
1118  "*sensor_los* is not allowed to have values below 0.");
1119  }
1120  if (atmosphere_dim == 3) {
1121  if (max(sensor_los(joker, 1)) > 180)
1122  throw runtime_error(
1123  "Second column of *sensor_los* is not allowed to have values above 180.");
1124  else if (min(sensor_los(joker, 1)) < -180)
1125  throw runtime_error(
1126  "Second column of *sensor_los* is not allowed to have values below -180.");
1127  }
1128 
1129  // Transmission position.
1130  if (transmitter_pos.ncols() > 0 && transmitter_pos.nrows() > 0) {
1131  if (transmitter_pos.nrows() != sensor_pos.nrows())
1132  throw runtime_error(
1133  "*transmitter_pos* must either be empty or have "
1134  "the same number of rows as *sensor_pos*.");
1135  if (transmitter_pos.ncols() != max(Index(2), atmosphere_dim))
1136  throw runtime_error(
1137  "*transmitter_pos* must either be empty, have "
1138  "2 for 1D/2D or 3 columns for 3D.");
1139  }
1140 
1141  // mblock_dlos_grid
1142  //
1143  if (mblock_dlos_grid.empty())
1144  throw runtime_error("*mblock_dlos_grid* is empty.");
1145  if (mblock_dlos_grid.ncols() > 2)
1146  throw runtime_error(
1147  "The maximum number of columns in *mblock_dlos_grid* is two.");
1148  if (atmosphere_dim < 3) {
1149  if (mblock_dlos_grid.ncols() != 1)
1150  throw runtime_error(
1151  "For 1D and 2D *mblock_dlos_grid* must have exactly one column.");
1152  }
1153 
1154  // Sensor
1155  //
1156  if (sensor_response.ncols() != niyb) {
1157  ostringstream os;
1158  os << "The *sensor_response* matrix does not have the right size,\n"
1159  << "either the method *sensor_responseInit* has not been run or some\n"
1160  << "of the other sensor response methods has not been correctly\n"
1161  << "configured.";
1162  throw runtime_error(os.str());
1163  }
1164 
1165  // Sensor aux variables
1166  //
1167  if (n1y != sensor_response_f.nelem() || n1y != sensor_response_pol.nelem() ||
1168  n1y != sensor_response_dlos.nrows()) {
1169  ostringstream os;
1170  os << "Sensor auxiliary variables do not have the correct size.\n"
1171  << "The following variables should all have same size:\n"
1172  << "length of y for one block : " << n1y << "\n"
1173  << "sensor_response_f.nelem() : " << sensor_response_f.nelem()
1174  << "\nsensor_response_pol.nelem() : " << sensor_response_pol.nelem()
1175  << "\nsensor_response_dlos.nrows(): " << sensor_response_dlos.nrows()
1176  << "\n";
1177  throw runtime_error(os.str());
1178  }
1179 
1180  // If here, all OK
1181  sensor_checked = 1;
1182 }
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
void scat_data_checkedCalc(Index &scat_data_checked, const ArrayOfArrayOfSingleScatteringData &scat_data, const Vector &f_grid, const Numeric &dfrel_threshold, const String &check_level, const Numeric &sca_mat_threshold, const Verbosity &verbosity)
WORKSPACE METHOD: scat_data_checkedCalc.
Definition: m_checked.cc:741
The Agenda class.
Definition: agenda_class.h:44
Index nelem() const
Number of elements.
Definition: array.h:195
bool empty() const
Returns true if variable size is zero.
Definition: matpackI.cc:426
void atmgeom_checkedCalc(Index &atmgeom_checked, const Index &atmosphere_dim, const Vector &p_grid, const Vector &lat_grid, const Vector &lon_grid, const Tensor3 &z_field, const Vector &refellipsoid, const Matrix &z_surface, const Vector &lat_true, const Vector &lon_true, const Verbosity &)
WORKSPACE METHOD: atmgeom_checkedCalc.
Definition: m_checked.cc:383
void scat_dataCheck(const ArrayOfArrayOfSingleScatteringData &scat_data, const String &check_type, const Numeric &threshold, const Verbosity &verbosity)
WORKSPACE METHOD: scat_dataCheck.
void chk_atm_surface(const String &x_name, const Matrix &x, const Index &dim, ConstVectorView lat_grid, ConstVectorView lon_grid)
chk_atm_surface
void chk_if_increasing(const String &x_name, const ArrayOfIndex &x)
chk_if_increasing
Definition: check_input.cc:117
The Vector class.
Definition: matpackI.h:860
#define abs(x)
bool is_increasing(ConstVectorView x)
Checks if a vector is sorted and strictly increasing.
Definition: logic.cc:215
The Sparse class.
Definition: matpackII.h:60
The Tensor4 class.
Definition: matpackIV.h:421
const Numeric LAT_LON_MIN
bool empty() const
Returns true if variable size is zero.
Definition: matpackI.cc:49
Index ncols() const
Returns the number of columns.
Definition: matpackII.cc:69
bool empty() const
Check if variable is empty.
Definition: matpackIII.cc:38
void chk_if_bool(const String &x_name, const Index &x)
chk_if_bool
Definition: check_input.cc:65
#define min(a, b)
Index nrows() const
Returns the number of rows.
Definition: matpackIII.h:147
G0 G2 FVC Y DV Numeric Numeric Numeric Zeeman LowerQuantumNumbers void * data
void atmfields_checkedCalc(Index &atmfields_checked, const Index &atmosphere_dim, const Vector &p_grid, const Vector &lat_grid, const Vector &lon_grid, const ArrayOfArrayOfSpeciesTag &abs_species, const Tensor3 &t_field, const Tensor4 &vmr_field, const Tensor3 &wind_u_field, const Tensor3 &wind_v_field, const Tensor3 &wind_w_field, const Tensor3 &mag_u_field, const Tensor3 &mag_v_field, const Tensor3 &mag_w_field, const SpeciesAuxData &partition_functions, const Index &abs_f_interp_order, const Index &negative_vmr_ok, const Index &bad_partition_functions_ok, const Verbosity &)
WORKSPACE METHOD: atmfields_checkedCalc.
Definition: m_checked.cc:125
Index nelem() const
Returns the number of elements.
Definition: matpackI.cc:51
Index ncols() const
Returns the number of columns.
Definition: matpackI.cc:432
const AuxType & getParamType(const Index species, const Index isotopologue) const
Return a constant reference to the parameter types.
Definition: absorption.h:276
The Tensor3 class.
Definition: matpackIII.h:339
Index TotalNumberOfElements(const Array< Array< base > > &aa)
Determine total number of elements in an ArrayOfArray.
Definition: array.h:343
The global header file for ARTS.
bool has_method(const String &methodname) const
Check if method is in Agenda.
bool is_same_within_epsilon(const Numeric &a, const Numeric &b, const Numeric &epsilon)
Check, if two numbers agree within a given epsilon.
Definition: logic.cc:351
_CS_string_type str() const
Definition: sstream.h:491
const Numeric DEG2RAD
Index ncols() const
Returns the number of columns.
Definition: matpackIII.h:150
void toupper()
Convert to upper case.
Definition: mystring.h:74
Index nrows() const
Returns the number of rows.
Definition: matpackII.cc:66
A tag group can consist of the sum of several of these.
Index find_first_species_tg(const ArrayOfArrayOfSpeciesTag &tgs, const Index &spec)
Find first occurrence of species in tag groups.
const Joker joker
const ArrayOfGriddedField1 & getParam(const Index species, const Index isotopologue) const
Return a constant reference to the parameters.
Definition: absorption.cc:145
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
The Matrix class.
Definition: matpackI.h:1193
Index nspecies() const
Returns number of species.
Definition: absorption.h:239
void chk_atm_vecfield_lat90(const String &x1_name, ConstTensor3View x1, const String &x2_name, ConstTensor3View x2, const Index &dim, ConstVectorView lat_grid, const Numeric &threshold)
chk_atm_vecfield_lat90
Implementation of Matrix, Vector, and such stuff.
Index nisotopologues(const Index species) const
Returns number of isotopologues for a certain species.
Definition: absorption.h:242
basic_ostringstream< char, string_char_traits< char >, alloc > ostringstream
Definition: sstream.h:204
Index npages() const
Returns the number of pages.
Definition: matpackIII.h:144
bool is_wigner3_ready(const Rational &J)
Tells if the function is ready for Wigner 3J calculations.
void chk_if_in_range(const String &x_name, const Index &x, const Index &x_low, const Index &x_high)
chk_if_in_range
Definition: check_input.cc:89
void checkIsotopologueRatios(const ArrayOfArrayOfSpeciesTag &abs_species, const SpeciesAuxData &isoratios)
Check that isotopologue ratios for the given species are correctly defined.
Definition: absorption.cc:301
void checkPartitionFunctions(const ArrayOfArrayOfSpeciesTag &abs_species, const SpeciesAuxData &partfun)
Check that partition functions for the given species are correctly defined.
Definition: absorption.cc:356
void resize(Index n)
Resize function.
Definition: matpackI.cc:404
void propmat_clearsky_agenda_checkedCalc(Workspace &ws, Index &propmat_clearsky_agenda_checked, const ArrayOfArrayOfSpeciesTag &abs_species, const Agenda &propmat_clearsky_agenda, const Verbosity &)
WORKSPACE METHOD: propmat_clearsky_agenda_checkedCalc.
Definition: m_checked.cc:976
#define max(a, b)
void sensor_checkedCalc(Index &sensor_checked, const Index &atmosphere_dim, const Index &stokes_dim, const Vector &f_grid, const Matrix &sensor_pos, const Matrix &sensor_los, const Matrix &transmitter_pos, const Matrix &mblock_dlos_grid, const Sparse &sensor_response, const Vector &sensor_response_f, const ArrayOfIndex &sensor_response_pol, const Matrix &sensor_response_dlos, const Verbosity &)
WORKSPACE METHOD: sensor_checkedCalc.
Definition: m_checked.cc:1059
void chk_atm_field(const String &x_name, ConstTensor3View x, const Index &dim, ConstVectorView p_grid, ConstVectorView lat_grid, ConstVectorView lon_grid, const bool &chk_lat90)
chk_atm_field (simple fields)
Workspace class.
Definition: workspace_ng.h:40
void cloudbox_checkedCalc(Index &cloudbox_checked, const Index &atmfields_checked, const Index &atmosphere_dim, const Vector &p_grid, const Vector &lat_grid, const Vector &lon_grid, const Tensor3 &z_field, const Matrix &z_surface, const Tensor3 &wind_u_field, const Tensor3 &wind_v_field, const Tensor3 &wind_w_field, const Index &cloudbox_on, const ArrayOfIndex &cloudbox_limits, const Tensor4 &pnd_field, const ArrayOfTensor4 &dpnd_field_dx, const ArrayOfRetrievalQuantity &jacobian_quantities, const ArrayOfArrayOfSingleScatteringData &scat_data, const ArrayOfString &scat_species, const Matrix &particle_masses, const ArrayOfArrayOfSpeciesTag &abs_species, const Index &negative_pnd_ok, const Verbosity &)
WORKSPACE METHOD: cloudbox_checkedCalc.
Definition: m_checked.cc:484
#define _U_
Definition: config.h:183
void abs_xsec_agenda_checkedCalc(Workspace &ws, Index &abs_xsec_agenda_checked, const ArrayOfArrayOfSpeciesTag &abs_species, const Agenda &abs_xsec_agenda, const Verbosity &)
WORKSPACE METHOD: abs_xsec_agenda_checkedCalc.
Definition: m_checked.cc:44
Auxiliary data for isotopologues.
Definition: absorption.h:217
Internal cloudbox functions.
void lbl_checkedCalc(Index &lbl_checked, const ArrayOfArrayOfAbsorptionLines &abs_lines_per_species, const ArrayOfArrayOfSpeciesTag &abs_species, const SpeciesAuxData &isotopologue_ratios, const SpeciesAuxData &partition_functions, const Verbosity &)
WORKSPACE METHOD: lbl_checkedCalc.
Definition: m_checked.cc:895
void chk_atm_grids(const Index &dim, ConstVectorView p_grid, ConstVectorView lat_grid, ConstVectorView lon_grid)
chk_atm_grids
Index nrows() const
Returns the number of rows.
Definition: matpackI.cc:429