# Generating atmosphere model {#model-generation}

The model is generated by `calcmysky` utility from a text file, whose name normally has `.atmo` suffix. The command
```
calcmysky description.atmo --out-dir output-directory
```
will use the input file `description.atmo` and output the model to a directory named `output-directory`.

This utility has some options that can be listed by running it with `--help` option.

## Invocation of `calcmysky`

Generally the command line of `calcmysky` utility looks as
```
calcmysky [OPTION]... atmosphere-description.atmo --out-dir /path/to/output/dir
```
### Command-line options

<!-- The ul trickery here is to provide indentation of the text -->

 `-h`, `--help`
<ul style="list-style-type: none;"><li> Display help and exit. </li></ul>

 `-v`, `--version`
<ul style="list-style-type: none;"><li> Display version and exit. </li></ul>

 `--out-dir <output directory>`
<ul style="list-style-type: none;"><li> Set directory for the model generated. This is a mandatory option. </li></ul>

<a name="radiance-option"> `--radiance` </a>
<ul style="list-style-type: none;"><li> Save result as radiance instead of XYZW components. This lets the user change solar spectrum on the fly (see [Solar spectrum](model-preview.html#solar-spectrum-control) control in the previewer), as well as examine spectral radiance of the pixels in the rendered image (see [Show radiance plot](model-preview.html#show-radiance-plot-control) control). </li></ul>

<a name="no-eds-tex-option"> `--no-eds-tex` </a>
<ul style="list-style-type: none;"><li> Don't compute/save eclipsed double scattering textures. The model generated with this option will only be able to render eclipsed atmosphere's double scattering radiance on the fly. </li></ul>

 `--texture-save-precision <bits>`
<ul style="list-style-type: none;"><li> Reduce precision of the 3D textures to the given number of bits. Valid values are from 1 to 24, the latter meaning full precision. The reduction of precision is achieved by zeroing out the least significant bits of the significand. This lets one improve compressibility of the textures at the expense of fidelity of output. </li></ul>

### Debugging options

These options are not useful for a normal user, they are used by developers.

<a name="no-save-tex-option"> `--no-save-tex` </a>
<ul style="list-style-type: none;"><li> Don't save textures, only save shaders and other fast-to-compute data. Also don't run the long 4D textures computations. This option is useful when you edit a shader template and want to regenerate the shaders without recomputing the textures. Note that some changes may actually affect texture data, use with caution. </li></ul>

 `--opengl-debug`
<ul style="list-style-type: none;"><li> Install a GL_KHR_debug message callback and print all the messages from OpenGL. </li></ul>

 `--opengl-debug-full`
<ul style="list-style-type: none;"><li> Like --opengl-debug, but don't hide notification-level messages. </li></ul>

 `--save-irradiance`
<ul style="list-style-type: none;"><li> Save intermediate ground irradiance textures. </li></ul>

 `--save-scat-density2-from-ground`
<ul style="list-style-type: none;"><li> Save order 2 scattering density from ground. </li></ul>

 `--save-scat-density`
<ul style="list-style-type: none;"><li> Save scattering density textures. </li></ul>

 `--save-delta-scattering`
<ul style="list-style-type: none;"><li> Save delta scattering textures for each order. </li></ul>

 `--save-accum-scattering`
<ul style="list-style-type: none;"><li> Save accumulated multiple scattering textures for each order. </li></ul>

 `--save-light-pollution`
<ul style="list-style-type: none;"><li> Save intermediate light pollution textures. </li></ul>

## Format of model description file

Model description files consist of entries that represent key-value pairs. Empty lines between entries are ignored, and "#" character starts comments. Single-line entries can also be followed by a comment in the same line.

Any text on a line before the first colon character ":" is considered to be key. Depending on the key, corresponding value can be one of the following:
 * a number, e.g. `123.456`;
 * a dimensionful quantity (see [Dimensionful quantities](#dimensionful-quantities));
 * a spectrum (see [Spectra](#spectra))
 * a range of wavelengths, e.g. `min=360nm,max=830nm,count=16`;
 * a section (see [Sections](#sections));
 * a code block (see [Code blocks](#code-blocks)).

### <a name="dimensionful-quantities">Dimensionful quantities</a>

A dimensionful quantity is a number followed by a unit. Scientific notation is not supported. An example of a length quantity is `1.234 m`.

Several types of quantities are supported:

| Dimension         | Supported units                                                                       |
|-------------------|---------------------------------------------------------------------------------------|
| length            |                      `nm`, `um`, `mm`, `m`, `km`, `Mm`, `Gm`, `AU`                    |
|reciprocal length  |                `nm^-1`, `um^-1`, `mm^-1`, `m^-1`, `km^-1`, `Mm^-1`, `Gm^-1`           |
| area              | `am^2`, `fm^2`, `pm^2`, `nm^2`, `um^2`, `mm^2`, `cm^2`, `m^2`, `km^2`, `Mm^2`, `Gm^2` |

### <a name="spectra">Spectra</a>

Spectra are specified in predefined units, which depend on the key to which this spectrum corresponds.

There are several ways to specify a spectrum:

1. A list of numbers, which can be in normal or scientific format, separated with commas. Each list item must correspond to a particular wavelength from the `wavelengths` entry. Example of such spectrum:
```
    solar irradiance at TOA: 1.037, 1.249, 1.684, 1.975, 1.968, 1.877, 1.854, 1.818, 1.723, 1.604, 1.516, 1.408, 1.309, 1.23, 1.142, 1.062
```
2. A file path prepended with `"file "`. The format is described in [Spectrum file format](#spectrum-format) section. Here the spectrum may be sampled at any points, it will be resampled to match `wavelengths` automatically. Example:
```
    solar irradiance at TOA: file spectra/solar-irradiance-at-toa.csv
```
3. Spectra from several files added together with weighting coefficients. A filename must be prepended with `"weighted file "`, and each new such entry accumulates the new values in the corresponding spectrum. Example:
```
    ground albedo: weighted file 0.8 spectra/ground-albedo-grass.csv
    ground albedo: weighted file 0.2 spectra/ground-albedo-snow.csv
```

### <a name="spectrum-format">Spectrum file format</a>

Spectrum files are CSV (Comma-Separated Values) tables with two columns. Each line corresponds to one spectral point: first column specifies wavelength in nanometers, second column holds value. Empty lines are ignored.

Example of a spectrum from \f$400\,\mathrm{nm}\f$ to \f$700\,\mathrm{nm}\f$ with \f$100\,\mathrm{nm}\f$ interval:
```
400,0.2342
500,0.8134
600,0.478
700,1.235
```

### <a name="sections">Sections</a>

A section begins on the next line after the key, the colon character remains on the line with the key.

Top-level sections are bounded by an opening brace "{" and a closing brace "}". Between braces there can be multiple key-value entries.

Example of a section:

    Some section:
    {
        some value: 234
    }

### <a name="code-blocks">Code blocks</a>

Code blocks look similarly to sections, but instead of braces they are bounded by triple backticks "```", similarly to fenced code blocks in Markdown.

Example of a code block:

    number density:
    ```
        const float rayleighScaleHeight=8*km;
        return 3.08458e25*exp(-1/rayleighScaleHeight * altitude);
    ```

## Keys and values

The keys listed here are grouped by common parts of the name. The omitted parts are marked with `"*"`.  A few examples of complete `*.atmo` files can be found under the `examples` directory in the source tree.

### `version`
This entry must be the first entry in the atmosphere description file. It defines the layout of the model data and general format of the atmosphere description file. If it doesn't match the format supported by the given version of CalcMySky, an error will be emitted by `calcmysky` and `showmysky` utilities, as well as by the `ShowMySky` library.

### `atmosphere height`
This entry is [dimensionful](#dimensionful-quantities). Atmosphere height is the maximum altitude at which density of some constituents of the atmosphere is considered nonzero. The sphere of all the points at this altitude is called TOA, i.e. top of atmosphere. All the textures span altitudes from 0 to atmosphere height.
Valid values for this entry are length quantities from 1&nbsp;m to 1&nbsp;Mm.

### `scattering orders`

When a light ray propagates in the atmosphere, it can be scattered on the inhomogeneities of this medium (molecules, dust, etc.). This produces secondary rays, which, in turn, can also be scattered to produce tertiary rays, etc. The first scattering of the initial ray is called first-order scattering. Scattering of the secondary rays is second-order, and so on.

Radiance in each subsequent scattering order normally becomes smaller, approaching zero in the limit. This makes it possible to ignore the scattering events starting with some order of scattering, with negligible loss of accuracy. The `scattering orders` entry sets number of scattering orders to take into account.

### `transmittance texture size*`

Transmittance texture holds a map of percentage of light that's transmitted through the atmosphere from the TOA to the camera, given altitude of a camera and view zenith angle (VZA) of this camera. The entries above control the resolution of the transmittance texture in each of these dimensions.

### `irradiance texture size*`

Irradiance texture contains values of irradiance of a horizontal surface at the point with given altitude and zenith angle of the Sun (SZA). The entries above control the resolution of the irradiance texture in each of these dimensions.

### `scattering texture size*`

Scattering textures are the main textures that contain the actual radiance or luminance from given direction as seen by a camera at the given altitude, with the Sun being at a given zenith angle.

VZA, SZA and altitude here are similar to the corresponding parameters in irradiance and transmittance textures.

The `dot(view,sun)` parameter determines cosine of the angular distance between the direction from the camera to the Sun and the direction of view of the camera.

For technical reasons the texture size for VZA here must be even.

### `eclipsed scattering texture size*`

When solar eclipse is simulated, corresponding first-order scattering texture is computed on the fly during rendering, for the current altitude of the camera and the current positions of the Sun and the Moon. This is unlike the case of non-eclipsed calculations, where such radiance is precomputed for all altitudes and solar elevations.

Relative azimuth is the azimuth of the view direction relative to the Sun. VZA is view zenith angle, as described for transmittance texture.

### `eclipsed double scattering texture size*`

When solar eclipse is simulated, it's only simulated for two scattering orders, because going further is prohibitively slow. Even second-order scattering is quite slow on many GPUs. These entries control precomputation of a texture that will hold second-order scattering radiance for the given view zenith angle, solar elevation, and azimuth of view relative to the Sun.

### `eclipsed double scattering number of * pairs to sample`

Because second-order scattering is so slow to compute, radiance is sampled on a very sparse grid of points. Several circles at different azimuths are sampled at multiple elevations, with an optimized distribution of samples. The samples are taken in pairs, e.g. if one sampling direction is forward, one more will be backward.

The more samples one takes, the higher the resolution of the final second-order scattering layer.

### `light pollution texture size*`

Light pollution is simulated with the assumption that the whole Earth glows uniformly with the given luminance (which is controlled at runtime). This makes the radiance quite symmetric (although overestimated near the horizon), depending only on altitude of the camera and zenith angle of its view direction. These entries control resolution in these parameters.

### `transmittance/radial integration points`

Computation of transmittance and inscattered radiance is done in the direction of view from camera position to the TOA. Since transmittance is stored in a 2D texture, rather than 4D, it's relatively cheap to compute it more precisely. Inscattered radiance, OTOH, is stored in a 4D texture, so `radial integration points` value has to be smaller to make the computation faster. This is especially important for eclipsed atmosphere, where this computation is done on the fly.

### `angular integration points*`

Angular integration is done at every point of sampling of a ray, to collect the radiance that comes in from all directions, and compute the radiance that is scattered out. The integration is performed using a quasi-uniform spherical Fibonacci lattice, a good explanation of which can be seen [here](https://stackoverflow.com/a/44164075/673852). The entries above all define total number of points in this lattice, for normal and eclipsed atmospheres.

### `light pollution angular integration points`

Due to the symmetry of the uniformly-glowing-globe approximation, light pollution is computed as a 1D integral over elevations, so this entry just defines number of points in 1D quadrature.

### `Earth-Sun distance`, `Earth-Moon distance`, `Earth radius`

These entries are [dimensionful](#dimensionful-quantities). They define the physical constants used in the model. Earth-Sun distance can be from \f$0.5\,\mathrm{AU}\f$ to \f$10^{20}\,\mathrm{AU},\f$ Earth-Moon distance can be from \f$10^{-4}\,\mathrm{AU}\f$ to \f$10^{20}\,\mathrm{AU},\f$ and Earth radius can be from 100&nbsp;km to 10&nbsp;Gm.

Earth-Moon distance is used only for precomputation of eclipsed double scattering.

Note that these limits are rather arbitrary, and nothing too far (like orders of magnitude difference) from the real Earth-Sun-Moon system has ever been tested.

### `wavelengths`

This entry describes the set of wavelengths to use. It consists of smallest wavelength (`min`), largest (`max`), and total number of wavelengths in the set (`count`). The calculations are done separately for each wavelength to obtain radiance from different directions. Then these values are saved into the textures.

After radiance is obtained, to be displayed on a screen it needs to be converted to some color space. This is done by numerically integrating the radiance with respect to the CIE 1931 color matching functions, after which the conversion to the target color space is done.

Scattering textures are stored as either spectral radiance (when requested by `--radiance` option for `calcmysky`), or as \f$XYZW\f$ luminance. \f$XYZ\f$ here are the CIE 1931 tristimulus values, and \f$W\f$ is the scotopic luminance.

### <a name="solar-irradiance-at-toa">`solar irradiance at TOA`</a>

This entry is a [spectrum](#spectra). It defines spectral irradiance in \f$\mathrm{\frac W{m^2 nm}}\f$ as it would be measured at the TOA when the Sun is at zenith.

### `ground albedo`

This entry is a [spectrum](#spectra). It defines ground albedo, where each point is a dimensionless value in the range from 0 to 1. Ground BRDF is hard-coded to be Lambertian.

### `light pollution relative radiance`

This entry is a [spectrum](#spectra). It defines spectral radiance of the ground, in \f$\mathrm{cd/m^2}.\f$ The total luminance here should be normalized to \f$1\,\mathrm{cd/m^2}.\f$

### <a name="scatterer">`Scatterer "*"`</a>

This entry is a [section](#sections). Its name is formed as `Scatterer` keyword followed by name of the scatterer species in quotes. The species name must consist only of alphanumeric characters and underscores and have no spaces. Inside the braces there are several key-value entries, described in the following subsections.

#### <a name="scatterer-number-density">`number density`</a>

This entry is a [code block](#code-blocks). It defines number density of the scatterer being described in the current section. This code block is used as the implementation of a GLSL function that has a `float` parameter called `altitude`, with a value in meters, and returns a `float` value of number density in \f$\mathrm m^{-3}\f$.

#### `phase function`
This entry is a [code block](#code-blocks) that computes the [phase function](single-multiple-scattering.html#phase-function) of the current scatterer. It takes a `float` parameter called `dotViewSun`, and returns `vec4` relative intensity, where each component of `vec4` corresponds to wavelength in corresponding component of the global `vec4` variable `wavelengths`.

Mathematically, the parameter is cosine of the angle between the incoming ray and the scattered ray. Each component of the output `vec4` (let's call \f$ i\f$th component \f$f_i\f$) must be normalized by the following condition:

\f{equation}{
\int_{0}^{2\pi}\mathrm{d}\varphi \int_{0}^{\pi} \mathrm{d}\theta \sin(\theta) f_i(\theta)=1.
\f}

#### <a name="phase-function-type">`phase function type`</a>

Depending on the properties of the scatterer, there may be some ways to optimize storage of the computation results. This entry can have the following values:

 * `general` — the most general way of storing computation results: first-order scattering in a separate texture, split into separate textures per wavelength set, multiple scattering in another texture.
 * `achromatic` — denotes a phase function that doesn't depend on wavelength. This lets us merge all the single scattering radiance textures into a single luminance texture without compromising correctness of rendering.
 * `smooth` — a kind of phase function that doesn't need a high resolution texture to be represented well. This lets the phase function be embedded into the texture. Such texture data can be saved as color instead of radiance. This helps save storage space and improve rendering performance.

#### `cross section at 1 um`

This entry is a [dimensionful](#dimensionful-quantities) quantity of area. It defines extinction cross section of the current scatterer at \f$1\,\mathrm{\mu m}\f$ wavelength. The values for other wavelengths are obtained using the [<code>angstrom exponent</code>](#angstrom-exponent) parameter.

For gases Rayleigh scattering cross section can be found from refractive index using the following formula
(see Landau, Lifshitz, "Electrodynamics of Continuous Media", equation \f$(120.4)\f$ for reference; we augment it with \f$h=\sigma N\f$ to get \f$\sigma\f$):

\f{equation}{
\sigma_{\text{sc}}=\frac{8\pi^3}3\frac{(n^2-1)^2}{\lambda^4}\left(\frac{k_{\text{B}}T}P\right)^2,
\f}

where \f$n\f$ is refractive index, \f$\lambda\f$ is the vacuum wavelength (taken as \f$1\,\mathrm{\mu m}\f$ for this entry), \f$k_{\text{B}}\f$ is the Boltzmann constant, and \f$T\f$ and \f$P\f$ are respectively temperature and pressure at which this refractive index was measured.

#### <a name="angstrom-exponent">`angstrom exponent`</a>

This entry defines the Ångström exponent, which describes the power law dependence of the optical thickness (extinction coefficient) of a medium on wavelength. For Rayleigh scattering its value is 4, while for clouds it is about zero.

#### `single scattering albedo`

This entry is a [spectrum](#spectra). It defines single scattering albedo of current scatterer. Each point of this spectrum is a dimensionless value in the range from 0 to 1. If not specified, the default is albedo of 1 at each wavelength.

#### `needs interpolation guides`

This entry is a special token that's not a key: it isn't followed by a colon with a value.

Presence of this entry means that single scattering data for the scatterer described in current section have a rapid variation of colors in the Venus belt region, which, if texture resolution is small, will look jumpy when interpolated using the usual quadrilinear filter — either when looking at a single frame (similar to aliasing of lines), or when watching the sunset (the Venus belt will jump from one elevation to the next in the texture as the Sun goes deeper under the horizon). To fix this problem, special files will be created which will guide the renderer's interpolation function to improve quality.

If this entry is not present, interpolation guides are not created, so interpolation will use quadrilinear filter. This is better for performance, so should be the default.

### `Absorber "*"`

This entry is a [section](#sections). Its name is formed as `Absorber` keyword followed by name of the absorbing species in quotes. The species name must consist only of alphanumeric characters and underscores and have no spaces. Inside the braces there are several key-value entries, described in the following subsections.

#### <a name="absorber-number-density">`number density`</a>

This entry is of the same kind as [the one in the <code>Scatterer</code> section](#scatterer-number-density).

#### `cross section`

This entry is a [spectrum](#spectra). It defines cross section of absorption of the current absorber. The data points in this spectrum are in units of \f$\mathrm{\frac{m^2}{particle}}\f$ (where "particle" is the object counted by the [number density](#absorber-number-density) parameter).
