Skip to content

Bridge USD and EUR across all vintages at a chosen exchange-rate period - #64

Open
Wegatriespython wants to merge 3 commits into
IAMconsortium:mainfrom
Wegatriespython:feat/deflator-update
Open

Bridge USD and EUR across all vintages at a chosen exchange-rate period#64
Wegatriespython wants to merge 3 commits into
IAMconsortium:mainfrom
Wegatriespython:feat/deflator-update

Conversation

@Wegatriespython

@Wegatriespython Wegatriespython commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

This makes a configured currency bridge usable across all deflator vintages rather than only the one it was configured at, and adds the deflator data needed to reach recent years. Follow-up to #61; continues #25. The bridge-year interpretation follows @khaeru's proposal discussed in iiasa/sparccle-workflow#19.

configure_currency(method, period) previously redefined only the {currency}_{period} unit in terms of USD. Because each vintage is defined relative to its own anchor (EUR_2005, USD_2005), redefining a single non-anchor vintage detached it from the rest of the chain: configure_currency("EXC", 2010) could convert USD_2010EUR_2010 but raised DimensionalityError for EUR_2024. Only period=2005 worked, because there the redefined unit is the anchor.

This PR reinterprets period as the exchange-rate bridge year only:

USD_y --(USD deflator)--> USD_period --(exchange rate @ period)--> EUR_period --(EUR deflator)--> EUR_z
  • configure_currency() anchors the bridge at the target currency's chain anchor ({currency}_2005), scaled by the deflator factor between period and 2005, so the whole vintage chain stays connected. period=2005 results are unchanged.
  • A registry holds one bridge per target currency: re-running with the same (method, period) is a no-op; changing either raises ValueError rather than silently re-anchoring earlier conversions.
  • Adds USD_2023, USD_2024 and EUR_2015 to definitions.txt.

To write that bridge, the EUR deflator factors are now named in definitions.txt : _EUR_deflator_2010 = 0.901141, with EUR_2010 = _EUR_deflator_2010 * EUR_2005 as before, so configure_currency() can define the bridge as a plain pint expression, EUR_2005 = USD_2010 / 0.754309 / _EUR_deflator_2010, and let pint do the arithmetic. The factors follow the underscore prefix as _gwp, since they are not units. DEVELOPING.rst records that a new period or currency now needs a matching factor and chain anchor added by hand.

Data sourcing: the USD factors are each year's World Bank US GDP deflator (NY.GDP.DEFL.ZS, series last updated 2026-07-13) divided by the 2015 reference value and rounded to 4 decimals, following the existing 2000–2022 entries; EUR_2015 uses the euro-area series (NY.GDP.DEFL.KD.ZG, aggregate XC), taken from the 2026-04-08 vintage.

Adds test_currency_bridge covering every supported period and every defined EUR vintage.

@codecov-commenter

codecov-commenter commented Jun 8, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.72%. Comparing base (3b78494) to head (cf9cb50).

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #64      +/-   ##
==========================================
+ Coverage   91.48%   91.72%   +0.23%     
==========================================
  Files           6        6              
  Lines         282      290       +8     
==========================================
+ Hits          258      266       +8     
  Misses         24       24              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@khaeru

khaeru commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Hi, thanks for a PR. Can you clarify whether you used LLMs in preparing this, and how?

@Wegatriespython

Copy link
Copy Markdown
Contributor Author

Hi, yes an LLM—Claude Code, was used to prepare this PR, upon request from the SPARCCLE workflow team to support alternate exchange rate periods (2024). When trying to use non-2005 periods, DimensonalityError came up.

I reviewed the code, however since I am not an expert on this repo, the review was high level.

@Wegatriespython

Copy link
Copy Markdown
Contributor Author

So I have force-pushed an update to slim down this PR, changes to updater have been cut out and deferred to a future PR. This PR is now only fixing the bridge bug plus adds data for USD_2023,USD_2024, EUR_2015) needed to use recent periods.

Hopefully this is in a more reviewable state now.

@byersiiasa

Copy link
Copy Markdown

Hi @khaeru - can we please get this merged or is there something blocking it?
We need it on SPARCCLE scenario explorer workflow so we can actually do analysis. Thanks

@Wegatriespython

Copy link
Copy Markdown
Contributor Author

Will rebase and reduce some tech debt with the cache workaround in a bit. WB also put out new values for US deflators, will rope those in as well.

USD_2023 and USD_2024 are from the World Bank US GDP deflator
(NY.GDP.DEFL.ZS, country USA; series last updated 2026-07-13): each
factor is the year's value divided by the 2015 reference value, rounded
to 4 decimals, following the existing 2000-2022 entries. Existing
factors are left unchanged, as in previous updates to this block, even
where the World Bank has since revised the underlying series.

EUR_2015 is from the euro-area GDP deflator (NY.GDP.DEFL.KD.ZG,
aggregate XC), using the running-product formula documented above the
block and the 2026-04-08 vintage of the series. That is the vintage the
existing EUR_2010, EUR_2020 and EUR_2024 factors come from, and it
reproduces all three to six decimals. Every EUR factor is a running
product from the common 2005 anchor, so taking one of them from a later
vintage would leave it inconsistent with the rest of the chain.
Previously configure_currency(method, period) redefined only the
{currency}_{period} unit in terms of USD. Because every vintage is
defined relative to its chain anchor ({currency}_2005), redefining a
single non-anchor vintage detached it from the rest of the chain:
configure_currency("EXC", 2010) converted USD_2010 to EUR_2010 but
raised DimensionalityError for EUR_2024. Only period=2005 worked fully,
because there the redefined unit is the anchor.

Reinterpret period as the exchange-rate bridge year only: anchor the
bridge at the target currency's chain base, scaled by that currency's
deflator factor between period and 2005, so the whole vintage chain
stays connected. Any USD_* vintage now converts to any defined EUR_*
vintage through the chosen period; period=2005 results are unchanged.

A registry holds one bridge per target currency: repeated calls with
the same (method, period) are a no-op, and changing either for an
already-bridged currency raises ValueError instead of silently
re-anchoring earlier conversions.

The deflator factors are named in definitions.txt so that the bridge can
be written as a plain pint expression. They are internal, and carry the
underscore prefix used for other internal units such as _gwp;
DEVELOPING.rst records that extending the supported periods or
currencies now means adding them by hand.
@Wegatriespython

Copy link
Copy Markdown
Contributor Author

Pushed the rebase on main with the following changes :

  1. The earlier cache workaround via registry._build_cache() is gone, it was there earlier because configure_currency() read the deflator factor by converting EUR_period to EUR_2005, which cached those units' pre-bridge dimensionality immediately before define() made it stale. With the factors now moved to definitions.txt, the bridge is a pint expression that pint resolves.
  2. USD_2023 and USD_2024 are refreshed to the current World Bank vintage, 1.2577 and 1.2889, replacing the 1.2431 and 1.2739 first pushed here.

@byersiiasa byersiiasa left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi - can we please merge it now or please have some quick feedback?

This is getting embarrassing for the project that it takes us 3 months to update currency conversion.

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.

4 participants