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