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
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
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
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
@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
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
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
@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
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
@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
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
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
1477
1478
1479
1480
1481
1482
1483
1484
1485
@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
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
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()
    }
    units = {
        key: str(array_info.units or "") for key, array_info in array_info.items()
    }

    def get_desc(key: str, info: _ArrayInfo) -> str:
        desc = info.field.description or ""
        unit = units.get(key, "")
        if unit:
            desc = desc.replace(f"[{unit}]", "")

        return f"{desc} (output.{info.dotted_attr})"

    annotations = {key: get_desc(key, info) for key, info in array_info.items()}
    return tools.table_output(
        units,  # 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
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
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
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
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
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
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
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
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
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
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
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
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
1640
1641
1642
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
1753
1754
1755
1756
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
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
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
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
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
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
@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
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
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
@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
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
@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
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
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
1477
1478
1479
1480
1481
1482
1483
1484
1485
@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
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
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()
    }
    units = {
        key: str(array_info.units or "") for key, array_info in array_info.items()
    }

    def get_desc(key: str, info: _ArrayInfo) -> str:
        desc = info.field.description or ""
        unit = units.get(key, "")
        if unit:
            desc = desc.replace(f"[{unit}]", "")

        return f"{desc} (output.{info.dotted_attr})"

    annotations = {key: get_desc(key, info) for key, info in array_info.items()}
    return tools.table_output(
        units,  # 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
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
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
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
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
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
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
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
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
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
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
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
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
1640
1641
1642
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
1753
1754
1755
1756
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
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
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(*args, **kwargs)

Bases: _OutputBase

Calculated output field statistics. Mean field position and size.

Source code in genesis/version4/output.py
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

    self.units.setdefault("intensity_farfield", parsers.known_unit["1"])
    self.units.setdefault("intensity_nearfield", parsers.known_unit["1"])
    self.units.setdefault("phase_farfield", parsers.known_unit["rad"])
    self.units.setdefault("phase_nearfield", parsers.known_unit["rad"])
    self.units.setdefault("power", parsers.known_unit["W"])
    self.units.setdefault("xdivergence", parsers.known_unit["rad"])
    self.units.setdefault("ydivergence", parsers.known_unit["rad"])

    self.units.setdefault("xpointing", parsers.known_unit["rad"])
    self.units.setdefault("ypointing", parsers.known_unit["rad"])
    self.units.setdefault("xposition", parsers.known_unit["m"])
    self.units.setdefault("yposition", parsers.known_unit["m"])

    self.units.setdefault("xsize", parsers.known_unit["m"])
    self.units.setdefault("ysize", parsers.known_unit["m"])
    self.units.setdefault("energy", parsers.known_unit["J"])

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
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
@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()
        if isinstance(value, np.ndarray)
    }

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

genesis.version4.output.OutputFieldGlobal

OutputFieldGlobal(*args, **kwargs)

Bases: _OutputBase

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

Source code in genesis/version4/output.py
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

    self.units.setdefault("energy", parsers.known_unit["J"])
    self.units.setdefault("intensity_farfield", parsers.known_unit["1"])
    self.units.setdefault("intensity_nearfield", parsers.known_unit["1"])
    self.units.setdefault("xdivergence", parsers.known_unit["rad"])
    self.units.setdefault("ydivergence", parsers.known_unit["rad"])
    self.units.setdefault("xpointing", parsers.known_unit["rad"])
    self.units.setdefault("ypointing", parsers.known_unit["rad"])

    self.units.setdefault("xposition", parsers.known_unit["m"])
    self.units.setdefault("yposition", parsers.known_unit["m"])

    self.units.setdefault("xsize", parsers.known_unit["m"])
    self.units.setdefault("ysize", parsers.known_unit["m"])

genesis.version4.output.OutputField

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

Bases: _OutputBase

Source code in genesis/version4/output.py
1196
1197
1198
1199
1200
1201
1202
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
1212
1213
1214
1215
1216
1217
1218
1219
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
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
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, following this formula:

\[ \text{bunching}_m = \frac{\left| \displaystyle\sum_{n=1}^{N} e^{i \phi_{mn}}\, b_{mn}\, I_{mn} \right|}{\displaystyle\sum_{n=1}^{N} I_{mn}} \]

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
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
@staticmethod
def calculate_bunching(
    current: np.ndarray,
    bunching: np.ndarray,
    bunchingphase: np.ndarray,
) -> np.ndarray:
    r"""
    Calculate bunching, following this formula:

    $$ \text{bunching}_m = \frac{\left| \displaystyle\sum_{n=1}^{N} e^{i \phi_{mn}}\, b_{mn}\, I_{mn} \right|}{\displaystyle\sum_{n=1}^{N} I_{mn}} $$

    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
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
@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
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
@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(*args, **kwargs)

Bases: _OutputBase

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

Source code in genesis/version4/output.py
645
646
647
648
649
650
651
652
653
def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

    self.units.setdefault("energy", parsers.known_unit["eV"])
    self.units.setdefault("energyspread", parsers.known_unit["1"])
    self.units.setdefault("xposition", parsers.known_unit["m"])
    self.units.setdefault("yposition", parsers.known_unit["m"])
    self.units.setdefault("xsize", parsers.known_unit["m"])
    self.units.setdefault("ysize", parsers.known_unit["m"])

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
845
846
847
848
849
850
851
852
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)