Migrating from older LUME-Genesis versions¶
Lattices and namelists as dictionaries¶
LUME-Genesis still supports lattices and namelists defined as dictionaries of Genesis 4 parameter names to their values.
Using them will require extra steps as we want to encourage users to utilize the classes directly.
import genesis.version4 as g4
MAIN = [
    {
        "type": "setup",
        "rootname": "Benchmark",
        "lattice": "lattice.lat",
        "beamline": "ARAMIS",
        "lambda0": 1e-10,
        "gamma0": 11357.82,
        "delz": 0.045,
        "shotnoise": 0,
        "beam_global_stat": True,
        "field_global_stat": True,
    },
    {"type": "lattice", "zmatch": 9.5},
    {
        "type": "field",
        "power": 5000,
        "dgrid": 0.0002,
        "ngrid": 255,
        "waist_size": 3e-05,
    },
    {"type": "beam", "current": 3000, "delgam": 1, "ex": 4e-07, "ey": 4e-07},
    {"type": "track", "zstop": 123.5},
]
main = g4.MainInput.from_dicts(MAIN)
main
MainInput(
  namelists=[
    Setup(
      rootname='Benchmark',
      lattice='lattice.lat',
      beamline='ARAMIS',
      gamma0=11357.82,
      delz=0.045,
      shotnoise=False,
      beam_global_stat=True,
      field_global_stat=True,
    ),
    LatticeNamelist(zmatch=9.5),
    Field(power=5000.0, waist_size=3e-05, dgrid=0.0002, ngrid=255),
    Beam(delgam=1.0, current=3000.0, ex=4e-07, ey=4e-07),
    Track(zstop=123.5),
  ],
  filename=None,
)
Mistakes in old dictionaries¶
If you encounter these errors, please double-check your input dictionaries.
Invalid or missing "type" names will raise exceptions.
try:
    g4.MainInput.from_dicts([{"type": "invalid_type", "zstop": 123.5}])
except Exception:
    print("Failed to convert")
Failed to convert
Invalid attributes for the Pydantic classes will similarly be problematic:
try:
    g4.MainInput.from_dicts([{"type": "beam", "INVALID_ITEM": 123.5}])
except Exception as ex:
    print("Failed to convert:", ex)
Failed to convert: Dictionary #0 with type 'beam' did not pass pydantic validation. Are all parameters for the given class valid?
Converting from strings¶
If you have functions which create lattices or main input files from strings, you can similarly migrate to using the beamline element classes.
Using Lattice.from_contents can simplify the conversion task.
For example:
import string
def make_lat(k1=2):
    return string.Template(
        """
D1: DRIFT = { l = 0.445};
D2: DRIFT = { l = 0.24};
QF: QUADRUPOLE = { l = 0.080000, k1= ${my_k1} };
QD: QUADRUPOLE = { l = 0.080000, k1= -${my_k1} };
UND: UNDULATOR = { lambdau=0.015000,nwig=266,aw=0.84853};
FODO: LINE= {UND,D1,QF,D2,UND,D1,QD,D2};
ARAMIS: LINE= {13*FODO};
    """
    ).substitute(my_k1=k1)
g4.Lattice.from_contents(make_lat())
Lattice(
  elements={
    'D1': Drift(L=0.445),
    'D2': Drift(L=0.24),
    'QF': Quadrupole(L=0.08, k1=2.0),
    'QD': Quadrupole(L=0.08, k1=-2.0),
    'UND': Undulator(aw=0.84853, lambdau=0.015, nwig=266),
    'FODO': Line(elements=['UND', 'D1', 'QF', 'D2', 'UND', 'D1', 'QD', 'D2']),
    'ARAMIS': Line(elements=[DuplicatedLineItem(label='FODO', count=13)]),
  },
  filename=pathlib.Path('unknown'),
)
def make_lat(k1=2):
    return g4.Lattice(
        {
            "D1": g4.Drift(L=0.445),
            "D2": g4.Drift(L=0.24),
            "QF": g4.Quadrupole(L=0.08, k1=k1),
            "QD": g4.Quadrupole(L=0.08, k1=-k1),
            "UND": g4.Undulator(aw=0.84853, lambdau=0.015, nwig=266),
            "FODO": g4.Line(
                elements=["UND", "D1", "QF", "D2", "UND", "D1", "QD", "D2"]
            ),
            "ARAMIS": g4.Line(elements=[g4.DuplicatedLineItem(label="FODO", count=13)]),
        },
    )
make_lat()
Lattice(
  elements={
    'D1': Drift(L=0.445),
    'D2': Drift(L=0.24),
    'QF': Quadrupole(L=0.08, k1=2.0),
    'QD': Quadrupole(L=0.08, k1=-2.0),
    'UND': Undulator(aw=0.84853, lambdau=0.015, nwig=266),
    'FODO': Line(elements=['UND', 'D1', 'QF', 'D2', 'UND', 'D1', 'QD', 'D2']),
    'ARAMIS': Line(elements=[DuplicatedLineItem(label='FODO', count=13)]),
  },
)
G = g4.Genesis4(main, make_lat())
G.input
Genesis4Input(
  main=MainInput(
    namelists=[
      Setup(
        rootname='Benchmark',
        lattice='lattice.lat',
        beamline='ARAMIS',
        gamma0=11357.82,
        delz=0.045,
        shotnoise=False,
        beam_global_stat=True,
        field_global_stat=True,
      ),
      LatticeNamelist(zmatch=9.5),
      Field(power=5000.0, waist_size=3e-05, dgrid=0.0002, ngrid=255),
      Beam(delgam=1.0, current=3000.0, ex=4e-07, ey=4e-07),
      Track(zstop=123.5),
    ],
    filename=None,
  ),
  lattice=Lattice(
    elements={
      'D1': Drift(L=0.445),
      'D2': Drift(L=0.24),
      'QF': Quadrupole(L=0.08, k1=2.0),
      'QD': Quadrupole(L=0.08, k1=-2.0),
      'UND': Undulator(aw=0.84853, lambdau=0.015, nwig=266),
      'FODO': Line(elements=['UND', 'D1', 'QF', 'D2', 'UND', 'D1', 'QD', 'D2']),
      'ARAMIS': Line(elements=[DuplicatedLineItem(label='FODO', count=13)]),
    },
  ),
)
Reusing the Genesis4 object¶
Generally, we do not recommend reusing the Genesis4 object for multiple input configurations or lattices.
Creating a new Genesis4 object does not take a significant amount of resources, and it keeps the results of your simulation runs separate.
new_main = g4.MainInput.from_dicts(MAIN)
# No:
G.input.main = new_main
# Yes:
G1 = g4.Genesis4(main, make_lat())
Importantly, the Genesis4 object takes control of your input files and lattice files. The goal is for you to write Python code for your configuration and lattice and then not have to worry about the files on disk or the underlying Genesis 4 file formats.
If you attempt to change G.input.main.setup.lattice to a different filename, lume-genesis will simply use that as a new filename when it writes the lattice to disk (during G.write_input() or G.run())
# No!
# G.input.main.setup.lattice = "my_fancy_latfile.lat"
# Yes!
# G1 = g4.Genesis4(main, "my_fancy_latfile.lat")