Skip to content

Commit

Permalink
Add outage incidence visualizations for individual microgrids in rest…
Browse files Browse the repository at this point in the history
…oration model
  • Loading branch information
SaeedRazavi committed Mar 22, 2024
1 parent 8928ed6 commit 337c4de
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 10 deletions.
13 changes: 12 additions & 1 deletion omf/models/restoration.html
Original file line number Diff line number Diff line change
Expand Up @@ -189,13 +189,24 @@
<div id="utilityOutageCostCalc" class="tightContent">
{{ allOutputDataDict['utilityOutageHtml'] }}
</div>
<p class="reportTitle"><label class="tooltip">Outage Incidence <span class="classic">The "Before" status of loads at each timestep as seen in the Timeline below is used to calculate Outage Incidence. The final timestep represents values using the "After" status for the last time in the Timeline. E.g. The Load Outage % value at Before Hour X=5 is the % of loads experiencing an outage calculated with the "Before" value of each load in the Timeline at Time 5. </span></label></p>
<p class="reportTitle"><label class="tooltip">Outage Incidence for Full System<span class="classic">The "Before" status of loads at each timestep as seen in the Timeline below is used to calculate Outage Incidence. The final timestep represents values using the "After" status for the last time in the Timeline. E.g. The Load Outage % value at Before Hour X=5 is the % of loads experiencing an outage calculated with the "Before" value of each load in the Timeline at Time 5. </span></label></p>
<div id="fig6" class="tightContent">
<div id="fig6Chart" style="width:1000px"></div>
<script type="text/javascript">
Plotly.newPlot("fig6Chart", JSON.parse(allOutputData["fig6Data"]), JSON.parse(allOutputData["fig6Layout"]) || {})
</script>
</div>
<p class="reportTitle"><label class="tooltip">Outage Incidence for Microgrids<span class="classic">The "Before" status of loads at each timestep as seen in the Timeline below is used to calculate Outage Incidence. The final timestep represents values using the "After" status for the last time in the Timeline. E.g. The Load Outage % value at Before Hour X=5 is the % of loads experiencing an outage calculated with the "Before" value of each load in the Timeline at Time 5. </span></label></p>
<div id="outageIncidenceFigures" class="tightContent" style="max-height:450px; overflow-y: scroll;">
<script type="text/javascript">
for (let [mgID,figData] of Object.entries(JSON.parse(allOutputData['mgOIFigsData']))) {
$("<div/>").appendTo("#outageIncidenceFigures")
.attr("id", "fig_mg_"+mgID)
.attr("style","width:1000px")
Plotly.newPlot("fig_mg_"+mgID, figData, JSON.parse(allOutputData["mgOIFigsLayout"]))
}
</script>
</div>
<p class="reportTitle" style="page-break-before:always">Timeline</p>
<div id="outageCostCalc" class="tightContent sorttable" style="max-height:500px; overflow-y:scroll">
{{ allOutputDataDict['timelineStatsHtml'] }}
Expand Down
51 changes: 42 additions & 9 deletions omf/models/restoration.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
# Model metadata:
tooltip = 'Calculate load, generator and switching controls to maximize power restoration for a circuit with multiple networked microgrids.'
modelName, template = __neoMetaModel__.metadata(__file__)
hidden = True
hidden = False

def makeCicuitTraversalDict(pathToOmd):
''' Note: comment out line 99 in comms.py: "nxG = graphValidator(pathToOmdFile, nxG)" as a quick fix for the purpose of this funct
Expand Down Expand Up @@ -435,7 +435,7 @@ def kWhApprox(kWDict, averagekWperhr, iterate):
return outageCost, kWperhrEstimate, times, localMax

def outageIncidenceGraph(customerOutageData, outputTimeline, startTime, numTimeSteps, loadPriorityFilePath, loadMicrogridDict):
''' Returns a plotly figure displaying a graph of outage incidences over the course of the event data.
''' Returns plotly figures displaying graphs of outage incidences over the course of the event data.
Unweighted outage incidence at each timestep is calculated as (num loads experiencing outage)/(num loads).
A load is considered to be "experiencing an outage" at a particular timestep if its "loadBefore" value
in outputTimeline is "offline". The last x-value on the graph is the exception, with its value corresponding
Expand All @@ -449,7 +449,7 @@ def outageIncidenceGraph(customerOutageData, outputTimeline, startTime, numTimeS
# TODO: Rename function

loadList = list(loadMicrogridDict.keys())
mgTags = set(loadMicrogridDict.values())
mgIDs = set(loadMicrogridDict.values())
timeList = [*range(startTime, numTimeSteps+1)] # The +1 is because we want the 'before' for each timestep + the 'after' for the last timestep

# Create a copy of outputTimeline containing only load devices sorted by device name and then time.
Expand Down Expand Up @@ -531,10 +531,40 @@ def calcWeightedOI(loadWeights):
# Calculate weighted outage incidence based on individually assigned weights
with open(loadPriorityFilePath) as inFile:
loadWeights = json.load(inFile)
individuallyWeightedOutageIncidence = calcWeightedOI(loadWeights)
indivWeightedOI = calcWeightedOI(loadWeights)

# TODO: Run calcWeightedOI with various microgrid masks (1 for loads in microgrid, 0 otherwise. For unweighted, use mask as weight. For weighted, multiply mask element-wise by weight)


mgOIFigures = {}
for targetID in mgIDs:
mgLoadMask = {load:(1 if id == targetID else 0) for (load,id) in loadMicrogridDict.items()}
mgLoadWeights = {load:(val*loadWeights.get(load,1)) for (load,val) in mgLoadMask.items()}
mgOI = calcWeightedOI(mgLoadMask)
mgOIWeighted = calcWeightedOI(mgLoadWeights)
mgOIFigures[targetID] = go.Figure()
mgOIFigures[targetID].add_trace(go.Scatter(
x=timeList,
y=mgOI,
mode='lines',
name=f'Unweighted OI for Microgrid {targetID}',
hovertemplate=
'<b>Time Step</b>: %{x}<br>' +
f'<b>Unweighted OI for Microgrid {targetID}</b>: %{{y:.3f}}%'))
mgOIFigures[targetID].add_trace(go.Scatter(
x=timeList,
y=mgOIWeighted,
mode='lines',
name=f'Priority-Weighted OI for Microgrid {targetID}',
hovertemplate=
'<b>Time Step</b>: %{x}<br>' +
f'<b>Priority-Weighted OI for Microgrid {targetID}</b>: %{{y:.3f}}%'))
mgOIFigures[targetID].update_layout(
xaxis_title='Before Hour X',
yaxis_title='Load Outage %',
yaxis_range=[-5,105],
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1))

outageIncidenceFigure = go.Figure()
outageIncidenceFigure.add_trace(go.Scatter(
x=timeList,
Expand All @@ -555,7 +585,7 @@ def calcWeightedOI(loadWeights):
'<b>Group-Weighted Outage Incidence</b>: %{y:.3f}%'))
outageIncidenceFigure.add_trace(go.Scatter(
x=timeList,
y=individuallyWeightedOutageIncidence,
y=indivWeightedOI,
mode='lines',
name='Priority-Weighted Outage Incidence',
hovertemplate=
Expand All @@ -568,7 +598,7 @@ def calcWeightedOI(loadWeights):
yaxis_range=[-5,105],
legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1))

return outageIncidenceFigure
return outageIncidenceFigure, mgOIFigures

def getMicrogridInfo(modelDir, pathToOmd, settingsFile, makeCSV = True):
''' Gathers microgrid info including loads in each microgrid by finding what microgrid each load's parent bus is designated as having.
Expand Down Expand Up @@ -620,6 +650,7 @@ def runMicrogridControlSim(modelDir, solFidelity, eventsFilename, loadPriorityFi
lpFile = loadPriorityFile if loadPriorityFile != None else ''
mgFile = microgridTaggingFile if microgridTaggingFile != None else ''


PowerModelsONM.build_settings_file(
circuitPath=pJoin(modelDir,'circuit.dss'),
settingsPath=pJoin(modelDir,'settings.json'),
Expand Down Expand Up @@ -1072,7 +1103,7 @@ def coordStrFormatter(coordString):
showarrow=False
)

outageIncidenceFig = outageIncidenceGraph(customerOutageData, outputTimeline, startTime, numTimeSteps, loadPriorityFile, loadMicrogridDict)
outageIncidenceFig, mgOIFigs = outageIncidenceGraph(customerOutageData, outputTimeline, startTime, numTimeSteps, loadPriorityFile, loadMicrogridDict)

customerOutageHtml = customerOutageTable(customerOutageData, outageCost, modelDir)
profit_on_energy_sales = float(profit_on_energy_sales)
Expand All @@ -1082,7 +1113,7 @@ def coordStrFormatter(coordString):
utilityOutageHtml = utilityOutageTable(average_lost_kwh, profit_on_energy_sales, restoration_cost, hardware_cost, outageDuration, modelDir)
try: customerOutageCost = customerOutageCost
except: customerOutageCost = 0
return {'utilityOutageHtml': utilityOutageHtml, 'customerOutageHtml': customerOutageHtml, 'timelineStatsHtml': timelineStatsHtml, 'outageIncidenceFig': outageIncidenceFig, 'gens': gens, 'loads': loads, 'volts': volts, 'fig': fig, 'customerOutageCost': customerOutageCost, 'numTimeSteps': numTimeSteps, 'stepSize': stepSize, 'custHist': custHist}
return {'utilityOutageHtml': utilityOutageHtml, 'customerOutageHtml': customerOutageHtml, 'timelineStatsHtml': timelineStatsHtml, 'outageIncidenceFig': outageIncidenceFig, 'mgOIFigs':mgOIFigs, 'gens': gens, 'loads': loads, 'volts': volts, 'fig': fig, 'customerOutageCost': customerOutageCost, 'numTimeSteps': numTimeSteps, 'stepSize': stepSize, 'custHist': custHist}

def buildCustomEvents(eventsCSV='', feeder='', customEvents='customEvents.json', defaultDispatchable = 'true'):
def outageSwitchState(outList): return ('open'*(outList[3] == 'closed') + 'closed'*(outList[3]=='open'))
Expand Down Expand Up @@ -1197,7 +1228,7 @@ def work(modelDir, inputDict):
dssConvert.dss_to_clean_via_save(f'{modelDir}/circuitOmfCompatible.dss', f'{modelDir}/circuitOmfCompatible_cleanLists.dss')

pathToLocalFile = copyInputFilesToModelDir(modelDir, inputDict)

runMicrogridControlSim(
modelDir = modelDir,
solFidelity = inputDict['solFidelity'],
Expand Down Expand Up @@ -1254,6 +1285,8 @@ def work(modelDir, inputDict):
outData['fig5Layout'] = json.dumps(layoutOb, cls=py.utils.PlotlyJSONEncoder)
outData['fig6Data'] = json.dumps(plotOuts.get('outageIncidenceFig',{}), cls=py.utils.PlotlyJSONEncoder)
outData['fig6Layout'] = json.dumps(layoutOb, cls=py.utils.PlotlyJSONEncoder)
outData['mgOIFigsData'] = json.dumps(plotOuts.get('mgOIFigs',{}), cls=py.utils.PlotlyJSONEncoder)
outData['mgOIFigsLayout'] = json.dumps(layoutOb, cls=py.utils.PlotlyJSONEncoder)
# Stdout/stderr.
outData['stdout'] = 'Success'
outData['stderr'] = ''
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"bus1006": "Left", "bus1013": "Left", "bus1005": "Left", "bus1008": "Left", "t_bus2058_l": "Left", "bus1010": "Left", "bus1002": "Left", "t_bus1010_l": "Left", "bus1017": "Left", "t_bus1005_l": "Left", "bus1016": "Left", "bus1007": "Left", "t_bus1006_l": "Left", "t_bus1004_l": "Left", "t_bus2059_l": "Left", "t_bus1015_l": "Left", "t_bus1013_l": "Left", "t_bus1003_l": "Left", "bus1011": "Left", "bus1004": "Left", "bus2058": "Left", "bus1009": "Left", "t_bus1014_l": "Left", "t_bus1008_l": "Left", "t_bus1016_l": "Left", "t_bus1017_l": "Left", "t_bus1009_l": "Left", "t_bus1007_l": "Left", "bus1012": "Left", "t_bus2060_l": "Left", "bus1015": "Left", "bus1014": "Left", "bus2057": "Left", "bus2059": "Left", "t_bus1012_l": "Left", "bus1003": "Left", "bus2060": "Left", "t_bus1011_l": "Left", "bus3121": "Right", "bus3038": "Right", "bus3122": "Right", "bus3033": "Right", "bus3017": "Right", "bus3014": "Right", "bus3084": "Right", "t_bus3087_l": "Right", "t_bus3124_l": "Right", "bus2004": "Left", "bus3104": "Right", "bus2003": "Left", "t_bus3014_l": "Right", "t_bus3109_l": "Right", "t_bus3043_l": "Right", "bus3042": "Right", "t_bus3028_l": "Right", "bus3066": "Right", "t_bus3096_l": "Right", "bus3133": "Right", "t_bus3009_l": "Right", "bus2056": "Left", "t_bus3085_l": "Right", "bus2043": "Left", "bus2036": "Left", "t_bus2040_l": "Left", "t_bus3155_l": "Right", "bus3077": "Right", "t_bus3019_l": "Right", "bus3063": "Right", "bus2039": "Left", "t_bus2055_l": "Left", "t_bus3025_l": "Right", "bus2018": "Right", "bus3016": "Right", "bus3073": "Right", "bus3043": "Right", "bus3092": "Right", "bus3047": "Right", "bus3037": "Right", "t_bus3114_l": "Right", "t_bus3049_l": "Right", "bus3010": "Right", "bus2044": "Left", "t_bus3117_l": "Right", "t_bus3158_l": "Right", "t_bus3129_l": "Right", "bus3089": "Right", "bus3131": "Right", "t_bus3130_l": "Right", "t_bus2008_l": "Left", "bus2033": "Left", "bus2020": "Left", "t_bus2005_l": "Left", "bus3093": "Right", "bus3079": "Right", "bus3107": "Right", "bus3115": "Right", "bus3153": "Right", "bus3113": "Right", "bus2016": "Right", "bus3160": "Right", "t_bus3023_l": "Right", "bus3005": "Right", "t_bus3101_l": "Right", "bus3091": "Right", "t_bus3135_l": "Right", "t_bus3116_l": "Right", "t_bus3036_l": "Right", "bus3135": "Right", "t_bus3078_l": "Right", "t_bus2052_l": "Left", "bus3059": "Right", "bus3127": "Right", "bus3044": "Right", "bus3147": "Right", "bus3152": "Right", "t_bus3061_l": "Right", "bus2007": "Left", "t_bus2041_l": "Left", "bus3054": "Right", "bus3012": "Right", "t_bus3094_l": "Right", "bus3035": "Right", "t_bus3131_l": "Right", "bus2024": "Left", "t_bus3143_l": "Right", "bus3116": "Right", "bus2034": "Left", "bus3021": "Right", "t_bus2042_l": "Left", "bus3069": "Right", "bus3161": "Right", "t_bus3150_l": "Right", "bus3086": "Right", "bus3138": "Right", "bus3118": "Right", "bus2023": "Left", "bus2006": "Left", "bus3053": "Right", "bus3024": "Right", "bus3031": "Right", "t_bus3149_l": "Right", "bus3057": "Right", "t_bus3054_l": "Right", "t_bus3007_l": "Right", "t_bus3153_l": "Right", "t_bus3154_l": "Right", "t_bus3125_l": "Right", "bus3090": "Right", "t_bus3152_l": "Right", "t_bus2047_l": "Left", "t_bus3108_l": "Right", "bus3011": "Right", "t_bus3128_l": "Right", "bus3071": "Right", "bus2048": "Left", "bus3074": "Right", "bus2045": "Left", "t_bus3127_l": "Right", "t_bus3082_l": "Right", "bus3068": "Right", "bus3067": "Right", "bus3060": "Right", "t_bus3017_l": "Right", "t_bus3099_l": "Right", "bus3034": "Right", "t_bus3045_l": "Right", "bus3015": "Right", "t_bus3098_l": "Right", "t_bus3146_l": "Right", "t_bus2003_l": "Left", "t_bus3062_l": "Right", "t_bus3157_l": "Right", "bus3056": "Right", "bus3087": "Right", "bus3082": "Right", "bus2013": "Left", "t_bus3086_l": "Right", "bus3022": "Right", "t_bus3013_l": "Right", "bus2011": "Left", "bus3085": "Right", "bus3128": "Right", "bus3105": "Right", "bus3142": "Right", "t_bus3145_l": "Right", "t_bus3104_l": "Right", "t_bus3126_l": "Right", "bus3052": "Right", "bus2031": "Left", "bus3076": "Right", "t_bus3047_l": "Right", "t_bus3032_l": "Right", "bus3009": "Right", "t_bus3039_l": "Right", "bus3051": "Right", "t_bus2020_l": "Left", "bus2047": "Left", "t_bus3105_l": "Right", "bus3158": "Right", "t_bus3083_l": "Right", "bus2012": "Left", "bus3065": "Right", "bus3075": "Right", "bus3111": "Right", "bus3139": "Right", "t_bus2037_l": "Left", "bus2010": "Left", "bus2053": "Left", "t_bus3110_l": "Right", "t_bus3064_l": "Right", "bus3018": "Right", "t_bus2046_l": "Left", "bus3030": "Right", "t_bus3137_l": "Right", "bus3088": "Right", "bus2028": "Left", "bus3029": "Right", "bus3106": "Right", "bus2005": "Left", "t_bus3012_l": "Right", "t_bus3020_l": "Right", "t_bus3090_l": "Right", "t_bus2028_l": "Left", "bus3130": "Right", "t_bus3148_l": "Right", "t_bus3159_l": "Right", "t_bus3074_l": "Right", "bus3144": "Right", "t_bus2023_l": "Left", "bus2049": "Left", "t_bus3042_l": "Right", "t_bus3026_l": "Right", "t_bus3095_l": "Right", "bus3110": "Right", "t_bus3050_l": "Right", "t_bus3070_l": "Right", "t_bus3073_l": "Right", "t_bus3063_l": "Right", "bus3109": "Right", "bus3148": "Right", "bus2027": "Left", "bus3154": "Right", "t_bus3021_l": "Right", "bus3078": "Right", "bus3036": "Right", "t_bus3077_l": "Right", "bus3150": "Right", "bus3140": "Right", "bus2054": "Left", "bus2029": "Left", "bus2055": "Left", "t_bus3089_l": "Right", "bus3046": "Right", "t_bus2032_l": "Left", "bus3119": "Right", "bus3108": "Right", "t_bus3103_l": "Right", "t_bus3106_l": "Right", "bus3083": "Right", "bus3006": "Right", "t_bus2030_l": "Left", "t_bus3048_l": "Right", "bus2052": "Left", "bus3103": "Right", "bus3117": "Right", "t_bus3071_l": "Right", "t_bus3038_l": "Right", "bus3124": "Right", "bus2017": "Right", "t_bus2045_l": "Left", "t_bus3139_l": "Right", "bus2008": "Left", "t_bus3151_l": "Right", "bus3095": "Right", "bus2019": "Left", "t_bus2049_l": "Left", "t_bus3115_l": "Right", "bus3129": "Right", "t_bus2025_l": "Left", "t_bus3084_l": "Right", "t_bus2024_l": "Left", "t_bus3162_l": "Right", "t_bus2050_l": "Left", "bus2050": "Left", "bus3039": "Right", "bus3050": "Right", "t_bus3102_l": "Right", "t_bus3057_l": "Right", "t_bus3044_l": "Right", "bus3125": "Right", "t_bus2018_l": "Right", "t_bus2029_l": "Left", "bus3041": "Right", "t_bus2009_l": "Left", "bus3070": "Right", "bus3099": "Right", "t_bus3056_l": "Right", "bus3061": "Right", "t_bus3018_l": "Right", "t_bus3160_l": "Right", "bus3137": "Right", "t_bus2017_l": "Right", "t_bus2035_l": "Left", "t_bus3111_l": "Right", "bus3007": "Right", "bus3058": "Right", "t_bus2022_l": "Left", "bus3028": "Right", "t_bus2051_l": "Left", "t_bus3147_l": "Right", "bus2002": "Left", "t_bus3122_l": "Right", "t_bus3088_l": "Right", "bus3045": "Right", "bus3114": "Right", "t_bus3066_l": "Right", "bus3048": "Right", "bus2041": "Left", "t_bus3041_l": "Right", "t_bus3011_l": "Right", "bus3019": "Right", "bus3143": "Right", "t_bus3144_l": "Right", "t_bus2015_l": "Left", "bus3013": "Right", "bus3136": "Right", "bus2051": "Left", "t_bus3093_l": "Right", "t_bus2053_l": "Left", "bus2032": "Left", "t_bus3072_l": "Right", "t_bus3081_l": "Right", "bus2046": "Left", "t_bus3123_l": "Right", "t_bus3027_l": "Right", "bus3120": "Right", "bus3162": "Right", "bus2038": "Left", "t_bus2034_l": "Left", "t_bus2054_l": "Left", "t_bus2056_l": "Left", "bus3126": "Right", "bus3146": "Right", "bus3145": "Right", "t_bus3142_l": "Right", "bus3157": "Right", "t_bus2011_l": "Left", "t_bus3031_l": "Right", "t_bus3112_l": "Right", "bus3155": "Right", "t_bus3006_l": "Right", "bus2025": "Left", "t_bus3097_l": "Right", "bus3020": "Right", "bus3151": "Right", "t_bus3016_l": "Right", "t_bus3034_l": "Right", "t_bus2043_l": "Left", "bus3097": "Right", "bus3159": "Right", "bus3098": "Right", "t_bus3051_l": "Right", "bus2022": "Left", "bus3027": "Right", "bus3049": "Right", "t_bus3033_l": "Right", "t_bus3134_l": "Right", "t_bus3035_l": "Right", "t_bus3138_l": "Right", "bus3025": "Right", "bus3112": "Right", "t_bus3058_l": "Right", "bus3064": "Right", "t_bus3059_l": "Right", "t_bus3060_l": "Right", "t_bus3091_l": "Right", "t_bus3029_l": "Right", "bus2026": "Left", "bus2035": "Left", "bus3008": "Right", "t_bus3024_l": "Right", "bus3080": "Right", "bus3100": "Right", "bus3023": "Right", "t_bus2010_l": "Left", "bus3096": "Right", "bus2040": "Left", "t_bus3161_l": "Right", "t_bus3010_l": "Right", "bus3132": "Right", "bus3062": "Right", "t_bus3136_l": "Right", "bus2014": "Left", "bus2015": "Left", "t_bus3141_l": "Right", "t_bus3037_l": "Right", "bus3102": "Right", "t_bus3067_l": "Right", "bus2021": "Left", "t_bus2048_l": "Left", "bus3081": "Right", "t_bus2002_l": "Left", "t_bus3052_l": "Right", "bus3032": "Right", "bus3149": "Right", "bus3055": "Right", "t_bus3065_l": "Right", "t_bus3120_l": "Right", "bus2009": "Left", "t_bus3132_l": "Right", "bus3026": "Right", "bus3156": "Right", "bus3141": "Right", "t_bus2014_l": "Left", "bus2037": "Left", "t_bus2016_l": "Right", "t_bus3121_l": "Right", "bus3072": "Right", "bus3101": "Right", "t_bus2031_l": "Left", "bus3094": "Right", "bus2030": "Left", "bus2042": "Left", "bus3123": "Right", "bus3134": "Right", "bus3040": "Right", "t_bus3004_l": "Right", "bus3003": "Right", "t_bus3002_l": "Right", "bus3002": "Right", "bus3004": "Right"}

0 comments on commit 337c4de

Please sign in to comment.