MRIO File Specification for DisruptSC¶
This document specifies how to build the mrio.csv file consumed by the DisruptSC model. It is intended for both human and AI readers.
Overview¶
The MRIO (Multi-Regional Input-Output) table describes monetary flows between economic sectors across regions. In DisruptSC, it serves three purposes:
- Firm creation: Each (region, sector) pair in the intermediary matrix becomes a firm agent.
- Supply chain construction: Technical coefficients derived from the intermediary matrix determine supplier-buyer relationships.
- External trade: Import rows and Export columns define how external trade partners (Country agents) interact with domestic firms.
Architecture: Internal vs External Regions¶
The MRIO distinguishes two types of regions:
- Internal regions: Fully modeled with firms, households, and transport networks. They appear in the intermediary matrix (both rows and columns) and in final_demand columns.
- External regions (countries/trade blocs): Modeled as Country agents that import from and export to internal firms. They appear only in Imports rows and Exports columns.
This separation is fundamental. A region cannot be both internal and external.
CSV Structure¶
The file is read with pd.read_csv(filepath, header=[0, 1], index_col=[0, 1]), producing a DataFrame with 2-level MultiIndex for both rows and columns.
Header (first 2 rows of CSV)¶
row 1 (level 0): region codes → ARE, ARE, ..., SAU, SAU, ..., IND, EUR, ..., ARE, SAU, ...
row 2 (level 1): sector names → Agriculture, Construction, ..., Agriculture, ..., Exports, Exports, ..., final_demand, final_demand, ...
Index (first 2 columns of CSV)¶
col 1 (level 0): region codes → ARE, ARE, ..., SAU, ..., IND, EUR, ...
col 2 (level 1): sector names → Agriculture, Construction, ..., ..., Imports, Imports, ...
Matrix Layout¶
┌─────────────────────────┬──────────────┬────────────────┐
│ Internal Sectors │ Exports │ final_demand │
│ (region, sector) cols │ (ext, Exp) │ (int, fd) │
┌─────────────────────────┼─────────────────────────┼──────────────┼────────────────┤
│ Internal Sectors │ │ │ │
│ (region, sector) rows │ INTERMEDIARY MATRIX │ EXPORT cols │ FINAL DEMAND │
│ │ (must be square) │ │ │
├─────────────────────────┼─────────────────────────┼──────────────┼────────────────┤
│ Imports │ │ │ │
│ (ext_region, Imports) │ IMPORT ROWS │ TRANSIT │ (ignored) │
├─────────────────────────┼─────────────────────────┼──────────────┼────────────────┤
│ value_added (optional) │ VALUE ADDED │ │ │
├─────────────────────────┼─────────────────────────┼──────────────┼────────────────┤
│ tax (optional) │ TAX │ │ │
└─────────────────────────┴─────────────────────────┴──────────────┴────────────────┘
Label Detection (Critical)¶
The model auto-detects special row/column labels using case-insensitive regex on the level-1 index/column values. The first match is used.
| Label | Axis | Regex Pattern | Typical Value |
|---|---|---|---|
export_label |
columns (axis=1) | export |
Exports |
final_demand_label |
columns (axis=1) | final.?demand |
final_demand |
capital_label |
columns (axis=1) | capital |
capital |
import_label |
rows (axis=0) | import |
Imports |
value_added_label |
rows (axis=0) | value.?added\|va |
value_added |
tax_label |
rows (axis=0) | tax |
tax |
Naming Pitfalls¶
Because regex matching is greedy and case-insensitive, sector names must not accidentally match these patterns:
| Problematic Name | Matches | Fix |
|---|---|---|
Re-export & Re-import |
matches export AND import |
Rename to Others |
Private Households |
matches va (in "Pri**va**te") |
Rename to Households |
Taxes on products |
matches tax |
Rename to Product levies |
Value chains |
matches value.?added\|va |
Rename to Supply chains |
Excavation |
matches va |
Safe (the va pattern requires word boundary in practice, but be cautious) |
Rule of thumb: No sector name should contain the substrings export, import, tax, va, capital, or final demand (case-insensitive).
Missing Labels¶
| Label | If Missing | Impact |
|---|---|---|
Exports |
external_buying_countries = [] |
No Country agents created as buyers. Model may still run if there are selling countries. |
final_demand |
region_households = [] |
No household demand. Model will fail. |
Imports |
external_selling_countries = [] |
No Country agents created as sellers. |
value_added |
Defaults to 20% margin for all industries | Acceptable approximation. |
tax |
Ignored | No impact. |
capital |
Ignored | No impact. |
Required Sections¶
1. Intermediary Matrix (required)¶
- Rows:
(internal_region, sector)tuples - Columns: Same
(internal_region, sector)tuples, in the same order - Must be square: The set of (region, sector) pairs in rows must exactly equal the set in columns
- Values: Monetary flows in the unit specified by
monetary_units_in_datain the YAML config (typicallymUSDorUSDper year) - No negative values
2. Final Demand Columns (required)¶
- Column level-0: Internal region code (one per internal region)
- Column level-1: Must match the
final_demandregex (usefinal_demand) - Rows: Same as intermediary matrix rows
- Values: Household consumption per (region, sector)
3. Export Columns (required for external trade)¶
- Column level-0: External region/bloc code (e.g.,
EUR,CHN,AFR) - Column level-1: Must match the
exportregex (useExports) - Rows: Same as intermediary matrix rows
- Values: Total exports from each internal (region, sector) to each external bloc
- These define
external_buying_countries: Each unique level-0 value in Export columns becomes a Country agent that buys from internal firms
4. Import Rows (required for external trade)¶
- Row level-0: External region/bloc code (must match the ones used in Export columns if the same bloc both sells and buys)
- Row level-1: Must match the
importregex (useImports) - Columns: Same as intermediary matrix columns
- Values: Total imports from each external bloc to each internal (region, sector)
- These define
external_selling_countries: Each unique level-0 value in Import rows becomes a Country agent that sells to internal firms
5. Transit Submatrix (derived)¶
- Located at the intersection of Import rows and Export columns
- Represents goods that pass through the modeled region (imported then re-exported)
- Can be zero if transit trade is not relevant
6. Value Added Row (optional)¶
- Row level-0: Empty string or
NaN - Row level-1: Must match
value.?added|va(usevalue_added) - Values: Value added per (region, sector)
- Used to compute profit margins (value_added / total_output)
- If missing: all industries default to 20% margin
7. Tax Row (optional)¶
- Same structure as value_added
- Currently unused by the model
Minimal Working Example¶
A minimal MRIO with 2 internal regions (A, B), 2 sectors (Agri, Mfg), and 1 external bloc (EXT):
,,A,A,B,B,EXT,A,B
,,Agri,Mfg,Agri,Mfg,Exports,final_demand,final_demand
A,Agri,10,20,5,3,8,50,2
A,Mfg,5,15,2,10,12,30,5
B,Agri,3,1,8,15,4,1,40
B,Mfg,2,8,6,12,6,3,25
EXT,Imports,7,4,3,2,0,0,0
This produces: - 4 firms: A_Agri, A_Mfg, B_Agri, B_Mfg - 2 households: A, B (from final_demand) - 1 country: EXT (appears in both Exports and Imports)
Building from Eora26¶
When extracting from the Eora26 MRIO database (190 countries, 26 sectors):
Step 1: Define internal and external regions¶
INTERNAL = ['ARE', 'SAU', 'QAT', 'KWT', 'BHR', 'OMN', 'IRQ']
EXTERNAL = ['IND', 'PAK', 'EAS', 'EUR', 'AFR', 'ROW']
Some external blocs may be aggregations of multiple Eora countries (e.g., EUR = all EU countries, EAS = East/Southeast Asian countries, AFR = African countries).
Step 2: Extract the intermediary matrix¶
Select only rows and columns where both region and sector belong to internal regions. Exclude Eora's special sectors:
- Private Households (rename to Households or exclude)
- Re-export & Re-import (rename to Others or exclude)
- Others (can be kept or excluded)
Step 3: Build final_demand columns¶
For each internal region, sum the household/final demand columns from Eora.
Step 4: Build Exports columns¶
For each external bloc, sum ALL purchases by that bloc from internal sectors: - Sum across all sectors of the external bloc in the original Eora intermediary - Optionally include the external bloc's final demand from internal sectors
This gives one Exports column per external bloc.
Step 5: Build Imports rows¶
For each external bloc, sum ALL sales by that bloc to internal sectors: - Sum across all sectors of the external bloc in the original Eora intermediary
This gives one Imports row per external bloc.
Step 6: Rename problematic sectors¶
Apply the renaming rules from the "Naming Pitfalls" section above.
Step 7: Validate¶
- Intermediary matrix is square
- No negative values
- Row sums (total output) approximately equal column sums (total input) for each (region, sector)
- No sector name accidentally matches the regex patterns
Companion Files¶
sector_table.csv¶
One row per (region, sector) pair that appears in the intermediary matrix.
Required columns:
- region_sector: String "{region}_{sector}" (e.g., ARE_Agriculture)
- sector: Sector name (e.g., Agriculture)
- type: Sector type, one of: agriculture, mining, manufacturing, transport, trade, service, utility, construction
- region: Region code (e.g., ARE)
- share_exporting_firms: Float 0-1, share of firms that export
- usd_per_ton: Float, monetary value per physical ton (used for logistics costing)
The sector to type mapping must be consistent across all regions (same sector name always maps to the same type).
usd_per_ton.csv¶
Required columns: region, sector, usd_per_ton
One row per (region, sector). Values represent the average USD value per metric ton of output for that sector in that region.
Configuration (YAML)¶
filepaths:
mrio: "Economic/mrio.csv"
sector_table: "Economic/sector_table.csv"
usd_per_ton: "Economic/usd_per_ton.csv"
monetary_units_in_data: "mUSD" # or "USD", "kUSD"
The monetary_units_in_data parameter tells the model what unit the MRIO values are in. Eora26 uses millions of USD (mUSD). The model internally converts to the appropriate time resolution.
Validation Checklist¶
- CSV loads correctly with
pd.read_csv(path, header=[0,1], index_col=[0,1]) - Intermediary matrix is square (same region-sectors in rows and columns)
- No sector name matches
export,import,va,tax,capital, orfinal.?demandpatterns -
Exportscolumn label detected correctly -
final_demandcolumn label detected correctly -
Importsrow label detected correctly - All values are non-negative
- Each Export column level-0 region has a matching entry in
countries.geojson - Each Import row level-0 region has a matching entry in
countries.geojson - Each internal region has a
final_demandcolumn -
monetary_units_in_datain YAML matches actual units in the CSV -
sector_table.csvcovers all (region, sector) pairs in the intermediary matrix -
usd_per_ton.csvcovers all (region, sector) pairs in the intermediary matrix