ARTS  2.2.66
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 
22 /*===========================================================================
23  === File description
24  ===========================================================================*/
25 
38 #include "arts.h"
39 #include "auto_md.h"
40 #include "matpackI.h"
41 
42 extern const Numeric DEG2RAD;
43 
44 
45 /* Workspace method: Doxygen documentation will be auto-generated */
47  Index& abs_xsec_agenda_checked,
48  // WS Input:
49  const ArrayOfArrayOfSpeciesTag& abs_species,
50  const Agenda& abs_xsec_agenda,
51  const Verbosity&
52  )
53 {
54  bool needs_lines = false;
55  bool needs_continua = false;
56  bool needs_cia = false;
57 
58  for (Index sp = 0; sp < abs_species.nelem(); sp++)
59  {
60  for (Index tgs = 0; tgs < abs_species[sp].nelem(); tgs++)
61  {
62  switch (abs_species[sp][tgs].Type())
63  {
64  case SpeciesTag::TYPE_PLAIN: needs_lines = true; break;
65  case SpeciesTag::TYPE_ZEEMAN: break;
66  case SpeciesTag::TYPE_PREDEF: needs_continua = true; break;
67  case SpeciesTag::TYPE_CIA: needs_cia = true; break;
69  case SpeciesTag::TYPE_PARTICLES: break;
70  default:
71  ostringstream os;
72  os << "Unknown species type: " <<
73  abs_species[sp][tgs].Type();
74  throw runtime_error(os.str());
75  break;
76  }
77 
78  }
79 
80  }
81 
82  if (needs_lines
83  && !abs_xsec_agenda.has_method("abs_xsec_per_speciesAddLines"))
84  {
85  throw runtime_error(
86  "*abs_species* contains line species but *abs_xsec_agenda*\n"
87  "does not contain *abs_xsec_per_speciesAddLines*.");
88  }
89 
90  if (needs_continua
91  && !abs_xsec_agenda.has_method("abs_xsec_per_speciesAddConts"))
92  {
93  throw runtime_error(
94  "*abs_species* contains continuum species but *abs_xsec_agenda*\n"
95  "does not contain *abs_xsec_per_speciesAddConts*.");
96  }
97 
98  if (needs_cia
99  && !abs_xsec_agenda.has_method("abs_xsec_per_speciesAddCIA"))
100  {
101  throw runtime_error(
102  "*abs_species* contains CIA species but *abs_xsec_agenda*\n"
103  "does not contain *abs_xsec_per_speciesAddCIA*.");
104  }
105 
106  // If here, all OK
107  abs_xsec_agenda_checked = 1;
108 }
109 
110 
111 
112 
113 
114 /* Workspace method: Doxygen documentation will be auto-generated */
116  Index& atmfields_checked,
117  const Index& atmosphere_dim,
118  const Vector& p_grid,
119  const Vector& lat_grid,
120  const Vector& lon_grid,
121  const ArrayOfArrayOfSpeciesTag& abs_species,
122  const Tensor3& t_field,
123  const Tensor4& vmr_field,
124  const Tensor3& wind_u_field,
125  const Tensor3& wind_v_field,
126  const Tensor3& wind_w_field,
127  const Tensor3& mag_u_field,
128  const Tensor3& mag_v_field,
129  const Tensor3& mag_w_field,
130  const Index& abs_f_interp_order,
131  const Index& negative_vmr_ok,
132  const Verbosity&)
133 {
134  // Consistency between dim, grids and atmospheric fields/surfaces
135  chk_if_in_range( "atmosphere_dim", atmosphere_dim, 1, 3 );
136  chk_atm_grids( atmosphere_dim, p_grid, lat_grid, lon_grid );
137  chk_atm_field( "t_field", t_field, atmosphere_dim,
138  p_grid, lat_grid, lon_grid );
139  chk_atm_field( "vmr_field", vmr_field, atmosphere_dim, abs_species.nelem(),
140  p_grid, lat_grid, lon_grid );
141 
142  // More for vmr_field.
143  if( !negative_vmr_ok && abs_species.nelem() && min(vmr_field) < 0 )
144  throw runtime_error( "All values in *vmr_field* must be >= 0." );
145 
146  // More for t_field.
147  if( min(t_field) <= 0 )
148  throw runtime_error( "All temperatures in *t_field* must be > 0." );
149 
150  // Winds
151  if( wind_w_field.npages() > 0 )
152  {
153  chk_atm_field( "wind_w_field", wind_w_field, atmosphere_dim,
154  p_grid, lat_grid, lon_grid );
155  }
156  if( atmosphere_dim < 3 && wind_v_field.npages() > 0 )
157  {
158  chk_atm_field( "wind_v_field", wind_v_field, atmosphere_dim,
159  p_grid, lat_grid, lon_grid );
160  }
161  if( atmosphere_dim > 2 )
162  {
163  if( wind_u_field.npages() > 0 )
164  {
165  if( wind_v_field.npages() > 0 )
166  {
167  bool chk_poles = false;
168  chk_atm_field( "wind_u_field", wind_u_field, atmosphere_dim,
169  p_grid, lat_grid, lon_grid, chk_poles);
170  chk_atm_field( "wind_v_field", wind_v_field, atmosphere_dim,
171  p_grid, lat_grid, lon_grid, chk_poles);
172  chk_atm_vecfield_lat90( "wind_v_field", wind_v_field,
173  "wind_u_field", wind_u_field,
174  atmosphere_dim, lat_grid);
175  }
176  else
177  {
178  chk_atm_field( "wind_u_field", wind_u_field, atmosphere_dim,
179  p_grid, lat_grid, lon_grid );
180  }
181  }
182  else
183  {
184  if( wind_v_field.npages() > 0 )
185  {
186  chk_atm_field( "wind_v_field", wind_v_field, atmosphere_dim,
187  p_grid, lat_grid, lon_grid);
188  }
189  }
190  }
191 
192  // If any of the wind fields exist, abs_f_interp_order must not be zero.
193  if (wind_u_field.npages() > 0 ||
194  wind_v_field.npages() > 0 ||
195  wind_w_field.npages() > 0)
196  {
197  if (abs_f_interp_order==0)
198  {
199  ostringstream os;
200  os << "You have a wind field set, but abs_f_interp_order zero.\n"
201  << "This is not allowed. Though abs_f_interp_order only is\n"
202  << "required and has an effect if absorption lookup tables\n"
203  << "are used, for safety reasons you also have to set it >0\n"
204  << "in case of on-the-fly absorption.";
205  throw runtime_error(os.str());
206  }
207  }
208 
209  // Magnetic field
210  if( mag_w_field.npages() > 0 )
211  {
212  chk_atm_field( "mag_w_field (vertical magfield component)",
213  mag_w_field, atmosphere_dim, p_grid, lat_grid, lon_grid );
214  }
215  if( mag_u_field.npages() > 0 )
216  {
217  if( mag_v_field.npages() > 0 )
218  {
219  bool chk_poles = false;
220  chk_atm_field( "mag_v_field", mag_v_field, atmosphere_dim,
221  p_grid, lat_grid, lon_grid, chk_poles );
222  chk_atm_field( "mag_u_field", mag_u_field, atmosphere_dim,
223  p_grid, lat_grid, lon_grid, chk_poles );
224  chk_atm_vecfield_lat90( "mag_v_field", mag_v_field,
225  "mag_u_field", mag_u_field,
226  atmosphere_dim, lat_grid);
227  }
228  else
229  {
230  chk_atm_field( "mag_u_field", mag_u_field, atmosphere_dim,
231  p_grid, lat_grid, lon_grid );
232  }
233  }
234  else
235  {
236  if( mag_v_field.npages() > 0 )
237  {
238  chk_atm_field( "mag_v_field", mag_v_field, atmosphere_dim,
239  p_grid, lat_grid, lon_grid);
240  }
241  }
242 
243  // If here, all OK
244  atmfields_checked = 1;
245 }
246 
247 
248 
249 
250 
251 /* Workspace method: Doxygen documentation will be auto-generated */
253  Index& atmgeom_checked,
254  const Index& atmosphere_dim,
255  const Vector& p_grid,
256  const Vector& lat_grid,
257  const Vector& lon_grid,
258  const Tensor3& z_field,
259  const Vector& refellipsoid,
260  const Matrix& z_surface,
261  const Verbosity&)
262 {
263  // A repetition from atmfields_checked, but we do this to make the two parts
264  // independent (the other option would be to demand atmfields_checkec == 1)
265  chk_if_in_range( "atmosphere_dim", atmosphere_dim, 1, 3 );
266  chk_atm_grids( atmosphere_dim, p_grid, lat_grid, lon_grid );
267 
268  // *refellipsoid*
269  if( refellipsoid.nelem() != 2 )
270  throw runtime_error( "The WSV *refellispoid* must be a vector of "
271  "length 2*." );
272  if( refellipsoid[0] <= 0 )
273  throw runtime_error( "The first element of *refellipsoid* must "
274  "be > 0." );
275  if( refellipsoid[1] < 0 || refellipsoid[1] > 1 )
276  throw runtime_error( "The second element of *refellipsoid* must be "
277  "inside [0,1]." );
278  if( atmosphere_dim == 1 && refellipsoid[1] != 0 )
279  throw runtime_error( "For 1D, the second element of *refellipsoid* "
280  "(the eccentricity) must be 0." );
281 
282  chk_atm_field( "z_field", z_field, atmosphere_dim,
283  p_grid, lat_grid, lon_grid );
284  chk_atm_surface( "z_surface", z_surface, atmosphere_dim,
285  lat_grid, lon_grid );
286 
287  // Check that z_field has strictly increasing pages.
288  for( Index row=0; row<z_field.nrows(); row++ )
289  {
290  for( Index col=0; col<z_field.ncols(); col++ )
291  {
292  ostringstream os;
293  os << "z_field (for latitude nr " << row << " and longitude nr "
294  << col << ")";
295  chk_if_increasing( os.str(), z_field(joker,row,col) );
296  }
297  }
298 
299  // Check that there is no gap between the surface and lowest pressure
300  // level
301  // (A copy of this code piece is found in z_fieldFromHSE. Make this to an
302  // internal function if used in more places.)
303  for( Index row=0; row<z_surface.nrows(); row++ )
304  {
305  for( Index col=0; col<z_surface.ncols(); col++ )
306  {
307  if( z_surface(row,col)<z_field(0,row,col) ||
308  z_surface(row,col)>=z_field(z_field.npages()-1,row,col) )
309  {
310  ostringstream os;
311  os << "The surface altitude (*z_surface*) cannot be outside\n"
312  << "of the altitudes in *z_field*.\n"
313  << "z_surface: " << z_surface(row,col) << "\n"
314  << "min of z_field: " << z_field(0,row,col) << "\n"
315  << "max of z_field: "
316  << z_field(z_field.npages()-1,row,col) << "\n";
317  if( atmosphere_dim > 1 )
318  os << "\nThis was found to be the case for:\n"
319  << "latitude " << lat_grid[row];
320  if( atmosphere_dim > 2 )
321  os << "\nlongitude " << lon_grid[col];
322  throw runtime_error( os.str() );
323  }
324  }
325  }
326 
327  // If here, all OK
328  atmgeom_checked = 1;
329 }
330 
331 
332 
333 
334 /* Workspace method: Doxygen documentation will be auto-generated */
336  Index& cloudbox_checked,
337  const Index& atmfields_checked,
338  const Index& atmosphere_dim,
339  const Vector& p_grid,
340  const Vector& lat_grid,
341  const Vector& lon_grid,
342  const Tensor3& z_field,
343  const Matrix& z_surface,
344  const Tensor3& wind_u_field,
345  const Tensor3& wind_v_field,
346  const Tensor3& wind_w_field,
347  const Index& cloudbox_on,
348  const ArrayOfIndex& cloudbox_limits,
349  const Tensor4& pnd_field,
350  const ArrayOfSingleScatteringData& scat_data_array,
351  const Matrix& particle_masses,
352  const ArrayOfArrayOfSpeciesTag& abs_species,
353  const Verbosity&)
354 {
355  // Demanded space between cloudbox and lat and lon edges [degrees]
356  const Numeric llmin = 20;
357 
358  if( atmfields_checked != 1 )
359  throw runtime_error( "The atmospheric fields must be flagged to have "
360  "passed a consistency check (atmfields_checked=1)." );
361 
362  chk_if_bool( "cloudbox_on", cloudbox_on );
363 
364  if( cloudbox_on )
365  {
366  // Winds, must be empty variables (i.e. no winds allowed)
367  {
368  ostringstream ow;
369  ow << "The scattering methods are not (yet?) handling winds. For this\n"
370  << "reason, the WSVs for wind fields must all be empty with an\n."
371  << "active cloudbox.";
372  if( wind_w_field.npages() > 0 )
373  { throw runtime_error( ow.str() ); }
374  if( wind_v_field.npages() > 0 )
375  { throw runtime_error( ow.str() ); }
376  if( atmosphere_dim > 2 && wind_u_field.npages() > 0 )
377  { throw runtime_error( ow.str() ); }
378  }
379 
380  // no "particles" in abs_species if cloudbox is on (they act on the same
381  // scat_data_array! and there is no good reason to have some particles as
382  // abs-only, if we anyway do a scattering calculation.).
383  Index has_absparticles=0;
384  for( Index sp = 0; sp < abs_species.nelem() && has_absparticles < 1; sp++ )
385  {
386  if ( abs_species[sp][0].Type() == SpeciesTag::TYPE_PARTICLES )
387  {
388  has_absparticles=1;
389  }
390  }
391  if ( has_absparticles )
392  {
393  throw runtime_error( "For scattering calculations (cloudbox is on),"
394  "abs_species is not allowed to contain\n"
395  "'particles' (absorbing-only particles)!" );
396  }
397 
398  // Cloudbox limits
399  if( cloudbox_limits.nelem() != atmosphere_dim*2 )
400  {
401  ostringstream os;
402  os << "The array *cloudbox_limits* has incorrect length.\n"
403  << "For atmospheric dim. = " << atmosphere_dim
404  << " the length shall be " << atmosphere_dim*2
405  << " but it is " << cloudbox_limits.nelem() << ".";
406  throw runtime_error( os.str() );
407  }
408  if( cloudbox_limits[1]<=cloudbox_limits[0] || cloudbox_limits[0]<0 ||
409  cloudbox_limits[1]>=p_grid.nelem() )
410  {
411  ostringstream os;
412  os << "Incorrect value(s) for cloud box pressure limit(s) found."
413  << "\nValues are either out of range or upper limit is not "
414  << "greater than lower limit.\nWith present length of "
415  << "*p_grid*, OK values are 0 - " << p_grid.nelem()-1
416  << ".\nThe pressure index limits are set to "
417  << cloudbox_limits[0] << " - " << cloudbox_limits[1] << ".";
418  throw runtime_error( os.str() );
419  }
420 
421  Index nlat=1, nlon=1;
422 
423  if( atmosphere_dim >= 2 )
424  {
425  nlat = lat_grid.nelem();
426  if( cloudbox_limits[3]<=cloudbox_limits[2] ||
427  cloudbox_limits[2]<1 || cloudbox_limits[3]>=nlat-1 )
428  {
429  ostringstream os;
430  os << "Incorrect value(s) for cloud box latitude limit(s) found."
431  << "\nValues are either out of range or upper limit is not "
432  << "greater than lower limit.\nWith present length of "
433  << "*lat_grid*, OK values are 1 - " << nlat-2
434  << ".\nThe latitude index limits are set to "
435  << cloudbox_limits[2] << " - " << cloudbox_limits[3] << ".";
436  throw runtime_error( os.str() );
437  }
438  if( ( lat_grid[cloudbox_limits[2]] - lat_grid[0] < llmin ) &&
439  ( atmosphere_dim==2 || (atmosphere_dim==3 && lat_grid[0]>-90)) )
440  {
441  ostringstream os;
442  os << "Too small distance between cloudbox and lower end of "
443  << "latitude grid.\n"
444  << "This distance must be " << llmin << " degrees.\n"
445  << "Cloudbox ends at " << lat_grid[cloudbox_limits[2]]
446  << " and latitude grid starts at " << lat_grid[0] << ".";
447  throw runtime_error( os.str() );
448  }
449  if( ( lat_grid[nlat-1] - lat_grid[cloudbox_limits[3]] < llmin ) &&
450  ( atmosphere_dim==2 ||
451  (atmosphere_dim==3 && lat_grid[nlat-1]<90) ) )
452  {
453  ostringstream os;
454  os << "Too small distance between cloudbox and upper end of "
455  << "latitude grid.\n"
456  << "This distance must be " << llmin << " degrees.\n"
457  << "Cloudbox ends at " << lat_grid[cloudbox_limits[3]]
458  << " and latitude grid ends at " << lat_grid[nlat-1] << ".";
459  throw runtime_error( os.str() );
460  }
461  }
462 
463  if( atmosphere_dim >= 3 )
464  {
465  nlon = lon_grid.nelem();
466  if( cloudbox_limits[5]<=cloudbox_limits[4] || cloudbox_limits[4]<1 ||
467  cloudbox_limits[5]>=nlon-1 )
468  {
469  ostringstream os;
470  os << "Incorrect value(s) for cloud box longitude limit(s) found"
471  << ".\nValues are either out of range or upper limit is not "
472  << "greater than lower limit.\nWith present length of "
473  << "*lon_grid*, OK values are 1 - " << nlon-2
474  << ".\nThe longitude limits are set to "
475  << cloudbox_limits[4] << " - " << cloudbox_limits[5] << ".";
476  throw runtime_error( os.str() );
477  }
478  if( lon_grid[nlon-1] - lon_grid[0] < 360 )
479  {
480  const Numeric latmax = max( abs(lat_grid[cloudbox_limits[2]]),
481  abs(lat_grid[cloudbox_limits[3]]) );
482  const Numeric lfac = 1 / cos( DEG2RAD*latmax );
483  if( lon_grid[cloudbox_limits[4]]-lon_grid[0] < llmin/lfac )
484  {
485  ostringstream os;
486  os << "Too small distance between cloudbox and lower end of"
487  << "the longitude\ngrid. This distance must here be "
488  << llmin/lfac << " degrees.";
489  throw runtime_error( os.str() );
490  }
491  if( lon_grid[nlon-1]-lon_grid[cloudbox_limits[5]] < llmin/lfac )
492  {
493  ostringstream os;
494  os << "Too small distance between cloudbox and upper end of"
495  << "the longitude\ngrid. This distance must here be "
496  << llmin/lfac << " degrees.";
497  throw runtime_error( os.str() );
498  }
499  }
500  }
501 
502  // Check with respect to z_surface
503  for( Index o=0; o<nlon; o++ )
504  {
505  for( Index a=0; a<nlat; a++ )
506  {
507  if( z_field(cloudbox_limits[1],a,o) <= z_surface(a,o) )
508  throw runtime_error(
509  "The upper vertical limit of the cloudbox must be above "
510  "the surface altitude (for all latitudes and longitudes)." );
511  }
512  }
513 
514  // pnd_field
515  //
516  const Index np = scat_data_array.nelem();
517  // Dummy variables to mimic grids of correct size
518  Vector g1( cloudbox_limits[1]-cloudbox_limits[0]+1 ), g2(0), g3(0);
519  if( atmosphere_dim >= 2 )
520  { g2.resize( cloudbox_limits[3]-cloudbox_limits[2]+1 ); }
521  if( atmosphere_dim == 3 )
522  { g3.resize( cloudbox_limits[5]-cloudbox_limits[4]+1 ); }
523  //
524  chk_atm_field( "pnd_field", pnd_field, atmosphere_dim, np, g1, g2, g3 );
525  //
526  if( min(pnd_field) < 0 )
527  throw runtime_error( "Negative values in *pnd_field* not allowed." );
528  //
529  for( Index a=0; a<g2.nelem(); a++ ) {
530  for( Index o=0; o<g3.nelem(); o++ ) {
531  if( max(pnd_field(joker,0,a,o)) > 0 &&
532  z_field(cloudbox_limits[0],a,o) > z_surface(a,o) )
533  throw runtime_error( "A non-zero value found in *pnd_field* at the"
534  " lower altitude limit of the cloudbox (but the "
535  "position is not at or below the surface altitude)." );
536  } }
537  if( max(pnd_field(joker,g1.nelem()-1,joker,joker)) > 0 )
538  throw runtime_error( "A non-zero value found in *pnd_field* at "
539  "upper altitude limit of the cloudbox." );
540  if( atmosphere_dim >= 2 )
541  {
542  if( max(pnd_field(joker,joker,0,joker)) > 0 )
543  throw runtime_error( "A non-zero value found in *pnd_field* at "
544  "lower latitude limit of the cloudbox." );
545  if( max(pnd_field(joker,joker,g2.nelem()-1,joker)) > 0 )
546  throw runtime_error( "A non-zero value found in *pnd_field* at "
547  "upper latitude limit of the cloudbox." );
548  }
549  if( atmosphere_dim == 3 )
550  {
551  if( max(pnd_field(joker,joker,joker,0)) > 0 )
552  throw runtime_error( "A non-zero value found in *pnd_field* at "
553  "lower longitude limit of the cloudbox." );
554  if( max(pnd_field(joker,joker,joker,g3.nelem()-1)) > 0 )
555  throw runtime_error( "A non-zero value found in *pnd_field* at "
556  "upper longitude limit of the cloudbox." );
557  }
558 
559  // particle_masses
560  //
561  if( particle_masses.nrows() > 0 )
562  {
563  if( particle_masses.nrows() != np )
564  throw runtime_error( "The WSV *particle_masses* must either be "
565  "empty or have a row size matching the "
566  "length of *scat_data_array*." );
567  if( min(particle_masses) < 0 )
568  throw runtime_error(
569  "All values in *particles_masses* must be >= 0." );
570  }
571  }
572 
573  // If here, all OK
574  cloudbox_checked = 1;
575 }
576 
577 
578 
579 
580 
581 /* Workspace method: Doxygen documentation will be auto-generated */
583  Workspace& ws _U_,
584  Index& propmat_clearsky_agenda_checked,
585  // WS Input:
586  const ArrayOfArrayOfSpeciesTag& abs_species,
587  const Agenda& propmat_clearsky_agenda,
588  const Verbosity& )
589 {
590  bool needs_lines = false;
591  bool needs_zeeman = false;
592  bool needs_continua = false;
593  bool needs_cia = false;
594  //bool needs_free_electrons = false;
595  bool needs_particles = false;
596 
597  for (Index sp = 0; sp < abs_species.nelem(); sp++)
598  {
599  for (Index tgs = 0; tgs < abs_species[sp].nelem(); tgs++)
600  {
601  switch (abs_species[sp][tgs].Type())
602  {
603  case SpeciesTag::TYPE_PLAIN: needs_lines = true; break;
604  case SpeciesTag::TYPE_ZEEMAN: needs_zeeman = true; break;
605  case SpeciesTag::TYPE_PREDEF: needs_continua = true; break;
606  case SpeciesTag::TYPE_CIA: needs_cia = true; break;
608  case SpeciesTag::TYPE_PARTICLES: needs_particles = true; break;
609  default:
610  ostringstream os;
611  os << "Unknown species type: " <<
612  abs_species[sp][tgs].Type();
613  throw runtime_error(os.str());
614  break;
615  }
616  }
617  }
618 
619  if ((needs_lines || needs_continua || needs_cia)
620  && !(propmat_clearsky_agenda.has_method("propmat_clearskyAddOnTheFly")
621  || propmat_clearsky_agenda.has_method("propmat_clearskyAddFromLookup")))
622  {
623  throw runtime_error("*abs_species* contains line species, CIA species, or continua but "
624  "*propmat_clearsky_agenda*\n"
625  "does not contain *propmat_clearskyAddOnTheFly* nor "
626  "*propmat_clearskyAddFromLookup*.");
627  }
628 
629  if (needs_zeeman
630  && !propmat_clearsky_agenda.has_method("propmat_clearskyAddZeeman"))
631  {
632  throw runtime_error("*abs_species* contains Zeeman species but *propmat_clearsky_agenda*\n"
633  "does not contain *propmat_clearskyAddZeeman*.");
634  }
635 /*
636  if (needs_free_electrons
637  && !propmat_clearsky_agenda.has_method("propmat_clearskyAddFaraday"))
638  {
639  throw runtime_error("*abs_species* contains free electrons but *propmat_clearsky_agenda*\n"
640  "does not contain *propmat_clearskyAddFaraday*.");
641  }
642 */
643  if (needs_particles
644  && !propmat_clearsky_agenda.has_method("propmat_clearskyAddParticles"))
645  {
646  throw runtime_error("*abs_species* contains particles but *propmat_clearsky_agenda*\n"
647  "does not contain *propmat_clearskyAddParticles*.");
648  }
649 
650  propmat_clearsky_agenda_checked = 1;
651 }
652 
653 
654 
655 
656 
657 /* Workspace method: Doxygen documentation will be auto-generated */
659  Index& sensor_checked,
660  const Index& atmosphere_dim,
661  const Index& stokes_dim,
662  const Vector& f_grid,
663  const Matrix& sensor_pos,
664  const Matrix& sensor_los,
665  const Matrix& transmitter_pos,
666  const Vector& mblock_za_grid,
667  const Vector& mblock_aa_grid,
668  const Index& antenna_dim,
669  const Sparse& sensor_response,
670  const Vector& sensor_response_f,
671  const ArrayOfIndex& sensor_response_pol,
672  const Vector& sensor_response_za,
673  const Vector& sensor_response_aa,
674  const Verbosity& )
675 {
676 
677  // Some sizes
678  const Index nf = f_grid.nelem();
679  const Index nza = mblock_za_grid.nelem();
680  Index naa = mblock_aa_grid.nelem();
681  if( antenna_dim == 1 )
682  { naa = 1; }
683  const Index n1y = sensor_response.nrows();
684  const Index nmblock = sensor_pos.nrows();
685  const Index niyb = nf * nza * naa * stokes_dim;
686 
687 
688  // Sensor position and LOS.
689  //
690  if( sensor_pos.ncols() != atmosphere_dim )
691  throw runtime_error( "The number of columns of sensor_pos must be "
692  "equal to the atmospheric dimensionality." );
693  if( atmosphere_dim <= 2 && sensor_los.ncols() != 1 )
694  throw runtime_error( "For 1D and 2D, sensor_los shall have one column." );
695  if( atmosphere_dim == 3 && sensor_los.ncols() != 2 )
696  throw runtime_error( "For 3D, sensor_los shall have two columns." );
697  if( sensor_los.nrows() != nmblock )
698  {
699  ostringstream os;
700  os << "The number of rows of sensor_pos and sensor_los must be "
701  << "identical, but sensor_pos has " << nmblock << " rows,\n"
702  << "while sensor_los has " << sensor_los.nrows() << " rows.";
703  throw runtime_error( os.str() );
704  }
705  if( max( sensor_los(joker,0) ) > 180 )
706  throw runtime_error(
707  "First column of *sensor_los* is not allowed to have values above 180." );
708  if( atmosphere_dim == 2 )
709  {
710  if( min( sensor_los(joker,0) ) < -180 )
711  throw runtime_error( "For atmosphere_dim = 2, first column of "
712  "*sensor_los* is not allowed to have values below -180." );
713  }
714  else
715  {
716  if( min( sensor_los(joker,0) ) < 0 )
717  throw runtime_error( "For atmosphere_dim != 2, first column of "
718  "*sensor_los* is not allowed to have values below 0." );
719  }
720  if( atmosphere_dim == 3 && max( sensor_los(joker,1) ) > 180 )
721  throw runtime_error(
722  "Second column of *sensor_los* is not allowed to have values above 180." );
723 
724  // Transmission position.
725  if( transmitter_pos.ncols() > 0 && transmitter_pos.nrows() > 0 )
726  {
727  if( transmitter_pos.nrows() != sensor_pos.nrows() )
728  throw runtime_error( "*transmitter_pos* must either be empty or have "
729  "the same number of rows as *sensor_pos*." );
730  if( transmitter_pos.ncols() != max(Index(2),atmosphere_dim) )
731  throw runtime_error( "*transmitter_pos* must either be empty, have "
732  "2 for 1D/2D or 3 columns for 3D." );
733  }
734 
735  // Antenna
736  //
737  chk_if_in_range( "antenna_dim", antenna_dim, 1, 2 );
738  //
739  if( nza == 0 )
740  throw runtime_error( "The measurement block zenith angle grid is empty." );
741  chk_if_increasing( "mblock_za_grid", mblock_za_grid );
742  //
743  if( antenna_dim == 1 )
744  {
745  if( mblock_aa_grid.nelem() != 0 )
746  throw runtime_error(
747  "For antenna_dim = 1, the azimuthal angle grid must be empty." );
748  }
749  else
750  {
751  if( atmosphere_dim < 3 )
752  throw runtime_error( "2D antennas (antenna_dim=2) can only be "
753  "used with 3D atmospheres." );
754  if( mblock_aa_grid.nelem() == 0 )
755  throw runtime_error(
756  "The measurement block azimuthal angle grid is empty." );
757  chk_if_increasing( "mblock_aa_grid", mblock_aa_grid );
758  }
759 
760  // Sensor
761  //
762  if( sensor_response.ncols() != niyb )
763  {
764  ostringstream os;
765  os << "The *sensor_response* matrix does not have the right size,\n"
766  << "either the method *sensor_responseInit* has not been run or some\n"
767  << "of the other sensor response methods has not been correctly\n"
768  << "configured.";
769  throw runtime_error( os.str() );
770  }
771 
772  // Sensor aux variables
773  //
774  if( antenna_dim==1 && sensor_response_aa.nelem() )
775  throw runtime_error( "If *antenna_dim* is 1, *sensor_response_aa* must "
776  "be empty." );
777 
778  if( n1y != sensor_response_f.nelem() || n1y != sensor_response_pol.nelem() ||
779  n1y != sensor_response_za.nelem() ||
780  ( antenna_dim==2 && n1y != sensor_response_aa.nelem() ) )
781  {
782  ostringstream os;
783  os << "Sensor auxiliary variables do not have the correct size.\n"
784  << "The following variables should all have same size:\n"
785  << "length of y for one block : " << n1y << "\n"
786  << "sensor_response_f.nelem() : " << sensor_response_f.nelem()
787  << "\nsensor_response_pol.nelem(): " << sensor_response_pol.nelem()
788  << "\nsensor_response_za.nelem() : " << sensor_response_za.nelem()
789  << "\n";
790  if( antenna_dim == 2 )
791  { os << "sensor_response_aa.nelem() : " << sensor_response_aa.nelem()
792  << "\n"; }
793  throw runtime_error( os.str() );
794  }
795 
796  // If here, all OK
797  sensor_checked = 1;
798 }
INDEX Index
The type to use for all integer numbers and indices.
Definition: matpack.h:35
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:115
The Agenda class.
Definition: agenda_class.h:44
Index nelem() const
Number of elements.
Definition: array.h:176
void chk_atm_surface(const String &x_name, const Matrix &x, const Index &dim, ConstVectorView lat_grid, ConstVectorView lon_grid)
chk_atm_surface
void chk_if_increasing(const String &x_name, const ArrayOfIndex &x)
chk_if_increasing
Definition: check_input.cc:132
The Vector class.
Definition: matpackI.h:556
The Sparse class.
Definition: matpackII.h:55
The Tensor4 class.
Definition: matpackIV.h:383
Index ncols() const
Returns the number of columns.
Definition: matpackII.cc:62
void chk_if_bool(const String &x_name, const Index &x)
chk_if_bool
Definition: check_input.cc:73
Index nrows() const
Returns the number of rows.
Definition: matpackIII.h:146
Index nelem() const
Returns the number of elements.
Definition: matpackI.cc:180
Index ncols() const
Returns the number of columns.
Definition: matpackI.cc:838
The Tensor3 class.
Definition: matpackIII.h:348
The global header file for ARTS.
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 Vector &mblock_za_grid, const Vector &mblock_aa_grid, const Index &antenna_dim, const Sparse &sensor_response, const Vector &sensor_response_f, const ArrayOfIndex &sensor_response_pol, const Vector &sensor_response_za, const Vector &sensor_response_aa, const Verbosity &)
WORKSPACE METHOD: sensor_checkedCalc.
Definition: m_checked.cc:658
bool has_method(const String &methodname) const
Check if method is in Agenda.
const Numeric DEG2RAD
Index ncols() const
Returns the number of columns.
Definition: matpackIII.h:149
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 ArrayOfSingleScatteringData &scat_data_array, const Matrix &particle_masses, const ArrayOfArrayOfSpeciesTag &abs_species, const Verbosity &)
WORKSPACE METHOD: cloudbox_checkedCalc.
Definition: m_checked.cc:335
#define max(a, b)
Definition: continua.cc:20461
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 Verbosity &)
WORKSPACE METHOD: atmgeom_checkedCalc.
Definition: m_checked.cc:252
Index nrows() const
Returns the number of rows.
Definition: matpackII.cc:56
#define abs(x)
Definition: continua.cc:20458
const Joker joker
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: matpack.h:29
The Matrix class.
Definition: matpackI.h:788
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
Index npages() const
Returns the number of pages.
Definition: matpackIII.h:143
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:101
void resize(Index n)
Assignment operator from VectorView.
Definition: matpackI.cc:798
#define min(a, b)
Definition: continua.cc:20460
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:582
void chk_atm_field(const String &x_name, ConstTensor3View x, const Index &dim, ConstVectorView p_grid, ConstVectorView lat_grid, ConstVectorView lon_grid, const bool &chk_lat90)
chk_atm_field (simple fields)
Workspace class.
Definition: workspace_ng.h:47
#define _U_
Definition: config.h:167
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:46
void chk_atm_grids(const Index &dim, ConstVectorView p_grid, ConstVectorView lat_grid, ConstVectorView lon_grid)
chk_atm_grids
Index nrows() const
Returns the number of rows.
Definition: matpackI.cc:832