Communication with MAD-NG

Protocol Overview

PyMAD-NG communicates with MAD-NG using a pipe-based protocol, ensuring efficient, direct, two-way communication between the Python and MAD-NG processes.

Key points:

  • Data is sent through FIFO pipes (first-in, first-out).

  • Commands are sent as MAD-NG script strings (Lua-like).

  • Data is retrieved via {func}MAD.recv() after explicit instruction to send it.

  • MAD-NG stdout is redirected to Python, but not intercepted.

Important

You must always send instructions before sending data, and send a request before receiving data.

Example: Basic Communication

from pymadng import MAD
mad = MAD()

mad.send("a = py:recv()")   # Tell MAD-NG to receive
mad.send(42)                # Send the value
mad.send("py:send(a)")     # Request it back
mad.recv()                  # Receive the value → 42

Both MAD.send() and MAD.recv() are the core communication methods. See the pymadng.MAD reference for more details.


Supported Data Types

The following types can be sent from Python to MAD-NG:

Table 1 Supported Send Types

Python Type

MAD-NG Type

Function to Use

None, str, int, float, complex, bool, list

Various

MAD.send()

numpy.ndarray (float64)

matrix

MAD.send()

numpy.ndarray (complex128)

cmatrix

MAD.send()

numpy.ndarray (int32)

imatrix

MAD.send()

range

irange

MAD.send()

start, stop, size as float, int

range, logrange

mad.send_rng(), mad.send_lrng()

Complex structures (e.g., TPSA, CTPSA)

TPSA, CTPSA

mad.send_tpsa(), mad.send_ctpsa()

For full compatibility, see the pymadng.MAD documentation.


Converting TFS Tables to DataFrames

If you use twiss() or survey(), MAD-NG returns an mtable, which can be converted to a Pandas or TFS-style DataFrame:

mtbl = mad.twiss(...)
df = mtbl.to_df()  # Either DataFrame or TfsDataFrame

If the object is not an mtable, a TypeError will be raised.

Note

tfs-pandas (if installed) will enhance the output with headers and metadata.

See:

 1    mad.ps.beam = mad.psbeam
 2    )
 3            )
 4        )
 5    # fmt: on
 6    df = mad.mtbl.to_df()
 7    try:
 8        import tfs
 9
10        assert type(df) is tfs.TfsDataFrame
11        print("tfs-pandas installed, so the header is stored in headers")
12        print(df.headers)
13    except ImportError:
14        print("tfs-pandas not installed, so the header is stored in attrs instead of headers")

Avoiding Deadlocks

Deadlocks can occur if Python and MAD-NG wait on each other to send/receive large data without syncing.

Example of a Deadlock

mad.send('arr = py:recv()')
mad.send(arr0)                 # Large matrix
mad.send('py:send(arr)')       # Sends data to Python
mad.send('arr2 = py:recv()')   # Asks for new data
mad.send(arr2)                 # DEADLOCK if previous data not yet received

Warning

Always ensure each MAD.send() has a matching MAD.recv() if data is expected back.


Scope: Local vs Global

MAD-NG uses Lua-style scoping:

  • Variables declared with local are temporary.

  • Variables without local persist across MAD.send() calls.

Example:

mad.send("""
a = 10
local b = 20
print(a + b)
""")

mad.send("print(a + (b or 5))")  # b is nil → 10 + 5 = 15

Tip

Use local to avoid polluting the global MAD-NG namespace.


Customising the Environment

You can configure the MAD() instance with options to better suit your environment:

Change the Python alias used inside MAD-NG:

mad = MAD(py_name="python")

Specify a custom MAD-NG binary:

mad = MAD(mad_path="/custom/path/to/mad")

Enable debug mode:

mad = MAD(debug=True)

Increase the number of temporary variables:

mad = MAD(num_temp_vars=10)

See pymadng.MAD.__init__() for all configuration options.


Summary

  • Always match MAD.send() with MAD.recv() when data is expected.

  • Use mad.to_df() for table conversion.

  • Avoid deadlocks by receiving before sending again.

  • Manage scope using local wisely.

  • Use configuration flags to tailor behaviour.

For more, see the Advanced Features in PyMAD-NG, Debugging & Troubleshooting in PyMAD-NG, and Useful Functions & Objects in PyMAD-NG sections.