diff --git a/Project.toml b/Project.toml
index 7e2b825f..2e70000e 100644
--- a/Project.toml
+++ b/Project.toml
@@ -6,6 +6,7 @@ version = "0.4.0"
[deps]
CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
+EzXML = "8f5d6c58-4d21-5cfd-889c-e3ad7ee6a615"
Graphs = "86223c79-3864-5bf0-83f7-82e725a168b6"
HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
diff --git a/src/io.jl b/src/io.jl
index a5ed963b..00e3a3f9 100644
--- a/src/io.jl
+++ b/src/io.jl
@@ -1,5 +1,7 @@
export create_parameters_and_sets_from_file,
- create_graph, save_solution_to_file, compute_rp_partitions
+ create_graph, save_solution_to_file, compute_rp_partitions, read_esdl, read_esdl_assets
+
+using EzXML
"""
parameters, sets = create_parameters_and_sets_from_file(input_folder)
@@ -372,3 +374,70 @@ function compute_rp_partitions(df, elements, time_steps_per_rp)
return rp_partitions
end
+
+"""
+ read_esdl(file_path; instance_name)
+
+Read an ESDL file to construct the flow graph and link the related
+assets and flows from the specification
+
+An ESDL file can contain multiple instances. If multiple instances
+are present in the file, a specific instance has to be selected.
+"""
+function read_esdl(file_path; instance_name = nothing)
+ esdl_assets = read_esdl_assets(file_path; instance_name = instance_name)
+
+ # Gather all in-ports
+ id_to_index = Dict{String,Int}()
+ for (to_id, asset) in enumerate(esdl_assets)
+ for port in eachelement(asset)
+ if port.name != "port" || port["xsi:type"] != "esdl:InPort"
+ continue
+ end
+ id_to_index[port["id"]] = to_id
+ end
+ end
+
+ # Create graph based on out-ports and previously gathered in-ports
+ graph = Graphs.DiGraph(length(esdl_assets))
+ for (from_id, asset) in enumerate(esdl_assets)
+ for port in eachelement(asset)
+ if port.name != "port" || port["xsi:type"] != "esdl:OutPort"
+ continue
+ end
+ flows = eachsplit(port["connectedTo"], " ")
+ for flow in flows
+ if !haskey(id_to_index, flow)
+ # throw(ErrorException("No InPort with id '$flow' was found"))
+ println("No InPort with id '$flow' was found, ignoring...")
+ continue
+ end
+ to_id = id_to_index[flow]
+ Graphs.add_edge!(graph, from_id, to_id)
+ end
+ end
+ end
+
+ return graph
+end
+
+function read_esdl_assets(file_path; instance_name = nothing)
+ doc = readxml(file_path)
+ doc_root = root(doc)
+ if countelements(doc_root) == 0 || firstelement(doc_root).name != "instance"
+ throw(ErrorException("no instance was found in given ESDL file"))
+ elseif isnothing(instance_name)
+ if countelements(doc_root) > 1
+ throw(
+ ErrorException(
+ "multiple instances found in file, but no instance_name was given",
+ ),
+ )
+ else
+ instance_name = firstelement(doc_root)["name"]
+ end
+ end
+
+ # Use XPath expression to find all assets under the instance with name `instance_name`
+ return findall("//instance[@name='$instance_name']//asset", doc)
+end
diff --git a/test/esdl/no_instance.esdl b/test/esdl/no_instance.esdl
new file mode 100644
index 00000000..fa32cec3
--- /dev/null
+++ b/test/esdl/no_instance.esdl
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/test/esdl/one_instance.esdl b/test/esdl/one_instance.esdl
new file mode 100644
index 00000000..11175efe
--- /dev/null
+++ b/test/esdl/one_instance.esdl
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/esdl/two_instances.esdl b/test/esdl/two_instances.esdl
new file mode 100644
index 00000000..765d0ae5
--- /dev/null
+++ b/test/esdl/two_instances.esdl
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/runtests.jl b/test/runtests.jl
index aafb892c..87cdb1e1 100644
--- a/test/runtests.jl
+++ b/test/runtests.jl
@@ -7,6 +7,7 @@ using Test
# Folders names
const INPUT_FOLDER = joinpath(@__DIR__, "inputs")
const OUTPUT_FOLDER = joinpath(@__DIR__, "outputs")
+const ESDL_FOLDER = joinpath(@__DIR__, "esdl")
# Add run all test files in test folder
include("test-io.jl")
diff --git a/test/test-io.jl b/test/test-io.jl
index 12a73d3b..293a54d7 100644
--- a/test/test-io.jl
+++ b/test/test-io.jl
@@ -57,3 +57,39 @@ end
@test_throws AssertionError TEM._parse_rp_partition(Val(:math), "3x4", 1:14)
end
end
+
+@testset "ESDL parsing" begin
+ @testset "instance detection error handling" begin
+ @testset "no instance" begin
+ @test_throws ErrorException read_esdl_assets(
+ joinpath(ESDL_FOLDER, "no_instance.esdl"),
+ )
+ end
+
+ @testset "two instances" begin
+ @test_throws ErrorException read_esdl_assets(
+ joinpath(ESDL_FOLDER, "two_instances.esdl"),
+ )
+ end
+ end
+
+ @testset "instance asset parsing" begin
+ @testset "unnamed single instance" begin
+ assets = read_esdl_assets(joinpath(ESDL_FOLDER, "one_instance.esdl"))
+ @test length(assets) == 8
+ end
+
+ @testset "named instance out of multiple" begin
+ flat_assets = read_esdl_assets(
+ joinpath(ESDL_FOLDER, "two_instances.esdl");
+ instance_name = "Flat",
+ )
+ @test length(flat_assets) == 4
+ nested_assets = read_esdl_assets(
+ joinpath(ESDL_FOLDER, "two_instances.esdl");
+ instance_name = "Nested",
+ )
+ @test length(nested_assets) == 10
+ end
+ end
+end