From 9d2f2dc9e6eb156989bc555b08b40d7f52a2aa5c Mon Sep 17 00:00:00 2001 From: Laurent Farvacque Date: Wed, 15 Jun 2022 14:05:05 +0200 Subject: [PATCH 1/2] define and use the frequency_control decorator. --- pyat/at/acceptance/acceptance.py | 7 +++-- pyat/at/acceptance/boundary.py | 14 +++------- pyat/at/physics/revolution.py | 45 ++++++++++++++++++++++++++------ 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/pyat/at/acceptance/acceptance.py b/pyat/at/acceptance/acceptance.py index 7092ac954..2ef5b1ab2 100644 --- a/pyat/at/acceptance/acceptance.py +++ b/pyat/at/acceptance/acceptance.py @@ -1,21 +1,24 @@ import numpy from .boundary import GridMode +# noinspection PyProtectedMember from .boundary import boundary_search import multiprocessing from ..lattice import Lattice +from ..physics import frequency_control __all__ = ['get_acceptance', 'get_1d_acceptance', 'get_horizontal_acceptance', 'get_vertical_acceptance', 'get_momentum_acceptance'] +@frequency_control def get_acceptance(ring, planes, npoints, amplitudes, nturns=1024, refpts=None, dp=None, offset=None, bounds=None, grid_mode=GridMode.RADIAL, use_mp=False, verbose=True, start_method=None, divider=2, shift_zero=1.0e-9): """ Computes the acceptance at repfts observation points - Grid Coordiantes ordering is as follows: CARTESIAN: (x,y), RADIAL/RECURSIVE + Grid Coordinates ordering is as follows: CARTESIAN: (x,y), RADIAL/RECURSIVE (r, theta). Scalar inputs can be used for 1D grid. The grid can be changed using grid_mode input: at.GridMode.CARTESIAN: (x,y) grid @@ -192,7 +195,7 @@ def get_1d_acceptance(ring, plane, resolution, amplitude, nturns=1024, dp=None, nturns=nturns, dp=dp, refpts=refpts, grid_mode=grid_mode, use_mp=use_mp, verbose=verbose, start_method=start_method, - divider=2, shift_zero=0.0) + divider=divider, shift_zero=0.0) return numpy.squeeze(b), s, g diff --git a/pyat/at/acceptance/boundary.py b/pyat/at/acceptance/boundary.py index 98a781b7b..d0bfa148d 100644 --- a/pyat/at/acceptance/boundary.py +++ b/pyat/at/acceptance/boundary.py @@ -4,12 +4,10 @@ grid definitions """ -import at from at.lattice import AtError from at.tracking import lattice_pass, patpass from enum import Enum import numpy -import warnings from scipy.ndimage import binary_dilation, binary_opening from collections import namedtuple import time @@ -79,20 +77,14 @@ def set_ring_orbit(ring, dp, obspt, orbit): Returns a ring starting at obspt and initial closed orbit """ - if ring.radiation: - newring = ring.set_rf_frequency(dp=dp, copy=True) - dp = None - else: - newring = ring - if obspt is not None: assert numpy.isscalar(obspt), 'Scalar value needed for obspt' - newring = newring.rotate(obspt) + ring = ring.rotate(obspt) if orbit is None: - orbit, _ = newring.find_orbit(dp=dp) + orbit = ring.find_orbit(dp=dp)[0] - return orbit, newring + return orbit, ring def grid_configuration(planes, npoints, amplitudes, grid_mode, bounds=None, diff --git a/pyat/at/physics/revolution.py b/pyat/at/physics/revolution.py index 9e3b3a7b5..30be770d5 100644 --- a/pyat/at/physics/revolution.py +++ b/pyat/at/physics/revolution.py @@ -4,9 +4,40 @@ from ..tracking import lattice_pass from .orbit import find_orbit4 import numpy +import functools -__all__ = ['get_mcf', 'get_slip_factor', 'get_revolution_frequency', - 'set_rf_frequency'] +__all__ = ['frequency_control', 'get_mcf', 'get_slip_factor', + 'get_revolution_frequency', 'set_rf_frequency'] + + +def frequency_control(func): + """Function to be used as decorator for ``func(ring, *args, **kwargs)`` + + If ``ring.radiation`` is ``True`` and ``dp``, ``dct`` or ``df`` is + specified, make a copy of ``ring`` with a modified RF frequency, remove + ``dp``, ``dct`` or ``df`` from ``kwargs`` and call ``func`` with the + modified ``ring``. + + If ``ring.radiation`` is ``False``, ``func`` is called unchanged. + + Examples:: + + @frequency_control + def func(ring, *args, dp=None, dct=None, **kwargs): + pass + """ + @functools.wraps(func) + def wrapper(ring, *args, **kwargs): + if ring.radiation: + momargs = {} + for key in ['dp', 'dct', 'df']: + v = kwargs.pop(key, None) + if v is not None: + momargs[key] = v + if len(momargs) > 0: + ring = set_rf_frequency(ring, **momargs, copy=True) + return func(ring, *args, **kwargs) + return wrapper @check_radiation(False) @@ -50,7 +81,7 @@ def get_slip_factor(ring, **kwargs): return etac -def get_revolution_frequency(ring, dp=None, dct=None, **kwargs): +def get_revolution_frequency(ring, dp=None, dct=None): """Compute the revolution frequency of the full ring [Hz] PARAMETERS @@ -59,9 +90,6 @@ def get_revolution_frequency(ring, dp=None, dct=None, **kwargs): KEYWORDS dp=0.0 momentum deviation. dct=0.0 Path length deviation - keep_lattice Assume no lattice change since the previous tracking. - Defaults to False - dp_step=1.0E-6 momentum deviation used for differentiation """ lcell = ring.get_s_pos(len(ring))[0] frev = ring.beta * clight / lcell / ring.periodicity @@ -69,8 +97,9 @@ def get_revolution_frequency(ring, dp=None, dct=None, **kwargs): frev *= lcell / (lcell + dct) elif dp is not None: rnorad = ring.radiation_off(copy=True) if ring.radiation else ring - etac = get_slip_factor(rnorad, **kwargs) - frev += frev * etac * dp + orbit = lattice_pass(rnorad, rnorad.find_orbit4(dp=dp)[0]) + dct = numpy.squeeze(orbit)[5] + frev *= lcell / (lcell + dct) return frev From dfe7dbce5db59e0740138aa3d5b6c652358c2209 Mon Sep 17 00:00:00 2001 From: Laurent Farvacque Date: Wed, 15 Jun 2022 16:54:08 +0200 Subject: [PATCH 2/2] imprived frequency control in Matlab --- atmat/atphysics/LongitudinalDynamics/atsetcavity.m | 9 ++++++--- pyat/at/physics/revolution.py | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/atmat/atphysics/LongitudinalDynamics/atsetcavity.m b/atmat/atphysics/LongitudinalDynamics/atsetcavity.m index 2046efd7b..fedf8210b 100644 --- a/atmat/atphysics/LongitudinalDynamics/atsetcavity.m +++ b/atmat/atphysics/LongitudinalDynamics/atsetcavity.m @@ -92,9 +92,12 @@ if isfinite(dct) frev=frev * lcell/(lcell+dct); elseif isfinite(dp) - [~,ringrad]=check_radiation(ring,false,'force'); - etac=1/gamma0^2 - mcf(ringrad); - frev=frev + frev*etac*dp; + % Find the path lengthening for dp + [~,rnorad]=check_radiation(ring,false,'force'); + [~,orbitin]=findorbit4(rnorad,dp); + orbitout=ringpass(rnorad,orbitin); + dct=orbitout(6); + frev=frev * lcell/(lcell+dct); end frequency = frev * props_harmnumber(harmnumber,props); else diff --git a/pyat/at/physics/revolution.py b/pyat/at/physics/revolution.py index 30be770d5..0e24cc164 100644 --- a/pyat/at/physics/revolution.py +++ b/pyat/at/physics/revolution.py @@ -96,6 +96,7 @@ def get_revolution_frequency(ring, dp=None, dct=None): if dct is not None: frev *= lcell / (lcell + dct) elif dp is not None: + # Find the path lengthening for dp rnorad = ring.radiation_off(copy=True) if ring.radiation else ring orbit = lattice_pass(rnorad, rnorad.find_orbit4(dp=dp)[0]) dct = numpy.squeeze(orbit)[5]