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