163 def of(cls, session:
"Session") ->
"NetworkTrace":
164 """The static description of ``session``'s network, columns empty."""
165 built = session.model.built
167 diagram = session.model.diagram
168 symbols = {n.id: n
for n
in diagram.nodes}
169 edges = {e.id
for e
in diagram.edges}
172 ports = built.engine_ports
173 injector_of: dict[str, str] = {}
174 inlets: dict[str, str] = {}
175 for side, key
in ((
"ox",
"oxidiser"), (
"fuel",
"fuel")):
176 branch_id = ports.get(key,
"")
177 if branch_id
in net.branches:
178 injector_of[branch_id] = side
179 inlets[net.branches[branch_id].upstream] = side
181 vessels = {sim.ullage_node
for sim
in session.tanks.values()}
182 vessels |= {sim.outlet_node
for sim
in session.tanks.values()}
183 vessels |= {b.node
for b
in session.bottles.values()}
184 fixed = {n
for n, node
in net.nodes.items()
if node.pressure
is not None}
186 def phase_of(node_id: str) -> str:
187 phase = net.nodes[node_id].phase
188 if phase
in (
"gas",
"liquid"):
190 return "gas" if node_id == chamber
else "liquid"
193 adjacency: dict[str, list[tuple[str, str, bool]]] = {n: []
for n
in net.nodes}
194 for branch_id, branch
in net.branches.items():
195 adjacency[branch.upstream].
append((branch.downstream, branch_id,
True))
196 adjacency[branch.downstream].
append((branch.upstream, branch_id,
False))
200 tank_side: dict[str, str] = {}
201 liquid_reach: dict[str, set[str]] = {}
202 for tank_id, sim
in session.tanks.items():
206 lambda n: phase_of(n) ==
"liquid" and n
not in fixed,
208 liquid_reach[tank_id] = reach
209 side = next((inlets[n]
for n
in reach
if n
in inlets),
"")
213 species =
_normal(net.nodes[sim.outlet_node].fluid)
214 side =
"ox" if species
in OXIDISERS
else "fuel"
215 tank_side[tank_id] = side
217 node_side: dict[str, str |
None] = {}
218 for tank_id, reach
in liquid_reach.items():
219 for node_id
in reach:
220 node_side.setdefault(node_id, tank_side[tank_id])
221 for node_id
in net.nodes:
222 if node_id
in node_side:
224 if node_id == chamber:
225 node_side[node_id] =
None
226 elif node_id
in inlets:
227 node_side[node_id] = inlets[node_id]
228 elif phase_of(node_id) ==
"gas":
229 node_side[node_id] =
"gas"
231 node_side[node_id] =
None
234 for node_id
in net.nodes:
235 if node_side[node_id]
is None and node_id
in fixed
and node_id != chamber:
238 for far, _, _
in adjacency[node_id]
239 if node_side.get(far)
in (
"ox",
"fuel")
242 node_side[node_id] = near[0]
245 bottles = {b.node
for b
in session.bottles.values()}
246 ullages = {sim.ullage_node: tank_id
for tank_id, sim
in session.tanks.items()}
247 outlets = {sim.outlet_node: tank_id
for tank_id, sim
in session.tanks.items()}
248 for node_id, node
in net.nodes.items():
251 label=
_node_label(node_id, symbols, ullages, outlets, chamber, inlets),
253 node_id, symbols, bottles, ullages, outlets, chamber, inlets, fixed
255 side=node_side.get(node_id),
256 phase=phase_of(node_id),
259 for branch_id, branch
in net.branches.items():
260 component = branch.component
261 symbol = symbols.get(branch_id)
262 if branch_id
in injector_of:
264 label = f
"{injector_of[branch_id]} injector"
265 elif symbol
is not None:
267 label = symbol.label
or branch_id
269 kind = COMPONENT_KINDS.get(getattr(component,
"type",
""),
"line")
270 label = branch_id
if branch_id
in edges
else str(component.id)
271 ends = (branch.upstream, branch.downstream)
273 node_side[n]
for n
in ends
if node_side.get(n)
in (
"ox",
"fuel")
275 if branch_id
in injector_of:
276 branch_side: str |
None = injector_of[branch_id]
278 branch_side = liquid_sides[0]
279 elif all(node_side.get(n) ==
"gas" for n
in ends):
283 params = getattr(component,
"p", {})
or {}
284 cv = params.get(
"Cv")
290 upstream=branch.upstream,
291 downstream=branch.downstream,
293 cv=float(cv)
if cv
is not None else None,
297 trace._flow_terms[branch_id] = ((branch_id, 1.0),)
299 trace._state_keys[branch_id] = keys
303 for tank_id, sim
in session.tanks.items():
304 head = f
"{tank_id}{HEAD}"
305 label = symbols[tank_id].label
if tank_id
in symbols
else tank_id
308 label=f
"{label or tank_id} liquid head",
310 upstream=sim.ullage_node,
311 downstream=sim.outlet_node,
312 side=tank_side[tank_id],
316 terms: list[tuple[str, float]] = []
317 for branch_id, branch
in net.branches.items():
318 if branch.upstream == sim.outlet_node:
319 terms.append((branch_id, 1.0))
320 elif branch.downstream == sim.outlet_node:
321 terms.append((branch_id, -1.0))
322 trace._flow_terms[head] = tuple(terms)
325 for tank_id, sim
in session.tanks.items():
326 path_side = tank_side[tank_id]
327 if path_side
in trace.paths:
333 lambda n: phase_of(n) ==
"gas" and n
not in fixed,
340 lambda n: n
not in fixed
and phase_of(n) ==
"liquid",
346 list(gas
or []) + [(f
"{tank_id}{HEAD}",
True)] + list(liquid_leg
or [])
348 for branch_id, forward
in steps:
349 if not forward
and not trace.branches[branch_id].reversed:
350 trace._reverse(branch_id)
351 trace.paths[path_side] = [branch_id
for branch_id, _
in steps]
353 for node_id
in trace.nodes:
354 trace.pressure[node_id] = []
355 trace.temperature[node_id] = []
356 for branch_id, info
in trace.branches.items():
357 trace.mdot[branch_id] = []
358 trace.dp[branch_id] = []
360 trace.state[branch_id] = []