Summary
In the Python bindings, OREApp::getCube() and InputParameters::setCube() are declared with different spellings of the same type, so the cube returned by the getter cannot be passed to the setter:
TypeError: in method 'InputParameters_setCube', argument 2 of type
'QuantLib::ext::shared_ptr< ore::analytics::NPVCube > const &'
setMarketCube/getMarketCube are affected identically. This is a regression between v1.8.15.0 and v1.8.16.0, and it disables in-memory cube reuse from Python — running the XVA analytic postprocess-only on a previously simulated cube.
Root cause
The C++ is self-consistent — both sides use QuantLib::ext::shared_ptr:
OREAnalytics/orea/app/oreapp.hpp:78 — QuantLib::ext::shared_ptr<NPVCube> getCube(std::string cubeName);
OREAnalytics/orea/app/inputparameters.hpp:674 — void setCube(const QuantLib::ext::shared_ptr<NPVCube>& cube)
The SWIG interface qualifies only the setters:
ORE-SWIG/OREAnalytics-SWIG/SWIG/orea_app.i
355: void setCube(const QuantLib::ext::shared_ptr<ore::analytics::NPVCube>& file); // qualified
356: void setMarketCube(const QuantLib::ext::shared_ptr<ore::analytics::AggregationScenarioData>& file);
...
554: ext::shared_ptr<ore::analytics::NPVCube> getCube(std::string cubeName); // NOT qualified
557: ext::shared_ptr<ore::analytics::AggregationScenarioData> getMarketCube(std::string cubeName);
SWIG keys its type table on the literal spelling, so ext::shared_ptr<...> and QuantLib::ext::shared_ptr<...> are registered as two distinct types. The mismatch is visible in the proxy objects themselves:
returned by getCube : <ORE.NPVCube; proxy of <Swig Object of type 'ext::shared_ptr< ore::analytics::NPVCube > *'>>
expected by setCube : QuantLib::ext::shared_ptr< ore::analytics::NPVCube > const &
In v1.8.15.0 both sides read ext::shared_ptr<NPVCube> (lines 345/383) — consistent, and it works. The setters were qualified to match the C++ somewhere in v1.8.15.0..v1.8.16.0 (the change enters on the merge 85c8f7494, feature/QPR-13887) and the getters were not updated with them.
Suggested fix: add the QuantLib:: prefix to the two getter declarations at orea_app.i:554 and :557, so they match the setters and the C++.
Reproducer
Any run that produces a cube, then handing that cube back:
import ORE
app = ORE.OREApp(params, logfile, log_mask, True)
app.run(market_data, fixings) # analytics: NPV + EXPOSURE + XVA
cube = app.getCube(next(iter(app.getCubeNames())))
market_cube = app.getMarketCube(next(iter(app.getMarketCubeNames())))
p = ORE.InputParameters()
p.setCube(cube) # TypeError
p.setMarketCube(market_cube) # TypeError
Both calls raise on 1.8.16.0 and both succeed on 1.8.15.0.
Impact
The intended workflow is unreachable from Python. Reuse requires both cubes — XvaAnalyticImpl hard-requires the market cube ("XVA without EXPOSURE requires a market cube as input", xvaanalytic.cpp) — and there is no substitute for either:
- The market cube cannot be supplied as a file instead, because
AggregationScenarioData is not serialisable through the binding (the SWIG wrapper types the qualifier argument of has/get as an opaque bare string, so qualified entries are unreachable).
- It cannot be obtained from the engine either:
OREApp::run(loader) ends at // Leave any report writing to the calling aplication and writes no cubes; only the file-loader path, OREApp::analytics(), calls saveCube/saveAggregationScenarioData.
So a Python caller using the InputParameters setter path cannot reuse a cube at all on 1.8.16.0, and must re-simulate. For a Monte-Carlo exposure cube this is the difference between seconds and a full simulation.
Noting in passing that inputparameters.hpp:670 carries // TODO: API for setting NPV and market cubes directly above these two setters, so this area may already be known to be unfinished.
Environment
open-source-risk-engine 1.8.16.0 (PyPI wheel, cp312-cp312-macosx_14_0_arm64), Python 3.12.13, macOS 15 arm64
- Compared against 1.8.16.0 and 1.8.15.0 wheels on the same machine; the C++ /
.i line references are from tags v1.8.16.0 and v1.8.15.0
Summary
In the Python bindings,
OREApp::getCube()andInputParameters::setCube()are declared with different spellings of the same type, so the cube returned by the getter cannot be passed to the setter:setMarketCube/getMarketCubeare affected identically. This is a regression between v1.8.15.0 and v1.8.16.0, and it disables in-memory cube reuse from Python — running the XVA analytic postprocess-only on a previously simulated cube.Root cause
The C++ is self-consistent — both sides use
QuantLib::ext::shared_ptr:OREAnalytics/orea/app/oreapp.hpp:78—QuantLib::ext::shared_ptr<NPVCube> getCube(std::string cubeName);OREAnalytics/orea/app/inputparameters.hpp:674—void setCube(const QuantLib::ext::shared_ptr<NPVCube>& cube)The SWIG interface qualifies only the setters:
ORE-SWIG/OREAnalytics-SWIG/SWIG/orea_app.iSWIG keys its type table on the literal spelling, so
ext::shared_ptr<...>andQuantLib::ext::shared_ptr<...>are registered as two distinct types. The mismatch is visible in the proxy objects themselves:In v1.8.15.0 both sides read
ext::shared_ptr<NPVCube>(lines 345/383) — consistent, and it works. The setters were qualified to match the C++ somewhere inv1.8.15.0..v1.8.16.0(the change enters on the merge85c8f7494,feature/QPR-13887) and the getters were not updated with them.Suggested fix: add the
QuantLib::prefix to the two getter declarations atorea_app.i:554and:557, so they match the setters and the C++.Reproducer
Any run that produces a cube, then handing that cube back:
Both calls raise on 1.8.16.0 and both succeed on 1.8.15.0.
Impact
The intended workflow is unreachable from Python. Reuse requires both cubes —
XvaAnalyticImplhard-requires the market cube ("XVA without EXPOSURE requires a market cube as input",xvaanalytic.cpp) — and there is no substitute for either:AggregationScenarioDatais not serialisable through the binding (the SWIG wrapper types thequalifierargument ofhas/getas an opaque barestring, so qualified entries are unreachable).OREApp::run(loader)ends at// Leave any report writing to the calling aplicationand writes no cubes; only the file-loader path,OREApp::analytics(), callssaveCube/saveAggregationScenarioData.So a Python caller using the
InputParameterssetter path cannot reuse a cube at all on 1.8.16.0, and must re-simulate. For a Monte-Carlo exposure cube this is the difference between seconds and a full simulation.Noting in passing that
inputparameters.hpp:670carries// TODO: API for setting NPV and market cubesdirectly above these two setters, so this area may already be known to be unfinished.Environment
open-source-risk-engine1.8.16.0 (PyPI wheel,cp312-cp312-macosx_14_0_arm64), Python 3.12.13, macOS 15 arm64.iline references are from tagsv1.8.16.0andv1.8.15.0