Progress output#
A full-wave run spends most of its wall time before the first field is updated: the mesh is built, the stability time step is measured, and every port’s mode problem is solved. On a two-million-cell model that is well over half a minute of setup. Magnelio reports each of those phases as it runs, so that a long-running call can be told apart from a stalled one.
The switch#
Every long-running operation takes a verbose argument, and the
process-wide default behind it is set once:
import magnelio as mio
mio.set_verbosity(False) # a batch sweep: no output at all
mio.set_verbosity(True) # the default
The argument overrides the default for one call:
mesh = mio.Mesh.from_geometry(model, control, f_max=12e9, verbose=False)
analysis = mio.AnalysisScatteringTD(mesh=mesh, verbose=True)
Leaving verbose unset (None) means follow the process-wide
setting. That is what makes the setting reach nested work: a port
refinement builds a mesh and solves ports once per rung, and those
inner calls inherit your setting rather than being silenced.
What the phases mean#
Output lines are prefixed with the operation reporting them.
mesh | materials | done (1.6 s)
mesh | conformal cells | 795 sections
mesh | conformal cells | done (20.2 s)
mesh | PEC masks | done (0.5 s)
mesh | 131 x 122 x 130 cells (22.4 s total)
mesh follows the mesh build: locating the planes the geometry
demands, generating the grid lines, filling material identities from
cross-sections, classifying partially filled cells, and building the
conductor masks. The two phases missing from the listing above —
finding the feature planes and generating the grid lines — finished
too quickly to be worth a line; see Short phases below.
On a model with curved or free-form surfaces the conformal cell classification dominates, and by a wide margin: the run above is a reflector antenna where it takes 20 of the 22 seconds, because every partially filled cell needs its own cross-section through a curved face. A running count of those cross-sections appears while it works. It is a count and not a percentage on purpose — the phase makes several passes for different material properties, and a percentage would run to 100 and start over, which reads as a stall followed by a restart.
setup | CFL eigenvalue | done (14.1 s)
setup | port 'feed' | done (8.6 s)
setup covers the work between a finished mesh and the first time
step, whether it runs inside run or on its own through
solve_ports. The CFL
eigenvalue is often the surprise here. Magnelio measures the exact
stability limit with an iteration over the whole update operator rather
than estimating it from the cell sizes, which buys a time step several
times larger than the geometric estimate — but it is proportional to
the size of the model, not to the number of ports. A port report on a
large model therefore takes noticeably longer than the ports alone
would suggest. The measured value is cached on the mesh, so inspecting
the ports first and running afterwards pays for it only once:
analysis = mio.AnalysisScatteringTD(mesh=mesh, f_min=8.5e9)
print(analysis.solve_ports()["feed"]) # pays the eigenvalue
result = analysis.run(f_axis=f_axis) # does not pay it again
FIT-TD | 37 k cells | dt 1.32 ps | single on NumPy (CPU) | ≈ 4 MB
FIT-TD | stops at energy -70 dB or port signal -60 dB, cap 388480 steps
FIT-TD | step 2900/∞ | 0.7 s | energy -58.4/-70 dB | 3.9k steps/s
FIT-TD | step 6001/∞ | 1.5 s | energy -70.2/-70 dB | done (energy criterion)
run | finished in 2.6 s
FIT-TD is the time loop. Two lines before the first step say what is
about to run and what will end it: the cell count, the time step, the
precision and the device, and the memory the solver’s own arrays take
(ports, monitors and the absorbing boundary come on top, hence the ≈);
then the stop criteria the run watches and the runtime cap behind them.
While it marches, the line reports the step, a running wall clock, the
quantity the active stop criterion watches — stored energy in dB below
the run peak, or the port-signal envelope — and the step rate. A run
with a fixed step count also shows the estimated time to the end
(ETA); an open-ended run does not, because it ends on a criterion, and
the distance to that is exactly what the dB figure shows. The closing
line keeps the same slots and names the criterion that fired, so it
reads as the last state of the running line.
run closes the analysis call itself. finished in counts from the
start of the call, setup included, and a multi-excitation analysis says
how many runs it made. The same clock is kept on what comes back:
every result carries started, finished and elapsed (the wall time
of the marching), and a project store books them per run, resumes
summed. A checkpoint written on request and a resumed run each get a
line of their own under these labels. All of this is the output of
the process that computes; to follow a run from another process —
a second notebook, a laptop — see Projects and runs.
eigen | factorising at sigma=2.012e+21 (7.14 GHz) | done (14.0 s)
eigen | eigensolve at sigma=2.012e+21 (7.14 GHz) | done (2.7 s)
The shift is reported both as the solver holds it — an eigenvalue of
the curl-curl operator, so (2*pi*f)**2 — and as the frequency it
targets, which is the number to check against your model.
eigen is the cavity eigenmode solver. It reports phases rather than
a percentage, because an eigensolver converges when it converges — but
the phases are informative on their own: the factorisation of the
shifted operator regularly costs several times the iteration that
follows it, and it scales with the mesh, so a slow eigenmode run is
usually asking for a coarser grid rather than more patience.
refine | level 1/1: meshing and solving the port slab
refine | level 1: 684 plane cells, f_cutoff = 6.55527e+09 Δ +0.085 %
refine is the port-plane convergence ladder. Each rung is announced
before it runs and reported with its value and change afterwards, and
the mesh build and port solve of the rung in progress report inside it.
Short phases#
A phase that finishes in under half a second does not report that it
finished. Nothing is gained by learning that five separate steps each
took no measurable time, and a small model — every tutorial, most
tests — would otherwise print a wall of done (0.0 s) lines that say
nothing. A small mesh build therefore reports only its result:
mesh | 14 x 7 x 4 cells
The closing line of an operation carries its total wall time whenever that total is itself worth reporting, so a build with several long phases needs no addition in your head.
Terminals, notebooks and logs#
On a terminal, progress is one line that updates in place a few times a second. A notebook cell redraws such a line the same way, so there the line updates in place too, about twice a second — every refresh is a message to the browser, and that cadence keeps the line live without flooding the connection. Everywhere else — a log file, a CI job, a captured pipe — Magnelio writes whole lines at a slow cadence instead, because overwriting depends on carriage returns that a log file records literally and concatenates into one unreadable row. You do not configure this; it follows from where the output is going.
One consequence worth knowing: redirecting a run to a file gives you a readable record, not a transcript of every refresh.
Work running inside worker processes stays silent. Mesh sectioning and the band port kernel are computed by process pools, and every worker reporting to one terminal would interleave into noise; only the parent process reports.