ARTS  1.0.222
m_los.cc
Go to the documentation of this file.
1 /* Copyright (C) 2000, 2001 Patrick Eriksson <patrick@rss.chalmers.se>
2 
3  This program is free software; you can redistribute it and/or modify it
4  under the terms of the GNU General Public License as published by the
5  Free Software Foundation; either version 2, or (at your option) any
6  later version.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16  USA. */
17 
18 
19 
21 // File description
23 
44 // External declarations
47 
48 #include <cmath>
49 #include "arts.h"
50 #include "atm_funcs.h"
51 #include "complex.h"
52 #include "matpackI.h"
53 #include "los.h"
54 #include "math_funcs.h"
55 #include "messages.h"
56 #include "auto_wsv.h"
57 #include "auto_md.h"
58 extern const Numeric PI;
59 extern const Numeric DEG2RAD;
60 extern const Numeric RAD2DEG;
61 extern const Numeric COSMIC_BG_TEMP;
62 extern const Numeric SUN_TEMP;
63 extern const Numeric PLANCK_CONST;
64 extern const Numeric BOLTZMAN_CONST;
65 extern const Numeric SPEED_OF_LIGHT;
66 extern const Numeric EARTH_GRAV_CONST;
67 extern const Numeric AVOGADROS_NUMB;
68 
69 
71 // LOS help functions
73 
75 
86 bool any_ground( const ArrayOfIndex& ground )
87 {
88  for ( Index i=0; i<ground.nelem(); i++ )
89  {
90  if ( ground[i] )
91  return 1;
92  }
93  return 0;
94 }
95 
96 
97 
98 
100 
127  Vector& z,
128  Vector& psi,
129  Numeric& l_step,
130  const Numeric& z_plat,
131  const Numeric& za,
132  const Numeric& atm_limit,
133  const Numeric& r_geoid )
134 {
135  // A safety check
136  assert( za <= 90 );
137 
138  Vector l; // Lengths along the LOS from the tangent point
139  Index nz; // Length of z and psi
140 
141  // Some temporary values are always double to avoid numerical problems
142  // (this is especially a problem where r_geoid is squared).
143  double a, b; // Temporary values
144  double llim; // distance to atmospheric limit
145 
146  // Distance from the lowest point of the LOS to the atmospheric limit
147  a = r_geoid + atm_limit;
148  b = (r_geoid+z_plat) * sin(DEG2RAD*za);
149  llim = sqrt( a*a - b*b ) - (r_geoid+z_plat)*cos(DEG2RAD*za) ;
150 
151  // Handle the rare case that llim < l_step
152  if ( llim < l_step )
153  l_step = llim*0.9999; // *0.9999 to avoid problem in interpolations
154 
155  // Create equally spaced points along the LOS
156  linspace( l, 0, llim, l_step );
157 
158  nz = l.nelem();
159  z.resize( nz );
160  psi.resize( nz );
161 
162  // Calculate vertical altitudes and angles
163  b = r_geoid + z_plat;
164  a = b * b;
165  //
166  for ( Index i=0; i<nz; i++ )
167  {
168  z[i] = sqrt( a + l[i]*l[i] + 2.0*b*l[i]*cos(DEG2RAD*za) );
169  psi[i] = RAD2DEG * acos( (a+z[i]*z[i]-l[i]*l[i]) / (2.0*b*z[i]) );
170 
171  // Nan can in some cases be obtained for very small angles
172  if ( isnan(psi[i]) )
173  psi[i] = 0;
174 
175  z[i] = z[i] - r_geoid;
176  }
177 }
178 
179 
180 
182 
206  Vector& z,
207  Vector& psi,
208  Numeric& l_step,
209  const Numeric& z_plat,
210  const Numeric& za,
211  const Numeric& atm_limit,
212  const Numeric& r_geoid,
213  const Vector& /* p_abs */,
214  const Vector& z_abs,
215  const Index& /* refr */,
216  const Index& refr_lfac,
217  const Vector& refr_index,
218  const Numeric& c )
219 {
220  // A safety check
221  assert( za <= 90 );
222 
223  // Allocate memory for temporary z and psi. To be safe, make vectors 50 %
224  // as long than for the geometric case
225  Index np;
226  {
227  // Distance from the lowest point of the LOS to the atmospheric limit
228  double a = r_geoid + atm_limit;
229  double b = (r_geoid+z_plat) * sin(DEG2RAD*za);
230  double llim = sqrt( a*a - b*b ) - (r_geoid+z_plat)*cos(DEG2RAD*za) ;
231 
232  // Handle the rare case that llim < l_step
233  if ( llim < l_step )
234  l_step = llim*0.9999; // *0.9999 to avoid problem in interpolations
235 
236  np = Index( ceil( 1.5 * ( llim/l_step + 1) ) );
237  }
238  Vector zv(np), pv(np);
239 
240  // Double is used here instead of Numeric to avoid nuerical problems
241  const double l = l_step / (double)refr_lfac; // Step length of ray tracing
242  Index i = refr_lfac; // Ray tracing step counter
243  double z1; // Old altitude of the LOS
244  double z2 = z_plat; // New altitude of the LOS
245  double rz1, rz2; // As z1 and z2 but + r_geoid
246  double psi1; // Old angle of the LOS
247  double psi2 = 0; // New angle of the LOS
248  double n1, n2; // Refractive index at z1 and z2
249  double n; // Either n1 or the mean of n1 and n2
250  double c2=c; c2 = c2 * c2; // Square of the LOS constant
251  Index j; // See below
252  double d, e, f; // Some temporary values
253 
254  np = 0;
255 
256  // To save computational time, the interpolation is handled locally so
257  // the indeces for the refr_index vector can be remembered from one
258  // interpolation to next.
259  const Index nz = z_abs.nelem();
260  Index iz;
261  for ( iz=0; (iz<nz) && (z_abs[iz]<=z2); iz++ ) {}
262  if ( iz < nz )
263  n2 = refr_index[iz-1] + (refr_index[iz]-refr_index[iz-1])*
264  (z2-z_abs[iz-1])/(z_abs[iz]-z_abs[iz-1]);
265  else
266  n2 = 1;
267 
268  while ( z2 <= atm_limit )
269  {
270 
271  z1 = z2;
272  psi1 = psi2;
273  n1 = n2;
274 
275  if ( i == Index(refr_lfac) )
276  {
277  zv[np] = z2;
278  pv[np] = RAD2DEG * psi2;
279  i = 1;
280  np++;
281  assert( np < zv.nelem() );
282  }
283  else
284  i++;
285 
286  // We repeat the calculation of z2 some times to get better estimates for
287  // a mean of value of n between z1 and z2. For first iteration n is set
288  // to n1, and for later iteration as the mean of n1 and n2.
289  //
290  // A practical test showed a clear improvement when doing 2 iterations
291  // instead of a single iteration, but just a marginally improvement when
292  // going to 3 iterations. So 2 iterations seem to be the best choice.
293  //
294  for ( j=1; j<=2; j++ )
295  {
296 
297  if ( j == 1 )
298  n = n1;
299  else
300  n = ( n1 + n2 ) / 2;
301 
302  rz1 = z1 + r_geoid;
303  d = rz1 * rz1;
304  e = c2/(n*n);
305  f = d - e;
306 
307  // When using float, there have been NaNs here (due to z1 < c/n).
308  // So we must make a check to avoid these NaNs.
309  //
310  if ( f <= 0 )
311  rz2 = sqrt( l*l + e );
312  else
313  rz2 = sqrt( pow( l + sqrt(f), 2 ) + e );
314 
315  z2 = rz2 - r_geoid;
316 
317  // Determine n at z2
318  for ( ; (iz<nz) && (z_abs[iz]<=z2); iz++ ) {}
319  if ( iz < nz )
320  n2 = refr_index[iz-1] + (refr_index[iz]-refr_index[iz-1])*
321  (z2-z_abs[iz-1])/(z_abs[iz]-z_abs[iz-1]);
322  else
323  n2 = 1;
324  }
325 
326  psi2 = psi1 + acos( (d+rz2*rz2-l*l) / (2*rz1*rz2) );
327  }
328 
329  // Move values from temporary vectors
330  z.resize( np );
331  psi.resize( np );
332  z = zv[Range(0,np)]; // Copy first np values of zv to z.
333  psi = pv[Range(0,np)]; // Copy first np values of pv to psi.
334 }
335 
336 
337 
339 // The sub-function to losCalc
341 
343 
372 void los_1za(
373  Vector& z,
374  Vector& psi,
375  Numeric& l_step,
376  Index& ground,
377  Index& start,
378  Index& stop,
379  Numeric& z_tan,
380  const Numeric& z_plat,
381  const Numeric& za,
382  const Numeric& l_step_max,
383  const Numeric& z_ground,
384  const Numeric& r_geoid,
385  const Vector& p_abs,
386  const Vector& z_abs,
387  const Index& refr,
388  const Index& refr_lfac,
389  const Vector& refr_index )
390 {
391  Numeric c; // LOS constant when considering refraction
392 
393  // Determine the upper limit of the atmosphere
394  const Numeric atm_limit = last(z_abs);
395 
396  if ( refr )
397  {
398  c = refr_constant( r_geoid, za, z_plat, p_abs, z_abs, atm_limit,
399  refr_index );
400  z_tan = ztan_refr( c, za, z_plat, z_ground, p_abs, z_abs, refr_index,
401  r_geoid );
402  }
403  else
404  z_tan = ztan_geom( za, z_plat, r_geoid );
405 
406  // Set l_step to its most probable value
407  l_step = l_step_max;
408 
409 
410  //=== Observation from space ================================================
411  if ( z_plat >= atm_limit )
412  {
413  Index nz; // Length of z and psi
414  Numeric psi0 = 0; // Correction value for psi
415 
416  out3 << " (z_tan = " << z_tan/1e3 << " km)";
417 
418  // If LOS outside the atmosphere, return empty vectors
419  if ( z_tan >= atm_limit )
420  {
421  ground = 0;
422  z.resize( 0 );
423  psi.resize( 0 );
424  nz = 1;
425  }
426 
427  // Only through the atmosphere
428  else if ( z_tan >= z_ground )
429  {
430  if ( !refr )
431  {
432  los_geometric( z, psi, l_step, z_tan, 90.0, atm_limit, r_geoid );
433  psi0 = za - 90.0;
434  }
435  else
436  {
437  los_refraction( z, psi, l_step, z_tan, 90.0, atm_limit, r_geoid,
438  p_abs, z_abs, refr, refr_lfac, refr_index, c );
439 
440  // Determine the "zenith angle" of the LOS at the top of the atmosphere
441  Numeric zmax = last( z );
442  Numeric n = interpz( p_abs, z_abs, refr_index, zmax );
443  Numeric theta = RAD2DEG * asin( c / ((r_geoid+zmax)*n) );
444 
445  psi0 = theta + za - 180.0 + last(psi);
446  }
447 
448  ground = 0;
449  nz = z.nelem();
450  }
451 
452  // Intersection with the ground
453  else
454  {
455  // The "zenith angle" at ground level
456  Numeric za_g;
457 
458  if ( !refr )
459  {
460  za_g = RAD2DEG * asin( (r_geoid+z_tan) / (r_geoid+z_ground) );
461 
462  los_geometric( z, psi, l_step, z_ground, za_g, atm_limit, r_geoid );
463 
464  psi0 = za + za_g - 180.0;
465  }
466  else
467  {
468  za_g = RAD2DEG * asin( c / ( (r_geoid+z_ground) *
469  n_for_z( z_ground, p_abs, z_abs, refr_index, atm_limit ) ) );
470 
471  los_refraction( z, psi, l_step, z_ground, za_g, atm_limit, r_geoid,
472  p_abs, z_abs, refr, refr_lfac, refr_index, c );
473 
474  // Determine the "zenith angle" of the LOS at the top of the atmosphere
475  Numeric zmax = last( z );
476  Numeric n = n_for_z( zmax, p_abs, z_abs, refr_index, atm_limit );
477  Numeric theta = RAD2DEG * asin( c / ((r_geoid+zmax)*n) );
478 
479  psi0 = theta + za - 180.0 + last(psi);
480  }
481 
482  ground = 1;
483  nz = z.nelem();
484  }
485 
486  // Add psi0 to all elements:
487  if ( psi0 != 0 )
488  psi += psi0;
489 
490  start = stop = nz - 1;
491  }
492 
493 
494  //=== Inside the atmosphere looking upwards =================================
495  else if ( za <= 90 )
496  {
497  if ( !refr )
498  los_geometric( z, psi, l_step, z_plat, za, atm_limit, r_geoid );
499  else
500  los_refraction( z, psi, l_step, z_plat, za, atm_limit, r_geoid,
501  p_abs, z_abs, refr, refr_lfac, refr_index, c );
502  ground = 0;
503  stop = 0;
504  start = z.nelem() - 1;
505  }
506 
507  //=== Inside the atmosphere looking downwards ===============================
508  else
509  {
510  // Some temporary values are always double to avoid numerical problems
511  // (this is especially a problem where r_geoid is squared).
512  double l1; // Distance between platform and tangent point or ground
513  double a, b; // Temporary values
514 
515  out3 << " (z_tan = " << z_tan/1e3 << " km)";
516 
517  // Only through the atmosphere
518  if ( z_tan >= z_ground )
519  {
520  if ( !refr )
521  {
522  // Calculate the distance platform-tangent point
523  a = r_geoid + z_plat;
524  b = r_geoid + z_tan;
525  l1 = sqrt(a*a-b*b);
526 
527  // A sufficient large distance between platform and tangent point
528  if ( l1 > l_step_max/10 )
529  {
530  // Adjust l_step downwards to get an integer number of steps
531  stop = Index( ceil( l1 / l_step_max + 1.0 ) - 1 );
532  l_step = l1 / Numeric(stop);
533  }
534 
535  // Ignore downwrd part if platform is very close to tangent point
536  else
537  {
538  l_step = l_step_max;
539  stop = 0;
540  }
541 
542  los_geometric( z, psi, l_step, z_tan, 90.0, atm_limit, r_geoid );
543  }
544  else
545  {
546  // Calculate a first LOS from the tangent point and up to the sensor
547  // using l_step/refr_lfac as step length
548  Numeric l = l_step / (Numeric)refr_lfac;
549  los_refraction( z, psi, l, z_tan, 90.0, z_plat+l, r_geoid,
550  p_abs, z_abs, refr, 1, refr_index, c );
551 
552  // Determine the distance along the LOS between the tangent point and
553  // the sensor by an interpolation
554  {
555  Vector ls;
556  linspace( ls, 0, l*(Numeric)(z.nelem()-1) , l );
557  l1 = interp_lin( z, ls, z_plat );
558  }
559 
560  // A sufficient large distance between platform and tangent point
561  if ( l1 > l_step_max/10 )
562  {
563  // Adjust l_step downwards to get an integer number of steps
564  stop = Index( ceil( l1 / l_step_max + 1.0 ) - 1 );
565  l_step = l1 / Numeric(stop);
566  }
567 
568  // Ignore downwrd part if platform is very close to tangent point
569  else
570  {
571  l_step = l_step_max;
572  stop = 0;
573  }
574 
575  los_refraction( z, psi, l_step, z_tan, 90.0, atm_limit, r_geoid,
576  p_abs, z_abs, refr, refr_lfac, refr_index, c );
577  }
578 
579  ground = 0;
580  start = z.nelem() - 1;
581 
582  // The angular distance between the sensor and the tangent point
583  // is psi[stop]
584  psi += psi[stop]; // Matpack can add element-vise like this.
585  }
586 
587  // Intersection with the ground
588  else
589  {
590  Numeric za_g; // The "zenith angle" at ground level
591 
592  if ( !refr )
593  {
594  // Calculate the distance platform-ground
595  a = r_geoid + z_plat;
596  b = r_geoid + z_tan;
597  b = b * b;
598  l1 = sqrt(a*a-b);
599  a = r_geoid + z_ground;
600  l1 = l1 - sqrt(a*a-b);
601 
602  // A sufficient large distance between platform and ground
603  if ( l1 > l_step_max/10 )
604  {
605  // Adjust l_step downwards to get an integer number of steps
606  stop = Index( ceil( l1 / l_step_max + 1.0 ) - 1 );
607  l_step = l1 / Numeric(stop);
608  }
609 
610  // Ignore downwrd part if platform is very close to ground
611  else
612  {
613  l_step = l_step_max;
614  stop = 0;
615  }
616 
617  za_g = RAD2DEG * asin( (r_geoid+z_tan) / (r_geoid+z_ground) );
618 
619  los_geometric( z, psi, l_step, z_ground, za_g, atm_limit, r_geoid );
620  }
621 
622  else
623  {
624  za_g = RAD2DEG * asin( c / ( (r_geoid+z_ground) *
625  n_for_z( z_ground, p_abs, z_abs, refr_index, atm_limit ) ) );
626 
627  Numeric l = l_step / (Numeric)refr_lfac;
628  los_refraction( z, psi, l, z_ground, za_g, z_plat+l, r_geoid,
629  p_abs, z_abs, refr, 1, refr_index, c );
630 
631  // Determine the distance along the LOS between the tangent point and
632  // the sensor by an interpolation
633  {
634  Vector ls;
635  linspace( ls, 0, l*(Numeric)(z.nelem()-1) , l );
636  l1 = interp_lin( z, ls, z_plat );
637  }
638 
639  // A sufficient large distance between platform and ground
640  if ( l1 > l_step_max/10 )
641  {
642  // Adjust l_step downwards to get an integer number of steps
643  stop = Index( ceil( l1 / l_step_max + 1.0 ) - 1 );
644  l_step = l1 / Numeric(stop);
645  }
646 
647  // Ignore downwrd part if platform is very close to ground
648  else
649  {
650  l_step = l_step_max;
651  stop = 0;
652  }
653 
654  los_refraction( z, psi, l_step, z_ground, za_g, atm_limit, r_geoid,
655  p_abs, z_abs, refr, refr_lfac, refr_index, c );
656  }
657 
658  ground = 1;
659  start = z.nelem() - 1;
660 
661  // The angular distance between the sensor and the ground
662  // is psi[stop]
663  psi += psi[stop]; // Matpack can add element-vise like this.
664  }
665  }
666 }
667 
668 
669 
671 // The sub-function to yCalc
673 
678 void y_rte (
679  Vector& y,
680  const Los& los,
681  ConstVectorView f_mono,
682  ConstVectorView y_space,
683  const ArrayOfMatrix& source,
684  const ArrayOfMatrix& trans,
685  ConstVectorView e_ground,
686  const Numeric& t_ground,
687  const Index& z_start,
688  const Index& z_end )
689 {
690  // Some variables
691  const Index n=los.start.nelem(); // Number of zenith angles
692  const Index nf=f_mono.nelem(); // Number of frequencies
693  Vector y_tmp(nf); // Temporary storage for spectra
694  Index iy0=0; // Reference index for output vector
695 
696  out2 << " Integrating the radiative transfer eq. with emission.\n";
697 
698  assert (z_start >= 0);
699  assert (z_end < n);
700 
701  // Resize y
702  y.resize( nf* (z_end - z_start + 1) );
703 
704  // Set up vector for ground blackbody radiation if any ground intersection
705  // Check also if the ground emission vector has the correct length
706  Vector y_ground(f_mono.nelem());
707  if ( any_ground(los.ground) )
708  {
709  if ( t_ground <= 0 )
710  throw runtime_error(
711  "There are intersections with the ground, but the ground\n"
712  "temperature is set to be <=0 (are dummy values used?).");
713  if ( e_ground.nelem() != nf )
714  throw runtime_error(
715  "There are intersections with the ground, but the frequency and\n"
716  "ground emission vectors have different lengths (are dummy values\n"
717  "used?).");
718  out2 << " There are intersections with the ground.\n";
719  planck( y_ground, f_mono, t_ground );
720  }
721 
722  // Loop zenith angles
723  out3 << " Zenith angle nr: ";
724  for ( Index i = z_start; i <= z_end; i++ )
725  {
726  if ( (i%20)==0 )
727  out3 << "\n ";
728  out3 << " " << i; cout.flush();
729 
730  // Iteration is done in seperate function
731  rte( y_tmp, los.start[i], los.stop[i], trans[i],
732  source[i], y_space, los.ground[i], e_ground, y_ground);
733 
734  // Move values to output vector
735  y[Range(iy0,nf)] = y_tmp; // Copy to nf elements to y, starting at iy0.
736 
737  // Update iy0
738  iy0 += nf;
739  }
740  out3 << "\n";
741 }
742 
743 
748 void y_tau (
749  Vector& y,
750  const Los& los,
751  const ArrayOfMatrix& trans,
752  ConstVectorView e_ground,
753  const Index& z_start,
754  const Index& z_end )
755 {
756  // Some variables
757  const Index n=los.start.nelem(); // Number of zenith angles
758  const Index nf=trans[0].nrows(); // Number of frequencies
759  Index iy, iy0=0; // Index for output vector
760  Vector y_tmp; // Temporary storage for spectra
761 
762  assert (z_start >= 0);
763  assert (z_end < n);
764 
765  out2 << " Calculating optical thicknesses.\n";
766 
767  // Resize y and set to 1
768  y.resize( nf*n );
769  y = 1.0; // Matpack can set all elements like this.
770 
771  // Check if the ground emission vector has the correct length
772  if ( any_ground(los.ground) )
773  {
774  if ( e_ground.nelem() != nf )
775  throw runtime_error(
776  "There are intersections with the ground, but the frequency and\n"
777  "ground emission vectors have different lengths (are dummy values\n"
778  "used?).");
779  out2 << " There are intersections with the ground.\n";
780  }
781 
782  // Loop zenith angles
783  out3 << " Zenith angle nr: ";
784  for ( Index i = z_start; i <= z_end; i++ )
785  {
786  if ( (i%20)==0 )
787  out3 << "\n ";
788  out3 << " " << i; cout.flush();
789 
790  // Iteration is done in seperate function
791  bl( y_tmp, los.start[i], los.stop[i], trans[i], los.ground[i], e_ground );
792 
793  // Convert to optical thicknesses and move values to output vector
794  for ( iy=0; iy<nf; iy++ )
795  y[iy0+iy] = -log( y_tmp[iy] );
796 
797  // Update iy0
798  iy0 += nf;
799  }
800  out3 << "\n";
801 }
802 
803 
804 
805 
807 // Workspace methods
809 
816 void r_geoidStd( Numeric& r_geoid )
817 {
818  extern const Numeric EARTH_RADIUS;
819  r_geoid = EARTH_RADIUS;
820 }
821 
822 
830  Numeric& r_geoid,
831  const Numeric& latitude,
832  const Numeric& obsdirection )
833 {
834  check_if_in_range( -90, 90, latitude, "latitude" );
835  check_if_in_range( -360, 360, obsdirection, "obsdirection" );
836 
837  const Numeric rq = 6378.138e3, rp = 6356.752e3;
838  Numeric a, b, rns, rew;
839 
840  // Calculate NS and EW radius
841  a = cos(latitude*DEG2RAD);
842  b = sin(latitude*DEG2RAD);
843  rns = rq*rq*rp*rp/pow(rq*rq*a*a+rp*rp*b*b,(Numeric)1.5);
844  rew = rq*rq/sqrt(rq*rq*a*a+rp*rp*b*b);
845 
846  // Calculate the radius in the observation direction
847  a = cos(obsdirection*DEG2RAD);
848  b = sin(obsdirection*DEG2RAD);
849  r_geoid = 1/(a*a/rns+b*b/rew);
850 }
851 
852 
853 
860 void groundOff(
861  Numeric& z_ground,
862  Numeric& t_ground,
863  Vector& e_ground,
864  const Vector& z_abs )
865 {
866  z_ground = z_abs[0];
867  t_ground = 0;
868  e_ground.resize( 0 );
869 }
870 
871 
872 
879 void groundSet(
880  Numeric& z_ground,
881  Numeric& t_ground,
882  Vector& e_ground,
883  const Vector& p_abs,
884  const Vector& t_abs,
885  const Vector& z_abs,
886  const Vector& f_mono,
887  const Numeric& z,
888  const Numeric& e )
889 {
890  check_if_in_range( 0, 1, e, "e" );
891  z_ground = z;
892  t_ground = interpz( p_abs, z_abs, t_abs, z );
893  e_ground.resize( f_mono.nelem() );
894  e_ground = e;
895 }
896 
897 
898 
906  Numeric& z_ground,
907  Numeric& t_ground,
908  Vector& e_ground,
909  const Vector& t_abs,
910  const Vector& z_abs,
911  const Vector& f_mono,
912  const Numeric& e )
913 {
914  check_if_in_range( 0, 1, e, "e" );
915  z_ground = z_abs[0];
916  t_ground = t_abs[0];
917  e_ground.resize( f_mono.nelem() );
918  e_ground = e; // Matpack can set all elements like this.
919 }
920 
921 
922 
930  Numeric& z_ground,
931  Numeric& t_ground,
932  Vector& e_ground,
933  const Vector& p_abs,
934  const Vector& t_abs,
935  const Vector& z_abs,
936  const Vector& f_mono,
937  const Vector& za_pencil,
938  const Numeric& z_plat,
939  const Numeric& r_geoid,
940  const Index& refr,
941  const Vector& refr_index,
942  const String& pol,
943  const Numeric& t_skin )
944 {
945  if( z_abs[0] > 0 || z_abs[z_abs.nelem()-1] < 0 )
946  throw runtime_error( "The WSV *z_abs* must span 0 m." );
947  if( min(f_mono) < 10e9 || max(f_mono) > 1000e9 )
948  throw runtime_error(
949  "Frequencies below 10 GHz or above 1000 GHz are not allowed." );
950 
951  z_ground = z_abs[0];
952 
953  if( t_skin > 0 )
954  { t_ground = t_skin; }
955  else
956  { t_ground = interpz( p_abs, z_abs, t_abs, 0 ); }
957 
958  // Calculate indidence angle
959  Numeric n_plat = 1, n_ground = 1;
960  if( refr )
961  {
962  n_plat = n_for_z( z_plat, p_abs, z_abs, refr_index, last(z_abs) );
963  n_ground = n_for_z( z_ground, p_abs, z_abs, refr_index, last(z_abs) );
964  }
965  Numeric sintheta = n_plat * (r_geoid+z_plat) * sin(DEG2RAD*max(za_pencil))
966  / ( n_ground * (r_geoid+z_ground) );
967  // If no LOS hits the ground, sintheta will be > 1. We set the angle then
968  // to 90 degreees.
969  if( sintheta > 1 )
970  { sintheta = 1; }
971  //
972  const Numeric costheta = sqrt( 1 - sintheta*sintheta );
973 
974 
975  // The expressions for the dielectric constant are taken from the file
976  // epswater93.m (by C. Mätzler), part of Atmlab.
977  // The constant e2 is here set to 3.52, which according to Mätzler
978  // corresponds to Liebe 1993.
979 
980  // Some constants
981  const Numeric theta = 1 - 300 / t_ground;
982  const Numeric e0 = 77.66 - 103.3 * theta;
983  const Numeric e1 = 0.0671 * e0;
984  const Numeric f1 = 20.2 + 146.4 * theta + 316 * theta * theta;
985  const Numeric e2 = 3.52;
986  const Numeric f2 = 39.8 * f1;
987  //
988  const Numeric n1 = 1;
989 
990 
991  // Loop frequencies
992  //
993  e_ground.resize( f_mono.nelem() );
994  //
995  for( Index i=0; i<f_mono.nelem(); i++ )
996  {
997  const Complex ifGHz( 0.0, f_mono[i]/1e9 );
998 
999  const Complex eps = e2 + (e1-e2) / (Numeric(1.0)-ifGHz/f2) +
1000  (e0-e1) / (Numeric(1.0)-ifGHz/f1);
1001  const Complex n2 = sqrt( eps );
1002  Complex a,b;
1003 
1004  if( pol == "v" )
1005  {
1006  a = n2 * costheta;
1007  b = n1 * cos( asin( n1 * sintheta / n2.real() ) );
1008  }
1009  else if( pol == "h" )
1010  {
1011  a = n1 * costheta;
1012  b = n2 * cos( asin( n1 * sintheta / n2.real() ) );
1013  }
1014  else
1015  throw runtime_error(
1016  "The keyword argument *pol* must be \"v\" or \"h\"." );
1017 
1018  // Power reflection coefficient
1019  const Numeric r = pow( abs( ( a - b ) / ( a + b ) ), Numeric(2.0) );
1020 
1021  e_ground[i] = 1 - r;
1022  }
1023 }
1024 
1025 
1026 
1033 void emissionOn( Index& emission )
1034 {
1035  emission = 1;
1036 }
1037 
1038 
1045 void emissionOff( Index& emission )
1046 {
1047  emission = 0;
1048 }
1049 
1050 
1051 
1058 void losCalc( Los& los,
1059  Vector& z_tan,
1060  const Numeric& z_plat,
1061  const Vector& za,
1062  const Numeric& l_step,
1063  const Vector& p_abs,
1064  const Vector& z_abs,
1065  const Index& refr,
1066  const Index& refr_lfac,
1067  const Vector& refr_index,
1068  const Numeric& z_ground,
1069  const Numeric& r_geoid )
1070 {
1071  Index n = za.nelem(); // number of zenith angles
1072 
1073  // Some checks
1074  check_if_bool( refr, "refr" );
1075  if ( z_ground < z_abs[0] )
1076  throw runtime_error(
1077  "There is a gap between the ground and the lowest absorption altitude.");
1078  if ( z_plat < z_ground )
1079  throw runtime_error("Your platform altitude is below the ground.");
1080  if ( z_plat < z_abs[0] )
1081  throw runtime_error(
1082  "The platform cannot be below the lowest absorption altitude.");
1083  if ( refr && ( p_abs.nelem() != refr_index.nelem() ) )
1084  throw runtime_error(
1085  "Refraction is turned on, but the length of refr_index does not match\n"
1086  "the length of p_abs. Are dummy vales used?");
1087  if ( refr && ( refr_lfac < 1 ) )
1088  throw runtime_error(
1089  "Refraction is turned on, but the refraction length factor is < 1. \n"
1090  "Are dummy vales used?");
1091 
1092  // Reallocate the los structure and z_tan
1093  los.p.resize( n );
1094  los.psi.resize( n );
1095  los.z.resize( n );
1096  los.l_step.resize( n );
1097  los.ground.resize( n );
1098  los.start.resize( n );
1099  los.stop.resize( n );
1100  z_tan.resize( n );
1101 
1102  // Print messages
1103  if ( refr == 0 )
1104  out2 << " Calculating line of sights WITHOUT refraction.\n";
1105  else if ( refr == 1 )
1106  out2 << " Calculating line of sights WITH refraction.\n";
1107  //
1108  out3 << " z_plat: " << z_plat/1e3 << " km\n";
1109 
1110  // Loop the zenith angles
1111  for ( Index i=0; i<n; i++ )
1112  {
1113  out3 << " za: " << za[i] << " degs.";
1114 
1115  los_1za( los.z[i], los.psi[i], los.l_step[i], los.ground[i], los.start[i],
1116  los.stop[i], z_tan[i], z_plat, za[i], l_step, z_ground, r_geoid,
1117  p_abs, z_abs, refr, refr_lfac, refr_index );
1118  out3 << "\n";
1119 
1120  // Convert altitudes to pressures
1121  los.p[i].resize( los.z[i].nelem() );
1122  z2p( los.p[i], z_abs, p_abs, los.z[i] );
1123  }
1124 }
1125 
1126 
1127 
1135  // WS Goutput
1136  Vector& za,
1137  const String& /* za_name */,
1138  // WS input
1139  const Vector& z_tan,
1140  const Numeric& z_plat,
1141  const Vector& p_abs,
1142  const Vector& z_abs,
1143  const Index& refr,
1144  const Vector& refr_index,
1145  const Numeric& r_geoid,
1146  const Numeric& z_ground )
1147 {
1148  check_lengths( p_abs, "p_abs", z_abs, "z_abs" );
1149  if ( refr )
1150  check_lengths( p_abs, "p_abs", refr_index, "refr_index" );
1151 
1152  const Numeric atm_limit = last(z_abs);
1153  const Index nz = z_tan.nelem();
1154 
1155  za.resize(nz);
1156 
1157  for (Index i=0; i<nz; i++)
1158  {
1159  if (z_tan[i]>z_plat)
1160  throw runtime_error(
1161  "One tangent altitude is larger than the platform altitude");
1162 
1163  // No refraction
1164  if (!refr)
1165  za[i] = 90 + RAD2DEG*acos ( (r_geoid + z_tan[i]) / (r_geoid + z_plat) );
1166 
1167  // Refraction
1168  else
1169  {
1170  Numeric nz_plat = n_for_z(z_plat,p_abs,z_abs,refr_index,atm_limit);
1171  if (z_tan[i]>=0)
1172  {
1173  // Calculating constant
1174  Numeric nza = n_for_z(z_tan[i],p_abs,z_abs,refr_index,atm_limit);
1175  Numeric c = (r_geoid + z_tan[i]) * nza;
1176  za[i] = 180 - RAD2DEG * asin( c / nz_plat / (r_geoid + z_plat));
1177  }
1178  else
1179  {
1180  // inside the Earth, looking for hitting point
1181  Numeric ze = RAD2DEG * acos((r_geoid + z_tan[i]) / r_geoid);
1182  // from hitting point to platform
1183  Numeric nze = n_for_z(z_ground,p_abs,z_abs,refr_index,atm_limit);
1184  Numeric c = r_geoid * sin(DEG2RAD * (90-ze)) * nze;
1185  za[i] = 180 - RAD2DEG * asin( c / nz_plat / (r_geoid + z_plat));
1186  }
1187  }
1188  }
1189 }
1190 
1191 
1192 
1200  // WS Generic Output:
1201  Vector& za,
1202  // WS Generic Output Names:
1203  const String& /* za_name */,
1204  // WS Input:
1205  const Numeric& z_plat,
1206  const Vector& p_abs,
1207  const Vector& z_abs,
1208  const Numeric& l_step,
1209  const Index& refr,
1210  const Index& refr_lfac,
1211  const Vector& refr_index,
1212  const Numeric& r_geoid,
1213  const Numeric& z_ground,
1214  // Control Parameters:
1215  const Numeric& delta_t,
1216  const Vector& z_tan_lim )
1217 
1218 {
1219  // Checking stuff
1220  check_lengths( p_abs, "p_abs", z_abs, "z_abs" );
1221  if ( refr ) {
1222  check_lengths( p_abs, "p_abs", refr_index, "refr_index" );
1223  }
1224  if ( z_tan_lim[0] > z_tan_lim[1] )
1225  throw runtime_error(
1226  "The lower tangent latitude is larger than the higher (in z_tan_lim).");
1227 
1228  // No refraction
1229  if (!refr)
1230  {
1231  // Geometric calculations
1232  Vector phi(2);
1233  Vector za_lim(2);
1234  String zastr = "za_lim";
1235 
1236  zaFromZtan(za_lim, zastr, z_tan_lim, z_plat, p_abs, z_abs, refr,
1237  refr_index, r_geoid, z_ground);
1238 
1239  phi[0] = za_lim[0] - 90;
1240  phi[1] = za_lim[1] - 90;
1241 
1242  const Numeric ang_step = RAD2DEG * delta_t *
1243  sqrt (EARTH_GRAV_CONST / pow(r_geoid + z_plat,3));
1244 
1245  if (((phi[0]-phi[1])/ang_step) <=0)
1246  throw runtime_error("The time given is too large to have any cross-link in the given altitude range");
1247 
1248  const Index n=Index(floor((phi[0]-phi[1])/ang_step));
1249 
1250  za.resize(n);
1251  for ( Index j=0;j<n;j++ )
1252  za[j] = 90 + phi[0] - ((Numeric)j * ang_step);
1253  }
1254 
1255  // Refraction
1256  else
1257  {
1258  const Index ztanstep = 100; // 100 meters step
1259  const Index n=Index(floor((z_tan_lim[1]-z_tan_lim[0])/ztanstep));
1260 
1261  Vector z_tan_1(n);
1262  Vector z_tan_2(n);
1263  za.resize(n);
1264 
1265  // ztan altitudes for later doing the interpolation
1266  for ( Index j=0;j<n;j++ )
1267  z_tan_1[j]=z_tan_lim[0]+(Numeric)j*ztanstep;
1268 
1269  // corresponding zenith angles
1270  String za_str = "za";
1271  zaFromZtan(za, za_str, z_tan_1, z_plat, p_abs, z_abs, refr, refr_index,
1272  r_geoid, z_ground);
1273 
1274  // corresponding psi
1275  Los los;
1276  losCalc(los,z_tan_2,z_plat,za,l_step,p_abs,z_abs,refr,refr_lfac,
1277  refr_index,z_ground,r_geoid);
1278  // psi corresponding to the ztan defined for interpolation
1279  Vector psizb(n);
1280  for ( Index j=0;j<n;j++ )
1281  psizb[j]=los.psi[j][0];
1282  // lower and higer psi
1283  const Numeric psitop = psizb[n-1];
1284  const Numeric psibot = psizb[0];
1285 
1286  // vel * deltat
1287  const Numeric ang_step = RAD2DEG * delta_t *
1288  sqrt (EARTH_GRAV_CONST / pow(r_geoid + z_plat,3));
1289 
1290  // number of cross links in the ztan range specified for the given deltat
1291  if (((psibot-psitop)/ang_step)<=0)
1292  throw runtime_error("The time given is too large to have any cross-link in the given altitude range");
1293  const Index np=Index(floor((psibot-psitop)/ang_step));
1294  // corresponding psi (in that z_tan_lim[1]-z_tan_lim[0])
1295  Vector psit(np);
1296  for ( Index j=0;j<np;j++ )
1297  psit[j]=psibot-(Numeric)j*ang_step;
1298 
1299 
1300  // ztan for psi for deltat from psi and ztan for interpolation
1301  z_tan_1.resize(np);
1302  for ( Index j=0;j<np;j++ )
1303  {
1304  z_tan_1[j]=interp_lin(psizb,z_tan_2,psit[j]);
1305  }
1306 
1307  // corresponding zenith angles
1308  zaFromZtan(za, za_str, z_tan_1, z_plat, p_abs, z_abs, refr, refr_index,
1309  r_geoid, z_ground);
1310  }
1311 }
1312 
1313 
1314 
1322  ArrayOfMatrix& source,
1323  const Index& emission,
1324  const Los& los,
1325  const Vector& p_abs,
1326  const Vector& t_abs,
1327  const Vector& f_mono )
1328 {
1329  check_if_bool( emission, "emission" );
1330  check_lengths( p_abs, "p_abs", t_abs, "t_abs" );
1331 
1332  if ( emission == 0 )
1333  {
1334  out2 << " Setting the source array to be empty.\n";
1335  source.resize( 0 );
1336  }
1337 
1338  else
1339  {
1340  Vector tlos; // temperatures along the LOS
1341  const Index nza=los.start.nelem(); // the number of zenith angles
1342  const Index nf=f_mono.nelem(); // the number of frequencies
1343  Index nlos; // the number of pressure points
1344  Matrix b; // the Planck function for TLOS
1345  Index iv, ilos; // frequency and LOS point index
1346 
1347  out2 << " Calculating the source function for LTE and no scattering.\n";
1348 
1349  // Resize the source array
1350  source.resize(nza);
1351 
1352  // Loop the zenith angles and:
1353  // 1. interpolate the temperature
1354  // 2. calculate the Planck function for the interpolated temperatures
1355  // 3. take the mean of neighbouring Planck values
1356  out3 << " Zenith angle nr: ";
1357  for (Index i=0; i<nza; i++ )
1358  {
1359  if ( (i%20)==0 )
1360  out3 << "\n ";
1361  out3 << " " << i; cout.flush();
1362 
1363  if ( los.p[i].nelem() > 0 )
1364  {
1365  nlos = los.p[i].nelem();
1366  tlos.resize( nlos );
1367  interpp( tlos, p_abs, t_abs, los.p[i] );
1368  b.resize( nf, nlos );
1369  planck( b, f_mono, tlos );
1370  source[i].resize(nf,nlos-1);
1371  for ( ilos=0; ilos<(nlos-1); ilos++ )
1372  {
1373  for ( iv=0; iv<nf; iv++ )
1374  source[i](iv,ilos) = ( b(iv,ilos) + b(iv,ilos+1) ) / 2.0;
1375  }
1376  }
1377  }
1378  out3 << "\n";
1379  }
1380 }
1381 
1382 
1383 
1391  ArrayOfMatrix& trans,
1392  const Los& los,
1393  const Vector& p_abs,
1394  const Matrix& abs )
1395 {
1396  check_length_ncol( p_abs, "p_abs", abs, "abs" );
1397 
1398  // Some variables
1399  const Index n = los.start.nelem(); // the number of zenith angles
1400  const Index nf = abs.nrows(); // the number of frequencies
1401  Index np; // the number of pressure points
1402  Index row, col; // counters
1403  Matrix abs2 ; // matrix to store interpolated abs.
1404  Numeric w; // = -l_step/2
1405 
1406  out2 << " Calculating transmissions WITHOUT scattering.\n";
1407 
1408  // Resize the transmission array
1409  trans.resize(n);
1410 
1411  // Loop the zenith angles and:
1412  // 1. interpolate the absorption
1413  // 2. calculate the transmission using the mean absorption between points
1414  out3 << " Zenith angle nr: ";
1415  for (Index i=0; i<n; i++ )
1416  {
1417  if ( (i%20)==0 )
1418  out3 << "\n ";
1419  out3 << " " << i; cout.flush();
1420 
1421  np = los.p[i].nelem();
1422  if ( np > 0 )
1423  {
1424  abs2.resize( nf, np );
1425  interpp( abs2, p_abs, abs, los.p[i] );
1426  trans[i].resize( nf, np-1 );
1427  w = -0.5*los.l_step[i];
1428  for ( row=0; row<nf; row++ )
1429  {
1430  for ( col=0; col<(np-1); col++ )
1431  trans[i](row,col) = exp( w * ( abs2(row,col)+abs2(row,col+1) ) );
1432  }
1433  }
1434  }
1435  out3 << "\n";
1436 }
1437 
1438 
1439 
1447  Vector& y_space,
1448  const Vector& f,
1449  const String& choice )
1450 {
1451  y_space.resize( f.nelem() );
1452 
1453  if ( choice == "zero" )
1454  {
1455  y_space = 0.0; // Matpack can set all elements like this.
1456  out2 << " Setting y_space to zero.\n";
1457  }
1458  else if ( choice == "cbgr" )
1459  {
1460  planck( y_space, f, COSMIC_BG_TEMP );
1461  out2 << " Setting y_space to cosmic background radiation.\n";
1462  }
1463  else if ( choice == "sun" )
1464  {
1465  planck( y_space, f, SUN_TEMP );
1466  out2 << " Setting y_space to blackbody radiation corresponding to "
1467  << "the Sun temperature\n";
1468  }
1469  else
1470  throw runtime_error(
1471  "Possible choices for y_space are \"zero\", \"cbgr\" and \"sun\".");
1472 
1473 }
1474 
1475 
1476 
1483 void yCalc (
1484  Vector& y,
1485  const Index& emission,
1486  const Los& los,
1487  const Vector& f_mono,
1488  const Vector& y_space,
1489  const ArrayOfMatrix& source,
1490  const ArrayOfMatrix& trans,
1491  const Vector& e_ground,
1492  const Numeric& t_ground )
1493 {
1494  // Check input
1495  // (ground emission and temperature are checked in the sub-functions)
1496  //
1497  check_if_bool( emission, "emission" );
1498  if ( los.p.nelem() != trans.nelem() )
1499  throw runtime_error(
1500  "The number of zenith angles of *los* and *trans* are different.");
1501  if ( emission )
1502  {
1503  check_lengths( f_mono, "f_mono", y_space, "y_space" );
1504  if ( los.p.nelem() != source.nelem() )
1505  throw runtime_error(
1506  "The number of zenith angles of *los* and *source* are different.");
1507  }
1508 
1509  if ( emission == 0 )
1510  y_tau( y, los, trans, e_ground, 0, los.start.nelem () - 1 );
1511  else
1512  y_rte( y, los, f_mono, y_space, source, trans, e_ground, t_ground,
1513  0, los.start.nelem () - 1 );
1514 }
1515 
1523  Vector& y,
1524  const Index& emission,
1525  const Los& los,
1526  const Vector& p_abs,
1527  const Vector& t_abs,
1528  const Vector& f_mono,
1529  const Matrix& abs,
1530  const Vector& y_space,
1531  const Vector& e_ground,
1532  const Numeric& t_ground,
1533  const Index& f_chunksize)
1534 {
1535  // Some variables
1536  const Index n=los.start.nelem(); // Number of zenith angles
1537  const Index nf=f_mono.nelem(); // Number of frequencies
1538 
1539  assert (f_chunksize > 0);
1540 
1541  Index chunksize;
1542  if (f_chunksize > nf) chunksize=nf;
1543  else chunksize=f_chunksize;
1544 
1545  // make y the right size
1546  y.resize( nf*n );
1547 
1548  for (Index i = 0; i < nf / chunksize + 1; i++)
1549  {
1550  Index nf_local;
1551 
1552  if ((i+1) * chunksize <= nf)
1553  nf_local = chunksize;
1554  else
1555  nf_local = nf % (i * chunksize);
1556 
1557  if (! nf_local) break;
1558 
1559  Range r (i * chunksize, nf_local);
1560 
1561  ConstVectorView f_monolocal (f_mono [r]);
1562  ConstVectorView e_groundlocal (e_ground [r]);
1563  ConstVectorView y_spacelocal (y_space [r]);
1564  ConstMatrixView abslocal (abs (r, joker));
1565 
1566  // Calculate source:
1567  ArrayOfMatrix sourcelocal;
1568  sourceCalc(// Output:
1569  sourcelocal,
1570  // Input:
1571  emission,
1572  los,
1573  p_abs,
1574  t_abs,
1575  f_monolocal);
1576 
1577  // Calculate transmittances:
1578  ArrayOfMatrix translocal;
1579  transCalc(// Output:
1580  translocal,
1581  //Input:
1582  los,
1583  p_abs,
1584  abslocal);
1585 
1586  // Check input
1587  // (ground emission and temperature are checked in the sub-functions)
1588  //
1589  check_if_bool( emission, "emission" );
1590  if ( los.p.nelem() != translocal.nelem() )
1591  throw runtime_error( "The number of zenith angles of *los* and "
1592  "*translocal* are different.");
1593  if ( emission )
1594  {
1595  if ( los.p.nelem() != sourcelocal.nelem() )
1596  throw runtime_error( "The number of zenith angles of *los* "
1597  "and *sourcelocal* are different.");
1598  }
1599 
1600  for (Index j = 0; j < n; j++)
1601  {
1602  // Calculate Spectrum:
1603  Vector ylocal;
1604 
1605  if ( emission == 0 )
1606  y_tau( ylocal, los, translocal, e_groundlocal, j, j );
1607  else
1608  y_rte( ylocal, los, f_monolocal, y_spacelocal, sourcelocal,
1609  translocal, e_groundlocal, t_ground, j, j );
1610 
1611  // Move values to output vector
1612  y[Range(i * chunksize + j * nf, nf_local)] = ylocal;
1613  }
1614  }
1615 
1616 }
1617 
1624 void yTB (
1625  Vector& y,
1626  const Vector& f_mono,
1627  const Vector& za_pencil )
1628 {
1629  out2 << " Converts the values of *y* to Planck temperatures.\n";
1630  invplanck( y, f_mono, za_pencil );
1631 }
1632 
1633 
1634 
1641 void yTRJ (
1642  Vector& y,
1643  const Vector& f_mono,
1644  const Vector& za_pencil )
1645 {
1646  out2 << " Converts the values of *y* to Rayleigh-Jean temperatures.\n";
1647  invrayjean( y, f_mono, za_pencil );
1648 }
1649 
1650 
1651 
1658 void MatrixTRJ (// WS Generic Output:
1659  Matrix& kout,
1660  // WS Generic Output Names:
1661  const String& kout_name,
1662  // WS Input:
1663  const Vector& f_mono,
1664  const Vector& za_pencil,
1665  // WS Generic Input:
1666  const Matrix& kin,
1667  // WS Generic Input Names:
1668  const String& kin_name)
1669 {
1670  out2 << " Converts the values of *" << kin_name << "* to Rayleigh-Jean "
1671  << "temperatures,\n and stores the result in *" << kout_name
1672  << "*.\n";
1673 
1674  // Resize kout if necessary:
1675  if ( kout.nrows()!=kin.nrows() || kout.ncols()!=kin.ncols() )
1676  kout.resize(kin.nrows(),kin.ncols());
1677 
1678  for ( Index i=0; i<kin.ncols(); i++ )
1679  {
1680  kout(Range(joker),i) = kin(Range(joker),i); // Copy to ith column of kout.
1681  invrayjean( kout(Range(joker),i), f_mono, za_pencil );
1682  }
1683 }
1684 
1685 
1686 
1693 void MatrixTB (// WS Generic Output:
1694  Matrix& kout,
1695  // WS Generic Output Names:
1696  const String& kout_name,
1697  // WS Input:
1698  const Vector& f_mono,
1699  const Vector& za_pencil,
1700  // WS Generic Input:
1701  const Matrix& kin,
1702  // WS Generic Input Names:
1703  const String& kin_name)
1704 {
1705  out2 << " Converts the values of *" << kin_name << "* to Planck "
1706  << "temperatures,\n and stores the result in *" << kout_name
1707  << "*.\n";
1708 
1709  // Resize kout if necessary:
1710  if (kout.nrows()!=kin.nrows() ||
1711  kout.ncols()!=kin.ncols())
1712  kout.resize(kin.nrows(),kin.ncols());
1713 
1714  Vector y(kin.nrows());
1715  for ( Index i=0; i<kin.ncols(); i++ )
1716  {
1717  y = kin(Range(joker),i); // Copy ith column of kin to y.
1718  invplanck( y, f_mono, za_pencil );
1719  kout(Range(joker),i) = y; // Copy to ith column of kout.
1720  }
1721 }
1722 
1723 
1724 
1725 
1733  Matrix& coolrate,
1734  const Numeric& lstep0,
1735  const Vector& p_abs,
1736  const Vector& z_abs,
1737  const Vector& t_abs,
1738  const Vector& f_mono,
1739  const Matrix& absorption,
1740  const Vector& za_pencil,
1741  const Index& refr,
1742  const Index& refr_lfac,
1743  const Vector& refr_index,
1744  const Numeric& r_geoid,
1745  const Numeric& z_ground,
1746  const Vector& e_ground,
1747  const Numeric& t_ground,
1748  const Vector& p_coolrate,
1749  const Numeric& lstep_limit )
1750 {
1751  // Some sizes
1752  const Index nf = f_mono.nelem();
1753  const Index nza = za_pencil.nelem();
1754  const Index np = p_coolrate.nelem();
1755 
1756  // Input checks not done elsewhere
1757  if ( za_pencil[0] != 0 || za_pencil[nza-1] != 180 )
1758  throw runtime_error(
1759  "The given zenith angle grid must start with 0 and end with 180" );
1760 
1761  // Give *coolrate* the correct size and set to 0
1762  coolrate.resize( nf, np );
1763  coolrate = 0;
1764 
1765  // Altitudes, temperatures and absorption corresponding to *p_coolrate*
1766  Vector z_coolrate( np ), t_coolrate( np );
1767  Matrix abs_coolrate( nf, np );
1768  interpp( z_coolrate, p_abs, z_abs, p_coolrate );
1769  interpp( t_coolrate, p_abs, t_abs, p_coolrate );
1770  interpp( abs_coolrate, p_abs, absorption, p_coolrate );
1771 
1772  // Create matrix to store values to be integrated in (zenith angles)
1773  // Fill with zeros to have OK values for zenith angles 0 and 180
1774  Matrix intgrmatrix( nf, nza, 0 );
1775 
1776  // Activate emssion and create vector with cosmic background radiation
1777  const Index emission = 1;
1778  Vector y_space( nf );
1779  y_spaceStd( y_space, f_mono, "cbgr" );
1780 
1781  // Define local correspondance to some WSV
1782  Los los;
1783  Vector z_tan, y;
1784  ArrayOfMatrix source, trans;
1785 
1786 
1787  // Loop pressure levels and do calculations described in AUG
1788  for( Index ip=0; ip<np; ip++ )
1789  {
1790  // Determine blackbody radiation at present altitude
1791  //planck( bbody, f_mono, t_coolrate[ip] );
1792 
1793  // Loop zenith angles and calculate incoming radiation
1794  // Skip 0 and 180 degrees as result anyhow will be zero (due to sin term)
1795  for( Index iza=1; iza<nza-1; iza++ )
1796  {
1797  Numeric lstep = lstep0 / abs( cos( DEG2RAD*za_pencil[iza] ) );
1798  if( lstep > lstep_limit || abs( za_pencil[iza] - 90 ) < 0.01 )
1799  lstep = lstep_limit;
1800 
1801  losCalc( los, z_tan, z_coolrate[ip], Vector(1,za_pencil[iza]),
1802  lstep, p_abs, z_abs, refr, refr_lfac, refr_index,
1803  z_ground, r_geoid );
1804  sourceCalc( source, emission, los, p_abs, t_abs, f_mono );
1805  transCalc( trans, los, p_abs, absorption );
1806  yCalc ( y, emission, los, f_mono, y_space, source, trans,
1807  e_ground, t_ground );
1808 
1809  const Numeric sinv = sin( DEG2RAD*za_pencil[iza] );
1810 
1811  for( Index iv=0; iv<nf; iv++ )
1812  {
1813  Numeric bb_eff;
1814  if( los.stop[0] == 0)
1815  { bb_eff = source[0](iv,los.stop[0]); }
1816  else
1817  { bb_eff = source[0](iv,los.stop[0]-1); }
1818 
1819  intgrmatrix(iv,iza) = (bb_eff-y[iv])*abs_coolrate(iv,ip)*sinv;
1820  }
1821  }
1822 
1823  // Loop zenith angles and make integration
1824  //
1825  const Numeric cp = 1.00e3;
1826  const Numeric rho = 28.8 * p_coolrate[ip] /
1827  ( t_coolrate[ip] * BOLTZMAN_CONST * AVOGADROS_NUMB );
1828  const Numeric factor1 = 2 * PI / (cp*rho);
1829  //
1830  for( Index iza=1; iza<nza; iza++ )
1831  {
1832  const Numeric factor2 = DEG2RAD*(za_pencil[iza]-za_pencil[iza-1]);
1833 
1834  for( Index iv=0; iv<nf; iv++ )
1835  {
1836  coolrate(iv,ip) += factor1 * factor2 *
1837  ( intgrmatrix(iv,iza) + intgrmatrix(iv,iza-1) ) / 2;
1838  }
1839  }
1840  }
1841 }
y_tau
void y_tau(Vector &y, const Los &los, const ArrayOfMatrix &trans, ConstVectorView e_ground, const Index &z_start, const Index &z_end)
Definition: m_los.cc:748
Matrix
The Matrix class.
Definition: matpackI.h:544
Los::psi
ArrayOfVector psi
Definition: los.h:105
RAD2DEG
const Numeric RAD2DEG
out2
Out2 out2
Level 2 output stream.
Definition: messages.cc:54
y_spaceStd
void y_spaceStd(Vector &y_space, const Vector &f, const String &choice)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1446
groundFlatSea
void groundFlatSea(Numeric &z_ground, Numeric &t_ground, Vector &e_ground, const Vector &p_abs, const Vector &t_abs, const Vector &z_abs, const Vector &f_mono, const Vector &za_pencil, const Numeric &z_plat, const Numeric &r_geoid, const Index &refr, const Vector &refr_index, const String &pol, const Numeric &t_skin)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:929
groundAtBottom
void groundAtBottom(Numeric &z_ground, Numeric &t_ground, Vector &e_ground, const Vector &t_abs, const Vector &z_abs, const Vector &f_mono, const Numeric &e)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:905
Los::z
ArrayOfVector z
Definition: los.h:106
MatrixTB
void MatrixTB(Matrix &kout, const String &kout_name, const Vector &f_mono, const Vector &za_pencil, const Matrix &kin, const String &kin_name)
Convert a matrix containing radiances to Planck BTs.
Definition: m_los.cc:1693
losCalc
void losCalc(Los &los, Vector &z_tan, const Numeric &z_plat, const Vector &za, const Numeric &l_step, const Vector &p_abs, const Vector &z_abs, const Index &refr, const Index &refr_lfac, const Vector &refr_index, const Numeric &z_ground, const Numeric &r_geoid)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1058
auto_md.h
atm_funcs.h
This file contains declerations of functions releated to atmospheric physics or geometry.
check_length_ncol
void check_length_ncol(const Vector &x, const String &x_name, const Matrix &A, const String &A_name)
Checkss that the length of a vector and the number of columns of a matrix match.
Definition: math_funcs.cc:592
EARTH_RADIUS
const Numeric EARTH_RADIUS
Global constant, the radius of the Earth [m].
sourceCalc
void sourceCalc(ArrayOfMatrix &source, const Index &emission, const Los &los, const Vector &p_abs, const Vector &t_abs, const Vector &f_mono)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1321
COSMIC_BG_TEMP
const Numeric COSMIC_BG_TEMP
los.h
This file contains the definition of the LOS structure and functions related to this structure.
last
Numeric last(ConstVectorView x)
Gives the last value of a vector.
Definition: math_funcs.cc:83
emissionOn
void emissionOn(Index &emission)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1033
check_lengths
void check_lengths(const Vector &x1, const String &x1_name, const Vector &x2, const String &x2_name)
Checks that two vectors have the same length.
Definition: math_funcs.cc:527
transCalc
void transCalc(ArrayOfMatrix &trans, const Los &los, const Vector &p_abs, const Matrix &abs)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1390
Vector::resize
void resize(Index n)
Resize function.
Definition: matpackI.h:1467
invplanck
void invplanck(VectorView y, ConstVectorView f, ConstVectorView za)
Converts a vector with radiances to Plack brightness temperatures.
Definition: atm_funcs.cc:145
ConstMatrixView::nrows
Index nrows() const
Returns the number of rows.
Definition: matpackI.h:1491
los_1za
void los_1za(Vector &z, Vector &psi, Numeric &l_step, Index &ground, Index &start, Index &stop, Numeric &z_tan, const Numeric &z_plat, const Numeric &za, const Numeric &l_step_max, const Numeric &z_ground, const Numeric &r_geoid, const Vector &p_abs, const Vector &z_abs, const Index &refr, const Index &refr_lfac, const Vector &refr_index)
Performs the LOS calculations for one zenith angle.
Definition: m_los.cc:372
joker
Joker joker
Define the global joker objekt.
Definition: constants.cc:233
bl
void bl(Vector &y, const Index start_index, const Index stop_index, ConstMatrixView tr, const Index ground, ConstVectorView e_ground)
Performs the BL (transmission) calculations for one zenith angle.
Definition: atm_funcs.cc:560
SPEED_OF_LIGHT
const Numeric SPEED_OF_LIGHT
BOLTZMAN_CONST
const Numeric BOLTZMAN_CONST
PLANCK_CONST
const Numeric PLANCK_CONST
EARTH_GRAV_CONST
const Numeric EARTH_GRAV_CONST
matpackI.h
complex.h
A class implementing complex numbers for ARTS.
emissionOff
void emissionOff(Index &emission)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1045
Array< Index >
y_rte
void y_rte(Vector &y, const Los &los, ConstVectorView f_mono, ConstVectorView y_space, const ArrayOfMatrix &source, const ArrayOfMatrix &trans, ConstVectorView e_ground, const Numeric &t_ground, const Index &z_start, const Index &z_end)
Definition: m_los.cc:678
groundOff
void groundOff(Numeric &z_ground, Numeric &t_ground, Vector &e_ground, const Vector &z_abs)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:860
SUN_TEMP
const Numeric SUN_TEMP
check_if_bool
void check_if_bool(const Index &x, const String &x_name)
Checks if an integer is 0 or 1.
Definition: math_funcs.cc:468
any_ground
bool any_ground(const ArrayOfIndex &ground)
Checks if any of the pencil beam spectra corresponds to a ground reflection.
Definition: m_los.cc:86
messages.h
Declarations having to do with the four output streams.
planck
void planck(MatrixView B, ConstVectorView f, ConstVectorView t)
Calculates a blackbody radiation (the Planck function) matrix.
Definition: atm_funcs.cc:75
invrayjean
void invrayjean(VectorView y, ConstVectorView f, ConstVectorView za)
Converts a vector with radiances to Rayleigh-Jean brightness temperatures.
Definition: atm_funcs.cc:202
ConstMatrixView::ncols
Index ncols() const
Returns the number of columns.
Definition: matpackI.h:1497
my_basic_string
The implementation for String, the ARTS string class.
Definition: mystring.h:61
abs
#define abs(x)
Definition: continua.cc:12946
CoolingRates
void CoolingRates(Matrix &coolrate, const Numeric &lstep0, const Vector &p_abs, const Vector &z_abs, const Vector &t_abs, const Vector &f_mono, const Matrix &absorption, const Vector &za_pencil, const Index &refr, const Index &refr_lfac, const Vector &refr_index, const Numeric &r_geoid, const Numeric &z_ground, const Vector &e_ground, const Numeric &t_ground, const Vector &p_coolrate, const Numeric &lstep_limit)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1732
Numeric
NUMERIC Numeric
The type to use for all floating point numbers.
Definition: arts.h:147
zaFromZtan
void zaFromZtan(Vector &za, const String &, const Vector &z_tan, const Numeric &z_plat, const Vector &p_abs, const Vector &z_abs, const Index &refr, const Vector &refr_index, const Numeric &r_geoid, const Numeric &z_ground)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1134
ConstVectorView::nelem
Index nelem() const
Returns the number of elements.
Definition: matpackI.h:937
los_refraction
void los_refraction(Vector &z, Vector &psi, Numeric &l_step, const Numeric &z_plat, const Numeric &za, const Numeric &atm_limit, const Numeric &r_geoid, const Vector &, const Vector &z_abs, const Index &, const Index &refr_lfac, const Vector &refr_index, const Numeric &c)
Core function for LOS calculations with refraction.
Definition: m_los.cc:205
r_geoidStd
void r_geoidStd(Numeric &r_geoid)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:816
interp_lin
Numeric interp_lin(ConstVectorView x, ConstVectorView y, const Numeric xi)
Single linear interpolation of a vector (return version).
Definition: math_funcs.cc:435
Los::p
ArrayOfVector p
Definition: los.h:104
yCalc
void yCalc(Vector &y, const Index &emission, const Los &los, const Vector &f_mono, const Vector &y_space, const ArrayOfMatrix &source, const ArrayOfMatrix &trans, const Vector &e_ground, const Numeric &t_ground)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1483
PI
const Numeric PI
groundSet
void groundSet(Numeric &z_ground, Numeric &t_ground, Vector &e_ground, const Vector &p_abs, const Vector &t_abs, const Vector &z_abs, const Vector &f_mono, const Numeric &z, const Numeric &e)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:879
math_funcs.h
Contains declerations of basic mathematical and vector/matrix functions.
interpz
void interpz(VectorView x, ConstVectorView p0, ConstVectorView z0, ConstVectorView x0, ConstVectorView z)
Interpolates a vertical profile at a new set of vertical altitudes.
Definition: atm_funcs.cc:774
r_geoidWGS84
void r_geoidWGS84(Numeric &r_geoid, const Numeric &latitude, const Numeric &obsdirection)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:829
los_geometric
void los_geometric(Vector &z, Vector &psi, Numeric &l_step, const Numeric &z_plat, const Numeric &za, const Numeric &atm_limit, const Numeric &r_geoid)
Core function for geometric LOS calculations.
Definition: m_los.cc:126
Matrix::resize
void resize(Index r, Index c)
Resize function.
Definition: matpackI.h:2237
Los::stop
ArrayOfIndex stop
Definition: los.h:110
max
#define max(a, b)
Definition: continua.cc:12949
ConstMatrixView
A constant view of a Matrix.
Definition: matpackI.h:426
DEG2RAD
const Numeric DEG2RAD
Range
The range class.
Definition: matpackI.h:139
out3
Out3 out3
Level 3 output stream.
Definition: messages.cc:56
ztan_geom
Numeric ztan_geom(const Numeric za, const Numeric z_plat, const Numeric r_geoid)
Calculates the geometrical tangent altitude (no refraction).
Definition: atm_funcs.cc:839
yTB
void yTB(Vector &y, const Vector &f_mono, const Vector &za_pencil)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1624
AVOGADROS_NUMB
const Numeric AVOGADROS_NUMB
Los::start
ArrayOfIndex start
Definition: los.h:109
Index
INDEX Index
The type to use for all integer numbers and indices.
Definition: arts.h:153
sourcetransyCalcSaveMemory
void sourcetransyCalcSaveMemory(Vector &y, const Index &emission, const Los &los, const Vector &p_abs, const Vector &t_abs, const Vector &f_mono, const Matrix &abs, const Vector &y_space, const Vector &e_ground, const Numeric &t_ground, const Index &f_chunksize)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1522
MatrixTRJ
void MatrixTRJ(Matrix &kout, const String &kout_name, const Vector &f_mono, const Vector &za_pencil, const Matrix &kin, const String &kin_name)
Convert a matrix containing radiances to Rayleigh-Jeans BTs.
Definition: m_los.cc:1658
ztan_refr
Numeric ztan_refr(const Numeric c, const Numeric za, const Numeric z_plat, const Numeric z_ground, ConstVectorView p_abs, ConstVectorView z_abs, ConstVectorView refr_index, const Numeric r_geoid)
Calculates the tangent altitude with refraction.
Definition: atm_funcs.cc:940
min
#define min(a, b)
Definition: continua.cc:12948
Los::l_step
Vector l_step
Definition: los.h:107
interpp
void interpp(VectorView x, ConstVectorView p0, ConstVectorView x0, ConstVectorView p)
Interpolates a vertical profile at a new set of pressures.
Definition: atm_funcs.cc:658
yTRJ
void yTRJ(Vector &y, const Vector &f_mono, const Vector &za_pencil)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1641
zaFromDeltat
void zaFromDeltat(Vector &za, const String &, const Numeric &z_plat, const Vector &p_abs, const Vector &z_abs, const Numeric &l_step, const Index &refr, const Index &refr_lfac, const Vector &refr_index, const Numeric &r_geoid, const Numeric &z_ground, const Numeric &delta_t, const Vector &z_tan_lim)
See the the online help (arts -d FUNCTION_NAME)
Definition: m_los.cc:1199
linspace
void linspace(Vector &x, const Numeric start, const Numeric stop, const Numeric step)
Linearly spaced vector with specified spacing.
Definition: math_funcs.cc:139
n_for_z
Numeric n_for_z(const Numeric z, ConstVectorView p_abs, ConstVectorView z_abs, ConstVectorView refr_index, const Numeric atm_limit)
Returns the refractive index for a vertical altitude.
Definition: atm_funcs.cc:871
refr_constant
Numeric refr_constant(const Numeric r_geoid, const Numeric za, const Numeric z_plat, ConstVectorView p_abs, ConstVectorView z_abs, const Numeric atm_limit, ConstVectorView refr_index)
Determines the constant for a refractive LOS.
Definition: atm_funcs.cc:908
Vector
The Vector class.
Definition: matpackI.h:389
Los::ground
ArrayOfIndex ground
Definition: los.h:108
Los
The line of sight (LOS).
Definition: los.h:103
ConstVectorView
A constant view of a Vector.
Definition: matpackI.h:232
Array::nelem
Index nelem() const
Number of elements.
Definition: array.h:115
z2p
void z2p(VectorView p, ConstVectorView z0, ConstVectorView p0, ConstVectorView z)
Converts an altitude vector to pressures.
Definition: atm_funcs.cc:621
check_if_in_range
void check_if_in_range(const Numeric &x_low, const Numeric &x_high, const Numeric &x, const String &x_name)
Checks if a numeric variable is inside a specified range.
Definition: math_funcs.cc:495
auto_wsv.h
Declares the enum type that acts as a handle for workspace variables. Also declares the workspace its...
complex
Definition: continua.cc:12805
arts.h
The global header file for ARTS.
rte
void rte(VectorView y, const Index start_index, const Index stop_index, ConstMatrixView tr, ConstMatrixView s, ConstVectorView y_space, const Index ground, ConstVectorView e_ground, ConstVectorView y_ground)
Performs the RTE calculations for one zenith angle.
Definition: atm_funcs.cc:433