Skip to content

centiv

CentIvModule

CentIvModule(parameters: dict, scenario: Scenario)

Bases: Plugin

Run CentIv simulations

Source code in src/plugins/centiv/cgep/create_scenario_fast.py
def __init__(self, parameters: dict, scenario: Scenario):
    self.config = Config(**parameters)
    self.__data_context = scenario.get_data_context()
    if self.__data_context.type != "mysql":
        raise ValueError("CentIv only works with a MySQL database")
    self.model = DataImport(self.config.timeperiods)

config instance-attribute

config = Config(**parameters)

model instance-attribute

model = DataImport(timeperiods)

get_default_parameters classmethod

get_default_parameters() -> dict
Source code in src/plugins/centiv/cgep/create_scenario_fast.py
@classmethod
def get_default_parameters(cls) -> dict:
    return asdict(Config())

run

run() -> None
Source code in src/plugins/centiv/cgep/create_scenario_fast.py
def run(self) -> None:

    if self.config.single_electric_node:
        logging.warning("Single electric node mode is enabled. This will not run the full CentIv simulation.")
    else:
        logging.warning("Single electric node mode is disabled. Running full CentIv simulation.")                
    print("Starting CentIv simulation...")

    duration_dict = {}
    start_time = time.time()
    print("Starting MySQLConnect" + 70 * "-")
    self.model.MySQLConnect(
        host=self.__data_context.host,
        database=self.__data_context.name,
        user=self.__data_context.user,
        password=self.__data_context.password
    )
    duration_dict['MySQLConnect'] = time.time() - start_time
    logging.debug('MySQLConnect took ' + str(duration_dict['MySQLConnect']) + ' minutes')

    logging.debug("Starting LoadDistIvResults_MAT")
    self.model.LoadDistIvResults_MAT(self.config.distivresults_directory)
    duration_dict['LoadDistIvResults_MAT'] = (time.time() - start_time)/60

    logging.debug("Starting LoadABMResults_MAT")
    self.model.LoadABMResults_MAT(self.config.abmresults_directory)
    duration_dict['LoadABMResults_MAT'] = (time.time() - start_time)/60
    logging.debug("LoadABMResults_MAT took " + str(duration_dict['LoadABMResults_MAT']) + " minutes")

    print("Starting LoadCascadesResults_CSV")
    self.model.LoadCascadesResults_CSV(self.config.cascadesresults_directory)
    duration_dict['LoadCascadesResults_CSV'] = (time.time() - start_time)/60
    logging.debug("LoadCascadesResults_CSV took " + str(duration_dict['LoadCascadesResults_CSV']) + " minutes")

    print("Starting GetScenario")
    self.model.GetScenario(self.config)
    duration_dict['GetScenario'] = (time.time() - start_time)/60
    logging.debug("GetScenario took " + str(duration_dict['GetScenario']) + " minutes")

    logging.debug("Starting GetOptimization")
    self.model.GetOptimization(self.config)
    duration_dict['GetOptimization'] = (time.time() - start_time)/60
    logging.debug("GetOptimization took " + str(duration_dict['GetOptimization']) + " minutes")

    logging.debug("CentIv simulation completed in " + str((time.time() - start_time)/60) + " minutes.")
    logging.debug("Duration log in the run method duration_dict is:")
    logging.debug(duration_dict)

Config dataclass

Config(
    results_path: str = "results",
    idScenario: int = 5,
    ici_multiplier: float = 1.0,
    vci_multiplier: float = 1.0,
    foci_multiplier: float = 1.0,
    demandCH: float = 0,
    targetRES: float | None = None,
    targetRESPV: float = 0.0,
    targetH2: float = 0.0,
    targetCH4: float = 0.0,
    targetCO2: float = 0.0,
    distIvRESproduction: float = 0.0,
    distIvPVinstalled: float = 0,
    distivresults_directory: str = join(getcwd(), "output_jo"),
    abmresults_directory: str = join(getcwd(), "abm_dist_invest"),
    cascadesresults_directory: str = join(getcwd(), "cascades_invest"),
    timeperiods: int = 8760,
    battDIS: float = 0.00054,
    solarUP: float = 0.008,
    solarDOWN: float = 0.0085,
    windUP: float = 0.0615,
    windDOWN: float = 0.0654,
    loadShedding_cost: float = 10000.0,
    maxdailyH2withdrawal_p2g2p: float = 0.062,
    maxdailyH2injection_p2g2p: float = 0.037,
    CH4pmin: float = 0.45,
    alpha_ex_CentIv: float = 0,
    duals_required: bool = True,
    continvest_required: bool = True,
    continvestnuclear_required: bool = True,
    contnuclear_required: bool = True,
    equalexportsimports_required: bool = False,
    resolution_in_days: int = 1,
    disableREStarget: bool = False,
    enableTSODSOlimit: bool = False,
    single_electric_node: bool = False,
    threads: int = 8,
    min_nuclear_gen_lim: bool = True,
    include_nuclear_in_RES_target: bool = False,
    max_LL_switch: float = 0.3,
)

CH4pmin class-attribute instance-attribute

CH4pmin: float = 0.45

Percentage of Pmax set for the minimum operating point of the methanation reactor

abmresults_directory class-attribute instance-attribute

abmresults_directory: str = join(getcwd(), 'abm_dist_invest')

Directory in which the output from ABM is located

alpha_ex_CentIv class-attribute instance-attribute

alpha_ex_CentIv: float = 0

TSO-DSO Power flow limit is set at alpha_ex_CentIv * maximum load at that node.

battDIS class-attribute instance-attribute

battDIS: float = 0.00054

Battery self-discharge

The default value is taken from: https://www.sciencedirect.com/science/article/pii/S0306261920307091

cascadesresults_directory class-attribute instance-attribute

cascadesresults_directory: str = join(getcwd(), 'cascades_invest')

Directory in which the output from Cascades is located

continvest_required class-attribute instance-attribute

continvest_required: bool = True

Flag for whether we require continuous investments in candidate conventional units (1) or not (0)

continvestnuclear_required class-attribute instance-attribute

continvestnuclear_required: bool = True

Flag for whether we require continuous investments in candidate nuclear units (1) or not (0)

contnuclear_required class-attribute instance-attribute

contnuclear_required: bool = True

Flag for whether we require continuous operation of Swiss nuclear units (1) or not (0)

demandCH class-attribute instance-attribute

demandCH: float = 0

Total (yearly) Swiss demand in MWh - Input from Gemel

disableREStarget class-attribute instance-attribute

disableREStarget: bool = False

Disable RES target for the simulation

distIvPVinstalled class-attribute instance-attribute

distIvPVinstalled: float = 0

Total installed PV capacity in MW - Input from distIv

distIvRESproduction class-attribute instance-attribute

distIvRESproduction: float = 0.0

Total distribution level RES production in TWh - Input from distIv

distivresults_directory class-attribute instance-attribute

distivresults_directory: str = join(getcwd(), 'output_jo')

Directory in which the output from DistIv is located

duals_required class-attribute instance-attribute

duals_required: bool = True

Flag for whether we require re-solve fixing the investment variables to get the duals (1) or not (0)

enableTSODSOlimit class-attribute instance-attribute

enableTSODSOlimit: bool = False

Enable TSO-DSO Power flow limit

equalexportsimports_required class-attribute instance-attribute

equalexportsimports_required: bool = False

Flag for whether we require the total annual exports to equal the total annual imports

foci_multiplier class-attribute instance-attribute

foci_multiplier: float = 1.0

Multiplier for the fixed operational costs - Input from Gemel

ici_multiplier class-attribute instance-attribute

ici_multiplier: float = 1.0

Multiplier for the investment costs - Input from Gemel

idScenario class-attribute instance-attribute

idScenario: int = 5

ID of simulated scenario from MySQL database Represents the simulated year

include_nuclear_in_RES_target class-attribute instance-attribute

include_nuclear_in_RES_target: bool = False

if set true, the generation from nuclear plants is included in the RES target accounting (e.g., in the 45 TWh target for 2050)

loadShedding_cost class-attribute instance-attribute

loadShedding_cost: float = 10000.0

Cost of load shedding in CHF/MWh

max_LL_switch class-attribute instance-attribute

max_LL_switch: float = 0.3

For calibration purposes, adding X% of max lost load for other countries as back up capacity

maxdailyH2injection_p2g2p class-attribute instance-attribute

maxdailyH2injection_p2g2p: float = 0.037

Maximum daily injection rate in [%] of H2 storage of P2G2P unit

The default value is taken from: https://www.sciencedirect.com/science/article/pii/S0360319914021223?via%3Dihub

maxdailyH2withdrawal_p2g2p class-attribute instance-attribute

maxdailyH2withdrawal_p2g2p: float = 0.062

Maximum daily withdrawal rate in [%] of H2 storage of P2G2P unit

The default value is taken from: https://www.sciencedirect.com/science/article/pii/S0360319914021223?via%3Dihub

min_nuclear_gen_lim class-attribute instance-attribute

min_nuclear_gen_lim: bool = True

if set true, a given minimum of generation is forced on new nuclear plants, if False, the generation may go as low as 0

resolution_in_days class-attribute instance-attribute

resolution_in_days: int = 1

Resolution of simulated timeperiods

results_path class-attribute instance-attribute

results_path: str = 'results'

Folder in which the results are stored

single_electric_node class-attribute instance-attribute

single_electric_node: bool = False

Flag for whether we want to run the simulation with a single electric node (True) or not (False, that is, with multiple electric nodes based on DC load flow)

solarDOWN class-attribute instance-attribute

solarDOWN: float = 0.0085

Coeff for increasing RR down reserves due to newly installed solar capacities

solarUP class-attribute instance-attribute

solarUP: float = 0.008

Coeff for increasing RR up reserves due to newly installed solar capacities

targetCH4 class-attribute instance-attribute

targetCH4: float = 0.0

Total Swiss CH4 target in GWh_th

targetCO2 class-attribute instance-attribute

targetCO2: float = 0.0

Total Swiss CO2 target in tonnes CO2

targetH2 class-attribute instance-attribute

targetH2: float = 0.0

Total Swiss H2 target in tonnes H2

targetRES class-attribute instance-attribute

targetRES: float | None = None

Total Swiss RES target in TWh

targetRESPV class-attribute instance-attribute

targetRESPV: float = 0.0

Total Swiss RES target in TWh to be covered by solar rooftop PV installations

threads class-attribute instance-attribute

threads: int = 8

Number of threads to use for solving in gurobi

timeperiods class-attribute instance-attribute

timeperiods: int = 8760

Number of simulated timeperiods

vci_multiplier class-attribute instance-attribute

vci_multiplier: float = 1.0

Multiplier for the variable costs - Input from Gemel

windDOWN class-attribute instance-attribute

windDOWN: float = 0.0654

Coeff for increasing RR down reserves due to newly installed wind capacities

windUP class-attribute instance-attribute

windUP: float = 0.0615

Coeff for increasing RR up reserves due to newly installed wind capacities