// Phase 4: time nodes (Delay and Queue).
//
// Delay: pulls along incoming edges each step, holds the amount for `param`
// steps, then releases it along outgoing edges (a fixed-length delay
// line). param <= 0 behaves as a 1-step delay.
// Queue: pulls into a single store and releases up to `param` per step (FIFO).
//
// Released amounts are distributed across outgoing edges by weight (same
// largest-remainder split as gates); overflow beyond capacity is dropped.
///|
fn process_time_nodes(
diagram : Diagram,
state : SimState,
work : Array[Int],
flows : Array[Int],
) -> Unit {
let edges = diagram.resources
for ni in 0.. true
_ => false
}
let is_queue = match node.kind {
Queue => true
_ => false
}
if (!is_delay && !is_queue) || !node_active(diagram, state, ni) {
continue
}
// Pull from incoming edges.
let mut incoming = 0
for ei in 0..
effective_rate(diagram, state, ei, resolve_rate(e.rate, state, 0))
_ =>
effective_rate(
diagram,
state,
ei,
resolve_rate(e.rate, state, work[e.from]),
)
}
let avail = match from.kind {
Source => want
_ => work[e.from]
}
let mut amt = if want < avail { want } else { avail }
if amt < 0 {
amt = 0
}
match from.kind {
Source => ()
_ => work[e.from] = work[e.from] - amt
}
incoming = incoming + amt
flows[ei] = amt
}
// Advance the buffer and compute the released amount.
let buf = state.buffers[ni]
let mut release = 0
if is_delay {
let d = buf.length()
if d > 0 {
release = buf[0]
for i in 0..<(d - 1) {
buf[i] = buf[i + 1]
}
buf[d - 1] = incoming
} else {
release = incoming
}
} else {
buf[0] = buf[0] + incoming
let r = if node.param > 0 { node.param } else { 1 }
release = if buf[0] < r { buf[0] } else { r }
buf[0] = buf[0] - release
}
// Distribute the release across outgoing edges.
let out_idx : Array[Int] = []
let weights : Array[Double] = []
for ei in 0.. {
let room = cap - work[edges[ei].to]
if place > room {
place = room
}
}
None => ()
}
if place < 0 {
place = 0
}
match to.kind {
Drain | Source => ()
_ => work[edges[ei].to] = work[edges[ei].to] + place
}
flows[ei] = place
}
}
}