SMS++ Block for capacity expansion: the investment in the assets of an
inner Block, such as the units and the lines of a UCBlock.
The InvestmentBlock class, which derives from Block, has a vector of
ColVariable, each of which represents the investment in a particular
asset, with its bounds and, optionally, its integrality. Its Objective is
the sum of one or more InvestmentFunction: a single one is the Function
of its FRealObjective, while several are its components, each in a
sub-Block of its own and weighted by the weight of the Objective of its
inner Block (see Block::get_objective_weight()), which BundleSolver
sees as separate components. The components may share the same
ColVariable, as the scenarios of a stochastic problem do, or each invest
in its own and charge its cost against those of another, as the periods of
a multi-period problem do (see AssetVarIndex and AssetBaselineVarIndex
in InvestmentFunction). The components are solved independently of each
other: an inner Block whose state passes from one period to the next is
not solved as such when its periods are written as separate components.
Besides the bounds, the InvestmentBlock has a linear constraint for each
limit on how much an asset may grow or shrink from its baseline (see
MaxInvestment and MaxDisinvestment in InvestmentFunction), and each
InvestmentFunction may have "implicit" linear constraints on its assets,
which it generates itself as "vertical linearizations".
An InvestmentFunction is a C05Function that is capable of evaluating the
investment on a set of assets. InvestmentFunction derives from both
C05Function and Block. The main ingredients of an InvestmentFunction are
the following:
-
The active
ColVariableof theInvestmentFunctionrepresent investments that can be made in certain assets. What investing in an asset means is said by the asset itself, which names in the methods factory the method that writes the investment into the innerBlockand the one that reads back the derivative of the value with respect to it (seeAssetSetterandAssetLinearizationinInvestmentFunction). Those ofUCBlockinvest an amount x in-
a unit that stands for x identical copies of itself (see
UCBlock::replicate()andUnitBlock::replicate()), such as aThermalUnitBlockor aConversionUnitBlock; -
a unit resized to x in the way of its class (see
UCBlock::resize_unit()), such as anIntermittentUnitBlockor aBatteryUnitBlockwhose minimum and maximum power and storage levels are scaled by x usingset_kappa(); the storage and the converter of aBatteryUnitBlockcan also be sized apart, with an asset each (seeAssetTypeinInvestmentFunction); -
a line, of any carrier, whose minimum and maximum power flow are scaled by x using
set_kappa()(seeUCBlock::resize_line()).
-
-
The value of the
InvestmentFunctionis given by a fixed investment cost (CAPEX) and an [expected] operational cost (OPEX). The fixed investment cost is a linear function of theColVariableof theInvestmentFunction. The [expected] operational cost is given by the solution value of the innerBlock(which depends on the investment being made, i.e., the values of the variables of theInvestmentFunction). -
The
InvestmentFunctionhas an innerBlockwhich contains the assets to invest in: anyBlockthe methods of its assets can be called on, such as aUCBlock, aTwoStageStochasticBlockor aMultiStageStochasticBlockofUCBlock, or anSDDPBlock. An innerBlockmade ofBlockof the class of those methods, as the scenarios of aTwoStageStochasticBlock, is split when theInvestmentBlockis read into one component for each of them, weighted by its probability; if the innerBlockties them withVariableorConstraintof its own,ScenarioDecomposition0 keeps it whole. Over anSDDPBlockthe OPEX is the mean cost of the simulations of the policy that itsSDDPSimulationSolvertrains, the investment being written into theUCBlockof each stage and the same for all of them.
An inner Block in design mode, i.e., one whose units and lines carry the
design Variable of their investment, as a TwoStageStochasticBlock written
to be solved as a whole, is refused when the InvestmentBlock is read: the
class of the Blocks the investment is written into tells it with a getter
<class>::has_design in the methods factory (UCBlock::has_design for a
UCBlock), and a class without it has no design mode. The investment is
decided once, by the InvestmentBlock, so such a file has to be converted
first into one of InvestmentBlock, each design an asset, by the tool
design_converter.
The netCDF format of an InvestmentBlock is described in the comments of
InvestmentBlock::deserialize() and InvestmentFunction::deserialize().
These instructions will let you build InvestmentBlock on your system.
The module also comes ready-made: on Ubuntu as libsmspp-investment-dev (and
smspp-investment for the tool), in vcpkg as smspp[core,investment], and in
the other channels that the installation
guide of
SMS++ lists. What follows is about building it yourself.
- The SMS++ core library and its requirements.
The classes of the inner Block, e.g., UCBlock, TwoStageStochasticBlock or SDDPBlock, are not needed to build the module: whoever reads an inner Block of one of them links it.
Configure and build the library with:
mkdir build
cd build
cmake ..
cmake --build .The library has the same configuration options of SMS++.
Optionally, install the library in the system with:
cmake --install .After the library is built, you can use it in your CMake project with:
find_package(InvestmentBlock)
target_link_libraries(<my_target> SMS++::InvestmentBlock)Carefully hand-crafted makefiles have also been developed for those unwilling to use CMake. Makefiles build the executable in-source (in the same directory tree where the code is) as opposed to out-of-source (in the copy of the directory tree constructed in the build/ folder) and therefore it is more convenient when having to recompile often, such as when developing/debugging a new module, as opposed to the compile-and-forget usage envisioned by CMake.
Each executable using InvestmentBlock has to include a "main makefile" of
the module, which typically is either makefile-c including all
necessary libraries comprising the "core SMS++" one, or
makefile-s including all necessary libraries but not the "core
SMS++" one (for the common case in which this is used together with other
modules that already include them). One relevant case is the
InvestmentBlock main in the tools/ repo. The makefiles
in turn recursively include all the required other makefiles, hence one should
only need to edit the "main makefile" for compilation type (C++ compiler and
its options) and it all should be good to go. In case some of the external
libraries are not at their default location, it should only be necessary to
create the ../extlib/makefile-paths out of the
extlib/makefile-default-paths-* for your OS * and edit the relevant bits
(commenting out all the rest).
Check the SMS++ installation wiki for further details.
The test folder contains InvestmentBlock_unit_test, which checks
the curvature that an InvestmentFunction declares and compares its
linearization with the finite differences of its value on small UCBlock.
The cross-module testers are in the
tests repo (tests/InvestmentBlock/).
We provide some data sets that are used, among other things, by some of the testers of the test repo. Since they are large they are not included in the repo. They are automatically downloaded by CMake if the test repo is included, but if you are not using CMake to build the system you need to do it by hand, via
cd data
wget https://gitlab.com/api/v4/projects/45125867/packages/generic/nc4/latest/nc4.tgz
tar xzvf nc4.tgzThis builds the data/nc4 folder with the InvestmentBlock
instances (such as the pypsa-data set) used by the tests.
If you need support, you want to submit bugs or propose a new feature, you can open a new issue.
Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting merge requests to us.
-
Rafael Durbano Lobato
Dipartimento di Informatica
Università di Pisa -
Donato Meoli
Dipartimento di Informatica
Università di Pisa -
Francesco Secoli
Dipartimento di Informatica
Università di Pisa
- Antonio Frangioni
Dipartimento di Informatica
Università di Pisa
This code is provided free of charge under the GNU Lesser General Public License version 3.0 - see the LICENSE file for details.
The code is currently provided free of charge under an open-source license. As such, it is provided "as is", without any explicit or implicit warranty that it will properly behave or it will suit your needs. The Authors of the code cannot be considered liable, either directly or indirectly, for any damage or loss that anybody could suffer for having used it. More details about the non-warranty attached to this code are available in the license description file.