# Calculation

There are two different datasets used for benchmarking obtained from the {py:mod}`contourpy.util` functions
{py:func}`~contourpy.util.data.simple` and {py:func}`~contourpy.util.data.random`.  The former is the sum
of two gaussians that results in a small number of relatively short contours.  The latter is random
data that results in a large number of small contours and a few large contours; this is an extreme
dataset designed to stress the contouring algorithms. Both have the option to generate masked data.

All of the results shown are for a single chunk with a problem size `n` (`== nx == ny`) of 1000.

As a guide to the complexity of the output, the unmasked datasets generate the following line
contours in the benchmarks

- `simple`: 38 lines of about 36 thousand points.
- `random`: 850 thousand lines of about 7.4 million points.

and the following filled contours

- `simple`: 55 boundaries (39 outers and 16 holes) of about 76 thousand points.
- `random`: 1.7 million boundaries (half each of outers and holes) of about 15 million points.

## Contour lines

```{image} ../_static/lines_simple_1000_light.svg
   :class: only-light
```

```{image} ../_static/lines_simple_1000_dark.svg
   :class: only-dark
```

For the `simple` dataset above the performance of {ref}`serial` for contour lines is the same
regardless of {py:class}`~.LineType`. It is about the same as {ref}`mpl2005` and significantly faster
than {ref}`mpl2014` with a speedup of 1.8-1.9.

```{image} ../_static/lines_random_1000_light.svg
   :class: only-light
```

```{image} ../_static/lines_random_1000_dark.svg
   :class: only-dark
```

For the `random` dataset above the performance of {ref}`serial` varies significantly by
{py:class}`~.LineType`.  For `LineType.SeparateCode` {ref}`serial` is 10-20% faster than
{ref}`mpl2005`, and is about the same as {ref}`mpl2014` if masked and 10% slower if not masked.

Other {py:class}`~.LineType` are faster.  `LineType.Separate` has a speedup of about 1.4 compared to
`LineType.SeparateCode`; most of the difference here is the time taken to allocate the extra 850
thousand {{ NumPy }} arrays (one per line) and a small amount is the time taken to calculate the
{{ Matplotlib }} kind codes to put in them.

The chunked line types (`LineType.ChunkCombinedCode`, `LineType.ChunkCombinedOffset` and
`LineType.ChunkCombinedNan`) have similar timings with a speedup of 2.4-2.7 compared to
`LineType.SeparateCode`.  The big difference here again is in array allocation, for a single chunk
these two `LineType` allocate just two large arrays whereas `LineType.SeparateCode` allocates
1.7 million {{ NumPy }} arrays, i.e. two per each line returned.

## Filled contours

```{image} ../_static/filled_simple_1000_light.svg
   :class: only-light
```

```{image} ../_static/filled_simple_1000_dark.svg
   :class: only-dark
```

For the `simple` dataset above the performance of {ref}`serial` for filled contours is the same
regardless of {py:class}`~.FillType`.  It is about the same as {ref}`mpl2005` and significantly
faster than {ref}`mpl2014` with a speedup of 1.9-2.0.

```{image} ../_static/filled_random_1000_light.svg
   :class: only-light
```

```{image} ../_static/filled_random_1000_dark.svg
   :class: only-dark
```

For the `random` dataset above the performance of {ref}`serial` varies significantly by {py:class}`~.FillType`.
For `FillType.OuterCode` it is faster than {ref}`mpl2014` with a speedup of 1.5-1.7.  It is also
faster than {ref}`mpl2005` but only the `corner_mask=False` option is shown in full as the unmasked
benchmark here is off the scale at 11.7 seconds.  The {ref}`mpl2005` algorithm calculates points for
outer and hole boundaries in an interleaved format which need to be reordered, and this approach
scales badly for a large outer boundary containing many holes as occurs here for unmasked `z`.

Other {py:class}`~.FillType` are faster, although `FillType.OuterOffset` is only marginally so as it
creates the same number of {{ NumPy }} arrays as `FillType.OuterCode` but the arrays are shorter.

The other four {py:class}`~.FillType` can be grouped in pairs: `FillType.ChunkCombinedCodeOffset` and
`FillType.ChunkCombinedOffsetOffset` have a speedup of 1.8-2.0 compared to
`FillType.OuterCode`; whereas `FillType.ChunkCombinedCode` and
`FillType.ChunkCombinedOffset` are marginally faster with a speedup of 1.9-2.1.  The speed
improvement has the usual explanation that they only allocate a small number of arrays whereas
`FillType.OuterCode` allocates 1.7 million arrays.  `FillType.ChunkCombinedCode` and
`FillType.ChunkCombinedOffset` are slightly faster than the other two because they do not
determine the relationships between outer boundaries and their holes, they treat all boundaries the
same.
