+++
title = "Scan"
weight = 20
+++

## Scan models

Scans are needed to construct simulations of types
[reflectometry](/ref/sim/class/specular),
[off-specular scattering](/ref/sim/class/offspec),
[depth probe](/ref/sim/class/depthprobe).

There are three types of scan:
- Alpha scans, for instruments that are mechanically scanning
  the grazing angle $\alpha\_\text{i}$;
- Lambda scans, for instruments that are scanning the wavelength $\lambda$;
- Qz scans, for both angular-scanning or time-of-flight instruments.


#### Common properties

All scan types have `intensity`: 

```python
scan.setIntensity(intensity)
```

[Polarization and analyzer](/ref/instr/pol) can be assigned to the scan when needed 
(for [specular](/ref/sim/class/specular) and [off-specular](/ref/sim/class/offspec) simulations).

```python
scan.setPolarization(polarization) # for specular & off-specular
scan.setAnalyzer(analyzer) # for specular
```


### Alpha scans

To specify a scan with `n` equidistant points in the grazing angle $\alpha\_\text{i}$, use
```python
scan = ba.AlphaScan(n, alpha_start, alpha_stop)
```

Usage is demonstrated by most examples in
{{% ref-ex "specular" %}}.

For other sequences of $\alpha\_\text{i}$ values, use the more generic
```python
alpha_list = ba.ListScan("alpha_i (rad)", [0*deg, 0.01*deg, ... 1.2*deg]) # all points
scan = ba.AlphaScan(alpha_list)
```

After constructing a scan, set the wavelength and optionally the azimuthal angle and a constant offset
$\delta\alpha\_\text{i}$ using
```python
scan.setWavelength(lambda)
scan.setAzimuthalAngle(phi)

scan.setAlphaOffset(dalpha)
```

`alpha`, `lambda`, `phi` may also have [distributions](/ref/other/distributions), then create them and assign to the scan:

```python
scan.setWavelengthDistribution(lambda_distr)
scan.setGrazingAngleDistribution(alpha_distr)
scan.setAzimuthalAngleDistribution(phi_distr)
```

[Footprint](/ref/instr/beam/footprint) can be assigned to the alpha scan 
(for [specular](/ref/sim/class/specular) and [off-specular](/ref/sim/class/offspec) simulations).

```python
scan.setFootprint(footprint) # for specular & off-specular
```

### Lambda scans

To specify a scan with `n` equidistant points in the neutron/X-ray wavelength $\lambda$, use
```python
scan = ba.LambdaScan(n, lambda_start, lambda_stop)
```

To specify a scan with any other sequence of $\lambda$ values, use
```python
lambda_list = ba.ListScan("lambda (nm)", [0.6*nm, 0.61*nm, ... 0.7*nm]) # all points
scan = ba.LambdaScan(lambda_list)
```

After constructing a scan, set the grazing angle and optionally the azimuthal angle using
```python
scan.setGrazingAngle(alpha)
scan.setAzimuthalAngle(phi)
```

`alpha`, `lambda`, `phi` may also have [distributions](/ref/other/distributions), then create them and assign to the scan:

```python
scan.setWavelengthDistribution(lambda_distr)
scan.setGrazingAngleDistribution(alpha_distr)
scan.setAzimuthalAngleDistribution(phi_distr)
```

[Footprint](/ref/instr/beam/footprint) can be assigned to the lambda scan 
(for [specular](/ref/sim/class/specular) and [off-specular](/ref/sim/class/offspec) simulations).

```python
scan.setFootprint(footprint) # for specular & off-specular
```

Usage in off-specular scattering is demonstrated by
{{% ref-ex "specular/OffspecLambda.py" %}}.

See also the example page [off-specular simulation](/ref/sim/class/offspec/ex).

### Qz scans

To specify a scan with `n` equidistant steps in the vertical wavenumber $q_z$, use
```python
scan = ba.QzScan(n, qz_start, qz_stop)
```

For other sequences of $q_z$ values, use the more generic
```python
qz_list = ba.ListScan("q_z (1/nm)", [0.01/nm, 0.02/nm, ... 1.2/nm]) # all points
scan = ba.QzScan(qz_list)
```

A third alternative consists in passing a NumPy array,
```python
import numpy as np
qz_vector = np.linspace(0.01, 1, n)
scan = ba.QzScan(qz_vector)
```

After constructing a scan, a constant offset $\delta q_z$ can be set using

```python
scan.setOffset(dqz)
```

To specify q-resolution one needs at first create corresponding [distribution](/ref/other/distributions) `distr` 
but then there are three ways to specify a q-resolution.

1. Set absolute value of resolution, given in units of `1/nm`:
```python
scan.setAbsoluteQResolution(distr, dq)
```

2. Set relative value of resolution, given as fraction of $q_z$ value at each point of scan:
```python
scan.setRelativeQResolution(distr, dq_rel)
```

3. Set individual absolute value of resolution, given as vector of the same length `n`:
```python
dq_vector = 0.03*np.linspace(0.01, 1, n)  # dq-values in "1/nm"
scan.setVectorResolution(distr, dq_vector)
```
    
As Qz scan does not contain full information about simulation geometry, it is _incompatible_ with footprint.

`alpha`, `lambda`, `phi` and thair distributions cannot be set.
    
Usage is demonstrated in page [time-of-flight reflectometry](tof).

Handling of resolution will change soon.
The current API is demonstrated in page
[time-of-flight reflectometry with resolution](tof-resolution).
