Skip to content

Xcoll release 0.7.0

Choose a tag to compare

@freddieknets freddieknets released this 08 Nov 15:42
· 15 commits to main since this release
e5fad72

What's Changed

General

  • CollimatorDatabase now has to_dict, to_json, and to_yaml functionality.
  • New class ParticlesTree to inspect the family tree of particles and their children. This is an experimental feature and the API might change in future releases. See tests/test_particle_id_hierarchy.py for some example usage. Some inspection functions like print_tree (ASCII) and plot_tree (with matplotlib) are available but limited in usability when many particles are shown.

Materials

  • Expansive list of predefined materials and alias names (see xcoll.materials.db.show()), including most atomic elements, and some relevant compounds and mixtures/alloys. Predefined materials originally from K2 still exist with a prefixed name (as in K2MolybdenumGraphite) for backward compatibility if needed.
  • Any material can now be defined, either as:
    • an atomic element (e.g. different allotropes) by specifying Z and A
    • a compound by specifiying components and n_atoms
    • a mixture or alloy by specifying components and mass_fractions, volume_fractions, or molar_fractions (or atomic_fractions which is equivalent to molar_fractions)
    • see examples/materials.py.
  • The material property density is a required argument. Other material properties are automatically estimated, while radiation_length and excitation_energy can also be explicitly provided for more precision if known.
  • Everest-specific parameters (nuclear_radius, nuclear_elastic_slope, cross_section, and hcut) are not yet automatically estimated (though this is in the pipeline). Without these, material interactions are only described by multiple-Coulomb scattering and ionisation loss (so no nuclear scattering). Most materials are hence only partially Everest-compatible. This can be verified with the full_everest_supported attribute.
  • Code auto-generation for Geant4/BDSIM (and blueprint for similar auto-generation for FLUKA) is in place.

Interface to Geant4

(#75, #77, #85, #114, #116, #123, #126, #128, #129, #130, #151 by @freddieknets, @bjlindst, @gbrogginess)

  • Prerequisite: Need a complete installation of Geant4 and BDSIM (easiest is to install bdsim-g4 with conda/mamba). Then compile the interface with xcoll.geant4.environment.compile() (this needs to be done only once).
  • New element Geant4Collimator which works exactly like an EverestCollimator but with Geant4 physics.
  • Before scattering can be active, a connection to Geant4/BDSIM needs to be made. This is done by starting the engine: xcoll.geant4.engine.start(). For this, the necessary arguments are either elements or line to specify which elements are to be linked (with the additional optional argument names if it is only a subset), and particle_ref to describe the beam if not already provided by the line (and in case the line has a different reference particle, this is overwritten by the engine's one and restored when the engine stops). Optional arguments include:
    • seed to set the seed in BDSIM
    • cwd to define a run folder (a random named one is generated by default for the logs etc)
    • clean to clean up connection and log files
    • verbose to print out info during the connection setup and input file generation
    • relative_energy_cut to define a lower energy threshold in kinetic energy for child particles to be considered
    • physics_list to specify the BDSIM/Geant4 physics list to be considered (otherwise a relevant list is chosen in function of the reference particle)
    • stop_secondaries to avoid the generation of child particles
    • extra_opts and extra_input which are extra options resp. commands to be put in the gmad file to be sent to BDSIM.
  • Note that engine attributes can be pre-set on the engine before starting. In that case, they keep their value even after stopping the engine (within the same Python session). Otherwise, they are reset to their defaults after stopping the engine.
  • BDSIM uses an input file with some settings and definitions. This is auto-generated based on the options above, though, for full flexibility, a user-provided file can also be passed to the engine with the input_file argument. Note that, to ensure a certain input file is compatible for the set of elements passed to the engine, the input file has an Xcoll header (as comments) with relevant info of the elements. As it is not trivial to manually generate this header, a function xcoll.geant4.engine.generate_input_file() is available to generate the input file (including the header) based on a line or set of elements, which can then be manually adapted to the user's wishes before using this file to start the engine. It takes the same arguments as xcoll.geant4.engine.start() with the additional optional argument filename.
  • There is a small caveat with starting and stopping the engine in succession (within the same python session, as e.g. happens when testing multiple tests with pytest). Certain environment variables inside Geant4 are not cleared, making a second connection fail in a rather obscure way. This is beyond our control (it has been flagged to the Geant4 devs), but a workaround exists using rpyc to spawn a python session inside the current session, and connect from the nested one over a network protocol. This is the default behaviour (need to pip install rpyc), but can be switched off as it produces a visible performance reduction (around 30% slower tracking). To achieve this, set xcoll.geant4.engine.reentry_protection_enabled = False but this is at the user's own risk, as one has to remember to always exit and restart Python when tracking is interrupted, to avoid unexpected behaviour.
  • The material definition of an element is governed inside Xcoll, and the correct code to define it in BDSIM is auto-generated. If a material already exists in the built-in Geant4/BDSIM databases but not in Xcoll's, there are two options:
    • Define the material in Xcoll the standard way, and set the attribute geant4_name to the correct name (case-sensitive). This will essentially ignore the Xcoll parameters and use the material definition in Geant4/BDSIM. It is the user's responsibility to make sure both definitions represent the same to avoid misunderstandings.
    • Use a ReferenceMaterial which has no properties except geant4_name. This is preferred, as it is clear that no Xcoll definition is used.
  • See the examples for more info.

Develop Updates

  • To be able to use formatted output (as in the materials database), a function style is defined (in xcoll.pretty_print) which uses ANSI styles to format terminal output (color, bg for background colour, italic, bold, underline, and dim are supported).
  • New class Constants to define an xobjects-style set of constants by deriving from it. Constant names are enforced to be unique across all modules the class is imported to. See xcoll/headers/particle_states.py for an example usage.
    • Inside the new class, the following attributes define its logic:
      • __category__ for the name of the constant type (e.g. particle_state).
      • __plural__ (optional) if the auto-generated plural name of the category is not correct.
      • __reverse__ which can be "unique", "multi", or None (default: "unique"). If "unique", constants' values are enforced to be unique across all modules the class is imported to. If None, a reverse look-up does not exist.
      • __c_prefix__ to prefix the generated constant name in the C code.
      • __include_guard__ to wrap the C code in an include shield.
    • Each constant is defined in the class as NAME = constant(value, info=..., c_name=...) or without the wrapper as e.g. NAME = 9.8. The type is automatically deduced, and all constants should be of the same type if the map is reversible. The info attribute is wrapped into a docstring, such that constants can be inspected in an ipython session. If c_name is not provided, it is auto-generated using the main C prefix.
    • A group of constants can be defined as GROUPNAME = group(c1, c2, c3, ..., info=...). This is useful for things like np.isin(part.state, xc.constants.USE_IN_LOSSMAP) where USE_IN_LOSSMAP represents all lost particle state codes for a loss map (apertures and all collimation elements).
    • The class on itself does nothing, but should be exported to a module using the function export_to_module(). See e.g. xcoll/constants/__init__.py which imports the particle states and interaction types into xcoll.constants. In particular it imports:
      • A mapping (dict) between all constant names and their values. This variable is named using its category plural name (e.g. xcoll.constants.particle_states).
      • A reversed mapping between all constant values and their names, if the class is defined to be reversible. This variable is named as <category>_names (e.g. xcoll.constants.particle_state_names).
      • If include_src=True: a string with the C code. This variable is named as <plural>_src (e.g. xc.constants.particle_states_src)
      • If include_meta=True: a mapping between the constants and all their metadata (mainly for debugging). This variable is named as <plural>_meta (e.g. xcoll.constants.particle_states_meta).
      • If import_vars=True: all constants are imported in the module. This allows us to use e.g. xcoll.constants.MASSLESS_OR_NEUTRAL inside a formulation while still getting a description by using ?xcoll.constants.MASSLESS_OR_NEUTRAL in ipython.
      • If include_groups=True: all groups are imported in a way similar to the constants. Additionally, a mapping between the group names and a tuple of constants they represent is imported and named as <category>_groups (e.g. xcoll.constants.particle_state_groups).
    • xcoll/constants/aggregate_constants.py is a first step to implement this behaviour over different packages (not yet used).

Full Changelog: v0.6.8...v0.7.0