Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
build/
source/reference/_generated/
**/__pycache__/
.jupyter_cache/
jupyter_execute/
.DS_Store
13 changes: 13 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Minimal Sphinx makefile for the ORD reference site
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build

help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
134 changes: 134 additions & 0 deletions docs/source/_ext/gen_oed_reference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
"""Generate OED reference pages from ``oed.json`` (single source of truth).

The OED standard is defined by ``oed.json`` at the repo root — the same machine-readable
spec that ods-tools consumes. Rather than hand-maintain reference tables, this extension
reads ``oed.json`` at build time and writes MyST Markdown into ``reference/_generated/``
which the reference pages include. Edit ``oed.json`` (and its source CSVs), not the
generated Markdown.

Runs on the Sphinx ``config-inited`` event; also runnable standalone for quick checks.
"""
import json
import os

HERE = os.path.dirname(os.path.abspath(__file__))
REPO_ROOT = os.path.abspath(os.path.join(HERE, os.pardir, os.pardir, os.pardir))
OED_JSON = os.path.join(REPO_ROOT, "oed.json")
OUT_DIR = os.path.join(HERE, os.pardir, "reference", "_generated")

# input-file groups, in exposure-modelling order
FILE_ORDER = [("Loc", "Location"), ("Acc", "Account"),
("ReinsInfo", "Reinsurance Info"), ("ReinsScope", "Reinsurance Scope")]


def _cell(text):
return str(text).replace("|", "\\|").replace("\n", " ").replace("\r", " ").strip()


def _pipe_table(columns, rows):
out = ["| " + " | ".join(columns) + " |",
"| " + " | ".join(["---"] * len(columns)) + " |"]
for row in rows:
out.append("| " + " | ".join(_cell(c) for c in row) + " |")
return "\n".join(out)


def _write(name, text):
os.makedirs(OUT_DIR, exist_ok=True)
with open(os.path.join(OUT_DIR, name), "w", encoding="utf-8") as fh:
fh.write(text + "\n")


def generate_fields(oed):
"""input_fields -> field reference, grouped by input file."""
fields = oed["input_fields"]
parts = ["<!-- generated by _ext/gen_oed_reference.py from oed.json (input_fields) -->"]
total = 0
for key, title in FILE_ORDER:
recs = fields.get(key)
if not recs:
continue
parts.append(f"\n## {title} (`{key}`)\n")
rows = []
for rec in recs.values():
rows.append([
rec.get("Input Field Name", ""),
rec.get("Type & Description", ""),
rec.get("Data Type", ""),
rec.get("Property field status", ""),
rec.get("Default", ""),
])
total += 1
parts.append(_pipe_table(
["Field", "Description", "Data type", "Status", "Default"], rows))
_write("oed_fields.md", "\n".join(parts))
return total


def generate_values(oed):
"""Coded value lists -> code reference tables."""
parts = ["<!-- generated by _ext/gen_oed_reference.py from oed.json (value lists) -->"]
total = 0

# perils: nested under 'info'
perils = oed.get("perils", {}).get("info", {})
if perils:
parts.append("\n## Perils\n")
rows = [[code, r.get("DB table PerilCode", ""), r.get("Peril Description", ""),
r.get("Grouped PerilCode", "")] for code, r in perils.items()]
parts.append(_pipe_table(["Code", "PerilCode", "Description", "Grouped"], rows))
total += len(rows)

def simple(key, title, cols):
nonlocal total
v = oed.get(key)
if not isinstance(v, dict):
return
parts.append(f"\n## {title}\n")
rows = [[code] + [rec.get(c, "") for _, c in cols] for code, rec in v.items()]
parts.append(_pipe_table(["Code"] + [h for h, _ in cols], rows))
total += len(rows)

simple("occupancy", "Occupancy codes",
[("Name", "Name"), ("Description", "Description"), ("Broad Category", "Broad Category")])
simple("construction", "Construction codes",
[("Name", "Name"), ("Description", "Description"), ("Broad Category", "Broad Category")])
simple("country", "Country codes", [("Name", "Name")])
simple("CoverageValues", "Coverage types",
[("CoverageID", "CoverageID"), ("Description", "Description"), ("Type", "Type")])
_write("oed_values.md", "\n".join(parts))
return total


def _ensure_oed_json():
"""oed.json is a generated artifact (utils/gen-json.py builds it from the CSVs) and is not
committed. Generate it if missing so the docs build is self-sufficient in CI."""
if os.path.exists(OED_JSON):
return
import subprocess
import sys
gen = os.path.join(REPO_ROOT, "utils", "gen-json.py")
subprocess.run([sys.executable, gen, "--output-path", OED_JSON], cwd=REPO_ROOT, check=True)


def run(app=None, config=None):
_ensure_oed_json()
with open(OED_JSON, encoding="utf-8") as fh:
oed = json.load(fh)
n_fields = generate_fields(oed)
n_values = generate_values(oed)
msg = f"[gen_oed_reference] wrote {n_fields} fields, {n_values} coded values -> reference/_generated/"
if app is not None:
from sphinx.util import logging
logging.getLogger(__name__).info(msg)
else:
print(msg)


def setup(app):
app.connect("config-inited", run)
return {"parallel_read_safe": True, "parallel_write_safe": True}


if __name__ == "__main__":
run()
Binary file added docs/source/_static/OASIS_LMF_COLOUR.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/_static/OASIS_LMF_WHITE.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
77 changes: 77 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""Sphinx configuration for the Open Exposure Data (OED) standard reference site.

The field and coded-value reference is generated at build time from ``oed.json`` by the
local ``gen_oed_reference`` extension (single source of truth). Theme and MyST setup mirror
the other OasisLMF documentation sites for a consistent aggregated site.
"""
import datetime
import os
import sys

sys.path.insert(0, os.path.abspath("_ext"))

project = "Open Exposure Data (OED)"
author = "Oasis LMF"
copyright = f"{datetime.date.today().year} Oasis LMF"

extensions = [
"myst_parser",
"sphinx_design",
"sphinx_copybutton",
"gen_oed_reference", # build-time reference generation from oed.json
]

source_suffix = {".rst": "restructuredtext", ".md": "markdown"}
master_doc = "index"
language = "en"
# _generated/*.md are include-only fragments, not standalone documents
exclude_patterns = ["reference/_generated/**"]

myst_enable_extensions = ["colon_fence", "deflist", "substitution", "tasklist"]
myst_heading_anchors = 6

html_theme = "furo"
html_title = "Open Exposure Data (OED)"
html_static_path = ["_static"] if os.path.isdir(os.path.join(os.path.dirname(__file__), "_static")) else []


# -- Cross-component links (intersphinx, aggregated site) --------------------
# The GenerateDocs orchestrator sets OASIS_INTERSPHINX_MAP (JSON) to point cross-references at
# the other components' built inventories; standalone builds add nothing. Use explicit roles,
# e.g. {external+ord:doc}`reference/tables` or :external+oed:ref:`some-label`.
import json as _ix_json
import os as _ix_os
if "sphinx.ext.intersphinx" not in extensions:
extensions = list(extensions) + ["sphinx.ext.intersphinx"]
try:
intersphinx_mapping
except NameError:
intersphinx_mapping = {}
intersphinx_mapping.update({
_k: (_v[0], _v[1])
for _k, _v in _ix_json.loads(_ix_os.environ.get("OASIS_INTERSPHINX_MAP") or "{}").items()
})
# -- Oasis shared branding (logo, palette, GitHub footer) -------------------
if globals().get("html_theme") == "furo":
if "_static" not in (globals().get("html_static_path") or []):
html_static_path = list(globals().get("html_static_path") or []) + ["_static"]
try:
html_theme_options
except NameError:
html_theme_options = {}
html_theme_options.setdefault("light_logo", "OASIS_LMF_COLOUR.png")
html_theme_options.setdefault("dark_logo", "OASIS_LMF_WHITE.png")
_lcv = html_theme_options.setdefault("light_css_variables", {})
_lcv.setdefault("color-brand-primary", "#862633")
_lcv.setdefault("color-brand-content", "#d22630")
_lcv.setdefault("font-stack", "Raleway, sans-serif")
_dcv = html_theme_options.setdefault("dark_css_variables", {})
_dcv.setdefault("color-brand-primary", "#e2919b")
_dcv.setdefault("color-brand-content", "#ef8b93")
# GitHub link — Furo's conventional spot is the footer icons (bottom of every page)
html_theme_options.setdefault("footer_icons", [{
"name": "GitHub", "url": "https://github.com/OasisLMF", "class": "",
"html": '<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path></svg>',
}])
if "https://fonts.googleapis.com/css?family=Raleway" not in (globals().get("html_css_files") or []):
html_css_files = list(globals().get("html_css_files") or []) + ["https://fonts.googleapis.com/css?family=Raleway"]
113 changes: 113 additions & 0 deletions docs/source/explanation/asset-details.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
Asset Related Details
======================

The following sections describe the OED specification for the asset value, usage, construction, and other modifiers that can influence the susceptibility of an asset to damage from a peril.
Coverage total insurable value (TIV)

Total insurable value (TIV) for each property is captured in four location level fields:

• **BuildingTIV**: The total insurable value of the buildings.

• **ContentsTIV**: The total insurance value of contents and stock.

• **BITIV**: The total business interruption, or other time related, total insurable value.

• **OtherTIV**: The total insurable value for elements other than the main building / contents / time elements. Typically used to represent the TIV for outbuildings / ap

Total insurable value is not peril dependent. The currency of the TIV is specified in the **LocCurrency** field.

|

Occupancy Type
##############

Occupancy codes are stored in the **OccupancyCode** field. The occupancy type list is predominantly a one to one mapping from the AIR CEDE occupancy codes, although some extra codes have been added. The broad categories of code and the number ranges are shown in the table below.


.. csv-table::
:widths: 10,10
:header: "OED Occupancy Code Range", "Broad Category of Occupancy"

"1000", "Unknown"
"1050 – 1099", "Residential"
"1100 – 1149", "Commercial"
"1150 – 1199", "Industrial"
"1200 – 1249", "Religion / Government / Education"
"1250 – 1299", "Transportation"
"1300 – 1349", "Utilities"
"1350 – 1399", "Miscellaneous"
"2000 – 2799", "Industrial Facility"
"3000 – 3999", "Offshore"

Although the code ranges above infer an extremely long list of codes there are less than 200 distinct occupancy codes in total. Yachts and automobiles are included under construction type codes rather than occupancy codes.
Some users may have translated from a different (original) occupancy code to the OED occupancy code but would like to store the original occupancy code information. This can be done using the **OrgOccupancyScheme** and **OrgOccupancyCode** fields.

|

Construction Type
##################

Construction codes are stored in the **ConstructionCode** field. The construction type list is predominantly a one to one mapping from the AIR CEDE construction codes, although some extra codes have been added. The broad categories of code and the number ranges are shown in table below.


.. csv-table::
:widths: 10,10
:header: "OED Construction Code Range", "Broad Category of Construction"

"5000", "Unknown"
"5050 – 5099", "Wood"
"5100 – 5149", "Masonry"
"5150 – 5199", "Concrete"
"5200 – 5249", "Steel"
"5250 – 5299", "Composite"
"5300 – 5349", "Special"
"5350 – 5399", "Mobile Homes"
"5400 – 5449", "Bridges"
"5450 – 5499", "Roads, Railroads, Runways"
"5500 – 5549", "Dams"
"5550 – 5599", "Tunnels"
"5600 – 5649", "Storage Tanks"
"5650 – 5699", "Pipelines"
"5700 – 5749", "Chimneys"
"5750 – 5799", "Towers"
"5800 – 5849", "Equipment"
"5850 – 5899", "Automobiles"
"5900 – 5949", "Yachts"
"5950 – 5999", "Miscellaneous"
"6000 – 6099", "Marine Cargo General"
"6100 – 6149", "Marine Cargo Combustible"
"6150 – 6199", "Marine Cargo Non-Combustible"
"7000 - 7999", "Offshore"

|

Although the code ranges above infer a very long list of codes there are less than 200 construction codes in total.
Some users may have translated from a different (original) construction code scheme to the OED construction code scheme but would like to store the original construction code information. This can be done using the **OrgConstructionScheme** and **OrgConstructionCode** fields.

|

Other Common Modifiers
######################

While different catastrophe models will use different modifiers to adjust the vulnerability of an asset, the following are the most commonly used modifiers:

• **YearBuilt**: the year the building was built. **YearUpgraded**, **RoofYearBuil** are also modifiers that allow the user to add additional information.

• **NumberOfStoreys**: The total number of storeys in a building. **BuildingHeight** is also available for the user to add in the precise height of the building if this is known. **FloorsOccupied** allows the specific floors in the building that are occupied to be specified.

• **NumberOfBuildings**: The number of buildings represented by this location. This is commonly used to indicate the presence of aggregated data. If, instead, a user has specific details about different locations, but wants to denote a linkage of some kind between each location then the **LocGroup** field can be used to link individual locations (either for reporting purposes or to define a reinsurance ‘risk’ level). **CorrelationGroup** can be used to denote a correlation in secondary uncertainty between groups of locations.

• **FloorArea** & **FloorAreaUnit**: The total floor area occupied, summing the area of multiple floors.

Other modifiers, either peril specific or less commonly used by models, are available and are listed in the specification spreadsheet. They can be identified by filtering on the SecMod column in the ‘OED Input Fields’ sheet in the specification spreadsheet.

|

Flexi-tables
############

Despite the wide range of fields available in OED, there is always the possibility that a user needs to enter or store information without a corresponding OED field. This can be achieved through the flexi-table functionality within OED, which essentially provides a key-value pair back end table at the main hierarchical levels.
To enter additional field / values, a user can enter additional columns: **FlexiLocZZZ**, **FlexPolZZZ**, **FlexiAccZZZ**, where ‘ZZZ’ contains the name of the new field.
For example, if a user wants to store information on house colour, they could add an additional column to the location input file with the fieldname *FlexiLocHouseColour*.


Loading
Loading