/*******************************************************************************
 *
 *  airmass -- A program to compute the airmass for a given zenith angle.
 *
 *  Copyright (C) 2000 Reed D. Meyer (rxm128@yahoo.com).
 *  You are permitted to copy and distribute this program as much as you want,
 *  as long as you leave the source code, including this comments section,
 *  intact and unmodified.
 *
 *  To compile, type:  gcc airmass.c -o airmass -s -O3 -lm
 *     (This command should work in any environment where the GNU C compiler,
 *     gcc, is installed, including Linux and most UNIX environments)
 *
 *  To run, type:
 *
 *    airmass [-a <alt>] [-d <day>] [-H <h>] [-l <lat>] [-L <wavelength>]
 *            [-p <P>] [-t <T>] [-v] <zenith>
 *
 *  where:
 *     <zenith> is the APPARENT zenith angle (not the true angle in the
 *         absence of atmosphere) at which you want the airmass;
 *     -a <alt> sets the altitude of the observer to <alt> meters above mean
 *         sea level (the default is 0 meters);
 *     -d <day> specifies the date, in days since the beginning of the year
 *         (0 = midnight Jan. 1; the default is 80, corresponding roughly to
 *         the vernal equinox); don't worry about fractions of a day, since the
 *         seasonal effect on airmass is relatively small, as discussed below;
 *     -H <h>, if specified, tells the program to additionally compute an
 *         estimate of the water vapor column density and airmass, using a
 *         CRUDE model for the water vapor profile based on the local relative
 *         humidity at ground level, <h>.  <h> is in percent (100 = saturated).
 *         The local humidity is NOT used in the computation of the standard
 *         (dry atmosphere) airmass.  See EXTINCTION below for details.
 *     -l <lat> sets the observer's latitude to <lat> degrees (negative = south;
 *         default is 45 degrees);
 *     -L <wavelength> changes the observing wavelength in Angstroms (default
 *         5500 A; don't worry too much about an exact figure here, as the
 *         wavelength dependence is very small, as discussed below);
 *     -p <P> specifies the local pressure in millibars, presumably read off
 *         a barometer at the time of observation (default is 1013.25 mb,
 *         the so-called standard atmosphere);
 *     -T <T> specifies the local temperature in Celsius, again at the time
 *         of observation (default is 15 C, again the standard atmosphere);
 *     -v is a flag that increase the "verbosity" of the output.  In this
 *         context, the program computes the relative improvement it makes
 *         over some standard airmass formulas astronomers use (e.g. polynomial
 *         expansion in (sec(z) - 1) terms) -- see VERBOSITY OPTION below
 *         for details.
 *
 *
 *  VERSION HISTORY
 *  ===============
 *
 *  1.0 (2000 Aug. 13): first public release.
 *
 *
 *  BACKGROUND
 *  ==========
 *
 *  This program, and the necessary underlying algorithm, was developed to
 *  find out to just what degree the standard approximate formulas for airmass
 *  are inaccurate.  Many astronomers use the following polynomial in
 *  (sec(z) - 1) to calculate the airmass for a given zenith angle z:
 *
 *                                                     2                      3
 *  X = secz - 0.0018167(secz - 1) - 0.002875(secz - 1)  - 0.0008083(secz - 1)
 *
 *  (that is, those astronomers who do not use the simpler approximation
 *  X = sec(z), or the formula used in IRAF which is from Allen's _Astrophysical
 *  Quantities_.)  The fact is, though, that some astronomers take this formula
 *  practically as "truth" and do not stop to think about its origin.
 *  This formula is a fit to a table of theoretical airmass as a function of z,
 *  computed at the turn of the century, when the structure of the atmosphere
 *  was less well-understood and equations were simplified to ease numerical
 *  integration since there wasn't the benefit of computers.  To the best of
 *  my knowledge, the polynomial approximation above was first presented by
 *  R.H. Hardie in _Astronomical Techniques_ (W.A. Hiltner, ed.) (Chicago:
 *  U. Chicago Press), p. 180 (1962).  This was a fit to computations by
 *  A. Bemporad (Mitt. d. Grossh. Sternwarte Heidelberg 4 (1904)), published
 *  again by E. Schoenberg in _Handbuch der Astrophysik_ (Berlin: J. Springer),
 *  2, 268-273 (1929).*
 *       So there are two potential sources of inaccuracy in using this method:
 *  First, and perhaps the greatest source, is simply that the formula is
 *  a fitted function to a table of discrete values (and, moreover, was not
 *  designed to fit well the entire range of zenith angles).  The second is
 *  that the underlying table of theoretical values itself is based on an
 *  old model atmosphere, and used simplifying assumptions which further
 *  degrade the accuracy of the model.
 *       What if, instead, we were to use the power of modern computers to
 *  obviate the need for most simplifying assumptions and, in addition,
 *  calculate the airmass directly for any given z rather than make use of
 *  interpolating or best-fit functions?  This is what this program was
 *  designed to do.  In carrying out such a "modernization" of the airmass
 *  function, we might as well incorporate more modern theories of the
 *  structure of the atmosphere, too.
 *
 *  *Interestingly, the literature seems confused by Bemporad's work: some
 *   think the (sec(z) - 1) fit was to real DATA but in fact Bemporad just
 *   tabulated the results of his theoretical airmass formula.  It is pleasing
 *   to note that even the old German references can be found in the Yale
 *   Astronomy Library.
 *
 *
 *  DERIVATION
 *  ==========
 *
 *       We assume a spherically symmetric atmosphere of constant chemical
 *  composition.  The equation for the column density, which can be derived
 *  strictly from Snell's Law with the above assumption, is (c.f.
 *  Schoenberg (1929)):
 *
 *                 /\ r_m
 *                 |                rho dr
 *                 |     -----------------------------
 *        N(z) =   |                 2     2      2                       (1)
 *                 |                r_o  mu_o  sin  z
 *                 |     sqrt(1 -   -----------------)
 *                 |                    2   2
 *                \/ r_o               r  mu
 *
 *  where the subscript o refers to values at the observer, and r is the
 *  distance from the center of the earth, mu is the air's index of refraction
 *  at r, rho is the air's density at r, r_m is the upper limit on the
 *  integration (taken as the top of the mesosphere; see below) and z
 *  is the apparent zenith angle for which we're calculating the airmass.
 *  Note that this is just the expression for the column density of air
 *  directly overhead, with a correction factor (sqrt(...) in the denominator)
 *  to account for the light's actual path through the atmosphere when the
 *  source is not actually at the zenith.
 *       To get the airmass as it's traditionally defined (i.e., normalized to
 *  1 at the zenith), simply divide by the column density at z = 0:
 *
 *                   N(z)
 *           X(z) = ------  .                                             (2)
 *                   N(0)
 *
 *  The Clausius-Mossotti equation (see, for example, B. Garfinkel, AJ 72, 235
 *  (1967)) gives the index of refraction in terms of the density to an
 *  extremely good approximation; rewriting the equation gives
 *
 *             2     3 + 4 c rho
 *           mu  =  -------------                                         (3)
 *                   3 - 2 c rho
 *
 *  where c is a wavelength-varying constant depending only on the chemical
 *  composition of the gas.  A formula for air's index of refraction at a
 *  given wavelength appearing in the CRC Handbook of Chemistry and Physics
 *  can be rewritten to yield c:
 *
 *                      13.412      0.3777      -7     273.15 K
 *      c ~ [2875.66 + -------- + ----------] 10   R [-----------]        (4)
 *                      2   -8      4   -16            101325 Pa
 *                     L  10       L  10
 *
 *  where L is the wavelength in Angstroms and R is the ideal gas constant.
 *  (c has units of volume/mass so R needs to be expressed in energy/mass/K).
 *
 *  The main problem is finding an expression for rho(r).  We do this by
 *  assuming a temperature profile and then combining the ideal gas law
 *  (which expresses density in terms of pressure and temperature) with the
 *  condition of hydrostatic equilibrium (which gives density in terms of
 *  pressure).  This yields a unique density profile, given an assumed
 *  temperature profile.  The problem is the temperature profile.  This can
 *  only be determined uniquely by solving the equations of fluid dynamics
 *  for the atmosphere coupled with knowledge of the radiative processes in
 *  the atmosphere with appropriate boundary conditions, i.e., the incredibly
 *  complex problem which still makes accurate weather forecasting impossible.
 *  So we assume a temperature profile which is based on average measured
 *  values of temperatures at different heights in the atmosphere.  As I will
 *  argue below under ASSUMPTIONS, I feel that the approximate temperature
 *  profile probably does not deviate strongly from the real profile at the
 *  observer under most conditions, and since this is the primary assumption
 *  made in calculating the airmass for dry air, said airmass probably doesn't
 *  differ strongly from the real value.
 *       For our temperature profile, we start by assuming the atmosphere is
 *  broken down into several layers within which the temperature changes
 *  linearly with altitude.  In any given layer n, the temperature is
 *  T(Q) = T_n + beta_n (Q - Q_n), where beta_n is the slope of the temperature
 *  rise with altitude within the layer n, T_n is the temperature at the bottom
 *  of that layer, Q is the height (defined below), and Q_n is the height of
 *  the bottom of the layer.  This is the methodology used in the _U.S. Standard
 *  Atmosphere, 1962_ (Washington, DC: U.S. Govt. Printing Office), wherein a
 *  "standard atmosphere" appropriate for the continental United States is
 *  defined (a "standard atmosphere" being useful for aircraft and so forth).
 *  We take their bottom eight temperature layers (corresponding roughly to
 *  the troposphere, stratosphere, and mesosphere; top of eighth layer is at
 *  90 km above mean sea level).  But in order to generalize their work to make
 *  it more appropriate for any latitude and any season, we change the values
 *  defining the lowest two layers (the troposphere and lower stratosphere).
 *  We let the boundary between those two layers (the tropopause; Q_1) vary as
 *  a function of time of year and latitude.  The same thing goes for beta_0,
 *  the temperature falloff in the first layer.  The bottom of the first layer
 *  (Q_0) is set to the height Q of the observer's location.  The boundary
 *  condition "temperature at bottom of first layer" (T_0) is set to the
 *  actual local temperature at the observer.  The condition T_1 equals the
 *  temperature at the top of the first layer, i.e., as determined from the
 *  above expression for T with n = 0 and Q = Q_1.  Finally, beta_1 is set
 *  by forcing the temperature at the top of the second layer to match T_2
 *  (fixed at 216.65 K, the value in the U.S. Standard Atmosphere).  Although
 *  the temperatures in the third layer and higher (altitudes > 20 km) *do*
 *  vary with season and latitude, the variations are less severe than in the
 *  troposphere and lower stratosphere, and fortunately for us the atmosphere
 *  has already greatly thinned out by that point so these layers contribute
 *  little to the airmass calculation anyway.
 *       To determine Q_1 and beta_0 (the two quantities allowed to vary with
 *  time and latitude, and which define the lower two layers along with T_0),
 *  I extracted a table of values from two plots appearing on pages 48-49 of
 *  _General Meteorology_, 3rd ed.,  by H.R. Byers (New York: McGraw-Hill)
 *  (1959).  Byers provides a plot of the temperature distribution within the
 *  troposphere as a function of latitude for summer, and another for winter.
 *  Keep in mind that these are average values.  (In particular, the location
 *  of the tropopause at any given time is far more complex than the smooth
 *  line drawn in Byers' plots, due to the movement of the jet streams.)  I
 *  then fit a polynomial to the data to get a smooth function for beta_0 for
 *  any given latitude.  I fit another polynomial to the data to get a function
 *  for "r1", the altitude of the troposphere (which is related to Q_1).  The
 *  polynomials fit quite well and in any case are far more than adequate given
 *  the fact that Byers' plots are time averages.  beta_0 needed only a
 *  4th-order polynomial to fit the data but r1 required a 10th-order
 *  polynomial.  You can find the values of the best-fit coefficients by
 *  looking at the declarations of betapoly[] and r1poly[] in the source code.
 *  (The units are K/m and km, respectively.)  Then, to simulate the effect of
 *  seasonal changes, the odd coefficients in the polynomials sinusoidally vary
 *  with day of the year (period = 1 year; no change at day number 202,
 *  corresponding to the peak of summer).
 *       Now that we have values for the beta_n's, T_n's, and Q_n's (either
 *  from the _U.S. Standard Atmosphere_ or the method above for the bottom two
 *  layers), the simplicity of the temperature model leads to easily solvable
 *  equations which result in a closed-form expression for the density:
 *
 *            /
 *           |            T_n            (1 + g_E /(R beta_n))
 *           | [------------------------]
 *   rho     |   T_n + beta_n (Q - Q_n)                      , beta_n <> 0
 *  -----  =_/                                                              (5)
 *  rho_n    \
 *           |        g_E
 *           | exp[ ------- (Q_n - Q) ]
 *           |       R T_n                                   , beta_n = 0
 *            \
 *
 *  where as before, subscripts n refer to the bottom of some temperature layer
 *  n (0 <= n < 8); g_E is the standard value of the acceleration of gravity
 *  at the earth's surface (9.80665 m/s^2); and all other symbols are as
 *  defined above.
 *       In order to use (5) in Equation (1), we need to write r in terms of Q.
 *  (The only other quantity in the integrand of (1) which varies with r is mu,
 *  and we already have an expression for that in terms of rho.)  So, let us
 *  discuss the definition of Q.  The _U.S. Standard Atmosphere_ defines the
 *  geopotential altitude (here referred to as "h") as the integral from 0 to r
 *  of (g/g_E) dr (compare to their equation I.2.5-(1)), where g is the gravity
 *  at some r.  They then define their eight lowest temperature layers in terms
 *  of the geopotential altitude h.  The advantage of changing variables to h
 *  is that it lets us forget the fact that the g field is varying, thus
 *  simplifying the calculations.  To write the equations more simply, I
 *  further define the quantity Q by Q = h - (r_E^2 / r_msl), where r_E is the
 *  "standard" radius of the earth (i.e., the radius you would get from the
 *  formula g_E = G M_E / r_E^2, where M_E is the mass of the Earth, G is the
 *  gravitational constant, and g_E is the "standard" value of gravity as
 *  before); and r_msl is the actual radius of the earth at the latitude of
 *  the observer (i.e., the distance between the earth's center and a point
 *  at mean sea level at the latitude of the observer; "msl" means "mean sea
 *  level").  r_msl varies because the earth is an oblate spheroid; the reason
 *  for distinguishing r_E and r_msl is that Earth's gravity at the equator is
 *  slightly less than at the poles, because the earth's radius is larger at
 *  the equator.  Note that Q is always negative.
 *       We ignore the fact that the gravity vector is not exactly equal to
 *  the gravity vector of a spherical, nonrotating Earth (see ASSUMPTIONS
 *  below).  Combining our definitions for h and Q lets us write r in terms
 *  of Q:
 *
 *                      2
 *                   r_E
 *            r = - -----                                                 (6)
 *                    Q
 *
 *  Similarly we can find a Q for any desired r; for example, Q_o (the lower
 *  limit on the integrand in Equation (8), and the Q of the observer) is
 *  related to the observer's altitude "a" above mean sea level by
 *  Q_o = -r_E^2 / (r_msl + a).
 *       We calculate r_msl from the analytic geometry of the oblate spheroid,
 *  and the standard definition of the geographic latitude.  (Latitudes of
 *  actual places on the earth are always geographic latitudes.)  The result is
 *
 *              4     4    4     2
 *      2      b  + (a  - b ) cos  phi
 *     r    = -------------------------                                   (7)
 *      msl     2     2    2     2
 *             b  + (a  - b ) cos  phi
 *
 *  where a is the major axis of the spheroid (the Earth's equatorial radius),
 *  b is the spheroid's minor axis (the Earth's polar radius), and phi is the
 *  observer's latitude.  (Incidentally, the geocentric latitude phi_c can be
 *  found from:  tan phi_c = (b^2 / a^2) tan phi.)
 *       Plugging (6) into (1) gives
 *
 *                 /\ Q_m                  2
 *                 |                rho r_E  dQ
 *                 |     -------------------------------
 *        N(z) =   |                    2   2      2                      (8)
 *                 |      2            Q  mu_o  sin  z
 *                 |     R  sqrt(1 -  -----------------)
 *                 |                       2     2
 *                \/ Q_o                  Q_o  mu
 *
 *  (Q_m being the Q at the top of the highest temperature layer; for this
 *  layer, h = 88.743 km.  We take this as a suitable upper limit on the
 *  integration because the mass above this height is negligible; the air
 *  density at this altitude is 5 orders of magnitude less than at sea level.
 *  A practical reason for choosing this height for our upper limit is that
 *  at about this height (the top of the mesosphere), the molecular weight of
 *  the air begins to change appreciably.  While we can safely assume that all
 *  the air below this altitude has a fixed proportion of all the components
 *  important for extinction at visible and near-infrared wavelengths (besides
 *  water vapor, ozone, and aerosols), this assumption is not a good one
 *  above this rough altitude.
 *       Plugging Equations (3), (4), and (5) into (8) and integrating gives
 *  N(z); then we set z = 0 to use the same formulas and integration routines
 *  to get N(0); Equation (2) then gives us the desired airmass at z.
 *
 *
 *  EXTINCTION
 *  ==========
 *
 *  Of course, the whole point of calculating airmass, for astronomical
 *  purposes anyway, is to determine the atmospheric extinction.  In addition
 *  to calculating the airmass, the program also computes the column density,
 *  because it is perhaps a more appropriate figure for determining extinction.
 *  After all, the airmass only tells you what the extinction is going to be
 *  at some zenith angle, RELATIVE to at the zenith; you still need to know
 *  the extinction at the zenith!  The standard approximate formulas for
 *  airmass cannot provide this important bit of information, which is directly
 *  related to the column density.
 *       Several sources contribute to the atmospheric extinction at any given
 *  wavelength.  For visible and infrared wavelengths, we can limit the
 *  discussion to four primary contributors; the others are small enough to
 *  be negligible.  (Actually, there is an EXTREMELY important fifth component,
 *  namely suspended water droplets, commonly known as clouds; but in this
 *  discussion we'll assume that you're not trying to do high-precision
 *  photometric or spectroscopic work through clouds, so we'll ignore them.)
 *  The four components are: dry air, water vapor, ozone, and dust.  "Dust"
 *  means any particulate matter suspended in the air (i.e., aerosols), and
 *  "dry air" signifies clean (dust-free) air with zero humidity, and having
 *  a constant chemical composition.*
 *       The total extinction, in magnitudes, is given approximately by:
 *
 *      E = 2.5 log(e) (k_air N_air + k_O3 N_O3 + k_dust N_dust + k_H20 N_H20)
 *
 *  where the various k's are the extinction coefficients, in cm^2/g, for each
 *  contribution; the N's are the column densities (in g/cm^2) of each
 *  contribution; and the subscripts denote the contributions: air = dry,
 *  clean air of constant (or negligible) ozone composition; O3 = ozone;
 *  dust = suspended particles of any sort; H20 = water vapor.  The k's are
 *  wavelength-dependent, making E a function of wavelength.  This program
 *  computes the column density N_air, and optionally (with the "-H" flag on
 *  the command line) a crude estimate for N_H20.  (If your k's are in units of
 *  cm^2 rather than cm^2/g, convert the column densities to number densities
 *  by multiplying by A/m:
 *
 *       N (number density, units 1/cm^2) = N (g/cm^2) * A/m
 *
 *  where A is Avogadro's constant and m is the mean molecular weight of the
 *  constituent.  For dry air, m = 28.9644 g/mol, so the number density equals
 *  2.07915 * 10^22 * the column density in g/cm^2 for the dry air component.)
 *  k_air * N_air is approximately 0.2 at visual wavelengths, for dry air,
 *  observing at the zenith.
 *       Let us discuss the "-H" option briefly and how a crude estimate of
 *  the water vapor airmass and column density is calculated.  It is impossible
 *  to calculate the water vapor values from a simple theory; it requires the
 *  same sort of full-blown analysis that makes the calculation of the
 *  temperature profile impossible.  Thus, one needs either a direct
 *  measurement of the water vapor as a function of altitude (for example,
 *  through LIDAR), or one must make some approximation.  Based on an
 *  admittedly brief look into real vapor profiles, I propose the following
 *  extremely simplistic model, which does have the desired feature of being
 *  constrained by the actually measured value of the humidity at the
 *  observatory:
 *
 *            /
 *           |  H_0                                          , Q_0 < Q < Q_1
 *           |
 *           |          Q_2 - Q
 *     H =  _/  H_0 [ ----------- ]
 *           \         Q_2 - Q_1                             , Q_1 < Q < Q_2
 *           |
 *           |
 *           |  0                                            , otherwise
 *            \
 *
 *  where the Q's are as defined in the section "DERIVATION", H is the relative
 *  humidity at some point Q, and the H_n's are the relative humidities at the
 *  Q_n's.
 *       The primary motivation behind the above linear model (constant H up
 *  to the troposphere; linear falloff through the lower stratosphere; zero
 *  humidity above that) is that, as I just said, it is constrained by the
 *  measured value of the humidity at ground level (H_0).  In fact, it is
 *  quite strongly constrained, since H throughout the troposphere is assumed
 *  equal to this value.  Believe it or not, even though this is a very lame
 *  model, I believe it does have some merit, for the following reason: looking
 *  at a couple typical vapor profiles, the relative humidity did not tend to
 *  vary THAT MUCH throughout the lower troposphere -- "THAT MUCH" meaning
 *  "deviations larger than a factor of two, over large regions of the
 *  troposphere, seemed rare".  Furthermore, there is one great numerical
 *  property of the relative humidity which "limits the carnage" as far as
 *  keeping the REAL relative humidity from really deviating by orders of
 *  magnitude from the assumed value of H_0.  Which is this: a relative humidity
 *  above 100% is forbidden.  If the relative humidity exceeds 100%, it will
 *  not be by very much, and will probably not last for long, because the
 *  water vapor will try to condense as soon as it can (e.g., it spots a dust
 *  particle floating by and grabs onto it).  So, for all intents and purposes,
 *  we are numerically limited to values between 0% and 100% everywhere in the
 *  atmosphere, which is still a huge range of possible humidities but at least
 *  it is not all the real numbers.
 *       I am interested in seeing how well the above crude formula for H
 *  holds up against real data (both real measured humidity profiles as well
 *  as water vapor extinction computed from accurate photometry at some
 *  wavelength where water vapor dominates).  If you can supply any feedback
 *  on this, or if you know of a better humidity model which doesn't depend
 *  on complicated fluid dynamics equations, please do let me know.
 *       Anyway, once we have an assumed humidity profile, it is straightforward
 *  to calculate the water vapor column density and airmass.  The definition
 *  of relative humidity gives the water vapor pressure, given the vapor
 *  pressure at saturation.  The Clausius-Clapeyron equation gives the
 *  saturation vapor pressure as a function of temperature.  For the Clausius-
 *  Clapeyron equation, see Equation 4.4 in A.S. Monin, _Weather Forecasting
 *  as a Problem in Physics_ (Cambridge, MA: MIT Press), p. 15 (1972); we
 *  rewrite Monin's formulation of the equation so that it gives us exactly
 *  what we want, the saturation vapor pressure as a function of temperature,
 *  relative to some saturation pressure at some standard temperature.  These
 *  two conditions (the humidity profile and the Clausius-Clapeyron equation)
 *  let us solve for the vapor pressure.  Then, we assume local thermodynamic
 *  equilibrium (i.e., that the local temperature of the water vapor equals the
 *  temperature of dry air at that point -- a good assumption) and that the
 *  water vapor pressure behaves independently of the other gases in the
 *  neighborhood (not completely true, but certainly a good enough assumption
 *  given the poorly-known humidity profile).  Finally, we need only apply the
 *  ideal gas law (very close to valid for water vapor) and we have our density
 *  as a function of location in the atmosphere.  We use the same algorithm
 *  as with dry air, from that point on, to compute the column density and
 *  hence the airmass of the water vapor at some zenith angle z.
 *
 *  *In our airmass and column density calculations, ozone is included in the
 *   dry air component (with a constant fraction of the total air pressure
 *   assumed), showing up as a small contribution to the mean molecular weight.
 *   The mean molecular weight is the only way ozone has any impact in the
 *   dry air calculation.  Because the ozone concentration does change
 *   significantly throughout the atmosphere (it peaks in the lower
 *   stratosphere, and anyone who follows the news knows that there are "ozone
 *   holes", i.e., ozone is also a function of latitude and longitude), its
 *   column density CANNOT be calculated with the current code.  You should
 *   determine the ozone extinction contribution from a separate algorithm
 *   and then apply that contribution to the total extinction using the formula
 *   for E above.  (Since ozone is a small contribution to the mean molecular
 *   weight, do not worry about its effect in the calculation of the dry
 *   air column density or airmass.)
 *
 *
 *  NOTE ON ASSUMPTIONS
 *  ===================
 *
 *  Here is a rough analysis of the expected error in the calculation of the
 *  column density and airmass from using various assumptions.  As far as I
 *  know, the following list contains all the assumptions this program makes
 *  use of.  The list is sorted in order of their expected impact for most
 *  zenith angles (the worst assumption listed first).
 *       Note that this assumption list is only for the DRY AIR column density
 *  and airmass.  It is not a list of the assumptions on the water vapor column
 *  density or airmass which the program optionally calculates (see EXTINCTION
 *  above for more on that).  Nor does it deal with ozone or aerosol column
 *  densities or airmasses.
 *       Since the exact quantitative impacts of the assumptions depend on
 *  multiple factors, most particularly the zenith angle of interest, I only
 *  treat them in a qualitative sense, using adjectives like "moderate",
 *  "small", etc. to denote their expected relative importance.  From most to
 *  least in terms of impact, the adjectives are "moderate", "small", "very
 *  small", "minimal", "insignificant", and "unimportant".  Based on some
 *  VERY crude and quick calculations, "moderate" would correspond to a percent
 *  error (from using the approximation) of roughly 1% or less; "small" would
 *  correspond to something like 0.2% or less; "very small" smaller still;
 *  "minimal" meaning something like 0.01% if not considerably less;
 *  "insignificant" here meaning "probably falls into the class 'unimportant',
 *  but I'm not sure, and in any case is probably not a bigger assumption than
 *  something in the 'minimal' class"; and "unimportant" meaning around 0.001%
 *  if not considerably less.
 *       One thing to keep in mind is that these descriptions really only apply
 *  to LOW TO MODERATE ZENITH ANGLES (i.e., z less than ~ 60 degrees).  Many
 *  of the assumptions tend to become worse with z; those that are believed to
 *  have a significant z dependence (so that the assumptions are likely to be
 *  notably worse at extreme zenith angles) have the remark "z dependence."
 *  For example, the temperature profile assumption might become quite severe
 *  (i.e., larger than the rough 1% upper limit corresponding to the so-called
 *  "moderate" class) for zenith angles near 90 degrees.
 *       Another thing to keep in mind is that under no circumstances are the
 *  computed column density or airmass of higher accuracy than about 1 part in
 *  10^8.  This is because we consider the numerical integration "converged"
 *  when the column density changes by less than 1 part in 10^8 between
 *  iterations.  One could always change this tolerance limit, but there seems
 *  little point when certain assumptions like the temperature profile likely
 *  contribute a far larger fractional error than 1 in 10^8.  (The convergence
 *  criterion is the motivation, by the way, for printing the results to 8
 *  significant digits.  If all the following assumptions were negligible, in
 *  principle all 8 digits would be valid.)
 *
 *  TEMPERATURE PROFILE:  SMALL to MODERATE for column density, SMALL for
 *       airmass.  z dependence (possibly strong).  This is almost certainly
 *       the biggest assumption for the dry air calculations.  The problem is
 *       that we cannot compute this profile theoretically, and it would be
 *       impractical for most observatories to launch radiosondes or whatever
 *       to probe the atmosphere overhead.  Fortunately, Nature is kind to us
 *       in that the day-to-day fluctuations in the temperature at a given
 *       altitude are generally small compared to the absolute temperature;
 *       that is, the percent error of the fluctuations is relatively small
 *       when the temperature is expressed in Kelvins.  According to
 *       Figure II.2.1(b) in the _U.S. Standard Atmosphere_, at any given
 *       altitude the temperature will tend to be within about 10 K of the
 *       average value, over much of the altitude range of interest.  Thus
 *       the typical percent error is perhaps 5% at any given altitude and
 *       time under most conditions.  The variance is greatest at ground level,
 *       but we correct for that to a great extent by *incorporating* the
 *       ground temperature explicitly into our calculations of the temperature
 *       profile for the bottom two layers.  This should eliminate much of the
 *       variance at the lowest altitudes.  Furthermore, systematic offsets
 *       in one direction at one range of altitudes get balanced to some
 *       extent by offsets at another range, so the overall effect is lessened.
 *       And, unlike the U.S. Standard Atmosphere, we incorporate seasonal and
 *       latitude trends into our calculation of the bottom two layers, which
 *       helps reduce the offset between the theoretical profile and the real
 *       one.  Based on a crude experiment, I expect the error from not knowing
 *       the true profile to affect the column density by < 0.8%, and the
 *       airmass by < 0.3%.  These are conservative estimates, and the real
 *       error might be considerably less.
 *  SPHERICAL SYMMETRY:  SMALL under most conditions.  z dependence (possibly
 *       strong).  Except for the calculation of r_msl (see the discussion of
 *       the next assumption), complete spherical symmetry is assumed.  This,
 *       of course, is never absolutely true, for otherwise there would not
 *       be, for example, high-pressure and low-pressure weather systems since
 *       all locations on earth would have the same weather conditions at a
 *       given altitude.  The question really is to what extent these deviations
 *       from spherical symmetry affect the true airmass.  These deviations
 *       do not affect the column density at z=0 (the zenith) but in principle
 *       would for any other z.  Weather systems are essentially confined to
 *       the troposphere and lower stratosphere, i.e., roughly the lowest 20 km.
 *       Thus, except for extreme zenith angles, large weather patterns would
 *       not really affect our airmass that much because the horizontal distance
 *       starlight would travel through the weather system would not be great
 *       (less than 20 km for z = 45 degrees).  So, only local deviations from
 *       symmetry are important.  Small-scale effects such as turbulence would
 *       average out over the light's path, so only mesoscale deviations could
 *       be important, i.e., regions with sizes on the order of 20 km * sec(z)
 *       or less, but larger than ~ 1 km.  Furthermore, the dominant impact of
 *       these varying mesoscale regions would be a varying temperature, but
 *       this should be on the same order of magnitude if not considerably
 *       smaller than the vertical temperature variations, and therefore the
 *       effect of this assumption would be about the same if not much smaller
 *       than the "temperature profile" assumption.  One special case of
 *       deviation from spherical symmetry is discussed under the next
 *       assumption heading.
 *  GRAVITY VECTOR:  SMALL.  As the _U.S. Standard Atmosphere_ points out, the
 *       true gravity vector at any point does not generally point straight
 *       down to the center of the earth nor have the magnitude that you would
 *       calculate from Newton's Law of Gravitation for a sphere.  There are
 *       two main reasons.  The somewhat more important one, numerically, is the
 *       centrifugal force caused by the rotation of the earth.  Additionally,
 *       the earth is really an oblate spheroid (ironically, the earth is
 *       oblate precisely BECAUSE of the centrifugal force).  In principle, we
 *       could account for these effects in the computer code, since the theory
 *       is quite well known.  However, there really is no reason to complicate
 *       the algorithm in this manner, because the effects are rather small.
 *       Compared to the formula for a gravitating sphere, the first term of
 *       the centrifugal correction is ~ 580 times smaller, and the first term
 *       of the oblate spheroid correction is ~ 920 times smaller.  These are
 *       both on the order of the error of the "temperature profile" assumption
 *       above.  Thus, it did not seem necessary to complicate the code unless
 *       we have better information on the temperature profile.  The oblateness
 *       of the earth *is* accounted for in one way, however, since it is
 *       easy to implement it in the code.  It is in the calculation of r_msl,
 *       the true distance between mean sea level on some point on the earth's
 *       surface and the earth's center.  (See Equation (7) under DERIVATION
 *       above.)
 *  CONSTANCY OF CHEMICAL COMPOSITION:  VERY SMALL.  z dependence.  This is the
 *       assumption that all the components of dry, clean air have the same
 *       partial pressures throughout the atmosphere region over which we
 *       integrate (i.e., throughout the lowest 90 km).  For all the atmospheric
 *       gases which are important to extinction in visible and near-infrared
 *       wavelengths, except water vapor and ozone, this is a very good
 *       approximation.  It is such a good approximation that the U.S. Standard
 *       Atmosphere assumes a constant molecular weight of 28.9644 throughout
 *       the lowest 90 km.  Water vapor is considered separately (it is not
 *       a component of "dry, clean air", of course); ozone is a special case
 *       in that it is included into the dry air calculations through its
 *       molecular weight, but is considered constant throughout the atmosphere
 *       even though it's not.  (Ozone's contribution to the total molecular
 *       weight is small in any case, no matter how we consider its contribution
 *       to dry air.)  See also the "airmass independent of contaminants"
 *       assumption below.
 *  IDEAL GAS:  MINIMAL.  In many sources in the literature, dry air is said
 *       to behave very similarly to a ideal gas.  The deviation from an ideal
 *       gas is without question smaller than some of the assumptions above.
 *  HYDROSTATIC EQUILIBRIUM:  MINIMAL.  For hydrostatic equilibrium to be
 *       seriously violated, a parcel of air would practically have to be in
 *       a state of free fall.  Small-scale regions of turbulence would average
 *       out over a light's path, so a large region would have to be undergoing
 *       this type of motion extreme.  This seems quite unlikely except maybe
 *       near a tornado.  In which case, you wouldn't be observing.  Thus,
 *       departure from hydrostatic equilibrium is expected to have a quite
 *       minor effect on the true airmass.
 *  AIRMASS INDEPENDENT OF CONTAMINANTS:  INSIGNIFICANT.  z dependence.
 *       "Contaminants" here means water vapor, ozone, or aerosols (where
 *       ozone abundance varies with height).  As stated in the section
 *       "IMPORTANCE OF ATMOSPHERIC VARIABLES", water vapor is a very weak
 *       contribution to the total airMASS.  The same goes for ozone and
 *       aerosols.  We treat those components separately when considering
 *       EXTINCTION (q.v.), since water vapor, ozone, and aerosols do contribute
 *       heavily to the total extinction, even though they contribute so little
 *       to the mass of dry air.
 *  CLAUSIUS-MOSSOTTI EQUATION:  INSIGNIFICANT.  z dependence.  As it is, the
 *       Clausius-Mossotti Equation describes pretty well the relation between
 *       index of refraction and density for many materials, including air (c.f.
 *       Garfinkel 1967).  Furthermore, the index of refraction for air anywhere
 *       within the earth's atmosphere is going to be pretty close to 1, no
 *       matter what the functional form of mu(rho) is.  Finally, mu has only
 *       a rather weak impact on the airmass calculation (mainly because mu
 *       does stay close to 1); it is more important in calculating refraction.
 *       All these facts combined together illustrate that any errors which
 *       arise from using the Clausius-Mossotti Equation to calculate mu are
 *       probably quite small.
 *  ALL MASS BELOW 90 KM:  UNIMPORTANT.  The density at 90 km is about 10^5
 *       times less than at sea level, and continues to fall off nearly
 *       exponentially above that (see e.g. Figure I.2.11 in the _U.S. Standard
 *       Atmosphere_).  Thus, the contribution to the column density, and hence
 *       airmass, is about 10^5 times smaller than the contribution from the
 *       lower layers, so that this assumption contributes an error of around
 *       0.001%.  If you desire more precision, you could change the upper
 *       limit on the integration in the code, but to do it properly you would
 *       have to deal with the physics of the thermosphere, which does not
 *       have quite the same properties as the lower layers (for example, the
 *       assumption "constancy of chemical composition" breaks down).
 *  CRC FORMULA FOR MU(WAVELENGTH):  UNIMPORTANT.  This means the error in
 *       calculating the index of refraction mu for a given wavelength, because
 *       the formula in the CRC Handbook is not exact.  The wavelength of
 *       observation already has almost no effect on the airmass calculation
 *       (see IMPORTANCE OF ATMOSPHERIC VARIABLES below); the error in using
 *       the CRC formula (which itself is not a bad estimator for the index of
 *       refraction, at least for reasonable temperatures and pressures) must
 *       therefore have even less of an impact.  I feel pretty confident in
 *       saying that this is a good assumption.  Note that the code does not
 *       include an additional term in the formula for mu which accounts for
 *       humidity; this is safe because of the smallness of the term and
 *       because airmass depends on mu so weakly.
 *
 *
 *  VERBOSITY OPTION
 *  ================
 *
 *  With the -v ("verbose") flag, the program also spits out the airmass
 *  estimated by the polynomial approximation formula, and the percent error
 *  in this approximation (relative to the supposed "true" airmass computed
 *  by this program).  It also computes the result and error of the simple
 *  formula X ~ sec(z), and of the airmass formula used within IRAF.  The
 *  latter formula comes from  J.A. Ball, _Algorithms for the HP-45 and HP-35_
 *  (1975 ed.) (Cambridge, MA: Center for Astrophysics), with Q assumed to be
 *  750.  (Ball's algorithm comes from C.W. Allen, _Astrophysical Quantities_
 *  (3rd ed.) (London: Athlone), p. 133 (1973).)
 *       For all but extreme zenith angles (i.e., for z < 86 degrees), the
 *  sec(z) - 1 polynomial is the best of the three approximations.  The
 *  polynomial only goes bad at extreme zenith angles because it was not
 *  designed to fit these large angles.  Above about 86 degrees, the IRAF
 *  formula is a better approximation.  (The sec(z) - 1 polynomial goes negative
 *  above z ~ 88.35, which is of course physically impossible.)  But at these
 *  extremes it is clearly best to use the airmass algorithm utilized in this
 *  program.
 *       For low to moderate zenith angles, i.e., z < 70 roughly, it seems
 *  perfectly safe to use the sec(z) - 1 polynomial to approximate the airmass
 *  unless very high accuracy is required or atmospheric conditions are highly
 *  abnormal.  The error of that approximation is about 0.09% for typical
 *  atmospheric conditions.  The sec(z) - 1 polynomial error exceeds 1% at
 *  about z = 85 degrees, again for typical conditions.  The approximation
 *  rapidly deteriorates above this z.
 *       To judge the conditions over which the sec(z) - 1 polynomial is
 *  suitable, here is a table for a few large zenith angles.  Again, this is
 *  for the default values of atmospheric variables.  Also tabulated are
 *  percent errors for the polynomial when atmospheric conditions are at the
 *  most extreme one could expect to encounter at any reasonable point on the
 *  earth's surface.  The sec(z) and IRAF formula errors are also included.
 *
 *                           PERCENT ERRORS RELATIVE TO THIS PROGRAM
 *       z (deg)    sec(z)-1  (extreme)   IRAF   (extreme)   sec(z)  (extreme)
 *       =======    ===================   ================   =================
 *        60          0.0346     0.12      0.111    0.20      0.310     0.40
 *        65          0.0537     0.18      0.169    0.29      0.474     0.60
 *        70          0.0889     0.27      0.273    0.46      0.774     0.96
 *        75          0.159      0.44      0.489    0.77      1.41      1.7
 *        80          0.280      0.90      1.04     1.7       3.16      3.8
 *        81          0.294      1.0       1.25     2.0       3.87      4.6
 *        82          0.279      1.2       1.52     2.4       4.84      5.8
 *        83          0.186      1.7       1.88     3.0       6.20      7.4
 *        84          0.106      2.5       2.37     3.9       8.20      9.8
 *        85          0.942      4.1       3.02     5.0      11.3      14.
 *        86          3.42       7.6       3.89     6.6      16.5      20.
 *        87         12.0       17.        4.99     8.9      26.2      31.
 *        88         52.0       56.        6.06    12.       47.7      56.
 *        88.1       61.8       65.        6.13    12.       51.2      60.
 *        88.2       73.9       76.        6.20    13.       55.2      64.
 *        88.3       89.2       90.        6.25    13.       59.7      70.
 *        88.4       ----       ----       6.28    13.       64.8      76.
 *        88.5       ----       ----       6.29    14.       70.6      82.
 *        88.6       ----       ----       6.28    14.       77.3      90.
 *        88.7       ----       ----       6.25    14.       85.1      99.
 *        88.8       ----       ----       6.19    14.       94.3     110
 *        88.9       ----       ----       6.09    15.      105.      120
 *        89         ----       ----       5.96    15.      118.      140
 *        89.5       ----       ----       4.58    16.      266.      300
 *        89.9       ----       ----       2.30    16.        1.46E3    1.7E3
 *        89.99      ----       ----       1.61    16.        1.50E4    1.7E4
 *        89.999     ----       ----       1.53    16.        1.50E5    1.7E5
 *
 *  As the above table shows, atmospheric variable effects become important at
 *  large zenith angles (on the order of z = 80 and higher, but perhaps z ~ 70
 *  or even lower angles if you need high accuracy or the deviation of the
 *  atmospheric variables from standard values is extreme).
 *       Incidentally, sec(z) *ALWAYS* overestimates the true airmass; that is,
 *  you could consider sec(z) an upper bound on the value of the true airmass
 *  if you needed a rough estimate.  (And, of course, the sec(z) estimate
 *  progressively gets worse with larger z.)
 *
 *
 *  IMPORTANCE OF ATMOSPHERIC VARIABLES
 *  ===================================
 *
 *  For low to moderate zenith angles, the dependence of airmass on atmospheric
 *  variables (pressure, temperature, etc.) is generally small unless you need
 *  high accuracy or your observing conditions are extreme.  For these zenith
 *  angles, you can probably safely assume the values built into the program by
 *  default: temperature = 15 C, pressure = 1013.25 millibars, altitude = mean
 *  sea level, latitude = 45 degrees, day of year = 80, wavelength = 5500
 *  Angstroms.  (Most of these aren't technically atmospheric conditions but
 *  are considered here as site-dependent variables like the local temperature
 *  and pressure.)  These values correspond in a rough way to the definition of
 *  the U.S. Standard Atmosphere.  (The correspondence is not exact because of
 *  the way we calculate the characteristics of the bottom two temperature
 *  layers.)
 *       The importance of these variables in affecting the airmass calculation
 *  is roughly: temperature most important; pressure of medium importance;
 *  seasonal effects (latitude combined with day of year) not very important;
 *  altitude and wavelength unimportant.  A note about the above sentence:
 *  it only refers to the effects of actually changing the PARAMETERS to the
 *  program; each parameter is associated with an effect, e.g., "-a" for
 *  altitude.  However, the "real-life" effect of changing certain parameters
 *  is strongly coupled to changing others.  That is, if the observer literally
 *  changes his *altitude* (for example, he moves further up a mountain), the
 *  locally observed *pressure* is going to change tremendously (after all,
 *  altimeters are in essence just barometers), as well as the observed
 *  temperature (it tends to get colder as you move up), so that the true
 *  effect of changing the observer's altitude is actually stronger than
 *  if the local temperature or pressure alone would change, despite what
 *  the first sentence says.  Similarly, if the observer moves a great distance
 *  in latitude, the local temperature will obviously change.  To make sure
 *  there isn't any confusion about this point: just feed in the actual values
 *  of the observing conditions (temperature, pressure, altitude, latitude,
 *  day of year, wavelength) and everything will be fine.
 *       The wavelength (the wavelength of light we're observing at) has such
 *  a weak effect because it only affects the airmass calculation indirectly,
 *  in the calculation of the path the light takes through the atmosphere; the
 *  majority of the wavelength-dependent effect enters by way of refraction,
 *  whose effect is to change the APPARENT zenith angle of the object, which
 *  of course by far is the main parameter (z) affecting airmass; non-refraction
 *  wavelength dependence is thus rather minor.  Altitude is minor because of
 *  the way the bottom two temperature layers are calculated.  (It only enters
 *  the algorithm at all through the calculation of the lower limit of the
 *  integration.)  Temperature is the most important observing condition
 *  because it determines the temperature profile within the two lowest layers,
 *  which is of tremendous importance in calculating the density (c.f.
 *  Equation (5).)
 *        Humidity is NOT treated in this code for determining the airmass
 *  of dry air.  This is because, while certainly the presence of water vapor
 *  (especially condensed water!) affects the extinction coefficient of air,
 *  it does not affect the airMASS very much.  That is, it does not greatly
 *  affect the molecular weight or total density, since even saturated air does
 *  not carry much water vapor by mass.  Furthermore, to calculate the dry
 *  airmass precisely, taking the presence of water vapor correctly into
 *  account, requires an accurate knowledge of humidity as a function of height
 *  in the atmosphere, and as discussed under EXTINCTION above, we don't
 *  usually have such information.  In any case humidity's affect on airmass
 *  (particularly since airmass is normalized to 1 at the zenith) has got to be
 *  very small, for any conceivable atmospheric condition besides perhaps,
 *  perhaps, the innermost winds of a hurricane, and at that point other
 *  assumptions like spherical symmetry break down anyway.  Humidity is
 *  implicitly included in the sense that refraction changes the apparent zenith
 *  angle of the object, and any good refraction algorithm includes humidity.
 *
 ******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/*******************************************************************************
 *  Mathematical and physical constants, and constants derived from them.
 *  It's probably best to keep these as they are, since the temperature levels
 *  defined in the U.S. Standard Atmosphere were calculated using the values
 *  of the physical constants below.
 ******************************************************************************/

#define DEG2RAD (M_PI/180.)      /* factor for converting degrees to radians */
#define EQUATOR 6378178.           /* Earth's equatorial radius in meters */
#define POLAR (EQUATOR*(1.-1./298.32))  /* Earth's polar radius in meters */
#define GEOCENTGRAVCONST 3.9862216E14    /* G * mass of Earth (m^3 / s^2) */
#define STANDARDG0 9.80665               /* standard value of g0, in m/s^2 */
#define GASCONSTANT 8.314510       /* universal gas constant (R), in J/mol/K */
#define AIRKGPERMOLE 0.0289644    /* dry air mol.wt. 28.9644 * 0.001 g -> kg */
#define VAPORKGPERMOLE 0.0180153    /* water mol.wt. 18.0153 * 0.001 g -> kg */
#define AIRCONSTANT (GASCONSTANT/AIRKGPERMOLE)    /* R for dry air, J/kg/K */
#define VAPORCONSTANT (GASCONSTANT/VAPORKGPERMOLE)  /* R for vapor, J/kg/K */
#define CONSTC (AIRCONSTANT*273.15/101325.) /* constant for calculating c */
#define CONSTRHO (-(STANDARDG0)/AIRCONSTANT) /* constant for calculating rho */
#define STANDARDR02 (GEOCENTGRAVCONST/STANDARDG0)     /* GM/g0,  in m^2 */
#define CPVAPOR 1.81E3    /* typical heat capacity of water vapor, J/kg/K */
#define CWATER 4.20E3     /* typical specific heat of water, J/kg/K */
#define T0VAPOR 298.15   /* saturation vapor press. calibrated to this T (K) */
#define LATENTVAPOR 2443240. /* latent heat vap. at 25 C and 760 mm Hg (J/kg) */
#define P0VAPOR 3167.6       /* saturation vapor press. at 25 C (Pascals) */
#define VAPPRESSFACT1 ((CWATER-CPVAPOR)/VAPORCONSTANT) /* used in vaporrho() */
#define VAPPRESSFACT2 (((LATENTVAPOR/T0VAPOR)+(CWATER-CPVAPOR))/VAPORCONSTANT)
#define NTLEVELS 8  /* Number of different temperature regions in atmosphere */
#define K 5      /* constant used in polint() and qromb() */
#define IMAX 50  /* constant used in qromb() */

/*******************************************************************************
 *  Global variables (actually, constants, once they are computed in main().)
 *  The first two default values for betavec and tvec are replaced by values
 *  computed in main() (the default values come from the U.S. Standard
 *  Atmosphere, but we attempt a more "sophisticated" estimation of them based
 *  on the observed local temperature, pressure, etc.)
 ******************************************************************************/

static double cee, const6, const7, rhovec[NTLEVELS], bigrvec[(NTLEVELS+1)],
     betavec[NTLEVELS]={-0.0065, 0., 0.0010, 0.0028, 0., -0.0020, -0.0040, 0.},
     tvec[NTLEVELS]={288.15, 216.65, 216.65, 228.65, 270.65, 270.65, 252.65,
     180.65}, relhumid=-1.;

/*******************************************************************************
 *  vaporrho - called only if "-H" was passed on the command line.
 *  Calculates the wator vapor density, given the temperature (t) and
 *  relative humidity (rh).
 ******************************************************************************/

inline double vaporrho(double t, double rh)
{
   return rh*(P0VAPOR/VAPORCONSTANT)*pow(T0VAPOR/t, VAPPRESSFACT1)*
        exp(VAPPRESSFACT2-(VAPPRESSFACT2*T0VAPOR)/t)/t;
}

inline double frho(double rdiff, double rhobottom, double tbottom, double beta)
{
   return (fabs(beta)<1.E-10) ? rhobottom*exp(CONSTRHO*rdiff/tbottom) :
        rhobottom*pow(tbottom/(tbottom+beta*rdiff), 1.-CONSTRHO/beta);
}

inline double musquare(double rho)
{
   return (3.+4.*cee*rho)/(3.-2.*cee*rho);
}

double columndensityint(double r)
{
   unsigned long ju=NTLEVELS, jm, index=0;
   double rho;

   /* figure out index, the temperature layer corresponding to the given r. */
   /* The algorithm is based on "locate" in Numerical Recipes, and handles */
   /* r values outside the "proper" range (we simply assume the bottom (top) */
   /* temp. layer continues on to negative (positive) infinity, in such cases)*/
   while (ju-index>1) {
      jm=(ju+index)>>1;
      if (r>bigrvec[jm]) index=jm;
      else ju=jm;
   }

   rho=frho(r-bigrvec[index], rhovec[index], tvec[index], betavec[index]);
   r*=r;
   return STANDARDR02*rho/(r*sqrt(1.-const6*r/musquare(rho)));
}

double vaporcolumndensityint(double r)
{
   double rho, rdiff, vaprho;

   if (r<bigrvec[1]) {   /* if we are in the troposphere */
      rdiff=r-*bigrvec;
      rho=frho(rdiff, *rhovec, *tvec, *betavec);
      vaprho=vaporrho(*tvec+*betavec*rdiff, relhumid);
   } else {   /* assume we're in the lower stratosphere */
      rdiff=r-bigrvec[1];
      rho=frho(rdiff, rhovec[1], tvec[1], betavec[1]);
      vaprho=vaporrho(tvec[1]+betavec[1]*rdiff, const7*(bigrvec[2]-r));
   }
   r*=r;
   return STANDARDR02*vaprho/(r*sqrt(1.-const6*r/musquare(rho)));
}

/*******************************************************************************
 *  trapzd - auxiliary to qromb integration routine
 *  Adapted from J. Percival, who in turn adapted it from the original
 *  Numerical Recipes routine by Press et al.
 ******************************************************************************/

inline double trapzd(double (*func)(double), double a, double b, int n)
{
   double del, sum, tnm, x;
   int j;
   static double s;
   static int it;

   if (n<=0) {
      s=0.5*(b-a)*((*func)(a)+(*func)(b));
      it=1;
   } else {
      tnm=it;
      del=(b-a)/tnm;
      x=a+0.5*del;
      sum=0;
      for(j=0;j<it;j++) {
         sum+=(*func)(x);
         x+=del;
      }
      s=0.5*(s+(b-a)*sum/tnm);
      it*=2;
   }
   return s;
}

/*******************************************************************************
 *  polint - auxiliary to qromb integration routine
 *  Adapted from J. Percival, who in turn adapted it from the original
 *  Numerical Recipes routine by Press et al.
 ******************************************************************************/

inline double polint(double *xa, double *ya)
{
   double c[K], d[K], den, dif, dift, ho, hp, w, y;
   int i, m, ns;

   /* find the index of the closest table entry */
   ns=0;
   dif=fabs(xa[ns]);
   for(i=0;i<K;i++) {
      dift=fabs(xa[i]);
      if (dift<dif) {
         ns=i;
         dif=dift;
      }
      c[i]=ya[i];
      d[i]=ya[i];
   }

   y=ya[ns--]; /* first guess */
   for (m=0;m<(K-1);m++) {
      for(i=0;i<(K-1)-m;i++) {
         ho=xa[i];
         hp=xa[i+m+1];
         w=c[i+1]-d[i];
         den=ho-hp;
         den=w/den;
         c[i]=ho*den;
         d[i]=hp*den;
      }
      y+=(2*ns+1<(K-2)-m) ? c[ns+1] : d[ns--];
   }
   return y;
}

/*******************************************************************************
 *  qromb - Romberg rule integration
 *  Adapted from J. Percival, who in turn adapted it from the original
 *  Numerical Recipes routine by Press et al.
 *  Changed the convergence criterion to fabs(ss-oldss)<eps.
 ******************************************************************************/

double qromb(double (*func)(double), double a, double b, double eps)
{
   double ss=0., oldss=0., h[(IMAX+1)], s[IMAX];
   int i;

   h[0]=1;
   for (i=0;i<IMAX;i++) {
      s[i]=trapzd(func, a, b, i);
      if (i>=(K-1)) {
         ss=polint(h+i-(K-1), s+i-(K-1));
         if (fabs((ss-oldss)/ss)<eps) return ss;
         oldss=ss;
      } else oldss=s[i];
      h[i+1]=0.25*h[i];
   }

   printf("EXCEEDED MAX ITERATIONS (%d) IN qromb\n", IMAX);
   return ss;
}


void usage(void)
{
   printf("Usage:\n\nairmass [-a <alt>] [-d <day>] [-H <h>] [-l <lat>] [-L "
        "<wavelength>] [-p <P>]\n        [-t <T>] [-v] <zenith>\n\nwhere "
        "<zenith> is the APPARENT zenith angle, in degrees, whose airmass you\n"
        "want to calculate.  Program by default uses standard atmosphere "
        "values;\nto override these use any of: \n\t"
        "-a <alt> : observer's altitude above sea level, in meters (default 0)"
        "\n\t-d <day> : day number from beginning of year (0 = Jan 1; default "
        "80)\n\t-H <h> : relative humidity at observer, in percent (default "
        "n/a)\n\t-l <lat> : observer's latitude in degrees (default +45)"
        "\n\t-L <wavelength> : the observing wavelength in Angstroms (default "
        "5500)\n\t-p <P> : local pressure, in millibars (default 1013.25)"
        "\n\t-t <T> : local temperature, in Celsius (default 15).\n"
        "Additionally, you can specify the -v option to calculate the airmass"
        "\npredicted by standard approximate formulas (sec(z)-1 polynomial, "
        "IRAF, sec(z))\nand their error relative to the airmass computed by "
        "this program.\nIf -H is used, program will also compute a *CRUDE* "
        "estimate of the water vapor\ncolumn density and airmass, using the "
        "specified <h>.\n");
   exit(1);
}

int main(int argc, char **argv)
{
   char *s, verbos=0;
   int i;
   double colz, col0, cosyearfrac, sinz, rmsl, bigrmsl, zfact, approximation,
        rjunk, coslatsq, airmass, t0=288.15, p0=101325., lambda=5500., alt=0.,
        z=-1., lat=45., daynum=80., betapoly[5]={-0.0065107, -4.5403e-06,
        3.6599e-07, -2.2174e-09, 7.9392e-12}, r1poly[11]={17.204, 8.9155e-03,
        -3.6420e-03, 2.5617e-05, 2.4796e-07, -1.2774e-08, 1.3017e-10,
        2.0151e-12, -2.6985e-14, -1.0397e-16, 1.4849e-18}, hvec[(NTLEVELS+1)]=
        {0., 11000., 20000., 32000., 47000., 52000., 61000., 79000., 88743.};

   /* get command line arguments */
   argc--;
   while(argc--) {
      if( **++argv == '-') for(s = *argv+1;*s != '\0';s++) switch(*s) {
         case 'a':    /* observer's altitude in meters above mean sea level */
            sscanf(*++argv,"%lg",&alt);
            argc--;
            break;
         case 'd':    /* Day number from beginning of year, 0 = midnight Jan 1*/
            sscanf(*++argv,"%lg",&daynum);
            argc--;
            break;
         case 'H':    /* Do water vapor calc.  Relative humidity in percent */
            sscanf(*++argv,"%lg",&relhumid);
            relhumid*=0.01;   /* convert to fraction (range 0 - 1) */
            argc--;
            break;
         case 'l':    /* observer's latitude in degrees north of Equator */
            sscanf(*++argv,"%lg",&lat);
            argc--;
            break;
         case 'L':    /* observing wavelength in Angstroms */
            sscanf(*++argv,"%lg",&lambda);
            argc--;
            break;
         case 'p':    /* local pressure in millibars */
            sscanf(*++argv,"%lg",&p0);
            p0*=100.;   /* convert to Pascals */
            argc--;
            break;
         case 't':    /* local temperature in Celsius */
            sscanf(*++argv,"%lg",&t0);
            t0+=273.15;   /* convert to Kelvins */
            argc--;
            break;
         case 'v':    /* increase verbosity: compute error in approximation */
            verbos++;
            break;
         default:
            printf("illegal option: %s\n",s);
            usage();
      } else sscanf(*argv,"%lg",&z);
   }
   if ((z<0.) || (z>= 90.)) {
      printf("zenith angle not found or unacceptable value\n");
      usage();
   }

   sinz=sin(z*DEG2RAD);
   cee=CONSTC*(2.87566E-4+134.12/(lambda*lambda)+3.777E8*pow(lambda, -4.));
   cosyearfrac=cos((daynum-202.)*(360.*DEG2RAD/365.));
   coslatsq=cos(lat*DEG2RAD);
   coslatsq*=coslatsq;
   rmsl=sqrt(((POLAR*POLAR*POLAR*POLAR)+(EQUATOR*EQUATOR*EQUATOR*EQUATOR-
        POLAR*POLAR*POLAR*POLAR)*coslatsq)/((POLAR*POLAR)+(EQUATOR*EQUATOR-
        POLAR*POLAR)*coslatsq));
   bigrmsl=(-STANDARDR02)/rmsl;

   /* Calculate bigrvec, the bigr at the bottom of each temperature layer */
   *bigrvec=(-STANDARDR02)/(rmsl+alt);
   rjunk=r1poly[10];
   for (i=9;i>=0;i--) rjunk=rjunk*lat+((i%2) ? r1poly[i]*cosyearfrac :
        r1poly[i]);
   bigrvec[1]=(-STANDARDR02)/(rmsl+rjunk*1000.);
   for (i=2;i<(NTLEVELS+1);i++) bigrvec[i]=hvec[i]+bigrmsl;

   /* Set up our temperature profile for the troposphere/lower stratosphere */
   *betavec=betapoly[4];
   for (i=3;i>=0;i--) *betavec=*betavec*lat+((i%2) ? betapoly[i]*cosyearfrac :
        betapoly[i]);
   *betavec*=(-rmsl/bigrvec[1]);
   *tvec=t0;
   tvec[1]=t0+*betavec*(bigrvec[1]-*bigrvec);
   betavec[1]=(tvec[2]-tvec[1])/(bigrvec[2]-bigrvec[1]);

   /* Compute the density at the bottom of each temperature layer */
   *rhovec=p0/(AIRCONSTANT*t0);
   for (i=0;i<(NTLEVELS-1);i++) rhovec[i+1]=frho(bigrvec[i+1]-bigrvec[i],
        rhovec[i], tvec[i], betavec[i]);

   const6=musquare(*rhovec)*sinz*sinz/(*bigrvec*(*bigrvec));    /* for z */
   colz=qromb(columndensityint, *bigrvec, bigrvec[NTLEVELS], 1.E-8);
   const6=0.;  /* equivalent to setting z = 0. */
   col0=qromb(columndensityint, *bigrvec, bigrvec[NTLEVELS], 1.E-8);
   airmass=colz/col0;

   printf("for z=%.15g: column density=%.8g g/cm^2; AIRMASS=%.8g\n", z,
        0.1*colz, airmass);

   /* if desired, compute error in using various airmass approximations */
   if (verbos) {
      printf("Comparisons to various approximate formulae for the airmass:\n");

      /* Do the sec(z)-1 polynomial approximation */
      zfact=1./cos(z*DEG2RAD)-1.;
      approximation=1.+zfact*(0.9981833-zfact*(0.002875+(zfact*0.0008083)));
      printf("sec(z) - 1 polynomial gives %.8g, an error of %.3g%%.\n",
           approximation, 100.*fabs(approximation-airmass)/airmass);

      /* Do the IRAF approximation (based on J.A. Ball, from Allen) */
      zfact=750.*cos(z*DEG2RAD);
      approximation=sqrt(zfact*zfact+1501.)-zfact;
      printf("IRAF formula gives %.8g, an error of %.3g%%.\n",
           approximation, 100.*fabs(approximation-airmass)/airmass);

      /* Do the simple airmass ~ sec(z) approximation */
      approximation=1./cos(z*DEG2RAD);
      printf("sec(z) gives %.8g, an error of %.3g%%.\n",
           approximation, 100.*fabs(approximation-airmass)/airmass);
   }

   /* if desired, compute the (very crude) estimate of vapor column density */
   if (relhumid>0.) {
      const7=relhumid/(bigrvec[2]-bigrvec[1]);
      const6=musquare(*rhovec)*sinz*sinz/(*bigrvec*(*bigrvec));    /* for z */
      colz=qromb(vaporcolumndensityint, *bigrvec, bigrvec[2], 1.E-8);
      const6=0.;  /* equivalent to setting z = 0. */
      col0=qromb(vaporcolumndensityint, *bigrvec, bigrvec[2], 1.E-8);
      printf("water vapor column density=%.8g g/cm^2; water vapor "
           "airmass=%.8g\n", 0.1*colz, colz/col0);
   }
   exit(0);
}
