From 17219e76f30c3859120178081866ca5ce0865e29 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 3 Oct 2024 18:40:22 +0200 Subject: [PATCH 001/129] only create attributes if self is not an element --- pyat/at/lattice/variable_elements.py | 49 +++++++++++++++------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index aa9fb8b99..9c3dcfbfd 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -26,8 +26,7 @@ class VariableMultipole(Element): FuncA=_array, FuncB=_array, Ramps=_array, Periodic=bool) - def __init__(self, family_name, AmplitudeA=None, AmplitudeB=None, - mode=ACMode.SINE, **kwargs): + def __init__(self, family_name, *args, **kwargs): # noinspection PyUnresolvedReferences r""" Parameters: @@ -75,32 +74,38 @@ def __init__(self, family_name, AmplitudeA=None, AmplitudeB=None, * For ``mode=ACMode.ARBITRARY`` the ``Func(A,B)`` corresponding to the ``Amplitude(A,B)`` has to be provided """ - kwargs.setdefault('PassMethod', 'VariableThinMPolePass') - self.MaxOrder = kwargs.pop('MaxOrder', 0) - self.Periodic = kwargs.pop('Periodic', True) - self.Mode = int(mode) - if AmplitudeA is None and AmplitudeB is None: - raise AtError('Please provide at least one amplitude for A or B') - AmplitudeB = self._set_params(AmplitudeB, mode, 'B', **kwargs) - AmplitudeA = self._set_params(AmplitudeA, mode, 'A', **kwargs) - self._setmaxorder(AmplitudeA, AmplitudeB) - if mode == ACMode.WHITENOISE: - self.Seed = kwargs.pop('Seed', datetime.now().timestamp()) - self.PolynomA = numpy.zeros(self.MaxOrder+1) - self.PolynomB = numpy.zeros(self.MaxOrder+1) - ramps = kwargs.pop('Ramps', None) - if ramps is not None: - assert len(ramps)==4, \ - 'Ramps has to be a vector with 4 elements' - self.Ramps = ramps + # if element has not been created + if not hasattr(self,'to_dict'): + self.FamName = family_name + kwargs.setdefault('PassMethod', 'VariableThinMPolePass') + AmplitudeA = kwargs.pop('AmplitudeA', None) + AmplitudeB = kwargs.pop('AmplitudeB', None) + mode = kwargs.pop('mode',ACMode.SINE) + self.MaxOrder = kwargs.pop('MaxOrder', 0) + self.Periodic = kwargs.pop('Periodic', True) + self.Mode = int(mode) + if AmplitudeA is None and AmplitudeB is None: + raise AtError('Please provide at least one amplitude for A or B') + AmplitudeB = self._set_params(AmplitudeB, mode, 'B', **kwargs) + AmplitudeA = self._set_params(AmplitudeA, mode, 'A', **kwargs) + self._setmaxorder(AmplitudeA, AmplitudeB) + if mode == ACMode.WHITENOISE: + self.Seed = kwargs.pop('Seed', datetime.now().timestamp()) + self.PolynomA = numpy.zeros(self.MaxOrder+1) + self.PolynomB = numpy.zeros(self.MaxOrder+1) + ramps = kwargs.pop('Ramps', None) + if ramps is not None: + assert len(ramps)==4, \ + 'Ramps has to be a vector with 4 elements' + self.Ramps = ramps super(VariableMultipole, self).__init__(family_name, **kwargs) def _setmaxorder(self, ampa, ampb): mxa, mxb = 0, 0 if ampa is not None: - mxa = numpy.max(numpy.nonzero(ampa)) + mxa = numpy.max(numpy.append(numpy.nonzero(ampa),0)) if ampb is not None: - mxb = numpy.max(numpy.nonzero(ampb)) + mxb = numpy.max(numpy.append(numpy.nonzero(ampb),0)) self.MaxOrder = max(mxa, mxb) if ampa is not None: delta = self.MaxOrder - len(ampa) From 84d3bf86d5012c1cb97df7cfb7726b92e2669399 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 3 Oct 2024 18:48:28 +0200 Subject: [PATCH 002/129] import numpy as np --- pyat/at/lattice/variable_elements.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 9c3dcfbfd..cab77eaa9 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -1,4 +1,4 @@ -import numpy +import numpy as np from .elements import Element, _array from .utils import AtError from typing import Optional, Union @@ -91,8 +91,8 @@ def __init__(self, family_name, *args, **kwargs): self._setmaxorder(AmplitudeA, AmplitudeB) if mode == ACMode.WHITENOISE: self.Seed = kwargs.pop('Seed', datetime.now().timestamp()) - self.PolynomA = numpy.zeros(self.MaxOrder+1) - self.PolynomB = numpy.zeros(self.MaxOrder+1) + self.PolynomA = np.zeros(self.MaxOrder+1) + self.PolynomB = np.zeros(self.MaxOrder+1) ramps = kwargs.pop('Ramps', None) if ramps is not None: assert len(ramps)==4, \ @@ -103,26 +103,26 @@ def __init__(self, family_name, *args, **kwargs): def _setmaxorder(self, ampa, ampb): mxa, mxb = 0, 0 if ampa is not None: - mxa = numpy.max(numpy.append(numpy.nonzero(ampa),0)) + mxa = np.max(np.append(np.nonzero(ampa),0)) if ampb is not None: - mxb = numpy.max(numpy.append(numpy.nonzero(ampb),0)) + mxb = np.max(np.append(np.nonzero(ampb),0)) self.MaxOrder = max(mxa, mxb) if ampa is not None: delta = self.MaxOrder - len(ampa) if delta > 0: - ampa = numpy.pad(ampa, (0, delta)) + ampa = np.pad(ampa, (0, delta)) setattr(self, 'AmplitudeA', ampa) if ampb is not None: delta = self.MaxOrder + 1 - len(ampb) if delta > 0: - ampb = numpy.pad(ampb, (0, delta)) + ampb = np.pad(ampb, (0, delta)) setattr(self, 'AmplitudeB', ampb) def _set_params(self, amplitude, mode, ab, **kwargs): if amplitude is not None: - if numpy.isscalar(amplitude): - amp = numpy.zeros(self.MaxOrder) - amplitude = numpy.append(amp, amplitude) + if np.isscalar(amplitude): + amp = np.zeros(self.MaxOrder) + amplitude = np.append(amp, amplitude) if mode == ACMode.SINE: self._set_sine(ab, **kwargs) if mode == ACMode.ARBITRARY: From ce697be38fc2f2759e2b1f3fa20bc13276be2fdc Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 3 Oct 2024 18:49:27 +0200 Subject: [PATCH 003/129] isort --- pyat/at/lattice/variable_elements.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index cab77eaa9..897c3b24f 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -1,9 +1,11 @@ +from datetime import datetime +from enum import IntEnum +from typing import Optional, Union + import numpy as np + from .elements import Element, _array from .utils import AtError -from typing import Optional, Union -from enum import IntEnum -from datetime import datetime class ACMode(IntEnum): From 7c3949ddc1464ad0e36af284fa90157d61423e16 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 3 Oct 2024 18:51:57 +0200 Subject: [PATCH 004/129] black --- pyat/at/lattice/variable_elements.py | 95 +++++++++++++++------------- 1 file changed, 51 insertions(+), 44 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 897c3b24f..a4b8c2027 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -10,23 +10,33 @@ class ACMode(IntEnum): """Class to define the excitation types""" + SINE = 0 WHITENOISE = 1 ARBITRARY = 2 class VariableMultipole(Element): - """Class to generate an AT variable thin multipole element - """ + """Class to generate an AT variable thin multipole element""" + _BUILD_ATTRIBUTES = Element._BUILD_ATTRIBUTES - _conversions = dict(Element._conversions, - Mode=int, - AmplitudeA=_array, AmplitudeB=_array, - FrequencyA=float, FrequencyB=float, - PhaseA=float, PhaseB=float, - Seed=int, NSamplesA=int, NSamplesB=int, - FuncA=_array, FuncB=_array, Ramps=_array, - Periodic=bool) + _conversions = dict( + Element._conversions, + Mode=int, + AmplitudeA=_array, + AmplitudeB=_array, + FrequencyA=float, + FrequencyB=float, + PhaseA=float, + PhaseB=float, + Seed=int, + NSamplesA=int, + NSamplesB=int, + FuncA=_array, + FuncB=_array, + Ramps=_array, + Periodic=bool, + ) def __init__(self, family_name, *args, **kwargs): # noinspection PyUnresolvedReferences @@ -52,14 +62,14 @@ def __init__(self, family_name, *args, **kwargs): FuncA(list): User defined tbt kick list for PolynomA FuncB(list): User defined tbt kick list for PolynomB Periodic(bool): If True (default) the user defined kick is repeated - Ramps(list): Vector (t0, t1, t2, t3) in turn number to define the ramping + Ramps(list): Vector (t0, t1, t2, t3) in turn number to define the ramping of the excitation * ``t 0: ampa = np.pad(ampa, (0, delta)) - setattr(self, 'AmplitudeA', ampa) + setattr(self, "AmplitudeA", ampa) if ampb is not None: delta = self.MaxOrder + 1 - len(ampb) if delta > 0: ampb = np.pad(ampb, (0, delta)) - setattr(self, 'AmplitudeB', ampb) + setattr(self, "AmplitudeB", ampb) def _set_params(self, amplitude, mode, ab, **kwargs): if amplitude is not None: @@ -132,17 +141,15 @@ def _set_params(self, amplitude, mode, ab, **kwargs): return amplitude def _set_sine(self, ab, **kwargs): - frequency = kwargs.pop('Frequency' + ab, None) - phase = kwargs.pop('Phase' + ab, 0) - assert frequency is not None, \ - 'Please provide a value for Frequency' + ab - setattr(self, 'Frequency' + ab, frequency) - setattr(self, 'Phase' + ab, phase) + frequency = kwargs.pop("Frequency" + ab, None) + phase = kwargs.pop("Phase" + ab, 0) + assert frequency is not None, "Please provide a value for Frequency" + ab + setattr(self, "Frequency" + ab, frequency) + setattr(self, "Phase" + ab, phase) def _set_arb(self, ab, **kwargs): - func = kwargs.pop('Func' + ab, None) + func = kwargs.pop("Func" + ab, None) nsamp = len(func) - assert func is not None, \ - 'Please provide a value for Func' + ab - setattr(self, 'Func' + ab, func) - setattr(self, 'NSamples' + ab, nsamp) + assert func is not None, "Please provide a value for Func" + ab + setattr(self, "Func" + ab, func) + setattr(self, "NSamples" + ab, nsamp) From 51db2ce97b08568dfd30d1bab34a733e6d551c5a Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 3 Oct 2024 19:22:57 +0200 Subject: [PATCH 005/129] do flake8 easy fix; many are left --- pyat/at/lattice/variable_elements.py | 36 +++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index a4b8c2027..83cc587c4 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -1,6 +1,7 @@ +from __future__ import annotations + from datetime import datetime from enum import IntEnum -from typing import Optional, Union import numpy as np @@ -9,7 +10,7 @@ class ACMode(IntEnum): - """Class to define the excitation types""" + """Class to define the excitation types.""" SINE = 0 WHITENOISE = 1 @@ -17,7 +18,7 @@ class ACMode(IntEnum): class VariableMultipole(Element): - """Class to generate an AT variable thin multipole element""" + """Class to generate an AT variable thin multipole element.""" _BUILD_ATTRIBUTES = Element._BUILD_ATTRIBUTES _conversions = dict( @@ -38,15 +39,18 @@ class VariableMultipole(Element): Periodic=bool, ) - def __init__(self, family_name, *args, **kwargs): + def __init__(self, family_name: str, **kwargs: dict[str, any]): # noinspection PyUnresolvedReferences r""" + Create VariableMultipole. + Parameters: family_name(str): Element name - Keyword Arguments: - AmplitudeA(list,float): Amplitude of the excitation for PolynomA. Default None - AmplitudeB(list,float): Amplitude of the excitation for PolynomB. Default None + AmplitudeA(list,float): Amplitude of the excitation for PolynomA. + Default None + AmplitudeB(list,float): Amplitude of the excitation for PolynomB. + Default None mode(ACMode): defines the evaluation grid. Default ACMode.SINE * :py:attr:`.ACMode.SINE`: sine function @@ -62,8 +66,8 @@ def __init__(self, family_name, *args, **kwargs): FuncA(list): User defined tbt kick list for PolynomA FuncB(list): User defined tbt kick list for PolynomB Periodic(bool): If True (default) the user defined kick is repeated - Ramps(list): Vector (t0, t1, t2, t3) in turn number to define the ramping - of the excitation + Ramps(list): Vector (t0, t1, t2, t3) in turn number to define + the ramping of the excitation * ``t 0: ampa = np.pad(ampa, (0, delta)) - setattr(self, "AmplitudeA", ampa) + self.AmplitudeA = ampa if ampb is not None: delta = self.MaxOrder + 1 - len(ampb) if delta > 0: ampb = np.pad(ampb, (0, delta)) - setattr(self, "AmplitudeB", ampb) + self.AmplitudeB = ampb - def _set_params(self, amplitude, mode, ab, **kwargs): + def _set_params(self, amplitude: np.ndarray, mode, ab, **kwargs: dict[str, any]): if amplitude is not None: if np.isscalar(amplitude): amp = np.zeros(self.MaxOrder) @@ -140,14 +144,14 @@ def _set_params(self, amplitude, mode, ab, **kwargs): self._set_arb(ab, **kwargs) return amplitude - def _set_sine(self, ab, **kwargs): + def _set_sine(self, ab, **kwargs: dict[str, any]): frequency = kwargs.pop("Frequency" + ab, None) phase = kwargs.pop("Phase" + ab, 0) assert frequency is not None, "Please provide a value for Frequency" + ab setattr(self, "Frequency" + ab, frequency) setattr(self, "Phase" + ab, phase) - def _set_arb(self, ab, **kwargs): + def _set_arb(self, ab, **kwargs: dict[str, any]): func = kwargs.pop("Func" + ab, None) nsamp = len(func) assert func is not None, "Please provide a value for Func" + ab From f6dae6761b3e5505e300a3551485a88152924f07 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 4 Oct 2024 10:31:09 +0200 Subject: [PATCH 006/129] fixing when saved in .mat --- pyat/at/lattice/variable_elements.py | 72 +++++++++++++++++----------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 83cc587c4..f7e9b4a3e 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -52,7 +52,6 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): AmplitudeB(list,float): Amplitude of the excitation for PolynomB. Default None mode(ACMode): defines the evaluation grid. Default ACMode.SINE - * :py:attr:`.ACMode.SINE`: sine function * :py:attr:`.ACMode.WHITENOISE`: gaussian white noise * :py:attr:`.GridMode.ARBITRARY`: user defined turn-by-turn kick list @@ -61,6 +60,7 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): PhaseA(float): Phase of the sine excitation for PolynomA. Default 0 PhaseB(float): Phase of the sine excitation for PolynomB. Default 0 MaxOrder(int): Order of the multipole for scalar amplitude. Default 0 + It is overwritten with the length of Amplitude(A,B) Seed(int): Seed of the random number generator for white noise excitation. Default datetime.now() FuncA(list): User defined tbt kick list for PolynomA @@ -83,36 +83,50 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): .. note:: - * For all excitation modes all least one amplitude has to be provided. + * If no parameters are given it will be initialized as IdentityPass. + * For all excitation modes at least one amplitudes (A or B) has + to be provided. The default excitation is ``ACMode.SINE`` * For ``mode=ACMode.SINE`` the ``Frequency(A,B)`` corresponding to the - ``Amplitude(A,B)`` has to be provided + ``Amplitude(A,B)`` has to be provided. * For ``mode=ACMode.ARBITRARY`` the ``Func(A,B)`` corresponding to the - ``Amplitude(A,B)`` has to be provided + ``Amplitude(A,B)`` has to be provided. """ - # if element has not been created - if not hasattr(self, "to_dict"): - self.FamName = family_name - kwargs.setdefault("PassMethod", "VariableThinMPolePass") - AmplitudeA = kwargs.pop("AmplitudeA", None) - AmplitudeB = kwargs.pop("AmplitudeB", None) + if len(kwargs) > 0: + if not "AmplitudeA" in kwargs and not "AmplitudeB" in kwargs: + raise AtError("Please provide at least one amplitude for A or B") + # start setting up Amplitudes and modes mode = kwargs.pop("mode", ACMode.SINE) - self.MaxOrder = kwargs.pop("MaxOrder", 0) - self.Periodic = kwargs.pop("Periodic", True) self.Mode = int(mode) - if AmplitudeA is None and AmplitudeB is None: - raise AtError("Please provide at least one amplitude for A or B") - AmplitudeB = self._set_params(AmplitudeB, mode, "B", **kwargs) - AmplitudeA = self._set_params(AmplitudeA, mode, "A", **kwargs) - self._setmaxorder(AmplitudeA, AmplitudeB) - if mode == ACMode.WHITENOISE: - self.Seed = kwargs.pop("Seed", datetime.now().timestamp()) - self.PolynomA = np.zeros(self.MaxOrder + 1) - self.PolynomB = np.zeros(self.MaxOrder + 1) + self.MaxOrder = kwargs.get("MaxOrder", 0) + amplitudea = None + amplitudeb = None + if "AmplitudeA" in kwargs: + amplitudea = kwargs.pop("AmplitudeA", None) + amplitudea = self._set_params(amplitudea, mode, "A", **kwargs) + if "AmplitudeB" in kwargs: + amplitudeb = kwargs.pop("AmplitudeB", None) + amplitudeb = self._set_params(amplitudeb, mode, "B", **kwargs) + if amplitudea is not None: + self.AmplitudeA = amplitudea + if amplitudeb is not None: + self.AmplitudeB = amplitudeb + # end setting up Amplitudes and modes + kwargs.setdefault("PassMethod", "VariableThinMPolePass") + # this overwrites MaxOrder + self._setmaxorder(amplitudea, amplitudeb) + if mode == ACMode.WHITENOISE and "Seed" not in kwargs: + kwargs.update({"Seed": datetime.now().timestamp()}) + self.Periodic = kwargs.pop("Periodic", True) + self.PolynomA = kwargs.pop("PolynomA", np.zeros(self.MaxOrder + 1)) + self.PolynomB = kwargs.pop("PolynomB", np.zeros(self.MaxOrder + 1)) + # check ramps ramps = kwargs.pop("Ramps", None) if ramps is not None: - assert len(ramps) == 4, "Ramps has to be a vector with 4 elements" + if len(ramps) != 4: + raise AtError("Ramps has to be a vector with 4 elements") self.Ramps = ramps + # fill in super class super().__init__(family_name, **kwargs) def _setmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): @@ -133,7 +147,9 @@ def _setmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): ampb = np.pad(ampb, (0, delta)) self.AmplitudeB = ampb - def _set_params(self, amplitude: np.ndarray, mode, ab, **kwargs: dict[str, any]): + def _set_params( + self, amplitude: int or str, mode: int, ab: str, **kwargs: dict[str, any] + ): if amplitude is not None: if np.isscalar(amplitude): amp = np.zeros(self.MaxOrder) @@ -144,16 +160,18 @@ def _set_params(self, amplitude: np.ndarray, mode, ab, **kwargs: dict[str, any]) self._set_arb(ab, **kwargs) return amplitude - def _set_sine(self, ab, **kwargs: dict[str, any]): + def _set_sine(self, ab: str, **kwargs: dict[str, any]): frequency = kwargs.pop("Frequency" + ab, None) phase = kwargs.pop("Phase" + ab, 0) - assert frequency is not None, "Please provide a value for Frequency" + ab + if frequency is None: + raise AtError("Please provide a value for Frequency" + ab) setattr(self, "Frequency" + ab, frequency) setattr(self, "Phase" + ab, phase) - def _set_arb(self, ab, **kwargs: dict[str, any]): + def _set_arb(self, ab: str, **kwargs: dict[str, any]): func = kwargs.pop("Func" + ab, None) nsamp = len(func) - assert func is not None, "Please provide a value for Func" + ab + if func is None: + raise AtError("Please provide a value for Func" + ab) setattr(self, "Func" + ab, func) setattr(self, "NSamples" + ab, nsamp) From 6ced948d8aa6d7a14c3d463d1776612f0b4fb5a1 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 4 Oct 2024 10:37:33 +0200 Subject: [PATCH 007/129] fix FamName when reading from matlab --- pyat/at/lattice/variable_elements.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index f7e9b4a3e..67f470244 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -93,6 +93,7 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): ``Amplitude(A,B)`` has to be provided. """ if len(kwargs) > 0: + self.FamName = family_name if not "AmplitudeA" in kwargs and not "AmplitudeB" in kwargs: raise AtError("Please provide at least one amplitude for A or B") # start setting up Amplitudes and modes From 7a12dc4c9e935979e7ee0bcce28cc443cdbb50d1 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 4 Oct 2024 10:57:24 +0200 Subject: [PATCH 008/129] fix read element from matlab --- pyat/at/lattice/variable_elements.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 67f470244..5f0e07d3d 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -97,8 +97,15 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): if not "AmplitudeA" in kwargs and not "AmplitudeB" in kwargs: raise AtError("Please provide at least one amplitude for A or B") # start setting up Amplitudes and modes - mode = kwargs.pop("mode", ACMode.SINE) + # fist modes are called differently + modepyatinput = kwargs.pop("mode", ACMode.SINE) + modefromdict = kwargs.pop("Mode", None) + if modefromdict is not None: + mode = modefromdict # matlab class + else: + mode = modepyatinput self.Mode = int(mode) + # MaxOrder is later overwritten by lenth of amplitudes self.MaxOrder = kwargs.get("MaxOrder", 0) amplitudea = None amplitudeb = None @@ -149,7 +156,7 @@ def _setmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): self.AmplitudeB = ampb def _set_params( - self, amplitude: int or str, mode: int, ab: str, **kwargs: dict[str, any] + self, amplitude: int or str, mode, ab: str, **kwargs: dict[str, any] ): if amplitude is not None: if np.isscalar(amplitude): From 05c0e8236cb81ea111ebfc59b71e6e01e90a0d51 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 4 Oct 2024 11:15:48 +0200 Subject: [PATCH 009/129] fix max order in matlab --- atmat/lattice/element_creation/atvariablemultipole.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index bdf83b4d7..27f6bcafe 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -107,16 +107,16 @@ function setsine(rsrc, ab) function rsrc = setmaxorder(rsrc) if isfield(rsrc,'AmplitudeA') - mxa=find(abs(rsrc.AmplitudeA)>0,1,'last'); + [~,mxa]=max(abs(rsrc.AmplitudeA)); else mxa=0; end if isfield(rsrc,'AmplitudeB') - mxb=find(abs(rsrc.AmplitudeB)>0,1,'last'); + [~,mxb]=max(abs(rsrc.AmplitudeB)); else mxb=0; end - mxab=max([mxa,mxb,rsrc.MaxOrder-1]); + mxab=max([mxa,mxb,rsrc.MaxOrder+1]); rsrc.MaxOrder=mxab-1; if isfield(rsrc,'AmplitudeA') rsrc.AmplitudeA(mxa+1:mxab)=0; From aa71888c494bd5b84977a9e3b07cbc37e2e2d7ea Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 4 Oct 2024 11:21:32 +0200 Subject: [PATCH 010/129] fixing flake8 --- pyat/at/lattice/variable_elements.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 5f0e07d3d..f6275e1ab 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -156,30 +156,30 @@ def _setmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): self.AmplitudeB = ampb def _set_params( - self, amplitude: int or str, mode, ab: str, **kwargs: dict[str, any] + self, amplitude: int or str, mode, a_b: str, **kwargs: dict[str, any] ): if amplitude is not None: if np.isscalar(amplitude): amp = np.zeros(self.MaxOrder) amplitude = np.append(amp, amplitude) if mode == ACMode.SINE: - self._set_sine(ab, **kwargs) + self._set_sine(a_b, **kwargs) if mode == ACMode.ARBITRARY: - self._set_arb(ab, **kwargs) + self._set_arb(a_b, **kwargs) return amplitude - def _set_sine(self, ab: str, **kwargs: dict[str, any]): - frequency = kwargs.pop("Frequency" + ab, None) - phase = kwargs.pop("Phase" + ab, 0) + def _set_sine(self, a_b: str, **kwargs: dict[str, any]): + frequency = kwargs.pop("Frequency" + a_b, None) + phase = kwargs.pop("Phase" + a_b, 0) if frequency is None: - raise AtError("Please provide a value for Frequency" + ab) - setattr(self, "Frequency" + ab, frequency) - setattr(self, "Phase" + ab, phase) + raise AtError("Please provide a value for Frequency" + a_b) + setattr(self, "Frequency" + a_b, frequency) + setattr(self, "Phase" + a_b, phase) - def _set_arb(self, ab: str, **kwargs: dict[str, any]): - func = kwargs.pop("Func" + ab, None) + def _set_arb(self, a_b: str, **kwargs: dict[str, any]): + func = kwargs.pop("Func" + a_b, None) nsamp = len(func) if func is None: - raise AtError("Please provide a value for Func" + ab) - setattr(self, "Func" + ab, func) - setattr(self, "NSamples" + ab, nsamp) + raise AtError("Please provide a value for Func" + a_b) + setattr(self, "Func" + a_b, func) + setattr(self, "NSamples" + a_b, nsamp) From 032c9da479b8b1b1efbfe12101a2f8b322828268 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 4 Oct 2024 11:30:46 +0200 Subject: [PATCH 011/129] fixing flake8 --- pyat/at/lattice/variable_elements.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index f6275e1ab..c9ad95162 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -74,6 +74,12 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): * ``t1 0: self.FamName = family_name - if not "AmplitudeA" in kwargs and not "AmplitudeB" in kwargs: + if "AmplitudeA" not in kwargs and "AmplitudeB" not in kwargs: raise AtError("Please provide at least one amplitude for A or B") # start setting up Amplitudes and modes # fist modes are called differently From e19c8f37bdf1231ccdfd1b21144c68e11c7c0e00 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 4 Oct 2024 12:04:31 +0200 Subject: [PATCH 012/129] add check isempty --- atmat/lattice/element_creation/atvariablemultipole.m | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 27f6bcafe..67246521e 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -107,12 +107,18 @@ function setsine(rsrc, ab) function rsrc = setmaxorder(rsrc) if isfield(rsrc,'AmplitudeA') - [~,mxa]=max(abs(rsrc.AmplitudeA)); + mxa=find(abs(rsrc.AmplitudeA)>0,1,'last'); + if isempty(mxa) + mxa=0; + end else mxa=0; end if isfield(rsrc,'AmplitudeB') - [~,mxb]=max(abs(rsrc.AmplitudeB)); + mxb=find(abs(rsrc.AmplitudeB)>0,1,'last'); + if isempty(mxb) + mxb=0; + end else mxb=0; end From ad441bad0b8569c049e1d792c576198f8c001130 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 4 Oct 2024 13:53:11 +0200 Subject: [PATCH 013/129] matlab index starts in 1, obviously --- atmat/lattice/element_creation/atvariablemultipole.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 67246521e..956098cf6 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -109,7 +109,7 @@ function setsine(rsrc, ab) if isfield(rsrc,'AmplitudeA') mxa=find(abs(rsrc.AmplitudeA)>0,1,'last'); if isempty(mxa) - mxa=0; + mxa=1; end else mxa=0; @@ -117,7 +117,7 @@ function setsine(rsrc, ab) if isfield(rsrc,'AmplitudeB') mxb=find(abs(rsrc.AmplitudeB)>0,1,'last'); if isempty(mxb) - mxb=0; + mxb=1; end else mxb=0; From 9e62915447183c19a4c3229647673ce5b446c970 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 4 Oct 2024 13:59:26 +0200 Subject: [PATCH 014/129] fix help matlab --- atmat/lattice/element_creation/atvariablemultipole.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 956098cf6..724a9a632 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -18,17 +18,17 @@ % FREQUENCYB Frequency of SINE excitation for PolynomB % PHASEA Phase of SINE excitation for PolynomA % PHASEB Phase of SINE excitation for PolynomB -% MAXORDER Order of the multipole for a scalar amplitude +% MAXORDER Order of the multipole for a scalar amplitude % SEED Input seed for the random number generator % FUNCA ARBITRARY excitation turn-by-turn kick list for PolynomA % FUNCB ARBITRARY excitation turn-by-turn kick list for PolynomB % PERIODIC If true (default) the user input kick list is repeated % RAMPS Vector (t0, t1, t2, t3) in turn number to define the ramping of the excitation % * t Date: Fri, 4 Oct 2024 14:11:55 +0200 Subject: [PATCH 015/129] fix doc string --- pyat/at/lattice/variable_elements.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index c9ad95162..1132c78e2 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -54,7 +54,7 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): mode(ACMode): defines the evaluation grid. Default ACMode.SINE * :py:attr:`.ACMode.SINE`: sine function * :py:attr:`.ACMode.WHITENOISE`: gaussian white noise - * :py:attr:`.GridMode.ARBITRARY`: user defined turn-by-turn kick list + * :py:attr:`.ACMode.ARBITRARY`: user defined turn-by-turn kick list FrequencyA(float): Frequency of the sine excitation for PolynomA FrequencyB(float): Frequency of the sine excitation for PolynomB PhaseA(float): Phase of the sine excitation for PolynomA. Default 0 @@ -70,15 +70,15 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): the ramping of the excitation * ``t Date: Tue, 8 Oct 2024 15:06:49 +0200 Subject: [PATCH 016/129] fix help --- atmat/lattice/element_creation/atvariablemultipole.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 724a9a632..c290e9efb 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -13,7 +13,7 @@ % AMPLITUDEA Vector or scalar to define the excitation amplitude for % PolynomA % AMPLITUDEB Vector or scalar to define the excitation amplitude for -% PolynomA +% PolynomB % FREQUENCYA Frequency of SINE excitation for PolynomA % FREQUENCYB Frequency of SINE excitation for PolynomB % PHASEA Phase of SINE excitation for PolynomA From 511549614e4ea68b94f3dd40ea214a7db40d3ef5 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 18 Nov 2024 17:13:57 +0100 Subject: [PATCH 017/129] testing function derivatives --- atintegrators/VariableThinMPolePass.c | 55 +++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index 0c25e9afa..be012142a 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -15,6 +15,9 @@ struct elemab { double Phase; int NSamples; double* Func; + double* Funcderiv1; + double* Funcderiv2; + double* Funcderiv3; }; struct elem { @@ -52,8 +55,8 @@ double get_pol(struct elemab* elem, double* ramps, int mode, double t, int turn, int seed, int order, int periodic) { int idx; - double ampt, freq, ph, val; - double* func; + double ampt, freq, ph, val, t2, oneoversix; + double* func, *funcderiv1, *funcderiv2, *funcderiv3; double* amp = elem->Amplitude; if (!amp) { return 0.0; @@ -72,8 +75,14 @@ double get_pol(struct elemab* elem, double* ramps, int mode, case 2: if (periodic || turn < elem->NSamples) { func = elem->Func; + funcderiv1 = elem->Funcderiv1; + funcderiv2 = elem->Funcderiv2; + funcderiv3 = elem->Funcderiv3; idx = turn % elem->NSamples; - ampt *= func[idx]; + t2 = t*t; + oneoversix = 0.166666666666667; + ampt *= func[idx] + funcderiv1[idx]*t + 0.5*funcderiv2[idx]*t2 + + oneoversix*funcderiv3[idx]*t2*t; return ampt; } else { return 0.0; @@ -100,7 +109,7 @@ void VariableThinMPolePass(double* r, struct elem* Elem, double t0, int turn, in struct elemab* ElemB = Elem->ElemB; double* ramps = Elem->Ramps; - if (mode != 0) { + if (mode == 1) { for (i = 0; i < maxorder + 1; i++) { pola[i] = get_pol(ElemA, ramps, mode, t, turn, seed, i, periodic); polb[i] = get_pol(ElemB, ramps, mode, t, turn, seed, i, periodic); @@ -110,7 +119,7 @@ void VariableThinMPolePass(double* r, struct elem* Elem, double t0, int turn, in for (c = 0; c < num_particles; c++) { r6 = r + c * 6; if (!atIsNaN(r6[0])) { - if (mode == 0) { + if (mode != 1) { double tpart = t + r6[5] / C0; for (i = 0; i < maxorder + 1; i++) { pola[i] = get_pol(ElemA, ramps, mode, tpart, turn, seed, i, periodic); @@ -130,6 +139,9 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, int MaxOrder, Mode, Seed, NSamplesA, NSamplesB, Periodic; double *PolynomA, *PolynomB, *AmplitudeA, *AmplitudeB; double *Ramps, *FuncA, *FuncB; + double *FuncAderiv1, *FuncBderiv1; + double *FuncAderiv2, *FuncBderiv2; + double *FuncAderiv3, *FuncBderiv3; double FrequencyA, FrequencyB; double PhaseA, PhaseB; struct elemab *ElemA, *ElemB; @@ -149,6 +161,12 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, NSamplesB=atGetOptionalLong(ElemData, "NSamplesB", 1); check_error(); FuncA=atGetOptionalDoubleArray(ElemData,"FuncA"); check_error(); FuncB=atGetOptionalDoubleArray(ElemData,"FuncB"); check_error(); + FuncAderiv1=atGetOptionalDoubleArray(ElemData,"FuncAderiv1"); check_error(); + FuncBderiv1=atGetOptionalDoubleArray(ElemData,"FuncBderiv1"); check_error(); + FuncAderiv2=atGetOptionalDoubleArray(ElemData,"FuncAderiv2"); check_error(); + FuncBderiv2=atGetOptionalDoubleArray(ElemData,"FuncBderiv2"); check_error(); + FuncAderiv3=atGetOptionalDoubleArray(ElemData,"FuncAderiv3"); check_error(); + FuncBderiv3=atGetOptionalDoubleArray(ElemData,"FuncBderiv3"); check_error(); Periodic=atGetOptionalLong(ElemData,"Periodic", 1); check_error(); Elem = (struct elem*)atMalloc(sizeof(struct elem)); ElemA = (struct elemab*)atMalloc(sizeof(struct elemab)); @@ -170,6 +188,12 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, ElemB->NSamples = NSamplesB; ElemA->Func = FuncA; ElemB->Func = FuncB; + ElemA->Funcderiv1 = FuncAderiv1; + ElemB->Funcderiv1 = FuncBderiv1; + ElemA->Funcderiv2 = FuncAderiv2; + ElemB->Funcderiv2 = FuncBderiv2; + ElemA->Funcderiv3 = FuncAderiv3; + ElemB->Funcderiv3 = FuncBderiv3; Elem->ElemA = ElemA; Elem->ElemB = ElemB; } @@ -193,6 +217,9 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) int MaxOrder, Mode, Seed, NSamplesA, NSamplesB, Periodic; double *PolynomA, *PolynomB, *AmplitudeA, *AmplitudeB; double *Ramps, *FuncA, *FuncB; + double *FuncAderiv1, *FuncBderiv1; + double *FuncAderiv2, *FuncBderiv2; + double *FuncAderiv3, *FuncBderiv3; double FrequencyA, FrequencyB; double PhaseA, PhaseB; struct elemab ElA, *ElemA = &ElA; @@ -214,6 +241,12 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) NSamplesB=atGetOptionalLong(ElemData, "NSamplesB", 0); check_error(); FuncA=atGetOptionalDoubleArray(ElemData,"FuncA"); check_error(); FuncB=atGetOptionalDoubleArray(ElemData,"FuncB"); check_error(); + FuncAderiv1=atGetOptionalDoubleArray(ElemData,"FuncAderiv1"); check_error(); + FuncBderiv1=atGetOptionalDoubleArray(ElemData,"FuncBderiv1"); check_error(); + FuncAderiv2=atGetOptionalDoubleArray(ElemData,"FuncAderiv2"); check_error(); + FuncBderiv2=atGetOptionalDoubleArray(ElemData,"FuncBderiv2"); check_error(); + FuncAderiv3=atGetOptionalDoubleArray(ElemData,"FuncAderiv3"); check_error(); + FuncBderiv3=atGetOptionalDoubleArray(ElemData,"FuncBderiv3"); check_error(); Periodic=atGetOptionalLong(ElemData,"Periodic", 1); check_error(); Elem->PolynomA = PolynomA; Elem->PolynomB = PolynomB; @@ -258,9 +291,15 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) mxSetCell(plhs[1], 7, mxCreateString("Seed")); mxSetCell(plhs[1], 8, mxCreateString("FuncA")); mxSetCell(plhs[1], 9, mxCreateString("FuncB")); - mxSetCell(plhs[1], 10, mxCreateString("NSamplesA")); - mxSetCell(plhs[1], 11, mxCreateString("NSamplesB")); - mxSetCell(plhs[1], 12, mxCreateString("Periodic")); + mxSetCell(plhs[1], 10, mxCreateString("FuncAderiv1")); + mxSetCell(plhs[1], 11, mxCreateString("FuncBderiv1")); + mxSetCell(plhs[1], 12, mxCreateString("FuncAderiv2")); + mxSetCell(plhs[1], 13, mxCreateString("FuncBderiv2")); + mxSetCell(plhs[1], 14, mxCreateString("FuncAderiv3")); + mxSetCell(plhs[1], 15, mxCreateString("FuncBderiv3")); + mxSetCell(plhs[1], 16, mxCreateString("NSamplesA")); + mxSetCell(plhs[1], 17, mxCreateString("NSamplesB")); + mxSetCell(plhs[1], 18, mxCreateString("Periodic")); } } else { mexErrMsgIdAndTxt("AT:WrongArg", "Needs 0 or 2 arguments"); From d899d083bf9b0e7f157ecfc157cf9f4fad4de105 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 18 Nov 2024 17:14:27 +0100 Subject: [PATCH 018/129] testing function derivatives --- .../element_creation/atvariablemultipole.m | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index c290e9efb..a1ffc189c 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -20,11 +20,23 @@ % PHASEB Phase of SINE excitation for PolynomB % MAXORDER Order of the multipole for a scalar amplitude % SEED Input seed for the random number generator -% FUNCA ARBITRARY excitation turn-by-turn kick list for PolynomA -% FUNCB ARBITRARY excitation turn-by-turn kick list for PolynomB +% FUNCA ARBITRARY excitation turn-by-turn (tbt) kick list for PolynomA +% FUNCB ARBITRARY excitation turn-by-turn (tbt) kick list for PolynomB +% FUNCADERIV1 ARBITRARY excitation tbt kick list for PolynomA 1st +% derivative wrt 5th coordinate +% FUNCBDERIV1 ARBITRARY excitation tbt kick list for PolynomB 1st +% derivative wrt 5th coordinate +% FUNCADERIV2 ARBITRARY excitation tbt kick list for PolynomA 2nd +% derivative wrt 5th coordinate +% FUNCBDERIV2 ARBITRARY excitation tbt kick list for PolynomB 2nd +% derivative wrt 5th coordinate +% FUNCADERIV3 ARBITRARY excitation tbt kick list for PolynomA 3rd +% derivative wrt 5th coordinate +% FUNCBDERIV3 ARBITRARY excitation tbt kick list for PolynomB 3rd +% derivative wrt 5th coordinate % PERIODIC If true (default) the user input kick list is repeated % RAMPS Vector (t0, t1, t2, t3) in turn number to define the ramping of the excitation -% * t Date: Tue, 19 Nov 2024 18:51:38 +0100 Subject: [PATCH 019/129] adding function derivatives wrt to tau --- .../element_creation/atvariablemultipole.m | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index a1ffc189c..18aece716 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -23,17 +23,20 @@ % FUNCA ARBITRARY excitation turn-by-turn (tbt) kick list for PolynomA % FUNCB ARBITRARY excitation turn-by-turn (tbt) kick list for PolynomB % FUNCADERIV1 ARBITRARY excitation tbt kick list for PolynomA 1st -% derivative wrt 5th coordinate +% derivative wrt tau % FUNCBDERIV1 ARBITRARY excitation tbt kick list for PolynomB 1st -% derivative wrt 5th coordinate +% derivative wrt tau % FUNCADERIV2 ARBITRARY excitation tbt kick list for PolynomA 2nd -% derivative wrt 5th coordinate +% derivative wrt tau % FUNCBDERIV2 ARBITRARY excitation tbt kick list for PolynomB 2nd -% derivative wrt 5th coordinate +% derivative wrt tau % FUNCADERIV3 ARBITRARY excitation tbt kick list for PolynomA 3rd -% derivative wrt 5th coordinate +% derivative wrt tau % FUNCBDERIV3 ARBITRARY excitation tbt kick list for PolynomB 3rd -% derivative wrt 5th coordinate +% derivative wrt tau +% FUNCTIMEDELAY TimeDelay to generate a small time offset on the +% function FUNC. It only has an effect if any of the +% derivatives is not zero. % PERIODIC If true (default) the user input kick list is repeated % RAMPS Vector (t0, t1, t2, t3) in turn number to define the ramping of the excitation % * t Date: Tue, 19 Nov 2024 18:52:58 +0100 Subject: [PATCH 020/129] add Func derivatives wrt tau --- atintegrators/VariableThinMPolePass.c | 75 ++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 12 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index be012142a..eb37eea9f 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -3,6 +3,8 @@ S.White */ +/* 2024nov19 oblanco at ALBA CELLS. Add Funcderiv 1to4*/ + #include "atconstants.h" #include "atelem.c" #include "atlalib.c" @@ -18,6 +20,8 @@ struct elemab { double* Funcderiv1; double* Funcderiv2; double* Funcderiv3; + double* Funcderiv4; + double FuncTimeDelay; }; struct elem { @@ -55,13 +59,15 @@ double get_pol(struct elemab* elem, double* ramps, int mode, double t, int turn, int seed, int order, int periodic) { int idx; - double ampt, freq, ph, val, t2, oneoversix; - double* func, *funcderiv1, *funcderiv2, *funcderiv3; + double ampt, freq, ph, val, t2, oneoversix, oneovertwentyfour, functdelay; + double* func; + double *funcderiv1, *funcderiv2, *funcderiv3, *funcderiv4; double* amp = elem->Amplitude; if (!amp) { return 0.0; } ampt = get_amp(amp[order], ramps, turn); + switch (mode) { case 0: freq = elem->Frequency; @@ -74,15 +80,23 @@ double get_pol(struct elemab* elem, double* ramps, int mode, return ampt; case 2: if (periodic || turn < elem->NSamples) { + func = elem->Func; funcderiv1 = elem->Funcderiv1; funcderiv2 = elem->Funcderiv2; funcderiv3 = elem->Funcderiv3; + funcderiv4 = elem->Funcderiv4; + functdelay = elem->FuncTimeDelay; idx = turn % elem->NSamples; + + t = t - functdelay; t2 = t*t; oneoversix = 0.166666666666667; - ampt *= func[idx] + funcderiv1[idx]*t + 0.5*funcderiv2[idx]*t2 - + oneoversix*funcderiv3[idx]*t2*t; + oneovertwentyfour = 0.041666666666667; + ampt = ampt*(func[idx] + funcderiv1[idx]*t + + 0.5*funcderiv2[idx]*t2 + + oneoversix*funcderiv3[idx]*t2*t + + oneovertwentyfour*funcderiv4[idx]*t2*t2); return ampt; } else { return 0.0; @@ -97,7 +111,9 @@ void VariableThinMPolePass(double* r, struct elem* Elem, double t0, int turn, in int i, c; double* r6; - double t = t0 * turn; + double tpart; + double time_in_this_mode = 0; + double branchsinmode; int maxorder = Elem->MaxOrder; int periodic = Elem->Periodic; @@ -111,16 +127,21 @@ void VariableThinMPolePass(double* r, struct elem* Elem, double t0, int turn, in if (mode == 1) { for (i = 0; i < maxorder + 1; i++) { - pola[i] = get_pol(ElemA, ramps, mode, t, turn, seed, i, periodic); - polb[i] = get_pol(ElemB, ramps, mode, t, turn, seed, i, periodic); + pola[i] = get_pol(ElemA, ramps, mode, 0, turn, seed, i, periodic); + polb[i] = get_pol(ElemB, ramps, mode, 0, turn, seed, i, periodic); }; }; + // branch the time offset avoiding if statement inside the particle tracking + if (mode == 0){ + time_in_this_mode = t0 * turn; + } + for (c = 0; c < num_particles; c++) { r6 = r + c * 6; if (!atIsNaN(r6[0])) { if (mode != 1) { - double tpart = t + r6[5] / C0; + tpart = time_in_this_mode + r6[5] / C0; for (i = 0; i < maxorder + 1; i++) { pola[i] = get_pol(ElemA, ramps, mode, tpart, turn, seed, i, periodic); polb[i] = get_pol(ElemB, ramps, mode, tpart, turn, seed, i, periodic); @@ -142,6 +163,8 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, double *FuncAderiv1, *FuncBderiv1; double *FuncAderiv2, *FuncBderiv2; double *FuncAderiv3, *FuncBderiv3; + double *FuncAderiv4, *FuncBderiv4; + double FuncATimeDelay, FuncBTimeDelay; double FrequencyA, FrequencyB; double PhaseA, PhaseB; struct elemab *ElemA, *ElemB; @@ -167,6 +190,10 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, FuncBderiv2=atGetOptionalDoubleArray(ElemData,"FuncBderiv2"); check_error(); FuncAderiv3=atGetOptionalDoubleArray(ElemData,"FuncAderiv3"); check_error(); FuncBderiv3=atGetOptionalDoubleArray(ElemData,"FuncBderiv3"); check_error(); + FuncAderiv4=atGetOptionalDoubleArray(ElemData,"FuncAderiv4"); check_error(); + FuncBderiv4=atGetOptionalDoubleArray(ElemData,"FuncBderiv4"); check_error(); + FuncATimeDelay=atGetOptionalDouble(ElemData,"FuncATimeDelay", 0); check_error(); + FuncBTimeDelay=atGetOptionalDouble(ElemData,"FuncBTimeDelay", 0); check_error(); Periodic=atGetOptionalLong(ElemData,"Periodic", 1); check_error(); Elem = (struct elem*)atMalloc(sizeof(struct elem)); ElemA = (struct elemab*)atMalloc(sizeof(struct elemab)); @@ -194,6 +221,10 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, ElemB->Funcderiv2 = FuncBderiv2; ElemA->Funcderiv3 = FuncAderiv3; ElemB->Funcderiv3 = FuncBderiv3; + ElemA->Funcderiv4 = FuncAderiv4; + ElemB->Funcderiv4 = FuncBderiv4; + ElemA->FuncTimeDelay = FuncATimeDelay; + ElemB->FuncTimeDelay = FuncBTimeDelay; Elem->ElemA = ElemA; Elem->ElemB = ElemB; } @@ -220,6 +251,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) double *FuncAderiv1, *FuncBderiv1; double *FuncAderiv2, *FuncBderiv2; double *FuncAderiv3, *FuncBderiv3; + double *FuncAderiv4, *FuncBderiv4; + double FuncATimeDelay, FuncBTimeDelay; double FrequencyA, FrequencyB; double PhaseA, PhaseB; struct elemab ElA, *ElemA = &ElA; @@ -247,6 +280,10 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) FuncBderiv2=atGetOptionalDoubleArray(ElemData,"FuncBderiv2"); check_error(); FuncAderiv3=atGetOptionalDoubleArray(ElemData,"FuncAderiv3"); check_error(); FuncBderiv3=atGetOptionalDoubleArray(ElemData,"FuncBderiv3"); check_error(); + FuncAderiv4=atGetOptionalDoubleArray(ElemData,"FuncAderiv4"); check_error(); + FuncBderiv4=atGetOptionalDoubleArray(ElemData,"FuncBderiv4"); check_error(); + FuncATimeDelay=atGetOptionalDouble(ElemData,"FuncATimeDelay", 0); check_error(); + FuncBTimeDelay=atGetOptionalDouble(ElemData,"FuncBTimeDelay", 0); check_error(); Periodic=atGetOptionalLong(ElemData,"Periodic", 1); check_error(); Elem->PolynomA = PolynomA; Elem->PolynomB = PolynomB; @@ -267,6 +304,16 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) ElemB->Func = FuncB; Elem->ElemA = ElemA; Elem->ElemB = ElemB; + ElemA->Funcderiv1 = FuncAderiv1; + ElemB->Funcderiv1 = FuncBderiv1; + ElemA->Funcderiv2 = FuncAderiv2; + ElemB->Funcderiv2 = FuncBderiv2; + ElemA->Funcderiv3 = FuncAderiv3; + ElemB->Funcderiv3 = FuncBderiv3; + ElemA->Funcderiv4 = FuncAderiv4; + ElemB->Funcderiv4 = FuncBderiv4; + ElemA->FuncTimeDelay = FuncATimeDelay; + ElemB->FuncTimeDelay = FuncBTimeDelay; /* ALLOCATE memory for the output array of the same size as the input */ plhs[0] = mxDuplicateArray(prhs[1]); r_in = mxGetDoubles(plhs[0]); @@ -280,7 +327,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) mxSetCell(plhs[0], 3, mxCreateString("PolynomB")); if (nlhs > 1) { /* list of optional fields */ - plhs[1] = mxCreateCellMatrix(13, 1); + plhs[1] = mxCreateCellMatrix(23, 1); mxSetCell(plhs[1], 0, mxCreateString("AmplitudeA")); mxSetCell(plhs[1], 1, mxCreateString("AmplitudeB")); mxSetCell(plhs[1], 2, mxCreateString("FrequencyA")); @@ -297,9 +344,13 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) mxSetCell(plhs[1], 13, mxCreateString("FuncBderiv2")); mxSetCell(plhs[1], 14, mxCreateString("FuncAderiv3")); mxSetCell(plhs[1], 15, mxCreateString("FuncBderiv3")); - mxSetCell(plhs[1], 16, mxCreateString("NSamplesA")); - mxSetCell(plhs[1], 17, mxCreateString("NSamplesB")); - mxSetCell(plhs[1], 18, mxCreateString("Periodic")); + mxSetCell(plhs[1], 16, mxCreateString("FuncAderiv4")); + mxSetCell(plhs[1], 17, mxCreateString("FuncBderiv4")); + mxSetCell(plhs[1], 18, mxCreateString("FuncATimeDelay")); + mxSetCell(plhs[1], 19, mxCreateString("FuncBTimeDelay")); + mxSetCell(plhs[1], 20, mxCreateString("NSamplesA")); + mxSetCell(plhs[1], 21, mxCreateString("NSamplesB")); + mxSetCell(plhs[1], 22, mxCreateString("Periodic")); } } else { mexErrMsgIdAndTxt("AT:WrongArg", "Needs 0 or 2 arguments"); From 7c405e2cd409393ad65c41cbae3da73266212c2a Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 2 Dec 2024 18:04:37 +0100 Subject: [PATCH 021/129] improving doc of SINE mode --- pyat/at/lattice/variable_elements.py | 30 ++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 1132c78e2..7f67c6405 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -44,17 +44,39 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): r""" Create VariableMultipole. + This function creates a thin multipole of order and type defined by the + amplitude components; the polynoms PolynomA and PolynomB are calculated + on every turn depending on the chosen mode. + + Keep in mind that this element varies on every turn, therefore, any ring + containing a variable element may change after tracking n turns. + + There are three different modes implemented: SINE, WHITENOISE and ARBITRARY. + + The SINE mode requires amplitude, frequency and phase of at least one of the + two polynoms A or B. The j-th component of the polynom on the n-th turn + is given by: + amplitude_j*sin[ 2\pi*frequency*(nth_turn*T0 + c\tau_k) + phase], + where T0 is the revolution period of the ideal ring, and c\tau_k is the delay + of the particle i.e. the sixth coordinate. + The following is an example of the SINE mode of an skew quad: + eleskew = at.VariableMultipole('VAR_SKEW', + AmplitudeA=[0,skewa2],FrequencyA=freqA,PhaseA=phaseA) + The WHITENOISE mode requires the amplitude. + THe ARBITRARY mode requires the Amplitude + + Parameters: family_name(str): Element name + mode(ACMode): defines the evaluation grid. Default ACMode.SINE + * :py:attr:`.ACMode.SINE`: sine function + * :py:attr:`.ACMode.WHITENOISE`: gaussian white noise + * :py:attr:`.ACMode.ARBITRARY`: user defined turn-by-turn kick list Keyword Arguments: AmplitudeA(list,float): Amplitude of the excitation for PolynomA. Default None AmplitudeB(list,float): Amplitude of the excitation for PolynomB. Default None - mode(ACMode): defines the evaluation grid. Default ACMode.SINE - * :py:attr:`.ACMode.SINE`: sine function - * :py:attr:`.ACMode.WHITENOISE`: gaussian white noise - * :py:attr:`.ACMode.ARBITRARY`: user defined turn-by-turn kick list FrequencyA(float): Frequency of the sine excitation for PolynomA FrequencyB(float): Frequency of the sine excitation for PolynomB PhaseA(float): Phase of the sine excitation for PolynomA. Default 0 From b531d4ea5fa738a19ac39f9955819d6c383c72d3 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 2 Dec 2024 18:30:24 +0100 Subject: [PATCH 022/129] removing mode from vararging --- pyat/at/lattice/variable_elements.py | 69 +++++++++++----------------- 1 file changed, 27 insertions(+), 42 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 7f67c6405..e8f2455e0 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -20,23 +20,22 @@ class ACMode(IntEnum): class VariableMultipole(Element): """Class to generate an AT variable thin multipole element.""" - _BUILD_ATTRIBUTES = Element._BUILD_ATTRIBUTES + _BUILD_ATTRIBUTES = Element._BUILD_ATTRIBUTES + ['Mode'] _conversions = dict( Element._conversions, - Mode=int, - AmplitudeA=_array, - AmplitudeB=_array, - FrequencyA=float, - FrequencyB=float, - PhaseA=float, - PhaseB=float, - Seed=int, - NSamplesA=int, - NSamplesB=int, - FuncA=_array, - FuncB=_array, - Ramps=_array, - Periodic=bool, + amplitudeA=_array, + amplitudeB=_array, + frequencyA=float, + frequencyB=float, + phaseA=float, + phaseB=float, + seed=int, + nsamplesA=int, + nsamplesB=int, + funcA=_array, + funcB=_array, + ramps=_array, + periodic=bool, ) def __init__(self, family_name: str, **kwargs: dict[str, any]): @@ -58,12 +57,12 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): is given by: amplitude_j*sin[ 2\pi*frequency*(nth_turn*T0 + c\tau_k) + phase], where T0 is the revolution period of the ideal ring, and c\tau_k is the delay - of the particle i.e. the sixth coordinate. + of the kth particle i.e. the sixth coordinate. The following is an example of the SINE mode of an skew quad: eleskew = at.VariableMultipole('VAR_SKEW', AmplitudeA=[0,skewa2],FrequencyA=freqA,PhaseA=phaseA) The WHITENOISE mode requires the amplitude. - THe ARBITRARY mode requires the Amplitude + THe ARBITRARY mode requires the amplitude Parameters: @@ -73,16 +72,14 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): * :py:attr:`.ACMode.WHITENOISE`: gaussian white noise * :py:attr:`.ACMode.ARBITRARY`: user defined turn-by-turn kick list Keyword Arguments: - AmplitudeA(list,float): Amplitude of the excitation for PolynomA. + amplitudeA(list,float): Amplitude of the excitation for PolynomA. Default None - AmplitudeB(list,float): Amplitude of the excitation for PolynomB. + amplitudeB(list,float): Amplitude of the excitation for PolynomB. Default None - FrequencyA(float): Frequency of the sine excitation for PolynomA - FrequencyB(float): Frequency of the sine excitation for PolynomB - PhaseA(float): Phase of the sine excitation for PolynomA. Default 0 - PhaseB(float): Phase of the sine excitation for PolynomB. Default 0 - MaxOrder(int): Order of the multipole for scalar amplitude. Default 0 - It is overwritten with the length of Amplitude(A,B) + frequencyA(float): Frequency of the sine excitation for PolynomA + frequencyB(float): Frequency of the sine excitation for PolynomB + phaseA(float): Phase of the sine excitation for PolynomA. Default 0 + phaseB(float): Phase of the sine excitation for PolynomB. Default 0 Seed(int): Seed of the random number generator for white noise excitation. Default datetime.now() FuncA(list): User defined tbt kick list for PolynomA @@ -105,16 +102,14 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): Examples: - >>> acmpole = at.VariableMultipole('ACMPOLE', AmplitudeB=amp, FrequencyB=frequency) - >>> acmpole = at.VariableMultipole('ACMPOLE', AmplitudeB=amp, mode=at.ACMode.WHITENOISE) - >>> acmpole = at.VariableMultipole('ACMPOLE', AmplitudeB=amp, FuncB=fun, mode=at.ACMode.ARBITRARY) + >>> acmpole = at.VariableMultipole('ACMPOLE', amplitudeB=amp, frequencyB=frequency) + >>> acmpole = at.VariableMultipole('ACMPOLE', amplitudeB=amp, mode=at.ACMode.WHITENOISE) + >>> acmpole = at.VariableMultipole('ACMPOLE', amplitudeB=amp, funcB=fun, mode=at.ACMode.ARBITRARY) .. note:: - * If no parameters are given it will be initialized as IdentityPass. * For all excitation modes at least one amplitudes (A or B) has to be provided. - The default excitation is ``ACMode.SINE`` * For ``mode=ACMode.SINE`` the ``Frequency(A,B)`` corresponding to the ``Amplitude(A,B)`` has to be provided. * For ``mode=ACMode.ARBITRARY`` the ``Func(A,B)`` corresponding to the @@ -122,19 +117,10 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): """ if len(kwargs) > 0: self.FamName = family_name + self.Mode = int(mode) if "AmplitudeA" not in kwargs and "AmplitudeB" not in kwargs: raise AtError("Please provide at least one amplitude for A or B") - # start setting up Amplitudes and modes - # fist modes are called differently - modepyatinput = kwargs.pop("mode", ACMode.SINE) - modefromdict = kwargs.pop("Mode", None) - if modefromdict is not None: - mode = modefromdict # matlab class - else: - mode = modepyatinput - self.Mode = int(mode) - # MaxOrder is later overwritten by lenth of amplitudes - self.MaxOrder = kwargs.get("MaxOrder", 0) + # start setting up Amplitudes amplitudea = None amplitudeb = None if "AmplitudeA" in kwargs: @@ -149,7 +135,6 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): self.AmplitudeB = amplitudeb # end setting up Amplitudes and modes kwargs.setdefault("PassMethod", "VariableThinMPolePass") - # this overwrites MaxOrder self._setmaxorder(amplitudea, amplitudeb) if mode == ACMode.WHITENOISE and "Seed" not in kwargs: kwargs.update({"Seed": datetime.now().timestamp()}) From 3ffa2f7abc87144dd9df34ccf32ee69174dfac6b Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 2 Dec 2024 18:31:19 +0100 Subject: [PATCH 023/129] remove mode from varargsin --- .../element_creation/atvariablemultipole.m | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 18aece716..322ec1229 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -1,15 +1,39 @@ -function elem=atvariablemultipole(fname,varargin) -%ATVARIABLEMULTIPOLE Creates a variable thin multipole element +function elem=atvariablemultipole(fname, mode, varargin) +% ATVARIABLEMULTIPOLE Creates a variable thin multipole element % +% ATVARIABLEMULTIPOLE(FAMNAME,MODE) % ATVARIABLEMULTIPOLE(FAMNAME,MODE,PASSMETHOD,[KEY,VALUE]...) -% +% +% This function creates a thin multipole of order and type defined by the +% amplitude components; the polynoms PolynomA and PolynomB are calculated +% on every turn depending on the chosen mode. +% +% Keep in mind that this element varies on every turn, therefore, any ring +% containing a variable element may change after tracking n turns. +% +% There are three different modes implemented: SINE, WHITENOISE and ARBITRARY. +% +% The SINE mode requires amplitude, frequency and phase of at least one of the +% two polynoms A or B. The j-th component of the polynom on the n-th turn +% is given by: +% amplitude_j*sin[ 2\pi*frequency*(nth_turn*T0 + c\tau_k) + phase], +% where T0 is the revolution period of the ideal ring, and c\tau_k is the delay +% of the kth particle i.e. the sixth coordinate. +% The following is an example of the SINE mode of an skew quad: +% +% varskew = ATVARIABLEMULTIPOLE('VAR_SKEW','SINE', ... +% AmplitudeA=[0,skewa2],FrequencyA=freqA,PhaseA=phaseA) +% +% The WHITENOISE mode requires the amplitude. +% THe ARBITRARY mode requires the amplitude +% +% % INPUTS % FNAME Family name % MODE Excitation mode: 'SINE', 'WHITENOISE' or 'ARBITRARY'. -% Default: 'SINE' -% PASSMETHOD Tracking function. Default: 'VariableThinMPolePass' % % OPTIONS (order does not matter) +% PASSMETHOD Tracking function. Default: 'VariableThinMPolePass' % AMPLITUDEA Vector or scalar to define the excitation amplitude for % PolynomA % AMPLITUDEB Vector or scalar to define the excitation amplitude for @@ -18,7 +42,6 @@ % FREQUENCYB Frequency of SINE excitation for PolynomB % PHASEA Phase of SINE excitation for PolynomA % PHASEB Phase of SINE excitation for PolynomB -% MAXORDER Order of the multipole for a scalar amplitude % SEED Input seed for the random number generator % FUNCA ARBITRARY excitation turn-by-turn (tbt) kick list for PolynomA % FUNCB ARBITRARY excitation turn-by-turn (tbt) kick list for PolynomB @@ -65,9 +88,8 @@ % >> atvariablemultipole('ACM','WHITENOISE','AmplitudeB',1.e-4); % Input parser for option -[mode,rsrc]=getargs(varargin,'SINE','check',@(arg) any(strcmpi(arg,{'SINE','WHITENOISE','ARBITRARY'}))); -[method,rsrc]=getargs(rsrc,'VariableThinMPolePass','check',@(arg) (ischar(arg) || isstring(arg)) && endsWith(arg,'Pass')); -[mode,rsrc] = getoption(rsrc,'Mode',mode); +[method,rsrc]=getargs(varargin,'VariableThinMPolePass', ... + 'check',@(arg) (ischar(arg) || isstring(arg)) && endsWith(arg,'Pass')); [method,rsrc] = getoption(rsrc,'PassMethod',method); [cl,rsrc] = getoption(rsrc,'Class','VariableMultipole'); [maxorder,rsrc] = getoption(rsrc,'MaxOrder',0); From 79351f2ba6261e0c1dcbf39753eeafea9075e5d1 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 2 Dec 2024 18:39:50 +0100 Subject: [PATCH 024/129] add docstring SINE mode --- atmat/lattice/element_creation/atvariablemultipole.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 322ec1229..18c0b64b2 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -17,8 +17,10 @@ % two polynoms A or B. The j-th component of the polynom on the n-th turn % is given by: % amplitude_j*sin[ 2\pi*frequency*(nth_turn*T0 + c\tau_k) + phase], -% where T0 is the revolution period of the ideal ring, and c\tau_k is the delay -% of the kth particle i.e. the sixth coordinate. +% where T0 is the revolution period of the ideal ring, and c\tau_k is the +% delay of the kth particle i.e. the sixth coordinate over the speed of light. +% Also, note that the position of the element on the ring has no effect, +% the phase should be used to add any delay due to the position along s. % The following is an example of the SINE mode of an skew quad: % % varskew = ATVARIABLEMULTIPOLE('VAR_SKEW','SINE', ... From 07fc985061d8942f62067e3e0d29e2c8aab3d115 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 2 Dec 2024 18:40:05 +0100 Subject: [PATCH 025/129] add docstring SINE mode --- pyat/at/lattice/variable_elements.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index e8f2455e0..758d9e174 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -57,10 +57,13 @@ def __init__(self, family_name: str, **kwargs: dict[str, any]): is given by: amplitude_j*sin[ 2\pi*frequency*(nth_turn*T0 + c\tau_k) + phase], where T0 is the revolution period of the ideal ring, and c\tau_k is the delay - of the kth particle i.e. the sixth coordinate. + of the kth particle i.e. the sixth coordinate over the speed of light. Also, + note that the position of the element on the ring has no effect, the phase + should be used to add any delay due to the position along s. The following is an example of the SINE mode of an skew quad: eleskew = at.VariableMultipole('VAR_SKEW', AmplitudeA=[0,skewa2],FrequencyA=freqA,PhaseA=phaseA) + The WHITENOISE mode requires the amplitude. THe ARBITRARY mode requires the amplitude From aedf3ab1e638e72205253d9695c89547dac46d34 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 2 Dec 2024 19:08:58 +0100 Subject: [PATCH 026/129] import VariableMultipole from variable_elements --- pyat/at/lattice/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyat/at/lattice/__init__.py b/pyat/at/lattice/__init__.py index 527b212d2..cfbe6a27c 100644 --- a/pyat/at/lattice/__init__.py +++ b/pyat/at/lattice/__init__.py @@ -18,7 +18,7 @@ from .lattice_object import * # from .lattice_variables import * from .cavity_access import * -from .variable_elements import * +from .variable_elements import VariableMultipole from .deprecated import * # Define the module "lattice.constants" for backward compatibility # noinspection PyUnresolvedReferences From 7c4361a99ce48d0f8eee3f19f3ed34f858486e7e Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 2 Dec 2024 19:09:24 +0100 Subject: [PATCH 027/129] mode needs to be defined --- pyat/at/lattice/variable_elements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 758d9e174..1636f7f36 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -38,7 +38,7 @@ class VariableMultipole(Element): periodic=bool, ) - def __init__(self, family_name: str, **kwargs: dict[str, any]): + def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): # noinspection PyUnresolvedReferences r""" Create VariableMultipole. From 0f552605d1f90c130032d7da6022b39b0f011de7 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 2 Dec 2024 19:10:15 +0100 Subject: [PATCH 028/129] import variable_elements; and defines pass method mappiing --- pyat/at/load/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyat/at/load/utils.py b/pyat/at/load/utils.py index 8d4872ab9..f2038f493 100644 --- a/pyat/at/load/utils.py +++ b/pyat/at/load/utils.py @@ -32,6 +32,7 @@ from at.lattice import elements as elt from at.lattice import Lattice, Particle, Element, Marker from at.lattice import idtable_element +from at.lattice import variable_elements _ext_suffix = sysconfig.get_config_var("EXT_SUFFIX") _placeholder = "placeholder" @@ -138,6 +139,7 @@ def __init__( "AperturePass": elt.Aperture, "IdTablePass": idtable_element.InsertionDeviceKickMap, "GWigSymplecticPass": elt.Wiggler, + "VariableThinMPolePass": variable_elements.VariableMultipole, } # Maps python class name to Matlab class From fb889ae07e13b6c072294802542472a980f1f462 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 3 Dec 2024 23:52:18 +0100 Subject: [PATCH 029/129] test --- pyat/at/lattice/variable_elements.py | 54 +++++++++++++++------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 1636f7f36..756b388f9 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -23,23 +23,22 @@ class VariableMultipole(Element): _BUILD_ATTRIBUTES = Element._BUILD_ATTRIBUTES + ['Mode'] _conversions = dict( Element._conversions, - amplitudeA=_array, - amplitudeB=_array, - frequencyA=float, - frequencyB=float, - phaseA=float, - phaseB=float, + amplitudea=_array, + amplitudeb=_array, + frequencya=float, + frequencyb=float, + phasea=float, + phaseb=float, seed=int, - nsamplesA=int, - nsamplesB=int, - funcA=_array, - funcB=_array, + nsamplesa=int, + nsamplesb=int, + funca=_array, + funcb=_array, ramps=_array, periodic=bool, ) def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): - # noinspection PyUnresolvedReferences r""" Create VariableMultipole. @@ -105,27 +104,34 @@ def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): Examples: - >>> acmpole = at.VariableMultipole('ACMPOLE', amplitudeB=amp, frequencyB=frequency) - >>> acmpole = at.VariableMultipole('ACMPOLE', amplitudeB=amp, mode=at.ACMode.WHITENOISE) - >>> acmpole = at.VariableMultipole('ACMPOLE', amplitudeB=amp, funcB=fun, mode=at.ACMode.ARBITRARY) + >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.SINE, amplitudeb=amp, frequencyb=frequency) + >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.WHITENOISE, amplitudeb=amp) + >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.ARBITRARY, amplitudeb=amp, funcb=fun) - .. note:: - - * For all excitation modes at least one amplitudes (A or B) has - to be provided. - * For ``mode=ACMode.SINE`` the ``Frequency(A,B)`` corresponding to the - ``Amplitude(A,B)`` has to be provided. * For ``mode=ACMode.ARBITRARY`` the ``Func(A,B)`` corresponding to the ``Amplitude(A,B)`` has to be provided. """ + print(kwargs) if len(kwargs) > 0: self.FamName = family_name self.Mode = int(mode) - if "AmplitudeA" not in kwargs and "AmplitudeB" not in kwargs: - raise AtError("Please provide at least one amplitude for A or B") # start setting up Amplitudes - amplitudea = None - amplitudeb = None + theamplitudes = {"amplitudea" : None, "amplitudeb": None} + # amplitude names need to be different in pyat and matlab in order to avoid + # problems between args and kwargs + validamplitudenames = ["amplitude","Amplitude"] + invalidname = 1 + namecounter = 0 + lenvalidnames = len(validamplitudenames) + for thetype in ['A','B']: + while invalidname: + if namecounter >= lenvalidnames: + raise AtError("Please provide at least one amplitude for A or B") + else: + if validamplitudenames[namecounter] in kwargs: + invalidname = 0 + else: + namecounter += 1 if "AmplitudeA" in kwargs: amplitudea = kwargs.pop("AmplitudeA", None) amplitudea = self._set_params(amplitudea, mode, "A", **kwargs) From c089301caec07aa68650a734590b11b39de4444b Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Wed, 4 Dec 2024 20:00:14 +0100 Subject: [PATCH 030/129] separate amplitude and other parameters --- pyat/at/lattice/variable_elements.py | 72 ++++++++++++---------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 756b388f9..e140dea3a 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -118,38 +118,34 @@ def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): # start setting up Amplitudes theamplitudes = {"amplitudea" : None, "amplitudeb": None} # amplitude names need to be different in pyat and matlab in order to avoid - # problems between args and kwargs - validamplitudenames = ["amplitude","Amplitude"] - invalidname = 1 - namecounter = 0 - lenvalidnames = len(validamplitudenames) - for thetype in ['A','B']: - while invalidname: - if namecounter >= lenvalidnames: - raise AtError("Please provide at least one amplitude for A or B") - else: - if validamplitudenames[namecounter] in kwargs: - invalidname = 0 - else: - namecounter += 1 - if "AmplitudeA" in kwargs: - amplitudea = kwargs.pop("AmplitudeA", None) - amplitudea = self._set_params(amplitudea, mode, "A", **kwargs) - if "AmplitudeB" in kwargs: - amplitudeb = kwargs.pop("AmplitudeB", None) - amplitudeb = self._set_params(amplitudeb, mode, "B", **kwargs) - if amplitudea is not None: - self.AmplitudeA = amplitudea - if amplitudeb is not None: - self.AmplitudeB = amplitudeb - # end setting up Amplitudes and modes + # problems between args and kwargs in python + amp_aux = {'A':None, 'B':None} + all_amplitudes_are_none = 1 + for key in amp_aux.keys(): + if 'Amplitude'+key in kwargs and 'amplitude'+key in kwargs: + raise AtError('Duplicated amplitude '+key+'parameters.') + some_amplitude_exists = 1 + lower_case_kwargs = {k.lower(): v for k, v in kwargs.items()} + amp_aux[key] = lower_case_kwargs.pop('amplitude'+key.lower(), None) + if amp_aux[key] is not None: + all_amplitudes_are_none = 0 + if all_amplitudes_are_none: + raise AtError("Please provide at least one amplitude for A or B") + for key in amp_aux.keys(): + amp_aux[key] = self._set_amplitude(amp_aux[key]) + self._set_params(mode, key, **kwargs) + if amp_aux[key] is not None: + setattr(self, 'Amplitude'+key, amp_aux[key]) kwargs.setdefault("PassMethod", "VariableThinMPolePass") - self._setmaxorder(amplitudea, amplitudeb) + self._setmaxorder(amp_aux['A'], amp_aux['B']) if mode == ACMode.WHITENOISE and "Seed" not in kwargs: kwargs.update({"Seed": datetime.now().timestamp()}) self.Periodic = kwargs.pop("Periodic", True) - self.PolynomA = kwargs.pop("PolynomA", np.zeros(self.MaxOrder + 1)) - self.PolynomB = kwargs.pop("PolynomB", np.zeros(self.MaxOrder + 1)) + for key in amp_aux.keys(): + if amp_aux[key] is not None: + setattr(self, 'Polynom'+key, amp_aux[key]) + else: + setattr(self, 'Polynom'+key, np.zeros(self.MaxOrder+1)) # check ramps ramps = kwargs.pop("Ramps", None) if ramps is not None: @@ -166,29 +162,21 @@ def _setmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): if ampb is not None: mxb = np.max(np.append(np.nonzero(ampb), 0)) self.MaxOrder = max(mxa, mxb) - if ampa is not None: - delta = self.MaxOrder - len(ampa) - if delta > 0: - ampa = np.pad(ampa, (0, delta)) - self.AmplitudeA = ampa - if ampb is not None: - delta = self.MaxOrder + 1 - len(ampb) - if delta > 0: - ampb = np.pad(ampb, (0, delta)) - self.AmplitudeB = ampb - def _set_params( - self, amplitude: int or str, mode, a_b: str, **kwargs: dict[str, any] - ): + def _set_amplitude(self, amplitude: int or str): if amplitude is not None: if np.isscalar(amplitude): amp = np.zeros(self.MaxOrder) amplitude = np.append(amp, amplitude) + return np.asarray(amplitude) + + def _set_params( + self, mode, a_b: str, **kwargs: dict[str, any] + ): if mode == ACMode.SINE: self._set_sine(a_b, **kwargs) if mode == ACMode.ARBITRARY: self._set_arb(a_b, **kwargs) - return amplitude def _set_sine(self, a_b: str, **kwargs: dict[str, any]): frequency = kwargs.pop("Frequency" + a_b, None) From 9d1412caff4e9579acee8ae920662e96890503ac Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 5 Dec 2024 18:45:07 +0100 Subject: [PATCH 031/129] set parameters only for A or B --- pyat/at/lattice/variable_elements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index e140dea3a..d475bfbc8 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -133,8 +133,8 @@ def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): raise AtError("Please provide at least one amplitude for A or B") for key in amp_aux.keys(): amp_aux[key] = self._set_amplitude(amp_aux[key]) - self._set_params(mode, key, **kwargs) if amp_aux[key] is not None: + self._set_params(mode, key, **kwargs) setattr(self, 'Amplitude'+key, amp_aux[key]) kwargs.setdefault("PassMethod", "VariableThinMPolePass") self._setmaxorder(amp_aux['A'], amp_aux['B']) From aa1d9050e89e9859024805ba8c54d1605cb763c6 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 12 Dec 2024 09:20:35 +0100 Subject: [PATCH 032/129] fixing bugs --- pyat/at/lattice/variable_elements.py | 53 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index d475bfbc8..b7cf83c98 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -80,8 +80,8 @@ def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): Default None frequencyA(float): Frequency of the sine excitation for PolynomA frequencyB(float): Frequency of the sine excitation for PolynomB - phaseA(float): Phase of the sine excitation for PolynomA. Default 0 - phaseB(float): Phase of the sine excitation for PolynomB. Default 0 + phaseA(float): Phase of the sine excitation for PolynomA. Default 0 rad + phaseB(float): Phase of the sine excitation for PolynomB. Default 0 rad Seed(int): Seed of the random number generator for white noise excitation. Default datetime.now() FuncA(list): User defined tbt kick list for PolynomA @@ -112,15 +112,18 @@ def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): ``Amplitude(A,B)`` has to be provided. """ print(kwargs) + print(vars(self)) if len(kwargs) > 0: self.FamName = family_name self.Mode = int(mode) # start setting up Amplitudes - theamplitudes = {"amplitudea" : None, "amplitudeb": None} # amplitude names need to be different in pyat and matlab in order to avoid - # problems between args and kwargs in python + # problems between args and kwargs in python when loading a .mat file + # as a dictionary. + # I chose to use lower case in the pyat args, and A and B when reading + # from kwargs. amp_aux = {'A':None, 'B':None} - all_amplitudes_are_none = 1 + all_amplitudes_are_none = True for key in amp_aux.keys(): if 'Amplitude'+key in kwargs and 'amplitude'+key in kwargs: raise AtError('Duplicated amplitude '+key+'parameters.') @@ -128,17 +131,17 @@ def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): lower_case_kwargs = {k.lower(): v for k, v in kwargs.items()} amp_aux[key] = lower_case_kwargs.pop('amplitude'+key.lower(), None) if amp_aux[key] is not None: - all_amplitudes_are_none = 0 + all_amplitudes_are_none = False if all_amplitudes_are_none: raise AtError("Please provide at least one amplitude for A or B") - for key in amp_aux.keys(): - amp_aux[key] = self._set_amplitude(amp_aux[key]) - if amp_aux[key] is not None: - self._set_params(mode, key, **kwargs) - setattr(self, 'Amplitude'+key, amp_aux[key]) + for k,v in amp_aux.items(): + amp_aux[k] = self._set_amplitude(v) + if amp_aux[k] is not None: + setattr(self, 'Amplitude'+k, amp_aux[k]) + self._set_params(mode, k, **kwargs) kwargs.setdefault("PassMethod", "VariableThinMPolePass") self._setmaxorder(amp_aux['A'], amp_aux['B']) - if mode == ACMode.WHITENOISE and "Seed" not in kwargs: + if mode == ACMode.WHITENOISE and "seed" not in kwargs: kwargs.update({"Seed": datetime.now().timestamp()}) self.Periodic = kwargs.pop("Periodic", True) for key in amp_aux.keys(): @@ -163,33 +166,31 @@ def _setmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): mxb = np.max(np.append(np.nonzero(ampb), 0)) self.MaxOrder = max(mxa, mxb) - def _set_amplitude(self, amplitude: int or str): + def _set_amplitude(self, amplitude: float or _array or None): if amplitude is not None: if np.isscalar(amplitude): - amp = np.zeros(self.MaxOrder) - amplitude = np.append(amp, amplitude) - return np.asarray(amplitude) - - def _set_params( - self, mode, a_b: str, **kwargs: dict[str, any] - ): - if mode == ACMode.SINE: - self._set_sine(a_b, **kwargs) - if mode == ACMode.ARBITRARY: - self._set_arb(a_b, **kwargs) + amplitude = [amplitude] + amplitude = np.asarray(amplitude) + return amplitude + + def _set_params( self, mode, a_b: str, **kwargs: dict[str, any]): + if mode == ACMode.SINE: + self._set_sine(a_b, **kwargs) + if mode == ACMode.ARBITRARY: + self._set_arb(a_b, **kwargs) def _set_sine(self, a_b: str, **kwargs: dict[str, any]): frequency = kwargs.pop("Frequency" + a_b, None) - phase = kwargs.pop("Phase" + a_b, 0) if frequency is None: raise AtError("Please provide a value for Frequency" + a_b) + phase = kwargs.pop("Phase" + a_b, 0) setattr(self, "Frequency" + a_b, frequency) setattr(self, "Phase" + a_b, phase) def _set_arb(self, a_b: str, **kwargs: dict[str, any]): func = kwargs.pop("Func" + a_b, None) - nsamp = len(func) if func is None: raise AtError("Please provide a value for Func" + a_b) + nsamp = len(func) setattr(self, "Func" + a_b, func) setattr(self, "NSamples" + a_b, nsamp) From 5630fa5bd5813ec75b8e39578d2859594b85d9a5 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 12 Dec 2024 14:37:12 +0100 Subject: [PATCH 033/129] add apertures and misalignments --- atintegrators/VariableThinMPolePass.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index eb37eea9f..48dbda90d 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -147,7 +147,17 @@ void VariableThinMPolePass(double* r, struct elem* Elem, double t0, int turn, in polb[i] = get_pol(ElemB, ramps, mode, tpart, turn, seed, i, periodic); }; }; + /* misalignment at entrance */ + if (T1) ATaddvv(r6,T1); + if (R1) ATmultmv(r6,R1); + /* Check physical apertures at the entrance of the magnet */ + if (RApertures) checkiflostRectangularAp(r6,RApertures); + if (EApertures) checkiflostEllipticalAp(r6,EApertures); + /* track */ strthinkick(r6, pola, polb, 1.0, maxorder); + /* Misalignment at exit */ + if (R2) ATmultmv(r6,R2); + if (T2) ATaddvv(r6,T2); } } } From 59adb5461a77806398d66ca1ad76b290d3b95d7a Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 12 Dec 2024 14:45:58 +0100 Subject: [PATCH 034/129] add R1, R2, T1, T2, RApertures, EApertures --- atintegrators/VariableThinMPolePass.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index 48dbda90d..3ba6286aa 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -125,6 +125,13 @@ void VariableThinMPolePass(double* r, struct elem* Elem, double t0, int turn, in struct elemab* ElemB = Elem->ElemB; double* ramps = Elem->Ramps; + double *T1 = Elem->T1; + double *T2 = Elem->T2, + double *R1 = Elem->R1; + double *R2 = Elem->R2; + double *RApertures = Elem->RApertures; + double *EApertures = Elem->EApertures; + if (mode == 1) { for (i = 0; i < maxorder + 1; i++) { pola[i] = get_pol(ElemA, ramps, mode, 0, turn, seed, i, periodic); From 6d88ad61687fbf38905fba54db1e0131161a9700 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 13 Dec 2024 13:51:27 +0100 Subject: [PATCH 035/129] adds aperture, rotation and translations --- atintegrators/VariableThinMPolePass.c | 46 +++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index 3ba6286aa..b75b1b7fc 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -34,6 +34,12 @@ struct elem { int MaxOrder; double* Ramps; int Periodic; + double *R1; + double *R2; + double *T1; + double *T2; + double *EApertures; + double *RApertures; }; double get_amp(double amp, double* ramps, double t) @@ -106,7 +112,12 @@ double get_pol(struct elemab* elem, double* ramps, int mode, } } -void VariableThinMPolePass(double* r, struct elem* Elem, double t0, int turn, int num_particles) +void VariableThinMPolePass( + double* r, + struct elem* Elem, + double t0, + int turn, + int num_particles) { int i, c; @@ -126,7 +137,7 @@ void VariableThinMPolePass(double* r, struct elem* Elem, double t0, int turn, in double* ramps = Elem->Ramps; double *T1 = Elem->T1; - double *T2 = Elem->T2, + double *T2 = Elem->T2; double *R1 = Elem->R1; double *R2 = Elem->R2; double *RApertures = Elem->RApertures; @@ -146,9 +157,14 @@ void VariableThinMPolePass(double* r, struct elem* Elem, double t0, int turn, in for (c = 0; c < num_particles; c++) { r6 = r + c * 6; + /* check if the particle is alive */ if (!atIsNaN(r6[0])) { + /* mode 0 : sin function */ + /* mode 1 : */ if (mode != 1) { + /* modify the time of arrival of the particle */ tpart = time_in_this_mode + r6[5] / C0; + /* calculate the polynom A and B components seen by the particle */ for (i = 0; i < maxorder + 1; i++) { pola[i] = get_pol(ElemA, ramps, mode, tpart, turn, seed, i, periodic); polb[i] = get_pol(ElemB, ramps, mode, tpart, turn, seed, i, periodic); @@ -175,6 +191,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, { if (!Elem) { int MaxOrder, Mode, Seed, NSamplesA, NSamplesB, Periodic; + double *R1, *R2, *T1, *T2, *EApertures, *RApertures; double *PolynomA, *PolynomB, *AmplitudeA, *AmplitudeB; double *Ramps, *FuncA, *FuncB; double *FuncAderiv1, *FuncBderiv1; @@ -185,6 +202,12 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, double FrequencyA, FrequencyB; double PhaseA, PhaseB; struct elemab *ElemA, *ElemB; + R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); + R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); + T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); + T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); + EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); + RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); Mode=atGetLong(ElemData,"Mode"); check_error(); PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); @@ -215,6 +238,12 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, Elem = (struct elem*)atMalloc(sizeof(struct elem)); ElemA = (struct elemab*)atMalloc(sizeof(struct elemab)); ElemB = (struct elemab*)atMalloc(sizeof(struct elemab)); + Elem->R1=R1; + Elem->R2=R2; + Elem->T1=T1; + Elem->T2=T2; + Elem->EApertures=EApertures; + Elem->RApertures=RApertures; Elem->PolynomA = PolynomA; Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; @@ -263,6 +292,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) const mxArray* ElemData = prhs[0]; int num_particles = mxGetN(prhs[1]); int MaxOrder, Mode, Seed, NSamplesA, NSamplesB, Periodic; + double *R1, *R2, *T1, *T2, *EApertures, *RApertures; double *PolynomA, *PolynomB, *AmplitudeA, *AmplitudeB; double *Ramps, *FuncA, *FuncB; double *FuncAderiv1, *FuncBderiv1; @@ -275,6 +305,12 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) struct elemab ElA, *ElemA = &ElA; struct elemab ElB, *ElemB = &ElB; struct elem El, *Elem = &El; + R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); + R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); + T1=atGetOptionalDoubleArray(ElemData,"T1"); check_error(); + T2=atGetOptionalDoubleArray(ElemData,"T2"); check_error(); + EApertures=atGetOptionalDoubleArray(ElemData,"EApertures"); check_error(); + RApertures=atGetOptionalDoubleArray(ElemData,"RApertures"); check_error(); MaxOrder=atGetLong(ElemData,"MaxOrder"); check_error(); Mode=atGetLong(ElemData,"Mode"); check_error(); PolynomA=atGetDoubleArray(ElemData,"PolynomA"); check_error(); @@ -368,6 +404,12 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) mxSetCell(plhs[1], 20, mxCreateString("NSamplesA")); mxSetCell(plhs[1], 21, mxCreateString("NSamplesB")); mxSetCell(plhs[1], 22, mxCreateString("Periodic")); + mxSetCell(plhs[1], 23,mxCreateString("T1")); + mxSetCell(plhs[1], 24,mxCreateString("T2")); + mxSetCell(plhs[1], 25,mxCreateString("R1")); + mxSetCell(plhs[1], 26,mxCreateString("R2")); + mxSetCell(plhs[1], 27,mxCreateString("RApertures")); + mxSetCell(plhs[1], 28,mxCreateString("EApertures")); } } else { mexErrMsgIdAndTxt("AT:WrongArg", "Needs 0 or 2 arguments"); From 9d80e37fcfcd17300a9122a35ee3eaab0934767c Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 13 Dec 2024 15:05:36 +0100 Subject: [PATCH 036/129] add mode --- pyat/at/lattice/variable_elements.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index b7cf83c98..4592a568f 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -17,6 +17,12 @@ class ACMode(IntEnum): ARBITRARY = 2 +def _array(value, shape=(-1,), dtype=np.float64): + # Ensure proper ordering(F) and alignment(A) for "C" access in integrators + return np.require(value, dtype=dtype, requirements=["F", "A"]).reshape( + shape, order="F" + ) + class VariableMultipole(Element): """Class to generate an AT variable thin multipole element.""" @@ -111,11 +117,9 @@ def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): * For ``mode=ACMode.ARBITRARY`` the ``Func(A,B)`` corresponding to the ``Amplitude(A,B)`` has to be provided. """ - print(kwargs) - print(vars(self)) + print('0',kwargs) + kwargs['Mode'] = kwargs.get('Mode',mode) if len(kwargs) > 0: - self.FamName = family_name - self.Mode = int(mode) # start setting up Amplitudes # amplitude names need to be different in pyat and matlab in order to avoid # problems between args and kwargs in python when loading a .mat file @@ -156,6 +160,7 @@ def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): raise AtError("Ramps has to be a vector with 4 elements") self.Ramps = ramps # fill in super class + print('1',kwargs) super().__init__(family_name, **kwargs) def _setmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): @@ -171,6 +176,7 @@ def _set_amplitude(self, amplitude: float or _array or None): if np.isscalar(amplitude): amplitude = [amplitude] amplitude = np.asarray(amplitude) + print(type(amplitude),amplitude) return amplitude def _set_params( self, mode, a_b: str, **kwargs: dict[str, any]): From 67fb8dc485ff0b7614d28f7f136dbbce0f0cbd3a Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 13 Dec 2024 17:01:11 +0100 Subject: [PATCH 037/129] updating element --- pyat/at/lattice/variable_elements.py | 110 +++++++++++++-------------- 1 file changed, 51 insertions(+), 59 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 4592a568f..a8905a209 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -16,12 +16,10 @@ class ACMode(IntEnum): WHITENOISE = 1 ARBITRARY = 2 - def _array(value, shape=(-1,), dtype=np.float64): # Ensure proper ordering(F) and alignment(A) for "C" access in integrators - return np.require(value, dtype=dtype, requirements=["F", "A"]).reshape( - shape, order="F" - ) + return np.require(value, dtype=dtype, requirements=['F', 'A']).reshape( + shape, order='F') class VariableMultipole(Element): """Class to generate an AT variable thin multipole element.""" @@ -117,81 +115,67 @@ def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): * For ``mode=ACMode.ARBITRARY`` the ``Func(A,B)`` corresponding to the ``Amplitude(A,B)`` has to be provided. """ - print('0',kwargs) kwargs['Mode'] = kwargs.get('Mode',mode) - if len(kwargs) > 0: - # start setting up Amplitudes - # amplitude names need to be different in pyat and matlab in order to avoid - # problems between args and kwargs in python when loading a .mat file - # as a dictionary. - # I chose to use lower case in the pyat args, and A and B when reading - # from kwargs. - amp_aux = {'A':None, 'B':None} - all_amplitudes_are_none = True - for key in amp_aux.keys(): - if 'Amplitude'+key in kwargs and 'amplitude'+key in kwargs: - raise AtError('Duplicated amplitude '+key+'parameters.') - some_amplitude_exists = 1 - lower_case_kwargs = {k.lower(): v for k, v in kwargs.items()} - amp_aux[key] = lower_case_kwargs.pop('amplitude'+key.lower(), None) - if amp_aux[key] is not None: - all_amplitudes_are_none = False - if all_amplitudes_are_none: - raise AtError("Please provide at least one amplitude for A or B") + kwargs.setdefault("PassMethod","VariableThinMPolePass") + kwargs.setdefault("Periodic", True) + if len(kwargs) > 3: + amp_aux = self._check_amplitudes(**kwargs) for k,v in amp_aux.items(): - amp_aux[k] = self._set_amplitude(v) if amp_aux[k] is not None: - setattr(self, 'Amplitude'+k, amp_aux[k]) - self._set_params(mode, k, **kwargs) - kwargs.setdefault("PassMethod", "VariableThinMPolePass") - self._setmaxorder(amp_aux['A'], amp_aux['B']) - if mode == ACMode.WHITENOISE and "seed" not in kwargs: - kwargs.update({"Seed": datetime.now().timestamp()}) - self.Periodic = kwargs.pop("Periodic", True) + amp_aux[k] = self._set_amplitude(v) + kwargs['Amplitude'+k] = kwargs.get('Amplitude'+k, amp_aux[k]) + self._check_mode(mode, k, **kwargs) + maxorder = self._getmaxorder(amp_aux['A'], amp_aux['B']) + kwargs['MaxOrder'] = kwargs.get("MaxOrder", maxorder) for key in amp_aux.keys(): - if amp_aux[key] is not None: - setattr(self, 'Polynom'+key, amp_aux[key]) - else: - setattr(self, 'Polynom'+key, np.zeros(self.MaxOrder+1)) - # check ramps - ramps = kwargs.pop("Ramps", None) + kwargs['Polynom'+key] = kwargs.get('Polynom'+key, np.zeros(maxorder+1)) + ramps = self._check_ramp(**kwargs) if ramps is not None: - if len(ramps) != 4: - raise AtError("Ramps has to be a vector with 4 elements") - self.Ramps = ramps - # fill in super class - print('1',kwargs) + kwargs["Ramps"] = ramps super().__init__(family_name, **kwargs) - def _setmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): + + def _check_amplitudes(self, **kwargs: dict[str, any]): + amp_aux = {'A':None, 'B':None} + all_amplitudes_are_none = True + for key in amp_aux.keys(): + if 'Amplitude'+key in kwargs and 'amplitude'+key in kwargs: + raise AtError('Duplicated amplitude '+key+'parameters.') + lower_case_kwargs = {k.lower(): v for k, v in kwargs.items()} + amp_aux[key] = lower_case_kwargs.pop('amplitude'+key.lower(), None) + if amp_aux[key] is not None: + all_amplitudes_are_none = False + if all_amplitudes_are_none: + raise AtError("Please provide at least one amplitude for A or B") + return amp_aux + + def _set_amplitude(self, amplitude: float or _array or None): + if np.isscalar(amplitude): + amplitude = [amplitude] + amplitude = np.asarray(amplitude) + return amplitude + + def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): mxa, mxb = 0, 0 if ampa is not None: mxa = np.max(np.append(np.nonzero(ampa), 0)) if ampb is not None: mxb = np.max(np.append(np.nonzero(ampb), 0)) - self.MaxOrder = max(mxa, mxb) - - def _set_amplitude(self, amplitude: float or _array or None): - if amplitude is not None: - if np.isscalar(amplitude): - amplitude = [amplitude] - amplitude = np.asarray(amplitude) - print(type(amplitude),amplitude) - return amplitude + return max(mxa, mxb) - def _set_params( self, mode, a_b: str, **kwargs: dict[str, any]): + def _check_mode( self, mode, a_b: str, **kwargs: dict[str, any]): + if mode == ACMode.WHITENOISE and "seed" not in kwargs: + kwargs["Seed"] = kwargs.get("Seed", datetime.now().timestamp()) if mode == ACMode.SINE: - self._set_sine(a_b, **kwargs) + self._check_sine(a_b, **kwargs) if mode == ACMode.ARBITRARY: self._set_arb(a_b, **kwargs) - def _set_sine(self, a_b: str, **kwargs: dict[str, any]): + def _check_sine(self, a_b: str, **kwargs: dict[str, any]): frequency = kwargs.pop("Frequency" + a_b, None) if frequency is None: raise AtError("Please provide a value for Frequency" + a_b) - phase = kwargs.pop("Phase" + a_b, 0) - setattr(self, "Frequency" + a_b, frequency) - setattr(self, "Phase" + a_b, phase) + kwargs["Phase" + a_b] = kwargs.get("Phase" + a_b, 0) def _set_arb(self, a_b: str, **kwargs: dict[str, any]): func = kwargs.pop("Func" + a_b, None) @@ -200,3 +184,11 @@ def _set_arb(self, a_b: str, **kwargs: dict[str, any]): nsamp = len(func) setattr(self, "Func" + a_b, func) setattr(self, "NSamples" + a_b, nsamp) + + def _check_ramp(self, **kwargs: dict[str, any]): + ramps = kwargs.get("Ramps", None) + if ramps is not None: + if len(ramps) != 4: + raise AtError("Ramps has to be a vector with 4 elements") + ramps = np.asarray(ramps) + return ramps From c7197ddd0442e0139fd4ae0620bfc39ad954822b Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 13 Dec 2024 17:12:53 +0100 Subject: [PATCH 038/129] fixing datatype --- pyat/at/lattice/variable_elements.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index a8905a209..c278c9ef5 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -121,9 +121,8 @@ def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): if len(kwargs) > 3: amp_aux = self._check_amplitudes(**kwargs) for k,v in amp_aux.items(): - if amp_aux[k] is not None: - amp_aux[k] = self._set_amplitude(v) - kwargs['Amplitude'+k] = kwargs.get('Amplitude'+k, amp_aux[k]) + if v is not None: + kwargs['Amplitude'+k] = self._set_amplitude(v) self._check_mode(mode, k, **kwargs) maxorder = self._getmaxorder(amp_aux['A'], amp_aux['B']) kwargs['MaxOrder'] = kwargs.get("MaxOrder", maxorder) From 41682683633d40a47e749bf82ecd511638acbb50 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 13 Dec 2024 17:14:44 +0100 Subject: [PATCH 039/129] black --- pyat/at/lattice/variable_elements.py | 38 +++++++++++++++------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index c278c9ef5..5e628184e 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -16,15 +16,18 @@ class ACMode(IntEnum): WHITENOISE = 1 ARBITRARY = 2 + def _array(value, shape=(-1,), dtype=np.float64): # Ensure proper ordering(F) and alignment(A) for "C" access in integrators - return np.require(value, dtype=dtype, requirements=['F', 'A']).reshape( - shape, order='F') + return np.require(value, dtype=dtype, requirements=["F", "A"]).reshape( + shape, order="F" + ) + class VariableMultipole(Element): """Class to generate an AT variable thin multipole element.""" - _BUILD_ATTRIBUTES = Element._BUILD_ATTRIBUTES + ['Mode'] + _BUILD_ATTRIBUTES = Element._BUILD_ATTRIBUTES + ["Mode"] _conversions = dict( Element._conversions, amplitudea=_array, @@ -42,7 +45,7 @@ class VariableMultipole(Element): periodic=bool, ) - def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): + def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): r""" Create VariableMultipole. @@ -115,33 +118,34 @@ def __init__(self, family_name: str, mode:int, **kwargs: dict[str, any]): * For ``mode=ACMode.ARBITRARY`` the ``Func(A,B)`` corresponding to the ``Amplitude(A,B)`` has to be provided. """ - kwargs['Mode'] = kwargs.get('Mode',mode) - kwargs.setdefault("PassMethod","VariableThinMPolePass") + kwargs["Mode"] = kwargs.get("Mode", mode) + kwargs.setdefault("PassMethod", "VariableThinMPolePass") kwargs.setdefault("Periodic", True) if len(kwargs) > 3: amp_aux = self._check_amplitudes(**kwargs) - for k,v in amp_aux.items(): + for k, v in amp_aux.items(): if v is not None: - kwargs['Amplitude'+k] = self._set_amplitude(v) + kwargs["Amplitude" + k] = self._set_amplitude(v) self._check_mode(mode, k, **kwargs) - maxorder = self._getmaxorder(amp_aux['A'], amp_aux['B']) - kwargs['MaxOrder'] = kwargs.get("MaxOrder", maxorder) + maxorder = self._getmaxorder(amp_aux["A"], amp_aux["B"]) + kwargs["MaxOrder"] = kwargs.get("MaxOrder", maxorder) for key in amp_aux.keys(): - kwargs['Polynom'+key] = kwargs.get('Polynom'+key, np.zeros(maxorder+1)) + kwargs["Polynom" + key] = kwargs.get( + "Polynom" + key, np.zeros(maxorder + 1) + ) ramps = self._check_ramp(**kwargs) if ramps is not None: kwargs["Ramps"] = ramps super().__init__(family_name, **kwargs) - def _check_amplitudes(self, **kwargs: dict[str, any]): - amp_aux = {'A':None, 'B':None} + amp_aux = {"A": None, "B": None} all_amplitudes_are_none = True for key in amp_aux.keys(): - if 'Amplitude'+key in kwargs and 'amplitude'+key in kwargs: - raise AtError('Duplicated amplitude '+key+'parameters.') + if "Amplitude" + key in kwargs and "amplitude" + key in kwargs: + raise AtError("Duplicated amplitude " + key + "parameters.") lower_case_kwargs = {k.lower(): v for k, v in kwargs.items()} - amp_aux[key] = lower_case_kwargs.pop('amplitude'+key.lower(), None) + amp_aux[key] = lower_case_kwargs.pop("amplitude" + key.lower(), None) if amp_aux[key] is not None: all_amplitudes_are_none = False if all_amplitudes_are_none: @@ -162,7 +166,7 @@ def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): mxb = np.max(np.append(np.nonzero(ampb), 0)) return max(mxa, mxb) - def _check_mode( self, mode, a_b: str, **kwargs: dict[str, any]): + def _check_mode(self, mode, a_b: str, **kwargs: dict[str, any]): if mode == ACMode.WHITENOISE and "seed" not in kwargs: kwargs["Seed"] = kwargs.get("Seed", datetime.now().timestamp()) if mode == ACMode.SINE: From a272b799e61645afdbd3321bb63780f8ef707c26 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 13 Dec 2024 17:44:53 +0100 Subject: [PATCH 040/129] improve docstring --- pyat/at/lattice/variable_elements.py | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 5e628184e..8275aa1b9 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -49,25 +49,27 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): r""" Create VariableMultipole. - This function creates a thin multipole of order and type defined by the - amplitude components; the polynoms PolynomA and PolynomB are calculated - on every turn depending on the chosen mode. + This function creates a thin multipole any order (1 to k) and type (Normal + or Skew) defined by the amplitude A or B components; the polynoms PolynomA + and PolynomB are calculated on every turn depending on the chosen mode. All + modes could be ramped. Keep in mind that this element varies on every turn, therefore, any ring containing a variable element may change after tracking n turns. There are three different modes implemented: SINE, WHITENOISE and ARBITRARY. + By default all are periodic. The SINE mode requires amplitude, frequency and phase of at least one of the - two polynoms A or B. The j-th component of the polynom on the n-th turn - is given by: - amplitude_j*sin[ 2\pi*frequency*(nth_turn*T0 + c\tau_k) + phase], - where T0 is the revolution period of the ideal ring, and c\tau_k is the delay - of the kth particle i.e. the sixth coordinate over the speed of light. Also, + two polynoms A or B. The j-th component of the kth order polynom on the + n-th turn is given by: + amplitude_j*sin[ 2\pi*frequency*(nth_turn*T0 + \tau_p) + phase], + where T0 is the revolution period of the ideal ring, and \tau_p is the delay + of the pth particle i.e. the sixth coordinate over the speed of light. Also, note that the position of the element on the ring has no effect, the phase should be used to add any delay due to the position along s. The following is an example of the SINE mode of an skew quad: - eleskew = at.VariableMultipole('VAR_SKEW', + eleskew = at.VariableMultipole('VAR_SKEW',ACMode.SINE, AmplitudeA=[0,skewa2],FrequencyA=freqA,PhaseA=phaseA) The WHITENOISE mode requires the amplitude. From a1045d7a95ccf1905e71e341491eb5a8d24fa7a6 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 16 Dec 2024 14:47:15 +0100 Subject: [PATCH 041/129] modify comments --- atintegrators/VariableThinMPolePass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index be095dabb..8bb5dd5aa 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -3,7 +3,7 @@ S.White */ -/* 2024nov19 oblanco at ALBA CELLS. Add Funcderiv 1to4*/ +/* 2024nov19 oblanco at ALBA CELLS. modified to be compatible with AT matlab*/ #include "atconstants.h" #include "atelem.c" From a87c6c7ff9677869ba33703f316c26e6bf56b0c4 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 16 Dec 2024 16:56:38 +0100 Subject: [PATCH 042/129] add mean and std on random function --- atintegrators/VariableThinMPolePass.c | 71 +++++++++++++++++---------- 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index 8bb5dd5aa..1f495a9da 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -16,6 +16,7 @@ struct elemab { double Frequency; double Phase; int NSamples; + double Mean, Std; double* Func; double* Funcderiv1; double* Funcderiv2; @@ -30,6 +31,7 @@ struct elem { struct elemab* ElemA; struct elemab* ElemB; int Seed; + double Mean, Std; int Mode; int MaxOrder; double* Ramps; @@ -69,6 +71,8 @@ double get_pol(struct elemab* elem, double* ramps, int mode, double* func; double *funcderiv1, *funcderiv2, *funcderiv3, *funcderiv4; double* amp = elem->Amplitude; + double randmean = elem->Mean; + double randstd = elem->Std; if (!amp) { return 0.0; } @@ -81,7 +85,8 @@ double get_pol(struct elemab* elem, double* ramps, int mode, ampt *= sin(TWOPI * freq * t + ph); return ampt; case 1: - val = atrandn(0.0, 1.0); + val = atrandn(randmean, randstd); + printf("%.4f\n",val); ampt *= val; return ampt; case 2: @@ -143,14 +148,18 @@ void VariableThinMPolePass( double *RApertures = Elem->RApertures; double *EApertures = Elem->EApertures; + /* mode 0 : sin function */ + /* mode 1 : random value applied to all particles */ + /* mode 2 : */ if (mode == 1) { for (i = 0; i < maxorder + 1; i++) { + /* calculate the polynom to apply on all particles */ pola[i] = get_pol(ElemA, ramps, mode, 0, turn, seed, i, periodic); polb[i] = get_pol(ElemB, ramps, mode, 0, turn, seed, i, periodic); }; }; - // branch the time offset avoiding if statement inside the particle tracking + // offset the time when applying the sin function if (mode == 0){ time_in_this_mode = t0 * turn; } @@ -159,9 +168,7 @@ void VariableThinMPolePass( r6 = r + c * 6; /* check if the particle is alive */ if (!atIsNaN(r6[0])) { - /* mode 0 : sin function */ - /* mode 1 : */ - if (mode != 1) { + if (mode == 0 || mode == 2) { /* modify the time of arrival of the particle */ tpart = time_in_this_mode + r6[5] / C0; /* calculate the polynom A and B components seen by the particle */ @@ -191,6 +198,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, { if (!Elem) { int MaxOrder, Mode, Seed, NSamplesA, NSamplesB, Periodic; + double Mean, Std; double *R1, *R2, *T1, *T2, *EApertures, *RApertures; double *PolynomA, *PolynomB, *AmplitudeA, *AmplitudeB; double *Ramps, *FuncA, *FuncB; @@ -220,6 +228,8 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, PhaseB=atGetOptionalDouble(ElemData,"PhaseB", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); Seed=atGetOptionalLong(ElemData, "Seed", 0); check_error(); + Mean=atGetOptionalDouble(ElemData, "Mean", 0); check_error(); + Std=atGetOptionalDouble(ElemData, "Std", 0); check_error(); NSamplesA=atGetOptionalLong(ElemData, "NSamplesA", 1); check_error(); NSamplesB=atGetOptionalLong(ElemData, "NSamplesB", 1); check_error(); FuncA=atGetOptionalDoubleArray(ElemData,"FuncA"); check_error(); @@ -248,6 +258,8 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; Elem->Seed = Seed; + Elem->Mean = Mean; + Elem->Std = Std; Elem->Mode = Mode; Elem->MaxOrder = MaxOrder; Elem->Periodic = Periodic; @@ -292,6 +304,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) const mxArray* ElemData = prhs[0]; int num_particles = mxGetN(prhs[1]); int MaxOrder, Mode, Seed, NSamplesA, NSamplesB, Periodic; + double Mean, Std; double *R1, *R2, *T1, *T2, *EApertures, *RApertures; double *PolynomA, *PolynomB, *AmplitudeA, *AmplitudeB; double *Ramps, *FuncA, *FuncB; @@ -323,6 +336,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) PhaseB=atGetOptionalDouble(ElemData,"PhaseB", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); Seed=atGetOptionalLong(ElemData, "Seed", 0); check_error(); + Mean=atGetOptionalDouble(ElemData, "Mean", 0); check_error(); + Std=atGetOptionalDouble(ElemData, "Std", 0); check_error(); NSamplesA=atGetOptionalLong(ElemData, "NSamplesA", 0); check_error(); NSamplesB=atGetOptionalLong(ElemData, "NSamplesB", 0); check_error(); FuncA=atGetOptionalDoubleArray(ElemData,"FuncA"); check_error(); @@ -342,6 +357,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; Elem->Seed = Seed; + Elem->Mean = Seed; + Elem->Std = Seed; Elem->Mode = Mode; Elem->MaxOrder = MaxOrder; Elem->Periodic = Periodic; @@ -389,27 +406,29 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) mxSetCell(plhs[1], 5, mxCreateString("PhaseB")); mxSetCell(plhs[1], 6, mxCreateString("Ramps")); mxSetCell(plhs[1], 7, mxCreateString("Seed")); - mxSetCell(plhs[1], 8, mxCreateString("FuncA")); - mxSetCell(plhs[1], 9, mxCreateString("FuncB")); - mxSetCell(plhs[1], 10, mxCreateString("FuncAderiv1")); - mxSetCell(plhs[1], 11, mxCreateString("FuncBderiv1")); - mxSetCell(plhs[1], 12, mxCreateString("FuncAderiv2")); - mxSetCell(plhs[1], 13, mxCreateString("FuncBderiv2")); - mxSetCell(plhs[1], 14, mxCreateString("FuncAderiv3")); - mxSetCell(plhs[1], 15, mxCreateString("FuncBderiv3")); - mxSetCell(plhs[1], 16, mxCreateString("FuncAderiv4")); - mxSetCell(plhs[1], 17, mxCreateString("FuncBderiv4")); - mxSetCell(plhs[1], 18, mxCreateString("FuncATimeDelay")); - mxSetCell(plhs[1], 19, mxCreateString("FuncBTimeDelay")); - mxSetCell(plhs[1], 20, mxCreateString("NSamplesA")); - mxSetCell(plhs[1], 21, mxCreateString("NSamplesB")); - mxSetCell(plhs[1], 22, mxCreateString("Periodic")); - mxSetCell(plhs[1], 23,mxCreateString("T1")); - mxSetCell(plhs[1], 24,mxCreateString("T2")); - mxSetCell(plhs[1], 25,mxCreateString("R1")); - mxSetCell(plhs[1], 26,mxCreateString("R2")); - mxSetCell(plhs[1], 27,mxCreateString("RApertures")); - mxSetCell(plhs[1], 28,mxCreateString("EApertures")); + mxSetCell(plhs[1], 8, mxCreateString("Mean")); + mxSetCell(plhs[1], 9, mxCreateString("Std")); + mxSetCell(plhs[1], 10, mxCreateString("FuncA")); + mxSetCell(plhs[1], 11, mxCreateString("FuncB")); + mxSetCell(plhs[1], 12, mxCreateString("FuncAderiv1")); + mxSetCell(plhs[1], 13, mxCreateString("FuncBderiv1")); + mxSetCell(plhs[1], 14, mxCreateString("FuncAderiv2")); + mxSetCell(plhs[1], 15, mxCreateString("FuncBderiv2")); + mxSetCell(plhs[1], 16, mxCreateString("FuncAderiv3")); + mxSetCell(plhs[1], 17, mxCreateString("FuncBderiv3")); + mxSetCell(plhs[1], 18, mxCreateString("FuncAderiv4")); + mxSetCell(plhs[1], 19, mxCreateString("FuncBderiv4")); + mxSetCell(plhs[1], 20, mxCreateString("FuncATimeDelay")); + mxSetCell(plhs[1], 21, mxCreateString("FuncBTimeDelay")); + mxSetCell(plhs[1], 22, mxCreateString("NSamplesA")); + mxSetCell(plhs[1], 23, mxCreateString("NSamplesB")); + mxSetCell(plhs[1], 24, mxCreateString("Periodic")); + mxSetCell(plhs[1], 25,mxCreateString("T1")); + mxSetCell(plhs[1], 26,mxCreateString("T2")); + mxSetCell(plhs[1], 27,mxCreateString("R1")); + mxSetCell(plhs[1], 28,mxCreateString("R2")); + mxSetCell(plhs[1], 29,mxCreateString("RApertures")); + mxSetCell(plhs[1], 30,mxCreateString("EApertures")); } } else { mexErrMsgIdAndTxt("AT:WrongArg", "Needs 0 or 2 arguments"); From 39c37d680e85a5c984f23bc1083adc9f3dd2c7c0 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 16 Dec 2024 16:56:59 +0100 Subject: [PATCH 043/129] set mean and std on random whitenoise --- pyat/at/lattice/variable_elements.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 8275aa1b9..1b9fa5740 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -169,8 +169,13 @@ def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): return max(mxa, mxb) def _check_mode(self, mode, a_b: str, **kwargs: dict[str, any]): - if mode == ACMode.WHITENOISE and "seed" not in kwargs: - kwargs["Seed"] = kwargs.get("Seed", datetime.now().timestamp()) + if mode == ACMode.WHITENOISE: + if "seed" not in kwargs: + kwargs["Seed"] = kwargs.get("Seed", datetime.now().timestamp()) + if 'Mean' not in kwargs: + kwargs['Mean'] = kwargs.get("Mean", 0) + if 'Std' not in kwargs: + kwargs['Std'] = kwargs.get("Std", 1) if mode == ACMode.SINE: self._check_sine(a_b, **kwargs) if mode == ACMode.ARBITRARY: From 2d07122895dda0a31677265ed0f1b14bef2c1c93 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 16 Dec 2024 17:08:21 +0100 Subject: [PATCH 044/129] remove MaxOrder from user input --- atmat/lattice/element_creation/atvariablemultipole.m | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 18c0b64b2..9f304d97d 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -94,9 +94,7 @@ 'check',@(arg) (ischar(arg) || isstring(arg)) && endsWith(arg,'Pass')); [method,rsrc] = getoption(rsrc,'PassMethod',method); [cl,rsrc] = getoption(rsrc,'Class','VariableMultipole'); -[maxorder,rsrc] = getoption(rsrc,'MaxOrder',0); rsrc = struct(rsrc{:}); -rsrc.MaxOrder = maxorder; m=struct('SINE',0,'WHITENOISE',1,'ARBITRARY',2); @@ -144,10 +142,13 @@ function setsine(rsrc, ab) if isfield(rsrc,amplarg) amp=rsrc.(amplarg); if isscalar(amp) - rsrc.(amplarg)=[zeros(1,rsrc.MaxOrder) amp]; + rsrc.(amplarg)=[amp]; end if strcmpi(mode,'SINE') setsine(rsrc,ab); + end + if strcmpi(mode,'WHITENOISE') + end if strcmpi(mode,'ARBITRARY') rsrc = setarb(rsrc,ab); From d11fb9970181f04d7e8c2f70bd9b019ebd3352d7 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 16 Dec 2024 17:27:49 +0100 Subject: [PATCH 045/129] set white noise --- .../element_creation/atvariablemultipole.m | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 9f304d97d..836f37f1f 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -137,18 +137,28 @@ function setsine(rsrc, ab) end end + function rsrc = setwhitenoise(rsrc, ab) + whitenoise_params = {'Mean','Std'}; + whitenoise_defvals = {0,1}; + for idx = 1:length(whitenoise_params) + funcarg=strcat(whitenoise_params{idx},ab); + if ~isfield(rsrc,funcarg) + auxvalue = whitenoise_defvals{idx}; + else + auxvalue = rsrc.(strcat(whitenoise_params{idx},ab)); + end + rsrc.(strcat(whitenoise_params{idx},ab)) = auxvalue; + end + end + function rsrc = setparams(rsrc,mode,ab) amplarg=strcat('Amplitude',ab); if isfield(rsrc,amplarg) - amp=rsrc.(amplarg); - if isscalar(amp) - rsrc.(amplarg)=[amp]; - end if strcmpi(mode,'SINE') setsine(rsrc,ab); end if strcmpi(mode,'WHITENOISE') - + rsrc = setwhitenoise(rsrc,ab); end if strcmpi(mode,'ARBITRARY') rsrc = setarb(rsrc,ab); @@ -173,7 +183,7 @@ function setsine(rsrc, ab) else mxb=0; end - mxab=max([mxa,mxb,rsrc.MaxOrder+1]); + mxab=max([mxa,mxb,1]); rsrc.MaxOrder=mxab-1; if isfield(rsrc,'AmplitudeA') rsrc.AmplitudeA(mxa+1:mxab)=0; From e0ee7399a48d8a2655dd1929b66a80d4ff3bf0f7 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 16 Dec 2024 18:22:47 +0100 Subject: [PATCH 046/129] remove periodic from definition --- pyat/at/lattice/variable_elements.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 1b9fa5740..aad2fa278 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -122,8 +122,7 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): """ kwargs["Mode"] = kwargs.get("Mode", mode) kwargs.setdefault("PassMethod", "VariableThinMPolePass") - kwargs.setdefault("Periodic", True) - if len(kwargs) > 3: + if len(kwargs) > 2: amp_aux = self._check_amplitudes(**kwargs) for k, v in amp_aux.items(): if v is not None: @@ -180,6 +179,7 @@ def _check_mode(self, mode, a_b: str, **kwargs: dict[str, any]): self._check_sine(a_b, **kwargs) if mode == ACMode.ARBITRARY: self._set_arb(a_b, **kwargs) + kwargs["Periodic"] = kwargs.get("Periodic", True) def _check_sine(self, a_b: str, **kwargs: dict[str, any]): frequency = kwargs.pop("Frequency" + a_b, None) From 9227f95b0d70c7fa8e01ee2fc43fa1282e05428f Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 16 Dec 2024 18:23:09 +0100 Subject: [PATCH 047/129] testting random generator --- atintegrators/VariableThinMPolePass.c | 36 ++++++++++++++++----------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index 1f495a9da..9ea9a0f81 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -64,15 +64,17 @@ double get_amp(double amp, double* ramps, double t) } double get_pol(struct elemab* elem, double* ramps, int mode, - double t, int turn, int seed, int order, int periodic) + double t, int turn, int seed, int order, int periodic, + pcg32_random_t* rng + ) { int idx; double ampt, freq, ph, val, t2, oneoversix, oneovertwentyfour, functdelay; double* func; double *funcderiv1, *funcderiv2, *funcderiv3, *funcderiv4; double* amp = elem->Amplitude; - double randmean = elem->Mean; - double randstd = elem->Std; + double randmean; + double randstd; if (!amp) { return 0.0; } @@ -85,8 +87,12 @@ double get_pol(struct elemab* elem, double* ramps, int mode, ampt *= sin(TWOPI * freq * t + ph); return ampt; case 1: - val = atrandn(randmean, randstd); - printf("%.4f\n",val); + randmean = elem->Mean; + randstd = elem->Std; + val = atrandn_r(rng, randmean, randstd); + printf("randmean %.4f\n",randmean); + printf("randstd %.4f\n",randstd); + printf("val %.4f\n",val); ampt *= val; return ampt; case 2: @@ -122,7 +128,9 @@ void VariableThinMPolePass( struct elem* Elem, double t0, int turn, - int num_particles) + int num_particles, + pcg32_random_t* rng + ) { int i, c; @@ -154,8 +162,8 @@ void VariableThinMPolePass( if (mode == 1) { for (i = 0; i < maxorder + 1; i++) { /* calculate the polynom to apply on all particles */ - pola[i] = get_pol(ElemA, ramps, mode, 0, turn, seed, i, periodic); - polb[i] = get_pol(ElemB, ramps, mode, 0, turn, seed, i, periodic); + pola[i] = get_pol(ElemA, ramps, mode, 0, turn, seed, i, periodic,rng); + polb[i] = get_pol(ElemB, ramps, mode, 0, turn, seed, i, periodic,rng); }; }; @@ -173,8 +181,8 @@ void VariableThinMPolePass( tpart = time_in_this_mode + r6[5] / C0; /* calculate the polynom A and B components seen by the particle */ for (i = 0; i < maxorder + 1; i++) { - pola[i] = get_pol(ElemA, ramps, mode, tpart, turn, seed, i, periodic); - polb[i] = get_pol(ElemB, ramps, mode, tpart, turn, seed, i, periodic); + pola[i] = get_pol(ElemA, ramps, mode, tpart, turn, seed, i, periodic, rng); + polb[i] = get_pol(ElemB, ramps, mode, tpart, turn, seed, i, periodic, rng); }; }; /* misalignment at entrance */ @@ -288,7 +296,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, } double t0 = Param->T0; int turn = Param->nturn; - VariableThinMPolePass(r_in, Elem, t0, turn, num_particles); + VariableThinMPolePass(r_in, Elem, t0, turn, num_particles, Param->thread_rng); return Elem; } @@ -357,8 +365,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; Elem->Seed = Seed; - Elem->Mean = Seed; - Elem->Std = Seed; + Elem->Mean = Mean; + Elem->Std = Std; Elem->Mode = Mode; Elem->MaxOrder = MaxOrder; Elem->Periodic = Periodic; @@ -387,7 +395,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) /* ALLOCATE memory for the output array of the same size as the input */ plhs[0] = mxDuplicateArray(prhs[1]); r_in = mxGetDoubles(plhs[0]); - VariableThinMPolePass(r_in, Elem, 0, 0, num_particles); + VariableThinMPolePass(r_in, Elem, 0, 0, num_particles, &pcg32_global); } else if (nrhs == 0) { /* list of required fields */ plhs[0] = mxCreateCellMatrix(4, 1); From 6a219b4907173c5fdc9eeb46567d152e6ecde8e2 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 16 Dec 2024 19:03:13 +0100 Subject: [PATCH 048/129] debugging mean and std --- atintegrators/VariableThinMPolePass.c | 86 ++++++++++++++++----------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index 9ea9a0f81..e7d3ffa70 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -31,7 +31,8 @@ struct elem { struct elemab* ElemA; struct elemab* ElemB; int Seed; - double Mean, Std; + double MeanA, StdA; + double MeanB, StdB; int Mode; int MaxOrder; double* Ramps; @@ -137,7 +138,6 @@ void VariableThinMPolePass( double* r6; double tpart; double time_in_this_mode = 0; - double branchsinmode; int maxorder = Elem->MaxOrder; int periodic = Elem->Periodic; @@ -156,6 +156,9 @@ void VariableThinMPolePass( double *RApertures = Elem->RApertures; double *EApertures = Elem->EApertures; + printf("mode %d\n",mode); + printf("Elem->mode %d\n",Elem->Mode); + printf("ElemB->Std %.4f\n",ElemB->Std); /* mode 0 : sin function */ /* mode 1 : random value applied to all particles */ /* mode 2 : */ @@ -172,6 +175,7 @@ void VariableThinMPolePass( time_in_this_mode = t0 * turn; } + /* cycle over all particles */ for (c = 0; c < num_particles; c++) { r6 = r + c * 6; /* check if the particle is alive */ @@ -206,7 +210,8 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, { if (!Elem) { int MaxOrder, Mode, Seed, NSamplesA, NSamplesB, Periodic; - double Mean, Std; + double MeanA, StdA; + double MeanB, StdB; double *R1, *R2, *T1, *T2, *EApertures, *RApertures; double *PolynomA, *PolynomB, *AmplitudeA, *AmplitudeB; double *Ramps, *FuncA, *FuncB; @@ -236,8 +241,10 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, PhaseB=atGetOptionalDouble(ElemData,"PhaseB", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); Seed=atGetOptionalLong(ElemData, "Seed", 0); check_error(); - Mean=atGetOptionalDouble(ElemData, "Mean", 0); check_error(); - Std=atGetOptionalDouble(ElemData, "Std", 0); check_error(); + MeanA=atGetOptionalDouble(ElemData, "MeanA", 0); check_error(); + StdA=atGetOptionalDouble(ElemData, "StdA", 0); check_error(); + MeanB=atGetOptionalDouble(ElemData, "MeanB", 0); check_error(); + StdB=atGetOptionalDouble(ElemData, "StdB", 0); check_error(); NSamplesA=atGetOptionalLong(ElemData, "NSamplesA", 1); check_error(); NSamplesB=atGetOptionalLong(ElemData, "NSamplesB", 1); check_error(); FuncA=atGetOptionalDoubleArray(ElemData,"FuncA"); check_error(); @@ -266,8 +273,10 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; Elem->Seed = Seed; - Elem->Mean = Mean; - Elem->Std = Std; + ElemA->Mean = MeanA; + ElemA->Std = StdA; + ElemB->Mean = MeanB; + ElemB->Std = StdB; Elem->Mode = Mode; Elem->MaxOrder = MaxOrder; Elem->Periodic = Periodic; @@ -312,7 +321,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) const mxArray* ElemData = prhs[0]; int num_particles = mxGetN(prhs[1]); int MaxOrder, Mode, Seed, NSamplesA, NSamplesB, Periodic; - double Mean, Std; + double MeanA, StdA; + double MeanB, StdB; double *R1, *R2, *T1, *T2, *EApertures, *RApertures; double *PolynomA, *PolynomB, *AmplitudeA, *AmplitudeB; double *Ramps, *FuncA, *FuncB; @@ -344,8 +354,10 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) PhaseB=atGetOptionalDouble(ElemData,"PhaseB", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); Seed=atGetOptionalLong(ElemData, "Seed", 0); check_error(); - Mean=atGetOptionalDouble(ElemData, "Mean", 0); check_error(); - Std=atGetOptionalDouble(ElemData, "Std", 0); check_error(); + MeanA=atGetOptionalDouble(ElemData, "MeanA", 0); check_error(); + StdA=atGetOptionalDouble(ElemData, "StdA", 0); check_error(); + MeanB=atGetOptionalDouble(ElemData, "MeanB", 0); check_error(); + StdB=atGetOptionalDouble(ElemData, "StdB", 0); check_error(); NSamplesA=atGetOptionalLong(ElemData, "NSamplesA", 0); check_error(); NSamplesB=atGetOptionalLong(ElemData, "NSamplesB", 0); check_error(); FuncA=atGetOptionalDoubleArray(ElemData,"FuncA"); check_error(); @@ -365,8 +377,10 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; Elem->Seed = Seed; - Elem->Mean = Mean; - Elem->Std = Std; + ElemA->Mean = MeanA; + ElemA->Std = StdA; + ElemB->Mean = MeanB; + ElemB->Std = StdB; Elem->Mode = Mode; Elem->MaxOrder = MaxOrder; Elem->Periodic = Periodic; @@ -414,29 +428,31 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) mxSetCell(plhs[1], 5, mxCreateString("PhaseB")); mxSetCell(plhs[1], 6, mxCreateString("Ramps")); mxSetCell(plhs[1], 7, mxCreateString("Seed")); - mxSetCell(plhs[1], 8, mxCreateString("Mean")); - mxSetCell(plhs[1], 9, mxCreateString("Std")); - mxSetCell(plhs[1], 10, mxCreateString("FuncA")); - mxSetCell(plhs[1], 11, mxCreateString("FuncB")); - mxSetCell(plhs[1], 12, mxCreateString("FuncAderiv1")); - mxSetCell(plhs[1], 13, mxCreateString("FuncBderiv1")); - mxSetCell(plhs[1], 14, mxCreateString("FuncAderiv2")); - mxSetCell(plhs[1], 15, mxCreateString("FuncBderiv2")); - mxSetCell(plhs[1], 16, mxCreateString("FuncAderiv3")); - mxSetCell(plhs[1], 17, mxCreateString("FuncBderiv3")); - mxSetCell(plhs[1], 18, mxCreateString("FuncAderiv4")); - mxSetCell(plhs[1], 19, mxCreateString("FuncBderiv4")); - mxSetCell(plhs[1], 20, mxCreateString("FuncATimeDelay")); - mxSetCell(plhs[1], 21, mxCreateString("FuncBTimeDelay")); - mxSetCell(plhs[1], 22, mxCreateString("NSamplesA")); - mxSetCell(plhs[1], 23, mxCreateString("NSamplesB")); - mxSetCell(plhs[1], 24, mxCreateString("Periodic")); - mxSetCell(plhs[1], 25,mxCreateString("T1")); - mxSetCell(plhs[1], 26,mxCreateString("T2")); - mxSetCell(plhs[1], 27,mxCreateString("R1")); - mxSetCell(plhs[1], 28,mxCreateString("R2")); - mxSetCell(plhs[1], 29,mxCreateString("RApertures")); - mxSetCell(plhs[1], 30,mxCreateString("EApertures")); + mxSetCell(plhs[1], 8, mxCreateString("MeanA")); + mxSetCell(plhs[1], 9, mxCreateString("StdA")); + mxSetCell(plhs[1], 10, mxCreateString("MeanB")); + mxSetCell(plhs[1], 11, mxCreateString("StdB")); + mxSetCell(plhs[1], 12, mxCreateString("FuncA")); + mxSetCell(plhs[1], 13, mxCreateString("FuncB")); + mxSetCell(plhs[1], 14, mxCreateString("FuncAderiv1")); + mxSetCell(plhs[1], 15, mxCreateString("FuncBderiv1")); + mxSetCell(plhs[1], 16, mxCreateString("FuncAderiv2")); + mxSetCell(plhs[1], 17, mxCreateString("FuncBderiv2")); + mxSetCell(plhs[1], 18, mxCreateString("FuncAderiv3")); + mxSetCell(plhs[1], 19, mxCreateString("FuncBderiv3")); + mxSetCell(plhs[1], 20, mxCreateString("FuncAderiv4")); + mxSetCell(plhs[1], 21, mxCreateString("FuncBderiv4")); + mxSetCell(plhs[1], 22, mxCreateString("FuncATimeDelay")); + mxSetCell(plhs[1], 23, mxCreateString("FuncBTimeDelay")); + mxSetCell(plhs[1], 24, mxCreateString("NSamplesA")); + mxSetCell(plhs[1], 25, mxCreateString("NSamplesB")); + mxSetCell(plhs[1], 26, mxCreateString("Periodic")); + mxSetCell(plhs[1], 27,mxCreateString("T1")); + mxSetCell(plhs[1], 28,mxCreateString("T2")); + mxSetCell(plhs[1], 29,mxCreateString("R1")); + mxSetCell(plhs[1], 30,mxCreateString("R2")); + mxSetCell(plhs[1], 31,mxCreateString("RApertures")); + mxSetCell(plhs[1], 32,mxCreateString("EApertures")); } } else { mexErrMsgIdAndTxt("AT:WrongArg", "Needs 0 or 2 arguments"); From d05627a90497d400ccb051f24f8c6aa02773623e Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Mon, 16 Dec 2024 19:54:50 +0100 Subject: [PATCH 049/129] debugging seed of random number generator --- atintegrators/VariableThinMPolePass.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index e7d3ffa70..ec3ea3927 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -129,8 +129,7 @@ void VariableThinMPolePass( struct elem* Elem, double t0, int turn, - int num_particles, - pcg32_random_t* rng + int num_particles ) { @@ -156,6 +155,10 @@ void VariableThinMPolePass( double *RApertures = Elem->RApertures; double *EApertures = Elem->EApertures; + pcg32_random_t rng; + printf("Elem->Seed %d\n",Elem->Seed); + pcg32_srandom_r(&rng, 1, Elem->Seed); + printf("mode %d\n",mode); printf("Elem->mode %d\n",Elem->Mode); printf("ElemB->Std %.4f\n",ElemB->Std); @@ -165,8 +168,8 @@ void VariableThinMPolePass( if (mode == 1) { for (i = 0; i < maxorder + 1; i++) { /* calculate the polynom to apply on all particles */ - pola[i] = get_pol(ElemA, ramps, mode, 0, turn, seed, i, periodic,rng); - polb[i] = get_pol(ElemB, ramps, mode, 0, turn, seed, i, periodic,rng); + pola[i] = get_pol(ElemA, ramps, mode, 0, turn, seed, i, periodic,&rng); + polb[i] = get_pol(ElemB, ramps, mode, 0, turn, seed, i, periodic,&rng); }; }; @@ -185,8 +188,8 @@ void VariableThinMPolePass( tpart = time_in_this_mode + r6[5] / C0; /* calculate the polynom A and B components seen by the particle */ for (i = 0; i < maxorder + 1; i++) { - pola[i] = get_pol(ElemA, ramps, mode, tpart, turn, seed, i, periodic, rng); - polb[i] = get_pol(ElemB, ramps, mode, tpart, turn, seed, i, periodic, rng); + pola[i] = get_pol(ElemA, ramps, mode, tpart, turn, seed, i, periodic, &rng); + polb[i] = get_pol(ElemB, ramps, mode, tpart, turn, seed, i, periodic, &rng); }; }; /* misalignment at entrance */ @@ -305,7 +308,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, } double t0 = Param->T0; int turn = Param->nturn; - VariableThinMPolePass(r_in, Elem, t0, turn, num_particles, Param->thread_rng); + VariableThinMPolePass(r_in, Elem, t0, turn, num_particles); return Elem; } @@ -409,7 +412,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) /* ALLOCATE memory for the output array of the same size as the input */ plhs[0] = mxDuplicateArray(prhs[1]); r_in = mxGetDoubles(plhs[0]); - VariableThinMPolePass(r_in, Elem, 0, 0, num_particles, &pcg32_global); + VariableThinMPolePass(r_in, Elem, 0, 0, num_particles); +// VariableThinMPolePass(r_in, Elem, 0, 0, num_particles, &pcg32_global); } else if (nrhs == 0) { /* list of required fields */ plhs[0] = mxCreateCellMatrix(4, 1); From a4c66f10206e61db9339b038e66650933e77286e Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 17 Dec 2024 10:43:55 +0100 Subject: [PATCH 050/129] add seed initial state --- atintegrators/VariableThinMPolePass.c | 65 +++++++++++++++------------ 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index ec3ea3927..f5bb0e43f 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -30,7 +30,7 @@ struct elem { double* PolynomB; struct elemab* ElemA; struct elemab* ElemB; - int Seed; + int Seed, Seedinitstate; double MeanA, StdA; double MeanB, StdB; int Mode; @@ -143,6 +143,7 @@ void VariableThinMPolePass( double* pola = Elem->PolynomA; double* polb = Elem->PolynomB; int seed = Elem->Seed; + int seedinitstate = Elem->Seedinitstate; int mode = Elem->Mode; struct elemab* ElemA = Elem->ElemA; struct elemab* ElemB = Elem->ElemB; @@ -157,7 +158,8 @@ void VariableThinMPolePass( pcg32_random_t rng; printf("Elem->Seed %d\n",Elem->Seed); - pcg32_srandom_r(&rng, 1, Elem->Seed); + printf("Elem->Seedinitstate %d\n",Elem->Seedinitstate); + pcg32_srandom_r(&rng, Elem->Seedinitstate, Elem->Seed); printf("mode %d\n",mode); printf("Elem->mode %d\n",Elem->Mode); @@ -212,7 +214,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, double* r_in, int num_particles, struct parameters* Param) { if (!Elem) { - int MaxOrder, Mode, Seed, NSamplesA, NSamplesB, Periodic; + int MaxOrder, Mode, Seed, Seedinitstate, NSamplesA, NSamplesB, Periodic; double MeanA, StdA; double MeanB, StdB; double *R1, *R2, *T1, *T2, *EApertures, *RApertures; @@ -244,6 +246,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, PhaseB=atGetOptionalDouble(ElemData,"PhaseB", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); Seed=atGetOptionalLong(ElemData, "Seed", 0); check_error(); + Seedinitstate=atGetOptionalLong(ElemData, "Seedinitstate", 0); check_error(); MeanA=atGetOptionalDouble(ElemData, "MeanA", 0); check_error(); StdA=atGetOptionalDouble(ElemData, "StdA", 0); check_error(); MeanB=atGetOptionalDouble(ElemData, "MeanB", 0); check_error(); @@ -276,6 +279,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; Elem->Seed = Seed; + Elem->Seedinitstate = Seedinitstate; ElemA->Mean = MeanA; ElemA->Std = StdA; ElemB->Mean = MeanB; @@ -323,7 +327,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) double* r_in; const mxArray* ElemData = prhs[0]; int num_particles = mxGetN(prhs[1]); - int MaxOrder, Mode, Seed, NSamplesA, NSamplesB, Periodic; + int MaxOrder, Mode, Seed, Seedinitstate, NSamplesA, NSamplesB, Periodic; double MeanA, StdA; double MeanB, StdB; double *R1, *R2, *T1, *T2, *EApertures, *RApertures; @@ -357,6 +361,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) PhaseB=atGetOptionalDouble(ElemData,"PhaseB", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); Seed=atGetOptionalLong(ElemData, "Seed", 0); check_error(); + Seedinitstate=atGetOptionalLong(ElemData, "Seedinitstate", 0); check_error(); MeanA=atGetOptionalDouble(ElemData, "MeanA", 0); check_error(); StdA=atGetOptionalDouble(ElemData, "StdA", 0); check_error(); MeanB=atGetOptionalDouble(ElemData, "MeanB", 0); check_error(); @@ -380,6 +385,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; Elem->Seed = Seed; + Elem->Seedinitstate = Seedinitstate; ElemA->Mean = MeanA; ElemA->Std = StdA; ElemB->Mean = MeanB; @@ -432,31 +438,32 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) mxSetCell(plhs[1], 5, mxCreateString("PhaseB")); mxSetCell(plhs[1], 6, mxCreateString("Ramps")); mxSetCell(plhs[1], 7, mxCreateString("Seed")); - mxSetCell(plhs[1], 8, mxCreateString("MeanA")); - mxSetCell(plhs[1], 9, mxCreateString("StdA")); - mxSetCell(plhs[1], 10, mxCreateString("MeanB")); - mxSetCell(plhs[1], 11, mxCreateString("StdB")); - mxSetCell(plhs[1], 12, mxCreateString("FuncA")); - mxSetCell(plhs[1], 13, mxCreateString("FuncB")); - mxSetCell(plhs[1], 14, mxCreateString("FuncAderiv1")); - mxSetCell(plhs[1], 15, mxCreateString("FuncBderiv1")); - mxSetCell(plhs[1], 16, mxCreateString("FuncAderiv2")); - mxSetCell(plhs[1], 17, mxCreateString("FuncBderiv2")); - mxSetCell(plhs[1], 18, mxCreateString("FuncAderiv3")); - mxSetCell(plhs[1], 19, mxCreateString("FuncBderiv3")); - mxSetCell(plhs[1], 20, mxCreateString("FuncAderiv4")); - mxSetCell(plhs[1], 21, mxCreateString("FuncBderiv4")); - mxSetCell(plhs[1], 22, mxCreateString("FuncATimeDelay")); - mxSetCell(plhs[1], 23, mxCreateString("FuncBTimeDelay")); - mxSetCell(plhs[1], 24, mxCreateString("NSamplesA")); - mxSetCell(plhs[1], 25, mxCreateString("NSamplesB")); - mxSetCell(plhs[1], 26, mxCreateString("Periodic")); - mxSetCell(plhs[1], 27,mxCreateString("T1")); - mxSetCell(plhs[1], 28,mxCreateString("T2")); - mxSetCell(plhs[1], 29,mxCreateString("R1")); - mxSetCell(plhs[1], 30,mxCreateString("R2")); - mxSetCell(plhs[1], 31,mxCreateString("RApertures")); - mxSetCell(plhs[1], 32,mxCreateString("EApertures")); + mxSetCell(plhs[1], 8, mxCreateString("Seedinitstate")); + mxSetCell(plhs[1], 9, mxCreateString("MeanA")); + mxSetCell(plhs[1], 10, mxCreateString("StdA")); + mxSetCell(plhs[1], 11, mxCreateString("MeanB")); + mxSetCell(plhs[1], 12, mxCreateString("StdB")); + mxSetCell(plhs[1], 13, mxCreateString("FuncA")); + mxSetCell(plhs[1], 14, mxCreateString("FuncB")); + mxSetCell(plhs[1], 15, mxCreateString("FuncAderiv1")); + mxSetCell(plhs[1], 16, mxCreateString("FuncBderiv1")); + mxSetCell(plhs[1], 17, mxCreateString("FuncAderiv2")); + mxSetCell(plhs[1], 18, mxCreateString("FuncBderiv2")); + mxSetCell(plhs[1], 19, mxCreateString("FuncAderiv3")); + mxSetCell(plhs[1], 20, mxCreateString("FuncBderiv3")); + mxSetCell(plhs[1], 21, mxCreateString("FuncAderiv4")); + mxSetCell(plhs[1], 22, mxCreateString("FuncBderiv4")); + mxSetCell(plhs[1], 23, mxCreateString("FuncATimeDelay")); + mxSetCell(plhs[1], 24, mxCreateString("FuncBTimeDelay")); + mxSetCell(plhs[1], 25, mxCreateString("NSamplesA")); + mxSetCell(plhs[1], 26, mxCreateString("NSamplesB")); + mxSetCell(plhs[1], 27, mxCreateString("Periodic")); + mxSetCell(plhs[1], 28,mxCreateString("T1")); + mxSetCell(plhs[1], 29,mxCreateString("T2")); + mxSetCell(plhs[1], 30,mxCreateString("R1")); + mxSetCell(plhs[1], 31,mxCreateString("R2")); + mxSetCell(plhs[1], 32,mxCreateString("RApertures")); + mxSetCell(plhs[1], 33,mxCreateString("EApertures")); } } else { mexErrMsgIdAndTxt("AT:WrongArg", "Needs 0 or 2 arguments"); From 287bb37cb7fb17b6fe863ffb4b9268b64b5d1e1a Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 17 Dec 2024 10:44:17 +0100 Subject: [PATCH 051/129] add seed initial state --- atmat/lattice/element_creation/atvariablemultipole.m | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 836f37f1f..6cf7d95b6 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -158,6 +158,12 @@ function setsine(rsrc, ab) setsine(rsrc,ab); end if strcmpi(mode,'WHITENOISE') + if ~isfield(rsrc,'Seed') + rsrc.Seed = 1; + end + if ~isfield(rsrc,'Seedinitstate') + rsrc.Seedinitstate = 1; + end rsrc = setwhitenoise(rsrc,ab); end if strcmpi(mode,'ARBITRARY') From 731b52b71aa1f995628ffdb8c2eec13721725a45 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 17 Dec 2024 10:44:39 +0100 Subject: [PATCH 052/129] add seed initial state --- pyat/at/lattice/variable_elements.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index aad2fa278..449e60843 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -37,6 +37,7 @@ class VariableMultipole(Element): phasea=float, phaseb=float, seed=int, + seedinitstate=int, nsamplesa=int, nsamplesb=int, funca=_array, @@ -171,6 +172,8 @@ def _check_mode(self, mode, a_b: str, **kwargs: dict[str, any]): if mode == ACMode.WHITENOISE: if "seed" not in kwargs: kwargs["Seed"] = kwargs.get("Seed", datetime.now().timestamp()) + if "seedinitstate" not in kwargs: + kwargs["Seedinitstate"] = kwargs.get("Seedinitstate", 1) if 'Mean' not in kwargs: kwargs['Mean'] = kwargs.get("Mean", 0) if 'Std' not in kwargs: From 74555bd96a097960085ef26a241bbce23497f124 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 17 Dec 2024 19:19:40 +0100 Subject: [PATCH 053/129] include comments --- atintegrators/VariableThinMPolePass.c | 87 +++++++++++++++++---------- 1 file changed, 56 insertions(+), 31 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index f5bb0e43f..b59456d60 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -11,6 +11,8 @@ #include "atrandom.c" #include "driftkick.c" + +/* This struct contains the parameters of either A or B */ struct elemab { double* Amplitude; double Frequency; @@ -25,16 +27,18 @@ struct elemab { double FuncTimeDelay; }; +/* This struct contains the parameters of the element. + * It uses elemab struct */ struct elem { - double* PolynomA; - double* PolynomB; struct elemab* ElemA; struct elemab* ElemB; - int Seed, Seedinitstate; - double MeanA, StdA; - double MeanB, StdB; - int Mode; + double* PolynomA; // calculated on every turn + double* PolynomB; // calculated on every turn int MaxOrder; + int Mode; + int Seed, Seedinitstate; // used in white noise mode + double MeanA, StdA; // used in white noise mode + double MeanB, StdB; // used in white noise mode double* Ramps; int Periodic; double *R1; @@ -45,6 +49,10 @@ struct elem { double *RApertures; }; + +/* get_amp returns the same value when ramps is False. + * If ramps is True, it returns a value linearly interpolated + * accoding to the ramping turn.*/ double get_amp(double amp, double* ramps, double t) { double ampt = amp; @@ -64,13 +72,27 @@ double get_amp(double amp, double* ramps, double t) return ampt; } -double get_pol(struct elemab* elem, double* ramps, int mode, - double t, int turn, int seed, int order, int periodic, + +/* get_pol calculates the PolynomA/B per turn and mode */ +double get_pol( + struct elemab* elem, + double* ramps, + int mode, + double t, + int turn, + int seed, + int order, + int periodic, pcg32_random_t* rng ) { - int idx; - double ampt, freq, ph, val, t2, oneoversix, oneovertwentyfour, functdelay; + int turnidx; // turn index + double val; // amplitude value + + double ampt, freq, ph; // sin function parameters + double t2; // time squared + double oneoversix, oneovertwentyfour, functdelay; // custom func constants + // double* func; double *funcderiv1, *funcderiv2, *funcderiv3, *funcderiv4; double* amp = elem->Amplitude; @@ -90,7 +112,9 @@ double get_pol(struct elemab* elem, double* ramps, int mode, case 1: randmean = elem->Mean; randstd = elem->Std; - val = atrandn_r(rng, randmean, randstd); + // using seed needs to be debugged + //val = atrandn_r(rng, randmean, randstd); + val = atrandn(randmean, randstd); printf("randmean %.4f\n",randmean); printf("randstd %.4f\n",randstd); printf("val %.4f\n",val); @@ -105,16 +129,16 @@ double get_pol(struct elemab* elem, double* ramps, int mode, funcderiv3 = elem->Funcderiv3; funcderiv4 = elem->Funcderiv4; functdelay = elem->FuncTimeDelay; - idx = turn % elem->NSamples; + turnidx = turn % elem->NSamples; t = t - functdelay; t2 = t*t; oneoversix = 0.166666666666667; oneovertwentyfour = 0.041666666666667; - ampt = ampt*(func[idx] + funcderiv1[idx]*t - + 0.5*funcderiv2[idx]*t2 - + oneoversix*funcderiv3[idx]*t2*t - + oneovertwentyfour*funcderiv4[idx]*t2*t2); + ampt = ampt*(func[turnidx] + funcderiv1[turnidx]*t + + 0.5*funcderiv2[turnidx]*t2 + + oneoversix*funcderiv3[turnidx]*t2*t + + oneovertwentyfour*funcderiv4[turnidx]*t2*t2); return ampt; } else { return 0.0; @@ -129,7 +153,8 @@ void VariableThinMPolePass( struct elem* Elem, double t0, int turn, - int num_particles + int num_particles, + pcg32_random_t* rng ) { @@ -156,22 +181,14 @@ void VariableThinMPolePass( double *RApertures = Elem->RApertures; double *EApertures = Elem->EApertures; - pcg32_random_t rng; - printf("Elem->Seed %d\n",Elem->Seed); - printf("Elem->Seedinitstate %d\n",Elem->Seedinitstate); - pcg32_srandom_r(&rng, Elem->Seedinitstate, Elem->Seed); - - printf("mode %d\n",mode); - printf("Elem->mode %d\n",Elem->Mode); - printf("ElemB->Std %.4f\n",ElemB->Std); /* mode 0 : sin function */ /* mode 1 : random value applied to all particles */ - /* mode 2 : */ + /* mode 2 : custom function */ if (mode == 1) { for (i = 0; i < maxorder + 1; i++) { /* calculate the polynom to apply on all particles */ - pola[i] = get_pol(ElemA, ramps, mode, 0, turn, seed, i, periodic,&rng); - polb[i] = get_pol(ElemB, ramps, mode, 0, turn, seed, i, periodic,&rng); + pola[i] = get_pol(ElemA, ramps, mode, 0, turn, seed, i, periodic, rng); + polb[i] = get_pol(ElemB, ramps, mode, 0, turn, seed, i, periodic, rng); }; }; @@ -190,8 +207,8 @@ void VariableThinMPolePass( tpart = time_in_this_mode + r6[5] / C0; /* calculate the polynom A and B components seen by the particle */ for (i = 0; i < maxorder + 1; i++) { - pola[i] = get_pol(ElemA, ramps, mode, tpart, turn, seed, i, periodic, &rng); - polb[i] = get_pol(ElemB, ramps, mode, tpart, turn, seed, i, periodic, &rng); + pola[i] = get_pol(ElemA, ramps, mode, tpart, turn, seed, i, periodic, rng); + polb[i] = get_pol(ElemB, ramps, mode, tpart, turn, seed, i, periodic, rng); }; }; /* misalignment at entrance */ @@ -214,6 +231,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, double* r_in, int num_particles, struct parameters* Param) { if (!Elem) { + int MaxOrder, Mode, Seed, Seedinitstate, NSamplesA, NSamplesB, Periodic; double MeanA, StdA; double MeanB, StdB; @@ -312,7 +330,12 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, } double t0 = Param->T0; int turn = Param->nturn; - VariableThinMPolePass(r_in, Elem, t0, turn, num_particles); + pcg32_random_t rng; + printf("pymexElem->Seed %d\n",Elem->Seed); + printf("pymexElem->Seedinitstate %d\n",Elem->Seedinitstate); + pcg32_srandom_r(&rng, Elem->Seedinitstate, Elem->Seed); + + VariableThinMPolePass(r_in, Elem, t0, turn, num_particles, &rng); return Elem; } @@ -418,6 +441,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) /* ALLOCATE memory for the output array of the same size as the input */ plhs[0] = mxDuplicateArray(prhs[1]); r_in = mxGetDoubles(plhs[0]); + + printf("mexElem->Seed %d\n",Elem->Seed); VariableThinMPolePass(r_in, Elem, 0, 0, num_particles); // VariableThinMPolePass(r_in, Elem, 0, 0, num_particles, &pcg32_global); } else if (nrhs == 0) { From 9a804f2bda3cef8af332e5620bd0d62b539373d4 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 17 Dec 2024 19:20:05 +0100 Subject: [PATCH 054/129] set Periodic True default --- atmat/lattice/element_creation/atvariablemultipole.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 6cf7d95b6..b86c03f94 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -168,6 +168,9 @@ function setsine(rsrc, ab) end if strcmpi(mode,'ARBITRARY') rsrc = setarb(rsrc,ab); + if ~isfield(rsrc,'Periodic') + rsrc.Periodic = true; + end end end end From 680efdbbf1a6ef87a2938ee4f4d7ed7725d7cca7 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 17 Dec 2024 19:20:23 +0100 Subject: [PATCH 055/129] fixing bug in conversions --- pyat/at/lattice/variable_elements.py | 43 ++++++++++++++-------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 449e60843..aea3331af 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -17,33 +17,34 @@ class ACMode(IntEnum): ARBITRARY = 2 -def _array(value, shape=(-1,), dtype=np.float64): - # Ensure proper ordering(F) and alignment(A) for "C" access in integrators - return np.require(value, dtype=dtype, requirements=["F", "A"]).reshape( - shape, order="F" - ) - - class VariableMultipole(Element): """Class to generate an AT variable thin multipole element.""" _BUILD_ATTRIBUTES = Element._BUILD_ATTRIBUTES + ["Mode"] _conversions = dict( Element._conversions, - amplitudea=_array, - amplitudeb=_array, - frequencya=float, - frequencyb=float, - phasea=float, - phaseb=float, - seed=int, - seedinitstate=int, - nsamplesa=int, - nsamplesb=int, - funca=_array, - funcb=_array, - ramps=_array, - periodic=bool, + AmplitudeA=_array, + AmplitudeB=_array, + FrequencyA=float, + FrequencyB=float, + PhaseA=float, + PhaseB=float, + Seed=int, + Seedinitstate=int, + NsamplesA=int, + NsamplesB=int, + FuncA=_array, + FuncAderiv1=_array, + FuncAderiv2=_array, + FuncAderiv3=_array, + FuncAderiv4=_array, + FuncB=_array, + FuncBderiv1=_array, + FuncBderiv2=_array, + FuncBderiv3=_array, + FuncBderiv4=_array, + Ramps=_array, + Periodic=bool, ) def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): From e1308eab886eea880b6b40082a56f70bc1b62b40 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Wed, 18 Dec 2024 19:26:27 +0100 Subject: [PATCH 056/129] using Param->thread_rng --- atintegrators/VariableThinMPolePass.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index b59456d60..96de43dab 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -50,7 +50,7 @@ struct elem { }; -/* get_amp returns the same value when ramps is False. +/* get_amp returns the input value when ramps is False. * If ramps is True, it returns a value linearly interpolated * accoding to the ramping turn.*/ double get_amp(double amp, double* ramps, double t) @@ -113,8 +113,8 @@ double get_pol( randmean = elem->Mean; randstd = elem->Std; // using seed needs to be debugged - //val = atrandn_r(rng, randmean, randstd); - val = atrandn(randmean, randstd); + val = atrandn_r(rng, randmean, randstd); + //val = atrandn(randmean, randstd); printf("randmean %.4f\n",randmean); printf("randstd %.4f\n",randstd); printf("val %.4f\n",val); @@ -330,12 +330,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, } double t0 = Param->T0; int turn = Param->nturn; - pcg32_random_t rng; - printf("pymexElem->Seed %d\n",Elem->Seed); - printf("pymexElem->Seedinitstate %d\n",Elem->Seedinitstate); - pcg32_srandom_r(&rng, Elem->Seedinitstate, Elem->Seed); - - VariableThinMPolePass(r_in, Elem, t0, turn, num_particles, &rng); + VariableThinMPolePass(r_in, Elem, t0, turn, num_particles, Param->thread_rng); return Elem; } @@ -443,8 +438,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) r_in = mxGetDoubles(plhs[0]); printf("mexElem->Seed %d\n",Elem->Seed); - VariableThinMPolePass(r_in, Elem, 0, 0, num_particles); -// VariableThinMPolePass(r_in, Elem, 0, 0, num_particles, &pcg32_global); + VariableThinMPolePass(r_in, Elem, 0, 0, num_particles, Param->thread_rng); } else if (nrhs == 0) { /* list of required fields */ plhs[0] = mxCreateCellMatrix(4, 1); From a524815be3f1f8f59a9ea01dfce452f3f4b8b54b Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 15:38:00 +0100 Subject: [PATCH 057/129] removing seed; add comments; add Sinlimit --- atintegrators/VariableThinMPolePass.c | 176 ++++++++++++++++---------- 1 file changed, 112 insertions(+), 64 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index 96de43dab..e730588c4 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -3,7 +3,33 @@ S.White */ -/* 2024nov19 oblanco at ALBA CELLS. modified to be compatible with AT matlab*/ +/* 2024nov19 oblanco at ALBA CELLS. modified to be compatible with + pyat and AT matlab*/ + +/* + This pass method is implements three modes. + Mode 0 : a sin function with frequency and phase + Mode 1 : a random kick + Mode 2 : a custom function defined in every turn + + All modes could be ramped using the flag `ramp:. + + The value of the polynoms A and B are calculated per turn during tracking, + and also, in modes 0 and 2, per particle to take in to account + the delay time. + + In mode 0, the sin function could be limited to be between any value above + `Sinlimit`. For example a half-sin function would be obtained by setting + `Sinlimit` to zero. + + In mode 1 the stream of pseudo-random values is taken from the + parameters structure in attypes.h. For more details about the random + generator in AT: + https://github.com/atcollab/at/discussions/879 + + In mode 2, the values could be periodically applied or not. +*/ + #include "atconstants.h" #include "atelem.c" @@ -11,11 +37,16 @@ #include "atrandom.c" #include "driftkick.c" +/* constants to be used in the Taylor expansion of the custom function */ +#define oneoversix 0.166666666666667 +#define oneovertwentyfour 0.041666666666667 -/* This struct contains the parameters of either A or B */ +/* This struct contains the values to set one of the two + poynoms: A or B */ struct elemab { double* Amplitude; double Frequency; + double Sinlimit; double Phase; int NSamples; double Mean, Std; @@ -36,7 +67,6 @@ struct elem { double* PolynomB; // calculated on every turn int MaxOrder; int Mode; - int Seed, Seedinitstate; // used in white noise mode double MeanA, StdA; // used in white noise mode double MeanB, StdB; // used in white noise mode double* Ramps; @@ -50,7 +80,7 @@ struct elem { }; -/* get_amp returns the input value when ramps is False. +/* get_amp returns the input value `amp` when ramps is False. * If ramps is True, it returns a value linearly interpolated * accoding to the ramping turn.*/ double get_amp(double amp, double* ramps, double t) @@ -73,31 +103,39 @@ double get_amp(double amp, double* ramps, double t) } -/* get_pol calculates the PolynomA/B per turn and mode */ +/* get_pol calculates the PolynomA/B per turn and mode. + If the mode is 0 or 2, the polynom depends on the particle time + of delay*/ double get_pol( struct elemab* elem, double* ramps, int mode, - double t, + double t, // time int turn, - int seed, - int order, + int order, //max(length of any of the polynoms) - 1 int periodic, pcg32_random_t* rng ) { int turnidx; // turn index - double val; // amplitude value + double val; // amplitude value + double ampt; // amplitude per turn - double ampt, freq, ph; // sin function parameters - double t2; // time squared - double oneoversix, oneovertwentyfour, functdelay; // custom func constants - // + // sin mode parameters + double whole_sin_limit = elem->Sinlimit; + double freq, ph, sinval; + + // random mode parameters + double randmean; + double randstd; + + // custom mode parameters double* func; double *funcderiv1, *funcderiv2, *funcderiv3, *funcderiv4; double* amp = elem->Amplitude; - double randmean; - double randstd; + double t2; // time squared + double functdelay; + if (!amp) { return 0.0; } @@ -107,22 +145,20 @@ double get_pol( case 0: freq = elem->Frequency; ph = elem->Phase; - ampt *= sin(TWOPI * freq * t + ph); + sinval = sin(TWOPI * freq * t + ph); + // branchless if, to get + // the whole sin if whole_sin_limit is -1 or less + // the positive side of sin uf whole_sin_limit is 0. + ampt = ampt*sinval*(sinval > whole_sin_limit); return ampt; case 1: randmean = elem->Mean; randstd = elem->Std; - // using seed needs to be debugged val = atrandn_r(rng, randmean, randstd); - //val = atrandn(randmean, randstd); - printf("randmean %.4f\n",randmean); - printf("randstd %.4f\n",randstd); - printf("val %.4f\n",val); ampt *= val; return ampt; case 2: if (periodic || turn < elem->NSamples) { - func = elem->Func; funcderiv1 = elem->Funcderiv1; funcderiv2 = elem->Funcderiv2; @@ -133,9 +169,8 @@ double get_pol( t = t - functdelay; t2 = t*t; - oneoversix = 0.166666666666667; - oneovertwentyfour = 0.041666666666667; - ampt = ampt*(func[turnidx] + funcderiv1[turnidx]*t + ampt = ampt*(func[turnidx] + + funcderiv1[turnidx]*t + 0.5*funcderiv2[turnidx]*t2 + oneoversix*funcderiv3[turnidx]*t2*t + oneovertwentyfour*funcderiv4[turnidx]*t2*t2); @@ -148,47 +183,58 @@ double get_pol( } } +/* This function tracks a particle through a thin element with + variable PolynomB and PolynomA per turn.*/ void VariableThinMPolePass( - double* r, - struct elem* Elem, - double t0, - int turn, - int num_particles, - pcg32_random_t* rng + double* r, // the particle in 6D + struct elem* Elem, //the variable element + double t0, //time of one revolution + int turn, //number of the current turn + int num_particles, //number of particles + pcg32_random_t* rng // pcg32 random stream ) { - int i, c; - double* r6; - double tpart; + int i; // order of the polynom, counter + int c; // particle, counter + double* r6; // particle 6D coordinates + double tpart; //time of particle delay + + // particle time offset for the mode double time_in_this_mode = 0; - int maxorder = Elem->MaxOrder; - int periodic = Elem->Periodic; - double* pola = Elem->PolynomA; - double* polb = Elem->PolynomB; - int seed = Elem->Seed; - int seedinitstate = Elem->Seedinitstate; + // setting the element properties int mode = Elem->Mode; struct elemab* ElemA = Elem->ElemA; struct elemab* ElemB = Elem->ElemB; + double* pola = Elem->PolynomA; + double* polb = Elem->PolynomB; + int maxorder = Elem->MaxOrder; double* ramps = Elem->Ramps; + // custom function is periodic + int periodic = Elem->Periodic; + + // offsets at input and output double *T1 = Elem->T1; double *T2 = Elem->T2; + // rotations at input and output double *R1 = Elem->R1; double *R2 = Elem->R2; + // apertures double *RApertures = Elem->RApertures; double *EApertures = Elem->EApertures; /* mode 0 : sin function */ /* mode 1 : random value applied to all particles */ /* mode 2 : custom function */ + if (mode == 1) { + /* calculate the polynom to apply on all particles */ + /* the particle delay time is not used */ for (i = 0; i < maxorder + 1; i++) { - /* calculate the polynom to apply on all particles */ - pola[i] = get_pol(ElemA, ramps, mode, 0, turn, seed, i, periodic, rng); - polb[i] = get_pol(ElemB, ramps, mode, 0, turn, seed, i, periodic, rng); + pola[i] = get_pol(ElemA, ramps, mode, 0, turn, i, periodic, rng); + polb[i] = get_pol(ElemB, ramps, mode, 0, turn, i, periodic, rng); }; }; @@ -202,13 +248,14 @@ void VariableThinMPolePass( r6 = r + c * 6; /* check if the particle is alive */ if (!atIsNaN(r6[0])) { + /* mode 0 and mode 2 take into account the particle delay time */ if (mode == 0 || mode == 2) { - /* modify the time of arrival of the particle */ + /* modify the time of delay of the particle */ tpart = time_in_this_mode + r6[5] / C0; /* calculate the polynom A and B components seen by the particle */ for (i = 0; i < maxorder + 1; i++) { - pola[i] = get_pol(ElemA, ramps, mode, tpart, turn, seed, i, periodic, rng); - polb[i] = get_pol(ElemB, ramps, mode, tpart, turn, seed, i, periodic, rng); + pola[i] = get_pol(ElemA, ramps, mode, tpart, turn, i, periodic, rng); + polb[i] = get_pol(ElemB, ramps, mode, tpart, turn, i, periodic, rng); }; }; /* misalignment at entrance */ @@ -231,8 +278,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, double* r_in, int num_particles, struct parameters* Param) { if (!Elem) { - - int MaxOrder, Mode, Seed, Seedinitstate, NSamplesA, NSamplesB, Periodic; + int MaxOrder, Mode, NSamplesA, NSamplesB, Periodic; double MeanA, StdA; double MeanB, StdB; double *R1, *R2, *T1, *T2, *EApertures, *RApertures; @@ -245,6 +291,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, double FuncATimeDelay, FuncBTimeDelay; double FrequencyA, FrequencyB; double PhaseA, PhaseB; + double SinlimitA, SinlimitB; struct elemab *ElemA, *ElemB; R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); @@ -262,9 +309,9 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, FrequencyB=atGetOptionalDouble(ElemData,"FrequencyB", 0); check_error(); PhaseA=atGetOptionalDouble(ElemData,"PhaseA", 0); check_error(); PhaseB=atGetOptionalDouble(ElemData,"PhaseB", 0); check_error(); + SinlimitA=atGetOptionalDouble(ElemData,"SinlimitA", 0); check_error(); + SinlimitB=atGetOptionalDouble(ElemData,"SinlimitB", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); - Seed=atGetOptionalLong(ElemData, "Seed", 0); check_error(); - Seedinitstate=atGetOptionalLong(ElemData, "Seedinitstate", 0); check_error(); MeanA=atGetOptionalDouble(ElemData, "MeanA", 0); check_error(); StdA=atGetOptionalDouble(ElemData, "StdA", 0); check_error(); MeanB=atGetOptionalDouble(ElemData, "MeanB", 0); check_error(); @@ -296,8 +343,6 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, Elem->PolynomA = PolynomA; Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; - Elem->Seed = Seed; - Elem->Seedinitstate = Seedinitstate; ElemA->Mean = MeanA; ElemA->Std = StdA; ElemB->Mean = MeanB; @@ -311,6 +356,8 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, ElemB->Frequency = FrequencyB; ElemA->Phase = PhaseA; ElemB->Phase = PhaseB; + ElemA->Sinlimit = SinlimitA; + ElemB->Sinlimit = SinlimitB; ElemA->NSamples = NSamplesA; ElemB->NSamples = NSamplesB; ElemA->Func = FuncA; @@ -330,7 +377,8 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, } double t0 = Param->T0; int turn = Param->nturn; - VariableThinMPolePass(r_in, Elem, t0, turn, num_particles, Param->thread_rng); + + VariableThinMPolePass(r_in, Elem, t0, turn, num_particles, Param->common_rng); return Elem; } @@ -345,7 +393,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) double* r_in; const mxArray* ElemData = prhs[0]; int num_particles = mxGetN(prhs[1]); - int MaxOrder, Mode, Seed, Seedinitstate, NSamplesA, NSamplesB, Periodic; + int MaxOrder, Mode, NSamplesA, NSamplesB, Periodic; double MeanA, StdA; double MeanB, StdB; double *R1, *R2, *T1, *T2, *EApertures, *RApertures; @@ -358,6 +406,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) double FuncATimeDelay, FuncBTimeDelay; double FrequencyA, FrequencyB; double PhaseA, PhaseB; + double SinlimitA, SinlimitB; struct elemab ElA, *ElemA = &ElA; struct elemab ElB, *ElemB = &ElB; struct elem El, *Elem = &El; @@ -377,9 +426,9 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) FrequencyB=atGetOptionalDouble(ElemData,"FrequencyB", 0); check_error(); PhaseA=atGetOptionalDouble(ElemData,"PhaseA", 0); check_error(); PhaseB=atGetOptionalDouble(ElemData,"PhaseB", 0); check_error(); + SinlimitA=atGetOptionalDouble(ElemData,"SinlimitA", 0); check_error(); + SinlimitB=atGetOptionalDouble(ElemData,"SinlimitB", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); - Seed=atGetOptionalLong(ElemData, "Seed", 0); check_error(); - Seedinitstate=atGetOptionalLong(ElemData, "Seedinitstate", 0); check_error(); MeanA=atGetOptionalDouble(ElemData, "MeanA", 0); check_error(); StdA=atGetOptionalDouble(ElemData, "StdA", 0); check_error(); MeanB=atGetOptionalDouble(ElemData, "MeanB", 0); check_error(); @@ -402,8 +451,6 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) Elem->PolynomA = PolynomA; Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; - Elem->Seed = Seed; - Elem->Seedinitstate = Seedinitstate; ElemA->Mean = MeanA; ElemA->Std = StdA; ElemB->Mean = MeanB; @@ -417,6 +464,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) ElemB->Frequency = FrequencyB; ElemA->Phase = PhaseA; ElemB->Phase = PhaseB; + ElemA->Sinlimit = SinlimitA; + ElemB->Sinlimit = SinlimitB; ElemA->NSamples = NSamplesA; ElemB->NSamples = NSamplesB; ElemA->Func = FuncA; @@ -437,8 +486,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) plhs[0] = mxDuplicateArray(prhs[1]); r_in = mxGetDoubles(plhs[0]); - printf("mexElem->Seed %d\n",Elem->Seed); - VariableThinMPolePass(r_in, Elem, 0, 0, num_particles, Param->thread_rng); + VariableThinMPolePass(r_in, Elem, 0, 0, num_particles, Param->common_rng); } else if (nrhs == 0) { /* list of required fields */ plhs[0] = mxCreateCellMatrix(4, 1); @@ -446,7 +494,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) mxSetCell(plhs[0], 1, mxCreateString("Mode")); mxSetCell(plhs[0], 2, mxCreateString("PolynomA")); mxSetCell(plhs[0], 3, mxCreateString("PolynomB")); - if (nlhs > 1) { + if (nlhs > 4) { /* list of optional fields */ plhs[1] = mxCreateCellMatrix(23, 1); mxSetCell(plhs[1], 0, mxCreateString("AmplitudeA")); @@ -455,9 +503,9 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) mxSetCell(plhs[1], 3, mxCreateString("FrequencyB")); mxSetCell(plhs[1], 4, mxCreateString("PhaseA")); mxSetCell(plhs[1], 5, mxCreateString("PhaseB")); - mxSetCell(plhs[1], 6, mxCreateString("Ramps")); - mxSetCell(plhs[1], 7, mxCreateString("Seed")); - mxSetCell(plhs[1], 8, mxCreateString("Seedinitstate")); + mxSetCell(plhs[1], 6, mxCreateString("SinlimitA")); + mxSetCell(plhs[1], 7, mxCreateString("SinlimitB")); + mxSetCell(plhs[1], 8, mxCreateString("Ramps")); mxSetCell(plhs[1], 9, mxCreateString("MeanA")); mxSetCell(plhs[1], 10, mxCreateString("StdA")); mxSetCell(plhs[1], 11, mxCreateString("MeanB")); From f84c5503a047db05da9ab94bc78446dfc1f8427b Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 16:12:59 +0100 Subject: [PATCH 058/129] sinlimit > or = --- atintegrators/VariableThinMPolePass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index e730588c4..cfa5b396c 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -149,7 +149,7 @@ double get_pol( // branchless if, to get // the whole sin if whole_sin_limit is -1 or less // the positive side of sin uf whole_sin_limit is 0. - ampt = ampt*sinval*(sinval > whole_sin_limit); + ampt = ampt*sinval*(sinval >= whole_sin_limit); return ampt; case 1: randmean = elem->Mean; From c0de95723f1b5d08b71cacaf5a65b37483d598c1 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 16:17:33 +0100 Subject: [PATCH 059/129] remove seed; add sinlimit --- pyat/at/lattice/variable_elements.py | 68 +++++++++++++++++++--------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index aea3331af..3d4871c4e 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -29,8 +29,8 @@ class VariableMultipole(Element): FrequencyB=float, PhaseA=float, PhaseB=float, - Seed=int, - Seedinitstate=int, + SinlimitA=float, + SinlimitB=float, NsamplesA=int, NsamplesB=int, FuncA=_array, @@ -53,14 +53,13 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): This function creates a thin multipole any order (1 to k) and type (Normal or Skew) defined by the amplitude A or B components; the polynoms PolynomA - and PolynomB are calculated on every turn depending on the chosen mode. All - modes could be ramped. + and PolynomB are calculated on every turn depending on the chosen mode, and + for some modes on the particle time delay. All modes could be ramped. Keep in mind that this element varies on every turn, therefore, any ring containing a variable element may change after tracking n turns. There are three different modes implemented: SINE, WHITENOISE and ARBITRARY. - By default all are periodic. The SINE mode requires amplitude, frequency and phase of at least one of the two polynoms A or B. The j-th component of the kth order polynom on the @@ -73,28 +72,58 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): The following is an example of the SINE mode of an skew quad: eleskew = at.VariableMultipole('VAR_SKEW',ACMode.SINE, AmplitudeA=[0,skewa2],FrequencyA=freqA,PhaseA=phaseA) - - The WHITENOISE mode requires the amplitude. - THe ARBITRARY mode requires the amplitude + The values of the sin function could be limited to be above a defined + threshold using `Sinlimit`. For example, you could create a half-sin + by setting `Sinlimit` to zero. + + The WHITENOISE mode requires the amplitude of either A or B. For example + elenoise = at.VariableMultipole('MYNOISE',ACMode.WHITENOISE, + AmplitudeA=[noiseA1]) + creates a gaussian vertical noise of amplitude noiseA1. The gaussian + distribution is generated with zero-mean and one standard deviation from + a pseudo-random stream pcg32. The pcg32 seed is fixed by the tracking + function, therefore using the same stream on all trackings (sequencial or + parallel). See https://github.com/atcollab/at/discussions/879 for more + details on the pseudo random stream. Additionally, the user could set + the mean and std values by setting MeanA, MeanB, StdA, StdB. + + The ARBITRARY mode requires the definition of a custom turn-by-turn function. + The user defines the value of the function and its Taylor expansion with + respect to \tau up to fourth order. + value = f(turn) + f'(turn)*tau + 0.5*f''(turn)*tau**2 + + 1/6*f'''(turn)*tau**3 + 1/24*f''''(turn)*tau**4 + where f is an array of values, f',f'',f''',f'''', are arrays containing + the derivatives wrt \tau, and \tau is the time delay of the particle, i.e. + the the sixth coordinate divided by the speed of light. + For example, the following is a positive vertical kick in the first turn, + negative on the second turn, and zero on the third turn. + funca = [1 -1 0]; + elesinglekick = at.VariableMultipole('CUSTOMFUNC','ARBITRARY', + AmplitudeA=1e-4,FuncA=funca,Periodic=True) + by default the array is assumed periodic. If Periodic is set to False + any turn exceeding the defined length of the function is assumed to have + no effect on the beam. Parameters: - family_name(str): Element name + family_name(str): Element name mode(ACMode): defines the evaluation grid. Default ACMode.SINE * :py:attr:`.ACMode.SINE`: sine function * :py:attr:`.ACMode.WHITENOISE`: gaussian white noise * :py:attr:`.ACMode.ARBITRARY`: user defined turn-by-turn kick list Keyword Arguments: - amplitudeA(list,float): Amplitude of the excitation for PolynomA. + AmplitudeA(list,float): Amplitude of the excitation for PolynomA. Default None - amplitudeB(list,float): Amplitude of the excitation for PolynomB. + AmplitudeB(list,float): Amplitude of the excitation for PolynomB. Default None - frequencyA(float): Frequency of the sine excitation for PolynomA - frequencyB(float): Frequency of the sine excitation for PolynomB - phaseA(float): Phase of the sine excitation for PolynomA. Default 0 rad - phaseB(float): Phase of the sine excitation for PolynomB. Default 0 rad - Seed(int): Seed of the random number generator for white - noise excitation. Default datetime.now() + FrequencyA(float): Frequency of the sine excitation for PolynomA + FrequencyB(float): Frequency of the sine excitation for PolynomB + PhaseA(float): Phase of the sine excitation for PolynomA. Default 0 rad + PhaseB(float): Phase of the sine excitation for PolynomB. Default 0 rad + SinlimitA(float): Default -1. Values of the sin function will be above + SinlimitA or zero. + SinlimitB(float): Default -1. Values of the sin function will be above + SinlimitB or zero. FuncA(list): User defined tbt kick list for PolynomA FuncB(list): User defined tbt kick list for PolynomB Periodic(bool): If True (default) the user defined kick is repeated @@ -171,10 +200,6 @@ def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): def _check_mode(self, mode, a_b: str, **kwargs: dict[str, any]): if mode == ACMode.WHITENOISE: - if "seed" not in kwargs: - kwargs["Seed"] = kwargs.get("Seed", datetime.now().timestamp()) - if "seedinitstate" not in kwargs: - kwargs["Seedinitstate"] = kwargs.get("Seedinitstate", 1) if 'Mean' not in kwargs: kwargs['Mean'] = kwargs.get("Mean", 0) if 'Std' not in kwargs: @@ -190,6 +215,7 @@ def _check_sine(self, a_b: str, **kwargs: dict[str, any]): if frequency is None: raise AtError("Please provide a value for Frequency" + a_b) kwargs["Phase" + a_b] = kwargs.get("Phase" + a_b, 0) + kwargs["Sinlimit" + a_b] = kwargs.get("Sinlimit" + a_b, -1) def _set_arb(self, a_b: str, **kwargs: dict[str, any]): func = kwargs.pop("Func" + a_b, None) From 4f13031de93110ded66cc94a9786cbea0335d7fe Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 17:04:23 +0100 Subject: [PATCH 060/129] add Sinlimit; remove seed --- .../element_creation/atvariablemultipole.m | 162 ++++++++++++------ 1 file changed, 106 insertions(+), 56 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index b86c03f94..089d48dd9 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -4,66 +4,53 @@ % ATVARIABLEMULTIPOLE(FAMNAME,MODE) % ATVARIABLEMULTIPOLE(FAMNAME,MODE,PASSMETHOD,[KEY,VALUE]...) % -% This function creates a thin multipole of order and type defined by the -% amplitude components; the polynoms PolynomA and PolynomB are calculated -% on every turn depending on the chosen mode. -% -% Keep in mind that this element varies on every turn, therefore, any ring -% containing a variable element may change after tracking n turns. -% -% There are three different modes implemented: SINE, WHITENOISE and ARBITRARY. -% -% The SINE mode requires amplitude, frequency and phase of at least one of the -% two polynoms A or B. The j-th component of the polynom on the n-th turn -% is given by: -% amplitude_j*sin[ 2\pi*frequency*(nth_turn*T0 + c\tau_k) + phase], -% where T0 is the revolution period of the ideal ring, and c\tau_k is the -% delay of the kth particle i.e. the sixth coordinate over the speed of light. -% Also, note that the position of the element on the ring has no effect, -% the phase should be used to add any delay due to the position along s. -% The following is an example of the SINE mode of an skew quad: -% -% varskew = ATVARIABLEMULTIPOLE('VAR_SKEW','SINE', ... -% AmplitudeA=[0,skewa2],FrequencyA=freqA,PhaseA=phaseA) -% -% The WHITENOISE mode requires the amplitude. -% THe ARBITRARY mode requires the amplitude -% -% % INPUTS % FNAME Family name % MODE Excitation mode: 'SINE', 'WHITENOISE' or 'ARBITRARY'. % -% OPTIONS (order does not matter) +% OPTIONS % PASSMETHOD Tracking function. Default: 'VariableThinMPolePass' -% AMPLITUDEA Vector or scalar to define the excitation amplitude for +% +% MORE OPTIONS (order does not matter) +% AmplitudeA Vector or scalar to define the excitation amplitude for +% PolynomA +% AmplitudeB Vector or scalar to define the excitation amplitude for +% PolynomB +% FrequencyA Frequency of SINE excitation for PolynomA +% FrequencyB Frequency of SINE excitation for PolynomB +% PhaseA Phase of SINE excitation for PolynomA +% PhaseB Phase of SINE excitation for PolynomB +% SinlimitA Limit the sin function to be above. Default -1. +% SinlimitB Limit the sin function to be above. Default -1. +% MeanA Mean value of the gaussian noise. Default 0. +% StdA Std value of the gaussian noise. Default 1. +% MeanB Mean value of the gaussian noise. Default 0. +% StdB Std value of the gaussian noise. Default 1. +% FuncA ARBITRARY excitation turn-by-turn (tbt) kick list for % PolynomA -% AMPLITUDEB Vector or scalar to define the excitation amplitude for +% FuncB ARBITRARY excitation turn-by-turn (tbt) kick list for % PolynomB -% FREQUENCYA Frequency of SINE excitation for PolynomA -% FREQUENCYB Frequency of SINE excitation for PolynomB -% PHASEA Phase of SINE excitation for PolynomA -% PHASEB Phase of SINE excitation for PolynomB -% SEED Input seed for the random number generator -% FUNCA ARBITRARY excitation turn-by-turn (tbt) kick list for PolynomA -% FUNCB ARBITRARY excitation turn-by-turn (tbt) kick list for PolynomB -% FUNCADERIV1 ARBITRARY excitation tbt kick list for PolynomA 1st +% FuncAderiv1 ARBITRARY excitation tbt kick list for PolynomA 1st % derivative wrt tau -% FUNCBDERIV1 ARBITRARY excitation tbt kick list for PolynomB 1st +% FuncBderiv1 ARBITRARY excitation tbt kick list for PolynomB 1st % derivative wrt tau -% FUNCADERIV2 ARBITRARY excitation tbt kick list for PolynomA 2nd +% FuncAderiv2 ARBITRARY excitation tbt kick list for PolynomA 2nd % derivative wrt tau -% FUNCBDERIV2 ARBITRARY excitation tbt kick list for PolynomB 2nd +% FuncBderiv2 ARBITRARY excitation tbt kick list for PolynomB 2nd % derivative wrt tau -% FUNCADERIV3 ARBITRARY excitation tbt kick list for PolynomA 3rd +% FuncAderiv3 ARBITRARY excitation tbt kick list for PolynomA 3rd % derivative wrt tau -% FUNCBDERIV3 ARBITRARY excitation tbt kick list for PolynomB 3rd +% FuncBderiv3 ARBITRARY excitation tbt kick list for PolynomB 3rd % derivative wrt tau -% FUNCTIMEDELAY TimeDelay to generate a small time offset on the +% FuncATimeDelay TimeDelay to generate a small time offset on the +% function FUNC. It only has an effect if any of the +% derivatives is not zero. +% FuncBTimeDelay TimeDelay to generate a small time offset on the % function FUNC. It only has an effect if any of the % derivatives is not zero. -% PERIODIC If true (default) the user input kick list is repeated -% RAMPS Vector (t0, t1, t2, t3) in turn number to define the ramping of the excitation +% Periodic If true (default) the user input kick list is repeated +% Ramps Vector (t0, t1, t2, t3) in turn number to define the +% ramping of the excitation % * t> atvariablemultipole('ACM','WHITENOISE','AmplitudeB',1.e-4); +% +% % Create a vertical kick in the first turn and the opposite kick in the second +% % turn. +% >> funca = [1 -1 0]; +% >> atvariablemultipole('CUSTOMFUNC','ARBITRARY','AmplitudeA',1e-4, ... +% 'FuncA',funca,'Periodic',false); +% +% +% MORE DETAILS +% +% This function creates a thin multipole of any order (1 to k) and type +% (Normal or Skew) defined by the amplitude A or B components; the polynoms +% PolynomA and PolynomB are calculated on every turn depending on the +% chosen mode, and for some modes also on the particle time delay. +% All modes could be ramped. +% +% Keep in mind that this element varies on every turn, therefore, any ring +% containing a variable element may change after tracking n turns. +% +% There are three different modes implemented: +% SINE, WHITENOISE and ARBITRARY. +% +% The SINE mode requires amplitude, frequency and phase of at least one of +% the two polynoms A or B. The j-th component of the kth order polynom on +% the n-th turn is given by: +% amplitude_j*sin[ 2\pi*frequency*(nth_turn*T0 + \tau_p) + phase], +% where T0 is the revolution period of the ideal ring, and \tau_p is the delay +% of the pth particle i.e. the sixth coordinate over the speed of light. Also, +% note that the position of the element on the ring has no effect, the phase +% should be used to add any delay due to the position along s. +% The following is an example of the SINE mode of an skew quad: +% eleskew = atvariablemultipole('VAR_SKEW','SINE', +% 'AmplitudeA',[0,skewa2],'FrequencyA',freqA,'PhaseA',phaseA) +% The values of the sin function could be limited to be above a defined +% threshold using `Sinlimit`. For example, you could create a half-sin +% by setting `Sinlimit` to zero. +% +% The WHITENOISE mode requires the amplitude of either A or B. For example +% elenoise = atvariablemultipole('MYNOISE','WHITENOISE', +% 'AmplitudeA',[noiseA1]) +% creates a gaussian vertical noise of amplitude noiseA1. The gaussian +% distribution is generated with zero-mean and one standard deviation from +% a pseudo-random stream pcg32. The pcg32 seed is fixed by the tracking +% function, therefore using the same stream on all trackings (sequencial or +% parallel). See https://github.com/atcollab/at/discussions/879 for more +% details on the pseudo random stream. Additionally, the user could set +% the mean and std values by setting MeanA, MeanB, StdA, StdB. +% +% The ARBITRARY mode requires the definition of a custom turn-by-turn function. +% The user defines the value of the function and its Taylor expansion with +% respect to \tau up to fourth order. +% value = f(turn) + f'(turn)*tau + 0.5*f''(turn)*tau**2 +% + 1/6*f'''(turn)*tau**3 + 1/24*f''''(turn)*tau**4 +% where f is an array of values, f',f'',f''',f'''', are arrays containing +% the derivatives wrt \tau, and \tau is the time delay of the particle, i.e. +% the the sixth coordinate divided by the speed of light. +% tau could be offset using FuncATimeDelay or FuncBTimeDelay. +% tau -> tau - Func[AB]TimeDelay +% For example, the following is a positive vertical kick in the first turn, +% negative on the second turn, and zero on the third turn. +% funca = [1 -1 0]; +% elesinglekick = at.VariableMultipole('CUSTOMFUNC','ARBITRARY', +% AmplitudeA=1e-4,FuncA=funca,Periodic=True) +% by default the array is assumed periodic. If Periodic is set to False +% any turn exceeding the defined length of the function is assumed to have +% no effect on the beam. +% % Input parser for option [method,rsrc]=getargs(varargin,'VariableThinMPolePass', ... @@ -116,6 +168,10 @@ function setsine(rsrc, ab) if ~isfield(rsrc,strcat('Frequency',ab)) error(strcat('Please provide a value for Frequency',ab)) end + funcarg=strcat('Sinlimit',ab); + if ~isfield(rsrc,funcarg) + rsrc.(funcarg) = -1; + end end function rsrc = setarb(rsrc, ab) @@ -158,12 +214,6 @@ function setsine(rsrc, ab) setsine(rsrc,ab); end if strcmpi(mode,'WHITENOISE') - if ~isfield(rsrc,'Seed') - rsrc.Seed = 1; - end - if ~isfield(rsrc,'Seedinitstate') - rsrc.Seedinitstate = 1; - end rsrc = setwhitenoise(rsrc,ab); end if strcmpi(mode,'ARBITRARY') From 1cd90d83674e919bc22336ef7c46fc4b2b03e0f7 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 17:19:02 +0100 Subject: [PATCH 061/129] use pcg32_global in AT matlab --- atintegrators/VariableThinMPolePass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index cfa5b396c..40e768cf8 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -486,7 +486,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) plhs[0] = mxDuplicateArray(prhs[1]); r_in = mxGetDoubles(plhs[0]); - VariableThinMPolePass(r_in, Elem, 0, 0, num_particles, Param->common_rng); + VariableThinMPolePass(r_in, Elem, 0, 0, num_particles, &pcg32_global); } else if (nrhs == 0) { /* list of required fields */ plhs[0] = mxCreateCellMatrix(4, 1); From 13f1cad36d84441fb54a38956f2cc0b222078c2e Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 18:12:13 +0100 Subject: [PATCH 062/129] black --- pyat/at/lattice/variable_elements.py | 39 +++++++++++++++++++++------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 3d4871c4e..d72f690fc 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -158,7 +158,7 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): for k, v in amp_aux.items(): if v is not None: kwargs["Amplitude" + k] = self._set_amplitude(v) - self._check_mode(mode, k, **kwargs) + kwargs = self._set_mode(mode, k, **kwargs) maxorder = self._getmaxorder(amp_aux["A"], amp_aux["B"]) kwargs["MaxOrder"] = kwargs.get("MaxOrder", maxorder) for key in amp_aux.keys(): @@ -198,32 +198,51 @@ def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): mxb = np.max(np.append(np.nonzero(ampb), 0)) return max(mxa, mxb) - def _check_mode(self, mode, a_b: str, **kwargs: dict[str, any]): + def _set_mode(self, mode, a_b: str, **kwargs: dict[str, any]): if mode == ACMode.WHITENOISE: - if 'Mean' not in kwargs: - kwargs['Mean'] = kwargs.get("Mean", 0) - if 'Std' not in kwargs: - kwargs['Std'] = kwargs.get("Std", 1) + kwargs = self._set_white_noise(a_b, **kwargs) if mode == ACMode.SINE: - self._check_sine(a_b, **kwargs) + kwargs = self._set_sine(a_b, **kwargs) if mode == ACMode.ARBITRARY: self._set_arb(a_b, **kwargs) kwargs["Periodic"] = kwargs.get("Periodic", True) + return kwargs - def _check_sine(self, a_b: str, **kwargs: dict[str, any]): + def _set_white_noise(self, a_b: str, **kwargs: dict[str, any]): + if "Mean" + a_b not in kwargs: + kwargs["Mean" + a_b] = kwargs.get("Mean" + a_b, 0) + if "Std" not in kwargs: + kwargs["Std" + a_b] = kwargs.get("Std" + a_b, 1) + return kwargs + + def _set_sine(self, a_b: str, **kwargs: dict[str, any]): frequency = kwargs.pop("Frequency" + a_b, None) if frequency is None: raise AtError("Please provide a value for Frequency" + a_b) kwargs["Phase" + a_b] = kwargs.get("Phase" + a_b, 0) kwargs["Sinlimit" + a_b] = kwargs.get("Sinlimit" + a_b, -1) + return kwargs def _set_arb(self, a_b: str, **kwargs: dict[str, any]): func = kwargs.pop("Func" + a_b, None) if func is None: raise AtError("Please provide a value for Func" + a_b) nsamp = len(func) - setattr(self, "Func" + a_b, func) - setattr(self, "NSamples" + a_b, nsamp) + kwargs["Func" + a_b] = func + kwargs["Func" + a_b + "deriv1"] = kwargs.get( + "Func" + a_b + "deriv1", np.zeros(nsamp) + ) + kwargs["Func" + a_b + "deriv2"] = kwargs.get( + "Func" + a_b + "deriv2", np.zeros(nsamp) + ) + kwargs["Func" + a_b + "deriv3"] = kwargs.get( + "Func" + a_b + "deriv3", np.zeros(nsamp) + ) + kwargs["Func" + a_b + "deriv4"] = kwargs.get( + "Func" + a_b + "deriv4", np.zeros(nsamp) + ) + kwargs["NSamples" + a_b] = nsamp + return kwargs def _check_ramp(self, **kwargs: dict[str, any]): ramps = kwargs.get("Ramps", None) From 94d583760df6f247fdbba0fb041dc06eb657d7fb Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 18:42:24 +0100 Subject: [PATCH 063/129] get frequency --- pyat/at/lattice/variable_elements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index d72f690fc..eb6403691 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -216,7 +216,7 @@ def _set_white_noise(self, a_b: str, **kwargs: dict[str, any]): return kwargs def _set_sine(self, a_b: str, **kwargs: dict[str, any]): - frequency = kwargs.pop("Frequency" + a_b, None) + frequency = kwargs.get("Frequency" + a_b, None) if frequency is None: raise AtError("Please provide a value for Frequency" + a_b) kwargs["Phase" + a_b] = kwargs.get("Phase" + a_b, 0) From 68ff29ec9f4a621c73f10a6d737f378464f5a5b6 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 19:02:33 +0100 Subject: [PATCH 064/129] fix bug in arbitrary function --- pyat/at/lattice/variable_elements.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index eb6403691..598ff7ea9 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -204,8 +204,7 @@ def _set_mode(self, mode, a_b: str, **kwargs: dict[str, any]): if mode == ACMode.SINE: kwargs = self._set_sine(a_b, **kwargs) if mode == ACMode.ARBITRARY: - self._set_arb(a_b, **kwargs) - kwargs["Periodic"] = kwargs.get("Periodic", True) + kwargs = self._set_arb(a_b, **kwargs) return kwargs def _set_white_noise(self, a_b: str, **kwargs: dict[str, any]): @@ -224,11 +223,10 @@ def _set_sine(self, a_b: str, **kwargs: dict[str, any]): return kwargs def _set_arb(self, a_b: str, **kwargs: dict[str, any]): - func = kwargs.pop("Func" + a_b, None) + func = kwargs.get("Func" + a_b, None) if func is None: raise AtError("Please provide a value for Func" + a_b) nsamp = len(func) - kwargs["Func" + a_b] = func kwargs["Func" + a_b + "deriv1"] = kwargs.get( "Func" + a_b + "deriv1", np.zeros(nsamp) ) @@ -241,7 +239,11 @@ def _set_arb(self, a_b: str, **kwargs: dict[str, any]): kwargs["Func" + a_b + "deriv4"] = kwargs.get( "Func" + a_b + "deriv4", np.zeros(nsamp) ) + kwargs["Func" + a_b + "TimeDelay"] = kwargs.get( + "Func" + a_b + "TimeDelay", 0 + ) kwargs["NSamples" + a_b] = nsamp + kwargs["Periodic"] = kwargs.get("Periodic", True) return kwargs def _check_ramp(self, **kwargs: dict[str, any]): From 0a6e2f56fa5c6a58a3e16aaf00a17ab2e45cd192 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 19:16:02 +0100 Subject: [PATCH 065/129] adding ACMode --- pyat/at/lattice/variable_elements.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 598ff7ea9..7dedd026c 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -8,6 +8,7 @@ from .elements import Element, _array from .utils import AtError +__all__ = ["ACMode","VariableMultipole"] class ACMode(IntEnum): """Class to define the excitation types.""" @@ -59,7 +60,8 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): Keep in mind that this element varies on every turn, therefore, any ring containing a variable element may change after tracking n turns. - There are three different modes implemented: SINE, WHITENOISE and ARBITRARY. + There are three different modes implemented: + SINE = 0, WHITENOISE = 1 and ARBITRARY = 2. The SINE mode requires amplitude, frequency and phase of at least one of the two polynoms A or B. The j-th component of the kth order polynom on the From ed6be2c1db07d81cbdbd8f66d01957cc7bc0f6d2 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 19:16:25 +0100 Subject: [PATCH 066/129] import all from VariableMultipole --- pyat/at/lattice/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyat/at/lattice/__init__.py b/pyat/at/lattice/__init__.py index b0d7bd4b0..cd2ed772f 100644 --- a/pyat/at/lattice/__init__.py +++ b/pyat/at/lattice/__init__.py @@ -17,7 +17,7 @@ from .lattice_object import * # from .lattice_variables import * from .cavity_access import * -from .variable_elements import VariableMultipole +from .variable_elements import * from .deprecated import * # Define the module "lattice.constants" for backward compatibility # noinspection PyUnresolvedReferences From 8f1e7f39e8582ac52f73715d0a1466927f084df7 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 19:41:25 +0100 Subject: [PATCH 067/129] improve help --- atmat/lattice/element_creation/atvariablemultipole.m | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 089d48dd9..21cd7b309 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -42,6 +42,10 @@ % derivative wrt tau % FuncBderiv3 ARBITRARY excitation tbt kick list for PolynomB 3rd % derivative wrt tau +% FuncAderiv4 ARBITRARY excitation tbt kick list for PolynomA 3rd +% derivative wrt tau +% FuncBderiv4 ARBITRARY excitation tbt kick list for PolynomB 3rd +% derivative wrt tau % FuncATimeDelay TimeDelay to generate a small time offset on the % function FUNC. It only has an effect if any of the % derivatives is not zero. @@ -93,7 +97,7 @@ % containing a variable element may change after tracking n turns. % % There are three different modes implemented: -% SINE, WHITENOISE and ARBITRARY. +% SINE = 0, WHITENOISE = 1 and ARBITRARY = 2. % % The SINE mode requires amplitude, frequency and phase of at least one of % the two polynoms A or B. The j-th component of the kth order polynom on @@ -137,8 +141,8 @@ % elesinglekick = at.VariableMultipole('CUSTOMFUNC','ARBITRARY', % AmplitudeA=1e-4,FuncA=funca,Periodic=True) % by default the array is assumed periodic. If Periodic is set to False -% any turn exceeding the defined length of the function is assumed to have -% no effect on the beam. +% it is assumed that the function has no effect on the particle in turns +% exceeding the function definition. % % Input parser for option From 93ba7198087b94d843a5b0aba4028cdbd70d8a6a Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 19:42:04 +0100 Subject: [PATCH 068/129] improve DocSgtring; black --- pyat/at/lattice/variable_elements.py | 70 ++++++++++++++++++---------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 7dedd026c..81489d228 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -8,7 +8,8 @@ from .elements import Element, _array from .utils import AtError -__all__ = ["ACMode","VariableMultipole"] +__all__ = ["ACMode", "VariableMultipole"] + class ACMode(IntEnum): """Class to define the excitation types.""" @@ -52,10 +53,11 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): r""" Create VariableMultipole. - This function creates a thin multipole any order (1 to k) and type (Normal - or Skew) defined by the amplitude A or B components; the polynoms PolynomA - and PolynomB are calculated on every turn depending on the chosen mode, and - for some modes on the particle time delay. All modes could be ramped. + This function creates a thin multipole of any order (1 to k) and type + (Normal or Skew) defined by the amplitude A or B components; the polynoms + PolynomA and PolynomB are calculated on every turn depending on the + chosen mode, and for some modes on the particle time delay. + All modes could be ramped. Keep in mind that this element varies on every turn, therefore, any ring containing a variable element may change after tracking n turns. @@ -63,23 +65,23 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): There are three different modes implemented: SINE = 0, WHITENOISE = 1 and ARBITRARY = 2. - The SINE mode requires amplitude, frequency and phase of at least one of the - two polynoms A or B. The j-th component of the kth order polynom on the - n-th turn is given by: + The SINE mode requires amplitude, frequency and phase of at least one of + the two polynoms A or B. The j-th component of the kth order polynom on + the n-th turn is given by: amplitude_j*sin[ 2\pi*frequency*(nth_turn*T0 + \tau_p) + phase], where T0 is the revolution period of the ideal ring, and \tau_p is the delay of the pth particle i.e. the sixth coordinate over the speed of light. Also, note that the position of the element on the ring has no effect, the phase should be used to add any delay due to the position along s. The following is an example of the SINE mode of an skew quad: - eleskew = at.VariableMultipole('VAR_SKEW',ACMode.SINE, + eleskew = at.VariableMultipole('VAR_SKEW',at.ACMode.SINE, AmplitudeA=[0,skewa2],FrequencyA=freqA,PhaseA=phaseA) The values of the sin function could be limited to be above a defined threshold using `Sinlimit`. For example, you could create a half-sin by setting `Sinlimit` to zero. The WHITENOISE mode requires the amplitude of either A or B. For example - elenoise = at.VariableMultipole('MYNOISE',ACMode.WHITENOISE, + elenoise = at.VariableMultipole('MYNOISE',at.ACMode.WHITENOISE, AmplitudeA=[noiseA1]) creates a gaussian vertical noise of amplitude noiseA1. The gaussian distribution is generated with zero-mean and one standard deviation from @@ -97,14 +99,16 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): where f is an array of values, f',f'',f''',f'''', are arrays containing the derivatives wrt \tau, and \tau is the time delay of the particle, i.e. the the sixth coordinate divided by the speed of light. + tau could be offset using FuncATimeDelay or FuncBTimeDelay. + tau -> tau - Func[AB]TimeDel For example, the following is a positive vertical kick in the first turn, negative on the second turn, and zero on the third turn. - funca = [1 -1 0]; - elesinglekick = at.VariableMultipole('CUSTOMFUNC','ARBITRARY', + funca = [1,-1,0]; + elesinglekick = at.VariableMultipole('CUSTOMFUNC',at.ACMODE.ARBITRARY, AmplitudeA=1e-4,FuncA=funca,Periodic=True) by default the array is assumed periodic. If Periodic is set to False - any turn exceeding the defined length of the function is assumed to have - no effect on the beam. + it is assumed that the function has no effect on the particle in turns + exceeding the function definition. Parameters: @@ -126,8 +130,30 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): SinlimitA or zero. SinlimitB(float): Default -1. Values of the sin function will be above SinlimitB or zero. - FuncA(list): User defined tbt kick list for PolynomA - FuncB(list): User defined tbt kick list for PolynomB + FuncA(list): User defined tbt kick list for PolynomA + FuncB(list): User defined tbt kick list for PolynomB + FuncAderiv1 ARBITRARY excitation tbt kick list for PolynomA 1st + derivative wrt tau + FuncBderiv1 ARBITRARY excitation tbt kick list for PolynomB 1st + derivative wrt tau + FuncAderiv2 ARBITRARY excitation tbt kick list for PolynomA 2nd + derivative wrt tau + FuncBderiv2 ARBITRARY excitation tbt kick list for PolynomB 2nd + derivative wrt tau + FuncAderiv3 ARBITRARY excitation tbt kick list for PolynomA 3rd + derivative wrt tau + FuncBderiv3 ARBITRARY excitation tbt kick list for PolynomB 3rd + derivative wrt tau + FuncAderiv4 ARBITRARY excitation tbt kick list for PolynomA 3rd + derivative wrt tau + FuncBderiv4 ARBITRARY excitation tbt kick list for PolynomB 3rd + derivative wrt tau + FuncATimeDelay TimeDelay to generate a small time offset on the + function FUNC. It only has an effect if any of the + derivatives is not zero. + FuncBTimeDelay TimeDelay to generate a small time offset on the + function FUNC. It only has an effect if any of the + derivatives is not zero. Periodic(bool): If True (default) the user defined kick is repeated Ramps(list): Vector (t0, t1, t2, t3) in turn number to define the ramping of the excitation @@ -146,12 +172,10 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): Examples: - >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.SINE, amplitudeb=amp, frequencyb=frequency) - >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.WHITENOISE, amplitudeb=amp) - >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.ARBITRARY, amplitudeb=amp, funcb=fun) + >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.SINE, AmplitudeB=amp, FrequencyB=frequency) + >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.WHITENOISE, AmplitudeB=amp) + >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.ARBITRARY, AmplitudeB=amp, FuncB=fun) - * For ``mode=ACMode.ARBITRARY`` the ``Func(A,B)`` corresponding to the - ``Amplitude(A,B)`` has to be provided. """ kwargs["Mode"] = kwargs.get("Mode", mode) kwargs.setdefault("PassMethod", "VariableThinMPolePass") @@ -241,9 +265,7 @@ def _set_arb(self, a_b: str, **kwargs: dict[str, any]): kwargs["Func" + a_b + "deriv4"] = kwargs.get( "Func" + a_b + "deriv4", np.zeros(nsamp) ) - kwargs["Func" + a_b + "TimeDelay"] = kwargs.get( - "Func" + a_b + "TimeDelay", 0 - ) + kwargs["Func" + a_b + "TimeDelay"] = kwargs.get("Func" + a_b + "TimeDelay", 0) kwargs["NSamples" + a_b] = nsamp kwargs["Periodic"] = kwargs.get("Periodic", True) return kwargs From 40bf18b108bd494a71ded13351843f40e60af714 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 20:02:59 +0100 Subject: [PATCH 069/129] fixing flake8 --- pyat/at/lattice/variable_elements.py | 60 ++++++++++++++-------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 81489d228..517cf7811 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -1,6 +1,7 @@ +"""VariableMultipole.""" + from __future__ import annotations -from datetime import datetime from enum import IntEnum import numpy as np @@ -50,9 +51,7 @@ class VariableMultipole(Element): ) def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): - r""" - Create VariableMultipole. - + r"""Create VariableMultipole. This function creates a thin multipole of any order (1 to k) and type (Normal or Skew) defined by the amplitude A or B components; the polynoms PolynomA and PolynomB are calculated on every turn depending on the @@ -133,26 +132,26 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): FuncA(list): User defined tbt kick list for PolynomA FuncB(list): User defined tbt kick list for PolynomB FuncAderiv1 ARBITRARY excitation tbt kick list for PolynomA 1st - derivative wrt tau + (list) derivative wrt tau FuncBderiv1 ARBITRARY excitation tbt kick list for PolynomB 1st - derivative wrt tau + (list) derivative wrt tau FuncAderiv2 ARBITRARY excitation tbt kick list for PolynomA 2nd - derivative wrt tau + (list) derivative wrt tau FuncBderiv2 ARBITRARY excitation tbt kick list for PolynomB 2nd - derivative wrt tau + (list) derivative wrt tau FuncAderiv3 ARBITRARY excitation tbt kick list for PolynomA 3rd - derivative wrt tau + (list) derivative wrt tau FuncBderiv3 ARBITRARY excitation tbt kick list for PolynomB 3rd - derivative wrt tau + (list) derivative wrt tau FuncAderiv4 ARBITRARY excitation tbt kick list for PolynomA 3rd - derivative wrt tau + (list) derivative wrt tau FuncBderiv4 ARBITRARY excitation tbt kick list for PolynomB 3rd - derivative wrt tau + (list) derivative wrt tau FuncATimeDelay TimeDelay to generate a small time offset on the - function FUNC. It only has an effect if any of the + (float) function FUNC. It only has an effect if any of the derivatives is not zero. FuncBTimeDelay TimeDelay to generate a small time offset on the - function FUNC. It only has an effect if any of the + (float) function FUNC. It only has an effect if any of the derivatives is not zero. Periodic(bool): If True (default) the user defined kick is repeated Ramps(list): Vector (t0, t1, t2, t3) in turn number to define @@ -181,13 +180,13 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): kwargs.setdefault("PassMethod", "VariableThinMPolePass") if len(kwargs) > 2: amp_aux = self._check_amplitudes(**kwargs) - for k, v in amp_aux.items(): - if v is not None: - kwargs["Amplitude" + k] = self._set_amplitude(v) - kwargs = self._set_mode(mode, k, **kwargs) + for key, value in amp_aux.items(): + if value is not None: + kwargs["Amplitude" + key] = self._set_amplitude(value) + kwargs = self._set_mode(mode, key, **kwargs) maxorder = self._getmaxorder(amp_aux["A"], amp_aux["B"]) kwargs["MaxOrder"] = kwargs.get("MaxOrder", maxorder) - for key in amp_aux.keys(): + for key in amp_aux: kwargs["Polynom" + key] = kwargs.get( "Polynom" + key, np.zeros(maxorder + 1) ) @@ -196,10 +195,10 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): kwargs["Ramps"] = ramps super().__init__(family_name, **kwargs) - def _check_amplitudes(self, **kwargs: dict[str, any]): + def _check_amplitudes(self, **kwargs: dict[str, any]) -> dict[str, any]: amp_aux = {"A": None, "B": None} all_amplitudes_are_none = True - for key in amp_aux.keys(): + for key in amp_aux: if "Amplitude" + key in kwargs and "amplitude" + key in kwargs: raise AtError("Duplicated amplitude " + key + "parameters.") lower_case_kwargs = {k.lower(): v for k, v in kwargs.items()} @@ -210,13 +209,12 @@ def _check_amplitudes(self, **kwargs: dict[str, any]): raise AtError("Please provide at least one amplitude for A or B") return amp_aux - def _set_amplitude(self, amplitude: float or _array or None): + def _set_amplitude(self, amplitude: float or _array or None) -> _array: if np.isscalar(amplitude): amplitude = [amplitude] - amplitude = np.asarray(amplitude) - return amplitude + return np.asarray(amplitude) - def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): + def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray) -> int: mxa, mxb = 0, 0 if ampa is not None: mxa = np.max(np.append(np.nonzero(ampa), 0)) @@ -224,7 +222,9 @@ def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray): mxb = np.max(np.append(np.nonzero(ampb), 0)) return max(mxa, mxb) - def _set_mode(self, mode, a_b: str, **kwargs: dict[str, any]): + def _set_mode( + self, mode: int, a_b: str, **kwargs: dict[str, any] + ) -> dict[str, any]: if mode == ACMode.WHITENOISE: kwargs = self._set_white_noise(a_b, **kwargs) if mode == ACMode.SINE: @@ -233,14 +233,14 @@ def _set_mode(self, mode, a_b: str, **kwargs: dict[str, any]): kwargs = self._set_arb(a_b, **kwargs) return kwargs - def _set_white_noise(self, a_b: str, **kwargs: dict[str, any]): + def _set_white_noise(self, a_b: str, **kwargs: dict[str, any]) -> dict[str, any]: if "Mean" + a_b not in kwargs: kwargs["Mean" + a_b] = kwargs.get("Mean" + a_b, 0) if "Std" not in kwargs: kwargs["Std" + a_b] = kwargs.get("Std" + a_b, 1) return kwargs - def _set_sine(self, a_b: str, **kwargs: dict[str, any]): + def _set_sine(self, a_b: str, **kwargs: dict[str, any]) -> dict[str, any]: frequency = kwargs.get("Frequency" + a_b, None) if frequency is None: raise AtError("Please provide a value for Frequency" + a_b) @@ -248,7 +248,7 @@ def _set_sine(self, a_b: str, **kwargs: dict[str, any]): kwargs["Sinlimit" + a_b] = kwargs.get("Sinlimit" + a_b, -1) return kwargs - def _set_arb(self, a_b: str, **kwargs: dict[str, any]): + def _set_arb(self, a_b: str, **kwargs: dict[str, any]) -> dict[str, any]: func = kwargs.get("Func" + a_b, None) if func is None: raise AtError("Please provide a value for Func" + a_b) @@ -270,7 +270,7 @@ def _set_arb(self, a_b: str, **kwargs: dict[str, any]): kwargs["Periodic"] = kwargs.get("Periodic", True) return kwargs - def _check_ramp(self, **kwargs: dict[str, any]): + def _check_ramp(self, **kwargs: dict[str, any]) -> _array: ramps = kwargs.get("Ramps", None) if ramps is not None: if len(ramps) != 4: From aa00a4fd69ad8c9673aa74b9c33b4bf581572b02 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 19 Dec 2024 20:05:58 +0100 Subject: [PATCH 070/129] flake8 --- pyat/at/lattice/variable_elements.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 517cf7811..3b3793959 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -52,6 +52,7 @@ class VariableMultipole(Element): def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): r"""Create VariableMultipole. + This function creates a thin multipole of any order (1 to k) and type (Normal or Skew) defined by the amplitude A or B components; the polynoms PolynomA and PolynomB are calculated on every turn depending on the From 5f704f79b63dd9b418f5dad7683d77d9f80bad44 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 20 Dec 2024 12:46:56 +0100 Subject: [PATCH 071/129] branchless if --- atintegrators/VariableThinMPolePass.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index 40e768cf8..7347a464a 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -146,9 +146,9 @@ double get_pol( freq = elem->Frequency; ph = elem->Phase; sinval = sin(TWOPI * freq * t + ph); - // branchless if, to get - // the whole sin if whole_sin_limit is -1 or less - // the positive side of sin uf whole_sin_limit is 0. + // branchless if + // sinval >= wholelimit -> sinval + // else -> 0 ampt = ampt*sinval*(sinval >= whole_sin_limit); return ampt; case 1: @@ -239,9 +239,10 @@ void VariableThinMPolePass( }; // offset the time when applying the sin function - if (mode == 0){ - time_in_this_mode = t0 * turn; - } + // branchless if + // mode == 0 -> time_in_this_mode = t0 *turn + // else -> 0 + time_in_this_mode = t0 * turn * (mode == 0); /* cycle over all particles */ for (c = 0; c < num_particles; c++) { From cfb48be4bb57f67ca4ada44463e4a76158d4169a Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 11:03:17 +0100 Subject: [PATCH 072/129] removing mean and std value in white noise --- atintegrators/VariableThinMPolePass.c | 79 ++++++++------------------- 1 file changed, 22 insertions(+), 57 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index 7347a464a..16c4d7b7f 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -49,7 +49,6 @@ struct elemab { double Sinlimit; double Phase; int NSamples; - double Mean, Std; double* Func; double* Funcderiv1; double* Funcderiv2; @@ -67,8 +66,6 @@ struct elem { double* PolynomB; // calculated on every turn int MaxOrder; int Mode; - double MeanA, StdA; // used in white noise mode - double MeanB, StdB; // used in white noise mode double* Ramps; int Periodic; double *R1; @@ -118,17 +115,12 @@ double get_pol( ) { int turnidx; // turn index - double val; // amplitude value double ampt; // amplitude per turn // sin mode parameters double whole_sin_limit = elem->Sinlimit; double freq, ph, sinval; - // random mode parameters - double randmean; - double randstd; - // custom mode parameters double* func; double *funcderiv1, *funcderiv2, *funcderiv3, *funcderiv4; @@ -152,10 +144,7 @@ double get_pol( ampt = ampt*sinval*(sinval >= whole_sin_limit); return ampt; case 1: - randmean = elem->Mean; - randstd = elem->Std; - val = atrandn_r(rng, randmean, randstd); - ampt *= val; + ampt *= atrandn_r(rng, 0, 1); return ampt; case 2: if (periodic || turn < elem->NSamples) { @@ -280,8 +269,6 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, { if (!Elem) { int MaxOrder, Mode, NSamplesA, NSamplesB, Periodic; - double MeanA, StdA; - double MeanB, StdB; double *R1, *R2, *T1, *T2, *EApertures, *RApertures; double *PolynomA, *PolynomB, *AmplitudeA, *AmplitudeB; double *Ramps, *FuncA, *FuncB; @@ -313,10 +300,6 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, SinlimitA=atGetOptionalDouble(ElemData,"SinlimitA", 0); check_error(); SinlimitB=atGetOptionalDouble(ElemData,"SinlimitB", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); - MeanA=atGetOptionalDouble(ElemData, "MeanA", 0); check_error(); - StdA=atGetOptionalDouble(ElemData, "StdA", 0); check_error(); - MeanB=atGetOptionalDouble(ElemData, "MeanB", 0); check_error(); - StdB=atGetOptionalDouble(ElemData, "StdB", 0); check_error(); NSamplesA=atGetOptionalLong(ElemData, "NSamplesA", 1); check_error(); NSamplesB=atGetOptionalLong(ElemData, "NSamplesB", 1); check_error(); FuncA=atGetOptionalDoubleArray(ElemData,"FuncA"); check_error(); @@ -344,10 +327,6 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, Elem->PolynomA = PolynomA; Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; - ElemA->Mean = MeanA; - ElemA->Std = StdA; - ElemB->Mean = MeanB; - ElemB->Std = StdB; Elem->Mode = Mode; Elem->MaxOrder = MaxOrder; Elem->Periodic = Periodic; @@ -395,8 +374,6 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) const mxArray* ElemData = prhs[0]; int num_particles = mxGetN(prhs[1]); int MaxOrder, Mode, NSamplesA, NSamplesB, Periodic; - double MeanA, StdA; - double MeanB, StdB; double *R1, *R2, *T1, *T2, *EApertures, *RApertures; double *PolynomA, *PolynomB, *AmplitudeA, *AmplitudeB; double *Ramps, *FuncA, *FuncB; @@ -430,10 +407,6 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) SinlimitA=atGetOptionalDouble(ElemData,"SinlimitA", 0); check_error(); SinlimitB=atGetOptionalDouble(ElemData,"SinlimitB", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); - MeanA=atGetOptionalDouble(ElemData, "MeanA", 0); check_error(); - StdA=atGetOptionalDouble(ElemData, "StdA", 0); check_error(); - MeanB=atGetOptionalDouble(ElemData, "MeanB", 0); check_error(); - StdB=atGetOptionalDouble(ElemData, "StdB", 0); check_error(); NSamplesA=atGetOptionalLong(ElemData, "NSamplesA", 0); check_error(); NSamplesB=atGetOptionalLong(ElemData, "NSamplesB", 0); check_error(); FuncA=atGetOptionalDoubleArray(ElemData,"FuncA"); check_error(); @@ -452,10 +425,6 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) Elem->PolynomA = PolynomA; Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; - ElemA->Mean = MeanA; - ElemA->Std = StdA; - ElemB->Mean = MeanB; - ElemB->Std = StdB; Elem->Mode = Mode; Elem->MaxOrder = MaxOrder; Elem->Periodic = Periodic; @@ -507,31 +476,27 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) mxSetCell(plhs[1], 6, mxCreateString("SinlimitA")); mxSetCell(plhs[1], 7, mxCreateString("SinlimitB")); mxSetCell(plhs[1], 8, mxCreateString("Ramps")); - mxSetCell(plhs[1], 9, mxCreateString("MeanA")); - mxSetCell(plhs[1], 10, mxCreateString("StdA")); - mxSetCell(plhs[1], 11, mxCreateString("MeanB")); - mxSetCell(plhs[1], 12, mxCreateString("StdB")); - mxSetCell(plhs[1], 13, mxCreateString("FuncA")); - mxSetCell(plhs[1], 14, mxCreateString("FuncB")); - mxSetCell(plhs[1], 15, mxCreateString("FuncAderiv1")); - mxSetCell(plhs[1], 16, mxCreateString("FuncBderiv1")); - mxSetCell(plhs[1], 17, mxCreateString("FuncAderiv2")); - mxSetCell(plhs[1], 18, mxCreateString("FuncBderiv2")); - mxSetCell(plhs[1], 19, mxCreateString("FuncAderiv3")); - mxSetCell(plhs[1], 20, mxCreateString("FuncBderiv3")); - mxSetCell(plhs[1], 21, mxCreateString("FuncAderiv4")); - mxSetCell(plhs[1], 22, mxCreateString("FuncBderiv4")); - mxSetCell(plhs[1], 23, mxCreateString("FuncATimeDelay")); - mxSetCell(plhs[1], 24, mxCreateString("FuncBTimeDelay")); - mxSetCell(plhs[1], 25, mxCreateString("NSamplesA")); - mxSetCell(plhs[1], 26, mxCreateString("NSamplesB")); - mxSetCell(plhs[1], 27, mxCreateString("Periodic")); - mxSetCell(plhs[1], 28,mxCreateString("T1")); - mxSetCell(plhs[1], 29,mxCreateString("T2")); - mxSetCell(plhs[1], 30,mxCreateString("R1")); - mxSetCell(plhs[1], 31,mxCreateString("R2")); - mxSetCell(plhs[1], 32,mxCreateString("RApertures")); - mxSetCell(plhs[1], 33,mxCreateString("EApertures")); + mxSetCell(plhs[1], 9, mxCreateString("FuncA")); + mxSetCell(plhs[1], 10, mxCreateString("FuncB")); + mxSetCell(plhs[1], 11, mxCreateString("FuncAderiv1")); + mxSetCell(plhs[1], 12, mxCreateString("FuncBderiv1")); + mxSetCell(plhs[1], 13, mxCreateString("FuncAderiv2")); + mxSetCell(plhs[1], 14, mxCreateString("FuncBderiv2")); + mxSetCell(plhs[1], 15, mxCreateString("FuncAderiv3")); + mxSetCell(plhs[1], 16, mxCreateString("FuncBderiv3")); + mxSetCell(plhs[1], 17, mxCreateString("FuncAderiv4")); + mxSetCell(plhs[1], 18, mxCreateString("FuncBderiv4")); + mxSetCell(plhs[1], 19, mxCreateString("FuncATimeDelay")); + mxSetCell(plhs[1], 20, mxCreateString("FuncBTimeDelay")); + mxSetCell(plhs[1], 21, mxCreateString("NSamplesA")); + mxSetCell(plhs[1], 22, mxCreateString("NSamplesB")); + mxSetCell(plhs[1], 23, mxCreateString("Periodic")); + mxSetCell(plhs[1], 24,mxCreateString("T1")); + mxSetCell(plhs[1], 25,mxCreateString("T2")); + mxSetCell(plhs[1], 26,mxCreateString("R1")); + mxSetCell(plhs[1], 27,mxCreateString("R2")); + mxSetCell(plhs[1], 28,mxCreateString("RApertures")); + mxSetCell(plhs[1], 29,mxCreateString("EApertures")); } } else { mexErrMsgIdAndTxt("AT:WrongArg", "Needs 0 or 2 arguments"); From 8da79fb5b3d2964443881d4edb976603e474ced3 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 11:04:01 +0100 Subject: [PATCH 073/129] removing mean and std from white noise --- .../element_creation/atvariablemultipole.m | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 21cd7b309..a0fa6e557 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -22,10 +22,6 @@ % PhaseB Phase of SINE excitation for PolynomB % SinlimitA Limit the sin function to be above. Default -1. % SinlimitB Limit the sin function to be above. Default -1. -% MeanA Mean value of the gaussian noise. Default 0. -% StdA Std value of the gaussian noise. Default 1. -% MeanB Mean value of the gaussian noise. Default 0. -% StdB Std value of the gaussian noise. Default 1. % FuncA ARBITRARY excitation turn-by-turn (tbt) kick list for % PolynomA % FuncB ARBITRARY excitation turn-by-turn (tbt) kick list for @@ -122,8 +118,7 @@ % a pseudo-random stream pcg32. The pcg32 seed is fixed by the tracking % function, therefore using the same stream on all trackings (sequencial or % parallel). See https://github.com/atcollab/at/discussions/879 for more -% details on the pseudo random stream. Additionally, the user could set -% the mean and std values by setting MeanA, MeanB, StdA, StdB. +% details on the pseudo random stream. % % The ARBITRARY mode requires the definition of a custom turn-by-turn function. % The user defines the value of the function and its Taylor expansion with @@ -197,35 +192,18 @@ function setsine(rsrc, ab) end end - function rsrc = setwhitenoise(rsrc, ab) - whitenoise_params = {'Mean','Std'}; - whitenoise_defvals = {0,1}; - for idx = 1:length(whitenoise_params) - funcarg=strcat(whitenoise_params{idx},ab); - if ~isfield(rsrc,funcarg) - auxvalue = whitenoise_defvals{idx}; - else - auxvalue = rsrc.(strcat(whitenoise_params{idx},ab)); - end - rsrc.(strcat(whitenoise_params{idx},ab)) = auxvalue; - end - end - function rsrc = setparams(rsrc,mode,ab) amplarg=strcat('Amplitude',ab); if isfield(rsrc,amplarg) if strcmpi(mode,'SINE') setsine(rsrc,ab); end - if strcmpi(mode,'WHITENOISE') - rsrc = setwhitenoise(rsrc,ab); - end if strcmpi(mode,'ARBITRARY') rsrc = setarb(rsrc,ab); if ~isfield(rsrc,'Periodic') rsrc.Periodic = true; end - end + end end end From 5aa0b0eed4fac60e83cf70eb68a1a9d2ec86f5ea Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 11:04:28 +0100 Subject: [PATCH 074/129] removing mean and std from white noise --- pyat/at/lattice/variable_elements.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 3b3793959..c028c662a 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -88,8 +88,7 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): a pseudo-random stream pcg32. The pcg32 seed is fixed by the tracking function, therefore using the same stream on all trackings (sequencial or parallel). See https://github.com/atcollab/at/discussions/879 for more - details on the pseudo random stream. Additionally, the user could set - the mean and std values by setting MeanA, MeanB, StdA, StdB. + details on the pseudo random stream. The ARBITRARY mode requires the definition of a custom turn-by-turn function. The user defines the value of the function and its Taylor expansion with @@ -226,21 +225,12 @@ def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray) -> int: def _set_mode( self, mode: int, a_b: str, **kwargs: dict[str, any] ) -> dict[str, any]: - if mode == ACMode.WHITENOISE: - kwargs = self._set_white_noise(a_b, **kwargs) if mode == ACMode.SINE: kwargs = self._set_sine(a_b, **kwargs) if mode == ACMode.ARBITRARY: kwargs = self._set_arb(a_b, **kwargs) return kwargs - def _set_white_noise(self, a_b: str, **kwargs: dict[str, any]) -> dict[str, any]: - if "Mean" + a_b not in kwargs: - kwargs["Mean" + a_b] = kwargs.get("Mean" + a_b, 0) - if "Std" not in kwargs: - kwargs["Std" + a_b] = kwargs.get("Std" + a_b, 1) - return kwargs - def _set_sine(self, a_b: str, **kwargs: dict[str, any]) -> dict[str, any]: frequency = kwargs.get("Frequency" + a_b, None) if frequency is None: From c631ae87ac2d3643f83e781e61fd4a7ba544b179 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 11:17:10 +0100 Subject: [PATCH 075/129] switch to AtWarning when amplitude is used instead of Amplitude --- pyat/at/lattice/variable_elements.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index c028c662a..e2b4d2cc6 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -7,7 +7,7 @@ import numpy as np from .elements import Element, _array -from .utils import AtError +from .utils import AtError, AtWarning __all__ = ["ACMode", "VariableMultipole"] @@ -199,8 +199,8 @@ def _check_amplitudes(self, **kwargs: dict[str, any]) -> dict[str, any]: amp_aux = {"A": None, "B": None} all_amplitudes_are_none = True for key in amp_aux: - if "Amplitude" + key in kwargs and "amplitude" + key in kwargs: - raise AtError("Duplicated amplitude " + key + "parameters.") + if "amplitude" + key in kwargs: + raise AtWarning("amplitude" + key + " should be Amplitude"+ key +".") lower_case_kwargs = {k.lower(): v for k, v in kwargs.items()} amp_aux[key] = lower_case_kwargs.pop("amplitude" + key.lower(), None) if amp_aux[key] is not None: From 7f5f574b79b83488a3d7ce3d783bce99ae641ce3 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 11:21:52 +0100 Subject: [PATCH 076/129] set default mode --- pyat/at/lattice/variable_elements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index e2b4d2cc6..e23d7aed7 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -176,7 +176,7 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.ARBITRARY, AmplitudeB=amp, FuncB=fun) """ - kwargs["Mode"] = kwargs.get("Mode", mode) + kwargs.setdefault("Mode", mode) kwargs.setdefault("PassMethod", "VariableThinMPolePass") if len(kwargs) > 2: amp_aux = self._check_amplitudes(**kwargs) From 3716abfcad4f0ccb91889f0139890500afa63424 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 11:28:49 +0100 Subject: [PATCH 077/129] removing any; using Any --- pyat/at/lattice/variable_elements.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index e23d7aed7..5446dfe96 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -8,6 +8,7 @@ from .elements import Element, _array from .utils import AtError, AtWarning +from typing import Any __all__ = ["ACMode", "VariableMultipole"] @@ -50,7 +51,7 @@ class VariableMultipole(Element): Periodic=bool, ) - def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): + def __init__(self, family_name: str, mode: int, **kwargs): r"""Create VariableMultipole. This function creates a thin multipole of any order (1 to k) and type @@ -195,7 +196,7 @@ def __init__(self, family_name: str, mode: int, **kwargs: dict[str, any]): kwargs["Ramps"] = ramps super().__init__(family_name, **kwargs) - def _check_amplitudes(self, **kwargs: dict[str, any]) -> dict[str, any]: + def _check_amplitudes(self, **kwargs) -> dict[str, Any]: amp_aux = {"A": None, "B": None} all_amplitudes_are_none = True for key in amp_aux: @@ -223,15 +224,14 @@ def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray) -> int: return max(mxa, mxb) def _set_mode( - self, mode: int, a_b: str, **kwargs: dict[str, any] - ) -> dict[str, any]: + self, mode: int, a_b: str, **kwargs) -> dict[str, Any]: if mode == ACMode.SINE: kwargs = self._set_sine(a_b, **kwargs) if mode == ACMode.ARBITRARY: kwargs = self._set_arb(a_b, **kwargs) return kwargs - def _set_sine(self, a_b: str, **kwargs: dict[str, any]) -> dict[str, any]: + def _set_sine(self, a_b: str, **kwargs) -> dict[str, Any]: frequency = kwargs.get("Frequency" + a_b, None) if frequency is None: raise AtError("Please provide a value for Frequency" + a_b) @@ -239,7 +239,7 @@ def _set_sine(self, a_b: str, **kwargs: dict[str, any]) -> dict[str, any]: kwargs["Sinlimit" + a_b] = kwargs.get("Sinlimit" + a_b, -1) return kwargs - def _set_arb(self, a_b: str, **kwargs: dict[str, any]) -> dict[str, any]: + def _set_arb(self, a_b: str, **kwargs) -> dict[str, Any]: func = kwargs.get("Func" + a_b, None) if func is None: raise AtError("Please provide a value for Func" + a_b) @@ -261,7 +261,7 @@ def _set_arb(self, a_b: str, **kwargs: dict[str, any]) -> dict[str, any]: kwargs["Periodic"] = kwargs.get("Periodic", True) return kwargs - def _check_ramp(self, **kwargs: dict[str, any]) -> _array: + def _check_ramp(self, **kwargs) -> _array: ramps = kwargs.get("Ramps", None) if ramps is not None: if len(ramps) != 4: From 5fecb70e2646e0f06fc62b509b82aaab0ebd2982 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 11:31:27 +0100 Subject: [PATCH 078/129] setdefault Phase, SinLimit --- pyat/at/lattice/variable_elements.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 5446dfe96..1a136f1ea 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -235,8 +235,8 @@ def _set_sine(self, a_b: str, **kwargs) -> dict[str, Any]: frequency = kwargs.get("Frequency" + a_b, None) if frequency is None: raise AtError("Please provide a value for Frequency" + a_b) - kwargs["Phase" + a_b] = kwargs.get("Phase" + a_b, 0) - kwargs["Sinlimit" + a_b] = kwargs.get("Sinlimit" + a_b, -1) + kwargs.setdefault("Phase" + a_b, 0) + kwargs.setdefault("Sinlimit" + a_b, -1) return kwargs def _set_arb(self, a_b: str, **kwargs) -> dict[str, Any]: From d0cb8f0ec82c1d34b210d8ee814bbe840f3749dc Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 11:36:26 +0100 Subject: [PATCH 079/129] remove set amplitude --- pyat/at/lattice/variable_elements.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 1a136f1ea..132da9bfd 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -183,7 +183,7 @@ def __init__(self, family_name: str, mode: int, **kwargs): amp_aux = self._check_amplitudes(**kwargs) for key, value in amp_aux.items(): if value is not None: - kwargs["Amplitude" + key] = self._set_amplitude(value) + kwargs["Amplitude" + key] = value kwargs = self._set_mode(mode, key, **kwargs) maxorder = self._getmaxorder(amp_aux["A"], amp_aux["B"]) kwargs["MaxOrder"] = kwargs.get("MaxOrder", maxorder) @@ -210,11 +210,6 @@ def _check_amplitudes(self, **kwargs) -> dict[str, Any]: raise AtError("Please provide at least one amplitude for A or B") return amp_aux - def _set_amplitude(self, amplitude: float or _array or None) -> _array: - if np.isscalar(amplitude): - amplitude = [amplitude] - return np.asarray(amplitude) - def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray) -> int: mxa, mxb = 0, 0 if ampa is not None: From acfb812ce3ad88d2faf81dd4143fa6c0a4d35704 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 11:49:37 +0100 Subject: [PATCH 080/129] moving functions inside __init__ --- pyat/at/lattice/variable_elements.py | 137 ++++++++++++++------------- 1 file changed, 69 insertions(+), 68 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 132da9bfd..9d2303530 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -177,6 +177,75 @@ def __init__(self, family_name: str, mode: int, **kwargs): >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.ARBITRARY, AmplitudeB=amp, FuncB=fun) """ + def _check_amplitudes(self, **kwargs) -> dict[str, Any]: + amp_aux = {"A": None, "B": None} + all_amplitudes_are_none = True + for key in amp_aux: + if "amplitude" + key in kwargs: + raise AtWarning("amplitude" + key + " should be Amplitude"+ key +".") + lower_case_kwargs = {k.lower(): v for k, v in kwargs.items()} + amp_aux[key] = lower_case_kwargs.pop("amplitude" + key.lower(), None) + if amp_aux[key] is not None: + all_amplitudes_are_none = False + if all_amplitudes_are_none: + raise AtError("Please provide at least one amplitude for A or B") + return amp_aux + + def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray) -> int: + mxa, mxb = 0, 0 + if ampa is not None: + mxa = np.max(np.append(np.nonzero(ampa), 0)) + if ampb is not None: + mxb = np.max(np.append(np.nonzero(ampb), 0)) + return max(mxa, mxb) + + def _set_mode( + self, mode: int, a_b: str, **kwargs) -> dict[str, Any]: + if mode == ACMode.SINE: + kwargs = self._set_sine(a_b, **kwargs) + if mode == ACMode.ARBITRARY: + kwargs = self._set_arb(a_b, **kwargs) + return kwargs + + def _set_sine(self, a_b: str, **kwargs) -> dict[str, Any]: + frequency = kwargs.get("Frequency" + a_b, None) + if frequency is None: + raise AtError("Please provide a value for Frequency" + a_b) + kwargs.setdefault("Phase" + a_b, 0) + kwargs.setdefault("Sinlimit" + a_b, -1) + return kwargs + + def _set_arb(self, a_b: str, **kwargs) -> dict[str, Any]: + func = kwargs.get("Func" + a_b, None) + if func is None: + raise AtError("Please provide a value for Func" + a_b) + nsamp = len(func) + kwargs["Func" + a_b + "deriv1"] = kwargs.get( + "Func" + a_b + "deriv1", np.zeros(nsamp) + ) + kwargs["Func" + a_b + "deriv2"] = kwargs.get( + "Func" + a_b + "deriv2", np.zeros(nsamp) + ) + kwargs["Func" + a_b + "deriv3"] = kwargs.get( + "Func" + a_b + "deriv3", np.zeros(nsamp) + ) + kwargs["Func" + a_b + "deriv4"] = kwargs.get( + "Func" + a_b + "deriv4", np.zeros(nsamp) + ) + kwargs["Func" + a_b + "TimeDelay"] = kwargs.get("Func" + a_b + "TimeDelay", 0) + kwargs["NSamples" + a_b] = nsamp + kwargs["Periodic"] = kwargs.get("Periodic", True) + return kwargs + + def _check_ramp(self, **kwargs) -> _array: + ramps = kwargs.get("Ramps", None) + if ramps is not None: + if len(ramps) != 4: + raise AtError("Ramps has to be a vector with 4 elements") + ramps = np.asarray(ramps) + return ramps + + # init begins kwargs.setdefault("Mode", mode) kwargs.setdefault("PassMethod", "VariableThinMPolePass") if len(kwargs) > 2: @@ -195,71 +264,3 @@ def __init__(self, family_name: str, mode: int, **kwargs): if ramps is not None: kwargs["Ramps"] = ramps super().__init__(family_name, **kwargs) - - def _check_amplitudes(self, **kwargs) -> dict[str, Any]: - amp_aux = {"A": None, "B": None} - all_amplitudes_are_none = True - for key in amp_aux: - if "amplitude" + key in kwargs: - raise AtWarning("amplitude" + key + " should be Amplitude"+ key +".") - lower_case_kwargs = {k.lower(): v for k, v in kwargs.items()} - amp_aux[key] = lower_case_kwargs.pop("amplitude" + key.lower(), None) - if amp_aux[key] is not None: - all_amplitudes_are_none = False - if all_amplitudes_are_none: - raise AtError("Please provide at least one amplitude for A or B") - return amp_aux - - def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray) -> int: - mxa, mxb = 0, 0 - if ampa is not None: - mxa = np.max(np.append(np.nonzero(ampa), 0)) - if ampb is not None: - mxb = np.max(np.append(np.nonzero(ampb), 0)) - return max(mxa, mxb) - - def _set_mode( - self, mode: int, a_b: str, **kwargs) -> dict[str, Any]: - if mode == ACMode.SINE: - kwargs = self._set_sine(a_b, **kwargs) - if mode == ACMode.ARBITRARY: - kwargs = self._set_arb(a_b, **kwargs) - return kwargs - - def _set_sine(self, a_b: str, **kwargs) -> dict[str, Any]: - frequency = kwargs.get("Frequency" + a_b, None) - if frequency is None: - raise AtError("Please provide a value for Frequency" + a_b) - kwargs.setdefault("Phase" + a_b, 0) - kwargs.setdefault("Sinlimit" + a_b, -1) - return kwargs - - def _set_arb(self, a_b: str, **kwargs) -> dict[str, Any]: - func = kwargs.get("Func" + a_b, None) - if func is None: - raise AtError("Please provide a value for Func" + a_b) - nsamp = len(func) - kwargs["Func" + a_b + "deriv1"] = kwargs.get( - "Func" + a_b + "deriv1", np.zeros(nsamp) - ) - kwargs["Func" + a_b + "deriv2"] = kwargs.get( - "Func" + a_b + "deriv2", np.zeros(nsamp) - ) - kwargs["Func" + a_b + "deriv3"] = kwargs.get( - "Func" + a_b + "deriv3", np.zeros(nsamp) - ) - kwargs["Func" + a_b + "deriv4"] = kwargs.get( - "Func" + a_b + "deriv4", np.zeros(nsamp) - ) - kwargs["Func" + a_b + "TimeDelay"] = kwargs.get("Func" + a_b + "TimeDelay", 0) - kwargs["NSamples" + a_b] = nsamp - kwargs["Periodic"] = kwargs.get("Periodic", True) - return kwargs - - def _check_ramp(self, **kwargs) -> _array: - ramps = kwargs.get("Ramps", None) - if ramps is not None: - if len(ramps) != 4: - raise AtError("Ramps has to be a vector with 4 elements") - ramps = np.asarray(ramps) - return ramps From 1fbfcfbead223e3d52621a49dcae777b9c265fa0 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 12:10:04 +0100 Subject: [PATCH 081/129] black --- pyat/at/lattice/variable_elements.py | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 9d2303530..20f7f6ee8 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -177,12 +177,15 @@ def __init__(self, family_name: str, mode: int, **kwargs): >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.ARBITRARY, AmplitudeB=amp, FuncB=fun) """ + def _check_amplitudes(self, **kwargs) -> dict[str, Any]: amp_aux = {"A": None, "B": None} all_amplitudes_are_none = True for key in amp_aux: if "amplitude" + key in kwargs: - raise AtWarning("amplitude" + key + " should be Amplitude"+ key +".") + raise AtWarning( + "amplitude" + key + " should be Amplitude" + key + "." + ) lower_case_kwargs = {k.lower(): v for k, v in kwargs.items()} amp_aux[key] = lower_case_kwargs.pop("amplitude" + key.lower(), None) if amp_aux[key] is not None: @@ -199,8 +202,7 @@ def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray) -> int: mxb = np.max(np.append(np.nonzero(ampb), 0)) return max(mxa, mxb) - def _set_mode( - self, mode: int, a_b: str, **kwargs) -> dict[str, Any]: + def _set_mode(self, mode: int, a_b: str, **kwargs) -> dict[str, Any]: if mode == ACMode.SINE: kwargs = self._set_sine(a_b, **kwargs) if mode == ACMode.ARBITRARY: @@ -220,21 +222,13 @@ def _set_arb(self, a_b: str, **kwargs) -> dict[str, Any]: if func is None: raise AtError("Please provide a value for Func" + a_b) nsamp = len(func) - kwargs["Func" + a_b + "deriv1"] = kwargs.get( - "Func" + a_b + "deriv1", np.zeros(nsamp) - ) - kwargs["Func" + a_b + "deriv2"] = kwargs.get( - "Func" + a_b + "deriv2", np.zeros(nsamp) - ) - kwargs["Func" + a_b + "deriv3"] = kwargs.get( - "Func" + a_b + "deriv3", np.zeros(nsamp) - ) - kwargs["Func" + a_b + "deriv4"] = kwargs.get( - "Func" + a_b + "deriv4", np.zeros(nsamp) - ) - kwargs["Func" + a_b + "TimeDelay"] = kwargs.get("Func" + a_b + "TimeDelay", 0) + kwargs.setdefault("Func" + a_b + "deriv1", np.zeros(nsamp)) + kwargs.setdefault("Func" + a_b + "deriv2", np.zeros(nsamp)) + kwargs.setdefault("Func" + a_b + "deriv3", np.zeros(nsamp)) + kwargs.setdefault("Func" + a_b + "deriv4", np.zeros(nsamp)) + kwargs.setdefault("Func" + a_b + "TimeDelay", 0) kwargs["NSamples" + a_b] = nsamp - kwargs["Periodic"] = kwargs.get("Periodic", True) + kwargs.setdefault("Periodic", True) return kwargs def _check_ramp(self, **kwargs) -> _array: From b47392dc5b40e2386121739fa25898b1e12a802f Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 12:12:51 +0100 Subject: [PATCH 082/129] isort --- pyat/at/lattice/variable_elements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 20f7f6ee8..195ec47c8 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -3,12 +3,12 @@ from __future__ import annotations from enum import IntEnum +from typing import Any import numpy as np from .elements import Element, _array from .utils import AtError, AtWarning -from typing import Any __all__ = ["ACMode", "VariableMultipole"] From 956d32e6ffe15a1cd525076b02fc5e4a26dd8ac9 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 14:39:43 +0100 Subject: [PATCH 083/129] change Sinlimit to Sinabove --- atintegrators/VariableThinMPolePass.c | 36 +++++++++++++-------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index 16c4d7b7f..fe6f4bd60 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -19,8 +19,8 @@ the delay time. In mode 0, the sin function could be limited to be between any value above - `Sinlimit`. For example a half-sin function would be obtained by setting - `Sinlimit` to zero. + `Sinabove`. For example a half-sin function would be obtained by setting + `Sinabove` to zero. In mode 1 the stream of pseudo-random values is taken from the parameters structure in attypes.h. For more details about the random @@ -46,7 +46,7 @@ struct elemab { double* Amplitude; double Frequency; - double Sinlimit; + double Sinabove; double Phase; int NSamples; double* Func; @@ -118,7 +118,7 @@ double get_pol( double ampt; // amplitude per turn // sin mode parameters - double whole_sin_limit = elem->Sinlimit; + double whole_sin_above = elem->Sinabove; double freq, ph, sinval; // custom mode parameters @@ -139,9 +139,9 @@ double get_pol( ph = elem->Phase; sinval = sin(TWOPI * freq * t + ph); // branchless if - // sinval >= wholelimit -> sinval + // sinval >= wholeabove -> sinval // else -> 0 - ampt = ampt*sinval*(sinval >= whole_sin_limit); + ampt = ampt*sinval*(sinval >= whole_sin_above); return ampt; case 1: ampt *= atrandn_r(rng, 0, 1); @@ -279,7 +279,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, double FuncATimeDelay, FuncBTimeDelay; double FrequencyA, FrequencyB; double PhaseA, PhaseB; - double SinlimitA, SinlimitB; + double SinaboveA, SinaboveB; struct elemab *ElemA, *ElemB; R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); @@ -297,8 +297,8 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, FrequencyB=atGetOptionalDouble(ElemData,"FrequencyB", 0); check_error(); PhaseA=atGetOptionalDouble(ElemData,"PhaseA", 0); check_error(); PhaseB=atGetOptionalDouble(ElemData,"PhaseB", 0); check_error(); - SinlimitA=atGetOptionalDouble(ElemData,"SinlimitA", 0); check_error(); - SinlimitB=atGetOptionalDouble(ElemData,"SinlimitB", 0); check_error(); + SinaboveA=atGetOptionalDouble(ElemData,"SinaboveA", 0); check_error(); + SinaboveB=atGetOptionalDouble(ElemData,"SinaboveB", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); NSamplesA=atGetOptionalLong(ElemData, "NSamplesA", 1); check_error(); NSamplesB=atGetOptionalLong(ElemData, "NSamplesB", 1); check_error(); @@ -336,8 +336,8 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, ElemB->Frequency = FrequencyB; ElemA->Phase = PhaseA; ElemB->Phase = PhaseB; - ElemA->Sinlimit = SinlimitA; - ElemB->Sinlimit = SinlimitB; + ElemA->Sinabove = SinaboveA; + ElemB->Sinabove = SinaboveB; ElemA->NSamples = NSamplesA; ElemB->NSamples = NSamplesB; ElemA->Func = FuncA; @@ -384,7 +384,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) double FuncATimeDelay, FuncBTimeDelay; double FrequencyA, FrequencyB; double PhaseA, PhaseB; - double SinlimitA, SinlimitB; + double SinaboveA, SinaboveB; struct elemab ElA, *ElemA = &ElA; struct elemab ElB, *ElemB = &ElB; struct elem El, *Elem = &El; @@ -404,8 +404,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) FrequencyB=atGetOptionalDouble(ElemData,"FrequencyB", 0); check_error(); PhaseA=atGetOptionalDouble(ElemData,"PhaseA", 0); check_error(); PhaseB=atGetOptionalDouble(ElemData,"PhaseB", 0); check_error(); - SinlimitA=atGetOptionalDouble(ElemData,"SinlimitA", 0); check_error(); - SinlimitB=atGetOptionalDouble(ElemData,"SinlimitB", 0); check_error(); + SinaboveA=atGetOptionalDouble(ElemData,"SinaboveA", 0); check_error(); + SinaboveB=atGetOptionalDouble(ElemData,"SinaboveB", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); NSamplesA=atGetOptionalLong(ElemData, "NSamplesA", 0); check_error(); NSamplesB=atGetOptionalLong(ElemData, "NSamplesB", 0); check_error(); @@ -434,8 +434,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) ElemB->Frequency = FrequencyB; ElemA->Phase = PhaseA; ElemB->Phase = PhaseB; - ElemA->Sinlimit = SinlimitA; - ElemB->Sinlimit = SinlimitB; + ElemA->Sinabove = SinaboveA; + ElemB->Sinabove = SinaboveB; ElemA->NSamples = NSamplesA; ElemB->NSamples = NSamplesB; ElemA->Func = FuncA; @@ -473,8 +473,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) mxSetCell(plhs[1], 3, mxCreateString("FrequencyB")); mxSetCell(plhs[1], 4, mxCreateString("PhaseA")); mxSetCell(plhs[1], 5, mxCreateString("PhaseB")); - mxSetCell(plhs[1], 6, mxCreateString("SinlimitA")); - mxSetCell(plhs[1], 7, mxCreateString("SinlimitB")); + mxSetCell(plhs[1], 6, mxCreateString("SinaboveA")); + mxSetCell(plhs[1], 7, mxCreateString("SinaboveB")); mxSetCell(plhs[1], 8, mxCreateString("Ramps")); mxSetCell(plhs[1], 9, mxCreateString("FuncA")); mxSetCell(plhs[1], 10, mxCreateString("FuncB")); From 8b64d114d58523bfe5af534c645dad14de756cd1 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 14:40:19 +0100 Subject: [PATCH 084/129] changes Sinlimit to Sinabove --- atmat/lattice/element_creation/atvariablemultipole.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index a0fa6e557..4cf2f1ecd 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -20,8 +20,8 @@ % FrequencyB Frequency of SINE excitation for PolynomB % PhaseA Phase of SINE excitation for PolynomA % PhaseB Phase of SINE excitation for PolynomB -% SinlimitA Limit the sin function to be above. Default -1. -% SinlimitB Limit the sin function to be above. Default -1. +% SinaboveA Limit the sin function to be above. Default -1. +% SinaboveB Limit the sin function to be above. Default -1. % FuncA ARBITRARY excitation turn-by-turn (tbt) kick list for % PolynomA % FuncB ARBITRARY excitation turn-by-turn (tbt) kick list for @@ -107,8 +107,8 @@ % eleskew = atvariablemultipole('VAR_SKEW','SINE', % 'AmplitudeA',[0,skewa2],'FrequencyA',freqA,'PhaseA',phaseA) % The values of the sin function could be limited to be above a defined -% threshold using `Sinlimit`. For example, you could create a half-sin -% by setting `Sinlimit` to zero. +% threshold using ``Sinabove``. For example, you could create a half-sin +% by setting ``Sinabove`` to zero. % % The WHITENOISE mode requires the amplitude of either A or B. For example % elenoise = atvariablemultipole('MYNOISE','WHITENOISE', @@ -167,7 +167,7 @@ function setsine(rsrc, ab) if ~isfield(rsrc,strcat('Frequency',ab)) error(strcat('Please provide a value for Frequency',ab)) end - funcarg=strcat('Sinlimit',ab); + funcarg=strcat('Sinabove',ab); if ~isfield(rsrc,funcarg) rsrc.(funcarg) = -1; end From e10b71cdea6b1004e4a3a600109bf0d5a3a510be Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 14:41:01 +0100 Subject: [PATCH 085/129] changes Sinlimit to Sinabove; fixes docstring --- pyat/at/lattice/variable_elements.py | 53 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 195ec47c8..bb3c154a1 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -14,7 +14,7 @@ class ACMode(IntEnum): - """Class to define the excitation types.""" + """Class to define the VariableMultipole excitation mode.""" SINE = 0 WHITENOISE = 1 @@ -22,7 +22,7 @@ class ACMode(IntEnum): class VariableMultipole(Element): - """Class to generate an AT variable thin multipole element.""" + """Turn by turn variable thin multipole.""" _BUILD_ATTRIBUTES = Element._BUILD_ATTRIBUTES + ["Mode"] _conversions = dict( @@ -33,8 +33,8 @@ class VariableMultipole(Element): FrequencyB=float, PhaseA=float, PhaseB=float, - SinlimitA=float, - SinlimitB=float, + SinaboveA=float, + SinaboveB=float, NsamplesA=int, NsamplesB=int, FuncA=_array, @@ -52,34 +52,35 @@ class VariableMultipole(Element): ) def __init__(self, family_name: str, mode: int, **kwargs): - r"""Create VariableMultipole. + r"""VariableMultipole initialization. - This function creates a thin multipole of any order (1 to k) and type - (Normal or Skew) defined by the amplitude A or B components; the polynoms - PolynomA and PolynomB are calculated on every turn depending on the - chosen mode, and for some modes on the particle time delay. - All modes could be ramped. + This Class creates a thin multipole of any order (dipole kick, quadrupole, + sextupole, etc.) and type (Normal or Skew) defined by AmplitudeA and/or + AmplitudeB components; the polynoms PolynomA and PolynomB are calculated + on every turn depending on the chosen mode, and for some modes on the + particle time delay. All modes could be ramped. - Keep in mind that this element varies on every turn, therefore, any ring - containing a variable element may change after tracking n turns. + Keep in mind that as this element varies on every turn, any ring + containing a VariableMultipole may change after tracking. - There are three different modes implemented: - SINE = 0, WHITENOISE = 1 and ARBITRARY = 2. + There are three different modes that could be set: + SINE = 0, WHITENOISE = 1 and ARBITRARY = 2. See ACMode. - The SINE mode requires amplitude, frequency and phase of at least one of - the two polynoms A or B. The j-th component of the kth order polynom on - the n-th turn is given by: - amplitude_j*sin[ 2\pi*frequency*(nth_turn*T0 + \tau_p) + phase], + The **SINE** mode requires amplitude, frequency and phase for A and/or B. + The value of the jth component of the polynom (A or B) at the nth turn + is given by + Amplitude[j]*sin[TWOPI*frequency*(n*T0 + \tau_p) + phase], where T0 is the revolution period of the ideal ring, and \tau_p is the delay of the pth particle i.e. the sixth coordinate over the speed of light. Also, note that the position of the element on the ring has no effect, the phase - should be used to add any delay due to the position along s. - The following is an example of the SINE mode of an skew quad: + could be used to add any delay due to the position along s. + + The following is an example of the SINE mode of an skew quad eleskew = at.VariableMultipole('VAR_SKEW',at.ACMode.SINE, AmplitudeA=[0,skewa2],FrequencyA=freqA,PhaseA=phaseA) The values of the sin function could be limited to be above a defined - threshold using `Sinlimit`. For example, you could create a half-sin - by setting `Sinlimit` to zero. + threshold using `Sinabove`. For example, you could create a half-sin + by setting `Sinabove` to zero. The WHITENOISE mode requires the amplitude of either A or B. For example elenoise = at.VariableMultipole('MYNOISE',at.ACMode.WHITENOISE, @@ -126,10 +127,8 @@ def __init__(self, family_name: str, mode: int, **kwargs): FrequencyB(float): Frequency of the sine excitation for PolynomB PhaseA(float): Phase of the sine excitation for PolynomA. Default 0 rad PhaseB(float): Phase of the sine excitation for PolynomB. Default 0 rad - SinlimitA(float): Default -1. Values of the sin function will be above - SinlimitA or zero. - SinlimitB(float): Default -1. Values of the sin function will be above - SinlimitB or zero. + SinaboveA(float): Default -1. + SinaboveB(float): Default -1. FuncA(list): User defined tbt kick list for PolynomA FuncB(list): User defined tbt kick list for PolynomB FuncAderiv1 ARBITRARY excitation tbt kick list for PolynomA 1st @@ -214,7 +213,7 @@ def _set_sine(self, a_b: str, **kwargs) -> dict[str, Any]: if frequency is None: raise AtError("Please provide a value for Frequency" + a_b) kwargs.setdefault("Phase" + a_b, 0) - kwargs.setdefault("Sinlimit" + a_b, -1) + kwargs.setdefault("Sinabove" + a_b, -1) return kwargs def _set_arb(self, a_b: str, **kwargs) -> dict[str, Any]: From eabf92ece50113c9bf3920de9d863cf031bba8ce Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 15:15:39 +0100 Subject: [PATCH 086/129] improve docstring --- pyat/at/lattice/variable_elements.py | 39 ++++++++++++++-------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index bb3c154a1..a213836a3 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -14,7 +14,7 @@ class ACMode(IntEnum): - """Class to define the VariableMultipole excitation mode.""" + """Class to define the ``VariableMultipole`` excitation mode.""" SINE = 0 WHITENOISE = 1 @@ -73,41 +73,40 @@ def __init__(self, family_name: str, mode: int, **kwargs): where T0 is the revolution period of the ideal ring, and \tau_p is the delay of the pth particle i.e. the sixth coordinate over the speed of light. Also, note that the position of the element on the ring has no effect, the phase - could be used to add any delay due to the position along s. - - The following is an example of the SINE mode of an skew quad + could be used to add any delay due to the position along s. The following is + an example of the SINE mode of an skew quad eleskew = at.VariableMultipole('VAR_SKEW',at.ACMode.SINE, AmplitudeA=[0,skewa2],FrequencyA=freqA,PhaseA=phaseA) The values of the sin function could be limited to be above a defined - threshold using `Sinabove`. For example, you could create a half-sin - by setting `Sinabove` to zero. + threshold using ``Sinabove``. For example, you could create a half-sin + by setting ``Sinabove`` to zero. - The WHITENOISE mode requires the amplitude of either A or B. For example - elenoise = at.VariableMultipole('MYNOISE',at.ACMode.WHITENOISE, - AmplitudeA=[noiseA1]) - creates a gaussian vertical noise of amplitude noiseA1. The gaussian + The **WHITENOISE** mode requires the amplitude of A and/or B. The gaussian distribution is generated with zero-mean and one standard deviation from a pseudo-random stream pcg32. The pcg32 seed is fixed by the tracking function, therefore using the same stream on all trackings (sequencial or parallel). See https://github.com/atcollab/at/discussions/879 for more - details on the pseudo random stream. + details on the pseudo random stream. For example + elenoise = at.VariableMultipole('MYNOISE',at.ACMode.WHITENOISE, + AmplitudeA=[noiseA1]) + creates a vertical kick as gaussian noise of amplitude noiseA1. - The ARBITRARY mode requires the definition of a custom turn-by-turn function. - The user defines the value of the function and its Taylor expansion with - respect to \tau up to fourth order. + The **ARBITRARY** mode requires the definition of a custom discrete function + to be sampled at every turn. The function and its Taylor expansion with + respect to \tau up to fourth order is used to calculate a value value = f(turn) + f'(turn)*tau + 0.5*f''(turn)*tau**2 + 1/6*f'''(turn)*tau**3 + 1/24*f''''(turn)*tau**4 - where f is an array of values, f',f'',f''',f'''', are arrays containing + f is an array of values, f',f'',f''',f'''', are arrays containing the derivatives wrt \tau, and \tau is the time delay of the particle, i.e. the the sixth coordinate divided by the speed of light. - tau could be offset using FuncATimeDelay or FuncBTimeDelay. - tau -> tau - Func[AB]TimeDel + tau could be offset using ``FuncATimeDelay`` or ``FuncBTimeDelay``. + tau = tau - Func[AB]TimeDelay + The function value is then multiplied by amplitude A and/or B. For example, the following is a positive vertical kick in the first turn, negative on the second turn, and zero on the third turn. - funca = [1,-1,0]; elesinglekick = at.VariableMultipole('CUSTOMFUNC',at.ACMODE.ARBITRARY, - AmplitudeA=1e-4,FuncA=funca,Periodic=True) - by default the array is assumed periodic. If Periodic is set to False + AmplitudeA=1e-4,FuncA=[1,-1,0],Periodic=True) + By default the array is assumed periodic. If ``Periodic`` is set to False it is assumed that the function has no effect on the particle in turns exceeding the function definition. From 19e056017a1fbbaa5a347726f6b1419df3beb06f Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 15:19:08 +0100 Subject: [PATCH 087/129] improve docstring --- pyat/at/lattice/variable_elements.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index a213836a3..17dce6232 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -113,7 +113,8 @@ def __init__(self, family_name: str, mode: int, **kwargs): Parameters: family_name(str): Element name - mode(ACMode): defines the evaluation grid. Default ACMode.SINE + mode(ACMode): defines the mode. Default ACMode.SINE: + * :py:attr:`.ACMode.SINE`: sine function * :py:attr:`.ACMode.WHITENOISE`: gaussian white noise * :py:attr:`.ACMode.ARBITRARY`: user defined turn-by-turn kick list From 2b637d3141e3b730eb9450a53023c10ded74459a Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 15:25:33 +0100 Subject: [PATCH 088/129] Changes Sinabove to SinAabove and SinBabove --- atintegrators/VariableThinMPolePass.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index fe6f4bd60..aee4d046f 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -279,7 +279,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, double FuncATimeDelay, FuncBTimeDelay; double FrequencyA, FrequencyB; double PhaseA, PhaseB; - double SinaboveA, SinaboveB; + double SinAabove, SinBabove; struct elemab *ElemA, *ElemB; R1=atGetOptionalDoubleArray(ElemData,"R1"); check_error(); R2=atGetOptionalDoubleArray(ElemData,"R2"); check_error(); @@ -297,8 +297,8 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, FrequencyB=atGetOptionalDouble(ElemData,"FrequencyB", 0); check_error(); PhaseA=atGetOptionalDouble(ElemData,"PhaseA", 0); check_error(); PhaseB=atGetOptionalDouble(ElemData,"PhaseB", 0); check_error(); - SinaboveA=atGetOptionalDouble(ElemData,"SinaboveA", 0); check_error(); - SinaboveB=atGetOptionalDouble(ElemData,"SinaboveB", 0); check_error(); + SinAabove=atGetOptionalDouble(ElemData,"SinAabove", 0); check_error(); + SinBabove=atGetOptionalDouble(ElemData,"SinBabove", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); NSamplesA=atGetOptionalLong(ElemData, "NSamplesA", 1); check_error(); NSamplesB=atGetOptionalLong(ElemData, "NSamplesB", 1); check_error(); @@ -336,8 +336,8 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, ElemB->Frequency = FrequencyB; ElemA->Phase = PhaseA; ElemB->Phase = PhaseB; - ElemA->Sinabove = SinaboveA; - ElemB->Sinabove = SinaboveB; + ElemA->Sinabove = SinAabove; + ElemB->Sinabove = SinBabove; ElemA->NSamples = NSamplesA; ElemB->NSamples = NSamplesB; ElemA->Func = FuncA; @@ -384,7 +384,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) double FuncATimeDelay, FuncBTimeDelay; double FrequencyA, FrequencyB; double PhaseA, PhaseB; - double SinaboveA, SinaboveB; + double SinAabove, SinBabove; struct elemab ElA, *ElemA = &ElA; struct elemab ElB, *ElemB = &ElB; struct elem El, *Elem = &El; @@ -404,8 +404,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) FrequencyB=atGetOptionalDouble(ElemData,"FrequencyB", 0); check_error(); PhaseA=atGetOptionalDouble(ElemData,"PhaseA", 0); check_error(); PhaseB=atGetOptionalDouble(ElemData,"PhaseB", 0); check_error(); - SinaboveA=atGetOptionalDouble(ElemData,"SinaboveA", 0); check_error(); - SinaboveB=atGetOptionalDouble(ElemData,"SinaboveB", 0); check_error(); + SinAabove=atGetOptionalDouble(ElemData,"SinAabove", 0); check_error(); + SinBabove=atGetOptionalDouble(ElemData,"SinBabove", 0); check_error(); Ramps=atGetOptionalDoubleArray(ElemData, "Ramps"); check_error(); NSamplesA=atGetOptionalLong(ElemData, "NSamplesA", 0); check_error(); NSamplesB=atGetOptionalLong(ElemData, "NSamplesB", 0); check_error(); @@ -434,8 +434,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) ElemB->Frequency = FrequencyB; ElemA->Phase = PhaseA; ElemB->Phase = PhaseB; - ElemA->Sinabove = SinaboveA; - ElemB->Sinabove = SinaboveB; + ElemA->Sinabove = SinAabove; + ElemB->Sinabove = SinBabove; ElemA->NSamples = NSamplesA; ElemB->NSamples = NSamplesB; ElemA->Func = FuncA; @@ -473,8 +473,8 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) mxSetCell(plhs[1], 3, mxCreateString("FrequencyB")); mxSetCell(plhs[1], 4, mxCreateString("PhaseA")); mxSetCell(plhs[1], 5, mxCreateString("PhaseB")); - mxSetCell(plhs[1], 6, mxCreateString("SinaboveA")); - mxSetCell(plhs[1], 7, mxCreateString("SinaboveB")); + mxSetCell(plhs[1], 6, mxCreateString("SinAabove")); + mxSetCell(plhs[1], 7, mxCreateString("SinBabove")); mxSetCell(plhs[1], 8, mxCreateString("Ramps")); mxSetCell(plhs[1], 9, mxCreateString("FuncA")); mxSetCell(plhs[1], 10, mxCreateString("FuncB")); From 8a6a26610a43d964b00e5af785603e0b30369b6a Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 15:26:11 +0100 Subject: [PATCH 089/129] changes Sinabove to SinAabove and SinBabove --- atmat/lattice/element_creation/atvariablemultipole.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 4cf2f1ecd..2427cc2eb 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -20,8 +20,8 @@ % FrequencyB Frequency of SINE excitation for PolynomB % PhaseA Phase of SINE excitation for PolynomA % PhaseB Phase of SINE excitation for PolynomB -% SinaboveA Limit the sin function to be above. Default -1. -% SinaboveB Limit the sin function to be above. Default -1. +% SinAabove Limit the sin function to be above. Default -1. +% SinBabove Limit the sin function to be above. Default -1. % FuncA ARBITRARY excitation turn-by-turn (tbt) kick list for % PolynomA % FuncB ARBITRARY excitation turn-by-turn (tbt) kick list for @@ -107,8 +107,8 @@ % eleskew = atvariablemultipole('VAR_SKEW','SINE', % 'AmplitudeA',[0,skewa2],'FrequencyA',freqA,'PhaseA',phaseA) % The values of the sin function could be limited to be above a defined -% threshold using ``Sinabove``. For example, you could create a half-sin -% by setting ``Sinabove`` to zero. +% threshold using ``Sin[AB]above``. For example, you could create a half-sin +% by setting ``Sin[AB]above`` to zero. % % The WHITENOISE mode requires the amplitude of either A or B. For example % elenoise = atvariablemultipole('MYNOISE','WHITENOISE', @@ -167,7 +167,7 @@ function setsine(rsrc, ab) if ~isfield(rsrc,strcat('Frequency',ab)) error(strcat('Please provide a value for Frequency',ab)) end - funcarg=strcat('Sinabove',ab); + funcarg=strcat('Sin',ab,'above'); if ~isfield(rsrc,funcarg) rsrc.(funcarg) = -1; end From d4a2e6659c1bcabaf90b390b03e776f6186d0793 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 15:26:50 +0100 Subject: [PATCH 090/129] changes Sinabove by SinAabove and SinBabove --- pyat/at/lattice/variable_elements.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 17dce6232..3d749efcc 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -33,8 +33,8 @@ class VariableMultipole(Element): FrequencyB=float, PhaseA=float, PhaseB=float, - SinaboveA=float, - SinaboveB=float, + SinAabove=float, + SinBabove=float, NsamplesA=int, NsamplesB=int, FuncA=_array, @@ -78,8 +78,8 @@ def __init__(self, family_name: str, mode: int, **kwargs): eleskew = at.VariableMultipole('VAR_SKEW',at.ACMode.SINE, AmplitudeA=[0,skewa2],FrequencyA=freqA,PhaseA=phaseA) The values of the sin function could be limited to be above a defined - threshold using ``Sinabove``. For example, you could create a half-sin - by setting ``Sinabove`` to zero. + threshold using ``Sin[AB]above``. For example, you could create a half-sin + by setting ``Sin[AB]above`` to zero. The **WHITENOISE** mode requires the amplitude of A and/or B. The gaussian distribution is generated with zero-mean and one standard deviation from @@ -127,8 +127,8 @@ def __init__(self, family_name: str, mode: int, **kwargs): FrequencyB(float): Frequency of the sine excitation for PolynomB PhaseA(float): Phase of the sine excitation for PolynomA. Default 0 rad PhaseB(float): Phase of the sine excitation for PolynomB. Default 0 rad - SinaboveA(float): Default -1. - SinaboveB(float): Default -1. + SinAabove(float): Default -1. + SinBabove(float): Default -1. FuncA(list): User defined tbt kick list for PolynomA FuncB(list): User defined tbt kick list for PolynomB FuncAderiv1 ARBITRARY excitation tbt kick list for PolynomA 1st @@ -213,7 +213,7 @@ def _set_sine(self, a_b: str, **kwargs) -> dict[str, Any]: if frequency is None: raise AtError("Please provide a value for Frequency" + a_b) kwargs.setdefault("Phase" + a_b, 0) - kwargs.setdefault("Sinabove" + a_b, -1) + kwargs.setdefault("Sin" + a_b + "above", -1) return kwargs def _set_arb(self, a_b: str, **kwargs) -> dict[str, Any]: From a1ecaa0c15604e9debba12fc1440a0146fd8ef76 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 16:25:36 +0100 Subject: [PATCH 091/129] fix docstring --- pyat/at/lattice/variable_elements.py | 90 ++++++++++++++-------------- 1 file changed, 44 insertions(+), 46 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 3d749efcc..87c410622 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -66,7 +66,7 @@ def __init__(self, family_name: str, mode: int, **kwargs): There are three different modes that could be set: SINE = 0, WHITENOISE = 1 and ARBITRARY = 2. See ACMode. - The **SINE** mode requires amplitude, frequency and phase for A and/or B. + The **SINE** mode requires amplitude and frequency for A and/or B. The value of the jth component of the polynom (A or B) at the nth turn is given by Amplitude[j]*sin[TWOPI*frequency*(n*T0 + \tau_p) + phase], @@ -101,7 +101,7 @@ def __init__(self, family_name: str, mode: int, **kwargs): the the sixth coordinate divided by the speed of light. tau could be offset using ``FuncATimeDelay`` or ``FuncBTimeDelay``. tau = tau - Func[AB]TimeDelay - The function value is then multiplied by amplitude A and/or B. + The function `value` is then **multiplied by Amplitude A and/or B**. For example, the following is a positive vertical kick in the first turn, negative on the second turn, and zero on the third turn. elesinglekick = at.VariableMultipole('CUSTOMFUNC',at.ACMODE.ARBITRARY, @@ -123,57 +123,55 @@ def __init__(self, family_name: str, mode: int, **kwargs): Default None AmplitudeB(list,float): Amplitude of the excitation for PolynomB. Default None - FrequencyA(float): Frequency of the sine excitation for PolynomA - FrequencyB(float): Frequency of the sine excitation for PolynomB + FrequencyA(float): Frequency of the PolynomA sine excitation. Unit Hz + FrequencyB(float): Frequency of the PolynomB sine excitation. Unit Hz PhaseA(float): Phase of the sine excitation for PolynomA. Default 0 rad PhaseB(float): Phase of the sine excitation for PolynomB. Default 0 rad - SinAabove(float): Default -1. - SinBabove(float): Default -1. - FuncA(list): User defined tbt kick list for PolynomA - FuncB(list): User defined tbt kick list for PolynomB - FuncAderiv1 ARBITRARY excitation tbt kick list for PolynomA 1st - (list) derivative wrt tau - FuncBderiv1 ARBITRARY excitation tbt kick list for PolynomB 1st - (list) derivative wrt tau - FuncAderiv2 ARBITRARY excitation tbt kick list for PolynomA 2nd - (list) derivative wrt tau - FuncBderiv2 ARBITRARY excitation tbt kick list for PolynomB 2nd - (list) derivative wrt tau - FuncAderiv3 ARBITRARY excitation tbt kick list for PolynomA 3rd - (list) derivative wrt tau - FuncBderiv3 ARBITRARY excitation tbt kick list for PolynomB 3rd - (list) derivative wrt tau - FuncAderiv4 ARBITRARY excitation tbt kick list for PolynomA 3rd - (list) derivative wrt tau - FuncBderiv4 ARBITRARY excitation tbt kick list for PolynomB 3rd - (list) derivative wrt tau - FuncATimeDelay TimeDelay to generate a small time offset on the - (float) function FUNC. It only has an effect if any of the - derivatives is not zero. - FuncBTimeDelay TimeDelay to generate a small time offset on the - (float) function FUNC. It only has an effect if any of the - derivatives is not zero. - Periodic(bool): If True (default) the user defined kick is repeated - Ramps(list): Vector (t0, t1, t2, t3) in turn number to define - the ramping of the excitation - - * ``t>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.SINE, AmplitudeB=amp, FrequencyB=frequency) - >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.WHITENOISE, AmplitudeB=amp) - >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.ARBITRARY, AmplitudeB=amp, FuncB=fun) + >>> acmpole = at.VariableMultipole('ACSKEW', at.ACMode.SINE, AmplitudeA=[0,amp], FrequencyA=freq) + >>> acmpole = at.VariableMultipole('ACHKICK', at.ACMode.WHITENOISE, AmplitudeB=amp) + >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.ARBITRARY, AmplitudeB=[0,0,amp], FuncB=fun) """ From 6573a21b5cc40f5baab2a5abf6169fd728a4fce7 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 16:37:44 +0100 Subject: [PATCH 092/129] fixing matlab help --- .../element_creation/atvariablemultipole.m | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index 2427cc2eb..aa891c247 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -16,15 +16,15 @@ % PolynomA % AmplitudeB Vector or scalar to define the excitation amplitude for % PolynomB -% FrequencyA Frequency of SINE excitation for PolynomA -% FrequencyB Frequency of SINE excitation for PolynomB +% FrequencyA Frequency of SINE excitation for PolynomA. Unit Hz +% FrequencyB Frequency of SINE excitation for PolynomB. Unit Hz. % PhaseA Phase of SINE excitation for PolynomA % PhaseB Phase of SINE excitation for PolynomB % SinAabove Limit the sin function to be above. Default -1. % SinBabove Limit the sin function to be above. Default -1. -% FuncA ARBITRARY excitation turn-by-turn (tbt) kick list for +% FuncA ARBITRARY excitation turn-by-turn (tbt) list for % PolynomA -% FuncB ARBITRARY excitation turn-by-turn (tbt) kick list for +% FuncB ARBITRARY excitation turn-by-turn (tbt) list for % PolynomB % FuncAderiv1 ARBITRARY excitation tbt kick list for PolynomA 1st % derivative wrt tau @@ -50,12 +50,13 @@ % derivatives is not zero. % Periodic If true (default) the user input kick list is repeated % Ramps Vector (t0, t1, t2, t3) in turn number to define the -% ramping of the excitation -% * t> atvariablemultipole('ACM','SINE','AmplitudeB',1.e-4,'FrequencyB',1.e3); +% % Create a sinusoidal skew quadrupole with amplitude 0.0001 and frequency 1 kHz +% >> atvariablemultipole('ACSKEW','SINE','AmplitudeA',[0,1.e-4],'FrequencyA',1.e3); % -% % Create a white noise dipole excitation of amplitude 0.1 mrad -% >> atvariablemultipole('ACM','WHITENOISE','AmplitudeB',1.e-4); +% % Create a white noise horizontal dipole excitation of amplitude 0.1 mrad +% >> atvariablemultipole('ACKICK','WHITENOISE','AmplitudeB',1.e-4); % % % Create a vertical kick in the first turn and the opposite kick in the second % % turn. @@ -83,26 +84,25 @@ % % MORE DETAILS % -% This function creates a thin multipole of any order (1 to k) and type -% (Normal or Skew) defined by the amplitude A or B components; the polynoms -% PolynomA and PolynomB are calculated on every turn depending on the -% chosen mode, and for some modes also on the particle time delay. -% All modes could be ramped. +% This function creates a thin multipole of any order (dipole kick, quadrupole, +% sextupole, etc.)) and type (Normal or Skew) defined by the AmplitudeA and/or +% AmplitudeB components; the polynoms PolynomA and PolynomB are calculated on +% every turn depending on the chosen mode, and for some modes also on the +% particle time delay. All modes could be ramped. % -% Keep in mind that this element varies on every turn, therefore, any ring -% containing a variable element may change after tracking n turns. +% Keep in mind that as this element varies on every turn, any ring +% containing a variable multipole may change after tracking. % -% There are three different modes implemented: +% There are three different modes that could be set: % SINE = 0, WHITENOISE = 1 and ARBITRARY = 2. % -% The SINE mode requires amplitude, frequency and phase of at least one of -% the two polynoms A or B. The j-th component of the kth order polynom on -% the n-th turn is given by: -% amplitude_j*sin[ 2\pi*frequency*(nth_turn*T0 + \tau_p) + phase], +% The SINE mode requires amplitude, frequency of at least for A and/or B. +% The jth component of the polynom (A or B) at the nth turn is given by: +% amplitude(j)*sin[ TWOPI*frequency*(n*T0 + \tau_p) + phase], % where T0 is the revolution period of the ideal ring, and \tau_p is the delay % of the pth particle i.e. the sixth coordinate over the speed of light. Also, % note that the position of the element on the ring has no effect, the phase -% should be used to add any delay due to the position along s. +% could be used to add any delay due to the position along s. % The following is an example of the SINE mode of an skew quad: % eleskew = atvariablemultipole('VAR_SKEW','SINE', % 'AmplitudeA',[0,skewa2],'FrequencyA',freqA,'PhaseA',phaseA) From 7544283c9c122422ba77ea06e259cf154e27709b Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 16:38:12 +0100 Subject: [PATCH 093/129] Adding default pass method to docstring --- pyat/at/lattice/variable_elements.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 87c410622..a3a5d34a8 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -54,6 +54,8 @@ class VariableMultipole(Element): def __init__(self, family_name: str, mode: int, **kwargs): r"""VariableMultipole initialization. + Default pass method: ``VariableThinMPolePass``. + This Class creates a thin multipole of any order (dipole kick, quadrupole, sextupole, etc.) and type (Normal or Skew) defined by AmplitudeA and/or AmplitudeB components; the polynoms PolynomA and PolynomB are calculated From 8605f7b3f6d61b42ee4b5352d67ceb9921ea0398 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 7 Jan 2025 17:05:05 +0100 Subject: [PATCH 094/129] removing self from methods inside __init__ --- pyat/at/lattice/variable_elements.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index a3a5d34a8..e593b1209 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -177,7 +177,7 @@ def __init__(self, family_name: str, mode: int, **kwargs): """ - def _check_amplitudes(self, **kwargs) -> dict[str, Any]: + def _check_amplitudes(**kwargs) -> dict[str, Any]: amp_aux = {"A": None, "B": None} all_amplitudes_are_none = True for key in amp_aux: @@ -193,7 +193,7 @@ def _check_amplitudes(self, **kwargs) -> dict[str, Any]: raise AtError("Please provide at least one amplitude for A or B") return amp_aux - def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray) -> int: + def _getmaxorder(ampa: np.ndarray, ampb: np.ndarray) -> int: mxa, mxb = 0, 0 if ampa is not None: mxa = np.max(np.append(np.nonzero(ampa), 0)) @@ -201,14 +201,14 @@ def _getmaxorder(self, ampa: np.ndarray, ampb: np.ndarray) -> int: mxb = np.max(np.append(np.nonzero(ampb), 0)) return max(mxa, mxb) - def _set_mode(self, mode: int, a_b: str, **kwargs) -> dict[str, Any]: + def _set_mode(mode: int, a_b: str, **kwargs) -> dict[str, Any]: if mode == ACMode.SINE: - kwargs = self._set_sine(a_b, **kwargs) + kwargs = _set_sine(a_b, **kwargs) if mode == ACMode.ARBITRARY: - kwargs = self._set_arb(a_b, **kwargs) + kwargs = _set_arb(a_b, **kwargs) return kwargs - def _set_sine(self, a_b: str, **kwargs) -> dict[str, Any]: + def _set_sine(a_b: str, **kwargs) -> dict[str, Any]: frequency = kwargs.get("Frequency" + a_b, None) if frequency is None: raise AtError("Please provide a value for Frequency" + a_b) @@ -216,7 +216,7 @@ def _set_sine(self, a_b: str, **kwargs) -> dict[str, Any]: kwargs.setdefault("Sin" + a_b + "above", -1) return kwargs - def _set_arb(self, a_b: str, **kwargs) -> dict[str, Any]: + def _set_arb(a_b: str, **kwargs) -> dict[str, Any]: func = kwargs.get("Func" + a_b, None) if func is None: raise AtError("Please provide a value for Func" + a_b) @@ -230,7 +230,7 @@ def _set_arb(self, a_b: str, **kwargs) -> dict[str, Any]: kwargs.setdefault("Periodic", True) return kwargs - def _check_ramp(self, **kwargs) -> _array: + def _check_ramp(**kwargs) -> _array: ramps = kwargs.get("Ramps", None) if ramps is not None: if len(ramps) != 4: @@ -242,18 +242,18 @@ def _check_ramp(self, **kwargs) -> _array: kwargs.setdefault("Mode", mode) kwargs.setdefault("PassMethod", "VariableThinMPolePass") if len(kwargs) > 2: - amp_aux = self._check_amplitudes(**kwargs) + amp_aux = _check_amplitudes(**kwargs) for key, value in amp_aux.items(): if value is not None: kwargs["Amplitude" + key] = value - kwargs = self._set_mode(mode, key, **kwargs) - maxorder = self._getmaxorder(amp_aux["A"], amp_aux["B"]) + kwargs = _set_mode(mode, key, **kwargs) + maxorder = _getmaxorder(amp_aux["A"], amp_aux["B"]) kwargs["MaxOrder"] = kwargs.get("MaxOrder", maxorder) for key in amp_aux: kwargs["Polynom" + key] = kwargs.get( "Polynom" + key, np.zeros(maxorder + 1) ) - ramps = self._check_ramp(**kwargs) + ramps = _check_ramp(**kwargs) if ramps is not None: kwargs["Ramps"] = ramps super().__init__(family_name, **kwargs) From cd27c42d779c3cd09fd15728b55e75823d17ebd0 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Wed, 8 Jan 2025 11:36:17 +0100 Subject: [PATCH 095/129] fixing help message --- .../element_creation/atvariablemultipole.m | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index aa891c247..a34e9cef4 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -27,31 +27,30 @@ % FuncB ARBITRARY excitation turn-by-turn (tbt) list for % PolynomB % FuncAderiv1 ARBITRARY excitation tbt kick list for PolynomA 1st -% derivative wrt tau +% derivative wrt tau. Default: zeros(1,length(FUNC)) % FuncBderiv1 ARBITRARY excitation tbt kick list for PolynomB 1st -% derivative wrt tau +% derivative wrt tau. Default: zeros(1,length(FUNC)) % FuncAderiv2 ARBITRARY excitation tbt kick list for PolynomA 2nd -% derivative wrt tau +% derivative wrt tau. Default: zeros(1,length(FUNC)) % FuncBderiv2 ARBITRARY excitation tbt kick list for PolynomB 2nd -% derivative wrt tau +% derivative wrt tau. Default: zeros(1,length(FUNC)) % FuncAderiv3 ARBITRARY excitation tbt kick list for PolynomA 3rd -% derivative wrt tau +% derivative wrt tau. Default: zeros(1,length(FUNC)) % FuncBderiv3 ARBITRARY excitation tbt kick list for PolynomB 3rd -% derivative wrt tau +% derivative wrt tau. Default: zeros(1,length(FUNC)) % FuncAderiv4 ARBITRARY excitation tbt kick list for PolynomA 3rd -% derivative wrt tau +% derivative wrt tau. Default: zeros(1,length(FUNC)) % FuncBderiv4 ARBITRARY excitation tbt kick list for PolynomB 3rd -% derivative wrt tau +% derivative wrt tau. Default: zeros(1,length(FUNC)) % FuncATimeDelay TimeDelay to generate a small time offset on the % function FUNC. It only has an effect if any of the -% derivatives is not zero. +% derivatives is not zero. Default: 0. % FuncBTimeDelay TimeDelay to generate a small time offset on the % function FUNC. It only has an effect if any of the -% derivatives is not zero. +% derivatives is not zero. Default 0. % Periodic If true (default) the user input kick list is repeated % Ramps Vector (t0, t1, t2, t3) in turn number to define the % ramping of the excitation: - % * t<=t0: excitation amplitude is zero. % * t0 tau - Func[AB]TimeDelay +% tau -> tau + Func[AB]TimeDelay +% The function value is then multiplied by Amplitude A and/or B. % For example, the following is a positive vertical kick in the first turn, % negative on the second turn, and zero on the third turn. -% funca = [1 -1 0]; -% elesinglekick = at.VariableMultipole('CUSTOMFUNC','ARBITRARY', -% AmplitudeA=1e-4,FuncA=funca,Periodic=True) +% atvariablemultipole('CUSTOMFUNC','ARBITRARY', ... +% 'AmplitudeA',1e-4,'FuncA',[1 -1 0],'Periodic',True); % by default the array is assumed periodic. If Periodic is set to False % it is assumed that the function has no effect on the particle in turns % exceeding the function definition. From 4b1812a2cb5b55bcd3d4e3a04a23c2de9148ec5c Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Wed, 8 Jan 2025 11:36:35 +0100 Subject: [PATCH 096/129] fixing help message --- pyat/at/lattice/variable_elements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index e593b1209..8d3c9b6e4 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -102,7 +102,7 @@ def __init__(self, family_name: str, mode: int, **kwargs): the derivatives wrt \tau, and \tau is the time delay of the particle, i.e. the the sixth coordinate divided by the speed of light. tau could be offset using ``FuncATimeDelay`` or ``FuncBTimeDelay``. - tau = tau - Func[AB]TimeDelay + tau = tau + Func[AB]TimeDelay The function `value` is then **multiplied by Amplitude A and/or B**. For example, the following is a positive vertical kick in the first turn, negative on the second turn, and zero on the third turn. From 02ee269a746b3de393b7616d32a295f3dea67be2 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Wed, 15 Jan 2025 16:30:04 +0100 Subject: [PATCH 097/129] changes type hint to Sequence --- pyat/at/lattice/variable_elements.py | 41 ++++++++++++++-------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 8d3c9b6e4..214ef468d 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -2,6 +2,7 @@ from __future__ import annotations +from collections.abc import Sequence from enum import IntEnum from typing import Any @@ -37,16 +38,16 @@ class VariableMultipole(Element): SinBabove=float, NsamplesA=int, NsamplesB=int, - FuncA=_array, - FuncAderiv1=_array, - FuncAderiv2=_array, - FuncAderiv3=_array, - FuncAderiv4=_array, - FuncB=_array, - FuncBderiv1=_array, - FuncBderiv2=_array, - FuncBderiv3=_array, - FuncBderiv4=_array, + FuncA=Sequence[float], + FuncAderiv1=Sequence[float], + FuncAderiv2=Sequence[float], + FuncAderiv3=Sequence[float], + FuncAderiv4=Sequence[float], + FuncB=Sequence[float], + FuncBderiv1=Sequence[float], + FuncBderiv2=Sequence[float], + FuncBderiv3=Sequence[float], + FuncBderiv4=Sequence[float], Ramps=_array, Periodic=bool, ) @@ -131,23 +132,23 @@ def __init__(self, family_name: str, mode: int, **kwargs): PhaseB(float): Phase of the sine excitation for PolynomB. Default 0 rad SinAabove(float): Limit the sin function to be above. Default -1. SinBabove(float): Limit the sin function to be above. Default -1. - FuncA(list): User defined tbt list for PolynomA - FuncB(list): User defined tbt list for PolynomB - FuncAderiv1(list): tbt list for PolynomA 1st derivative wrt tau. + FuncA(Sequence[float]): User defined tbt list for PolynomA + FuncB(Sequence[float]): User defined tbt list for PolynomB + FuncAderiv1(Sequence[float]): tbt list for PolynomA 1st derivative wrt tau. Default: zeros array of the custom function length. - FuncBderiv1(list): tbt list for PolynomB 1st derivative wrt tau. + FuncBderiv1(Sequence[float]): tbt list for PolynomB 1st derivative wrt tau. Default: zeros array of the custom function length. - FuncAderiv2(list): tbt list for PolynomA 2st derivative wrt tau. + FuncAderiv2(Sequence[float]): tbt list for PolynomA 2st derivative wrt tau. Default: zeros array of the custom function length. - FuncBderiv2(list): tbt list for PolynomB 2st derivative wrt tau. + FuncBderiv2(Sequence[float]): tbt list for PolynomB 2st derivative wrt tau. Default: zeros array of the custom function length. - FuncAderiv3(list): tbt list for PolynomA 3st derivative wrt tau. + FuncAderiv3(Sequence[float]): tbt list for PolynomA 3st derivative wrt tau. Default: zeros array of the custom function length. - FuncBderiv3(list): tbt list for PolynomB 3st derivative wrt tau. + FuncBderiv3(Sequence[float]): tbt list for PolynomB 3st derivative wrt tau. Default: zeros array of the custom function length. - FuncAderiv4(list): tbt list for PolynomA 4st derivative wrt tau. + FuncAderiv4(Sequence[float]): tbt list for PolynomA 4st derivative wrt tau. Default: zeros array of the custom function length. - FuncBderiv4(list): tbt list for PolynomB 4st derivative wrt tau. + FuncBderiv4(Sequence[float]): tbt list for PolynomB 4st derivative wrt tau. Default: zeros array of the custom function length. FuncATimeDelay(float): generate a time offset on the function FUNCA. It only has an effect if any of the derivatives is not zero. From 02a7bc0dbf092ca13ba40163415869df21184100 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Wed, 15 Jan 2025 16:31:22 +0100 Subject: [PATCH 098/129] fixing flake8 FNE008 --- pyat/at/lattice/variable_elements.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 214ef468d..7c36c1391 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -202,7 +202,7 @@ def _getmaxorder(ampa: np.ndarray, ampb: np.ndarray) -> int: mxb = np.max(np.append(np.nonzero(ampb), 0)) return max(mxa, mxb) - def _set_mode(mode: int, a_b: str, **kwargs) -> dict[str, Any]: + def _set_thismode(mode: int, a_b: str, **kwargs) -> dict[str, Any]: if mode == ACMode.SINE: kwargs = _set_sine(a_b, **kwargs) if mode == ACMode.ARBITRARY: @@ -247,7 +247,7 @@ def _check_ramp(**kwargs) -> _array: for key, value in amp_aux.items(): if value is not None: kwargs["Amplitude" + key] = value - kwargs = _set_mode(mode, key, **kwargs) + kwargs = _set_thismode(mode, key, **kwargs) maxorder = _getmaxorder(amp_aux["A"], amp_aux["B"]) kwargs["MaxOrder"] = kwargs.get("MaxOrder", maxorder) for key in amp_aux: From 3642a679ef8e045b8a05d5beeb551124cb1422bc Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Wed, 15 Jan 2025 16:39:01 +0100 Subject: [PATCH 099/129] set Periodic default False --- pyat/at/lattice/variable_elements.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 7c36c1391..18a88c23a 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -109,9 +109,9 @@ def __init__(self, family_name: str, mode: int, **kwargs): negative on the second turn, and zero on the third turn. elesinglekick = at.VariableMultipole('CUSTOMFUNC',at.ACMODE.ARBITRARY, AmplitudeA=1e-4,FuncA=[1,-1,0],Periodic=True) - By default the array is assumed periodic. If ``Periodic`` is set to False - it is assumed that the function has no effect on the particle in turns - exceeding the function definition. + By default the array is assumed non periodic, the function has no effect + on the particle in turns exceeding the function definition. If + ``Periodic`` is set to True, the sequence is repeated. Parameters: @@ -154,7 +154,7 @@ def __init__(self, family_name: str, mode: int, **kwargs): It only has an effect if any of the derivatives is not zero. FuncBTimeDelay(float): generate a time offset on the function FUNCB. It only has an effect if any of the derivatives is not zero. - Periodic(bool): If True (default) the user defined is repeated. + Periodic(bool): If True the user definition is repeated. Default False. Ramps(list): Four values (t0,t1,t2,t3) defining the ramping steps: * ``t<=t0``: excitation amplitude is zero. @@ -228,7 +228,7 @@ def _set_arb(a_b: str, **kwargs) -> dict[str, Any]: kwargs.setdefault("Func" + a_b + "deriv4", np.zeros(nsamp)) kwargs.setdefault("Func" + a_b + "TimeDelay", 0) kwargs["NSamples" + a_b] = nsamp - kwargs.setdefault("Periodic", True) + kwargs.setdefault("Periodic", False) return kwargs def _check_ramp(**kwargs) -> _array: From 8c0ea73fcb77f51504ecd7c52a3920c39abd68a5 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Wed, 15 Jan 2025 16:43:55 +0100 Subject: [PATCH 100/129] Periodic set default false --- atmat/lattice/element_creation/atvariablemultipole.m | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablemultipole.m index a34e9cef4..3511283f2 100644 --- a/atmat/lattice/element_creation/atvariablemultipole.m +++ b/atmat/lattice/element_creation/atvariablemultipole.m @@ -48,7 +48,7 @@ % FuncBTimeDelay TimeDelay to generate a small time offset on the % function FUNC. It only has an effect if any of the % derivatives is not zero. Default 0. -% Periodic If true (default) the user input kick list is repeated +% Periodic If true the user input list is repeated. Default: false. % Ramps Vector (t0, t1, t2, t3) in turn number to define the % ramping of the excitation: % * t<=t0: excitation amplitude is zero. @@ -134,9 +134,10 @@ % negative on the second turn, and zero on the third turn. % atvariablemultipole('CUSTOMFUNC','ARBITRARY', ... % 'AmplitudeA',1e-4,'FuncA',[1 -1 0],'Periodic',True); -% by default the array is assumed periodic. If Periodic is set to False -% it is assumed that the function has no effect on the particle in turns -% exceeding the function definition. +% by default the array is assumed non periodic. The function has +% no effect on the particle in turns exceeding the function definition. +% If Periodic is set to True, the sequence is repeated. + % % Input parser for option @@ -200,7 +201,7 @@ function setsine(rsrc, ab) if strcmpi(mode,'ARBITRARY') rsrc = setarb(rsrc,ab); if ~isfield(rsrc,'Periodic') - rsrc.Periodic = true; + rsrc.Periodic = false; end end end From 3d54be8a1543325878b8f1ea33a4c32fabdbadc9 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Wed, 15 Jan 2025 17:11:53 +0100 Subject: [PATCH 101/129] removing Float from type hint Sequence due to python3.7 error --- pyat/at/lattice/variable_elements.py | 40 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 18a88c23a..589d4f674 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -38,16 +38,16 @@ class VariableMultipole(Element): SinBabove=float, NsamplesA=int, NsamplesB=int, - FuncA=Sequence[float], - FuncAderiv1=Sequence[float], - FuncAderiv2=Sequence[float], - FuncAderiv3=Sequence[float], - FuncAderiv4=Sequence[float], - FuncB=Sequence[float], - FuncBderiv1=Sequence[float], - FuncBderiv2=Sequence[float], - FuncBderiv3=Sequence[float], - FuncBderiv4=Sequence[float], + FuncA=Sequence, + FuncAderiv1=Sequence, + FuncAderiv2=Sequence, + FuncAderiv3=Sequence, + FuncAderiv4=Sequence, + FuncB=Sequence, + FuncBderiv1=Sequence, + FuncBderiv2=Sequence, + FuncBderiv3=Sequence, + FuncBderiv4=Sequence, Ramps=_array, Periodic=bool, ) @@ -132,23 +132,23 @@ def __init__(self, family_name: str, mode: int, **kwargs): PhaseB(float): Phase of the sine excitation for PolynomB. Default 0 rad SinAabove(float): Limit the sin function to be above. Default -1. SinBabove(float): Limit the sin function to be above. Default -1. - FuncA(Sequence[float]): User defined tbt list for PolynomA - FuncB(Sequence[float]): User defined tbt list for PolynomB - FuncAderiv1(Sequence[float]): tbt list for PolynomA 1st derivative wrt tau. + FuncA(Sequence): User defined tbt list for PolynomA + FuncB(Sequence): User defined tbt list for PolynomB + FuncAderiv1(Sequence): tbt list for PolynomA 1st derivative wrt tau. Default: zeros array of the custom function length. - FuncBderiv1(Sequence[float]): tbt list for PolynomB 1st derivative wrt tau. + FuncBderiv1(Sequence): tbt list for PolynomB 1st derivative wrt tau. Default: zeros array of the custom function length. - FuncAderiv2(Sequence[float]): tbt list for PolynomA 2st derivative wrt tau. + FuncAderiv2(Sequence): tbt list for PolynomA 2st derivative wrt tau. Default: zeros array of the custom function length. - FuncBderiv2(Sequence[float]): tbt list for PolynomB 2st derivative wrt tau. + FuncBderiv2(Sequence): tbt list for PolynomB 2st derivative wrt tau. Default: zeros array of the custom function length. - FuncAderiv3(Sequence[float]): tbt list for PolynomA 3st derivative wrt tau. + FuncAderiv3(Sequence): tbt list for PolynomA 3st derivative wrt tau. Default: zeros array of the custom function length. - FuncBderiv3(Sequence[float]): tbt list for PolynomB 3st derivative wrt tau. + FuncBderiv3(Sequence): tbt list for PolynomB 3st derivative wrt tau. Default: zeros array of the custom function length. - FuncAderiv4(Sequence[float]): tbt list for PolynomA 4st derivative wrt tau. + FuncAderiv4(Sequence): tbt list for PolynomA 4st derivative wrt tau. Default: zeros array of the custom function length. - FuncBderiv4(Sequence[float]): tbt list for PolynomB 4st derivative wrt tau. + FuncBderiv4(Sequence): tbt list for PolynomB 4st derivative wrt tau. Default: zeros array of the custom function length. FuncATimeDelay(float): generate a time offset on the function FUNCA. It only has an effect if any of the derivatives is not zero. From 8cbcd973c71b49206fe8c254320f1ff21c0f769b Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Wed, 15 Jan 2025 18:17:19 +0100 Subject: [PATCH 102/129] change to VariableThinMultipole --- pyat/at/lattice/variable_elements.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 589d4f674..e34cc5c42 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -1,4 +1,4 @@ -"""VariableMultipole.""" +"""VariableThinMultipole.""" from __future__ import annotations @@ -11,18 +11,18 @@ from .elements import Element, _array from .utils import AtError, AtWarning -__all__ = ["ACMode", "VariableMultipole"] +__all__ = ["ACMode", "VariableThinMultipole"] class ACMode(IntEnum): - """Class to define the ``VariableMultipole`` excitation mode.""" + """Class to define the ``VariableThinMultipole`` excitation mode.""" SINE = 0 WHITENOISE = 1 ARBITRARY = 2 -class VariableMultipole(Element): +class VariableThinMultipole(Element): """Turn by turn variable thin multipole.""" _BUILD_ATTRIBUTES = Element._BUILD_ATTRIBUTES + ["Mode"] @@ -53,7 +53,7 @@ class VariableMultipole(Element): ) def __init__(self, family_name: str, mode: int, **kwargs): - r"""VariableMultipole initialization. + r"""VariableThinMultipole initialization. Default pass method: ``VariableThinMPolePass``. @@ -64,7 +64,7 @@ def __init__(self, family_name: str, mode: int, **kwargs): particle time delay. All modes could be ramped. Keep in mind that as this element varies on every turn, any ring - containing a VariableMultipole may change after tracking. + containing a VariableThinMultipole may change after tracking. There are three different modes that could be set: SINE = 0, WHITENOISE = 1 and ARBITRARY = 2. See ACMode. @@ -78,7 +78,7 @@ def __init__(self, family_name: str, mode: int, **kwargs): note that the position of the element on the ring has no effect, the phase could be used to add any delay due to the position along s. The following is an example of the SINE mode of an skew quad - eleskew = at.VariableMultipole('VAR_SKEW',at.ACMode.SINE, + eleskew = at.VariableThinMultipole('VAR_SKEW',at.ACMode.SINE, AmplitudeA=[0,skewa2],FrequencyA=freqA,PhaseA=phaseA) The values of the sin function could be limited to be above a defined threshold using ``Sin[AB]above``. For example, you could create a half-sin @@ -90,7 +90,7 @@ def __init__(self, family_name: str, mode: int, **kwargs): function, therefore using the same stream on all trackings (sequencial or parallel). See https://github.com/atcollab/at/discussions/879 for more details on the pseudo random stream. For example - elenoise = at.VariableMultipole('MYNOISE',at.ACMode.WHITENOISE, + elenoise = at.VariableThinMultipole('MYNOISE',at.ACMode.WHITENOISE, AmplitudeA=[noiseA1]) creates a vertical kick as gaussian noise of amplitude noiseA1. @@ -107,7 +107,7 @@ def __init__(self, family_name: str, mode: int, **kwargs): The function `value` is then **multiplied by Amplitude A and/or B**. For example, the following is a positive vertical kick in the first turn, negative on the second turn, and zero on the third turn. - elesinglekick = at.VariableMultipole('CUSTOMFUNC',at.ACMODE.ARBITRARY, + elesinglekick = at.VariableThinMultipole('CUSTOMFUNC',at.ACMODE.ARBITRARY, AmplitudeA=1e-4,FuncA=[1,-1,0],Periodic=True) By default the array is assumed non periodic, the function has no effect on the particle in turns exceeding the function definition. If @@ -172,9 +172,9 @@ def __init__(self, family_name: str, mode: int, **kwargs): Examples: - >>> acmpole = at.VariableMultipole('ACSKEW', at.ACMode.SINE, AmplitudeA=[0,amp], FrequencyA=freq) - >>> acmpole = at.VariableMultipole('ACHKICK', at.ACMode.WHITENOISE, AmplitudeB=amp) - >>> acmpole = at.VariableMultipole('ACMPOLE', at.ACMode.ARBITRARY, AmplitudeB=[0,0,amp], FuncB=fun) + >>> acmpole = at.VariableThinMultipole('ACSKEW', at.ACMode.SINE, AmplitudeA=[0,amp], FrequencyA=freq) + >>> acmpole = at.VariableThinMultipole('ACHKICK', at.ACMode.WHITENOISE, AmplitudeB=amp) + >>> acmpole = at.VariableThinMultipole('ACMPOLE', at.ACMode.ARBITRARY, AmplitudeB=[0,0,amp], FuncB=fun) """ From 0054f6e7424d6aee7a97a77a7b0da9f71a1dad1a Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Wed, 15 Jan 2025 18:19:03 +0100 Subject: [PATCH 103/129] atvariablethinmultiple.m --- .../{atvariablemultipole.m => atvariablethinmultipole.m} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename atmat/lattice/element_creation/{atvariablemultipole.m => atvariablethinmultipole.m} (100%) diff --git a/atmat/lattice/element_creation/atvariablemultipole.m b/atmat/lattice/element_creation/atvariablethinmultipole.m similarity index 100% rename from atmat/lattice/element_creation/atvariablemultipole.m rename to atmat/lattice/element_creation/atvariablethinmultipole.m From bf9b7ef55f61c18b568309430d83e018d8228a2d Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Wed, 15 Jan 2025 18:29:35 +0100 Subject: [PATCH 104/129] change to atvariablethinmultipole --- .../atvariablethinmultipole.m | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablethinmultipole.m b/atmat/lattice/element_creation/atvariablethinmultipole.m index 3511283f2..b3a106961 100644 --- a/atmat/lattice/element_creation/atvariablethinmultipole.m +++ b/atmat/lattice/element_creation/atvariablethinmultipole.m @@ -1,8 +1,8 @@ -function elem=atvariablemultipole(fname, mode, varargin) -% ATVARIABLEMULTIPOLE Creates a variable thin multipole element +function elem=atvariablethinmultipole(fname, mode, varargin) +% ATVARIABLETHINMULTIPOLE Creates a variable thin multipole element % -% ATVARIABLEMULTIPOLE(FAMNAME,MODE) -% ATVARIABLEMULTIPOLE(FAMNAME,MODE,PASSMETHOD,[KEY,VALUE]...) +% ATVARIABLETHINMULTIPOLE(FAMNAME,MODE) +% ATVARIABLETHINMULTIPOLE(FAMNAME,MODE,PASSMETHOD,[KEY,VALUE]...) % % INPUTS % FNAME Family name @@ -69,15 +69,15 @@ % EXAMPLES % % % Create a sinusoidal skew quadrupole with amplitude 0.0001 and frequency 1 kHz -% >> atvariablemultipole('ACSKEW','SINE','AmplitudeA',[0,1.e-4],'FrequencyA',1.e3); +% >> atvariablethinmultipole('ACSKEW','SINE','AmplitudeA',[0,1.e-4],'FrequencyA',1.e3); % % % Create a white noise horizontal dipole excitation of amplitude 0.1 mrad -% >> atvariablemultipole('ACKICK','WHITENOISE','AmplitudeB',1.e-4); +% >> atvariablethinmultipole('ACKICK','WHITENOISE','AmplitudeB',1.e-4); % % % Create a vertical kick in the first turn and the opposite kick in the second % % turn. % >> funca = [1 -1 0]; -% >> atvariablemultipole('CUSTOMFUNC','ARBITRARY','AmplitudeA',1e-4, ... +% >> atvariablethinmultipole('CUSTOMFUNC','ARBITRARY','AmplitudeA',1e-4, ... % 'FuncA',funca,'Periodic',false); % % @@ -103,14 +103,14 @@ % note that the position of the element on the ring has no effect, the phase % could be used to add any delay due to the position along s. % The following is an example of the SINE mode of an skew quad: -% atvariablemultipole('VAR_SKEW','SINE', +% atvariablethinmultipole('VAR_SKEW','SINE', % 'AmplitudeA',[0,skewa2],'FrequencyA',freqA,'PhaseA',phaseA) % The values of the sin function could be limited to be above a defined % threshold using ``Sin[AB]above``. For example, you could create a half-sin % by setting ``Sin[AB]above`` to zero. % % The WHITENOISE mode requires the amplitude of either A or B. For example -% atvariablemultipole('MYNOISE','WHITENOISE', +% atvariablethinmultipole('MYNOISE','WHITENOISE', % 'AmplitudeA',[noiseA1]) % creates a gaussian vertical noise of amplitude noiseA1. The gaussian % distribution is generated with zero-mean and one standard deviation from @@ -132,7 +132,7 @@ % The function value is then multiplied by Amplitude A and/or B. % For example, the following is a positive vertical kick in the first turn, % negative on the second turn, and zero on the third turn. -% atvariablemultipole('CUSTOMFUNC','ARBITRARY', ... +% atvariablethinmultipole('CUSTOMFUNC','ARBITRARY', ... % 'AmplitudeA',1e-4,'FuncA',[1 -1 0],'Periodic',True); % by default the array is assumed non periodic. The function has % no effect on the particle in turns exceeding the function definition. From 40840699521019e3762869f55ee486f85da1f258 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 16 Jan 2025 16:41:05 +0100 Subject: [PATCH 105/129] rename VariableMultipole to VariableThinMultipole --- pyat/at/tracking/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyat/at/tracking/utils.py b/pyat/at/tracking/utils.py index 105c21809..9b420da0b 100644 --- a/pyat/at/tracking/utils.py +++ b/pyat/at/tracking/utils.py @@ -8,7 +8,7 @@ from typing import Optional from ..lattice import Lattice, Element from ..lattice import BeamMoments, Collective, QuantumDiffusion -from ..lattice import SimpleQuantDiff, VariableMultipole +from ..lattice import SimpleQuantDiff, VariableThinMultipole from ..lattice import elements, refpts_iterator, set_value_refpts from ..lattice import DConstant, checktype, checkattr, get_bool_index @@ -20,7 +20,7 @@ DIMENSION_ERROR = 'Input to lattice_pass() must be a 6xN array.' _COLLECTIVE_ELEMS = (BeamMoments, Collective) -_VAR_ELEMS = (QuantumDiffusion, SimpleQuantDiff, VariableMultipole) +_VAR_ELEMS = (QuantumDiffusion, SimpleQuantDiff, VariableThinMultipole) _DISABLE_ELEMS = _COLLECTIVE_ELEMS + _VAR_ELEMS From 02dad6f3194ab439dcdea58373cc7db178bb6bf2 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 16 Jan 2025 16:41:20 +0100 Subject: [PATCH 106/129] rename VariableMultipole to VariableThinMultipole --- pyat/at/load/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyat/at/load/utils.py b/pyat/at/load/utils.py index fbf69ee40..4756603cd 100644 --- a/pyat/at/load/utils.py +++ b/pyat/at/load/utils.py @@ -143,7 +143,7 @@ def __init__( "AperturePass": elt.Aperture, "IdTablePass": idtable_element.InsertionDeviceKickMap, "GWigSymplecticPass": elt.Wiggler, - "VariableThinMPolePass": variable_elements.VariableMultipole, + "VariableThinMPolePass": variable_elements.VariableThinMultipole, } # Maps python class name to Matlab class From e25a0f1ca67a27e13535bcdeaa6324a2c6a9be57 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 16 Jan 2025 17:41:21 +0100 Subject: [PATCH 107/129] reset PolynomB and PolynomA to zeros after tracking; set Periodic to zero by default --- atintegrators/VariableThinMPolePass.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/atintegrators/VariableThinMPolePass.c b/atintegrators/VariableThinMPolePass.c index aee4d046f..8880f0121 100644 --- a/atintegrators/VariableThinMPolePass.c +++ b/atintegrators/VariableThinMPolePass.c @@ -314,7 +314,7 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, FuncBderiv4=atGetOptionalDoubleArray(ElemData,"FuncBderiv4"); check_error(); FuncATimeDelay=atGetOptionalDouble(ElemData,"FuncATimeDelay", 0); check_error(); FuncBTimeDelay=atGetOptionalDouble(ElemData,"FuncBTimeDelay", 0); check_error(); - Periodic=atGetOptionalLong(ElemData,"Periodic", 1); check_error(); + Periodic=atGetOptionalLong(ElemData,"Periodic", 0); check_error(); Elem = (struct elem*)atMalloc(sizeof(struct elem)); ElemA = (struct elemab*)atMalloc(sizeof(struct elemab)); ElemB = (struct elemab*)atMalloc(sizeof(struct elemab)); @@ -357,8 +357,14 @@ ExportMode struct elem* trackFunction(const atElem* ElemData, struct elem* Elem, } double t0 = Param->T0; int turn = Param->nturn; + int i; VariableThinMPolePass(r_in, Elem, t0, turn, num_particles, Param->common_rng); + /* reset the polynom values*/ + for (i = 0; i < Elem->MaxOrder + 1; i++){ + Elem->PolynomA[i] = 0; + Elem->PolynomB[i] = 0; + }; return Elem; } @@ -421,7 +427,7 @@ void mexFunction(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) FuncBderiv4=atGetOptionalDoubleArray(ElemData,"FuncBderiv4"); check_error(); FuncATimeDelay=atGetOptionalDouble(ElemData,"FuncATimeDelay", 0); check_error(); FuncBTimeDelay=atGetOptionalDouble(ElemData,"FuncBTimeDelay", 0); check_error(); - Periodic=atGetOptionalLong(ElemData,"Periodic", 1); check_error(); + Periodic=atGetOptionalLong(ElemData,"Periodic", 0); check_error(); Elem->PolynomA = PolynomA; Elem->PolynomB = PolynomB; Elem->Ramps = Ramps; From f5a341b35cb1a3eba5605b543b9efe3e30456e28 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 16 Jan 2025 20:07:58 +0100 Subject: [PATCH 108/129] fix bug in help message --- atmat/lattice/element_creation/atvariablethinmultipole.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atmat/lattice/element_creation/atvariablethinmultipole.m b/atmat/lattice/element_creation/atvariablethinmultipole.m index b3a106961..35542ea86 100644 --- a/atmat/lattice/element_creation/atvariablethinmultipole.m +++ b/atmat/lattice/element_creation/atvariablethinmultipole.m @@ -128,7 +128,7 @@ % the derivatives wrt \tau, and \tau is the time delay of the particle, i.e. % the the sixth coordinate divided by the speed of light. % tau could be offset using FuncATimeDelay or FuncBTimeDelay. -% tau -> tau + Func[AB]TimeDelay +% tau <- tau - Func[AB]TimeDelay % The function value is then multiplied by Amplitude A and/or B. % For example, the following is a positive vertical kick in the first turn, % negative on the second turn, and zero on the third turn. From df259e9e984ea37e14d050e7f151b8835b3e1473 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 17 Jan 2025 11:27:12 +0100 Subject: [PATCH 109/129] fixing help message --- atmat/lattice/element_creation/atvariablethinmultipole.m | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablethinmultipole.m b/atmat/lattice/element_creation/atvariablethinmultipole.m index 35542ea86..a51c2e16f 100644 --- a/atmat/lattice/element_creation/atvariablethinmultipole.m +++ b/atmat/lattice/element_creation/atvariablethinmultipole.m @@ -89,13 +89,14 @@ % every turn depending on the chosen mode, and for some modes also on the % particle time delay. All modes could be ramped. % -% Keep in mind that as this element varies on every turn, any ring -% containing a variable multipole may change after tracking. +% Keep in mind that as this element varies on every turn, and at the end of +% the tracking PolynomA and PolynomB are set to zero. % % There are three different modes that could be set: -% SINE = 0, WHITENOISE = 1 and ARBITRARY = 2. +% SINE (0), WHITENOISE (1) and ARBITRARY (2). +% when creating the element use 'SINE', 'WHITENOISE', or 'ARBITRARY'. % -% The SINE mode requires amplitude and frequency of at least for A and/or B. +% The SINE mode requires amplitude and frequency for at least A and/or B. % The jth component of the polynom (A or B) at the nth turn is given by: % amplitude(j)*sin[ TWOPI*frequency*(n*T0 + \tau_p) + phase], % where T0 is the revolution period of the ideal ring, and \tau_p is the delay From f08edc0626c5d9af9eb77c34371ba76bc6da9871 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 17 Jan 2025 14:25:32 +0100 Subject: [PATCH 110/129] fix help --- atmat/lattice/element_creation/atvariablethinmultipole.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/atmat/lattice/element_creation/atvariablethinmultipole.m b/atmat/lattice/element_creation/atvariablethinmultipole.m index a51c2e16f..1b04a53f1 100644 --- a/atmat/lattice/element_creation/atvariablethinmultipole.m +++ b/atmat/lattice/element_creation/atvariablethinmultipole.m @@ -92,11 +92,14 @@ % Keep in mind that as this element varies on every turn, and at the end of % the tracking PolynomA and PolynomB are set to zero. % +% Passing arrays of zeros as amplitude will initialize the MaxOrder to +% zero, and the polynom to a single zero. +% % There are three different modes that could be set: % SINE (0), WHITENOISE (1) and ARBITRARY (2). % when creating the element use 'SINE', 'WHITENOISE', or 'ARBITRARY'. % -% The SINE mode requires amplitude and frequency for at least A and/or B. +% The SINE mode requires amplitude and frequency for A and/or B. % The jth component of the polynom (A or B) at the nth turn is given by: % amplitude(j)*sin[ TWOPI*frequency*(n*T0 + \tau_p) + phase], % where T0 is the revolution period of the ideal ring, and \tau_p is the delay From 368ad6230a994271611d68d0fd7e4a7001473628 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Fri, 17 Jan 2025 14:26:27 +0100 Subject: [PATCH 111/129] fix help; work on the polynom inspection --- pyat/at/lattice/variable_elements.py | 97 +++++++++++++++++++++------- 1 file changed, 74 insertions(+), 23 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index e34cc5c42..ee97f3815 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -38,20 +38,67 @@ class VariableThinMultipole(Element): SinBabove=float, NsamplesA=int, NsamplesB=int, - FuncA=Sequence, - FuncAderiv1=Sequence, - FuncAderiv2=Sequence, - FuncAderiv3=Sequence, - FuncAderiv4=Sequence, - FuncB=Sequence, - FuncBderiv1=Sequence, - FuncBderiv2=Sequence, - FuncBderiv3=Sequence, - FuncBderiv4=Sequence, + FuncA=_array, + FuncAderiv1=_array, + FuncAderiv2=_array, + FuncAderiv3=_array, + FuncAderiv4=_array, + FuncB=_array, + FuncBderiv1=_array, + FuncBderiv2=_array, + FuncBderiv3=_array, + FuncBderiv4=_array, Ramps=_array, Periodic=bool, ) + def _get_amp(amp:float, ramps: _array, t: float): + """get_amp returns the input value `amp` when ramps is False. + + If ramps is True, it returns a value linearly interpolated + accoding to the ramping turn. + """ + ampt = amp; + if ramps != 0: + if t <= ramps[0]: + ampt = 0.0; + elif t <= ramps[1]: + ampt = amp * (t - ramps[0]) / (ramps[1] - ramps[0]) + elif t <= ramps[2]: + ampt = amp + elif t <= ramps[3]: + ampt = amp - amp * (t - ramps[2]) / (ramps[3] - ramps[2]) + else: + ampt = 0.0 + return ampt + + def _get_pol(self): + return 0 + + def _check_polynom_values(self, **kwargs): + """ + This function returns the PolynomA and PolynomB + used in tracking. + + Parameters + turns(int): Default 1. Number of turns to calculate. + + """ + turns = kwargs.setdefault('turns',1) + mode = self.Mode + ramps = self.Ramps + ampt = _get_amp(amp[order], ramps, turn) + + for t in range(turns): + if ramps: + # ramp_value = get_amp(amp + ampt = 0 + + + + + + def __init__(self, family_name: str, mode: int, **kwargs): r"""VariableThinMultipole initialization. @@ -63,11 +110,15 @@ def __init__(self, family_name: str, mode: int, **kwargs): on every turn depending on the chosen mode, and for some modes on the particle time delay. All modes could be ramped. - Keep in mind that as this element varies on every turn, any ring - containing a VariableThinMultipole may change after tracking. + Keep in mind that as this element varies on every turn, and at the end of + the tracking PolynomA and PolynomB are set to zero. + + Passing arrays of zeros as amplitude will initialize the MaxOrder to + zero, and the polynom to a single zero. There are three different modes that could be set: SINE = 0, WHITENOISE = 1 and ARBITRARY = 2. See ACMode. + For example, use at.ACMode.SINE or 0 to create an sin function element. The **SINE** mode requires amplitude and frequency for A and/or B. The value of the jth component of the polynom (A or B) at the nth turn @@ -103,7 +154,7 @@ def __init__(self, family_name: str, mode: int, **kwargs): the derivatives wrt \tau, and \tau is the time delay of the particle, i.e. the the sixth coordinate divided by the speed of light. tau could be offset using ``FuncATimeDelay`` or ``FuncBTimeDelay``. - tau = tau + Func[AB]TimeDelay + tau = tau - Func[AB]TimeDelay The function `value` is then **multiplied by Amplitude A and/or B**. For example, the following is a positive vertical kick in the first turn, negative on the second turn, and zero on the third turn. @@ -132,23 +183,23 @@ def __init__(self, family_name: str, mode: int, **kwargs): PhaseB(float): Phase of the sine excitation for PolynomB. Default 0 rad SinAabove(float): Limit the sin function to be above. Default -1. SinBabove(float): Limit the sin function to be above. Default -1. - FuncA(Sequence): User defined tbt list for PolynomA - FuncB(Sequence): User defined tbt list for PolynomB - FuncAderiv1(Sequence): tbt list for PolynomA 1st derivative wrt tau. + FuncA(Sequence[float]): User defined tbt list for PolynomA + FuncB(Sequence[float]): User defined tbt list for PolynomB + FuncAderiv1(Sequence[float]): tbt list for PolynomA 1st derivative wrt tau. Default: zeros array of the custom function length. - FuncBderiv1(Sequence): tbt list for PolynomB 1st derivative wrt tau. + FuncBderiv1(Sequence[float]): tbt list for PolynomB 1st derivative wrt tau. Default: zeros array of the custom function length. - FuncAderiv2(Sequence): tbt list for PolynomA 2st derivative wrt tau. + FuncAderiv2(Sequence[float]): tbt list for PolynomA 2st derivative wrt tau. Default: zeros array of the custom function length. - FuncBderiv2(Sequence): tbt list for PolynomB 2st derivative wrt tau. + FuncBderiv2(Sequence[float]): tbt list for PolynomB 2st derivative wrt tau. Default: zeros array of the custom function length. - FuncAderiv3(Sequence): tbt list for PolynomA 3st derivative wrt tau. + FuncAderiv3(Sequence[float]): tbt list for PolynomA 3st derivative wrt tau. Default: zeros array of the custom function length. - FuncBderiv3(Sequence): tbt list for PolynomB 3st derivative wrt tau. + FuncBderiv3(Sequence[float]): tbt list for PolynomB 3st derivative wrt tau. Default: zeros array of the custom function length. - FuncAderiv4(Sequence): tbt list for PolynomA 4st derivative wrt tau. + FuncAderiv4(Sequence[float]): tbt list for PolynomA 4st derivative wrt tau. Default: zeros array of the custom function length. - FuncBderiv4(Sequence): tbt list for PolynomB 4st derivative wrt tau. + FuncBderiv4(Sequence[float]): tbt list for PolynomB 4st derivative wrt tau. Default: zeros array of the custom function length. FuncATimeDelay(float): generate a time offset on the function FUNCA. It only has an effect if any of the derivatives is not zero. From b97d73d7b058e8855d00fb7f8a7cd6a54b0de081 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 23 Jan 2025 19:16:33 +0100 Subject: [PATCH 112/129] add polynom inspection --- pyat/at/lattice/variable_elements.py | 104 ++++++++++++++++++++++----- 1 file changed, 86 insertions(+), 18 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index ee97f3815..7da9e9b8f 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -52,13 +52,13 @@ class VariableThinMultipole(Element): Periodic=bool, ) - def _get_amp(amp:float, ramps: _array, t: float): + def _get_amp(self, amp:float, ramps: _array, t: float): """get_amp returns the input value `amp` when ramps is False. If ramps is True, it returns a value linearly interpolated accoding to the ramping turn. """ - ampt = amp; + ampt = amp if ramps != 0: if t <= ramps[0]: ampt = 0.0; @@ -72,13 +72,64 @@ def _get_amp(amp:float, ramps: _array, t: float): ampt = 0.0 return ampt - def _get_pol(self): - return 0 + def _get_pol(self, + ab, + ramps, + mode, + t, + turn, + order, + periodic, + ): + allamp = getattr(self, 'Amplitude' + ab) + amp = allamp[order] + ampout = 0 + # check if amp is zero + if amp == 0: + return ampout + + # get the ramp value + ampout = self._get_amp(amp, ramps, turn) + + if mode == 0: + # sin mode parameters + whole_sin_above = getattr(self, 'Sin'+ab+'above') + freq = getattr(self, 'Frequency'+ab) + ph = getattr(self, 'Phase'+ab) + sinval = np.sin(2*np.pi * freq * t + ph) + if sinval >= whole_sin_above: + ampout = ampout * sinval + else: + ampout = 0 + elif mode == 1: + ampout = np.nan + elif mode == 2: + nsamples = getattr(self, 'NSamples'+ab) + if (periodic or turn < nsamples): + func = getattr(self, 'Func'+ab) + funcderiv1 = np.array(getattr(self, 'Func' +ab+'deriv1')) + funcderiv2 = np.array(getattr(self, 'Func' +ab+'deriv2')) + funcderiv3 = np.array(getattr(self, 'Func' +ab+'deriv3')) + funcderiv4 = np.array(getattr(self, 'Func' +ab+'deriv4')) + functdelay = float(getattr(self, 'Func' +ab+'TimeDelay')) + turnidx = np.mod(turn , nsamples) + + t = t - functdelay + t2 = t*t + ampout = ampout*(func[turnidx] \ + + funcderiv1[turnidx]*t \ + + 0.5*funcderiv2[turnidx]*t2 \ + + 1.0/6.0*funcderiv3[turnidx]*t2*t \ + + 1.0/24.0*funcderiv4[turnidx]*t2*t2) + else: + ampout = 0.0 + else: + ampout = 0.0 + return ampout - def _check_polynom_values(self, **kwargs): + def inspect_polynom_values(self, **kwargs): """ - This function returns the PolynomA and PolynomB - used in tracking. + Get the polynom values per turn. Parameters turns(int): Default 1. Number of turns to calculate. @@ -86,17 +137,34 @@ def _check_polynom_values(self, **kwargs): """ turns = kwargs.setdefault('turns',1) mode = self.Mode - ramps = self.Ramps - ampt = _get_amp(amp[order], ramps, turn) - - for t in range(turns): - if ramps: - # ramp_value = get_amp(amp - ampt = 0 - - - - + if mode == 0: + # revolution time + trevol = float(kwargs['T0']) + tparticle = float(kwargs.setdefault('tparticle',0)) + timeoffset = trevol + tparticle + elif mode == 2: + # particle time + timeoffset = float(kwargs.setdefault('tparticle',0)) + ramps = getattr(self,'Ramps',0) + periodic = getattr(self,'Periodic',False) + maxorder = self.MaxOrder + + pola = np.full(maxorder+1,np.nan) + polb = np.full(maxorder+1,np.nan) + + listpola = [] + listpolb = [] + + for turn in range(turns): + for order in range(maxorder+1): + if hasattr(self, 'AmplitudeA'): + pola[order] = self._get_pol( 'A', ramps, mode, timeoffset*turn, turn, order, periodic) + if hasattr(self, 'AmplitudeB'): + polb[order] = self._get_pol( 'B', ramps, mode, timeoffset*turn, turn, order, periodic) + print(order,polb[order]) + listpola.append(np.copy(pola)) + listpolb.append(np.copy(polb)) + return {'PolynomA':listpola,'PolynomB':listpolb} def __init__(self, family_name: str, mode: int, **kwargs): From 8181d19f17f08c48d185f9f99a65d0efa78f47e2 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 23 Jan 2025 19:17:35 +0100 Subject: [PATCH 113/129] black --- pyat/at/lattice/variable_elements.py | 86 +++++++++++++++------------- 1 file changed, 46 insertions(+), 40 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 7da9e9b8f..9d7ced477 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -52,7 +52,7 @@ class VariableThinMultipole(Element): Periodic=bool, ) - def _get_amp(self, amp:float, ramps: _array, t: float): + def _get_amp(self, amp: float, ramps: _array, t: float): """get_amp returns the input value `amp` when ramps is False. If ramps is True, it returns a value linearly interpolated @@ -61,7 +61,7 @@ def _get_amp(self, amp:float, ramps: _array, t: float): ampt = amp if ramps != 0: if t <= ramps[0]: - ampt = 0.0; + ampt = 0.0 elif t <= ramps[1]: ampt = amp * (t - ramps[0]) / (ramps[1] - ramps[0]) elif t <= ramps[2]: @@ -72,7 +72,8 @@ def _get_amp(self, amp:float, ramps: _array, t: float): ampt = 0.0 return ampt - def _get_pol(self, + def _get_pol( + self, ab, ramps, mode, @@ -80,8 +81,8 @@ def _get_pol(self, turn, order, periodic, - ): - allamp = getattr(self, 'Amplitude' + ab) + ): + allamp = getattr(self, "Amplitude" + ab) amp = allamp[order] ampout = 0 # check if amp is zero @@ -93,10 +94,10 @@ def _get_pol(self, if mode == 0: # sin mode parameters - whole_sin_above = getattr(self, 'Sin'+ab+'above') - freq = getattr(self, 'Frequency'+ab) - ph = getattr(self, 'Phase'+ab) - sinval = np.sin(2*np.pi * freq * t + ph) + whole_sin_above = getattr(self, "Sin" + ab + "above") + freq = getattr(self, "Frequency" + ab) + ph = getattr(self, "Phase" + ab) + sinval = np.sin(2 * np.pi * freq * t + ph) if sinval >= whole_sin_above: ampout = ampout * sinval else: @@ -104,23 +105,25 @@ def _get_pol(self, elif mode == 1: ampout = np.nan elif mode == 2: - nsamples = getattr(self, 'NSamples'+ab) - if (periodic or turn < nsamples): - func = getattr(self, 'Func'+ab) - funcderiv1 = np.array(getattr(self, 'Func' +ab+'deriv1')) - funcderiv2 = np.array(getattr(self, 'Func' +ab+'deriv2')) - funcderiv3 = np.array(getattr(self, 'Func' +ab+'deriv3')) - funcderiv4 = np.array(getattr(self, 'Func' +ab+'deriv4')) - functdelay = float(getattr(self, 'Func' +ab+'TimeDelay')) - turnidx = np.mod(turn , nsamples) + nsamples = getattr(self, "NSamples" + ab) + if periodic or turn < nsamples: + func = getattr(self, "Func" + ab) + funcderiv1 = np.array(getattr(self, "Func" + ab + "deriv1")) + funcderiv2 = np.array(getattr(self, "Func" + ab + "deriv2")) + funcderiv3 = np.array(getattr(self, "Func" + ab + "deriv3")) + funcderiv4 = np.array(getattr(self, "Func" + ab + "deriv4")) + functdelay = float(getattr(self, "Func" + ab + "TimeDelay")) + turnidx = np.mod(turn, nsamples) t = t - functdelay - t2 = t*t - ampout = ampout*(func[turnidx] \ - + funcderiv1[turnidx]*t \ - + 0.5*funcderiv2[turnidx]*t2 \ - + 1.0/6.0*funcderiv3[turnidx]*t2*t \ - + 1.0/24.0*funcderiv4[turnidx]*t2*t2) + t2 = t * t + ampout = ampout * ( + func[turnidx] + + funcderiv1[turnidx] * t + + 0.5 * funcderiv2[turnidx] * t2 + + 1.0 / 6.0 * funcderiv3[turnidx] * t2 * t + + 1.0 / 24.0 * funcderiv4[turnidx] * t2 * t2 + ) else: ampout = 0.0 else: @@ -135,37 +138,40 @@ def inspect_polynom_values(self, **kwargs): turns(int): Default 1. Number of turns to calculate. """ - turns = kwargs.setdefault('turns',1) + turns = kwargs.setdefault("turns", 1) mode = self.Mode if mode == 0: # revolution time - trevol = float(kwargs['T0']) - tparticle = float(kwargs.setdefault('tparticle',0)) + trevol = float(kwargs["T0"]) + tparticle = float(kwargs.setdefault("tparticle", 0)) timeoffset = trevol + tparticle elif mode == 2: # particle time - timeoffset = float(kwargs.setdefault('tparticle',0)) - ramps = getattr(self,'Ramps',0) - periodic = getattr(self,'Periodic',False) + timeoffset = float(kwargs.setdefault("tparticle", 0)) + ramps = getattr(self, "Ramps", 0) + periodic = getattr(self, "Periodic", False) maxorder = self.MaxOrder - pola = np.full(maxorder+1,np.nan) - polb = np.full(maxorder+1,np.nan) + pola = np.full(maxorder + 1, np.nan) + polb = np.full(maxorder + 1, np.nan) listpola = [] listpolb = [] for turn in range(turns): - for order in range(maxorder+1): - if hasattr(self, 'AmplitudeA'): - pola[order] = self._get_pol( 'A', ramps, mode, timeoffset*turn, turn, order, periodic) - if hasattr(self, 'AmplitudeB'): - polb[order] = self._get_pol( 'B', ramps, mode, timeoffset*turn, turn, order, periodic) - print(order,polb[order]) + for order in range(maxorder + 1): + if hasattr(self, "AmplitudeA"): + pola[order] = self._get_pol( + "A", ramps, mode, timeoffset * turn, turn, order, periodic + ) + if hasattr(self, "AmplitudeB"): + polb[order] = self._get_pol( + "B", ramps, mode, timeoffset * turn, turn, order, periodic + ) + print(order, polb[order]) listpola.append(np.copy(pola)) listpolb.append(np.copy(polb)) - return {'PolynomA':listpola,'PolynomB':listpolb} - + return {"PolynomA": listpola, "PolynomB": listpolb} def __init__(self, family_name: str, mode: int, **kwargs): r"""VariableThinMultipole initialization. From 07c12900661f7da762db8b023e38eb76ac2603ad Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Thu, 23 Jan 2025 20:02:52 +0100 Subject: [PATCH 114/129] help docstring --- pyat/at/lattice/variable_elements.py | 46 ++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 9d7ced477..0933fd6d1 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -57,6 +57,15 @@ def _get_amp(self, amp: float, ramps: _array, t: float): If ramps is True, it returns a value linearly interpolated accoding to the ramping turn. + + Parameters + amp: amplitude component. + ramps: array containing the turns that define the ramp + t: turn + + Returns + amp if no ramp. + amp multiplied by the ramp state. """ ampt = amp if ramps != 0: @@ -74,14 +83,29 @@ def _get_amp(self, amp: float, ramps: _array, t: float): def _get_pol( self, - ab, - ramps, - mode, - t, - turn, - order, - periodic, + ab: str, + ramps: _array, + mode: int, + t: float, + turn: int, + order: int, + periodic: bool, ): + """ + Return the polynom component of a given order. + + Parameters + ab: either 'A' or 'B' indicating the polynom. + ramps: array containing the ramp definition. + mode: value to specify the type of variable element. + t: time for this mode + turn: turn to check + order: order of the polynom + periodic: whether the sequence is periodic or not. + + Returns + the amplitude for the polynom component + """ allamp = getattr(self, "Amplitude" + ab) amp = allamp[order] ampout = 0 @@ -134,9 +158,13 @@ def inspect_polynom_values(self, **kwargs): """ Get the polynom values per turn. - Parameters - turns(int): Default 1. Number of turns to calculate. + Keyword arguments + turns(int): Default 1. Number of turns to calculate. + T0(float): revolution time in seconds. Use only in SINE mode. + tparticle(float): Default 0. Time of the particle in seconds. + Returns + Dictionary with a list of PolynomA and PolynomB per turn. """ turns = kwargs.setdefault("turns", 1) mode = self.Mode From d03522b29e2c16958bed53b03dbf5f3cb53718dd Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 13:00:01 +0100 Subject: [PATCH 115/129] fix phase and Sinabove parameters --- atmat/lattice/element_creation/atvariablethinmultipole.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/atmat/lattice/element_creation/atvariablethinmultipole.m b/atmat/lattice/element_creation/atvariablethinmultipole.m index 1b04a53f1..567c9f73f 100644 --- a/atmat/lattice/element_creation/atvariablethinmultipole.m +++ b/atmat/lattice/element_creation/atvariablethinmultipole.m @@ -167,10 +167,14 @@ 'PolynomA',[],'PolynomB',[],rsrc{:}); - function setsine(rsrc, ab) + function rsrc = setsine(rsrc, ab) if ~isfield(rsrc,strcat('Frequency',ab)) error(strcat('Please provide a value for Frequency',ab)) end + funcarg=strcat('Phase',ab); + if ~isfield(rsrc,funcarg) + rsrc.(funcarg) = 0; + end funcarg=strcat('Sin',ab,'above'); if ~isfield(rsrc,funcarg) rsrc.(funcarg) = -1; @@ -200,7 +204,7 @@ function setsine(rsrc, ab) amplarg=strcat('Amplitude',ab); if isfield(rsrc,amplarg) if strcmpi(mode,'SINE') - setsine(rsrc,ab); + rsrc = setsine(rsrc,ab); end if strcmpi(mode,'ARBITRARY') rsrc = setarb(rsrc,ab); From 37746560b0f801c5b163f771786744019912a834 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 13:02:35 +0100 Subject: [PATCH 116/129] adds atmat/atutils/atinspectvariablethinmultipole.m --- .../atutils/atinspectvariablethinmultipole.m | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 atmat/atutils/atinspectvariablethinmultipole.m diff --git a/atmat/atutils/atinspectvariablethinmultipole.m b/atmat/atutils/atinspectvariablethinmultipole.m new file mode 100644 index 000000000..afdc3f878 --- /dev/null +++ b/atmat/atutils/atinspectvariablethinmultipole.m @@ -0,0 +1,152 @@ +function [listpola,listpolb] = atinspectvariablethinmultipole(element,varargin) +% [pola_array,polb_array] = atinspectvariablethinmultipole(element) +% +% Get the atvariablethinmultipole polynom values per turn. +% +% Keyword arguments +% turns(int): Default 1. Number of turns to calculate. +% T0(float): revolution time in seconds. Use only in SINE mode. +% tparticle(float): Default 0. Time of the particle in seconds. +% +% Returns +% Two cell arrays with the values of PolynomA and PolynomB per turn. + p = inputParser; + addOptional(p,'turns',1,@(x) isnumeric(x) && isscalar(x) && (x > 0)); + addOptional(p,'T0',0,@(x) isnumeric(x) && isscalar(x) && (x > 0)); + addOptional(p,'tparticle',0,@(x) isnumeric(x) && isscalar(x) && (x > 0)); + parse(p,varargin{:}); + par = p.Results; + + turns = par.turns; + T0 = par.T0; + tparticle = par.tparticle; + mode = element.Mode; + + switch mode + case 0 + % revolution time + timeoffset = T0 + tparticle; + case 2 + % particle time + timeoffset = tparticle; + otherwise + timeoffset = 0; + end + + if isfield(element,'Ramps') + ramps = element.Ramps; + else + ramps = 0; + end + + if isfield(element,'Periodic') + periodic = element.Periodic; + else + periodic = 0; + end + + maxorder = element.MaxOrder; + + pola = nan(1,maxorder+1); + polb = nan(1,maxorder+1); + + listpola = cell(1, turns); + listpolb = cell(1, turns); + + for turn = 0:turns-1 + for order = 0:maxorder + if isfield(element,'AmplitudeA') + pola(order+1) = get_pol(element, 'A', ramps, mode, ... + timeoffset * turn, turn, order, periodic); + end + if isfield(element,'AmplitudeB') + pola(order+1) = get_pol(element, 'B', ramps, mode, ... + timeoffset * turn, turn, order, periodic); + end + listpola{turn+1} = pola; + listpolb{turn+1} = polb; + end + end + +end + +function ampt = get_amp(amp, ramps, t) +% get_amp(ele, amp, ramps, t) +% +% get_amp returns the input value `amp` when ramps is False. +% If ramps is True, it returns a value linearly interpolated +% accoding to the ramping turn. + ampt = amp; + if length(ramps) == 4 + if t <= ramps(0) + ampt = 0.0; + elseif t <= ramps(1) + ampt = amp * (t - ramps(0)) / (ramps(1) - ramps(0)); + elseif t <= ramps(2) + ampt = amp; + elseif t <= ramps(3) + ampt = amp - amp * (t - ramps(2))/ (ramps(3) - ramps(2)); + else + ampt = 0.0; + end + end +end + + +function ampout = get_pol(element , ab, ramps, mode, t, turn, order, periodic) +% get_pol(element , ab, ramps, mode, t, turn, order, periodic) +% +% get_pol returns the polynom a or b for a given mode, turn, order, +% time and periodicity. + allamp = element.(strcat("Amplitude",ab) ); + amp = allamp(order+1); + ampout = 0; + + if amp == 0 + return + end + + % get the ramp value + ampoutaux = get_amp(amp, ramps, turn); + + switch mode + case 0 + % sin mode parameters + whole_sin_above = element.(strcat("Sin",ab,"above")); + freq = element.(strcat("Frequency",ab)); + ph = element.(strcat("Phase",ab)); + sinval = sin(2 * pi * freq * t + ph); + if sinval >= whole_sin_above + ampout = ampoutaux * sinval; + else + ampout = 0; + end + case 1 + ampout = nan; + case 2 + nsamples = element.(strcat("NSamples",ab)); + if periodic || turn < nsamples + func = element.(strcat("Func",ab)); + funcderiv1 = element.(strcat("Func",ab,"deriv1") ); + funcderiv2 = element.(strcat("Func",ab,"deriv2") ); + funcderiv3 = element.(strcat("Func",ab,"deriv3") ); + funcderiv4 = element.(strcat("Func",ab,"deriv4") ); + functdelay = element.(strcat("Func",ab,"TimeDelay") ); + turnidx = mod(turn, nsamples); + + t = t - functdelay; + t2 = t * t; + ampout = ampoutaux * ( ... + func(turnidx) ... + + funcderiv1(turnidx) * t ... + + 0.5 * funcderiv2(turnidx) * t2 ... + + 1.0 / 6.0 * funcderiv3(turnidx) * t2 * t ... + + 1.0 / 24.0 * funcderiv4(turnidx) * t2 * t2 ... + ); + else + ampout = 0.0; + end + otherwise + ampout = 0.0; + end +end From 500b0a9ee1539a8ad7c148f9ce4923827daec34d Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 13:37:11 +0100 Subject: [PATCH 117/129] fixing T0 --- atmat/atutils/atinspectvariablethinmultipole.m | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/atmat/atutils/atinspectvariablethinmultipole.m b/atmat/atutils/atinspectvariablethinmultipole.m index afdc3f878..3a0b23a57 100644 --- a/atmat/atutils/atinspectvariablethinmultipole.m +++ b/atmat/atutils/atinspectvariablethinmultipole.m @@ -12,8 +12,13 @@ % Two cell arrays with the values of PolynomA and PolynomB per turn. p = inputParser; addOptional(p,'turns',1,@(x) isnumeric(x) && isscalar(x) && (x > 0)); - addOptional(p,'T0',0,@(x) isnumeric(x) && isscalar(x) && (x > 0)); - addOptional(p,'tparticle',0,@(x) isnumeric(x) && isscalar(x) && (x > 0)); + if element.Mode == 0 + if ~any(strcmp(varargin,'T0')) + error('T0 is required.'); + end + addOptional(p,'T0',0,@(x) isnumeric(x) && (x > 0)); + end + addOptional(p,'tparticle',0,@(x) isnumeric(x)); parse(p,varargin{:}); par = p.Results; From d0fcb9b99cc3a9c9afeee2d89aaff3d903f0a26d Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 14:33:16 +0100 Subject: [PATCH 118/129] fix custom element --- atmat/atutils/atinspectvariablethinmultipole.m | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/atmat/atutils/atinspectvariablethinmultipole.m b/atmat/atutils/atinspectvariablethinmultipole.m index 3a0b23a57..c16294b15 100644 --- a/atmat/atutils/atinspectvariablethinmultipole.m +++ b/atmat/atutils/atinspectvariablethinmultipole.m @@ -23,7 +23,11 @@ par = p.Results; turns = par.turns; - T0 = par.T0; + if element.Mode == 0 + T0 = par.T0; + else + T0 = 0; + end tparticle = par.tparticle; mode = element.Mode; @@ -137,7 +141,7 @@ funcderiv3 = element.(strcat("Func",ab,"deriv3") ); funcderiv4 = element.(strcat("Func",ab,"deriv4") ); functdelay = element.(strcat("Func",ab,"TimeDelay") ); - turnidx = mod(turn, nsamples); + turnidx = mod(turn, nsamples)+1; t = t - functdelay; t2 = t * t; From 0c94dda1e46f533173269b0b6dbb727a320d3d32 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 14:38:10 +0100 Subject: [PATCH 119/129] add default timeoffset --- pyat/at/lattice/variable_elements.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 0933fd6d1..ff5953f55 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -168,6 +168,7 @@ def inspect_polynom_values(self, **kwargs): """ turns = kwargs.setdefault("turns", 1) mode = self.Mode + timeoffset = 0 if mode == 0: # revolution time trevol = float(kwargs["T0"]) From 01f09d9408c89fc510effc38383d25dc7e5fc2a8 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 14:47:45 +0100 Subject: [PATCH 120/129] fix help message --- .../atutils/atinspectvariablethinmultipole.m | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/atmat/atutils/atinspectvariablethinmultipole.m b/atmat/atutils/atinspectvariablethinmultipole.m index c16294b15..51026dc05 100644 --- a/atmat/atutils/atinspectvariablethinmultipole.m +++ b/atmat/atutils/atinspectvariablethinmultipole.m @@ -1,15 +1,17 @@ function [listpola,listpolb] = atinspectvariablethinmultipole(element,varargin) -% [pola_array,polb_array] = atinspectvariablethinmultipole(element) +% [pola_array,polb_array] = ATINSPECTVARIABLETHINMULTIPOLE(element) % -% Get the atvariablethinmultipole polynom values per turn. +% Get the ATVARIABLETHINMULTIPOLE polynom values per turn. % -% Keyword arguments -% turns(int): Default 1. Number of turns to calculate. -% T0(float): revolution time in seconds. Use only in SINE mode. -% tparticle(float): Default 0. Time of the particle in seconds. +% ARGUMENTS: +% element: an atvariablethinmultipole element. +% OPTIONAL ARGUMENTS: +% turns(int): Default 1. Number of turns to calculate. +% T0(float): revolution time in seconds. Only needed in SINE mode. +% tparticle(float): Default 0. Time of the particle in seconds. % -% Returns -% Two cell arrays with the values of PolynomA and PolynomB per turn. +% RETURNS +% Two cell arrays with the values of PolynomA and PolynomB per turn. p = inputParser; addOptional(p,'turns',1,@(x) isnumeric(x) && isscalar(x) && (x > 0)); if element.Mode == 0 @@ -21,7 +23,7 @@ addOptional(p,'tparticle',0,@(x) isnumeric(x)); parse(p,varargin{:}); par = p.Results; - + turns = par.turns; if element.Mode == 0 T0 = par.T0; @@ -30,7 +32,7 @@ end tparticle = par.tparticle; mode = element.Mode; - + switch mode case 0 % revolution time @@ -41,27 +43,27 @@ otherwise timeoffset = 0; end - + if isfield(element,'Ramps') ramps = element.Ramps; else ramps = 0; end - + if isfield(element,'Periodic') periodic = element.Periodic; else periodic = 0; end - + maxorder = element.MaxOrder; - + pola = nan(1,maxorder+1); polb = nan(1,maxorder+1); - + listpola = cell(1, turns); listpolb = cell(1, turns); - + for turn = 0:turns-1 for order = 0:maxorder if isfield(element,'AmplitudeA') From 90242458c9845335d9d64a4721da3c14d47e8559 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 14:50:01 +0100 Subject: [PATCH 121/129] add help message --- atmat/lattice/element_creation/atvariablethinmultipole.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atmat/lattice/element_creation/atvariablethinmultipole.m b/atmat/lattice/element_creation/atvariablethinmultipole.m index 567c9f73f..51c7c350c 100644 --- a/atmat/lattice/element_creation/atvariablethinmultipole.m +++ b/atmat/lattice/element_creation/atvariablethinmultipole.m @@ -141,8 +141,9 @@ % by default the array is assumed non periodic. The function has % no effect on the particle in turns exceeding the function definition. % If Periodic is set to True, the sequence is repeated. - % +% See also: +% ATINSPECTVARIABLETHINMULTIPOLE % Input parser for option [method,rsrc]=getargs(varargin,'VariableThinMPolePass', ... From ec7da173e4a9f42f3ada8ab90a4600e4e5329c9c Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 14:50:17 +0100 Subject: [PATCH 122/129] add to help message --- atmat/atutils/atinspectvariablethinmultipole.m | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/atmat/atutils/atinspectvariablethinmultipole.m b/atmat/atutils/atinspectvariablethinmultipole.m index 51026dc05..f4be3a75e 100644 --- a/atmat/atutils/atinspectvariablethinmultipole.m +++ b/atmat/atutils/atinspectvariablethinmultipole.m @@ -12,6 +12,10 @@ % % RETURNS % Two cell arrays with the values of PolynomA and PolynomB per turn. +% +% See Also: +% ATVARIABLETHINMULTIPOLE +% p = inputParser; addOptional(p,'turns',1,@(x) isnumeric(x) && isscalar(x) && (x > 0)); if element.Mode == 0 From bcd928b4a0fc8928f1e979b97a1a15dbc1eb9d83 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 14:54:57 +0100 Subject: [PATCH 123/129] add T1,T2,R1,R2 comment in help message --- atmat/atutils/atinspectvariablethinmultipole.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/atmat/atutils/atinspectvariablethinmultipole.m b/atmat/atutils/atinspectvariablethinmultipole.m index f4be3a75e..67b47de5d 100644 --- a/atmat/atutils/atinspectvariablethinmultipole.m +++ b/atmat/atutils/atinspectvariablethinmultipole.m @@ -3,6 +3,8 @@ % % Get the ATVARIABLETHINMULTIPOLE polynom values per turn. % +% Translations (T1,T2) and rotations (R1,R2) in the element are ignored. +% % ARGUMENTS: % element: an atvariablethinmultipole element. % OPTIONAL ARGUMENTS: From 5c9d75e60eb838049ad17d0f36583f4839ad3735 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 14:56:09 +0100 Subject: [PATCH 124/129] add to help --- atmat/lattice/element_creation/atvariablethinmultipole.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/atmat/lattice/element_creation/atvariablethinmultipole.m b/atmat/lattice/element_creation/atvariablethinmultipole.m index 51c7c350c..76f25ce60 100644 --- a/atmat/lattice/element_creation/atvariablethinmultipole.m +++ b/atmat/lattice/element_creation/atvariablethinmultipole.m @@ -142,6 +142,9 @@ % no effect on the particle in turns exceeding the function definition. % If Periodic is set to True, the sequence is repeated. % +% One could use the method inspect_polynom_values to check the polynom values +% used in every turn. +% % See also: % ATINSPECTVARIABLETHINMULTIPOLE From cddca24e42f536916af7d6f654ce0cf5aade0323 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 14:56:22 +0100 Subject: [PATCH 125/129] add to help --- pyat/at/lattice/variable_elements.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index ff5953f55..72212d2b7 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -158,6 +158,8 @@ def inspect_polynom_values(self, **kwargs): """ Get the polynom values per turn. + Translations (T1,T2) and Rotations (R1,R2) in the element are ignored. + Keyword arguments turns(int): Default 1. Number of turns to calculate. T0(float): revolution time in seconds. Use only in SINE mode. @@ -267,6 +269,9 @@ def __init__(self, family_name: str, mode: int, **kwargs): on the particle in turns exceeding the function definition. If ``Periodic`` is set to True, the sequence is repeated. + One could use the method inspect_polynom_values to check the polynom values + used in every turn. + Parameters: family_name(str): Element name From ef840e57b825d0bd0bb001a3674505f2351e7773 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 14:59:30 +0100 Subject: [PATCH 126/129] fixing flake8 --- pyat/at/lattice/variable_elements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 72212d2b7..2b23130ee 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -181,7 +181,7 @@ def inspect_polynom_values(self, **kwargs): timeoffset = float(kwargs.setdefault("tparticle", 0)) ramps = getattr(self, "Ramps", 0) periodic = getattr(self, "Periodic", False) - maxorder = self.MaxOrder + maxorder = getattr(self, "MaxOrder") pola = np.full(maxorder + 1, np.nan) polb = np.full(maxorder + 1, np.nan) From 9b2280e93860c51b101d58645855118a21c3d8bd Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 15:00:10 +0100 Subject: [PATCH 127/129] fixing flake8 --- pyat/at/lattice/variable_elements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 2b23130ee..304c636fb 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -169,7 +169,7 @@ def inspect_polynom_values(self, **kwargs): Dictionary with a list of PolynomA and PolynomB per turn. """ turns = kwargs.setdefault("turns", 1) - mode = self.Mode + mode = getattr(self, "Mode") timeoffset = 0 if mode == 0: # revolution time From 2f7549d940c8f4adb27abd942fda11da0481c183 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 15:29:13 +0100 Subject: [PATCH 128/129] fixing flake8 --- pyat/at/lattice/variable_elements.py | 309 +++++++++++++-------------- 1 file changed, 154 insertions(+), 155 deletions(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index 304c636fb..a75585745 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -2,7 +2,6 @@ from __future__ import annotations -from collections.abc import Sequence from enum import IntEnum from typing import Any @@ -52,159 +51,7 @@ class VariableThinMultipole(Element): Periodic=bool, ) - def _get_amp(self, amp: float, ramps: _array, t: float): - """get_amp returns the input value `amp` when ramps is False. - - If ramps is True, it returns a value linearly interpolated - accoding to the ramping turn. - - Parameters - amp: amplitude component. - ramps: array containing the turns that define the ramp - t: turn - - Returns - amp if no ramp. - amp multiplied by the ramp state. - """ - ampt = amp - if ramps != 0: - if t <= ramps[0]: - ampt = 0.0 - elif t <= ramps[1]: - ampt = amp * (t - ramps[0]) / (ramps[1] - ramps[0]) - elif t <= ramps[2]: - ampt = amp - elif t <= ramps[3]: - ampt = amp - amp * (t - ramps[2]) / (ramps[3] - ramps[2]) - else: - ampt = 0.0 - return ampt - - def _get_pol( - self, - ab: str, - ramps: _array, - mode: int, - t: float, - turn: int, - order: int, - periodic: bool, - ): - """ - Return the polynom component of a given order. - - Parameters - ab: either 'A' or 'B' indicating the polynom. - ramps: array containing the ramp definition. - mode: value to specify the type of variable element. - t: time for this mode - turn: turn to check - order: order of the polynom - periodic: whether the sequence is periodic or not. - - Returns - the amplitude for the polynom component - """ - allamp = getattr(self, "Amplitude" + ab) - amp = allamp[order] - ampout = 0 - # check if amp is zero - if amp == 0: - return ampout - - # get the ramp value - ampout = self._get_amp(amp, ramps, turn) - - if mode == 0: - # sin mode parameters - whole_sin_above = getattr(self, "Sin" + ab + "above") - freq = getattr(self, "Frequency" + ab) - ph = getattr(self, "Phase" + ab) - sinval = np.sin(2 * np.pi * freq * t + ph) - if sinval >= whole_sin_above: - ampout = ampout * sinval - else: - ampout = 0 - elif mode == 1: - ampout = np.nan - elif mode == 2: - nsamples = getattr(self, "NSamples" + ab) - if periodic or turn < nsamples: - func = getattr(self, "Func" + ab) - funcderiv1 = np.array(getattr(self, "Func" + ab + "deriv1")) - funcderiv2 = np.array(getattr(self, "Func" + ab + "deriv2")) - funcderiv3 = np.array(getattr(self, "Func" + ab + "deriv3")) - funcderiv4 = np.array(getattr(self, "Func" + ab + "deriv4")) - functdelay = float(getattr(self, "Func" + ab + "TimeDelay")) - turnidx = np.mod(turn, nsamples) - - t = t - functdelay - t2 = t * t - ampout = ampout * ( - func[turnidx] - + funcderiv1[turnidx] * t - + 0.5 * funcderiv2[turnidx] * t2 - + 1.0 / 6.0 * funcderiv3[turnidx] * t2 * t - + 1.0 / 24.0 * funcderiv4[turnidx] * t2 * t2 - ) - else: - ampout = 0.0 - else: - ampout = 0.0 - return ampout - - def inspect_polynom_values(self, **kwargs): - """ - Get the polynom values per turn. - - Translations (T1,T2) and Rotations (R1,R2) in the element are ignored. - - Keyword arguments - turns(int): Default 1. Number of turns to calculate. - T0(float): revolution time in seconds. Use only in SINE mode. - tparticle(float): Default 0. Time of the particle in seconds. - - Returns - Dictionary with a list of PolynomA and PolynomB per turn. - """ - turns = kwargs.setdefault("turns", 1) - mode = getattr(self, "Mode") - timeoffset = 0 - if mode == 0: - # revolution time - trevol = float(kwargs["T0"]) - tparticle = float(kwargs.setdefault("tparticle", 0)) - timeoffset = trevol + tparticle - elif mode == 2: - # particle time - timeoffset = float(kwargs.setdefault("tparticle", 0)) - ramps = getattr(self, "Ramps", 0) - periodic = getattr(self, "Periodic", False) - maxorder = getattr(self, "MaxOrder") - - pola = np.full(maxorder + 1, np.nan) - polb = np.full(maxorder + 1, np.nan) - - listpola = [] - listpolb = [] - - for turn in range(turns): - for order in range(maxorder + 1): - if hasattr(self, "AmplitudeA"): - pola[order] = self._get_pol( - "A", ramps, mode, timeoffset * turn, turn, order, periodic - ) - if hasattr(self, "AmplitudeB"): - polb[order] = self._get_pol( - "B", ramps, mode, timeoffset * turn, turn, order, periodic - ) - print(order, polb[order]) - listpola.append(np.copy(pola)) - listpolb.append(np.copy(polb)) - return {"PolynomA": listpola, "PolynomB": listpolb} - - def __init__(self, family_name: str, mode: int, **kwargs): + def __init__(self, family_name: str, mode: int or ACMode, **kwargs): r"""VariableThinMultipole initialization. Default pass method: ``VariableThinMPolePass``. @@ -275,7 +122,7 @@ def __init__(self, family_name: str, mode: int, **kwargs): Parameters: family_name(str): Element name - mode(ACMode): defines the mode. Default ACMode.SINE: + mode(at.ACMode): defines the mode. Default ACMode.SINE: * :py:attr:`.ACMode.SINE`: sine function * :py:attr:`.ACMode.WHITENOISE`: gaussian white noise @@ -417,3 +264,155 @@ def _check_ramp(**kwargs) -> _array: if ramps is not None: kwargs["Ramps"] = ramps super().__init__(family_name, **kwargs) + + def inspect_polynom_values(self, **kwargs) -> dict[str, list]: + """ + Get the polynom values per turn. + + Translations (T1,T2) and Rotations (R1,R2) in the element are ignored. + + Keyword arguments: + turns(int): Default 1. Number of turns to calculate. + T0(float): revolution time in seconds. Use only in SINE mode. + tparticle(float): Default 0. Time of the particle in seconds. + + Returns: + Dictionary with a list of PolynomA and PolynomB per turn. + """ + turns = kwargs.setdefault("turns", 1) + mode = self.Mode + timeoffset = 0 + if mode == 0: + # revolution time + trevol = float(kwargs["T0"]) + tparticle = float(kwargs.setdefault("tparticle", 0)) + timeoffset = trevol + tparticle + elif mode == 2: + # particle time + timeoffset = float(kwargs.setdefault("tparticle", 0)) + ramps = getattr(self, "Ramps", 0) + periodic = getattr(self, "Periodic", False) + maxorder = self.MaxOrder + + pola = np.full(maxorder + 1, np.nan) + polb = np.full(maxorder + 1, np.nan) + + listpola = [] + listpolb = [] + + for turn in range(turns): + for order in range(maxorder + 1): + if hasattr(self, "AmplitudeA"): + pola[order] = self._get_pol( + "A", ramps, mode, timeoffset * turn, turn, order, periodic + ) + if hasattr(self, "AmplitudeB"): + polb[order] = self._get_pol( + "B", ramps, mode, timeoffset * turn, turn, order, periodic + ) + print(order, polb[order]) + listpola.append(np.copy(pola)) + listpolb.append(np.copy(polb)) + return {"PolynomA": listpola, "PolynomB": listpolb} + + def _get_amp(self, amp: float, ramps: _array, _time: float) -> float: + """get_amp returns the input value `amp` when ramps is False. + + If ramps is True, it returns a value linearly interpolated + accoding to the ramping turn. + + Parameters: + amp: amplitude component. + ramps: array containing the turns that define the ramp + _time: turn + + Returns: + amp if no ramp. + amp multiplied by the ramp state. + """ + ampt = amp + if ramps != 0: + if _time <= ramps[0]: + ampt = 0.0 + elif _time <= ramps[1]: + ampt = amp * (_time - ramps[0]) / (ramps[1] - ramps[0]) + elif _time <= ramps[2]: + ampt = amp + elif _time <= ramps[3]: + ampt = amp - amp * (_time - ramps[2]) / (ramps[3] - ramps[2]) + else: + ampt = 0.0 + return ampt + + def _get_pol( + self, + a_b: str, + ramps: _array, + mode: int, + _time: float, + turn: int, + order: int, + periodic: bool, + ) -> float: + """ + Return the polynom component of a given order. + + Parameters: + a_b: either 'A' or 'B' indicating the polynom. + ramps: array containing the ramp definition. + mode: value to specify the type of variable element. + _time: time for this mode + turn: turn to check + order: order of the polynom + periodic: whether the sequence is periodic or not. + + Returns: + the amplitude for the polynom component + """ + allamp = getattr(self, "Amplitude" + a_b) + amp = allamp[order] + ampout = 0 + # check if amp is zero + if amp == 0: + return ampout + + # get the ramp value + ampout = self._get_amp(amp, ramps, turn) + + if mode == 0: + # sin mode parameters + whole_sin_above = getattr(self, "Sin" + a_b + "above") + freq = getattr(self, "Frequency" + a_b) + phase = getattr(self, "Phase" + a_b) + sinval = np.sin(2 * np.pi * freq * _time + phase) + if sinval >= whole_sin_above: + ampout = ampout * sinval + else: + ampout = 0 + elif mode == 1: + ampout = np.nan + elif mode == 2: + nsamples = getattr(self, "NSamples" + a_b) + if periodic or turn < nsamples: + func = getattr(self, "Func" + a_b) + funcderiv1 = np.array(getattr(self, "Func" + a_b + "deriv1")) + funcderiv2 = np.array(getattr(self, "Func" + a_b + "deriv2")) + funcderiv3 = np.array(getattr(self, "Func" + a_b + "deriv3")) + funcderiv4 = np.array(getattr(self, "Func" + a_b + "deriv4")) + functdelay = float(getattr(self, "Func" + a_b + "TimeDelay")) + turnidx = np.mod(turn, nsamples) + + _time = _time - functdelay + _time_2 = _time * _time + ampout = ampout * ( + func[turnidx] + + funcderiv1[turnidx] * _time + + 0.5 * funcderiv2[turnidx] * _time_2 + + 1.0 / 6.0 * funcderiv3[turnidx] * _time_2 * _time + + 1.0 / 24.0 * funcderiv4[turnidx] * _time_2 * _time_2 + ) + else: + ampout = 0.0 + else: + ampout = 0.0 + return ampout From 49e70ad3ec4468e177868f2309e12f22769aef02 Mon Sep 17 00:00:00 2001 From: oscarxblanco Date: Tue, 28 Jan 2025 15:51:11 +0100 Subject: [PATCH 129/129] remove debug --- pyat/at/lattice/variable_elements.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyat/at/lattice/variable_elements.py b/pyat/at/lattice/variable_elements.py index a75585745..411cdf647 100644 --- a/pyat/at/lattice/variable_elements.py +++ b/pyat/at/lattice/variable_elements.py @@ -310,7 +310,6 @@ def inspect_polynom_values(self, **kwargs) -> dict[str, list]: polb[order] = self._get_pol( "B", ramps, mode, timeoffset * turn, turn, order, periodic ) - print(order, polb[order]) listpola.append(np.copy(pola)) listpolb.append(np.copy(polb)) return {"PolynomA": listpola, "PolynomB": listpolb}