Skip to content
Snippets Groups Projects
Commit cc449190 authored by Julian Stürmer's avatar Julian Stürmer
Browse files

Add logging using Memento.jl

parent cbc014c6
No related branches found
No related tags found
No related merge requests found
...@@ -12,6 +12,7 @@ FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549" ...@@ -12,6 +12,7 @@ FileIO = "5789e2e9-d7fb-5bc7-8068-2c6fae9b9549"
Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9" Ipopt = "b6b21f68-93f8-5de0-b562-5493be1d77c9"
JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819"
LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" LaTeXStrings = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
Memento = "f28f55f0-a522-5efc-85c2-fe41dfb9b2d9"
NetCDF = "30363a11-5582-574a-97bb-aa9a979735b9" NetCDF = "30363a11-5582-574a-97bb-aa9a979735b9"
PowerModels = "c36e90e8-916a-50a6-bd94-075b64ef4655" PowerModels = "c36e90e8-916a-50a6-bd94-075b64ef4655"
PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0"
......
module ITCPG module ITCPG
#* Used packages #*------------------------------------------------------------------------------
#* Use packages
using CSV using CSV
using DataFrames using DataFrames
...@@ -14,8 +15,31 @@ using LaTeXStrings ...@@ -14,8 +15,31 @@ using LaTeXStrings
using DataStructures using DataStructures
using NetCDF using NetCDF
using Statistics using Statistics
using Memento
using Suppressor using Suppressor
#*------------------------------------------------------------------------------
#* Setup logger for generating .log files during simulations
function __init__()
### Setup logger (PowerModels.jl logger will inherit the format)
global _LOGGER = Memento.config!(
"info", fmt="[{date} | {level} | {name}]: {msg}"
)
end
#=
Changes the logger level to the passed level. Common options are "info" (default) and "debug" (additional logs for debugging)
=#
function config_logger(level="info")
info(_LOGGER, "Logger level set to $(level)!")
setlevel!(_LOGGER, level)
return nothing
end
export config_logger
#*------------------------------------------------------------------------------
#* Include other code files and export functions #* Include other code files and export functions
include("Data.jl") include("Data.jl")
......
...@@ -153,53 +153,42 @@ Calculates the total impact of a hurricane given a time series of damaged transm ...@@ -153,53 +153,42 @@ Calculates the total impact of a hurricane given a time series of damaged transm
function calc_total_impact!( function calc_total_impact!(
network_data::Dict{String,<:Any}, network_data::Dict{String,<:Any},
tl_damage::Array{Tuple{String,Int64},1}; # time series of tl damage tl_damage::Array{Tuple{String,Int64},1}; # time series of tl damage
method = :JuMP, # solver to use method = :JuMP, # solver to use (:JuMP or :NLsolve)
print_level = 5, # Ipopt output details print_level = 5, # level of detail for Ipopt output
outputpath = "", # path for saving solver terminal output logpath = "", # optional path to .log file for saving logs of interest
savepath = "", # path for saving final network data dictionary solpath = "" # path for saving results/solutions of interest
) )
if isempty(outputpath) == true # calculate cascade without saving output ### Check whether a .log file is passed for logging
_calc_total_impact!( if isempty(logpath) == false
network_data, tl_damage, method=method, print_level=print_level # push!(_LOGGER, DefaultHandler(logpath)) # add .log file to logger
) ### Add .log file to logger and set format
else # calculate cascade and save output push!(_LOGGER,
output = @capture_out _calc_total_impact!( DefaultHandler(
network_data, tl_damage, method=method, print_level=print_level logpath, DefaultFormatter("[{date} | {level} | {name}]: {msg}")
)
) )
### Write terminal output of solver into file
open(outputpath, "w") do io
write(io, output)
end
end end
if isempty(savepath) == false # save final network data ### Get unique frames in which transmission lines are damaged by the wind
save(savepath, "network_data", network_data)
end
return nothing
end
#=
See calc_total_impact!
=#
function _calc_total_impact!(
network_data::Dict{String,<:Any},
tl_damage::Array{Tuple{String,Int64},1}; # time series of tl damage
method = :JuMP, # solver to use
print_level = 0 # Ipopt output
)
### Get unique frames in which transmission lines were damaged
unique_frames = sort(unique([tl_damage[i][2] for i in 1:length(tl_damage)])) unique_frames = sort(unique([tl_damage[i][2] for i in 1:length(tl_damage)]))
### Go through frames in which transmission lines were destroyed ### Go through frames and calculate cascading failures
for f in unique_frames for f in unique_frames
### Deactivate transmission lines destroyed in frame f and log them
destroyed_tl = [dmg[1] for dmg in tl_damage if dmg[2] == f] destroyed_tl = [dmg[1] for dmg in tl_damage if dmg[2] == f]
destroy_tl!(network_data, destroyed_tl) destroy_tl!(network_data, destroyed_tl) # update network topology
info(_LOGGER,
"Overhead transmission lines destroyed in wind frame $f: " *
"$destroyed_tl"
) # log destroyed transmission lines
### Recalculate AC-PF and see whether a cascade unfolds
calc_cascade!(network_data, method, print_level, logpath, solpath)
end
### Resolve AC-PF and see whether a cascade unfolds if isempty(solpath) == false # save final network data
calc_cascade!(network_data, method, print_level) save(solpath, "network_data", network_data)
end end
return nothing return nothing
...@@ -209,42 +198,67 @@ end ...@@ -209,42 +198,67 @@ end
Calculates whether a cascading failure unfolds in a damaged network. If any network contained in network_data misses a slack bus, the largest generator is selected in each connected component. Additionally, the active power balance is restored for each connected component in every step, if it is violated. Calculates whether a cascading failure unfolds in a damaged network. If any network contained in network_data misses a slack bus, the largest generator is selected in each connected component. Additionally, the active power balance is restored for each connected component in every step, if it is violated.
=# =#
function calc_cascade!( function calc_cascade!(
network_data::Dict{String,<:Any}, network_data::Dict{String,<:Any}, # network with destroyed lines
method = :JuMP, method = :JuMP,
print_level = 0 print_level = 5, # level of detail for Ipopt output
logpath = "", # optional path to .log file for saving logs of interest
solpath = "" # path for saving results/solutions of interest
) )
### Update network topology (remove dangling buses etc.) ### Treat all connected components (restore APB, define new slacks etc.)
# simplify_network!(network_data) # treat_connected_components!(network_data, options, infopath, solpath)
### Define new slacks, if necessary ### Define new slacks, if necessary
correct_reference_buses!(network_data) correct_reference_buses!(network_data)
### Restore active power balance ### Restore active power balance
restore_p_balance!(network_data) restore_p_balance!(network_data)
### Calculate new AC-PF solution ### Calculate new AC-PF solution
set_ac_pf_start_values!(network_data) # last state as initial conditions set_ac_pf_start_values!(network_data) # last state as initial conditions
calc_ac_pf!(network_data, method, print_level=print_level)
### Check whether to write Ipopt output to a .log file
if isempty(logpath) == false
output = @capture_out calc_ac_pf!(
network_data, method, print_level=print_level
)
info(_LOGGER, output) # pass Ipopt output to logger
else
calc_ac_pf!(network_data, method, print_level=print_level)
end
### Check for overloaded branches ### Check for overloaded branches
overloaded_br = get_branches(network_data, min_loading=1.) overloaded_br = get_branches(network_data, min_loading=1.)
if isempty(overloaded_br) == false if isempty(overloaded_br) == false
### Print overloaded branches as output ### Log overloaded branches
println("-------------------------------------------------------------") info(_LOGGER, "The following branches are overloaded: $overloaded_br")
println("Overloaded branches:", overloaded_br)
println("-------------------------------------------------------------")
### Deactivate overloaded branches ### Deactivate overloaded branches
disable_branches!(network_data, [br[1] for br in overloaded_br]) disable_branches!(network_data, [br[1] for br in overloaded_br])
### Repeat cascade algorithm ### Repeat cascade algorithm
calc_cascade!(network_data, method, print_level) calc_cascade!(network_data, method, print_level, logpath, solpath)
end end
return nothing return nothing
end end
function treat_connected_components!(
network_data::Dict{String,<:Any}, # network with destroyed lines
options::Dict{String,<:Any}, # dictionary with simulation options
infopath::String, # name of .txt file for saving information of interest
solpath::String # path for saving results of interest (solutions)
)
### Calculate connected components
connected_components = calc_connected_components(network_data)
### Define new slacks and restore APB's, if necessary
for cc in connected_components
correct_slack_buses!(network_data, cc)
rebalance_active_power!(network_data, cc)
end
end
#= #=
Identifies connected components in the network and restores active power balance in each component. Identifies connected components in the network and restores active power balance in each component.
=# =#
...@@ -253,8 +267,8 @@ function restore_p_balance!(network_data::Dict{String,<:Any}) ...@@ -253,8 +267,8 @@ function restore_p_balance!(network_data::Dict{String,<:Any})
connected_components = calc_connected_components(network_data) connected_components = calc_connected_components(network_data)
### Restore active power balance for every connected component ### Restore active power balance for every connected component
for cc in connected_components for (cc_i, cc) in enumerate(connected_components)
_restore_p_balance!(network_data, cc) _restore_p_balance!(network_data, cc, cc_i)
end end
### Update network topology (remove dangling buses etc.) ### Update network topology (remove dangling buses etc.)
...@@ -266,7 +280,11 @@ end ...@@ -266,7 +280,11 @@ end
#= #=
Restores active power balance in a connected component identified by the set of buses cc. Depending on whether an overproduction or underproduction exists, generator dispatches may be increased or reduced. If necessary, load can be shed by reducing the demands uniformly until the total demand matches generation. For more details see flow chart. Restores active power balance in a connected component identified by the set of buses cc. Depending on whether an overproduction or underproduction exists, generator dispatches may be increased or reduced. If necessary, load can be shed by reducing the demands uniformly until the total demand matches generation. For more details see flow chart.
=# =#
function _restore_p_balance!(network_data::Dict{String,<:Any}, cc::Set{Int64}) function _restore_p_balance!(
network_data::Dict{String,<:Any},
cc::Set{Int64},
cc_i::Int64 # index/number of connected component cc
)
active_cc_gens = Int64[ active_cc_gens = Int64[
gen["index"] for gen in values(network_data["gen"]) if gen["index"] for gen in values(network_data["gen"]) if
gen["gen_bus"] cc && gen["gen_status"] != 0 gen["gen_bus"] cc && gen["gen_status"] != 0
...@@ -282,9 +300,14 @@ function _restore_p_balance!(network_data::Dict{String,<:Any}, cc::Set{Int64}) ...@@ -282,9 +300,14 @@ function _restore_p_balance!(network_data::Dict{String,<:Any}, cc::Set{Int64})
network_data, active_cc_gens, active_cc_loads, cc network_data, active_cc_gens, active_cc_loads, cc
) )
info(_LOGGER, "Active power mismatch in CC #$cc_i: $cc_Δp")
if isapprox(cc_Δp, 0, atol=1e-10) # "sufficient" power balance if isapprox(cc_Δp, 0, atol=1e-10) # "sufficient" power balance
nothing # nothing has to be done nothing # nothing has to be done
elseif cc_Δp > 0 # overproduction elseif cc_Δp > 0 # overproduction
debug(_LOGGER, "Overproduction in CC #$cc_i: $cc_Δp")
if isapprox(cc_Δp_lim, 0, atol=1e-10) # power balance at minimum if isapprox(cc_Δp_lim, 0, atol=1e-10) # power balance at minimum
### Set all active generators to their minimum ### Set all active generators to their minimum
for g in active_cc_gens for g in active_cc_gens
...@@ -412,6 +435,8 @@ function _reduce_p_dispatch!( ...@@ -412,6 +435,8 @@ function _reduce_p_dispatch!(
) # repeat ) # repeat
end end
# info(_LOGGER, "2 Active power mismatch in CC #1: $cc_Δp")
return nothing return nothing
end end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment