Skip to content

Genesis 4 Output

genesis.version4.Genesis4Output

Bases: Mapping, BaseModel

Genesis 4 command output.

Attributes:

Name Type Description
run RunInfo

Execution information - e.g., how long did it take and what was the output from Genesis 4.

alias dict[str, str]

Dictionary of aliased data keys.

Attributes

genesis.version4.Genesis4Output.beam_globals property
beam_globals

Genesis 4 output beam global information (/Beam/Global).

genesis.version4.Genesis4Output.field property
field

Genesis 4 output field information (/Field) - 1st harmonic.

genesis.version4.Genesis4Output.field_globals property
field_globals

Genesis 4 output 1st harmonic field global information (/Field/Global).

Functions

genesis.version4.Genesis4Output.archive
archive(h5)

Dump outputs into the given HDF5 group.

Parameters:

Name Type Description Default
h5 Group

The HDF5 file in which to write the information.

required
Source code in genesis/version4/output.py
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
def archive(self, h5: h5py.Group) -> None:
    """
    Dump outputs into the given HDF5 group.

    Parameters
    ----------
    h5 : h5py.Group
        The HDF5 file in which to write the information.
    """
    _archive.store_in_hdf5_file(h5, self)
genesis.version4.Genesis4Output.from_archive classmethod
from_archive(h5)

Loads output from the given HDF5 group.

Parameters:

Name Type Description Default
h5 str or File

The key to use when restoring the data.

required
Source code in genesis/version4/output.py
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
@classmethod
def from_archive(cls, h5: h5py.Group) -> Genesis4Output:
    """
    Loads output from the given HDF5 group.

    Parameters
    ----------
    h5 : str or h5py.File
        The key to use when restoring the data.
    """
    loaded = _archive.restore_from_hdf5_file(h5)
    if not isinstance(loaded, Genesis4Output):
        raise ValueError(
            f"Loaded {loaded.__class__.__name__} instead of a "
            f"Genesis4Output instance.  Was the HDF group correct?"
        )
    return loaded
genesis.version4.Genesis4Output.from_files classmethod
from_files(filename, load_fields=False, load_particles=False, smear=True)

Load Genesis 4 output from the given filename.

Parameters:

Name Type Description Default
filename Path or str
required
load_fields bool

After execution, load all field files. These are assumed to be in the same directory as the primary output filename.

True
load_particles bool

After execution, load all particle files. These are assumed to be in the same directory as the primary output filename.

True
smear bool

If set, this will smear the particle phase over the sample (skipped) slices, preserving the modulus.

True

Returns:

Type Description
Genesis4Output

The output data.

Source code in genesis/version4/output.py
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
@classmethod
def from_files(
    cls,
    filename: AnyPath,
    load_fields: bool = False,
    load_particles: bool = False,
    smear: bool = True,
) -> Genesis4Output:
    """
    Load Genesis 4 output from the given filename.

    Parameters
    ----------
    filename : pathlib.Path or str
    load_fields : bool, default=True
        After execution, load all field files.
        These are assumed to be in the same directory as the primary output
        filename.
    load_particles : bool, default=True
        After execution, load all particle files.
        These are assumed to be in the same directory as the primary output
        filename.
    smear : bool, default=True
        If set, this will smear the particle phase over the sample
        (skipped) slices, preserving the modulus.

    Returns
    -------
    Genesis4Output
        The output data.
    """
    output_root = pathlib.Path(filename).parent

    try:
        with h5py.File(filename, "r") as h5:
            data = parsers.extract_data(h5)
    except FileNotFoundError:
        raise FileNotFoundError(
            f"Genesis 4 simulation output file not found. "
            f"Check if the simulation ran successfully and if the run settings are correct. "
            f"The expected output filename is: {filename}"
        ) from None

    fields = [
        LoadableFieldH5File(
            key=get_key_from_filename(fn.name),
            filename=fn,
        )
        for fn in output_root.glob("*.fld.h5")
    ]
    particles = [
        LoadableParticleGroupH5File(
            key=get_key_from_filename(fn.name),
            filename=fn,
        )
        for fn in output_root.glob("*.par.h5")
    ]

    def get_harmonics_keys():
        # The first harmonic is just "Field"
        yield 1, "field"
        # Harmonic 2+ are HDF5 "FieldN" -> Python "field_n"
        for key in sorted(data):
            if not key.startswith("field_"):
                continue

            try:
                harmonic = int(key.split("_", 1)[1])
            except ValueError:
                logger.error(f"Unexpected field key in output: {key}")
                data.pop(key)
                continue

            yield harmonic, key

    globals_ = OutputGlobal.from_hdf5_data(data.pop("globals", {}))
    beam = OutputBeam.from_hdf5_data(data.pop("beam", {}))
    field_harmonics = {
        harmonic: OutputField.from_hdf5_data(data.pop(key, {}), slen=globals_.slen)
        for harmonic, key in get_harmonics_keys()
    }
    lattice = OutputLattice.from_hdf5_data(data.pop("lattice", {}))
    meta = OutputMeta.from_hdf5_data(data.pop("meta", {}))
    version = meta.version
    key_map = data.pop("hdf_key_map", {})

    for key, value in data.items():
        if not isinstance(value, (float, int, str, bool, np.ndarray)):
            logger.warning(
                f"Ignoring unexpected output file HDF5 key: {key}.  "
                f"This may indicate lume-genesis needs updating."
            )
            data.pop(key)

    extra = data

    output = cls(
        beam=beam,
        field_harmonics=field_harmonics,
        lattice=lattice,
        globals=globals_,
        version=version,
        extra=extra,
        meta=meta,
        alias={},
        field_files={field.key: field for field in fields},
        particle_files={particle.key: particle for particle in particles},
        hdf_key_map=key_map,
    )

    if load_fields:
        output.load_fields()

    if load_particles:
        output.load_particles(smear=smear)

    return output
genesis.version4.Genesis4Output.from_input_settings classmethod
from_input_settings(input, workdir, load_fields=False, load_particles=False, smear=True)

Load Genesis 4 output based on the configured input settings.

Parameters:

Name Type Description Default
load_fields bool

After execution, load all field files.

False
load_particles bool

After execution, load all particle files.

False
smear bool

If set, for particles, this will smear the phase over the sample (skipped) slices, preserving the modulus.

True

Returns:

Type Description
Genesis4Output

The output data.

Source code in genesis/version4/output.py
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
@classmethod
def from_input_settings(
    cls,
    input: Genesis4Input,
    workdir: pathlib.Path,
    load_fields: bool = False,
    load_particles: bool = False,
    smear: bool = True,
) -> Genesis4Output:
    """
    Load Genesis 4 output based on the configured input settings.

    Parameters
    ----------
    load_fields : bool, default=False
        After execution, load all field files.
    load_particles : bool, default=False
        After execution, load all particle files.
    smear : bool, default=True
        If set, for particles, this will smear the phase over the sample
        (skipped) slices, preserving the modulus.

    Returns
    -------
    Genesis4Output
        The output data.
    """
    output_filename = cls.get_output_filename(input, workdir)
    return cls.from_files(
        output_filename,
        load_fields=load_fields,
        load_particles=load_particles,
        smear=smear,
    )
genesis.version4.Genesis4Output.get_array
get_array(key)

Gets an array by its string alias.

For alias information, see .alias.

Returns:

Type Description
ndarray
Source code in genesis/version4/output.py
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
def get_array(self, key: str) -> np.ndarray:
    """
    Gets an array by its string alias.

    For alias information, see `.alias`.

    Returns
    -------
    np.ndarray
    """
    return self[key]
genesis.version4.Genesis4Output.get_output_filename staticmethod
get_output_filename(input, workdir)

Get the output filename based on the input/run-related settings.

Source code in genesis/version4/output.py
1274
1275
1276
1277
1278
1279
1280
1281
1282
@staticmethod
def get_output_filename(input: Genesis4Input, workdir: AnyPath) -> pathlib.Path:
    """Get the output filename based on the input/run-related settings."""
    root_name = input.output_path or input.main.setup.rootname
    if not root_name:
        raise RuntimeError(
            "Unable to find 'rootname'; cannot determine output filename."
        )
    return pathlib.Path(workdir) / f"{root_name}.out.h5"
genesis.version4.Genesis4Output.info
info()

Get information about available string keys for the output.

Source code in genesis/version4/output.py
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
def info(self):
    """
    Get information about available string keys for the output.
    """
    array_info = {key: self._get_array_info(key) for key in sorted(self.keys())}
    shapes = {
        key: str(array_info.shape or "") for key, array_info in array_info.items()
    }
    annotations = {
        key: array_info.field.description for key, array_info in array_info.items()
    }
    table = {
        key: str(array_info.units or "") for key, array_info in array_info.items()
    }
    return tools.table_output(
        table,  # column 0 (key) and 1 (units)
        annotations=shapes,  # column 2 (description) -> shape
        descriptions=annotations,  # column 3 (type/annotation) -> description
        headers=["Key", "Units", "Shape", "Description"],
    )
genesis.version4.Genesis4Output.load_field_by_key
load_field_by_key(key)

Loads a single field file by name into a dictionary.

Parameters:

Name Type Description Default
key str or int

The label of the particles (e.g., "end" of "end.fld.h5"), or the integer integration step.

required

Returns:

Type Description
FieldFile
Source code in genesis/version4/output.py
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
def load_field_by_key(self, key: FileKey) -> FieldFile:
    """
    Loads a single field file by name into a dictionary.

    Parameters
    ----------
    key : str or int
        The label of the particles (e.g., "end" of "end.fld.h5"), or the
        integer integration step.

    Returns
    -------
    FieldFile
    """
    loadable = self.field_files[key]
    field = loadable.load()
    assert isinstance(field, FieldFile)
    self.field3d[key] = field
    logger.info(f"Loaded field data: '{key}'")
    self.update_aliases()
    return field
genesis.version4.Genesis4Output.load_fields
load_fields()

Loads all field files produced.

Returns:

Type Description
list of str

Key names of all loaded fields.

Source code in genesis/version4/output.py
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
def load_fields(self) -> List[FileKey]:
    """
    Loads all field files produced.

    Returns
    -------
    list of str
        Key names of all loaded fields.
    """

    def sort_key(key: FileKey):
        if isinstance(key, int):
            return (key, "")
        return (-1, key)

    to_load = sorted(self.field_files, key=sort_key)
    for key in to_load:
        self.load_field_by_key(key)
    return to_load
genesis.version4.Genesis4Output.load_particles
load_particles(smear=True)

Loads all particle files produced.

Parameters:

Name Type Description Default
smear bool

If set, for particles, this will smear the phase over the sample (skipped) slices, preserving the modulus.

True

Returns:

Type Description
list of str

Key names of all loaded particles.

Source code in genesis/version4/output.py
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
def load_particles(self, smear: bool = True) -> List[FileKey]:
    """
    Loads all particle files produced.

    Parameters
    ----------
    smear : bool, default=True
        If set, for particles, this will smear the phase over the sample
        (skipped) slices, preserving the modulus.

    Returns
    -------
    list of str
        Key names of all loaded particles.
    """

    def sort_key(key: FileKey):
        if isinstance(key, int):
            return (key, "")
        return (-1, key)

    to_load = sorted(self.particle_files, key=sort_key)
    for key in to_load:
        self.load_particles_by_key(key, smear=smear)
    return list(to_load)
genesis.version4.Genesis4Output.load_particles_by_key
load_particles_by_key(key, smear=True)

Loads a single particle file into openPMD-beamphysics ParticleGroup object.

Parameters:

Name Type Description Default
key str or int

The label of the particles (e.g., "end" of "end.par.h5"), or the integer integration step.

required
smear bool

If set, will smear the phase over the sample (skipped) slices, preserving the modulus.

True
Source code in genesis/version4/output.py
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
def load_particles_by_key(self, key: FileKey, smear: bool = True) -> ParticleGroup:
    """
    Loads a single particle file into openPMD-beamphysics ParticleGroup
    object.

    Parameters
    ----------
    key : str or int
        The label of the particles (e.g., "end" of "end.par.h5"), or the
        integer integration step.
    smear : bool, optional, default=True
        If set, will smear the phase over the sample (skipped) slices,
        preserving the modulus.
    """
    loadable = self.particle_files[key]
    group = loadable.load(smear=smear)
    assert isinstance(group, ParticleGroup)
    self.particles[key] = group
    logger.info(
        f"Loaded particle data: '{key}' as a ParticleGroup with "
        f"{len(group)} particles"
    )
    return group
genesis.version4.Genesis4Output.load_raw_particles_by_key
load_raw_particles_by_key(key)

Loads a single particle file into a raw Genesis4ParticleData object.

Parameters:

Name Type Description Default
key str or int

The label of the particles (e.g., "end" of "end.par.h5"), or the integer integration step.

required
Source code in genesis/version4/output.py
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
def load_raw_particles_by_key(self, key: FileKey) -> Genesis4ParticleData:
    """
    Loads a single particle file into a raw Genesis4ParticleData object.

    Parameters
    ----------
    key : str or int
        The label of the particles (e.g., "end" of "end.par.h5"), or the
        integer integration step.
    """
    loadable = self.particle_files[key]
    particles = Genesis4ParticleData.from_filename(loadable.filename)
    logger.info(
        f"Loaded raw particle data: '{key}' with {len(particles.slices)} slices"
    )
    return particles
genesis.version4.Genesis4Output.plot
plot(y='field_energy', x='zplot', xlim=None, ylim=None, ylim2=None, yscale='linear', yscale2='linear', y2=(), nice=True, include_layout=True, include_legend=True, return_figure=False, tex=False, **kwargs)

Plots output multiple keys.

Parameters:

Name Type Description Default
y str or list of str

List of keys to be displayed on the Y axis

'field_energy'
x str

Key to be displayed as X axis

'zplot'
xlim list

Limits for the X axis

None
ylim list

Limits for the Y axis

None
ylim2 list

Limits for the secondary Y axis

None
yscale str

one of "linear", "log", "symlog", "logit", ... for the Y axis

'linear'
yscale2 str

one of "linear", "log", "symlog", "logit", ... for the secondary Y axis

'linear'
y2 list

List of keys to be displayed on the secondary Y axis

()
nice bool

Whether or not a nice SI prefix and scaling will be used to make the numbers reasonably sized. Default: True

True
include_layout bool

Whether or not to include a layout plot at the bottom. Default: True Whether or not the plot should include the legend. Default: True

True
return_figure bool

Whether or not to return the figure object for further manipulation. Default: True

False
kwargs dict

Extra arguments can be passed to the specific plotting function.

{}

Returns:

Name Type Description
fig Figure

The plot figure for further customizations or None if return_figure is set to False.

Source code in genesis/version4/output.py
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
def plot(
    self,
    y: Union[str, Sequence[str]] = "field_energy",
    x: str = "zplot",
    xlim: Optional[PlotLimits] = None,
    ylim: Optional[PlotMaybeLimits] = None,
    ylim2: Optional[PlotMaybeLimits] = None,
    yscale: str = "linear",
    yscale2: str = "linear",
    y2: Union[str, Sequence[str]] = (),
    nice: bool = True,
    include_layout: bool = True,
    include_legend: bool = True,
    return_figure: bool = False,
    tex: bool = False,
    **kwargs,
) -> Optional[matplotlib.figure.Figure]:
    """
    Plots output multiple keys.

    Parameters
    ----------
    y : str or list of str
        List of keys to be displayed on the Y axis
    x : str
        Key to be displayed as X axis
    xlim : list
        Limits for the X axis
    ylim : list
        Limits for the Y axis
    ylim2 : list
        Limits for the secondary Y axis
    yscale: str
        one of "linear", "log", "symlog", "logit", ... for the Y axis
    yscale2: str
        one of "linear", "log", "symlog", "logit", ... for the secondary Y axis
    y2 : list
        List of keys to be displayed on the secondary Y axis
    nice : bool
        Whether or not a nice SI prefix and scaling will be used to
        make the numbers reasonably sized. Default: True
    include_layout : bool
        Whether or not to include a layout plot at the bottom. Default: True
        Whether or not the plot should include the legend. Default: True
    return_figure : bool
        Whether or not to return the figure object for further manipulation.
        Default: True
    kwargs : dict
        Extra arguments can be passed to the specific plotting function.

    Returns
    -------
    fig : matplotlib.pyplot.figure.Figure
        The plot figure for further customizations or `None` if `return_figure` is set to False.
    """

    # Expand keys
    if isinstance(y, str):
        y = y.split()
    if isinstance(y2, str):
        y2 = y2.split()

    y = list(y)
    y2 = list(y2)

    return plot_stats_with_layout(
        self,
        ykeys=y,
        ykeys2=y2,
        xkey=x,
        xlim=xlim,
        ylim=ylim,
        ylim2=ylim2,
        yscale=yscale,
        yscale2=yscale2,
        nice=nice,
        tex=tex,
        include_layout=include_layout,
        include_legend=include_legend,
        return_figure=return_figure,
        **kwargs,
    )
genesis.version4.Genesis4Output.to_hdf_summary
to_hdf_summary()

Summarize the data based on HDF5 keys.

Source code in genesis/version4/output.py
1437
1438
1439
def to_hdf_summary(self):
    """Summarize the data based on HDF5 keys."""
    return _hdf_summary(self, base_attr="output", base_key="")
genesis.version4.Genesis4Output.units
units(key)

pmd_unit of a given key

Source code in genesis/version4/output.py
1550
1551
1552
1553
def units(self, key: str) -> Optional[pmd_unit]:
    """pmd_unit of a given key"""
    # return self.unit_info.get(key, None)
    return self._get_array_info(key).units
genesis.version4.Genesis4Output.update_aliases
update_aliases()

Update aliases based on available data.

Source code in genesis/version4/output.py
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
def update_aliases(self) -> None:
    """Update aliases based on available data."""
    self.alias.update(tools.make_dotted_aliases(self))

    if self.field is not None:
        self.alias.update(
            tools.make_dotted_aliases(
                self.field,
                existing_aliases=self.alias,
                attr_prefix="field.",
                alias_prefix="field_",
            )
        )

        self.alias.update(
            tools.make_dotted_aliases(
                self.field,
                existing_aliases=self.alias,
                attr_prefix="field.",
                alias_prefix="field1_",
            )
        )

    for harmonic, field in self.field_harmonics.items():
        if harmonic > 1:
            self.alias.update(
                tools.make_dotted_aliases(
                    field,
                    existing_aliases=self.alias,
                    attr_prefix=f"field_harmonics[{harmonic}].",
                    alias_prefix=f"field{harmonic}_",
                )
            )

    custom_aliases = {
        # Back-compat
        "beam_sigma_energy": "beam.stat.sigma_energy",
        "beam_sigma_x": "beam.stat.sigma_x",
        "beam_sigma_y": "beam.stat.sigma_y",
    }
    for alias_from, alias_to in custom_aliases.items():
        self.alias.setdefault(alias_from, alias_to)

genesis.version4.output.Genesis4Output

Bases: Mapping, BaseModel

Genesis 4 command output.

Attributes:

Name Type Description
run RunInfo

Execution information - e.g., how long did it take and what was the output from Genesis 4.

alias dict[str, str]

Dictionary of aliased data keys.

Attributes

genesis.version4.output.Genesis4Output.beam_globals property
beam_globals

Genesis 4 output beam global information (/Beam/Global).

genesis.version4.output.Genesis4Output.field property
field

Genesis 4 output field information (/Field) - 1st harmonic.

genesis.version4.output.Genesis4Output.field_globals property
field_globals

Genesis 4 output 1st harmonic field global information (/Field/Global).

Functions

genesis.version4.output.Genesis4Output.archive
archive(h5)

Dump outputs into the given HDF5 group.

Parameters:

Name Type Description Default
h5 Group

The HDF5 file in which to write the information.

required
Source code in genesis/version4/output.py
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
def archive(self, h5: h5py.Group) -> None:
    """
    Dump outputs into the given HDF5 group.

    Parameters
    ----------
    h5 : h5py.Group
        The HDF5 file in which to write the information.
    """
    _archive.store_in_hdf5_file(h5, self)
genesis.version4.output.Genesis4Output.from_archive classmethod
from_archive(h5)

Loads output from the given HDF5 group.

Parameters:

Name Type Description Default
h5 str or File

The key to use when restoring the data.

required
Source code in genesis/version4/output.py
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
@classmethod
def from_archive(cls, h5: h5py.Group) -> Genesis4Output:
    """
    Loads output from the given HDF5 group.

    Parameters
    ----------
    h5 : str or h5py.File
        The key to use when restoring the data.
    """
    loaded = _archive.restore_from_hdf5_file(h5)
    if not isinstance(loaded, Genesis4Output):
        raise ValueError(
            f"Loaded {loaded.__class__.__name__} instead of a "
            f"Genesis4Output instance.  Was the HDF group correct?"
        )
    return loaded
genesis.version4.output.Genesis4Output.from_files classmethod
from_files(filename, load_fields=False, load_particles=False, smear=True)

Load Genesis 4 output from the given filename.

Parameters:

Name Type Description Default
filename Path or str
required
load_fields bool

After execution, load all field files. These are assumed to be in the same directory as the primary output filename.

True
load_particles bool

After execution, load all particle files. These are assumed to be in the same directory as the primary output filename.

True
smear bool

If set, this will smear the particle phase over the sample (skipped) slices, preserving the modulus.

True

Returns:

Type Description
Genesis4Output

The output data.

Source code in genesis/version4/output.py
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
@classmethod
def from_files(
    cls,
    filename: AnyPath,
    load_fields: bool = False,
    load_particles: bool = False,
    smear: bool = True,
) -> Genesis4Output:
    """
    Load Genesis 4 output from the given filename.

    Parameters
    ----------
    filename : pathlib.Path or str
    load_fields : bool, default=True
        After execution, load all field files.
        These are assumed to be in the same directory as the primary output
        filename.
    load_particles : bool, default=True
        After execution, load all particle files.
        These are assumed to be in the same directory as the primary output
        filename.
    smear : bool, default=True
        If set, this will smear the particle phase over the sample
        (skipped) slices, preserving the modulus.

    Returns
    -------
    Genesis4Output
        The output data.
    """
    output_root = pathlib.Path(filename).parent

    try:
        with h5py.File(filename, "r") as h5:
            data = parsers.extract_data(h5)
    except FileNotFoundError:
        raise FileNotFoundError(
            f"Genesis 4 simulation output file not found. "
            f"Check if the simulation ran successfully and if the run settings are correct. "
            f"The expected output filename is: {filename}"
        ) from None

    fields = [
        LoadableFieldH5File(
            key=get_key_from_filename(fn.name),
            filename=fn,
        )
        for fn in output_root.glob("*.fld.h5")
    ]
    particles = [
        LoadableParticleGroupH5File(
            key=get_key_from_filename(fn.name),
            filename=fn,
        )
        for fn in output_root.glob("*.par.h5")
    ]

    def get_harmonics_keys():
        # The first harmonic is just "Field"
        yield 1, "field"
        # Harmonic 2+ are HDF5 "FieldN" -> Python "field_n"
        for key in sorted(data):
            if not key.startswith("field_"):
                continue

            try:
                harmonic = int(key.split("_", 1)[1])
            except ValueError:
                logger.error(f"Unexpected field key in output: {key}")
                data.pop(key)
                continue

            yield harmonic, key

    globals_ = OutputGlobal.from_hdf5_data(data.pop("globals", {}))
    beam = OutputBeam.from_hdf5_data(data.pop("beam", {}))
    field_harmonics = {
        harmonic: OutputField.from_hdf5_data(data.pop(key, {}), slen=globals_.slen)
        for harmonic, key in get_harmonics_keys()
    }
    lattice = OutputLattice.from_hdf5_data(data.pop("lattice", {}))
    meta = OutputMeta.from_hdf5_data(data.pop("meta", {}))
    version = meta.version
    key_map = data.pop("hdf_key_map", {})

    for key, value in data.items():
        if not isinstance(value, (float, int, str, bool, np.ndarray)):
            logger.warning(
                f"Ignoring unexpected output file HDF5 key: {key}.  "
                f"This may indicate lume-genesis needs updating."
            )
            data.pop(key)

    extra = data

    output = cls(
        beam=beam,
        field_harmonics=field_harmonics,
        lattice=lattice,
        globals=globals_,
        version=version,
        extra=extra,
        meta=meta,
        alias={},
        field_files={field.key: field for field in fields},
        particle_files={particle.key: particle for particle in particles},
        hdf_key_map=key_map,
    )

    if load_fields:
        output.load_fields()

    if load_particles:
        output.load_particles(smear=smear)

    return output
genesis.version4.output.Genesis4Output.from_input_settings classmethod
from_input_settings(input, workdir, load_fields=False, load_particles=False, smear=True)

Load Genesis 4 output based on the configured input settings.

Parameters:

Name Type Description Default
load_fields bool

After execution, load all field files.

False
load_particles bool

After execution, load all particle files.

False
smear bool

If set, for particles, this will smear the phase over the sample (skipped) slices, preserving the modulus.

True

Returns:

Type Description
Genesis4Output

The output data.

Source code in genesis/version4/output.py
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
@classmethod
def from_input_settings(
    cls,
    input: Genesis4Input,
    workdir: pathlib.Path,
    load_fields: bool = False,
    load_particles: bool = False,
    smear: bool = True,
) -> Genesis4Output:
    """
    Load Genesis 4 output based on the configured input settings.

    Parameters
    ----------
    load_fields : bool, default=False
        After execution, load all field files.
    load_particles : bool, default=False
        After execution, load all particle files.
    smear : bool, default=True
        If set, for particles, this will smear the phase over the sample
        (skipped) slices, preserving the modulus.

    Returns
    -------
    Genesis4Output
        The output data.
    """
    output_filename = cls.get_output_filename(input, workdir)
    return cls.from_files(
        output_filename,
        load_fields=load_fields,
        load_particles=load_particles,
        smear=smear,
    )
genesis.version4.output.Genesis4Output.get_array
get_array(key)

Gets an array by its string alias.

For alias information, see .alias.

Returns:

Type Description
ndarray
Source code in genesis/version4/output.py
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
def get_array(self, key: str) -> np.ndarray:
    """
    Gets an array by its string alias.

    For alias information, see `.alias`.

    Returns
    -------
    np.ndarray
    """
    return self[key]
genesis.version4.output.Genesis4Output.get_output_filename staticmethod
get_output_filename(input, workdir)

Get the output filename based on the input/run-related settings.

Source code in genesis/version4/output.py
1274
1275
1276
1277
1278
1279
1280
1281
1282
@staticmethod
def get_output_filename(input: Genesis4Input, workdir: AnyPath) -> pathlib.Path:
    """Get the output filename based on the input/run-related settings."""
    root_name = input.output_path or input.main.setup.rootname
    if not root_name:
        raise RuntimeError(
            "Unable to find 'rootname'; cannot determine output filename."
        )
    return pathlib.Path(workdir) / f"{root_name}.out.h5"
genesis.version4.output.Genesis4Output.info
info()

Get information about available string keys for the output.

Source code in genesis/version4/output.py
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
def info(self):
    """
    Get information about available string keys for the output.
    """
    array_info = {key: self._get_array_info(key) for key in sorted(self.keys())}
    shapes = {
        key: str(array_info.shape or "") for key, array_info in array_info.items()
    }
    annotations = {
        key: array_info.field.description for key, array_info in array_info.items()
    }
    table = {
        key: str(array_info.units or "") for key, array_info in array_info.items()
    }
    return tools.table_output(
        table,  # column 0 (key) and 1 (units)
        annotations=shapes,  # column 2 (description) -> shape
        descriptions=annotations,  # column 3 (type/annotation) -> description
        headers=["Key", "Units", "Shape", "Description"],
    )
genesis.version4.output.Genesis4Output.load_field_by_key
load_field_by_key(key)

Loads a single field file by name into a dictionary.

Parameters:

Name Type Description Default
key str or int

The label of the particles (e.g., "end" of "end.fld.h5"), or the integer integration step.

required

Returns:

Type Description
FieldFile
Source code in genesis/version4/output.py
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
def load_field_by_key(self, key: FileKey) -> FieldFile:
    """
    Loads a single field file by name into a dictionary.

    Parameters
    ----------
    key : str or int
        The label of the particles (e.g., "end" of "end.fld.h5"), or the
        integer integration step.

    Returns
    -------
    FieldFile
    """
    loadable = self.field_files[key]
    field = loadable.load()
    assert isinstance(field, FieldFile)
    self.field3d[key] = field
    logger.info(f"Loaded field data: '{key}'")
    self.update_aliases()
    return field
genesis.version4.output.Genesis4Output.load_fields
load_fields()

Loads all field files produced.

Returns:

Type Description
list of str

Key names of all loaded fields.

Source code in genesis/version4/output.py
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
def load_fields(self) -> List[FileKey]:
    """
    Loads all field files produced.

    Returns
    -------
    list of str
        Key names of all loaded fields.
    """

    def sort_key(key: FileKey):
        if isinstance(key, int):
            return (key, "")
        return (-1, key)

    to_load = sorted(self.field_files, key=sort_key)
    for key in to_load:
        self.load_field_by_key(key)
    return to_load
genesis.version4.output.Genesis4Output.load_particles
load_particles(smear=True)

Loads all particle files produced.

Parameters:

Name Type Description Default
smear bool

If set, for particles, this will smear the phase over the sample (skipped) slices, preserving the modulus.

True

Returns:

Type Description
list of str

Key names of all loaded particles.

Source code in genesis/version4/output.py
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
def load_particles(self, smear: bool = True) -> List[FileKey]:
    """
    Loads all particle files produced.

    Parameters
    ----------
    smear : bool, default=True
        If set, for particles, this will smear the phase over the sample
        (skipped) slices, preserving the modulus.

    Returns
    -------
    list of str
        Key names of all loaded particles.
    """

    def sort_key(key: FileKey):
        if isinstance(key, int):
            return (key, "")
        return (-1, key)

    to_load = sorted(self.particle_files, key=sort_key)
    for key in to_load:
        self.load_particles_by_key(key, smear=smear)
    return list(to_load)
genesis.version4.output.Genesis4Output.load_particles_by_key
load_particles_by_key(key, smear=True)

Loads a single particle file into openPMD-beamphysics ParticleGroup object.

Parameters:

Name Type Description Default
key str or int

The label of the particles (e.g., "end" of "end.par.h5"), or the integer integration step.

required
smear bool

If set, will smear the phase over the sample (skipped) slices, preserving the modulus.

True
Source code in genesis/version4/output.py
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
def load_particles_by_key(self, key: FileKey, smear: bool = True) -> ParticleGroup:
    """
    Loads a single particle file into openPMD-beamphysics ParticleGroup
    object.

    Parameters
    ----------
    key : str or int
        The label of the particles (e.g., "end" of "end.par.h5"), or the
        integer integration step.
    smear : bool, optional, default=True
        If set, will smear the phase over the sample (skipped) slices,
        preserving the modulus.
    """
    loadable = self.particle_files[key]
    group = loadable.load(smear=smear)
    assert isinstance(group, ParticleGroup)
    self.particles[key] = group
    logger.info(
        f"Loaded particle data: '{key}' as a ParticleGroup with "
        f"{len(group)} particles"
    )
    return group
genesis.version4.output.Genesis4Output.load_raw_particles_by_key
load_raw_particles_by_key(key)

Loads a single particle file into a raw Genesis4ParticleData object.

Parameters:

Name Type Description Default
key str or int

The label of the particles (e.g., "end" of "end.par.h5"), or the integer integration step.

required
Source code in genesis/version4/output.py
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
def load_raw_particles_by_key(self, key: FileKey) -> Genesis4ParticleData:
    """
    Loads a single particle file into a raw Genesis4ParticleData object.

    Parameters
    ----------
    key : str or int
        The label of the particles (e.g., "end" of "end.par.h5"), or the
        integer integration step.
    """
    loadable = self.particle_files[key]
    particles = Genesis4ParticleData.from_filename(loadable.filename)
    logger.info(
        f"Loaded raw particle data: '{key}' with {len(particles.slices)} slices"
    )
    return particles
genesis.version4.output.Genesis4Output.plot
plot(y='field_energy', x='zplot', xlim=None, ylim=None, ylim2=None, yscale='linear', yscale2='linear', y2=(), nice=True, include_layout=True, include_legend=True, return_figure=False, tex=False, **kwargs)

Plots output multiple keys.

Parameters:

Name Type Description Default
y str or list of str

List of keys to be displayed on the Y axis

'field_energy'
x str

Key to be displayed as X axis

'zplot'
xlim list

Limits for the X axis

None
ylim list

Limits for the Y axis

None
ylim2 list

Limits for the secondary Y axis

None
yscale str

one of "linear", "log", "symlog", "logit", ... for the Y axis

'linear'
yscale2 str

one of "linear", "log", "symlog", "logit", ... for the secondary Y axis

'linear'
y2 list

List of keys to be displayed on the secondary Y axis

()
nice bool

Whether or not a nice SI prefix and scaling will be used to make the numbers reasonably sized. Default: True

True
include_layout bool

Whether or not to include a layout plot at the bottom. Default: True Whether or not the plot should include the legend. Default: True

True
return_figure bool

Whether or not to return the figure object for further manipulation. Default: True

False
kwargs dict

Extra arguments can be passed to the specific plotting function.

{}

Returns:

Name Type Description
fig Figure

The plot figure for further customizations or None if return_figure is set to False.

Source code in genesis/version4/output.py
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
def plot(
    self,
    y: Union[str, Sequence[str]] = "field_energy",
    x: str = "zplot",
    xlim: Optional[PlotLimits] = None,
    ylim: Optional[PlotMaybeLimits] = None,
    ylim2: Optional[PlotMaybeLimits] = None,
    yscale: str = "linear",
    yscale2: str = "linear",
    y2: Union[str, Sequence[str]] = (),
    nice: bool = True,
    include_layout: bool = True,
    include_legend: bool = True,
    return_figure: bool = False,
    tex: bool = False,
    **kwargs,
) -> Optional[matplotlib.figure.Figure]:
    """
    Plots output multiple keys.

    Parameters
    ----------
    y : str or list of str
        List of keys to be displayed on the Y axis
    x : str
        Key to be displayed as X axis
    xlim : list
        Limits for the X axis
    ylim : list
        Limits for the Y axis
    ylim2 : list
        Limits for the secondary Y axis
    yscale: str
        one of "linear", "log", "symlog", "logit", ... for the Y axis
    yscale2: str
        one of "linear", "log", "symlog", "logit", ... for the secondary Y axis
    y2 : list
        List of keys to be displayed on the secondary Y axis
    nice : bool
        Whether or not a nice SI prefix and scaling will be used to
        make the numbers reasonably sized. Default: True
    include_layout : bool
        Whether or not to include a layout plot at the bottom. Default: True
        Whether or not the plot should include the legend. Default: True
    return_figure : bool
        Whether or not to return the figure object for further manipulation.
        Default: True
    kwargs : dict
        Extra arguments can be passed to the specific plotting function.

    Returns
    -------
    fig : matplotlib.pyplot.figure.Figure
        The plot figure for further customizations or `None` if `return_figure` is set to False.
    """

    # Expand keys
    if isinstance(y, str):
        y = y.split()
    if isinstance(y2, str):
        y2 = y2.split()

    y = list(y)
    y2 = list(y2)

    return plot_stats_with_layout(
        self,
        ykeys=y,
        ykeys2=y2,
        xkey=x,
        xlim=xlim,
        ylim=ylim,
        ylim2=ylim2,
        yscale=yscale,
        yscale2=yscale2,
        nice=nice,
        tex=tex,
        include_layout=include_layout,
        include_legend=include_legend,
        return_figure=return_figure,
        **kwargs,
    )
genesis.version4.output.Genesis4Output.to_hdf_summary
to_hdf_summary()

Summarize the data based on HDF5 keys.

Source code in genesis/version4/output.py
1437
1438
1439
def to_hdf_summary(self):
    """Summarize the data based on HDF5 keys."""
    return _hdf_summary(self, base_attr="output", base_key="")
genesis.version4.output.Genesis4Output.units
units(key)

pmd_unit of a given key

Source code in genesis/version4/output.py
1550
1551
1552
1553
def units(self, key: str) -> Optional[pmd_unit]:
    """pmd_unit of a given key"""
    # return self.unit_info.get(key, None)
    return self._get_array_info(key).units
genesis.version4.output.Genesis4Output.update_aliases
update_aliases()

Update aliases based on available data.

Source code in genesis/version4/output.py
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
def update_aliases(self) -> None:
    """Update aliases based on available data."""
    self.alias.update(tools.make_dotted_aliases(self))

    if self.field is not None:
        self.alias.update(
            tools.make_dotted_aliases(
                self.field,
                existing_aliases=self.alias,
                attr_prefix="field.",
                alias_prefix="field_",
            )
        )

        self.alias.update(
            tools.make_dotted_aliases(
                self.field,
                existing_aliases=self.alias,
                attr_prefix="field.",
                alias_prefix="field1_",
            )
        )

    for harmonic, field in self.field_harmonics.items():
        if harmonic > 1:
            self.alias.update(
                tools.make_dotted_aliases(
                    field,
                    existing_aliases=self.alias,
                    attr_prefix=f"field_harmonics[{harmonic}].",
                    alias_prefix=f"field{harmonic}_",
                )
            )

    custom_aliases = {
        # Back-compat
        "beam_sigma_energy": "beam.stat.sigma_energy",
        "beam_sigma_x": "beam.stat.sigma_x",
        "beam_sigma_y": "beam.stat.sigma_y",
    }
    for alias_from, alias_to in custom_aliases.items():
        self.alias.setdefault(alias_from, alias_to)

Shared output information

genesis.version4.output._OutputBase

_OutputBase(**kwargs)

Bases: BaseModel

Output model base class.

Source code in genesis/version4/output.py
133
134
135
def __init__(self, **kwargs: Any) -> None:
    extra = _split_extra(type(self), kwargs)
    super().__init__(**kwargs, extra=extra)

Run and general information

genesis.version4.output.RunInfo

Bases: BaseModel

Genesis 4 run information.

Attributes:

Name Type Description
error bool

True if an error occurred during the Genesis run.

error_reason str or None

Error explanation, if error is set.

run_script str

The command-line arguments used to run Genesis

output_log str

Genesis 4 output log

start_time float

Start time of the process

end_time float

End time of the process

run_time float

Wall clock run time of the process

Attributes

genesis.version4.output.RunInfo.success property
success

True if the run was successful.

genesis.version4.output.OutputGlobal

OutputGlobal(**kwargs)

Bases: _OutputBase

Global information from Genesis 4 output. (HDF5 /Global)

Source code in genesis/version4/output.py
133
134
135
def __init__(self, **kwargs: Any) -> None:
    extra = _split_extra(type(self), kwargs)
    super().__init__(**kwargs, extra=extra)

Field information

genesis.version4.output.FieldFile

Bases: BaseModel

Attributes

genesis.version4.output.FieldFile.hdf5_filename property
hdf5_filename

The label-based HDF5 filename which Genesis would write.

For a label of 'end' this would be 'end.fld.h5'.

Returns:

Type Description
str

Functions

genesis.version4.output.FieldFile.from_file classmethod
from_file(file)

Load a single Genesis 4-format field file (*.fld.h5).

Returns:

Type Description
FieldFile
Source code in genesis/version4/field.py
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
@classmethod
def from_file(
    cls,
    file: Union[AnyPath, h5py.File],
) -> FieldFile:
    """
    Load a single Genesis 4-format field file (``*.fld.h5``).

    Returns
    -------
    FieldFile
    """
    if isinstance(file, h5py.File):
        dfl, param = readers.load_genesis4_fields(file)
        filename = file.filename
    else:
        filename = pathlib.Path(file)
        if not h5py.is_hdf5(filename):
            raise ValueError(f"Field file {filename} is not an HDF5 file")

        with h5py.File(filename, "r") as h5:
            dfl, param = readers.load_genesis4_fields(h5)

    return cls(
        label=get_key_from_filename(pathlib.Path(filename).name),
        dfl=dfl,
        param=FieldFileParams(**param),
    )
genesis.version4.output.FieldFile.write_genesis4
write_genesis4(dest)

Write field data from memory to a file.

Parameters:

Name Type Description Default
dest (File, str or Path)

Destination to write to. May be an open HDF5 file handle or a filename.

required
Source code in genesis/version4/field.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
def write_genesis4(
    self,
    dest: Union[AnyPath, h5py.File],
) -> None:
    """
    Write field data from memory to a file.

    Parameters
    ----------
    dest : h5py.File, str or pathlib.Path
        Destination to write to.  May be an open HDF5 file handle or a
        filename.
    """

    if isinstance(dest, (str, pathlib.Path)):
        with h5py.File(dest, "w") as h5:
            return self._write_genesis4(h5)
    if isinstance(dest, h5py.Group):
        return self._write_genesis4(dest)

    raise ValueError(
        f"Unsupported destination: {dest}. It should be a path or an h5py Group"
    )
genesis.version4.output.FieldFile.write_openpmd_wavefront
write_openpmd_wavefront(dest, verbose=True)

Write the field file information to the given HDF5 file in OpenPMD-wavefront format.

Parameters:

Name Type Description Default
dest str, pathlib.Path, or h5py.Group

Filename or already-open h5py.Group to write to.

required
Source code in genesis/version4/field.py
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
def write_openpmd_wavefront(
    self,
    dest: Union[AnyPath, h5py.Group],
    verbose: bool = True,
) -> None:
    """
    Write the field file information to the given HDF5 file in
    OpenPMD-wavefront format.

    Parameters
    ----------
    dest : str, pathlib.Path, or h5py.Group
        Filename or already-open h5py.Group to write to.
    """
    from .writers import write_openpmd_wavefront, write_openpmd_wavefront_h5

    if isinstance(dest, (str, pathlib.Path)):
        write_openpmd_wavefront(
            str(dest), self.dfl, self.param.model_dump(), verbose=verbose
        )
        return
    if isinstance(dest, h5py.Group):
        write_openpmd_wavefront_h5(dest, self.dfl, self.param.model_dump())
        return

    raise ValueError(type(dest))  # type: ignore[unreachable]

genesis.version4.output.OutputFieldStat

OutputFieldStat(**kwargs)

Bases: _OutputBase

Calculated output field statistics. Mean field position and size.

Source code in genesis/version4/output.py
133
134
135
def __init__(self, **kwargs: Any) -> None:
    extra = _split_extra(type(self), kwargs)
    super().__init__(**kwargs, extra=extra)

Functions

genesis.version4.output.OutputFieldStat.from_output_field classmethod
from_output_field(field)

Calculate all statistics given an OutputField instance.

Source code in genesis/version4/output.py
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
@classmethod
def from_output_field(cls, field: OutputField) -> Optional[OutputFieldStat]:
    """Calculate all statistics given an `OutputField` instance."""
    power = np.nan_to_num(field.power)

    skip_attrs = {
        "energy",  # This is already calculated
    }
    for attr in OutputField.model_fields:
        value = getattr(field, attr)
        if not isinstance(value, np.ndarray):
            skip_attrs.add(attr)

    simple_stats = {
        attr: simple_mean_from_slice_data(getattr(field, attr), weight=power)
        for attr in set(OutputField.model_fields) - skip_attrs
    }
    extra = {
        key: simple_mean_from_slice_data(value, weight=power)
        for key, value in field.extra.items()
    }

    return OutputFieldStat(
        extra=extra,
        energy=field.energy,
        **simple_stats,
    )

genesis.version4.output.OutputFieldGlobal

OutputFieldGlobal(**kwargs)

Bases: _OutputBase

Field-global information from Genesis 4 output. (HDF5 /Field/Global)

Source code in genesis/version4/output.py
133
134
135
def __init__(self, **kwargs: Any) -> None:
    extra = _split_extra(type(self), kwargs)
    super().__init__(**kwargs, extra=extra)

genesis.version4.output.OutputField

OutputField(*args, slen=None, **kwargs)

Bases: _OutputBase

Source code in genesis/version4/output.py
993
994
995
996
997
998
999
def __init__(self, *args, slen: Optional[float] = None, **kwargs):
    super().__init__(*args, **kwargs)

    if slen is not None:
        self.energy = self.calculate_field_energy(slen)
    self.units["energy"] = parsers.known_unit["J"]
    self.units["peak_power"] = parsers.known_unit["W"]

Attributes

genesis.version4.output.OutputField.peak_power property
peak_power

Peak power [W].

genesis.version4.output.OutputField.stat cached property
stat

Calculate statistics for the field.

Returns None if the field data is malformed and no statistics are available.

Functions

genesis.version4.output.OutputField.calculate_field_energy
calculate_field_energy(slen)

Calculate field energy, given global slen.

Source code in genesis/version4/output.py
1009
1010
1011
1012
1013
1014
1015
1016
def calculate_field_energy(self, slen: float) -> np.ndarray:
    """Calculate field energy, given global ``slen``."""
    if not len(self.power):
        return _empty_ndarray()
    # Integrate to get J
    nslice = self.power.shape[1]
    ds = slen / nslice
    return np.sum(self.power, axis=1) * ds / c_light

Lattice information

genesis.version4.output.OutputLattice

OutputLattice(**kwargs)

Bases: _OutputBase

Genesis 4 lattice output information (HDF5 Group "/Lattice").

Array indices are per step of the simulation, which relates to the Z position.

The undulator strength, quadrupole field and other are resolved with the resolution of the requested integration step size, which is given in the dataset .dz.

For the z-position there are two datasets. The regular one .z has the same length and describes the lattice quantities from the position .z[i] to .z[i]+.dz[i] of the integration step i. The dataset .zplot is used for plotting the beam or field parameters along the undulator.

Note that those are evaluated before the integration started, so that there can be one more entry than the lattice datasets. Also if the output is reduced by the output step option in the tracking command, the length of zplot is shorter because it has to match the length of the beam and field parameters.

Source code in genesis/version4/output.py
133
134
135
def __init__(self, **kwargs: Any) -> None:
    extra = _split_extra(type(self), kwargs)
    super().__init__(**kwargs, extra=extra)

Functions

genesis.version4.output.OutputLattice.plot
plot(ax=None)

Plot the lattice \(aw\) and \(qf\) versus \(z\).

Parameters:

Name Type Description Default
ax Axes

The axes to insert the plot. If not specified, a new plot will be generated.

None

Returns:

Type Description
Axes
Source code in genesis/version4/output.py
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
def plot(self, ax: Optional[matplotlib.axes.Axes] = None) -> matplotlib.axes.Axes:
    """
    Plot the lattice $aw$ and $qf$ versus $z$.

    Parameters
    ----------
    ax : matplotlib.axes.Axes, optional
        The axes to insert the plot.  If not specified, a new plot will be
        generated.

    Returns
    -------
    matplotlib.axes.Axes
    """

    if ax is None:
        _, ax = plt.subplots()

    assert ax is not None

    aw_color = "tab:red"
    ax.set_xlabel(r"$z$ (m)")
    ax.set_ylabel(r"$a_w$", color=aw_color)
    ax.tick_params(axis="y", labelcolor=aw_color)
    ax.step(self.z, self.aw, color=aw_color, where="post")

    ax2 = ax.twinx()
    qf_color = "tab:blue"
    ax2.set_ylabel(r"$k_1$ (m$^{-2}$)", color=qf_color)
    ax2.tick_params(axis="y", labelcolor=qf_color)
    ax2.step(self.z, self.qf, color=qf_color, where="post")
    plt.show()
    return ax

Beam information

genesis.version4.output.OutputBeamStat

OutputBeamStat(**kwargs)

Bases: _OutputBase

Output Beam statistics, based on HDF5 /Beam.

These are calculated for you by LUME-Genesis.

Source code in genesis/version4/output.py
133
134
135
def __init__(self, **kwargs: Any) -> None:
    extra = _split_extra(type(self), kwargs)
    super().__init__(**kwargs, extra=extra)

Functions

genesis.version4.output.OutputBeamStat.calculate_bunching staticmethod
calculate_bunching(current, bunching, bunchingphase)

Calculate bunching.

Parameters:

Name Type Description Default
current ndarray
required
bunching ndarray
required
bunchingphase ndarray
required

Returns:

Type Description
ndarray
Source code in genesis/version4/output.py
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
@staticmethod
def calculate_bunching(
    current: np.ndarray,
    bunching: np.ndarray,
    bunchingphase: np.ndarray,
) -> np.ndarray:
    """
    Calculate bunching.

    Parameters
    ----------
    current : np.ndarray
    bunching : np.ndarray
    bunchingphase : np.ndarray

    Returns
    -------
    np.ndarray
    """
    if not len(bunching) or not len(bunchingphase) or not len(current):
        return _empty_ndarray()
    dat = np.nan_to_num(bunching)  # Convert any nan to zero for averaging.
    phase = np.nan_to_num(bunchingphase)
    return np.abs(np.sum(np.exp(1j * phase) * dat * current, axis=1)) / np.sum(
        current, axis=1
    )
genesis.version4.output.OutputBeamStat.calculate_projected_sigma staticmethod
calculate_projected_sigma(current, position, size)

Calculate projected sigma.

Parameters:

Name Type Description Default
current ndarray

1D current array.

required
position ndarray

2D _islice

required
size ndarray

2D >_islice array.

required

Returns:

Type Description
ndarray
Source code in genesis/version4/output.py
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
@staticmethod
def calculate_projected_sigma(
    current: np.ndarray,
    position: np.ndarray,
    size: np.ndarray,
) -> np.ndarray:
    """
    Calculate projected sigma.

    Parameters
    ----------
    current : np.ndarray
        1D current array.
    position : np.ndarray
        2D <x>_islice
    size : np.ndarray
        2D <x^2 - <x> >_islice array.

    Returns
    -------
    np.ndarray
    """
    if not len(position) or not len(size) or not len(current):
        return _empty_ndarray()
    # Properly calculated the projected value
    x = np.nan_to_num(position)  # <x>_islice
    x2 = np.nan_to_num(size**2)  # <x^2>_islice
    norm = np.sum(current, axis=1)
    # Total projected sigma_x
    sigma_x2 = (
        np.sum((x2 + x**2) * current, axis=1) / norm
        - (np.sum(x * current, axis=1) / norm) ** 2
    )
    return np.sqrt(sigma_x2)
genesis.version4.output.OutputBeamStat.from_output_beam classmethod
from_output_beam(beam)

Calculate all statistics given an OutputBeam instance.

Source code in genesis/version4/output.py
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
@classmethod
def from_output_beam(cls, beam: OutputBeam) -> OutputBeamStat:
    """Calculate all statistics given an `OutputBeam` instance."""
    current = np.nan_to_num(beam.current)

    skip_attrs = {
        # xsize, ysize don't make sense to keep per cmayes
        "xsize",
        "ysize",
        # Calculated below:
        "bunching",
        # Other:
        "emin",
        "emax",
    }
    for attr in set(OutputBeam.model_fields):
        value = getattr(beam, attr)
        if not isinstance(value, np.ndarray):
            skip_attrs.add(attr)

    simple_stats = {
        attr: simple_mean_from_slice_data(getattr(beam, attr), weight=current)
        for attr in set(OutputBeam.model_fields) - skip_attrs
    }
    extra = {
        key: simple_mean_from_slice_data(value, weight=current)
        for key, value in beam.extra.items()
    }
    units = dict(beam.units)
    units["sigma_x"] = pmd_unit("m")
    units["sigma_y"] = pmd_unit("m")
    units["sigma_energy"] = pmd_unit("eV")
    return OutputBeamStat(
        units=units,
        sigma_x=cls.calculate_projected_sigma(
            current=current,
            size=beam.xsize,
            position=beam.xposition,
        ),
        sigma_y=cls.calculate_projected_sigma(
            current=current,
            size=beam.ysize,
            position=beam.yposition,
        ),
        sigma_energy=cls.calculate_projected_sigma(
            current=current,
            size=beam.energyspread,
            position=beam.energy,
        ),
        bunching=cls.calculate_bunching(
            current=current,
            bunching=beam.bunching,
            bunchingphase=beam.bunchingphase,
        ),
        extra=extra,
        **simple_stats,
    )

genesis.version4.output.OutputBeamGlobal

OutputBeamGlobal(**kwargs)

Bases: _OutputBase

Output beam global information. (HDF5 /Beam/Global)

Source code in genesis/version4/output.py
133
134
135
def __init__(self, **kwargs: Any) -> None:
    extra = _split_extra(type(self), kwargs)
    super().__init__(**kwargs, extra=extra)

genesis.version4.output.OutputBeam

OutputBeam(**kwargs)

Bases: _OutputBase

Output beam information. (HDF5 /Beam)

Source code in genesis/version4/output.py
133
134
135
def __init__(self, **kwargs: Any) -> None:
    extra = _split_extra(type(self), kwargs)
    super().__init__(**kwargs, extra=extra)

Attributes

genesis.version4.output.OutputBeam.stat cached property
stat

Calculate statistics for the beam.

Returns None if the beam data is malformed and no statistics are available.

Metadata

genesis.version4.output.OutputMetaDumps

OutputMetaDumps(**kwargs)

Bases: _OutputBase

Dump-related output information. (HDF5 /Meta/*dumps)

Source code in genesis/version4/output.py
733
734
735
736
737
738
739
740
def __init__(self, **kwargs) -> None:
    filename_keys = [key for key in kwargs if key.startswith("filename_")]
    filenames = kwargs.pop("filenames", {})
    assert isinstance(filenames, dict)
    filenames.update(
        {key[len("filename_") :]: kwargs.pop(key) for key in filename_keys}
    )
    super().__init__(filenames=filenames, **kwargs)

genesis.version4.output.OutputMetaVersion

OutputMetaVersion(**kwargs)

Bases: _OutputBase

Version information from Genesis 4 output. (HDF5 /Meta/Version)

Source code in genesis/version4/output.py
133
134
135
def __init__(self, **kwargs: Any) -> None:
    extra = _split_extra(type(self), kwargs)
    super().__init__(**kwargs, extra=extra)

genesis.version4.output.OutputMeta

OutputMeta(**kwargs)

Bases: _OutputBase

Meta information from Genesis 4 output. (HDF5 /Meta)

Source code in genesis/version4/output.py
133
134
135
def __init__(self, **kwargs: Any) -> None:
    extra = _split_extra(type(self), kwargs)
    super().__init__(**kwargs, extra=extra)