diff --git a/NEWS.md b/NEWS.md index 9cdb45d..39f3500 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,12 @@ # Release notes +## Unversioned (2026-05-19) + +### Adjustments + +* If coordinates have not been saved to a design file for the nodes under an `Area`, they are now placed *symmetrically* around the circle (that is, accounting for one node being the `GeoAvailability` node to be placed at the center). +* The default value for the radius of the circle for placing nodes without coordinates is now a third of the minimal distance between area coordinates defined in the `top_level` design file. + ## Version 0.7.1 (2026-04-24) ### Bugfix diff --git a/docs/src/figures/EMI_geography.png b/docs/src/figures/EMI_geography.png index 4705b05..1b14210 100644 Binary files a/docs/src/figures/EMI_geography.png and b/docs/src/figures/EMI_geography.png differ diff --git a/docs/src/figures/EMI_geography_Oslo.png b/docs/src/figures/EMI_geography_Oslo.png index 19b5e2d..5c4f2bf 100644 Binary files a/docs/src/figures/EMI_geography_Oslo.png and b/docs/src/figures/EMI_geography_Oslo.png differ diff --git a/src/setup_topology.jl b/src/setup_topology.jl index 9d3c48d..63f8709 100644 --- a/src/setup_topology.jl +++ b/src/setup_topology.jl @@ -44,12 +44,42 @@ function EnergySystemDesign( Dict() end + # Complete the `id_to_color_map` if some products are lacking (this is done by choosing + # colors for the lacking `Resource`s that are most distinct to the existing set of colors) + if !issubset(get_products(system), keys(id_to_color_map)) + id_to_color_map = set_colors(get_products(system), id_to_color_map) + end + + # Initialize components and connections + components = EnergySystemDesign[] + connections = Connection[] + + # Create an iterator for the current system + elements = get_children(system) + + # Calculate radius for node placement if system is a SystemGeo (i.e. contains geographical information) if isa(system, SystemGeo) - # Collect all (lon, lat) coordinates from elements that have them - coords = [ - Point2f(element.lon, element.lat) - for element ∈ get_children(system) - ] + coordinates_missing = false + coords = Point2f[] + for element ∈ elements + # Extract available information from file (stored in the `design_dict` variable) + key::String = string(element) + system_info::Dict = haskey(design_dict, key) ? design_dict[key] : Dict() + if haskey(system_info, "x") && haskey(system_info, "y") + xy = Point2f(system_info["x"], system_info["y"]) + push!(coords, xy) + else + coordinates_missing = true + break + end + end + if coordinates_missing + # Collect all (lon, lat) coordinates from elements that have them + coords = [ + Point2f(element.lon, element.lat) + for element ∈ get_children(system) + ] + end # Compute all pairwise distances min_dist = Inf @@ -66,19 +96,6 @@ function EnergySystemDesign( radius = min_dist / 3 end - # Complete the `id_to_color_map` if some products are lacking (this is done by choosing - # colors for the lacking `Resource`s that are most distinct to the existing set of colors) - if !issubset(get_products(system), keys(id_to_color_map)) - id_to_color_map = set_colors(get_products(system), id_to_color_map) - end - - # Initialize components and connections - components = EnergySystemDesign[] - connections = Connection[] - - # Create an iterator for the current system - elements = get_children(system) - design = EnergySystemDesign( system, id_to_color_map, @@ -99,6 +116,11 @@ function EnergySystemDesign( if !isnothing(elements) current_node::Int64 = 1 nodes_count = length(get_children(system)) + if !isa(parent, NothingDesign) && isa(get_system(parent), SystemGeo) + # If the parent is a SystemGeo, we subtract one to the nodes count to account + # for the availability node that is placed in the center + nodes_count -= 1 + end # Loop through all components of `system` for element ∈ elements diff --git a/src/utils_gen/structures_utils.jl b/src/utils_gen/structures_utils.jl index 3d0f12f..c8278dc 100644 --- a/src/utils_gen/structures_utils.jl +++ b/src/utils_gen/structures_utils.jl @@ -15,13 +15,13 @@ function installed() end """ - place_nodes_in_circle(total_nodes::Int64, current_node::Int64, r::Float32, c::Point2f) + place_nodes_in_circle(n::Int64, i::Int64, r::Float32, c::Point2f) Return coordinate for point number `i` of a total of `n` points evenly distributed around a circle of radius `r` centered at `c` from -π/4 to 5π/4. """ function place_nodes_in_circle(n::Int64, i::Int64, r::Float32, c::Point2f) - θ::Float32 = n == 1 ? π32 : -π32 / 4 + 3π32 / 2 * (1 - (i - 1) / (n - 1)) + θ::Float32 = n == 1 ? π32 : -π32 / 4 + 3π32 / 2 * (1 - Float32(i - 1) / Float32(n - 1)) return c + r * Point2f(cos(θ), sin(θ)) end