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) ;
153 l_step = llim*0.9999;
163 b = r_geoid + z_plat;
166 for (
Index i=0; i<nz; i++ )
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]) );
175 z[i] = z[i] - r_geoid;
216 const Index& refr_lfac,
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) ;
234 l_step = llim*0.9999;
236 np =
Index( ceil( 1.5 * ( llim/l_step + 1) ) );
241 const double l = l_step / (double)refr_lfac;
250 double c2=c; c2 = c2 * c2;
261 for ( iz=0; (iz<nz) && (z_abs[iz]<=z2); iz++ ) {}
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]);
268 while ( z2 <= atm_limit )
275 if ( i ==
Index(refr_lfac) )
281 assert( np < zv.nelem() );
294 for ( j=1; j<=2; j++ )
311 rz2 = sqrt( l*l + e );
313 rz2 = sqrt( pow( l + sqrt(f), 2 ) + e );
318 for ( ; (iz<nz) && (z_abs[iz]<=z2); iz++ ) {}
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]);
326 psi2 = psi1 + acos( (d+rz2*rz2-l*l) / (2*rz1*rz2) );
333 psi = pv[
Range(0,np)];
388 const Index& refr_lfac,
389 const Vector& refr_index )
398 c =
refr_constant( r_geoid, za, z_plat, p_abs, z_abs, atm_limit,
400 z_tan =
ztan_refr( c, za, z_plat, z_ground, p_abs, z_abs, refr_index,
404 z_tan =
ztan_geom( za, z_plat, r_geoid );
411 if ( z_plat >= atm_limit )
416 out3 <<
" (z_tan = " << z_tan/1e3 <<
" km)";
419 if ( z_tan >= atm_limit )
428 else if ( z_tan >= z_ground )
432 los_geometric( z, psi, l_step, z_tan, 90.0, atm_limit, r_geoid );
438 p_abs, z_abs, refr, refr_lfac, refr_index, c );
445 psi0 = theta + za - 180.0 +
last(psi);
460 za_g =
RAD2DEG * asin( (r_geoid+z_tan) / (r_geoid+z_ground) );
462 los_geometric( z, psi, l_step, z_ground, za_g, atm_limit, r_geoid );
464 psi0 = za + za_g - 180.0;
468 za_g =
RAD2DEG * asin( c / ( (r_geoid+z_ground) *
469 n_for_z( z_ground, p_abs, z_abs, refr_index, atm_limit ) ) );
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 );
479 psi0 = theta + za - 180.0 +
last(psi);
490 start = stop = nz - 1;
498 los_geometric( z, psi, l_step, z_plat, za, atm_limit, r_geoid );
501 p_abs, z_abs, refr, refr_lfac, refr_index, c );
504 start = z.
nelem() - 1;
515 out3 <<
" (z_tan = " << z_tan/1e3 <<
" km)";
518 if ( z_tan >= z_ground )
523 a = r_geoid + z_plat;
528 if ( l1 > l_step_max/10 )
531 stop =
Index( ceil( l1 / l_step_max + 1.0 ) - 1 );
542 los_geometric( z, psi, l_step, z_tan, 90.0, atm_limit, r_geoid );
550 p_abs, z_abs, refr, 1, refr_index, c );
561 if ( l1 > l_step_max/10 )
564 stop =
Index( ceil( l1 / l_step_max + 1.0 ) - 1 );
576 p_abs, z_abs, refr, refr_lfac, refr_index, c );
580 start = z.
nelem() - 1;
595 a = r_geoid + z_plat;
599 a = r_geoid + z_ground;
600 l1 = l1 - sqrt(a*a-b);
603 if ( l1 > l_step_max/10 )
606 stop =
Index( ceil( l1 / l_step_max + 1.0 ) - 1 );
617 za_g =
RAD2DEG * asin( (r_geoid+z_tan) / (r_geoid+z_ground) );
619 los_geometric( z, psi, l_step, z_ground, za_g, atm_limit, r_geoid );
624 za_g =
RAD2DEG * asin( c / ( (r_geoid+z_ground) *
625 n_for_z( z_ground, p_abs, z_abs, refr_index, atm_limit ) ) );
629 p_abs, z_abs, refr, 1, refr_index, c );
640 if ( l1 > l_step_max/10 )
643 stop =
Index( ceil( l1 / l_step_max + 1.0 ) - 1 );
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 );
659 start = z.
nelem() - 1;
687 const Index& z_start,
696 out2 <<
" Integrating the radiative transfer eq. with emission.\n";
698 assert (z_start >= 0);
702 y.
resize( nf* (z_end - z_start + 1) );
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 )
715 "There are intersections with the ground, but the frequency and\n"
716 "ground emission vectors have different lengths (are dummy values\n"
718 out2 <<
" There are intersections with the ground.\n";
719 planck( y_ground, f_mono, t_ground );
723 out3 <<
" Zenith angle nr: ";
724 for (
Index i = z_start; i <= z_end; i++ )
728 out3 <<
" " << i; cout.flush();
732 source[i], y_space, los.
ground[i], e_ground, y_ground);
735 y[
Range(iy0,nf)] = y_tmp;
753 const Index& z_start,
758 const Index nf=trans[0].nrows();
762 assert (z_start >= 0);
765 out2 <<
" Calculating optical thicknesses.\n";
774 if ( e_ground.
nelem() != nf )
776 "There are intersections with the ground, but the frequency and\n"
777 "ground emission vectors have different lengths (are dummy values\n"
779 out2 <<
" There are intersections with the ground.\n";
783 out3 <<
" Zenith angle nr: ";
784 for (
Index i = z_start; i <= z_end; i++ )
788 out3 <<
" " << i; cout.flush();
794 for ( iy=0; iy<nf; iy++ )
795 y[iy0+iy] = -log( y_tmp[iy] );
837 const Numeric rq = 6378.138e3, rp = 6356.752e3;
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);
849 r_geoid = 1/(a*a/rns+b*b/rew);
892 t_ground =
interpz( p_abs, z_abs, t_abs, z );
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 )
949 "Frequencies below 10 GHz or above 1000 GHz are not allowed." );
954 { t_ground = t_skin; }
956 { t_ground =
interpz( p_abs, z_abs, t_abs, 0 ); }
959 Numeric n_plat = 1, n_ground = 1;
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) );
966 / ( n_ground * (r_geoid+z_ground) );
972 const Numeric costheta = sqrt( 1 - sintheta*sintheta );
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;
997 const Complex ifGHz( 0.0, f_mono[i]/1e9 );
1000 (e0-e1) / (
Numeric(1.0)-ifGHz/f1);
1001 const Complex n2 = sqrt( eps );
1007 b = n1 * cos( asin( n1 * sintheta / n2.real() ) );
1009 else if( pol ==
"h" )
1012 b = n2 * cos( asin( n1 * sintheta / n2.real() ) );
1015 throw runtime_error(
1016 "The keyword argument *pol* must be \"v\" or \"h\"." );
1021 e_ground[i] = 1 - r;
1066 const Index& refr_lfac,
1067 const Vector& refr_index,
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?");
1094 los.
psi.resize( n );
1098 los.
start.resize( n );
1099 los.
stop.resize( n );
1104 out2 <<
" Calculating line of sights WITHOUT refraction.\n";
1105 else if ( refr == 1 )
1106 out2 <<
" Calculating line of sights WITH refraction.\n";
1108 out3 <<
" z_plat: " << z_plat/1e3 <<
" km\n";
1111 for (
Index i=0; i<n; i++ )
1113 out3 <<
" za: " << za[i] <<
" degs.";
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 );
1121 los.
p[i].resize( los.
z[i].
nelem() );
1122 z2p( los.
p[i], z_abs, p_abs, los.
z[i] );
1144 const Vector& refr_index,
1157 for (
Index i=0; i<nz; i++)
1159 if (z_tan[i]>z_plat)
1160 throw runtime_error(
1161 "One tangent altitude is larger than the platform altitude");
1165 za[i] = 90 +
RAD2DEG*acos ( (r_geoid + z_tan[i]) / (r_geoid + z_plat) );
1170 Numeric nz_plat =
n_for_z(z_plat,p_abs,z_abs,refr_index,atm_limit);
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));
1183 Numeric nze =
n_for_z(z_ground,p_abs,z_abs,refr_index,atm_limit);
1185 za[i] = 180 -
RAD2DEG * asin( c / nz_plat / (r_geoid + z_plat));
1210 const Index& refr_lfac,
1211 const Vector& refr_index,
1216 const Vector& z_tan_lim )
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).");
1236 zaFromZtan(za_lim, zastr, z_tan_lim, z_plat, p_abs, z_abs, refr,
1237 refr_index, r_geoid, z_ground);
1239 phi[0] = za_lim[0] - 90;
1240 phi[1] = za_lim[1] - 90;
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");
1248 const Index n=
Index(floor((phi[0]-phi[1])/ang_step));
1251 for (
Index j=0;j<n;j++ )
1252 za[j] = 90 + phi[0] - ((
Numeric)j * ang_step);
1258 const Index ztanstep = 100;
1259 const Index n=
Index(floor((z_tan_lim[1]-z_tan_lim[0])/ztanstep));
1266 for (
Index j=0;j<n;j++ )
1267 z_tan_1[j]=z_tan_lim[0]+(
Numeric)j*ztanstep;
1271 zaFromZtan(za, za_str, z_tan_1, z_plat, p_abs, z_abs, refr, refr_index,
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);
1280 for (
Index j=0;j<n;j++ )
1281 psizb[j]=los.
psi[j][0];
1283 const Numeric psitop = psizb[n-1];
1284 const Numeric psibot = psizb[0];
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));
1296 for (
Index j=0;j<np;j++ )
1297 psit[j]=psibot-(
Numeric)j*ang_step;
1302 for (
Index j=0;j<np;j++ )
1304 z_tan_1[j]=
interp_lin(psizb,z_tan_2,psit[j]);
1308 zaFromZtan(za, za_str, z_tan_1, z_plat, p_abs, z_abs, refr, refr_index,
1323 const Index& emission,
1332 if ( emission == 0 )
1334 out2 <<
" Setting the source array to be empty.\n";
1347 out2 <<
" Calculating the source function for LTE and no scattering.\n";
1356 out3 <<
" Zenith angle nr: ";
1357 for (
Index i=0; i<nza; i++ )
1361 out3 <<
" " << i; cout.flush();
1363 if ( los.
p[i].
nelem() > 0 )
1367 interpp( tlos, p_abs, t_abs, los.
p[i] );
1369 planck( b, f_mono, tlos );
1370 source[i].resize(nf,nlos-1);
1371 for ( ilos=0; ilos<(nlos-1); ilos++ )
1373 for ( iv=0; iv<nf; iv++ )
1374 source[i](iv,ilos) = ( b(iv,ilos) + b(iv,ilos+1) ) / 2.0;
1406 out2 <<
" Calculating transmissions WITHOUT scattering.\n";
1414 out3 <<
" Zenith angle nr: ";
1415 for (
Index i=0; i<n; i++ )
1419 out3 <<
" " << i; cout.flush();
1426 trans[i].resize( nf, np-1 );
1428 for ( row=0; row<nf; row++ )
1430 for ( col=0; col<(np-1); col++ )
1431 trans[i](row,col) = exp( w * ( abs2(row,col)+abs2(row,col+1) ) );
1453 if ( choice ==
"zero" )
1456 out2 <<
" Setting y_space to zero.\n";
1458 else if ( choice ==
"cbgr" )
1461 out2 <<
" Setting y_space to cosmic background radiation.\n";
1463 else if ( choice ==
"sun" )
1466 out2 <<
" Setting y_space to blackbody radiation corresponding to "
1467 <<
"the Sun temperature\n";
1470 throw runtime_error(
1471 "Possible choices for y_space are \"zero\", \"cbgr\" and \"sun\".");
1485 const Index& emission,
1499 throw runtime_error(
1500 "The number of zenith angles of *los* and *trans* are different.");
1505 throw runtime_error(
1506 "The number of zenith angles of *los* and *source* are different.");
1509 if ( emission == 0 )
1512 y_rte( y, los, f_mono, y_space, source, trans, e_ground, t_ground,
1524 const Index& emission,
1533 const Index& f_chunksize)
1539 assert (f_chunksize > 0);
1542 if (f_chunksize > nf) chunksize=nf;
1543 else chunksize=f_chunksize;
1548 for (
Index i = 0; i < nf / chunksize + 1; i++)
1552 if ((i+1) * chunksize <= nf)
1553 nf_local = chunksize;
1555 nf_local = nf % (i * chunksize);
1557 if (! nf_local)
break;
1559 Range r (i * chunksize, nf_local);
1591 throw runtime_error(
"The number of zenith angles of *los* and "
1592 "*translocal* are different.");
1596 throw runtime_error(
"The number of zenith angles of *los* "
1597 "and *sourcelocal* are different.");
1600 for (
Index j = 0; j < n; j++)
1605 if ( emission == 0 )
1606 y_tau( ylocal, los, translocal, e_groundlocal, j, j );
1608 y_rte( ylocal, los, f_monolocal, y_spacelocal, sourcelocal,
1609 translocal, e_groundlocal, t_ground, j, j );
1612 y[
Range(i * chunksize + j * nf, nf_local)] = ylocal;
1627 const Vector& za_pencil )
1629 out2 <<
" Converts the values of *y* to Planck temperatures.\n";
1644 const Vector& za_pencil )
1646 out2 <<
" Converts the values of *y* to Rayleigh-Jean temperatures.\n";
1670 out2 <<
" Converts the values of *" << kin_name <<
"* to Rayleigh-Jean "
1671 <<
"temperatures,\n and stores the result in *" << kout_name
1705 out2 <<
" Converts the values of *" << kin_name <<
"* to Planck "
1706 <<
"temperatures,\n and stores the result in *" << kout_name
1739 const Matrix& absorption,
1742 const Index& refr_lfac,
1743 const Vector& refr_index,
1748 const Vector& p_coolrate,
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" );
1762 coolrate.
resize( nf, np );
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 );
1774 Matrix intgrmatrix( nf, nza, 0 );
1777 const Index emission = 1;
1788 for(
Index ip=0; ip<np; ip++ )
1795 for(
Index iza=1; iza<nza-1; iza++ )
1798 if( lstep > lstep_limit ||
abs( za_pencil[iza] - 90 ) < 0.01 )
1799 lstep = lstep_limit;
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 );
1811 for(
Index iv=0; iv<nf; iv++ )
1814 if( los.
stop[0] == 0)
1815 { bb_eff = source[0](iv,los.
stop[0]); }
1817 { bb_eff = source[0](iv,los.
stop[0]-1); }
1819 intgrmatrix(iv,iza) = (bb_eff-y[iv])*abs_coolrate(iv,ip)*sinv;
1826 const Numeric rho = 28.8 * p_coolrate[ip] /
1828 const Numeric factor1 = 2 *
PI / (cp*rho);
1830 for(
Index iza=1; iza<nza; iza++ )
1832 const Numeric factor2 =
DEG2RAD*(za_pencil[iza]-za_pencil[iza-1]);
1834 for(
Index iv=0; iv<nf; iv++ )
1836 coolrate(iv,ip) += factor1 * factor2 *
1837 ( intgrmatrix(iv,iza) + intgrmatrix(iv,iza-1) ) / 2;