Skip to content

Genesis4

genesis.Genesis4

Genesis4(input=None, lattice='', *, workdir=None, output=None, alias=None, units=None, command=None, command_mpi=None, use_mpi=False, mpi_run='', use_temp_dir=True, verbose=tools.global_display_options.verbose >= 1, timeout=None, initial_particles=None, initial_field=None, **kwargs)

Bases: CommandWrapper

Genesis 4 command wrapper for Python-defined configurations and lattices.

Files will be written into a temporary directory within workdir. If workdir=None, a location will be determined by the system.

Parameters:

Name Type Description Default
input MainInput, Genesis4Input, str, or pathlib.Path

Input settings for the Genesis 4 run. This may be a full configuration (Genesis4Input), main input file contents, or a path to an existing file with main input settings (e.g., genesis4.in).

None
lattice (Lattice, str or Path)

Lattice file source code or path to a lattice file. Not required if Genesis4Input is used for the input parameter.

''
command str

The command to run to execute Genesis 4.

"genesis4"
command_mpi str

The Genesis 4 executable to run under MPI.

"genesis4"
use_mpi bool

Enable parallel processing with MPI.

False
mpi_run str

The template for invoking mpirun. If not specified, the class attribute MPI_RUN is used. This is expected to be a formated string taking as parameters the number of processors (nproc) and the command to be executed (command_mpi).

""
use_temp_dir bool

Whether or not to use a temporary directory to run the process.

True
workdir path - like

The work directory to be used.

None
verbose bool

Whether or not to produce verbose output. Defaults to global_display_options.verbose, which is tied to the LUME_VERBOSE environment variable. When the variable is unset, verbose is False by default.

verbose >= 1
timeout float

The timeout in seconds to be used when running Genesis.

None
initial_particles ParticleGroup or Genesis4ParticleData

Initial particles to use in the simulation, using the OpenPMD-beamphysics standard.

None
initial_field FieldFile

Initial Genesis 4 format field file to use in the simulation. Use FieldFile.from_file to load the file first.

None
Source code in genesis/version4/run.py
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
def __init__(
    self,
    input: Optional[Union[MainInput, Genesis4Input, str, pathlib.Path]] = None,
    lattice: Union[Lattice, str, pathlib.Path] = "",
    *,
    workdir: Optional[Union[str, pathlib.Path]] = None,
    output: Optional[Genesis4Output] = None,
    alias: Optional[Dict[str, str]] = None,
    units: Optional[Dict[str, pmd_unit]] = None,
    command: Optional[str] = None,
    command_mpi: Optional[str] = None,
    use_mpi: bool = False,
    mpi_run: str = "",
    use_temp_dir: bool = True,
    verbose: bool = tools.global_display_options.verbose >= 1,
    timeout: Optional[float] = None,
    initial_particles: Optional[Union[ParticleGroup, Genesis4ParticleData]] = None,
    initial_field: Optional[FieldFile] = None,
    **kwargs: Any,
):
    super().__init__(
        command=command,
        command_mpi=command_mpi,
        use_mpi=use_mpi,
        mpi_run=mpi_run,
        use_temp_dir=use_temp_dir,
        workdir=workdir,
        verbose=verbose,
        timeout=timeout,
        **kwargs,
    )

    if input is None:
        input = Genesis4Input(
            main=MainInput(),
            lattice=Lattice(),
            initial_particles=initial_particles,
        )
    elif isinstance(input, MainInput):
        input = Genesis4Input.from_main_input(
            main=input,
            lattice=lattice,
            source_path=pathlib.Path(workdir or "."),
        )
    elif not isinstance(input, Genesis4Input):
        # We have either a string or a filename for our main input.
        workdir, input = _make_genesis4_input(
            input,
            lattice,
            source_path=workdir,
        )

    if (
        input.initial_particles is not initial_particles
        and initial_particles is not None
    ):
        input.initial_particles = initial_particles

    if input.initial_field is not initial_field and initial_field is not None:
        input.initial_field = initial_field

    if workdir is None:
        workdir = pathlib.Path(".")

    self.original_path = workdir
    self._input = input
    self.output = output

    # Internal
    self._units = dict(units or parsers.known_unit)
    self._alias = dict(alias or {})

    # MPI
    self.nproc = 1
    self.nnode = 1

Attributes

genesis.Genesis4.initial_field property writable
initial_field

Initial field, if defined. Property is alias for .input.main.initial_field.

genesis.Genesis4.initial_particles property writable
initial_particles

Initial particles, if defined. Property is alias for .input.main.initial_particles.

genesis.Genesis4.input property writable
input

The Genesis 4 input, including namelists and lattice information.

genesis.Genesis4.nproc property writable
nproc

Number of MPI processes to use.

Functions

genesis.Genesis4.archive
archive(dest)

Archive the latest run, input and output, to a single HDF5 file.

Parameters:

Name Type Description Default
dest filename or Group
required
Source code in genesis/version4/run.py
577
578
579
580
581
582
583
584
585
586
587
588
589
590
@override
def archive(self, dest: Union[AnyPath, h5py.Group]) -> None:
    """
    Archive the latest run, input and output, to a single HDF5 file.

    Parameters
    ----------
    dest : filename or h5py.Group
    """
    if isinstance(dest, (str, pathlib.Path)):
        with h5py.File(dest, "w") as fp:
            self._archive(fp)
    elif isinstance(dest, (h5py.File, h5py.Group)):
        self._archive(dest)
genesis.Genesis4.configure
configure()

Configure and set up for run.

Source code in genesis/version4/run.py
300
301
302
303
304
305
306
307
308
@override
def configure(self):
    """
    Configure and set up for run.
    """
    self.setup_workdir(self._workdir)
    self.vprint("Configured to run in:", self.path)
    self.configured = True
    self.finished = False
genesis.Genesis4.from_archive classmethod
from_archive(arch)

Create a new Genesis4 object from an archive file.

Parameters:

Name Type Description Default
arch filename or Group
required
Source code in genesis/version4/run.py
616
617
618
619
620
621
622
623
624
625
626
627
628
@override
@classmethod
def from_archive(cls, arch: Union[AnyPath, h5py.Group]) -> Genesis4:
    """
    Create a new Genesis4 object from an archive file.

    Parameters
    ----------
    arch : filename or h5py.Group
    """
    inst = cls()
    inst.load_archive(arch)
    return inst
genesis.Genesis4.get_executable
get_executable()

Gets the full path of the executable from .command, .command_mpi Will search environmental variables: Genesis4.command_env='GENESIS4_BIN' Genesis4.command_mpi_env='GENESIS4_BIN'

Source code in genesis/version4/run.py
433
434
435
436
437
438
439
440
441
442
443
444
445
446
def get_executable(self):
    """
    Gets the full path of the executable from .command, .command_mpi
    Will search environmental variables:
            Genesis4.command_env='GENESIS4_BIN'
            Genesis4.command_mpi_env='GENESIS4_BIN'
    """
    if self.use_mpi:
        return lume_tools.find_executable(
            exename=self.command_mpi, envname=self.command_mpi_env
        )
    return lume_tools.find_executable(
        exename=self.command, envname=self.command_env
    )
genesis.Genesis4.get_run_prefix
get_run_prefix()

Get the command prefix to run Genesis (e.g., 'mpirun' or 'genesis4').

Source code in genesis/version4/run.py
448
449
450
451
452
453
454
455
456
457
458
459
460
def get_run_prefix(self) -> str:
    """Get the command prefix to run Genesis (e.g., 'mpirun' or 'genesis4')."""
    exe = self.get_executable()

    if self.nproc != 1 and not self.use_mpi:
        self.vprint(f"Setting use_mpi = True because nproc = {self.nproc}")
        self.use_mpi = True

    if self.use_mpi:
        return self.mpi_run.format(
            nnode=self.nnode, nproc=self.nproc, command_mpi=exe
        )
    return exe
genesis.Genesis4.get_run_script
get_run_script(write_to_path=True)

Assembles the run script using self.mpi_run string of the form: 'mpirun -n {n} {command_mpi}' Optionally writes a file 'run' with this line to path.

mpi_exe could be a complicated string like: 'srun -N 1 --cpu_bind=cores {n} {command_mpi}' or 'mpirun -n {n} {command_mpi}'

Source code in genesis/version4/run.py
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
@override
def get_run_script(self, write_to_path: bool = True) -> str:
    """
    Assembles the run script using self.mpi_run string of the form:
        'mpirun -n {n} {command_mpi}'
    Optionally writes a file 'run' with this line to path.

    mpi_exe could be a complicated string like:
        'srun -N 1 --cpu_bind=cores {n} {command_mpi}'
        or
        'mpirun -n {n} {command_mpi}'
    """
    if self.path is None:
        raise ValueError("path (base_path) not yet set")

    runscript = shlex.join(
        [
            *shlex.split(self.get_run_prefix()),
            *self.input.arguments,
        ]
    )

    if write_to_path:
        self.write_run_script()

    return runscript
genesis.Genesis4.input_parser staticmethod
input_parser(path)

Invoke the specialized main input parser and returns the MainInput instance.

Parameters:

Name Type Description Default
path str or Path

Path to the main input file.

required

Returns:

Type Description
MainInput
Source code in genesis/version4/run.py
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
@override
@staticmethod
def input_parser(path: AnyPath) -> MainInput:
    """
    Invoke the specialized main input parser and returns the `MainInput`
    instance.

    Parameters
    ----------
    path : str or pathlib.Path
        Path to the main input file.

    Returns
    -------
    MainInput
    """
    return MainInput.from_file(path)
genesis.Genesis4.lattice_parser staticmethod
lattice_parser(path)

Invoke the specialized lattice input parser and returns the Lattice instance.

Parameters:

Name Type Description Default
path str or Path

Path to the lattice input file.

required

Returns:

Type Description
Lattice
Source code in genesis/version4/run.py
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
@staticmethod
def lattice_parser(path: AnyPath) -> Lattice:
    """
    Invoke the specialized lattice input parser and returns the `Lattice`
    instance.

    Parameters
    ----------
    path : str or pathlib.Path
        Path to the lattice input file.

    Returns
    -------
    Lattice
    """
    return Lattice.from_file(path)
genesis.Genesis4.load_archive
load_archive(arch)

Load an archive from a single HDF5 file into this Genesis4 object.

Parameters:

Name Type Description Default
arch filename or Group
required
Source code in genesis/version4/run.py
601
602
603
604
605
606
607
608
609
610
611
612
613
614
@override
def load_archive(self, arch: Union[AnyPath, h5py.Group]) -> None:
    """
    Load an archive from a single HDF5 file into this Genesis4 object.

    Parameters
    ----------
    arch : filename or h5py.Group
    """
    if isinstance(arch, (str, pathlib.Path)):
        with h5py.File(arch, "r") as fp:
            self._load_archive(fp)
    elif isinstance(arch, (h5py.File, h5py.Group)):
        self._load_archive(arch)
genesis.Genesis4.load_output
load_output(load_fields=False, load_particles=False, smear=True)

Load the Genesis 4 output files from disk.

Parameters:

Name Type Description Default
load_fields bool

Load all field files.

True
load_particles bool

Load all particle files.

True
smear bool

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

True

Returns:

Type Description
Genesis4Output
Source code in genesis/version4/run.py
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
@override
def load_output(
    self,
    load_fields: bool = False,
    load_particles: bool = False,
    smear: bool = True,
) -> Genesis4Output:
    """
    Load the Genesis 4 output files from disk.

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

    Returns
    -------
    Genesis4Output
    """
    if self.path is None:
        raise ValueError(
            "Cannot load the output if path is not set. "
            "Did you forget to run `.configure()`?"
        )
    return Genesis4Output.from_input_settings(
        input=self.input,
        workdir=pathlib.Path(self.path),
        load_fields=load_fields,
        load_particles=load_particles,
        smear=smear,
    )
genesis.Genesis4.load_raw_h5_output
load_raw_h5_output()

Load the unprocessed Genesis 4 HDF5 file from the last run.

Returns:

Type Description
File
Source code in genesis/version4/run.py
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
def load_raw_h5_output(self) -> h5py.File:
    """
    Load the unprocessed Genesis 4 HDF5 file from the last run.

    Returns
    -------
    h5py.File
    """
    if self.path is None:
        raise ValueError(
            "Cannot load the output if path is not set. "
            "Did you forget to run `.configure()`?"
        )
    filename = Genesis4Output.get_output_filename(
        self.input,
        workdir=pathlib.Path(self.path),
    )
    return h5py.File(filename)
genesis.Genesis4.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 list

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

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

'linear'
yscale2

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/run.py
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
@override
def plot(
    self,
    y: Union[str, Sequence[str]] = "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
    ----------
    y : list
        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.
    """
    if self.output is None:
        raise RuntimeError(
            "Genesis 4 has not yet been run; there is no output to plot."
        )

    if not tools.is_jupyter():
        # If not in jupyter mode, return a figure by default.
        return_figure = True

    return self.output.plot(
        y=y,
        x=x,
        xlim=xlim,
        ylim=ylim,
        ylim2=ylim2,
        yscale=yscale,
        yscale2=yscale2,
        y2=y2,
        nice=nice,
        include_layout=include_layout,
        include_legend=include_legend,
        return_figure=return_figure,
        tex=tex,
        **kwargs,
    )
genesis.Genesis4.run
run(load_fields=False, load_particles=False, smear=True, raise_on_error=True)

Execute Genesis 4 with 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
raise_on_error bool

If Genesis 4 fails to run, raise an error. Depending on the error, output information may still be accessible in the .output attribute.

True

Returns:

Type Description
Genesis4Output

The output data. This is also accessible as .output.

Source code in genesis/version4/run.py
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
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
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
427
428
429
430
431
@override
def run(
    self,
    load_fields: bool = False,
    load_particles: bool = False,
    smear: bool = True,
    raise_on_error: bool = True,
) -> Genesis4Output:
    """
    Execute Genesis 4 with 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.
    raise_on_error : bool, default=True
        If Genesis 4 fails to run, raise an error. Depending on the error,
        output information may still be accessible in the ``.output``
        attribute.

    Returns
    -------
    Genesis4Output
        The output data.  This is also accessible as ``.output``.
    """
    if not self.configured:
        self.configure()

    if self.path is None:
        raise ValueError("Path (base_path) not yet set")

    self.finished = False

    runscript = self.get_run_script()

    start_time = monotonic()
    self.vprint(f"Running Genesis4 in {self.path}")
    self.vprint(runscript)

    self.write_input()

    if self.timeout:
        self.vprint(
            f"Timeout of {self.timeout} is being used; output will be "
            f"displaye after Genesis exits."
        )
        execute_result = tools.execute2(
            shlex.split(runscript),
            timeout=self.timeout,
            cwd=self.path,
        )
        self.vprint(execute_result["log"])
    else:
        log = []
        try:
            for line in tools.execute(shlex.split(runscript), cwd=self.path):
                self.vprint(line, end="")
                log.append(line)
        except Exception as ex:
            log.append(f"Genesis 4 exited with an error: {ex}")
            self.vprint(log[-1])
            execute_result = {
                "log": "".join(log),
                "error": True,
                "why_error": "error",
            }
        else:
            execute_result = {
                "log": "".join(log),
                "error": False,
                "why_error": "",
            }

    end_time = monotonic()

    self.finished = True
    run_info = RunInfo(
        run_script=runscript,
        error=execute_result["error"],
        error_reason=execute_result["why_error"],
        start_time=start_time,
        end_time=end_time,
        run_time=end_time - start_time,
        output_log=execute_result["log"],
    )

    success_or_failure = "Success" if not execute_result["error"] else "Failure"
    self.vprint(f"{success_or_failure} - execution took {run_info.run_time:0.2f}s.")

    try:
        self.output = self.load_output(
            load_fields=load_fields,
            load_particles=load_particles,
            smear=smear,
        )
    except Exception as ex:
        stack = traceback.format_exc()
        run_info.error = True
        run_info.error_reason = (
            f"Failed to load output file. {ex.__class__.__name__}: {ex}\n{stack}"
        )
        self.output = Genesis4Output(run=run_info)
        if hasattr(ex, "add_note"):
            # Python 3.11+
            ex.add_note(
                f"\nGenesis output was:\n\n{execute_result['log']}\n(End of Genesis output)"
            )
        if raise_on_error:
            raise

    self.output.run = run_info
    if run_info.error and raise_on_error:
        raise Genesis4RunFailure(
            f"Genesis 4 failed to run: {run_info.error_reason}"
        )

    return self.output
genesis.Genesis4.stat
stat(key)

Calculate a statistic of the beam or field along z.

Source code in genesis/version4/run.py
768
769
770
771
772
773
774
775
776
def stat(self, key: str):
    """
    Calculate a statistic of the beam or field along z.
    """
    if self.output is None:
        raise RuntimeError(
            "Genesis 4 has not yet been run; there is no output to get statistics from."
        )
    return self.output.stat(key=key)
genesis.Genesis4.write_input
write_input(path=None, write_run_script=True)

Write the input parameters into the file.

Parameters:

Name Type Description Default
path str

The directory to write the input parameters

None
Source code in genesis/version4/run.py
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
@override
def write_input(
    self,
    path: Optional[AnyPath] = None,
    write_run_script: bool = True,
):
    """
    Write the input parameters into the file.

    Parameters
    ----------
    path : str, optional
        The directory to write the input parameters
    """
    if not self.configured:
        self.configure()

    if path is None:
        path = self.path

    if path is None:
        raise ValueError("Path has not yet been set; cannot write input.")

    path = pathlib.Path(path)
    self.input.write(workdir=path)
    if write_run_script:
        self.write_run_script(path)
genesis.Genesis4.write_run_script
write_run_script(path=None)

Write the 'run' script which can be used in a terminal to launch Genesis.

This is also performed automatically in write_input and get_run_script.

Parameters:

Name Type Description Default
path Path or str

Where to write the run script. Defaults to {self.path}/run.

None

Returns:

Type Description
Path

The run script location.

Source code in genesis/version4/run.py
489
490
491
492
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
def write_run_script(self, path: Optional[AnyPath] = None) -> pathlib.Path:
    """
    Write the 'run' script which can be used in a terminal to launch Genesis.

    This is also performed automatically in `write_input` and
    `get_run_script`.

    Parameters
    -------
    path : pathlib.Path or str
        Where to write the run script.  Defaults to `{self.path}/run`.

    Returns
    -------
    pathlib.Path
        The run script location.
    """
    path = path or self.path
    if path is None:
        raise ValueError("path (base_path) not yet set and no path specified")

    path = pathlib.Path(path)
    if path.is_dir():
        path = path / "run"

    self.input.write_run_script(
        path,
        command_prefix=self.get_run_prefix(),
    )
    logger.debug("Wrote run script to %s", path)
    return path

genesis.version4.Genesis4Input

Genesis4Input(**data)

Bases: BaseModel

All Genesis 4-related command input.

Attributes:

Name Type Description
main MainInput

The main input. This contains all the namelists, starting with &setup.

lattice Lattice

The lattice definition.

beamline (str, optional)

Optional override for beamline in the setup namelist.

lattice_name (str, optional)

Optional override for lattice in the setup namelist.

seed (str, optional)

Optional override for seed in the setup namelist.

output_path Optional[AnyPath] = None

Optional override for rootname in the setup namelist.

source_path Optional[AnyPath] = None

When using Genesis 4-compatible input as strings, this is the directory where we expect to find other input HDF5 files.

input_filename str = "genesis4.in"

The filename to use when writing the main input file. As a user, you should not need to worry about this as Genesis4Input will handle it for you.

initial_particles (ParticleGroup, optional)

OpenPMD ParticleGroup to use as the initial Genesis 4 particle distribution. If set, this acts as a shortcut for automatically adding an importdistribution namelist and writing the corresponding HDF5 file for Genesis.

initial_field (FieldFile, optional)

Initial Genesis 4 format field file to use in the simulation. Use FieldFile.from_file to load the file first.

Source code in genesis/version4/input/core.py
1003
1004
1005
1006
1007
1008
def __init__(self, /, **data: Any) -> None:
    self.__pydantic_validator__.validate_python(
        data,
        self_instance=self,
        context={"initializing": True},
    )

Attributes

genesis.version4.Genesis4Input.arguments property
arguments

Get all of the command-line arguments for running Genesis 4.

Returns:

Type Description
list of str

Individual arguments to pass to Genesis 4.

genesis.version4.Genesis4Input.lattice_filename property
lattice_filename

The filename of the lattice, determined from the Setup namelist.

Defaults to "genesis.lat" if not previously set.

Functions

genesis.version4.Genesis4Input.archive
archive(h5)

Dump input data 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/input/core.py
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
def archive(self, h5: h5py.Group) -> None:
    """
    Dump input data 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.Genesis4Input.from_archive classmethod
from_archive(h5)

Loads input from archived h5 file.

Parameters:

Name Type Description Default
h5 str or File

The filename or handle on h5py.File from which to load data.

required
Source code in genesis/version4/input/core.py
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
@classmethod
def from_archive(cls, h5: h5py.Group) -> Genesis4Input:
    """
    Loads input from archived h5 file.

    Parameters
    ----------
    h5 : str or h5py.File
        The filename or handle on h5py.File from which to load data.
    """
    loaded = _archive.restore_from_hdf5_file(h5)
    if not isinstance(loaded, Genesis4Input):
        raise ValueError(
            f"Loaded {loaded.__class__.__name__} instead of a "
            f"Genesis4Input instance.  Was the HDF group correct?"
        )
    return loaded
genesis.version4.Genesis4Input.from_main_input classmethod
from_main_input(main, lattice='', *, source_path=None)

Work with a lume-genesis MainInput and potentially an external lattice file or instance.

If the input refers to files that already exist on disk, ensures that source_path is set correctly.

Source code in genesis/version4/input/core.py
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
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
@classmethod
def from_main_input(
    cls,
    main: MainInput,
    lattice: Union[Lattice, str, pathlib.Path] = "",
    *,
    source_path: Optional[pathlib.Path] = None,
) -> Genesis4Input:
    """
    Work with a lume-genesis MainInput and potentially an external
    lattice file or instance.

    If the input refers to files that already exist on disk, ensures
    that `source_path` is set correctly.
    """
    from .lattice import Lattice

    if source_path is None:
        source_path = pathlib.Path(".")

    if isinstance(lattice, Lattice):
        return cls(
            main=main,
            lattice=lattice,
            source_path=source_path,
        )

    if lattice:
        lattice_path, lattice = tools.read_if_path(lattice)
        if lattice_path is not None:
            try:
                setup = main.setup
            except NoSuchNamelistError:
                # No setup yet; skip for now
                pass
            else:
                main.setup.lattice = lattice_path.name
        lattice = Lattice.from_contents(lattice, filename=lattice_path)
    else:
        logger.debug("Lattice not specified; determining from main input")
        setup = None
        try:
            setup = main.setup
            assert setup is not None
            # Use the lattice filename from main input's setup:
            with open(source_path / setup.lattice) as fp:
                lattice = fp.read()
        except Exception:
            if setup is not None:
                logger.exception(
                    (
                        "Lattice not specified and unable to determine it from the "
                        "main input's setup. Setup.lattice=%s Lattice file should "
                        "be located here: %s"
                    ),
                    setup.lattice,
                    source_path / setup.lattice,
                )
            raise
        lattice = Lattice.from_contents(
            lattice, filename=source_path / setup.lattice
        )

    return cls(
        main=main,
        lattice=lattice,
        source_path=source_path,
    )
genesis.version4.Genesis4Input.from_strings classmethod
from_strings(main, lattice='', *, source_path=pathlib.Path('.'), input_filename=None, lattice_filename=None)

Work directly with Genesis 4-compatible inputs.

If unspecified, lattice will be determined from the main input settings.

If the input refers to files that already exist on disk, ensures that source_path is set correctly.

Source code in genesis/version4/input/core.py
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
@classmethod
def from_strings(
    cls,
    main: str,
    lattice: str = "",
    *,
    source_path: pathlib.Path = pathlib.Path("."),
    input_filename: Optional[pathlib.Path] = None,
    lattice_filename: Optional[pathlib.Path] = None,
) -> Genesis4Input:
    """
    Work directly with Genesis 4-compatible inputs.

    If unspecified, `lattice` will be determined from the `main` input
    settings.

    If the input refers to files that already exist on disk, ensures
    that `source_path` is set correctly.
    """
    from .lattice import Lattice

    main_config = MainInput.from_contents(main, filename=input_filename)

    if not lattice:
        return cls.from_main_input(main_config, source_path=source_path)

    return cls(
        main=main_config,
        lattice=Lattice.from_contents(lattice, filename=lattice_filename),
        source_path=source_path,
    )
genesis.version4.Genesis4Input.write
write(workdir=pathlib.Path('.'), rename=True)

Write all input files for executing Genesis 4.

Parameters:

Name Type Description Default
workdir AnyPath

The working directory for Genesis 4. This will be where all input and output files are written.

Path('.')
rename bool

Adjust temporary filenames of HDF5 files, replacing random characters with sensible namelist-prefixed names.

True

Returns:

Type Description
List[Path]

Paths written.

Source code in genesis/version4/input/core.py
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
def write(
    self,
    workdir: AnyPath = pathlib.Path("."),
    rename: bool = True,
) -> List[pathlib.Path]:
    """
    Write all input files for executing Genesis 4.

    Parameters
    ----------
    workdir : AnyPath
        The working directory for Genesis 4. This will be where all
        input and output files are written.
    rename : bool, optional
        Adjust temporary filenames of HDF5 files, replacing random
        characters with sensible namelist-prefixed names.

    Returns
    -------
    List[pathlib.Path]
        Paths written.
    """
    path = pathlib.Path(workdir)
    path.mkdir(parents=True, mode=0o755, exist_ok=True)

    extra_paths = []
    # Write the particle and field files prior to MainInput, as it will
    # check to ensure that they exist
    if self.initial_particles is not None:
        extra_paths.append(self.write_initial_particles(path))

    if self.initial_field is not None:
        extra_paths.append(self.write_initial_field(path))

    main_paths = self.main.write_files(
        path,
        main_filename=self.input_filename,
        source_path=self.source_path,
        rename=rename,
    )

    extra_paths.extend(main_paths)

    lattice_path = path / self.lattice_filename
    self.lattice.to_file(filename=lattice_path)
    return [path / self.input_filename, lattice_path, *extra_paths]
genesis.version4.Genesis4Input.write_context
write_context(workdir)

Write all input files for executing Genesis 4.

This is a context manager. When the context manager exits, all input files will be cleaned up (i.e., deleted from disk).

Parameters:

Name Type Description Default
workdir AnyPath

The working directory for Genesis 4. This will be where all input and output files are written.

required

Yields:

Type Description
List[Path]

Paths written.

Source code in genesis/version4/input/core.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
@contextmanager
def write_context(
    self, workdir: AnyPath
) -> Generator[List[pathlib.Path], None, None]:
    """
    Write all input files for executing Genesis 4.

    This is a context manager. When the context manager exits, all input
    files will be cleaned up (i.e., deleted from disk).

    Parameters
    ----------
    workdir : AnyPath
        The working directory for Genesis 4. This will be where all
        input and output files are written.

    Yields
    ------
    List[pathlib.Path]
        Paths written.
    """
    paths = self.write(workdir)
    yield paths
    for path in paths:
        path.unlink(missing_ok=True)
genesis.version4.Genesis4Input.write_initial_field
write_initial_field(workdir)

Write the initial field file.

Source code in genesis/version4/input/core.py
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
def write_initial_field(self, workdir: AnyPath) -> pathlib.Path:
    """Write the initial field file."""
    if self.initial_field is None:
        raise ValueError("initial_field was not set")

    workdir = pathlib.Path(workdir)
    if not workdir.is_dir():
        raise ValueError("Provided path is not a directory: {}")

    import_field = self.main.import_field
    if not import_field.file:
        raise ValueError("import_field filename (.file) unset")

    filename = workdir / import_field.file
    self.initial_field.write_genesis4(filename)
    return filename
genesis.version4.Genesis4Input.write_initial_particles
write_initial_particles(workdir)

Write the initial particles file.

Source code in genesis/version4/input/core.py
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
def write_initial_particles(self, workdir: AnyPath) -> pathlib.Path:
    """Write the initial particles file."""
    if self.initial_particles is None:
        raise ValueError("initial_particles was not set")

    workdir = pathlib.Path(workdir)
    if not workdir.is_dir():
        raise ValueError("Provided path is not a directory: {}")

    if isinstance(self.initial_particles, Genesis4ParticleData):
        beam = self.main.import_beam
        particle_file = pathlib.Path(workdir) / beam.file
    elif isinstance(self.initial_particles, ParticleGroup):
        dist = self.main.import_distribution
        particle_file = pathlib.Path(workdir) / dist.file
        if dist.charge != self.initial_particles.charge:
            logger.warning(
                f"Updating distribution charge: was={dist.charge} "
                f"now={self.initial_particles.charge}"
            )
            dist.charge = self.initial_particles.charge
        for time_ in self.main.times:
            was = time_.slen
            time_.slen = get_particles_slen(self.initial_particles)
            if time_.slen != was:
                logger.warning(
                    f"Updating time namelist slen: was={was} now {time_.slen}",
                )
    else:
        raise ValueError(
            f"Initial particles type unexpected: {type(self.initial_particles).__name__}"
        )

    self.initial_particles.write_genesis4_distribution(
        str(particle_file),
        verbose=False,
    )
    return particle_file

genesis.version4.types.BaseModel

Bases: BaseModel

LUME-Genesis customized pydantic BaseModel.

Alters dir() handling and other things for user convenience.