| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- @enum Structure LI HI HO HOmod
- translate = (msg::A2A) -> (A2A(msg.activate))
- # Port Config
- function setup_ports!(top_model::CoupledDEVS, type::Structure)
- has_out_port = type in (HI, HO, HOmod)
- add_in_port!(top_model, :i_in)
- if has_out_port
- add_out_port!(top_model, :o_out)
- end
- if type in (HO, HOmod)
- add_in_port!(top_model, :i_in2)
- end
- if type == HO
- add_out_port!(top_model, :o_out2)
- end
- return has_out_port
- end
- function build_leaf_node(name::String, type::Structure, int_delay::Float64, ext_delay::Float64, stats::Bool)
- top_model = CoupledDEVS(name)
- has_out_port = setup_ports!(top_model, type)
- p_time = round(rand() + 1.0, digits=3)
- atom = add_submodel!(top_model, "A0", DelayedAtomic;
- inbox=(; i_in=A2A[]),
- out_ports=has_out_port ? (; o_out=A2A) : (;),
- int_delay=int_delay, ext_delay=ext_delay, prep_time=p_time,
- has_out_port=has_out_port, stats=stats)
- connect!(top_model, self.i_in, atom.i_in; Z=translate)
- if has_out_port
- connect!(top_model, atom.o_out, self.o_out; Z=translate)
- end
- return top_model
- end
- # Create Atomics (LI, HI, HO)
- function build_atomics!(top_model::CoupledDEVS, depth::Int, width::Int, int_delay::Float64, ext_delay::Float64, has_out_port::Bool, stats::Bool)
- width_models = ModelRef[]
- for idx in 0:(width - 2)
- p_time = 1.0 - round(rand() * (0.5 / width) + (idx / width), digits=3)
- atomic_name = "A$(idx)"
- atom = add_submodel!(top_model, atomic_name, DelayedAtomic;
- inbox=(; i_in=A2A[]),
- out_ports=has_out_port ? (; o_out=A2A) : (;),
- int_delay=int_delay, ext_delay=ext_delay, prep_time=p_time,
- has_out_port=has_out_port, stats=stats)
- push!(width_models, atom)
- end
- return width_models
- end
- # Routing
- function route_LI!(top_model::CoupledDEVS, width_models::Vector{ModelRef})
- for atom in width_models
- connect!(top_model, self.i_in, atom.i_in; Z=translate)
- end
- end
- function route_HI!(top_model::CoupledDEVS, width_models::Vector{ModelRef})
- for atom in width_models
- connect!(top_model, self.i_in, atom.i_in; Z=translate)
- end
- for i in 1:(length(width_models) - 1)
- connect!(top_model, width_models[i].o_out, width_models[i + 1].i_in; Z=translate)
- end
- end
- function route_HO!(top_model::CoupledDEVS, width_models::Vector{ModelRef})
- for i in 1:(length(width_models) - 1)
- curr_atom = width_models[i]
- next_atom = width_models[i + 1]
- connect!(top_model, curr_atom.o_out, next_atom.i_in; Z=translate)
- connect!(top_model, self.i_in2, curr_atom.i_in; Z=translate)
- connect!(top_model, curr_atom.o_out, self.o_out2; Z=translate)
- end
- if !isempty(width_models)
- last_atom = width_models[end]
- connect!(top_model, self.i_in2, last_atom.i_in; Z=translate)
- connect!(top_model, last_atom.o_out, self.o_out2; Z=translate)
- end
- end
- # Create HOmod Structure---
- function build_HOmod!(top_model::CoupledDEVS, child::ModelRef, depth::Int, width::Int, int_delay::Float64, ext_delay::Float64, stats::Bool)
- if width < 2
- return
- end
- atomics = Dict{Int, Vector{ModelRef}}()
- # create grid
- for i in 0:(width - 1)
- atomics[i] = ModelRef[]
- min_row_idx = i < 2 ? 0 : i - 1
- for j in min_row_idx:(width - 2)
- atomic_name = "A$(i)_$(j)"
- atom = add_submodel!(top_model, atomic_name, DelayedAtomic;
- inbox=(; i_in=A2A[]),
- out_ports=(; o_out=A2A),
- int_delay=int_delay, ext_delay=ext_delay, prep_time=1.0,
- has_out_port=true, stats=stats)
- push!(atomics[i], atom)
- end
- end
- for atom in atomics[0]
- connect!(top_model, self.i_in2, atom.i_in; Z=translate)
- end
- for i in 1:(width - 1)
- if !isempty(atomics[i])
- connect!(top_model, self.i_in2, atomics[i][1].i_in; Z=translate)
- end
- end
- for atom in atomics[0]
- connect!(top_model, atom.o_out, child.i_in2; Z=translate)
- end
- if haskey(atomics, 1) && haskey(atomics, 0)
- for atom1 in atomics[1]
- for atom0 in atomics[0]
- connect!(top_model, atom1.o_out, atom0.i_in; Z=translate)
- end
- end
- end
- for i in 2:(width - 1)
- for j in 1:length(atomics[i])
- connect!(top_model, atomics[i][j].o_out, atomics[i-1][j+1].i_in; Z=translate)
- end
- end
- end
- function build_devstone(type::Structure, name::String, depth::Int, width::Int, int_delay::Float64, ext_delay::Float64, stats::Bool=false)
- if depth < 1 || width < 1
- error("Invalid depth or width")
- end
- # Base Case
- if depth == 1
- return build_leaf_node(name, type, int_delay, ext_delay, stats)
- end
- # Recursive
- top_model = CoupledDEVS(name)
- has_out_port = setup_ports!(top_model, type)
- coupled_name = "C$(depth - 1)"
- child_coupled = build_devstone(type, coupled_name, depth - 1, width, int_delay, ext_delay, stats)
- child = add_submodel!(top_model, coupled_name, child_coupled)
- # Connect Parent to Child
- connect!(top_model, self.i_in, child.i_in; Z=translate)
- if type == HO
- connect!(top_model, self.i_in, child.i_in2; Z=translate)
- end
- if has_out_port
- connect!(top_model, child.o_out, self.o_out; Z=translate)
- end
- # Sub-topology Generation & Routing
- if type == HOmod
- build_HOmod!(top_model, child, depth, width, int_delay, ext_delay, stats)
- else
- width_models = build_atomics!(top_model, depth, width, int_delay, ext_delay, has_out_port, stats)
- if type == LI
- route_LI!(top_model, width_models)
- elseif type == HI
- route_HI!(top_model, width_models)
- elseif type == HO
- route_HO!(top_model, width_models)
- end
- end
- return top_model
- end
|