<jupyter_start><jupyter_text>Calculate capacity headroom<jupyter_code>import pandas as pd
import numpy as np
import copy
import pandapower as pp
import pandapower.plotting as plot
from datetime import date, datetime
import yaml
import folium
import copy
import json
import plotly.graph_objs as go

import os,sys,inspect

#To import packages from parent subfolder 
currentdir =  os.path.abspath(os.getcwd())
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir)

from capacitymap.grid.grid import Grid, generate_config_from_project, combine_dict, daterange
from capacitymap.analysis import analysis_check 
analysis_check.check_violations.counter = 0 #to make it run on first run
from capacitymap.analysis import capacity_analysis<jupyter_output><empty_output><jupyter_text>Data PreparationBefore requests can be assessed we need to start gathering the relevant grid model and calculate available capacity.  Load network and create grid objectWe start off by loading the grid model. This is a grid model representing the grid at normal operation. Depending on use case there is a possibility to also store time limited projects which results in re-configurations to the normal grid. This functions is available from the grid class but not used for this use case<jupyter_code># Pandapower grid
net = pp.from_json(os.path.join(currentdir,'data\svedala\svedala.json')) 

# Dataframe over planned projects, to start this list is empty
projects = pd.DataFrame(columns=['Start', 'End', 'Object_type','ObjectID', 'Status'])

# Create grid object
svedala = Grid('Svedala',net, {}, projects)

#Print svedala information:
print('Name: ', svedala.name)
print('Normal operation grid model: ', svedala.grid)
print('List of planned configuration: ', svedala.config_dict)
print('Planned projects: ', svedala.project_df)
print('Active date: ', svedala.active_date)
print('Active config: ', svedala.active_config)<jupyter_output>Name:  Svedala
Normal operation grid model:  This pandapower network includes the following parameter tables:
   - bus (108 elements)
   - load (73 elements)
   - gen (38 elements)
   - shunt (27 elements)
   - ext_grid (1 element)
   - line (75 elements)
   - trafo (53 elements)
   - controller (38 elements)
   - bus_geodata (108 elements)
 and the following results tables:
   - res_bus (108 elements)
   - res_line (75 elements)
   - res_trafo (53 elements)
   - res_ext_grid (1 element)
   - res_load (73 elements)
   - res_shunt (27 elements)
   - res_gen (38 elements)
List of planned configuration:  {}
Planned projects:  Empty DataFrame
Columns: [Start, End, Object_type, ObjectID, Status]
Index: []
Active date:  None
Active config:  None<jupyter_text>Define limits and contingency testBefore we can start with the capacity calculation we need to define the thresholds for the test we check for every power flow we run. The analysis builds on 8 test, if one of these fails the enterie scenario fails. The tests are:1. Upper limit on bus bus voltage2. Lower limit on bus voltage3. Max loading on line exceeded4. Max loading on trafo exceeded5. Subscription limit to overlying network exceeded6. Unsupplied loads7. Power flow did not converge, meaning something is really wrong :)Dependning on what test we run these thresholds can vary. For capacity calculation we run two types of calculations, one for normal operations and one for contingency scenarios (relevant N-1). We therfore define two sets of limits to validate available capacity:<jupyter_code># Normal operation limits
normal_limits = {'vmin': 0.9,
                'vmax': 1.12,
                'max_line_loading' : 105,
                'max_trafo_loading' : 100,
                'subscription_p_limits': 1000,
                'run_controllers': True}

# Limits for continency tests
cont_limits = {'vmin': 0.87,
                'vmax': 1.15,
                'max_line_loading' : 120,
                'max_trafo_loading' : 120,
                'subscription_p_limits': 1000,
                'run_controllers': True}<jupyter_output><empty_output><jupyter_text>For the contingency test, we need to define which objects to test. The list consists of two lists, one over lines to test and one over trafos to test.<jupyter_code>fileObject = open(os.path.join(currentdir,"data\\svedala\\line_to_test.json"), "r")
jsonContent = fileObject.read()
lines_to_test = json.loads(jsonContent)

fileObject = open(os.path.join(currentdir,"data\\svedala\\trafo_to_test.json"), "r")
jsonContent = fileObject.read()
trafos_to_test = json.loads(jsonContent)
contingency_scenario = [lines_to_test, trafos_to_test]<jupyter_output><empty_output><jupyter_text>Define capacity headroom<jupyter_code># Define type of capacity (generation or load)
cap_type = 'load'

# Define max headroom to test
upper_lim_p = 500<jupyter_output><empty_output><jupyter_text>Calculate capacity headroom<jupyter_code>cap_headroom = capacity_analysis.headroom(svedala.grid, cap_type,upper_lim_p, normal_limits=normal_limits, contingency_limits=cont_limits,contingency_scenario=contingency_scenario )
#Save result to json
#capfile = 'data\\svedala\\'+svedala.name+'_headroom_'+cap_type+'.json'
#cap_headroom.to_json(os.path.join(currentdir,capfile))
# Define type of capacity (generation or load)
cap_type = 'sgen'

# Define max headroom to test
upper_lim_p = 500
cap_headroom = capacity_analysis.headroom(svedala.grid, cap_type,upper_lim_p, normal_limits=normal_limits, contingency_limits=cont_limits,contingency_scenario=contingency_scenario )

#Save result to json
#capfile = 'data\\svedala\\'+svedala.name+'_headroom_'+cap_type+'.json'
#cap_headroom.to_json(os.path.join(currentdir,capfile))<jupyter_output>[                    ] 1% (number of PFs: 380)Max capacity is available
[=                   ] 8% (number of PFs: 706)Max capacity is available
[====                ] 20% (number of PFs: 1753)Max capacity is available
[====                ] 21% (number of PFs: 1798)Max capacity is available
[====                ] 22% (number of PFs: 1843)Max capacity is available
[========            ] 44% (number of PFs: 3405)Max capacity is available
[=========           ] 49% (number of PFs: 3790)Max capacity is available
[==========          ] 52% (number of PFs: 4001)Max capacity is available
[===========         ] 58% (number of PFs: 4710)Max capacity is available
[=============       ] 68% (number of PFs: 5615)Max capacity is available
[===============     ] 75% (number of PFs: 6757)Max capacity is available
[===============     ] 79% (number of PFs: 7002)Max capacity is available
[================    ] 82% (number of PFs: 7151)Max capacity is available
[=================== ] 95% (number of PFs:[...]
{'fraction_non_alphanumeric': 0.10517629407351838, 'fraction_numerical': 0.02355588897224306, 'mean_word_length': 4.446078431372549, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '588142', 'license': 'Apache-2.0', 'n_tokens_mistral': 2138, 'n_tokens_neox': 1955, 'n_words': 659, 'path': 'tutorials/Calculate capacity headroom.ipynb', 'repo_name': 'gridcapacitymap/gridcapacitymap', 'size': '6665'}