-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multiple DSS contexts #81
Comments
Where can I find examples for the C API with contexts? |
With multiple dispatch, it's easy to add an optional context that controls the DSS instance. # Normal usage (backwards compatible)
Circuit.SetActiveBus(bus)
v = Bus.Voltages()
# Calling a specific instance
Circuit.SetActiveBus(dss1, bus)
v = Bus.Voltages(dss1) Here's how a definition could look: """Set active bus name"""
function SetActiveBus(BusName::String)::Int
return @checked Lib.Circuit_SetActiveBus(ACTIVECONTEXT, Cstring(pointer(BusName)))
end
function SetActiveBus(dss::TDSSContext, BusName::String)::Int
return @checked Lib.Circuit_SetActiveBus(dss, Cstring(pointer(BusName)))
end |
@kdheepak I added a minimal C sample using OpenMP in https://github.com/dss-extensions/dss_capi/blob/master/examples/ctx_openmp.c Currently every function that depends on the context was duplicated, so we have
Thanks @tshort, I like the idea. It should be easy enough for users to adopt it too. |
I should have mentioned that in DSS Python, to avoid rewriting the code, I wrapped the For C# and C++, it was easier to migrate to the For compatibility, an initial context is always created and it's accessible via |
I was finally looking into this, so I tested the two approaches below. This is large enough that we could merge #88 as a check-point, and open another PR when DSS C-API 0.12.2 is ready. First version is simply updating all functions that need a context to receive the context """Array of strings containing all Load names"""
function AllNames(dss::DSSContext)::Vector{String}
return get_string_array(Lib.Loads_Get_AllNames, dss.ctx)
end
AllNames() = AllNames(DSS_DEFAULT_CTX)
Alternatively, using a macro do modify the function to add the the context argument, macro ctxify(ex::Expr)
ex_org = copy(ex)
fargs = ex.args[1].args[1].args
ex.args[1].args[1].args = [fargs[1]; :(dss::DSSContext); fargs[2:end]]
local found = false
ex_new = postwalk(ex) do x
if (x isa Symbol)
if (String(x) == "C_NULL_CTX")
found = true
return :(dss.ctx)
elseif (String(x) == "@checked")
found = true
return Symbol("@checked_ctx")
end
end
return x
end
if !found
return quote
@__doc__ $ex_org
end |> esc
end
return quote
@__doc__ $ex_org
$ex_new
end |> esc
end
#...
"""Array of strings containing all Load names"""
@ctxify function AllNames()::Vector{String}
return get_string_array(Lib.Loads_Get_AllNames, C_NULL_CTX)
end Since the macro uses Next steps would be to add Julia-specific docs and some examples for both the official Parallel API and multi-threading. A quick one would be to adapt custom_8760_pmap.jl to use multi-threading. I'm adding general notes to https://github.com/dss-extensions/dss-extensions/blob/main/multithreading.md Here, one thing we could recommend is to leave the default engine empty. So if the user accidentally forgets to pass an instance explicitly, that would result in an error sooner or later. Sample codeusing OpenDSSDirect
using OpenDSSDirect.Lib # for SolveModes
println("nthreads:", Threads.nthreads())
Basic.AllowChangeDir(false)
engines = [Basic.NewContext() for _=1:5]
losses = zeros(5)
mults = zeros(5)
@time Threads.@threads for idx in 1:length(engines)
e = engines[idx]
dss(e, "redirect ../electricdss-tst/Version8/Distrib/EPRITestCircuits/ckt5/Master_ckt5.dss")
Solution.LoadMult(e, 1.0 + 0.5 * idx / length(engines))
Solution.Mode(e, Lib.SolveModes_Daily)
Solution.Number(e, 1)
local this_losses = 0;
for n in 1:1000
Solution.Solve(e)
this_losses += real(Circuit.Losses(e))
end
mults[idx] = Solution.LoadMult(e)
losses[idx] = this_losses
end
println("Losses using multiple instances")
println(mults)
println(losses * 1e-6)
losses_main = zeros(5)
mults_main = zeros(5)
@time for idx in 1:length(engines)
dss("redirect ../electricdss-tst/Version8/Distrib/EPRITestCircuits/ckt5/Master_ckt5.dss")
Solution.LoadMult(1.0 + 0.5 * idx / length(engines))
Solution.Mode(Lib.SolveModes_Daily)
Solution.Number(1)
local this_losses = 0;
for n in 1:1000
Solution.Solve()
this_losses += real(Circuit.Losses())
end
mults_main[idx] = Solution.LoadMult()
losses_main[idx] = this_losses
end
println("Losses using the main instance")
println(mults_main)
println(losses_main * 1e-6)
@assert losses_main == losses Sample output with 5 threads
|
DSS C-API 0.12 supports creating multiple DSS instances that can be used separately, in threads, etc.
Should we expose this in ODD.jl? If so, what would be the best approach?
The text was updated successfully, but these errors were encountered: