GraphQL API =========== This section explains how to build Predicer input data using Hertta’s GraphQL API. Each subsection describes an object, its parameters, and provides examples. TimeLineSettings ---------------- The timeline defines the resolution and length of your optimisation problem. It is the same for all data objects, so the number of values in every time series must match the number of timesteps. Set the timeline with the ``updateTimeLine`` mutation. Example (six-hour timeline, hourly steps):: updateTimeLine( timeLineInput: { duration: { hours: 6, minutes: 0, seconds: 0 } step: { hours: 1, minutes: 0, seconds: 0 } } ) { errors { field message } } For a six-hour horizon starting at ``2025-04-20T00:00:00Z`` the resulting timestamps are:: 2025-04-20T00:00:00Z 2025-04-20T01:00:00Z 2025-04-20T02:00:00Z 2025-04-20T03:00:00Z 2025-04-20T04:00:00Z 2025-04-20T05:00:00Z InputDataSetup -------------- Global settings that affect optimisation behaviour. Create or edit via ``createInputDataSetup`` / ``updateInputDataSetup``. Example (enable market bids and reserves):: createInputDataSetup( setupUpdate: { useMarketBids: true useReserves: true useReserveRealisation: false useNodeDummyVariables: true useRampDummyVariables: true commonTimesteps: 0 commonScenarioName: null nodeDummyVariableCost: 1000000.0 rampDummyVariableCost: 1000000.0 } ) { errors { field message } } Scenarios --------- Scenarios represent different possible futures. Use ``createScenario`` to add them. Example:: createScenario(name: "scenarioA", weight: 1.0) { message } createScenario(name: "scenarioB", weight: 2.0) { message } Nodes ----- Nodes are fundamental building blocks in Predicer. Use ``createNode``. Nodes may represent commodities, markets, reserves or storages. Example 1: constant cost, no inflow:: createNode( node: { name: "Node1" isCommodity: false isMarket: false isRes: false cost: [ { scenario: null, constant: 24.0, series: null } ] inflow: [] } ) { errors { field message } } Example 2: cost series for a scenario:: createNode( node: { name: "Node2" isCommodity: false isMarket: false isRes: false cost: [ { scenario: "Scenario1" constant: null series: [10.0, 12.0, 14.0, 13.0, 11.0, 15.0] } ] inflow: [] } ) { errors { field message } } Example 3: inflow from an electricity price forecast:: createNode( node: { name: "Node3" isCommodity: false isMarket: false isRes: false cost: [] inflow: [ { scenario: "Scenario1" constant: null series: null forecast: "ELERING" fType: "electricity" } ] } ) { errors { field message } } Node state (storage) -------------------- If a node has storage, set its state separately using ``setNodeState``:: setNodeState( nodeName: "Node1" state: { inMax: 100.0 outMax: 80.0 stateLossProportional: 0.01 stateMin: 20.0 stateMax: 200.0 initialState: 50.0 isScenarioIndependent: true isTemp: false tEConversion: 1.0 residualValue: 0.0 } ) { errors { field message } } Processes --------- Processes convert or transfer commodities between nodes. Use ``createProcess`` with a ``NewProcess`` input. Example:: createProcess( process: { name: "Process1" conversion: UNIT isCfFix: false isOnline: true isRes: false eff: 0.95 loadMin: 0.3 loadMax: 1.0 startCost: 100.0 minOnline: 2.0 maxOnline: 6.0 minOffline: 1.0 maxOffline: 24.0 initialState: false isScenarioIndependent: true cf: [] effTs: [] } ) { errors { field message } } Groups ------ Groups allow you to bundle nodes or processes. Example:: # Create a process group createProcessGroup(name: "g1") { message } # Add a process to the group addProcessToGroup(processName: "Process1", groupName: "g1") { message } # Create a node group createNodeGroup(name: "ng1") { message } # Add a node to the group addNodeToGroup(nodeName: "Node1", groupName: "ng1") { message } Markets ------- Markets balance your model by allowing buying or selling of commodities. Markets can be of energy or reserve type. Example (energy market):: createMarket( market: { name: "el_market" mType: ENERGY node: "GridNode" processGroup: "" direction: null reserveType: null isBid: true isLimited: false minBid: 0.0 maxBid: 0.0 fee: 0.0 price: [ { scenario: null, constant: 50.0, series: null, forecast: null, fType: null } ] upPrice: [] downPrice: [] realisation: [] reserveActivationPrice: [] } ) { errors { field message } } Connect market prices to an external forecast:: connectMarketPricesToForecast( marketName: "el_market", forecastName: "ENTSOE", forecastType: "electricity" ) { message } Risk ---- Predicer models uncertainty by adding a Conditional Value at Risk (CVaR) term to the objective function. Example:: createRisk(risk: { parameter: "alfa", value: 0.95 }) { errors { field message } } createRisk(risk: { parameter: "beta", value: 0.1 }) { errors { field message } } Inflow Blocks ------------- Inflow blocks (or blocks) model flexibility actions like shifting inflow between timesteps. Each block has a binary variable and a series of constants defining how much inflow is shifted at each timestep. Blocks are linked to a specific node and scenario, and only one block may be active for a given node, time and scenario. Example of a block ``b1`` acting on node ``n1`` in scenario ``s1`` (tabular form):: t b1,n1 b1,s1 1 20.4.2022 1:00 6 2 20.4.2022 2:00 -3 3 20.4.2022 3:00 -2 4 20.4.2022 4:00 -1 (The Hertta API does not currently support creating blocks via GraphQL.) Node Diffusion -------------- Node diffusion models energy flow between two storage nodes based on their state (e.g. heat transfer). The flow is ``E = k * (T1 - T2)``, where ``k`` is the diffusion coefficient. Example:: createNodeDiffusion( newDiffusion: { fromNode: "Room1" toNode: "Room2" coefficient: [ { scenario: null, constant: 0.05, series: null } ] } ) { errors { field message } } Node Delay ---------- A node delay represents a one-way delay between two nodes (e.g. water travel time between reservoirs). Commodity and market nodes cannot participate in a delay. Example:: createNodeDelay( delay: { fromNode: "R1" toNode: "R2" delay: 3.0 minDelayFlow: -1e9 maxDelayFlow: 1e9 } ) { errors { field message } } Node Histories -------------- When modelling delays, the downstream node needs a history defining inflow for the first ``d`` timesteps. Example:: createNodeHistory(nodeName: "R2") { errors { field message } } addStepToNodeHistory( nodeName: "R2", step: { scenario: "Scenario1" durations: [ { hours: 1, minutes: 0, seconds: 0 }, { hours: 1, minutes: 0, seconds: 0 } ] values: [3.0, 4.0] } ) { errors { field message } } General Constraints ------------------- General constraints restrict relationships between process flows, storage states or online variables. They can be rigid (strict equality/inequality) or setpoint constraints with a penalty for deviations. Example (less-than constraint + flow factors):: createGenConstraint( constraint: { name: "gt_c1" gcType: LESS_THAN isSetpoint: false penalty: 0.0 constant: [ { scenario: null, constant: 0.0, series: null } ] } ) { errors { field message } } # Electricity flow factor createFlowConFactor( factor: [ { scenario: null, constant: 3.0, series: null } ], constraintName: "gt_c1", processName: "gas_turb", sourceOrSinkNodeName: "elc" ) # Heat flow factor createFlowConFactor( factor: [ { scenario: null, constant: -1.0, series: null } ], constraintName: "gt_c1", processName: "gas_turb", sourceOrSinkNodeName: "heat" )