ARTS 2.5.10 (git: 2f1c442c)
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 "arts_conversions.h"
37#include "auto_md.h"
38#include "check_input.h"
39#include "cloudbox.h"
40#include "matpackI.h"
41#include "wigner_functions.h"
42
45
46/* Workspace method: Doxygen documentation will be auto-generated */
48 Index& abs_xsec_agenda_checked,
49 // WS Input:
50 const ArrayOfArrayOfSpeciesTag& abs_species,
51 const Agenda& abs_xsec_agenda,
52 const Verbosity&) {
53 bool needs_continua = false;
54 bool needs_cia = false;
55 // bool needs_hxsec = false;
56
57 for (Index sp = 0; sp < abs_species.nelem(); sp++) {
58 for (Index tgs = 0; tgs < abs_species[sp].nelem(); tgs++) {
59 switch (abs_species[sp][tgs].Type()) {
60 case Species::TagType::Plain:
61 break;
62 case Species::TagType::Zeeman:
63 break;
64 case Species::TagType::Predefined:
65 break;
66 case Species::TagType::Cia:
67 needs_cia = true;
68 break;
69 case Species::TagType::FreeElectrons:
70 break;
71 case Species::TagType::Particles:
72 break;
73 case Species::TagType::XsecFit:
74 // needs_hxsec = true;
75 break;
76 default:
77 ARTS_USER_ERROR ("Unknown species type: ", abs_species[sp][tgs].Type())
78 break;
79 }
80 }
81 }
82
83 ARTS_USER_ERROR_IF (needs_continua &&
84 !abs_xsec_agenda.has_method("abs_xsec_per_speciesAddConts"),
85 "*abs_species* contains continuum species but *abs_xsec_agenda*\n"
86 "does not contain *abs_xsec_per_speciesAddConts*.");
87
88 ARTS_USER_ERROR_IF (needs_cia && !abs_xsec_agenda.has_method("abs_xsec_per_speciesAddCIA"),
89 "*abs_species* contains CIA species but *abs_xsec_agenda*\n"
90 "does not contain *abs_xsec_per_speciesAddCIA*.");
91
92 // If here, all OK
93 abs_xsec_agenda_checked = 1;
94}
95
96/* Workspace method: Doxygen documentation will be auto-generated */
97void atmfields_checkedCalc(Index& atmfields_checked,
98 const Index& atmosphere_dim,
99 const Vector& p_grid,
100 const Vector& lat_grid,
101 const Vector& lon_grid,
102 const ArrayOfArrayOfSpeciesTag& abs_species,
103 const Tensor3& t_field,
104 const Tensor4& vmr_field,
105 const Tensor3& wind_u_field,
106 const Tensor3& wind_v_field,
107 const Tensor3& wind_w_field,
108 const Tensor3& mag_u_field,
109 const Tensor3& mag_v_field,
110 const Tensor3& mag_w_field,
111 const Index& abs_f_interp_order,
112 const Index& negative_vmr_ok,
113 const Verbosity&) {
114 // Consistency between dim, grids and atmospheric fields/surfaces
115 chk_if_in_range("atmosphere_dim", atmosphere_dim, 1, 3);
116 chk_atm_grids(atmosphere_dim, p_grid, lat_grid, lon_grid);
117 chk_atm_field("t_field", t_field, atmosphere_dim, p_grid, lat_grid, lon_grid);
118 chk_atm_field("vmr_field",
119 vmr_field,
120 atmosphere_dim,
121 abs_species.nelem(),
122 p_grid,
123 lat_grid,
124 lon_grid);
125
126 // More for vmr_field.
127 ARTS_USER_ERROR_IF (!negative_vmr_ok && abs_species.nelem() && min(vmr_field) < 0,
128 "All values in *vmr_field* must be >= 0.");
129
130 // More for t_field.
131 ARTS_USER_ERROR_IF (min(t_field) <= 0,
132 "All temperatures in *t_field* must be > 0.");
133
134 // Winds
135 if (wind_w_field.npages() > 0) {
136 chk_atm_field("wind_w_field",
137 wind_w_field,
138 atmosphere_dim,
139 p_grid,
140 lat_grid,
141 lon_grid);
142 }
143 if (atmosphere_dim < 3 && wind_v_field.npages() > 0) {
144 chk_atm_field("wind_v_field",
145 wind_v_field,
146 atmosphere_dim,
147 p_grid,
148 lat_grid,
149 lon_grid);
150 }
151 if (atmosphere_dim > 2) {
152 if (wind_u_field.npages() > 0) {
153 if (wind_v_field.npages() > 0) {
154 bool chk_poles = false;
155 chk_atm_field("wind_u_field",
156 wind_u_field,
157 atmosphere_dim,
158 p_grid,
159 lat_grid,
160 lon_grid,
161 chk_poles);
162 chk_atm_field("wind_v_field",
163 wind_v_field,
164 atmosphere_dim,
165 p_grid,
166 lat_grid,
167 lon_grid,
168 chk_poles);
169 chk_atm_vecfield_lat90("wind_v_field",
170 wind_v_field,
171 "wind_u_field",
172 wind_u_field,
173 atmosphere_dim,
174 lat_grid);
175 } else {
176 chk_atm_field("wind_u_field",
177 wind_u_field,
178 atmosphere_dim,
179 p_grid,
180 lat_grid,
181 lon_grid);
182 }
183 } else {
184 if (wind_v_field.npages() > 0) {
185 chk_atm_field("wind_v_field",
186 wind_v_field,
187 atmosphere_dim,
188 p_grid,
189 lat_grid,
190 lon_grid);
191 }
192 }
193 }
194
195 // If any of the wind fields exist, abs_f_interp_order must not be zero.
196 if (wind_u_field.npages() > 0 || wind_v_field.npages() > 0 ||
197 wind_w_field.npages() > 0) {
198 ARTS_USER_ERROR_IF (abs_f_interp_order == 0,
199 "You have a wind field set, but abs_f_interp_order zero.\n"
200 "This is not allowed. Though abs_f_interp_order only is\n"
201 "required and has an effect if absorption lookup tables\n"
202 "are used, for safety reasons you also have to set it >0\n"
203 "in case of on-the-fly absorption.")
204 }
205
206 // Magnetic field
207 if (mag_w_field.npages() > 0) {
208 chk_atm_field("mag_w_field (vertical magfield component)",
209 mag_w_field,
210 atmosphere_dim,
211 p_grid,
212 lat_grid,
213 lon_grid);
214 }
215 if (mag_u_field.npages() > 0) {
216 if (mag_v_field.npages() > 0) {
217 bool chk_poles = false;
218 chk_atm_field("mag_v_field",
219 mag_v_field,
220 atmosphere_dim,
221 p_grid,
222 lat_grid,
223 lon_grid,
224 chk_poles);
225 chk_atm_field("mag_u_field",
226 mag_u_field,
227 atmosphere_dim,
228 p_grid,
229 lat_grid,
230 lon_grid,
231 chk_poles);
232 chk_atm_vecfield_lat90("mag_v_field",
233 mag_v_field,
234 "mag_u_field",
235 mag_u_field,
236 atmosphere_dim,
237 lat_grid);
238 } else {
239 chk_atm_field("mag_u_field",
240 mag_u_field,
241 atmosphere_dim,
242 p_grid,
243 lat_grid,
244 lon_grid);
245 }
246 } else {
247 if (mag_v_field.npages() > 0) {
248 chk_atm_field("mag_v_field",
249 mag_v_field,
250 atmosphere_dim,
251 p_grid,
252 lat_grid,
253 lon_grid);
254 }
255 }
256
257 // If here, all OK
258 atmfields_checked = 1;
259}
260
261/* Workspace method: Doxygen documentation will be auto-generated */
262void atmgeom_checkedCalc(Index& atmgeom_checked,
263 const Index& atmosphere_dim,
264 const Vector& p_grid,
265 const Vector& lat_grid,
266 const Vector& lon_grid,
267 const Tensor3& z_field,
268 const Vector& refellipsoid,
269 const Matrix& z_surface,
270 const Vector& lat_true,
271 const Vector& lon_true,
272 const Numeric& max500hpa_gradient,
273 const Verbosity&) {
274 // A repetition from atmfields_checked, but we do this to make the two parts
275 // independent (the other option would be to demand atmfields_checkec == 1)
276 chk_if_in_range("atmosphere_dim", atmosphere_dim, 1, 3);
277 chk_atm_grids(atmosphere_dim, p_grid, lat_grid, lon_grid);
278
279 // *refellipsoid*
280 ARTS_USER_ERROR_IF (refellipsoid.nelem() != 2,
281 "The WSV *refellispoid* must be a vector of "
282 "length 2*.");
283 ARTS_USER_ERROR_IF (refellipsoid[0] <= 0,
284 "The first element of *refellipsoid* must "
285 "be > 0.");
286 ARTS_USER_ERROR_IF (refellipsoid[1] < 0 || refellipsoid[1] > 1,
287 "The second element of *refellipsoid* must be "
288 "inside [0,1].");
289 ARTS_USER_ERROR_IF (atmosphere_dim == 1 && refellipsoid[1] != 0,
290 "For 1D, the second element of *refellipsoid* "
291 "(the eccentricity) must be 0.");
292
293 chk_atm_field("z_field", z_field, atmosphere_dim, p_grid, lat_grid, lon_grid);
294 chk_atm_surface("z_surface", z_surface, atmosphere_dim, lat_grid, lon_grid);
295
296 // Check that z_field has strictly increasing pages.
297 for (Index row = 0; row < z_field.nrows(); row++) {
298 for (Index col = 0; col < z_field.ncols(); col++) {
299 ostringstream os;
300 os << "z_field (for latitude nr " << row << " and longitude nr " << col
301 << ")";
302 chk_if_increasing(os.str(), z_field(joker, row, col));
303 }
304 }
305
306 // Check that there is no gap between the surface and lowest pressure
307 // level
308 // (A copy of this code piece is found in z_fieldFromHSE. Make this to an
309 // internal function if used in more places.)
310 for (Index row = 0; row < z_surface.nrows(); row++) {
311 for (Index col = 0; col < z_surface.ncols(); col++) {
312 ARTS_USER_ERROR_IF (z_surface(row, col) < z_field(0, row, col) ||
313 z_surface(row, col) >= z_field(z_field.npages() - 1, row, col),
314 "The surface altitude (*z_surface*) cannot be outside\n"
315 "of the altitudes in *z_field*.\n"
316 "z_surface: ", z_surface(row, col), "\n"
317 "min of z_field: ", z_field(0, row, col), "\n"
318 "max of z_field: ", z_field(z_field.npages() - 1, row, col),
319 "\n",
320 (atmosphere_dim > 1) ? var_string("\nThis was found to be the case for:\n", "latitude ", lat_grid[row]) : var_string(),
321 (atmosphere_dim > 2) ? var_string("\nlongitude ", lon_grid[col]) : var_string())
322 }
323 }
324
325 // A rough check of gradients in the 500 hPa level (or closest pressure level)
326 // This check is just run in the latitude direction, along some longitudes to
327 // save time
328 if (atmosphere_dim > 1) {
329 // Find 500 hPa
330 Index ip = -1; Numeric dpmin = 99e99;
331 for (Index i=0; i<p_grid.nelem(); i++) {
332 const Numeric dp = abs(p_grid[i] - 500e2);
333 if (dp < dpmin) {
334 ip = i;
335 dpmin = dp;
336 }
337 }
338 Numeric maxgrad = -1;
339 for (Index ilon=0; ilon<max(1,lon_grid.nelem()); ilon += 10) {
340 for (Index ilat=1; ilat<lat_grid.nelem(); ilat++) {
341 const Numeric grad = abs((z_field(ip,ilat,ilon)-z_field(ip,ilat-1,ilon)) /
342 (lat_grid[ilat]-lat_grid[ilat-1]));
343 if (grad > maxgrad)
344 maxgrad = grad;
345 }
346 }
347 // Scale to change over 100 km
348 maxgrad *= 100.0/111.0;
349 if (maxgrad > max500hpa_gradient) {
350 ostringstream os;
351 os << "A check of the altitude of the " << p_grid[ip]/100
352 << " hPa level has been made.\nThe maximum gradient found matches "
353 << maxgrad << " m/100km, that exceeds\nthe set limit of "
354 << max500hpa_gradient << " m/100km (by GIN *max500hpa_gradient*).\n"
355 << "Please check the smoothness of *z_field*.";
356 throw runtime_error(os.str());
357 }
358 }
359
360 // lat/lon true
361 if (atmosphere_dim < 3 && (lat_true.nelem() || lon_true.nelem())) {
362 if (atmosphere_dim == 1) {
363 ARTS_USER_ERROR_IF (lat_true.nelem() != 1,
364 "For 1D, *lat_true* must have length 1.");
365 ARTS_USER_ERROR_IF (lon_true.nelem() != 1,
366 "For 1D, *lon_true* must have length 1.");
367 } else if (atmosphere_dim == 2) {
368 ARTS_USER_ERROR_IF (lat_true.nelem() != lat_grid.nelem(),
369 "For 2D, *lat_true* must have same length as *lat_grid*.");
370 ARTS_USER_ERROR_IF (lon_true.nelem() != lat_grid.nelem(),
371 "For 2D, *lon_true* must have same length as *lat_grid*.");
372 }
373 ARTS_USER_ERROR_IF (lon_true.nelem() != lat_true.nelem(),
374 "If *lat_true* is set, also *lon_true* must be "
375 "set (and have the same length).");
376 ARTS_USER_ERROR_IF (min(lat_true) < -90 || max(lat_true) > 90,
377 "Values in *lat_true* must be inside [-90,90].");
378 ARTS_USER_ERROR_IF (min(lon_true) < -180 || max(lon_true) > 360,
379 "Values in *lon_true* must be inside [-180,360].");
380 }
381
382 // If here, all OK
383 atmgeom_checked = 1;
384}
385
386/* Workspace method: Doxygen documentation will be auto-generated */
387void cloudbox_checkedCalc(Index& cloudbox_checked,
388 const Index& atmfields_checked,
389 const Index& atmosphere_dim,
390 const Vector& p_grid,
391 const Vector& lat_grid,
392 const Vector& lon_grid,
393 const Tensor3& z_field,
394 const Matrix& z_surface,
395 const Tensor3& wind_u_field,
396 const Tensor3& wind_v_field,
397 const Tensor3& wind_w_field,
398 const Index& cloudbox_on,
399 const ArrayOfIndex& cloudbox_limits,
400 const Tensor4& pnd_field,
401 const ArrayOfTensor4& dpnd_field_dx,
402 const ArrayOfRetrievalQuantity& jacobian_quantities,
403 const ArrayOfArrayOfSingleScatteringData& scat_data,
404 const ArrayOfString& scat_species,
405 const Matrix& particle_masses,
406 const ArrayOfArrayOfSpeciesTag& abs_species,
407 const Index& demand_latlon_margin,
408 const Index& negative_pnd_ok,
409 const Verbosity&) {
410 ARTS_USER_ERROR_IF (atmfields_checked != 1,
411 "The atmospheric fields must be flagged to have "
412 "passed a consistency check (atmfields_checked=1).");
413
414 chk_if_bool("cloudbox_on", cloudbox_on);
415
416 if (cloudbox_on) {
417 // Winds, must be empty variables (i.e. no winds allowed)
418 ARTS_USER_ERROR_IF (!wind_w_field.empty() ||
419 !wind_v_field.empty() ||
420 !wind_u_field.empty(),
421 "The scattering methods are not (yet?) handling winds. For this\n"
422 "reason, the WSVs for wind fields must all be empty with an\n."
423 "active cloudbox.");
424
425 // no "particles" in abs_species if cloudbox is on (they act on the same
426 // scat_data! and there is no good reason to have some particles as
427 // abs-only, if we anyway do a scattering calculation.).
428 Index has_absparticles = 0;
429 for (Index sp = 0; sp < abs_species.nelem() && has_absparticles < 1; sp++) {
430 if (abs_species[sp].Particles()) {
431 has_absparticles = 1;
432 }
433 }
434 ARTS_USER_ERROR_IF (has_absparticles,
435 "For scattering calculations (cloudbox is on),"
436 "abs_species is not allowed to contain\n"
437 "'particles' (absorbing-only particles)!");
438
439 // Cloudbox limits
440 ARTS_USER_ERROR_IF (cloudbox_limits.nelem() != atmosphere_dim * 2,
441 "The array *cloudbox_limits* has incorrect length.\n"
442 "For atmospheric dim. = ", atmosphere_dim,
443 " the length shall be ", atmosphere_dim * 2, " but it is ",
444 cloudbox_limits.nelem(), ".")
445 ARTS_USER_ERROR_IF (cloudbox_limits[1] <= cloudbox_limits[0] || cloudbox_limits[0] < 0 ||
446 cloudbox_limits[1] >= p_grid.nelem(),
447 "Incorrect value(s) for cloud box pressure limit(s) found."
448 "\nValues are either out of range or upper limit is not "
449 "greater than lower limit.\nWith present length of "
450 "*p_grid*, OK values are 0 - ", p_grid.nelem() - 1,
451 ".\nThe pressure index limits are set to ", cloudbox_limits[0],
452 " - ", cloudbox_limits[1], ".")
453
454 Index nlat = 1, nlon = 1;
455
456 if (atmosphere_dim > 1) {
457 nlat = lat_grid.nelem();
458 if (demand_latlon_margin) {
459 ARTS_USER_ERROR_IF (cloudbox_limits[3] <= cloudbox_limits[2] ||
460 cloudbox_limits[2] < 1 ||
461 cloudbox_limits[3] >= nlat - 1,
462 "Incorrect value(s) for cloud box latitude limit(s) found."
463 "\nValues are either out of range or upper limit is not "
464 "greater than lower limit.\nWith present length of "
465 "*lat_grid* and demand_latlon_margin set to true, "
466 "OK values are 1 - ", nlat - 2,
467 ".\nThe latitude index limits are set to ", cloudbox_limits[2],
468 " - ", cloudbox_limits[3], ".")
469 ARTS_USER_ERROR_IF ((lat_grid[cloudbox_limits[2]] -
470 lat_grid[0] < LAT_LON_MIN) &&
471 (atmosphere_dim == 2 ||
472 (atmosphere_dim == 3 && lat_grid[0] > -90)),
473 "Too small distance between cloudbox and lower end of "
474 "latitude grid.\n"
475 "This distance must be ", LAT_LON_MIN, " degrees.\n"
476 "Cloudbox ends at ", lat_grid[cloudbox_limits[2]],
477 " and latitude grid starts at ", lat_grid[0], ".")
478 ARTS_USER_ERROR_IF ((lat_grid[nlat - 1] -
479 lat_grid[cloudbox_limits[3]] < LAT_LON_MIN) &&
480 (atmosphere_dim == 2 ||
481 (atmosphere_dim == 3 && lat_grid[nlat - 1] < 90)),
482 "Too small distance between cloudbox and upper end of "
483 "latitude grid.\n"
484 "This distance must be ", LAT_LON_MIN, " degrees.\n"
485 "Cloudbox ends at ", lat_grid[cloudbox_limits[3]],
486 " and latitude grid ends at ", lat_grid[nlat - 1], ".")
487 } else {
488 ARTS_USER_ERROR_IF (cloudbox_limits[3] <= cloudbox_limits[2] ||
489 cloudbox_limits[2] < 0 ||
490 cloudbox_limits[3] >= nlat,
491 "Incorrect value(s) for cloud box latitude limit(s) found."
492 "\nValues are either out of range or upper limit is not "
493 "greater than lower limit.\nWith present length of "
494 "*lat_grid* and demand_latlon_margin set to false, "
495 "OK values are 0 - ", nlat - 1,
496 ".\nThe latitude index limits are set to ", cloudbox_limits[2],
497 " - ", cloudbox_limits[3], ".")
498 }
499 }
500
501 if (atmosphere_dim > 2) {
502 nlon = lon_grid.nelem();
503 if (demand_latlon_margin) {
504 ARTS_USER_ERROR_IF (cloudbox_limits[5] <= cloudbox_limits[4] ||
505 cloudbox_limits[4] < 1 ||
506 cloudbox_limits[5] >= nlon - 1,
507 "Incorrect value(s) for cloud box longitude limit(s) found"
508 ".\nValues are either out of range or upper limit is not "
509 "greater than lower limit.\nWith present length of "
510 "*lon_grid* and demand_latlon_margin set to true,"
511 "OK values are 1 - ", nlon - 2,
512 ".\nThe longitude limits are set to ", cloudbox_limits[4],
513 " - ", cloudbox_limits[5], ".")
514 if (lon_grid[nlon - 1] - lon_grid[0] < 360) {
515 const Numeric latmax = max(abs(lat_grid[cloudbox_limits[2]]),
516 abs(lat_grid[cloudbox_limits[3]]));
517 const Numeric lfac = 1 / cos(DEG2RAD * latmax);
518 ARTS_USER_ERROR_IF (lon_grid[cloudbox_limits[4]] - lon_grid[0] <
519 LAT_LON_MIN / lfac,
520 "Too small distance between cloudbox and lower end of"
521 "the longitude\ngrid. This distance must here be ",
522 LAT_LON_MIN / lfac, " degrees.")
523 ARTS_USER_ERROR_IF (lon_grid[nlon - 1] - lon_grid[cloudbox_limits[5]] <
524 LAT_LON_MIN / lfac,
525 "Too small distance between cloudbox and upper end of"
526 "the longitude\ngrid. This distance must here be ",
527 LAT_LON_MIN / lfac, " degrees.")
528 }
529 } else {
530 ARTS_USER_ERROR_IF (cloudbox_limits[5] <= cloudbox_limits[4] ||
531 cloudbox_limits[4] < 0 ||
532 cloudbox_limits[5] >= nlon,
533 "Incorrect value(s) for cloud box longitude limit(s) found"
534 ".\nValues are either out of range or upper limit is not "
535 "greater than lower limit.\nWith present length of "
536 "*lon_grid* and demand_latlon_margin set to false,"
537 "OK values are 0 - ", nlon - 1,
538 ".\nThe longitude limits are set to ", cloudbox_limits[4],
539 " - ", cloudbox_limits[5], ".")
540 }
541 }
542
543 // Check with respect to z_surface
544 for (Index o = 0; o < nlon; o++) {
545 for (Index a = 0; a < nlat; a++) {
546 ARTS_USER_ERROR_IF (z_field(cloudbox_limits[1], a, o) <= z_surface(a, o),
547 "The upper vertical limit of the cloudbox must be above "
548 "the surface altitude (for all latitudes and longitudes).");
549 }
550 }
551
552 // Check pnd_field
553 //
554 const Index np = TotalNumberOfElements(scat_data);
555 // Dummy variables to mimic grids of correct size
556 Vector g1(cloudbox_limits[1] - cloudbox_limits[0] + 1), g2(0), g3(0);
557 if (atmosphere_dim > 1) {
558 g2.resize(cloudbox_limits[3] - cloudbox_limits[2] + 1);
559 }
560 if (atmosphere_dim > 2) {
561 g3.resize(cloudbox_limits[5] - cloudbox_limits[4] + 1);
562 }
563
564 chk_atm_field("pnd_field", pnd_field, atmosphere_dim, np, g1, g2, g3);
565
566 ARTS_USER_ERROR_IF (!negative_pnd_ok && min(pnd_field) < 0,
567 "Negative values in *pnd_field* not allowed.");
568
569 // No non-zero pnd at lower boundary unless lower boundary is at or below
570 // surface
571 for (Index a = 0; a < g2.nelem(); a++) {
572 for (Index o = 0; o < g3.nelem(); o++) {
573 ARTS_USER_ERROR_IF (max(pnd_field(joker, 0, a, o)) > 0 &&
574 z_field(cloudbox_limits[0], a, o) > z_surface(a, o),
575 "A non-zero value found in *pnd_field* at the"
576 " lower altitude limit of the cloudbox (but the "
577 "position is not at or below the surface altitude).");
578 }
579 }
580
581 // No non-zero pnd at upper boundary unless upper boundary is top of
582 // atmosphere
583 if (cloudbox_limits[1] != p_grid.nelem() - 1)
584 ARTS_USER_ERROR_IF (max(pnd_field(joker, g1.nelem() - 1, joker, joker)) > 0,
585 "A non-zero value found in *pnd_field* at "
586 "upper altitude limit of the cloudbox.");
587 if (atmosphere_dim >= 2) {
588 ARTS_USER_ERROR_IF (max(pnd_field(joker, joker, 0, joker)) > 0,
589 "A non-zero value found in *pnd_field* at "
590 "lower latitude limit of the cloudbox.");
591 ARTS_USER_ERROR_IF (max(pnd_field(joker, joker, g2.nelem() - 1, joker)) > 0,
592 "A non-zero value found in *pnd_field* at "
593 "upper latitude limit of the cloudbox.");
594 }
595 if (atmosphere_dim == 3) {
596 ARTS_USER_ERROR_IF (max(pnd_field(joker, joker, joker, 0)) > 0,
597 "A non-zero value found in *pnd_field* at "
598 "lower longitude limit of the cloudbox.");
599 ARTS_USER_ERROR_IF (max(pnd_field(joker, joker, joker, g3.nelem() - 1)) > 0,
600 "A non-zero value found in *pnd_field* at "
601 "upper longitude limit of the cloudbox.");
602 }
603
604 // And dpnd_field_dx
605 ARTS_USER_ERROR_IF (dpnd_field_dx.nelem() != jacobian_quantities.nelem(),
606 "Size of *dpnd_field_dx* inconsistent with number "
607 "of *jacobian_quantities*.");
608
609 // Check semi-mandatory variables, that are allowed to be empty
610 //
611
612 // scat_species:
613 if (scat_species.nelem() > 0)
614 ARTS_USER_ERROR_IF (scat_species.nelem() != scat_data.nelem(),
615 "Number of scattering species specified by scat_species does\n"
616 "not agree with number of scattering species in scat_data:\n"
617 "scat_species has ", scat_species.nelem(),
618 " entries, while scat_data has ", scat_data.nelem(), ".")
619
620 // particle_masses:
621 if (!particle_masses.empty()) {
622 ARTS_USER_ERROR_IF (particle_masses.nrows() != np,
623 "The WSV *particle_masses* must either be "
624 "empty or have a row size matching the "
625 "length of *scat_data*.");
626 ARTS_USER_ERROR_IF (min(particle_masses) < 0,
627 "All values in *particles_masses* must be >= 0.");
628 }
629 }
630
631 // If here, all OK
632 cloudbox_checked = 1;
633}
634
635/* Workspace method: Doxygen documentation will be auto-generated */
636void scat_data_checkedCalc(Index& scat_data_checked,
637 const ArrayOfArrayOfSingleScatteringData& scat_data,
638 const Vector& f_grid,
639 const Numeric& dfrel_threshold,
640 const String& check_level,
641 const Numeric& sca_mat_threshold,
642 const Verbosity& verbosity)
643// FIXME: when we allow K, a, Z to be on different f and T grids, their use in
644// the scatt solvers needs to be reviewed again and adapted to this!
645{
646 // Prevent the user from producing nonsense by using too much freedom in
647 // setting the single freq validity threshold...
648 ARTS_USER_ERROR_IF (dfrel_threshold > 0.5,
649 "*dfrel_threshold* too large (max. allowed: 0.5, your's: ",
650 dfrel_threshold, ").")
651
652 // freq range of calc covered?
653 ARTS_USER_ERROR_IF (f_grid.empty(), "The frequency grid is empty.");
654 if (f_grid.nelem() > 1) chk_if_increasing("f_grid", f_grid);
655
656 Index nf = f_grid.nelem();
657 Index N_ss = scat_data.nelem();
658 for (Index i_ss = 0; i_ss < N_ss; i_ss++) {
659 Index N_se = scat_data[i_ss].nelem();
660 for (Index i_se = 0; i_se < N_se; i_se++) {
661 // For each scattering element (se) check that se's f_grid is either
662 // identical to f_grid or contains a single entry only. In the latter
663 // case, the f/f_grid-ratio (equv. to a size parameter ratio) not allowed
664 // to exceed the dfrel_threshold.
665 Index nf_se = scat_data[i_ss][i_se].f_grid.nelem();
666 if (nf_se != 1) {
667 ARTS_USER_ERROR_IF (nf_se != nf,
668 "*scat_data* must have either one or *f_grid* (=", nf,
669 ") frequency entries,\n"
670 "but scattering element #", i_se, " in scattering species #",
671 i_ss, " has ", nf_se, ".")
672 for (Index f = 0; f < nf_se; f++) {
674 scat_data[i_ss][i_se].f_grid[f], f_grid[f], 0.5e-9),
675 "*scat_data* frequency grid has to be identical to *f_grid*\n"
676 "(or contain only a single entry),\n"
677 "but scattering element #", i_se,
678 " in scattering species #", i_ss,
679 " deviates for f_index ", f, ".")
680 }
681 } else {
682 ARTS_USER_ERROR_IF ((abs(1. - scat_data[i_ss][i_se].f_grid[0] / f_grid[0]) >
683 dfrel_threshold) or
684 (abs(1. - scat_data[i_ss][i_se].f_grid[0] / f_grid[nf - 1]) >
685 dfrel_threshold),
686 "Frequency entry (f=", scat_data[i_ss][i_se].f_grid[0],
687 "Hz) of scattering element #", i_se, "\n"
688 "in scattering species #", i_ss, " is too far (>",
689 dfrel_threshold * 1e2, "%) from one or more\n"
690 "of the f_grid limits (fmin=", f_grid[0],
691 "Hz, fmax=", f_grid[nf - 1], "Hz).")
692 }
693
694 // check that the freq dimension of sca_mat, ext_mat, and abs_vec is
695 // either ssd.f_grid.nelem() or 1 (FIXME: so far, being freq dim !=
696 // ssd.f_grid.nelem() switched off, as usage in scatt solvers so far
697 // doesn't allow this. see FIXME at start.).
698 {
699 ostringstream bs1, bs2;
700 bs1 << "Frequency dimension of ";
701 //bs2 << " must be either one or ssd.f_grid.nelem() (=" << nf_se << "),\n"
702 bs2 << " must be ssd.f_grid.nelem() (=" << nf_se << "),\n"
703 << "but scattering element #" << i_se << " in scattering species #"
704 << i_ss << " is ";
705 Index nf_sd = scat_data[i_ss][i_se].pha_mat_data.nlibraries();
706 ARTS_USER_ERROR_IF (nf_sd != nf_se,
707 bs1.str(), "pha_mat_data", bs2.str(), nf_se, ".")
708 nf_sd = scat_data[i_ss][i_se].ext_mat_data.nshelves();
709 ARTS_USER_ERROR_IF (nf_sd != nf_se,
710 bs1.str(), "ext_mat_data", bs2.str(), nf_se, ".")
711 nf_sd = scat_data[i_ss][i_se].abs_vec_data.nshelves();
712 ARTS_USER_ERROR_IF (nf_sd != nf_se,
713 bs1.str(), "abs_vec_data", bs2.str(), nf_se, ".")
714 }
715
716 // check that the temp dimension of K and a is ssd.T_grid.nelem(). For Z
717 // it might be ssd.T_grid.nelem() or 1.
718 {
719 ostringstream bs1, bs2;
720 Index nt_se = scat_data[i_ss][i_se].T_grid.nelem();
721 bs1 << "Temperature dimension of ";
722 //bs2 << " must be either one or ssd.T_grid.nelem(),\n"
723 bs2 << " must be ssd.T_grid.nelem() (=" << nt_se << "),\n"
724 << "but for scattering element #" << i_se
725 << " in scattering species #" << i_ss << " it is ";
726 Index nt_sd = scat_data[i_ss][i_se].pha_mat_data.nvitrines();
727 ARTS_USER_ERROR_IF (nt_sd != nt_se and nt_sd != 1,
728 bs1.str(), "pha_mat_data", bs2.str(), nt_sd, ".")
729 nt_sd = scat_data[i_ss][i_se].ext_mat_data.nbooks();
730 ARTS_USER_ERROR_IF (nt_sd != nt_se,
731 bs1.str(), "ext_mat_data", bs2.str(), nt_se, ".")
732 nt_sd = scat_data[i_ss][i_se].abs_vec_data.nbooks();
733 ARTS_USER_ERROR_IF (nt_sd != nt_se,
734 bs1.str(), "abs_vec_data", bs2.str(), nt_se, ".")
735 }
736 }
737 }
738
739 if (check_level.toupper() != "NONE") {
740 // handing over to scat_dataCheck which checks whether
741 // 1) scat_data containing any NaN?
742 // 2) any negative values in Z11, K11, or a1?
743 // 3) sca_mat norm sufficiently good (int(Z11)~=K11-a1?)
744 // 1) & 2) always done
745 // 3) only done if scat_data_check_level is "all"
746 scat_dataCheck(scat_data, check_level, sca_mat_threshold, verbosity);
747 }
748
749 // If here, all OK
750 scat_data_checked = 1;
751}
752
753/* Workspace method: Doxygen documentation will be auto-generated */
754void lbl_checkedCalc(Index& lbl_checked,
755 const ArrayOfArrayOfAbsorptionLines& abs_lines_per_species,
756 const ArrayOfArrayOfSpeciesTag& abs_species,
757 const SpeciesIsotopologueRatios& isotopologue_ratios,
758 const Verbosity&)
759{
760 checkIsotopologueRatios(abs_lines_per_species, isotopologue_ratios);
761 checkPartitionFunctions(abs_lines_per_species);
762
763 lbl_checked = false;
764
765 ARTS_USER_ERROR_IF (abs_lines_per_species.nelem() not_eq abs_species.nelem(),
766 "abs_lines_per_species and abs_species must have same length.\n"
767 "Instead len(abs_lines_per_species) = ",
768 abs_lines_per_species.nelem(),
769 " and len(abs_species) = ",
770 abs_species.nelem(),
771 '\n')
772
773 for (Index i=0; i<abs_species.nelem(); i++) {
774 auto& specs = abs_species[i];
775 auto& lines = abs_lines_per_species[i];
776
777 if (not specs.nelem()) {
778 if (not lines.nelem()) {
779 continue;
780 }
781 ARTS_USER_ERROR ( "Lines for non-existent species discovered!\n");
782 }
783
784 const bool any_zeeman = std::any_of(specs.cbegin(), specs.cend(), [](auto& x){return x.Type() == Species::TagType::Zeeman;});
785 ARTS_USER_ERROR_IF (any_zeeman and (not std::all_of(specs.cbegin(), specs.cend(), [](auto& x){return x.Type() == Species::TagType::Zeeman;})),
786 "Zeeman species found but not all sub-species tags support Zeeman effect.\n"
787 "Offending tag: ", specs, '\n')
788
789 if (any_zeeman) {
790 for (auto& band: lines) {
791 ARTS_USER_ERROR_IF (band.cutoff not_eq Absorption::CutoffType::None,
792 "Zeeman effects are not symmetric, you cannot use cutoff.\n");
793 for (Index k=0; k<band.NumLines(); k++) {
794 bool hasJ = band.lines[k].localquanta.val.has(QuantumNumberType::J);
795 bool hasF = band.lines[k].localquanta.val.has(QuantumNumberType::F);
796 ARTS_USER_ERROR_IF (not(hasF or hasJ),
797 "No J(s) or F(s) yet declared Zeeman splitting.\n");
798
799 auto& qn = hasF ? band.lines[k].localquanta.val[QuantumNumberType::F] : band.lines[k].localquanta.val[QuantumNumberType::J];
801 "Bad Wigner numbers for upper state F or J. Try increasing the Wigner memory allocation.\n");
803 "Bad Wigner numbers for lower state F or J. Try increasing the Wigner memory allocation.\n");
804
805 auto Ze = band.lines[k].zeeman;
806 ARTS_USER_ERROR_IF (Ze.gu() == 0 ? false : not std::isnormal(Ze.gu()),
807 "Bad value(s) in the upper Zeeman data not allowed when modeling Zeeman effect.\n");
808 ARTS_USER_ERROR_IF (Ze.gl() == 0 ? false : not std::isnormal(Ze.gl()),
809 "Bad value(s) in the lower Zeeman data not allowed when modeling Zeeman effect.\n");
810 }
811 }
812 } else /*if (not any any_zeeman)*/ {
813 }
814
815 // Checks per band
816 for (auto& band: lines) {
817 ARTS_USER_ERROR_IF (band.mirroring not_eq Absorption::MirroringType::Manual and
818 std::any_of(band.lines.cbegin(), band.lines.cend(),
819 [](auto& x){return x.F0 <= 0;}),
820 "Negative or zero frequency in non-Manual mirrored band.\n");
821 }
822 }
823
824 for (auto& lines: abs_lines_per_species) {
825 for (auto& band: lines) {
826
827 // Mirroring checks
828 for (auto& line: band.lines) {
829 if (band.mirroring == Absorption::MirroringType::Manual) {
830 ARTS_USER_ERROR_IF(line.F0 >= 0,
831 "Must have negative frequency, finds " , line.F0)
832 } else {
833 ARTS_USER_ERROR_IF(line.F0 <= 0,
834 "Must have positive frequency, finds " , line.F0)
835 }
836 }
837
838 // Cutoff checks
839 switch (band.cutoff) {
840 case Absorption::CutoffType::None: break;
841 case Absorption::CutoffType::ByLine: {
842 ARTS_USER_ERROR_IF (not (band.mirroring == Absorption::MirroringType::None or
843 band.mirroring == Absorption::MirroringType::Manual),
844 "Cutoff only possible with symmetric mirroring types")
846 "Cannot have relaxation matrix line mixing with cutoff calculations")
847 ARTS_USER_ERROR_IF (not (band.lineshapetype == LineShape::Type::DP or
848 band.lineshapetype == LineShape::Type::LP or
849 band.lineshapetype == LineShape::Type::VP),
850 "Cutoff only possible with symmetric line shape types")
851 for (auto& line: band.lines) {
852 for (auto& single_data: line.lineshape.Data()) {
853 // Skipping G() intentionally, since the calculations technically works with it
855 single_data.Y().type not_eq LineShape::TemperatureModel::None or
856 single_data.DV().type not_eq LineShape::TemperatureModel::None,
857 "Cannot have Rosenkranz-style line mixing with cutoff calculations\n"
858 "Note that abs_lines_per_speciesTurnOffLineMixing will make this error go away by modifying the data\n"
859 )
860 }
861 }
862 } break;
863 case Absorption::CutoffType::FINAL: ARTS_USER_ERROR("You have a band with undefined cutoff type.")
864 }
865 }
866 }
867
868 lbl_checked = true;
869}
870
871/* Workspace method: Doxygen documentation will be auto-generated */
873 Workspace& ws _U_,
874 Index& propmat_clearsky_agenda_checked,
875 // WS Input:
876 const ArrayOfArrayOfSpeciesTag& abs_species,
877 const Agenda& propmat_clearsky_agenda,
878 const Verbosity&) {
879 bool needs_lines = false;
880 bool needs_zeeman = false;
881 bool needs_predefined = false;
882 bool needs_continua = false;
883 bool needs_cia = false;
884 bool needs_free_electrons = false;
885 bool needs_particles = false;
886 bool needs_hxsec = false;
887
888 for (auto& tag_groups: abs_species) {
889 for (auto& tag: tag_groups) {
890 switch (tag.Type()) {
891 case Species::TagType::Plain:
892 needs_lines = true;
893 break;
894 case Species::TagType::Zeeman:
895 needs_zeeman = true;
896 break;
897 case Species::TagType::Predefined:
898 needs_predefined = true;
899 break;
900 case Species::TagType::Cia:
901 needs_cia = true;
902 break;
903 case Species::TagType::FreeElectrons:
904 needs_free_electrons = true;
905 break;
906 case Species::TagType::Particles:
907 needs_particles = true;
908 break;
909 case Species::TagType::XsecFit:
910 needs_hxsec = true;
911 break;
912 default:
913 ARTS_ASSERT(false, "Unknown species type: ", tag.Type())
914 break;
915 }
916 }
917 }
918
920 needs_lines and
921 not(propmat_clearsky_agenda.has_method("propmat_clearskyAddLines") or
922 propmat_clearsky_agenda.has_method(
923 "propmat_clearskyAddFromLookup")),
924 "*abs_species* contains normal lines species but *propmat_clearsky_agenda*\n"
925 "cannot support lines.");
926
928 needs_continua and
929 not(propmat_clearsky_agenda.has_method(
930 "propmat_clearskyAddXsecAgenda") or
931 propmat_clearsky_agenda.has_method("propmat_clearskyAddConts") or
932 propmat_clearsky_agenda.has_method(
933 "propmat_clearskyAddFromLookup")),
934 "*abs_species* contains legacy continua but *propmat_clearsky_agenda*\n"
935 "cannot support these.");
936
938 needs_cia and
939 not(propmat_clearsky_agenda.has_method(
940 "propmat_clearskyAddXsecAgenda") or
941 propmat_clearsky_agenda.has_method("propmat_clearskyAddCIA") or
942 propmat_clearsky_agenda.has_method(
943 "propmat_clearskyAddFromLookup")),
944 "*abs_species* contains CIA models but *propmat_clearsky_agenda*\n"
945 "cannot support these.");
946
948 needs_hxsec and
949 not(propmat_clearsky_agenda.has_method("propmat_clearskyAddXsecAgenda") or
950 propmat_clearsky_agenda.has_method("propmat_clearskyAddXsecFit") or
951 propmat_clearsky_agenda.has_method(
952 "propmat_clearskyAddFromLookup")),
953 "*abs_species* contains Hitran XSEC models but *propmat_clearsky_agenda*\n"
954 "cannot support these.");
955
957 needs_predefined and
958 not(propmat_clearsky_agenda.has_method("propmat_clearskyAddPredefined") or
959 propmat_clearsky_agenda.has_method(
960 "propmat_clearskyAddFromLookup")),
961 "*abs_species* contains modern continua models but *propmat_clearsky_agenda*\n"
962 "cannot support these.");
963
964 ARTS_USER_ERROR_IF (needs_zeeman and
965 not propmat_clearsky_agenda.has_method("propmat_clearskyAddZeeman"),
966 "*abs_species* contains Zeeman species but *propmat_clearsky_agenda*\n"
967 "does not contain *propmat_clearskyAddZeeman*.");
968
969 ARTS_USER_ERROR_IF (needs_free_electrons and
970 not propmat_clearsky_agenda.has_method("propmat_clearskyAddFaraday"),
971 "*abs_species* contains Zeeman species but *propmat_clearsky_agenda*\n"
972 "does not contain *propmat_clearskyAddFaraday*.");
973
974 ARTS_USER_ERROR_IF (needs_particles &&
975 !(propmat_clearsky_agenda.has_method("propmat_clearskyAddParticles")),
976 "*abs_species* contains particles but *propmat_clearsky_agenda*\n"
977 "does not contain *propmat_clearskyAddParticles*.");
978
979 propmat_clearsky_agenda_checked = 1;
980}
981
982/* Workspace method: Doxygen documentation will be auto-generated */
983void sensor_checkedCalc(Index& sensor_checked,
984 const Index& atmosphere_dim,
985 const Index& stokes_dim,
986 const Vector& f_grid,
987 const Matrix& sensor_pos,
988 const Matrix& sensor_los,
989 const Matrix& transmitter_pos,
990 const Matrix& mblock_dlos,
991 const Sparse& sensor_response,
992 const Vector& sensor_response_f,
993 const ArrayOfIndex& sensor_response_pol,
994 const Matrix& sensor_response_dlos,
995 const Verbosity&) {
996 // Some sizes
997 const Index nf = f_grid.nelem();
998 const Index nlos = mblock_dlos.nrows();
999 const Index n1y = sensor_response.nrows();
1000 const Index nmblock = sensor_pos.nrows();
1001 const Index niyb = nf * nlos * stokes_dim;
1002
1003 // Sensor position and LOS.
1004 //
1006 "*f_grid* must be a strictly increasing vector.");
1007
1008 // Sensor position and LOS.
1009 //
1010 ARTS_USER_ERROR_IF (sensor_pos.empty(),
1011 "*sensor_pos* is empty. This is not allowed.");
1012 ARTS_USER_ERROR_IF (sensor_los.empty(),
1013 "*sensor_los* is empty. This is not allowed.");
1014 //
1015 ARTS_USER_ERROR_IF (sensor_pos.ncols() != atmosphere_dim,
1016 "The number of columns of sensor_pos must be "
1017 "equal to the atmospheric dimensionality.");
1018 ARTS_USER_ERROR_IF (atmosphere_dim <= 2 && sensor_los.ncols() != 1,
1019 "For 1D and 2D, sensor_los shall have one column.");
1020 ARTS_USER_ERROR_IF (atmosphere_dim == 3 && sensor_los.ncols() != 2,
1021 "For 3D, sensor_los shall have two columns.");
1022 ARTS_USER_ERROR_IF (sensor_los.nrows() != nmblock,
1023 "The number of rows of sensor_pos and sensor_los must be "
1024 "identical, but sensor_pos has ", nmblock, " rows,\n"
1025 "while sensor_los has ", sensor_los.nrows(), " rows.")
1026 ARTS_USER_ERROR_IF (max(sensor_los(joker, 0)) > 180,
1027 "First column of *sensor_los* is not allowed to have values above 180.");
1028 if (atmosphere_dim == 2) {
1029 ARTS_USER_ERROR_IF (min(sensor_los(joker, 0)) < -180,
1030 "For atmosphere_dim = 2, first column of "
1031 "*sensor_los* is not allowed to have values below -180.");
1032 } else {
1033 ARTS_USER_ERROR_IF (min(sensor_los(joker, 0)) < 0,
1034 "For atmosphere_dim != 2, first column of "
1035 "*sensor_los* is not allowed to have values below 0.");
1036 }
1037 if (atmosphere_dim == 3) {
1038 ARTS_USER_ERROR_IF (max(sensor_los(joker, 1)) > 180,
1039 "Second column of *sensor_los* is not allowed to have values above 180.");
1040 ARTS_USER_ERROR_IF (min(sensor_los(joker, 1)) < -180,
1041 "Second column of *sensor_los* is not allowed to have values below -180.");
1042 }
1043
1044 // Transmission position.
1045 if (!transmitter_pos.empty()) {
1046 ARTS_USER_ERROR_IF (transmitter_pos.nrows() != sensor_pos.nrows(),
1047 "*transmitter_pos* must either be empty or have "
1048 "the same number of rows as *sensor_pos*.");
1049 ARTS_USER_ERROR_IF (transmitter_pos.ncols() != max(Index(2), atmosphere_dim),
1050 "*transmitter_pos* must either be empty, have "
1051 "2 for 1D/2D or 3 columns for 3D.");
1052 }
1053
1054 // mblock_dlos
1055 //
1056 ARTS_USER_ERROR_IF (mblock_dlos.empty(),
1057 "*mblock_dlos* is empty.");
1058 ARTS_USER_ERROR_IF (mblock_dlos.ncols() > 2,
1059 "The maximum number of columns in *mblock_dlos* is two.");
1060 if (atmosphere_dim < 3) {
1061 ARTS_USER_ERROR_IF (mblock_dlos.ncols() != 1,
1062 "For 1D and 2D *mblock_dlos* must have exactly one column.");
1063 }
1064
1065 // Sensor
1066 //
1067 ARTS_USER_ERROR_IF (sensor_response.ncols() != niyb,
1068 "The *sensor_response* matrix does not have the right size,\n"
1069 "either the method *sensor_responseInit* has not been run or some\n"
1070 "of the other sensor response methods has not been correctly\n"
1071 "configured.")
1072
1073 // Sensor aux variables
1074 //
1075 ARTS_USER_ERROR_IF (n1y != sensor_response_f.nelem() || n1y != sensor_response_pol.nelem() ||
1076 n1y != sensor_response_dlos.nrows(),
1077 "Sensor auxiliary variables do not have the correct size.\n"
1078 "The following variables should all have same size:\n"
1079 "length of y for one block : ", n1y, "\n"
1080 "sensor_response_f.nelem() : ", sensor_response_f.nelem(),
1081 "\nsensor_response_pol.nelem() : ", sensor_response_pol.nelem(),
1082 "\nsensor_response_dlos.nrows(): ", sensor_response_dlos.nrows(),
1083 "\n")
1084
1085 // If here, all OK
1086 sensor_checked = 1;
1087}
void checkIsotopologueRatios(const ArrayOfArrayOfAbsorptionLines &abs_lines_per_species, const Species::IsotopologueRatios &isoratios)
Check that isotopologue ratios for the given species are correctly defined.
Definition: absorption.cc:63
void checkPartitionFunctions(const ArrayOfArrayOfAbsorptionLines &abs_lines_per_species)
Check that ARTS was compiled for all requested species tags.
Definition: absorption.cc:52
Index TotalNumberOfElements(const Array< Array< base > > &aa)
Determine total number of elements in an ArrayOfArray.
Definition: array.h:241
base max(const Array< base > &x)
Max function.
Definition: array.h:145
base min(const Array< base > &x)
Min function.
Definition: array.h:161
The global header file for ARTS.
Common ARTS conversions.
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_bool(const String &x_name, const Index &x)
chk_if_bool
Definition: check_input.cc:65
void chk_atm_grids(const Index &dim, ConstVectorView p_grid, ConstVectorView lat_grid, ConstVectorView lon_grid)
chk_atm_grids
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
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:86
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)
void chk_if_increasing(const String &x_name, const ArrayOfIndex &x)
chk_if_increasing
Definition: check_input.cc:111
The Agenda class.
Definition: agenda_class.h:69
bool has_method(const String &methodname) const
Check if method is in Agenda.
Index nelem() const ARTS_NOEXCEPT
Definition: array.h:92
bool empty() const noexcept
Definition: matpackI.h:1086
Index nrows() const noexcept
Definition: matpackI.h:1079
Index ncols() const noexcept
Definition: matpackI.h:1080
bool empty() const noexcept
Definition: matpackIII.h:157
Index npages() const
Returns the number of pages.
Definition: matpackIII.h:145
Index nrows() const
Returns the number of rows.
Definition: matpackIII.h:148
Index ncols() const
Returns the number of columns.
Definition: matpackIII.h:151
Index nelem() const noexcept
Returns the number of elements.
Definition: matpackI.h:547
bool empty() const noexcept
Returns true if variable size is zero.
Definition: matpackI.h:536
The Matrix class.
Definition: matpackI.h:1285
The Tensor3 class.
Definition: matpackIII.h:352
The Tensor4 class.
Definition: matpackIV.h:435
The Vector class.
Definition: matpackI.h:910
void resize(Index n)
Resize function.
Definition: matpackI.cc:390
Workspace class.
Definition: workspace_ng.h:53
void toupper()
Convert to upper case.
Definition: mystring.h:147
Internal cloudbox functions.
#define _U_
Definition: config.h:180
#define ARTS_ASSERT(condition,...)
Definition: debug.h:102
#define ARTS_USER_ERROR(...)
Definition: debug.h:169
std::string var_string(Args &&... args)
Definition: debug.h:36
#define ARTS_USER_ERROR_IF(condition,...)
Definition: debug.h:153
bool is_increasing(ConstVectorView x)
Checks if a vector is sorted and strictly increasing.
Definition: logic.cc:218
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:354
void abs_xsec_agenda_checkedCalc(Workspace &ws, Index &abs_xsec_agenda_checked, const ArrayOfArrayOfSpeciesTag &abs_species, const Agenda &abs_xsec_agenda, const Verbosity &)
Definition: m_checked.cc:47
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 Index &abs_f_interp_order, const Index &negative_vmr_ok, const Verbosity &)
WORKSPACE METHOD: atmfields_checkedCalc.
Definition: m_checked.cc:97
constexpr Numeric DEG2RAD
Definition: m_checked.cc:43
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 &demand_latlon_margin, const Index &negative_pnd_ok, const Verbosity &)
WORKSPACE METHOD: cloudbox_checkedCalc.
Definition: m_checked.cc:387
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:872
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:636
void lbl_checkedCalc(Index &lbl_checked, const ArrayOfArrayOfAbsorptionLines &abs_lines_per_species, const ArrayOfArrayOfSpeciesTag &abs_species, const SpeciesIsotopologueRatios &isotopologue_ratios, const Verbosity &)
WORKSPACE METHOD: lbl_checkedCalc.
Definition: m_checked.cc:754
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 Numeric &max500hpa_gradient, const Verbosity &)
WORKSPACE METHOD: atmgeom_checkedCalc.
Definition: m_checked.cc:262
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, 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:983
void scat_dataCheck(const ArrayOfArrayOfSingleScatteringData &scat_data, const String &check_type, const Numeric &threshold, const Verbosity &verbosity)
WORKSPACE METHOD: scat_dataCheck.
void abs(Sparse &A, const Sparse &B)
Absolute value of sparse matrix elements.
Definition: matpackII.cc:394
Implementation of Matrix, Vector, and such stuff.
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:33
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:39
const Joker joker
constexpr bool relaxationtype_relmat(PopulationType in) noexcept
constexpr Numeric LAT_LON_MIN
Global constant, minimum distance of cloudbox to lat/lon_grid edges.
Definition: cloudbox.h:44
constexpr auto deg2rad(auto x) noexcept
Converts degrees to radians.
The Sparse class.
Definition: matpackII.h:75
Index nrows() const
Returns the number of rows.
Definition: matpackII.cc:62
Index ncols() const
Returns the number of columns.
Definition: matpackII.cc:65
#define a
bool is_wigner3_ready(const Rational &J)
Tells if the function is ready for Wigner 3J calculations.
Wigner symbol interactions.