From c767de8358d40f9bebce5f31bd0064eb08e3439e Mon Sep 17 00:00:00 2001 From: Frederik Van der Veken Date: Wed, 11 Dec 2024 12:18:27 +0100 Subject: [PATCH 1/8] Created release branch release/v0.5.12rc0. --- pyproject.toml | 2 +- tests/test_version.py | 2 +- xcoll/general.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c3fb8391..0f577b41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "xcoll" -version = "0.5.11" +version = "0.5.12rc0" description = "Xsuite collimation package" homepage = "https://github.com/xsuite/xcoll" repository = "https://github.com/xsuite/xcoll" diff --git a/tests/test_version.py b/tests/test_version.py index b59f0fc0..e2969acf 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -6,4 +6,4 @@ from xcoll import __version__ def test_version(): - assert __version__ == '0.5.11' + assert __version__ == '0.5.12rc0' diff --git a/xcoll/general.py b/xcoll/general.py index d1250bdb..b6717055 100644 --- a/xcoll/general.py +++ b/xcoll/general.py @@ -12,5 +12,5 @@ # ====================== # Do not change # ====================== -__version__ = '0.5.11' +__version__ = '0.5.12rc0' # ====================== From 2286031d4b8e72a618a9f8f97ccb09a7b2022fb4 Mon Sep 17 00:00:00 2001 From: Frederik Van der Veken Date: Wed, 11 Dec 2024 12:21:22 +0100 Subject: [PATCH 2/8] Homogenised lost particle state code names. --- xcoll/headers/particle_states.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xcoll/headers/particle_states.h b/xcoll/headers/particle_states.h index 40c471c4..66119085 100644 --- a/xcoll/headers/particle_states.h +++ b/xcoll/headers/particle_states.h @@ -10,10 +10,10 @@ #define XC_LOST_ON_EVEREST_COLL -331 #define XC_LOST_ON_EVEREST_CRYSTAL -332 #define XC_LOST_ON_FLUKA_BLOCK -333 -#define XC_LOST_ON_FLUKA -334 +#define XC_LOST_ON_FLUKA_COLL -334 #define XC_LOST_ON_FLUKA_CRYSTAL -335 #define XC_LOST_ON_GEANT4_BLOCK -336 -#define XC_LOST_ON_GEANT4 -337 +#define XC_LOST_ON_GEANT4_COLL -337 #define XC_LOST_ON_GEANT4_CRYSTAL -338 #define XC_LOST_ON_ABSORBER -340 From 429a032c209150d7f5de90cce8df1e50c83ce3e2 Mon Sep 17 00:00:00 2001 From: Frederik Van der Veken Date: Tue, 17 Dec 2024 15:36:20 +0100 Subject: [PATCH 3/8] Removed leftover print statement form development --- xcoll/line_tools.py | 1 - 1 file changed, 1 deletion(-) diff --git a/xcoll/line_tools.py b/xcoll/line_tools.py index ad7c35ea..0dc9c8f7 100644 --- a/xcoll/line_tools.py +++ b/xcoll/line_tools.py @@ -78,7 +78,6 @@ def install(self, names, elements, *, at_s=None, apertures=None, need_apertures= # Verify elements for el in elements: - print(el.__class__) assert isinstance(el, block_classes) el._tracking = False From c0a1db6b49c1460369af5315b3e61131f045f163 Mon Sep 17 00:00:00 2001 From: Frederik Van der Veken Date: Thu, 2 Jan 2025 05:01:08 +0100 Subject: [PATCH 4/8] Added BaseEngine for later reference and some xaux tools. --- xcoll/scattering_routines/engine.py | 403 ++++++++++++++++++++++++++++ xcoll/xaux.py | 117 ++++++++ 2 files changed, 520 insertions(+) create mode 100644 xcoll/scattering_routines/engine.py create mode 100644 xcoll/xaux.py diff --git a/xcoll/scattering_routines/engine.py b/xcoll/scattering_routines/engine.py new file mode 100644 index 00000000..2c64bd41 --- /dev/null +++ b/xcoll/scattering_routines/engine.py @@ -0,0 +1,403 @@ +# copyright ############################### # +# This file is part of the Xcoll Package. # +# Copyright (c) CERN, 2024. # +# ######################################### # + +import os +import numpy as np +import shutil + +import xobjects as xo +import xpart as xp +import xtrack as xt +try: + # TODO: once xaux is in Xsuite keep only this + from xaux import ClassProperty, ClassPropertyMeta, FsPath, singleton +except ImportError: + from ..xaux import ClassProperty, ClassPropertyMeta, FsPath, singleton + + +class BaseEngineMeta(xo.hybrid_class.MetaHybridClass, ClassPropertyMeta): + pass + +@singleton +class BaseEngine(xo.HybridClass, metaclass=BaseEngineMeta): + _xofields = { + '_particle_ref': xp.Particles, + '_seed': xo.UInt64, + '_capacity': xo.Int64, + } + + _int32 = False + _element_classes = None + _only_protons = False + _uses_input_file = False + _uses_run_folder = False + + def __init__(self, **kwargs): + if not self._initialised: + if np.any([key[0] != '_' for key in self._xofields.keys()]): + raise ValueError(f"All fields in `{self.__class__.__name__}._xofields` have " + + f"to start with an underscore! This is to ensure to work " + + f"correctly with `ClassProperty`.") + if '_xobject' not in kwargs: + # Initialise defaults + self._cwd = None + self._line = None + self._verbose = False + self._input_file = None + self._element_dict = {} + self._warning_given = False + self._tracking_initialised = False + kwargs.setdefault('_particle_ref', xp.Particles()) + kwargs.setdefault('_seed', 0) + kwargs.setdefault('_capacity', 0) + filtered_kwargs = {} + remaining_kwargs = {} + for key, value in kwargs.items(): + if key in self._xofields.keys() or key == '_xobject': + filtered_kwargs[key] = value + else: + remaining_kwargs[key] = value + super().__init__(**filtered_kwargs) + kwargs = remaining_kwargs + self._initialised = True + # Apply kwargs + for kk, vv in kwargs.items(): + if not hasattr(self.__class__, kk): + raise ValueError(f"Invalid attribute {kk} for {self.__class__.__name__}!") + setattr(self, kk, vv) + + def __del__(self, *args, **kwargs): + self.stop(warn=False) + + + def _warn(self, error=None): + if not self._warning_given: + print(f"Warning: Failed to import {self.__class__.__name__} environment " + + f" (did you compile?).\n{self.__class__.__name__.replace('Engine', '')} " + + f"elements will be installed but are not trackable.\n", flush=True) + if error: + print(error, flush=True) + self._warning_given = True + + + # ================== + # === Properties === + # ================== + + + @ClassProperty + def name(cls): + return cls.__name__.replace('Engine', '').lower() + + @ClassProperty + def verbose(cls): + return cls.get_self()._verbose + + @verbose.setter + def verbose(cls, val): + cls.get_self()._verbose = val + + @ClassProperty + def line(cls): + return cls.get_self()._line + + @line.setter + def line(cls, val): + if not val is None and not isinstance(val, xt.Line): + raise ValueError("`line` has to be an xt.Line object!") + cls.get_self()._line = val + + @line.deleter + def line(cls): + cls.get_self()._line = None + + @ClassProperty + def particle_ref(cls): + self = cls.get_self() + initial = xp.Particles().to_dict() + current = self._particle_ref.to_dict() + if xt.line._dicts_equal(initial, current): + return None + else: + return self._particle_ref + + @particle_ref.setter + def particle_ref(cls, val): + self = cls.get_self() + if val is None: + self._particle_ref = xp.Particles() + else: + if not isinstance(val, xp.Particles): + raise ValueError("`particle_ref` has to be an xp.Particles object!") + if val._capacity > 1: + raise ValueError("`particle_ref` has to be a single particle!") + if val.pdg_id[0] == 0: + if cls._only_protons: + val.pdg_id[0] = xp.get_pdg_id_from_name('proton') + else: + raise ValueError("`particle_ref` needs to have a valid pdg_id") + elif cls._only_protons and val.pdg_id[0] != xp.get_pdg_id_from_name('proton'): + raise ValueError("{cls.__name__} only supports protons!") + self._particle_ref = val + + @particle_ref.deleter + def particle_ref(cls): + cls.get_self()._particle_ref = xp.Particles() + + @ClassProperty + def capacity(cls): + self = cls.get_self() + if self._capacity == 0: + return None + else: + return int(self._capacity) + + @capacity.setter + def capacity(cls, val): + if val is None: + val = 0 + cls.get_self()._capacity = int(val) + + @capacity.deleter + def capacity(cls): + raise ValueError("Not allowed.") + + @ClassProperty + def seed(cls): + self = cls.get_self() + if self._seed == 0: + return None + else: + return self._seed + + @seed.setter + def seed(cls, val): + if val is None: + val = 0 + val = int(val) + if cls._int32: + new_val = np.uint32(val) + else: + new_val = np.uint64(val) + if new_val != val: + print(f"Warning: type change for seed {val}. Using {new_val}.") + cls.get_self()._seed = new_val + + @seed.deleter + def seed(cls): + cls.get_self()._seed = 0 + + @ClassProperty + def input_file(cls): + return cls.get_self()._input_file + + + # ====================== + # === Public Methods === + # ====================== + + + @classmethod + def start(cls, *, line=None, elements=None, names=None, cwd=None, seed=None, + particle_ref=None, input_file=None, **kwargs): + self = cls.get_self(**kwargs) + if self.is_running() is None: + raise NotImplementedError(f"Need to implement `is_running` for {cls.__name__}!") + elif self.is_running() is True: + if self.verbose: + print("Engine already running.", flush=True) + return + + self._starting_engine = True # We need this to allow changing the element settings which otherwise are locked + self._use_seed(seed) + self._use_line(line) + self._use_particle_ref(particle_ref) + self._sync_line_particle_ref() + self._get_elements(line=line, elements=elements, names=names) + self._set_cwd(cwd=cwd) + self._use_input_file(input_file=input_file, **kwargs) + self.clean_output_files() + self._starting_engine = False + + + @classmethod + def stop(cls, clean=False, **kwargs): + self = cls.get_self(**kwargs) + if hasattr(self, '_old_seed'): + self.seed = self._old_seed + del self._old_seed + if hasattr(self, '_old_line'): + self.line = self._old_line + del self._old_line + if hasattr(self, '_old_particle_ref'): + self.particle_ref = self._old_particle_ref + del self._old_particle_ref + self._sync_line_particle_ref() + if hasattr(self, '_old_cwd') and self._old_cwd is not None: + os.chdir(self._old_cwd) + del self._old_cwd + if clean: + self.clean_output_files(clean_all=True) + self._cwd = None + self._input_file = None + self._element_dict = {} + self._warning_given = False + self._tracking_initialised = False + + + @classmethod + def assert_particle_ref(cls, **kwargs): + if cls.get_self(**kwargs).particle_ref is None: + raise ValueError(f"{cls.__name__} reference particle not set!") + + + # ======================= + # === Private Methods === + # ======================= + + # For all the following fields, they can either be set in advance on the engine, + # or they can be set when the engine is started. In the latter case, the values + # are temporary and the original will be restored when the engine is stopped. + + def _use_line(self, line=None): + self._old_line = self.line + self.line = line + + def _use_seed(self, seed=None): + self._old_seed = self.seed + if seed is not None: + self.seed = seed + else: + if self.seed is None: + if self._int32: + self.seed = np.random.randint(0, int(2**32)) + else: + self.seed = np.random.randint(0, int(2**64)) + if self.verbose: + print(f"Using seed {self.seed}.") + + def _use_particle_ref(self, particle_ref=None): + # Prefer: provided particle_ref > existing particle_ref > particle_ref from line + self._old_particle_ref = self.particle_ref + if particle_ref is not None: + self.particle_ref = particle_ref + elif self.particle_ref is None: + if self.line is None or not hasattr(self.line, 'particle_ref') \ + or self.line.particle_ref is None: + raise ValueError("Need to provide either a line with a reference " + + "particle, or `particle_ref`.") + self.particle_ref = self.line.particle_ref + if self.verbose: + print(f"Using {xp.get_name_from_pdg_id(self.particle_ref.pdg_id[0])}.") + + def _sync_line_particle_ref(self): + if self.line is None: + return + if self.line.particle_ref is not None \ + and not xt.line._dicts_equal(self.line.particle_ref.to_dict(), + self.particle_ref.to_dict()): + overwrite_particle_ref_in_line = True + if overwrite_particle_ref_in_line: + print("Warning: Found different reference particle in line! Temporarily overwritten.") + self.line.particle_ref = self.particle_ref + + def _get_elements(self, line=None, elements=None, names=None): + if self._element_classes is None: + raise NotImplementedError(f"{self.__class__.__name__} needs to define `_element_classes`!") + if line is None: + if elements is None: + raise ValueError("Need to provide either `line` or `elements`.") + if not hasattr(elements, '__iter__') or isinstance(elements, str): + elements = [elements] + if names is None: + names = [f"{self.__class__.name}_el_{i}" for i, _ in enumerate(elements)] + else: + if not hasattr(names, '__iter__') or isinstance(names, str): + names = [names] + if len(names) != len(elements): + raise ValueError("Length of `elements` and `names` doesn't match.") + else: + if elements is not None: + raise ValueError("Cannot provide both `line` and `elements`.") + if names is None: + elements, names = line.get_elements_of_type(self._element_classes) + else: + if not hasattr(names, '__iter__') or isinstance(names, str): + names = [names] + elements = [line[name] for name in names] + elements = [el for el in elements if el.active and el.jaw is not None] + names = [name for el, name in zip(elements,names) if el.active and el.jaw is not None] + for el in elements: + if not isinstance(el, self._element_classes): + raise ValueError(f"Element {el} is not a " + + ", or a ".join([c.__name__ for c in self._element_classes]) + + ".") + if len(elements) == 0: + raise ValueError(f"No active {self.name} elements found!") + self._element_dict = dict(zip(names, elements)) + + def _set_cwd(self, cwd): + if self._uses_run_folder: + if cwd is not None: + cwd = FsPath(cwd).expanduser().resolve() + else: + # TODO: use xaux.ranID here + import base64 + ran = base64.urlsafe_b64encode(os.urandom(8)).decode('utf-8') + ran_str = ''.join(c if c.isalnum() else 'X' for c in ran) + cwd = FsPath.cwd() / f'{self.name}_run_{ran_str}' + self._cwd = cwd + cwd.mkdir(parents=True, exist_ok=True) + self._old_cwd = FsPath.cwd() + os.chdir(cwd) + + def _use_input_file(self, input_file=None, **kwargs): + if self._uses_input_file: + if input_file is None: + if not hasattr(self, 'generate_input_file'): + raise NotImplementedError("Need to implement `generate_input_file`" + "for {cls.__name__}!") + input_file = self.generate_input_file(**kwargs) + if not hasattr(input_file, '__iter__') or isinstance(input_file, str): + # Some engines might need multiple input files (like Fluka) + input_file = [input_file] + input_file = [FsPath(f).expanduser().resolve() for f in input_file] + new_files = [] + for file in input_file: + if not file.exists(): + raise ValueError(f"Input file {file.as_posix()} not found!") + if file.parent != FsPath.cwd(): + shutil.copy(file, FsPath.cwd()) + new_files.append(FsPath.cwd() / file.name) + else: + new_files.append(file) + self._input_file = new_files[0] if len(new_files)==1 else new_files + self._match_input_file() + + + # =============================== + # === Methods to be inherited === + # =============================== + + @classmethod + def is_running(cls, **kwargs): + self = cls.get_self(**kwargs) + if hasattr(self, '_starting_engine') and self._starting_engine: + # We need this to allow changing the element settings which otherwise are locked + return False + # If we get here, we cannot say if the engine is running or not and we need an + # implementation in the child class + return None + + @classmethod + def clean_output_files(cls, **kwargs): + pass + + def _match_input_file(self, **kwargs): + raise NotImplementedError("Need to implement `_match_input_file` for {cls.__name__}!") + + @classmethod + def generate_input_file(cls, **kwargs): + raise NotImplementedError("Need to implement `generate_input_file` for {cls.__name__}!") diff --git a/xcoll/xaux.py b/xcoll/xaux.py new file mode 100644 index 00000000..c8cba6c9 --- /dev/null +++ b/xcoll/xaux.py @@ -0,0 +1,117 @@ +# copyright ############################### # +# This file is part of the Xcoll Package. # +# Copyright (c) CERN, 2024. # +# ######################################### # + +import functools +from pathlib import Path + +FsPath = Path + + +def singleton(cls): + # Store the original __new__ method if it exists + original_new = cls.__new__ if hasattr(cls, '__new__') else None + + # Define a new __new__ method for the singleton + def singleton_new(cls, *args, **kwargs): + if not hasattr(cls, 'instance'): + cls.instance = (original_new(cls, *args, **kwargs) + if original_new + else super(cls, cls).__new__(cls)) + cls.instance._initialised = False + return cls.instance + cls.__new__ = singleton_new + + # Define the get_self method + @classmethod + def get_self(cls, **kwargs): + # Filter kwargs to include only ClassProperty attributes + filtered_kwargs = {key: value for key, value in kwargs.items() + if key in ClassProperty.get_properties(cls) or + key in getattr(cls, '_xofields', {})} + return cls(**filtered_kwargs) + cls.get_self = get_self + + return cls + + + +class ClassPropertyMeta(type): + def __setattr__(cls, key, value): + # Check if the attribute is a ClassProperty + for parent in cls.__mro__: + if key in parent.__dict__ and isinstance(parent.__dict__[key], ClassProperty): + return parent.__dict__[key].__set__(cls, value) + return super(ClassPropertyMeta, cls).__setattr__(key, value) + + +class ClassProperty: + _registry = {} # Registry to store ClassProperty names for each class + + @classmethod + def get_properties(cls, owner, parents=True): + if not parents: + return cls._registry.get(owner, []) + else: + return [prop for parent in owner.__mro__ + for prop in cls._registry.get(parent, [])] + + def __init__(self, fget=None, fset=None, fdel=None, doc=None): + functools.update_wrapper(self, fget) + self.fget = fget + self.fset = fset + self.fdel = fdel + if doc is None and fget is not None: + doc = fget.__doc__ + self.__doc__ = doc + + def __set_name__(self, owner, name): + self.name = name + # Verify that the class is a subclass of ClassPropertyMeta + if ClassPropertyMeta not in type(owner).__mro__: + raise AttributeError(f"Class `{owner.__name__}` must be a subtype of ClassPropertyMeta!") + # Add the property name to the registry for the class + if owner not in ClassProperty._registry: + ClassProperty._registry[owner] = [] + ClassProperty._registry[owner].append(name) + # Create default getter, setter, and deleter + if self.fget is None: + def _getter(*args, **kwargs): + raise AttributeError(f"Unreadable attribute `{name}` for class {owner.__name__}!") + self.fget = _getter + if self.fset is None: + def _setter(self, *args, **kwargs): + raise AttributeError(f"Can't set attribute `{name}` for class {owner.__name__}!") + self.fset = _setter + if self.fdel is None: + def _deleter(*args, **kwargs): + raise AttributeError(f"Can't delete attribute `{name}` for class {owner.__name__}!") + self.fdel = _deleter + + def __get__(self, instance, owner): + if owner is None: + owner = type(instance) + try: + return self.fget(owner) + except ValueError: + # Return a fallback if initialization fails + return None + + def __set__(self, cls, value): + self.fset(cls, value) + + def __delete__(self, instance): + self.fdel(instance.__class__) + + def getter(self, fget): + self.fget = fget + return self + + def setter(self, fset): + self.fset = fset + return self + + def deleter(self, fdel): + self.fdel = fdel + return self From ed6b43c6019df5bf80c91faa846ebb7deee0dd7b Mon Sep 17 00:00:00 2001 From: Frederik Van der Veken Date: Wed, 8 Jan 2025 11:39:16 +0100 Subject: [PATCH 5/8] Bugfix in dechanneling length calculation --- xcoll/scattering_routines/everest/properties.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xcoll/scattering_routines/everest/properties.h b/xcoll/scattering_routines/everest/properties.h index 8c47a43b..76ecd193 100644 --- a/xcoll/scattering_routines/everest/properties.h +++ b/xcoll/scattering_routines/everest/properties.h @@ -171,7 +171,7 @@ double calculate_dechanneling_length(EverestData restrict everest, double pc) { double energy = sqrt(pow(momentum, 2.) + pow(XC_PROTON_MASS, 2.)); // [MeV] double gammar = energy/XC_PROTON_MASS; - double const_dech = 256.0/(9.*pow(M_PI, 2.)) / (log(2.*XC_ELECTRON_MASS*gammar/exenergy) - 1.); + double const_dech = 256.0/(9.*pow(M_PI, 2.)) / (log(2.*XC_ELECTRON_MASS*gammar/exenergy/1000) - 1.); const_dech *= (XC_SCREENING*XC_PLANE_DISTANCE)/(XC_CRADE*XC_ELECTRON_MASS)*1.0e3; // [m/GeV] return const_dech; } From a24bf058fed534d9f0ffa023d37babd598881328 Mon Sep 17 00:00:00 2001 From: Frederik Van der Veken Date: Wed, 8 Jan 2025 12:44:10 +0100 Subject: [PATCH 6/8] Pencil on a crystal should always be on the upstream jaw --- xcoll/initial_distribution.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/xcoll/initial_distribution.py b/xcoll/initial_distribution.py index f3d55c76..0ba6edb4 100644 --- a/xcoll/initial_distribution.py +++ b/xcoll/initial_distribution.py @@ -187,25 +187,21 @@ def _generate_4D_pencil_one_jaw(line, name, num_particles, plane, side, impact_p coll = line[name] if side == '+': - if is_converging: - if isinstance(coll, EverestCrystal): - pencil_pos = coll.jaw_U + impact_parameter - else: - pencil_pos = coll.jaw_LU + impact_parameter + if isinstance(coll, EverestCrystal): + # A pencil on the crystal should always be upstream + pencil_pos = coll.jaw_U + impact_parameter else: - if isinstance(coll, EverestCrystal): - pencil_pos = coll.jaw_D - impact_parameter + if is_converging: + pencil_pos = coll.jaw_LU + impact_parameter else: pencil_pos = coll.jaw_LD + impact_parameter elif side == '-': - if is_converging: - if isinstance(coll, EverestCrystal): - pencil_pos = coll.jaw_U - impact_parameter - else: - pencil_pos = coll.jaw_RU - impact_parameter + if isinstance(coll, EverestCrystal): + # A pencil on the crystal should always be upstream + pencil_pos = coll.jaw_U - impact_parameter else: - if isinstance(coll, EverestCrystal): - pencil_pos = coll.jaw_D + impact_parameter + if is_converging: + pencil_pos = coll.jaw_RU - impact_parameter else: pencil_pos = coll.jaw_RD - impact_parameter From 60af69010cb5875d3ea9a1f0d4ad30322353cc33 Mon Sep 17 00:00:00 2001 From: Frederik Van der Veken Date: Wed, 8 Jan 2025 13:25:58 +0100 Subject: [PATCH 7/8] Update test listing --- tests/data/all_tests.list | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/data/all_tests.list b/tests/data/all_tests.list index 58942cd5..442e88a4 100644 --- a/tests/data/all_tests.list +++ b/tests/data/all_tests.list @@ -119,8 +119,8 @@ tests/test_jaw_and_gaps.py::test_gaps[B1-ContextCpu] tests/test_jaw_and_gaps.py::test_gaps[B1-ContextCpu:auto] tests/test_jaw_and_gaps.py::test_gaps[B2-ContextCpu] tests/test_jaw_and_gaps.py::test_gaps[B2-ContextCpu:auto] -tests/test_lossmap.py::test_run_lossmap[B1-ContextCpu] -tests/test_lossmap.py::test_run_lossmap[B1-ContextCpu:auto] +tests/test_lossmap.py::test_run_lossmap[B1H-ContextCpu] +tests/test_lossmap.py::test_run_lossmap[B1H-ContextCpu:auto] tests/test_lossmap.py::test_run_lossmap[B2V-ContextCpu] tests/test_lossmap.py::test_run_lossmap[B2V-ContextCpu:auto] tests/test_lossmap.py::test_run_lossmap[B1V_crystals-ContextCpu] From ba556ce90f780cafa5e200aeed536abdd486bfe1 Mon Sep 17 00:00:00 2001 From: Frederik Van der Veken Date: Wed, 8 Jan 2025 13:26:24 +0100 Subject: [PATCH 8/8] Updated version number to v0.5.12. --- pyproject.toml | 10 +++++----- tests/test_version.py | 2 +- xcoll/general.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0f577b41..d7673325 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "xcoll" -version = "0.5.12rc0" +version = "0.5.12" description = "Xsuite collimation package" homepage = "https://github.com/xsuite/xcoll" repository = "https://github.com/xsuite/xcoll" @@ -25,14 +25,14 @@ python = ">=3.8" ruamel-yaml = { version = "^0.17.31", optional = true } numpy = ">=1.0" pandas = ">=1.4" -xobjects = ">=0.4.5" -xdeps = ">=0.8.1" +xobjects = ">=0.4.6" +xdeps = ">=0.8.4" xpart = ">=0.19.3" -xtrack = ">=0.70.3" +xtrack = ">=0.72.2" [tool.poetry.dev-dependencies] pytest = ">=7.3" -xaux = ">=0.2.1" +xaux = ">=0.2.2" [tool.poetry.extras] tests = ["pytest", "ruamel-yaml", "pytest-html", "pytest-xdist"] diff --git a/tests/test_version.py b/tests/test_version.py index e2969acf..e834f590 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -6,4 +6,4 @@ from xcoll import __version__ def test_version(): - assert __version__ == '0.5.12rc0' + assert __version__ == '0.5.12' diff --git a/xcoll/general.py b/xcoll/general.py index b6717055..7a6454e6 100644 --- a/xcoll/general.py +++ b/xcoll/general.py @@ -12,5 +12,5 @@ # ====================== # Do not change # ====================== -__version__ = '0.5.12rc0' +__version__ = '0.5.12' # ======================