Skip to content

Single-sector default, heterogeneous CES epsilon, and UK-calibrated structural parameters#66

Open
vahid-ahmadi wants to merge 6 commits intomainfrom
feature/single-sector-default-and-het-epsilon
Open

Single-sector default, heterogeneous CES epsilon, and UK-calibrated structural parameters#66
vahid-ahmadi wants to merge 6 commits intomainfrom
feature/single-sector-default-and-het-epsilon

Conversation

@vahid-ahmadi
Copy link
Copy Markdown
Collaborator

@vahid-ahmadi vahid-ahmadi commented Mar 31, 2026

Summary

  • Default to M=1 (single sector): The 8-sector industry calibration is now opt-in via multi_sector=True on solve_steady_state() / run_transition_path(), or multi-sector CLI flag. This makes the default run faster and matches OG-Core's built-in M=1 defaults.
  • Enable heterogeneous CES epsilon in multi-sector mode: Uses calibrated literature values (Chirinko 2008, Knoblach et al. 2020) ranging from 0.40 (Real Estate) to 1.30 (Business Services), instead of forcing all sectors to Cobb-Douglas (ε=1.0).
  • Recalibrate TFP (Z) for CES: Solow residuals now use the CES production function when ε≠1, ensuring Z values are consistent with the production technology.
  • UK-calibrated structural parameters with sources:
Parameter Old New Source
frisch 0.4 0.35 Blundell, MaCurdy & Meghir (1999)
g_y_annual 0.01 0.011 OBR EFO Nov 2025, Table 1.1
delta_annual 0.05 0.065 ONS Capital stocks & fixed capital consumption (CAPSTK)
beta_annual 0.96 0.965 ONS Households saving ratio (NRJS)
world_int_rate_annual 0.0175 0.02 Bank of England yield curve data
  • Sector-specific depreciation rates (multi-sector mode): Tax depreciation (delta_tau_annual) now varies by sector using ONS CAPSTK data, from 3% (Real Estate — long-lived structures) to 10% (Info & Finance — IT equipment).

Usage

# Single sector (default, fast)
uv run python examples/run_oguk.py ss pooled
uv run python examples/run_oguk.py tpi

# 8-sector with heterogeneous CES
uv run python examples/run_oguk.py ss pooled multi-sector
uv run python examples/run_oguk.py tpi multi-sector

Dependencies

Depends on PSLmodels/OG-Core#1096 (numerical guards for CES production functions, merged 2026-04-13), first available in OG-Core 0.15.6. The ogcore floor in pyproject.toml has been bumped to >=0.15.6 accordingly.

Test plan

  • 8-sector SS with heterogeneous epsilon converges (resource constraint ~1e-6)
  • Unit tests pass with updated parameter values
  • Single-sector SS/TPI produces same results as before this PR
  • 8-sector TPI with heterogeneous epsilon converges (requires OG-Core#1096, included in ogcore>=0.15.6)

🤖 Generated with Claude Code

vahid-ahmadi and others added 3 commits March 31, 2026 13:37
Two changes:

1. Make single-sector (M=1) the default run mode. The 8-sector industry
   calibration is now opt-in via `multi_sector=True` parameter on
   solve_steady_state() and run_transition_path(), or via the
   `multi-sector` CLI flag:
     uv run python examples/run_oguk.py ss pooled              # M=1
     uv run python examples/run_oguk.py ss pooled multi-sector # M=8

2. Enable calibrated heterogeneous CES elasticities (epsilon) in the
   8-sector mode. Previously forced to 1.0 (Cobb-Douglas) for all
   sectors due to solver NaN issues — now uses literature values from
   Chirinko (2008) and Knoblach et al. (2020):
     Energy=0.50, Construction=0.70, Trade & Transport=1.00,
     Info & Finance=1.20, Real Estate=0.40, Business Services=1.30,
     Public & Other=0.90, Manufacturing=0.80

   Supporting changes:
   - Recalibrate TFP (Z) using CES Solow residuals instead of
     Cobb-Douglas residuals when epsilon != 1
   - Use hybr root-finder (Powell hybrid) instead of LM for
     multi-sector SS — LM gets stuck at ~1e-5 residuals
   - Relax mindist_SS and RC_SS to 1e-4 for multi-sector

   Requires OG-Core PR PSLmodels/OG-Core#1096 (numerical guards for
   CES production functions).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update default parameters from generic macro literature values to
UK-specific estimates: delta_annual 0.05→0.065 (ONS CAPSTK),
g_y_annual 0.01→0.011 (OBR EFO), frisch 0.4→0.35 (Blundell et al.),
beta_annual 0.96→0.965 (ONS savings ratio), world_int_rate 0.0175→0.02
(BoE gilt yields). Add sector-specific depreciation rates for 8-sector
mode from ONS capital consumption data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vahid-ahmadi vahid-ahmadi changed the title Default to single sector and enable heterogeneous CES epsilon Single-sector default, heterogeneous CES epsilon, and UK-calibrated structural parameters Mar 31, 2026
@vahid-ahmadi
Copy link
Copy Markdown
Collaborator Author

vahid-ahmadi commented Mar 31, 2026

Future improvement suggestions

Calibration

1. Open-economy parameters (zeta_D, zeta_K)

Currently at defaults (zeta_D=0.4, zeta_K=0.1). The UK runs a persistent current account deficit (~3-4% of GDP) and foreign investors hold ~30% of gilts. These should be calibrated from:

2. Government spending composition (alpha_G)

Currently auto-calibrated as a fiscal residual in SS. OBR publishes detailed departmental spending breakdowns that could anchor this, especially in multi-sector mode where government demand varies across sectors:

3. Immigration age profile

We use UN World Population Prospects data, which is smoothed. ONS publishes UK-specific immigration data by single year of age that captures the sharp peak at ages 18-25:

4. UK wealth distribution (lambdas and e)

The current J=7 ability types use US-derived earnings-by-age profiles. Re-estimating from UK data would improve distributional results:

5. Sector-specific effective corporate tax rates

Currently a flat 27% CIT across all 8 sectors. Effective rates vary in the UK (e.g. North Sea oil has a supplementary charge, R&D-intensive sectors get enhanced capital allowances):

Performance

6. Parallel calibration

The 3 budget-window years in calibrate() are estimated sequentially but are independent. Could run in parallel with concurrent.futures.ProcessPoolExecutor to cut calibration time by ~60%.

OG-Core PR #1096 (numerical guards for CES with heterogeneous epsilon)
merged 2026-04-13 and first shipped in ogcore 0.15.6. The heterogeneous
CES epsilon path in multi-sector mode can produce NaN with earlier
versions when inputs are near zero, so raise the floor accordingly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jdebacker
Copy link
Copy Markdown
Member

@vahid-ahmadi The code changes look good. We just need the unit test failure fixed.

Also, let's bump the version to 0.3.2, please.

Raise floors on numpy, scipy, and pygam so uv does not resolve
scipy==1.11.4/numpy==1.26.4 transitively on Python 3.13 (no cp313
wheels exist, which triggered a source build and mesonpy failure in CI).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
policyengine 4.3.0 ships with a data release manifest pinned to
policyengine-uk==2.88.0. Any newer policyengine-uk (e.g. 2.88.9) has
no published manifest, so import of policyengine.core raises
DataReleaseManifestUnavailableError and pytest collection fails.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants