# Windstorm through Oasis: the PiWind lane, with insured and net losses

The model lab's `oasis-piwind` lane runs PiWind, the reference windstorm
model of the Oasis Loss Modelling Framework, over the places you send. It
always gives **ground-up** losses. Send policy terms and reinsurance with
the spec and Oasis's own financial module adds two more views of the same
simulated years: **insured** losses and losses **net of reinsurance**. How
to submit a run is in [the agent walk](agents.md); every figure's meaning
is in [Lab metrics](lab-metrics.md). Every lab model is an open model, run
as its authors published it on fixed inputs. Craton has not validated it.

| Spec `model` | Version | Framework | Where |
|---|---|---|---|
| `oasis-piwind` | `oasislmf-2.5.7-r3` | Oasis LMF 2.5.7, PiWind at commit `94820c59` | A demonstration grid about 4 km by 7 km in England: lat 52.734 to 52.795, lon -0.918 to -0.857 |

**Basis:** a synthetic event set over a demonstration-grade hazard
footprint: not observed history, not a forecast. PiWind describes itself
as a toy model. It is here because it is the one openly runnable Oasis
model, so it shows the whole Oasis pipeline working end to end, financial
terms included; its figures are not a view of real windstorm risk.

Up to 100 places and 1 to 100 samples a run. Places outside the grid come
back `unmodeled`, not refused, and a schedule with no place inside answers
at once with no loss figure.

## The terms

`terms` is optional. Leave it out and the run is ground-up only, exactly as
before. Every field inside is optional too:

```json
{"model": "oasis-piwind",
 "samples": 10,
 "terms": {
   "policy": {"place_deductible": 10000, "place_limit": 750000,
              "account_deductible": 25000, "account_limit": 1000000},
   "reinsurance": {"quota_share": {"ceded_share": 0.3},
                   "layers": [{"attachment": 100000, "limit": 150000},
                              {"attachment": 250000, "limit": 400000,
                               "placed_share": 0.8}]}},
 "exposure": {"points": [
   {"lat": 52.767, "lon": -0.895, "value": 250000},
   {"lat": 52.74, "lon": -0.86, "value": 1000000},
   {"lat": 25.76, "lon": -80.19, "value": 500000}]}}
```

| Field | What it is | Default |
|---|---|---|
| `policy.place_deductible` | Deducted from each place's building loss | 0 |
| `policy.place_limit` | The most paid for one place, after its deductible | none |
| `policy.account_deductible` | Deducted from the sum over places, after the place terms | 0 |
| `policy.account_limit` | The most paid for the whole account, after its deductible | none |
| `policy.account_share` | The share of the account this insurer writes | 1 (all of it) |
| `reinsurance.quota_share.ceded_share` | The share of every insured loss ceded to reinsurers | none |
| `reinsurance.layers[].attachment` | Where a catastrophe layer starts, for one event | required |
| `reinsurance.layers[].limit` | The most a layer pays for one event | required |
| `reinsurance.layers[].placed_share` | The share of a layer placed with reinsurers | 1 |

Amounts are in the unit of your values; nothing is converted. A deductible
or an attachment is 0 or more, a limit is above 0 (`null` for no limit on a
policy limit), and a share is above 0 and at most 1 (0.3 is 30%). Every
amount is at most 1,000,000,000,000. `reinsurance` needs a quota share or
at least one layer; there are at most three layers, listed from the lowest
up, each starting at or above the top of the one before (its attachment
plus its limit). `GET /models` publishes the fields, labels and caps under
the lane's `terms`. A run with terms takes two to three minutes, and it runs
only on the lab's model machines: if none can be reached, it fails with the
reason rather than falling back to the lab's own small host.

The steps apply in this order, to every sample of every event:

1. each place's deductible, then its limit;
2. the account's deductible, limit and share, on the sum over places: this
   is the **insured** loss;
3. the quota share cedes its share of the insured loss;
4. the layers, each event on its own, on what the insurer keeps after the
   quota share: each pays the part above its attachment, up to its limit,
   times its placed share. What is left is the loss **net of
   reinsurance**.

## What comes back

- `result.metrics` stays the ground-up block, with every field it had.
- `result.perspectives.il` (insured) and `result.perspectives.ri` (net of
  reinsurance, when reinsurance is given) are full metrics blocks with the
  same fields, marked by `perspective`: average annual loss, standard
  deviation and standard error, OEP and AEP to 1 in 100, TVaR, each place's
  share, the largest events, and the year and event loss tables.
- `result.terms_summary` says where the ground-up average annual loss goes:
  a sentence (`text`) and its parts (`split`).

Per-place insured and net figures are Oasis's own: it shares account and
reinsurance amounts back to the places in proportion to each place's loss
at the step before, so the places add up to the total.

## A worked example

The spec above: two places inside the grid and one in Miami, which PiWind
does not cover, 10 samples. Figures in the unit of the values.

| | Ground-up | Insured | Net |
|---|---|---|---|
| Average annual loss | 53,155 | 42,095 | 15,167 |
| Standard deviation | 163,912 | 142,816 | 39,801 |
| 1 in 10, OEP | 149,798 | 110,336 | 77,235 |
| 1 in 100, OEP | 805,844 | 759,461 | 156,325 |
| 1 in 100, AEP | 868,679 | 798,006 | 174,864 |
| First place (250,000), AAL | 17,029 | 11,713 | 4,947 |
| Second place (1,000,000), AAL | 36,126 | 30,382 | 10,220 |

Of the ground-up average annual loss of 53,155, the policyholder keeps
21%, reinsurers take 51% and the insurer keeps 28%. The layers flatten the
net tail: the 1-in-100 net OEP is 156,325 against 759,461 insured.

Each step on its own, on the same schedule:

| Terms | Insured AAL | Net AAL | Net 1 in 100, OEP |
|---|---|---|---|
| `terms: {}` (every default) | 53,155 | | |
| The place and account terms above | 42,095 | | |
| Those, and the 30% quota share | 42,095 | 29,466 | 531,623 |
| Those, and the two layers without the quota share | 42,095 | 20,439 | 289,461 |
| All of it | 42,095 | 15,167 | 156,325 |

With every term at its default the insured loss is the ground-up loss,
figure for figure.

The ground-up block of this run is byte for byte the ground-up block of the
same spec without terms: terms never change the simulated losses, only
what is read from them.

## How the terms become OED

The runner writes the terms as Open Exposure Data files (OED 5.0.0),
checks all of them with the `ods_tools` validator before Oasis starts, and
passes them to `oasislmf model run` as the location, account, reinsurance
info and reinsurance scope files:

| Terms | OED |
|---|---|
| `place_deductible`, `place_limit` | Location file: `LocDed1Building`, `LocLimit1Building` (type 0, an amount; `LocPeril` WW1) |
| `account_deductible`, `account_limit`, `account_share` | Account file, one policy with one layer: `LayerAttachment`, `LayerLimit`, `LayerParticipation` |
| `quota_share.ceded_share` | Reinsurance info: `ReinsType` QS, `CededPercent`, `InuringPriority` 1 |
| `layers[]` | Reinsurance info: `ReinsType` CXL, one `ReinsLayerNumber` each, `OccAttachment`, `OccLimit`, `PlacedPercent`, `InuringPriority` 2 (1 without a quota share) |
| Scope | Reinsurance scope: every contract covers the one account |

OED writes "no limit" as 0, so a `null` limit becomes 0 there. Every file
carries the location file's currency code, so Oasis converts nothing.

## What it leaves out

- Terms for contents, other structures and business interruption: PiWind
  values are buildings only.
- Percentage, minimum and maximum deductibles, sublimits, step policies,
  and more than one policy or layer on the account.
- Per-risk treaties (a surplus share or per-risk excess of loss by place),
  aggregate layer limits, reinstatements and reinsurance premium: a layer
  pays in full for every event.
- More than one account, or reinsurance scoped to part of it.

## Checked against Oasis itself

PiWind ships an example portfolio beside its location file: ten places, one
account with policy layers at a 30% participation, and a surplus share. Run
straight through `oasislmf model run`, with the example's identifiers renamed
to the ones the lab writes (Oasis seeds its sampling from them), its
ground-up and insured figures are identical, field for field, to the lab's run
of the same places with an account deductible of 500,000, a limit of
5,000,000 and a share of 0.3: an insured average annual loss of 36,069.70 both
ways. With a quota share and two layers written by hand in PiWind's own
reinsurance format, the net figures are identical too. The surplus share
itself is a per-risk treaty, which this lane does not take. On one place, for
every event and every sample, the insured loss is the ground-up loss less the
deductible, capped at the limit, and the net loss is what the quota share and
the layer leave of it, to within 0.02; insured never exceeds ground-up, and
net never exceeds insured.

## Replaying a result

Run ids are content addresses over the spec, the model version and the
pinned inputs, so the same spec with the same terms is the same id, and the
terms are part of it: the same places with and without terms are two runs.
A spec that leaves a field at its default and one that writes the default
out are one run. Documents stored under `oasislmf-2.5.7-r2` and earlier
keep answering their own ids.
