diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 04f2aed..0c0d634 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -17,18 +17,18 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-22.04] - python-version: [3.11] + os: [ubuntu-24.04] + python-version: [3.12] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' - cache-dependency-path: '**/setup.py' + cache-dependency-path: '**/pyproject.toml' - name: Upgrade pip, setuptools and wheel run: python -m pip install --upgrade pip setuptools wheel diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index a8de11c..de3c2bb 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -20,17 +20,17 @@ jobs: strategy: matrix: # only lowest supported Python on latest ubuntu os: [ubuntu-latest] - python-version: [3.8] + python-version: [3.9] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} cache: 'pip' - cache-dependency-path: '**/setup.py' + cache-dependency-path: '**/pyproject.toml' - name: Get full Python version id: full-python-version diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7dc6c7d..c733602 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,31 +14,18 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, ubuntu-22.04, windows-latest, macos-latest] - python-version: [3.8, 3.9, "3.10", "3.11"] + os: [ubuntu-22.04, ubuntu-24.04, windows-latest, macos-latest] + python-version: [3.9, "3.10", 3.11, 3.12] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - - name: Get full Python version - id: full-python-version - run: echo ::set-output name=version::$(python -c "import sys; print('-'.join(str(v) for v in sys.version_info))") - - - name: Set up cache - uses: actions/cache@v2 - id: cache - with: - path: .venv - key: venv-${{ runner.os }}-${{ steps.full-python-version.outputs.version }} - - - name: Ensure cache is healthy - if: steps.cache.outputs.cache-hit == 'true' - run: pip --version >/dev/null 2>&1 || rm -rf .venv + cache: 'pip' + cache-dependency-path: '**/pyproject.toml' - name: Upgrade pip, setuptools and wheel run: | diff --git a/.zenodo.json b/.zenodo.json new file mode 100644 index 0000000..4fc4d94 --- /dev/null +++ b/.zenodo.json @@ -0,0 +1,35 @@ +{ + "creators": [ + { + "name": "Lukáš Malina", + "affiliation": "DESY", + "orcid": "0000-0002-4673-6035" + }, + { + "name": "Thorsten Hellert", + "affiliation": "LBNL", + "orcid": "0000-0002-2797-0926" + }, + { + "name": "Simone Liuzzo", + "affiliation": "ESRF", + "orcid": "0000-0003-3596-4654" + }, + { + "name": "Elaf Musa", + "affiliation": "DESY" + }, + { + "name": "Lina Hoummi", + "affiliation": "ESRF", + "orcid": "0009-0002-7631-3313" + }, + { + "name": "Bianca Veglia", + "affiliation": "DESY" + } + + ], + "title": "pySC", + "description": "Python library for simulated commissioning of storage-ring particle accelerators." +} \ No newline at end of file diff --git a/pySC/__init__.py b/pySC/__init__.py index e25017c..da3a4c6 100644 --- a/pySC/__init__.py +++ b/pySC/__init__.py @@ -9,7 +9,7 @@ __title__ = "pySC" __description__ = "Python version of Simulated Commissioning toolkit for synchrotrons (https://github.com/ThorstenHellert/SC) " __url__ = "https://github.com/lmalina/pySC" -__version__ = "0.1.0" +__version__ = "0.2.0" __author__ = "lmalina" __author_email__ = "lukas.malina@desy.de" diff --git a/pySC/core/beam.py b/pySC/core/beam.py index 8299e6d..c7134ab 100644 --- a/pySC/core/beam.py +++ b/pySC/core/beam.py @@ -61,7 +61,7 @@ def bpm_reading(SC: SimulatedCommissioning, bpm_ords: ndarray = None, calculate_ mean_bpm_sums_3d = np.nansum(mean_bpm_sums_3d, axis=2, keepdims=True) / SC.INJ.nTurns if calculate_errors and SC.INJ.trackMode == TRACK_TBT: bpm_orbits_4d[np.sum(np.isnan(bpm_orbits_4d), axis=3) > 0, :] = np.nan - squared_orbit_diffs = np.square(bpm_orbits_4d - mean_bpm_orbits_3d) + squared_orbit_diffs = np.square(bpm_orbits_4d - mean_bpm_orbits_3d[:, :, :, np.newaxis]) err_bpm_orbits_3d = np.sqrt(np.average(np.ma.array(squared_orbit_diffs, mask=np.isnan(bpm_orbits_4d)), weights=np.ma.array(bpm_sums_4d, mask=np.isnan(bpm_orbits_4d)), axis=3)).filled(np.nan) # Organising the array 2 x (nturns x nbpms) sorted by "arrival time" @@ -128,7 +128,8 @@ def beam_transmission(SC: SimulatedCommissioning, nParticles: int = None, nTurns if nTurns is None: nTurns = SC.INJ.nTurns LOGGER.debug(f'Calculating maximum beam transmission for {nParticles} particles and {nTurns} turns: ') - T = at_wrapper.patpass(SC.RING, generate_bunches(SC, nParticles=nParticles), nTurns, np.array([len(SC.RING)]), keep_lattice=False) + T = at_wrapper.lattice_track(SC.RING, generate_bunches(SC, nParticles=nParticles), nTurns, np.array([len(SC.RING)]), + keep_lattice=False, use_mp=True) fraction_survived = np.mean(~np.isnan(T[0, :, :, :]), axis=(0, 1)) max_turns = np.sum(fraction_survived > 1 - SC.INJ.beamLostAt) if plot: @@ -185,7 +186,7 @@ def _real_bpm_reading(SC, track_mat, bpm_inds=None): # track_mat should be only bpm_noise = bpm_noise[:, :, np.newaxis] * sc_tools.randnc(2, (2, n_bpms, nTurns)) bpm_offset = np.transpose(at_wrapper.atgetfieldvalues(SC.RING, bpm_ords, 'Offset') + at_wrapper.atgetfieldvalues(SC.RING, bpm_ords, 'SupportOffset')) bpm_cal_error = np.transpose(at_wrapper.atgetfieldvalues(SC.RING, bpm_ords, 'CalError')) - bpm_roll = np.squeeze(at_wrapper.atgetfieldvalues(SC.RING, bpm_ords, 'Roll') + at_wrapper.atgetfieldvalues(SC.RING, bpm_ords, 'SupportRoll'), axis=1) + bpm_roll = np.ravel(at_wrapper.atgetfieldvalues(SC.RING, bpm_ords, 'Roll')) + np.ravel(at_wrapper.atgetfieldvalues(SC.RING, bpm_ords, 'SupportRoll')) bpm_sum_error = np.transpose(at_wrapper.atgetfieldvalues(SC.RING, bpm_ords, 'SumError'))[:, np.newaxis] * sc_tools.randnc(2, (n_bpms, nTurns)) # averaging the X and Y positions at BPMs over particles mean_orbit = np.nanmean(track_mat, axis=1) @@ -211,7 +212,7 @@ def _tracking(SC: SimulatedCommissioning, refs: ndarray) -> ndarray: if SC.INJ.trackMode == TRACK_ORB: pos = np.transpose(at_wrapper.findorbit6(SC.RING, refs, keep_lattice=False)[1])[[0, 2], :].reshape(2, 1, len(refs), 1) else: - pos = at_wrapper.atpass(SC.RING, generate_bunches(SC), SC.INJ.nTurns, refs, keep_lattice=False)[[0, 2], :, :, :] + pos = at_wrapper.lattice_track(SC.RING, generate_bunches(SC), SC.INJ.nTurns, refs, keep_lattice=False)[[0, 2], :, :, :] pos[1, np.isnan(pos[0, :, :, :])] = np.nan return pos diff --git a/pySC/core/simulated_commissioning.py b/pySC/core/simulated_commissioning.py index 119d9ad..ed5ff31 100644 --- a/pySC/core/simulated_commissioning.py +++ b/pySC/core/simulated_commissioning.py @@ -35,7 +35,7 @@ class SimulatedCommissioning: Examples: >>> import at - >>> SC = SimulatedCommissioning(at.Lattice(at.Monitor('BPM')) + >>> SC = SimulatedCommissioning(at.Lattice(at.Monitor('BPM'))) >>> SC.register_bpms(np.array(0), Offset=2e-6*np.ones(2)) >>> print(SC.ORD) 0 @@ -560,7 +560,7 @@ def apply_errors(self, nsigmas: float = 2): self.INJ.randomInjectionZ = 1 * self.SIG.randomInjectionZ # Circumference if 'Circumference' in self.SIG.keys(): - circScaling = 1 + self.SIG.Circumference * sc_tools.randnc(nsigmas, (1, 1)) + circScaling = 1 + self.SIG.Circumference * sc_tools.randnc(nsigmas, ()) self.RING = sc_tools.scale_circumference(self.RING, circScaling, 'rel') LOGGER.info('Circumference error applied.') # Misalignments @@ -586,7 +586,7 @@ def _apply_support_alignment_error(self, nsigmas): classdef_tools.randn_cutoff(value, nsigmas) if field in self.SIG.Support[ordPair[1]].keys() else getattr(self.RING[ordPair[0]], field)) - struct_length = np.remainder(np.diff(s_pos[ordPair]), s_pos[-1]) + struct_length = np.remainder(s_pos[ordPair][1] - s_pos[ordPair][0], s_pos[-1]) rolls0 = copy.deepcopy(getattr(self.RING[ordPair[0]], f"{support_type}Roll")) # Twisted supports are not considered offsets0 = copy.deepcopy(getattr(self.RING[ordPair[0]], f"{support_type}Offset")) offsets1 = copy.deepcopy(getattr(self.RING[ordPair[1]], f"{support_type}Offset")) @@ -696,7 +696,7 @@ def update_supports(self, offset_bpms: bool = True, offset_magnets: bool = True) for i, ind in enumerate(self.ORD.BPM): setattr(self.RING[ind], "SupportOffset", offsets[0:2, i]) # No longitudinal BPM offsets implemented setattr(self.RING[ind], "SupportRoll", - np.array([rolls[0, i]])) # BPM pitch and yaw angles not implemented + rolls[0, i]) # BPM pitch and yaw angles not implemented else: LOGGER.warning('SC: No BPMs have been registered!') diff --git a/pySC/correction/bba.py b/pySC/correction/bba.py index 1faefbb..e0b7a0a 100644 --- a/pySC/correction/bba.py +++ b/pySC/correction/bba.py @@ -227,7 +227,7 @@ def fake_bba(SC, bpm_ords, mag_ords, errors=None, fake_offset=None): fake_bpm_offset = (SC.RING[mag_ords[inds[0], inds[1]]].MagnetOffset[inds[0]] + SC.RING[mag_ords[inds[0], inds[1]]].SupportOffset[inds[0]] - SC.RING[bpm_ords[inds[0], inds[1]]].SupportOffset[inds[0]] - + fake_offset[inds[0]] * sc_tools.randnc()) + + fake_offset[inds[0]] * sc_tools.randnc(2, ())) if not np.isnan(fake_bpm_offset): SC.RING[bpm_ords[inds[0], inds[1]]].Offset[inds[0]] = fake_bpm_offset else: diff --git a/pySC/correction/injection_fit.py b/pySC/correction/injection_fit.py index 356e2b4..95a35e1 100644 --- a/pySC/correction/injection_fit.py +++ b/pySC/correction/injection_fit.py @@ -68,7 +68,7 @@ def _fit_bpm_data(s_bpm, bref): def _merit_function(x, SC, bref, ords_used): - t = at_wrapper.atpass(SC.IDEALRING, np.concatenate((x, np.zeros(2))), 1, ords_used, keep_lattice=False)[[0, 2], 0, :, 0] + t = at_wrapper.lattice_track(SC.IDEALRING, np.concatenate((x, np.zeros(2))), 1, ords_used, keep_lattice=False)[[0, 2], 0, :, 0] return np.sqrt(np.mean(bref - t) ** 2) diff --git a/pySC/lattice_properties/apertures.py b/pySC/lattice_properties/apertures.py index 53cf477..7aaf94a 100644 --- a/pySC/lattice_properties/apertures.py +++ b/pySC/lattice_properties/apertures.py @@ -26,7 +26,7 @@ def SCdynamicAperture(RING, dE, bounds=np.array([0, 1e-3]), nturns=1000, thetas= for cntt in range(len(thetas)): # Loop over angles theta = thetas[cntt] limits = inibounds - at_wrapper.atpass(RING, np.full(6, np.nan), 1, [1]) # Fake Track to initialize lattice + at_wrapper.lattice_track(RING, np.full(6, np.nan), 1, [1]) # Fake Track to initialize lattice scales = 0 while scales < 16: if _check_bounds(RING, ZCO, nturns, theta, limits): @@ -102,7 +102,7 @@ def _check_bounds(RING, ZCO, nturns, theta, boundsIn): Zmax = ZCO[:] Zmax[0] = boundsIn[1] * np.cos(theta) Zmax[2] = boundsIn[1] * np.sin(theta) - ROUT = at_wrapper.atpass(RING, [Zmin, Zmax], nturns, len(RING), keep_lattice=True) # Track + ROUT = at_wrapper.lattice_track(RING, [Zmin, Zmax], nturns, len(RING), keep_lattice=True) # Track RLAST = ROUT[:, len(ROUT) - 1:len(ROUT)] # Get positions after last turn return ~np.isnan(RLAST[0, 0]) and np.isnan(RLAST[0, 1]) @@ -114,7 +114,7 @@ def _refine_bounds(RING, ZCO, nturns, theta, boundsIn): Z = ZCO[:] Z[0] = rmid * np.cos(theta) Z[2] = rmid * np.sin(theta) - ROUT = at_wrapper.atpass(RING, Z, nturns, len(RING), keep_lattice=True) # Track + ROUT = at_wrapper.lattice_track(RING, Z, nturns, len(RING), keep_lattice=True) # Track RLAST = ROUT[:, len(ROUT) - 1] # Get positions after last turn return [rmin, rmid] if np.isnan(RLAST[0]) else [rmid, rmax] # Midpoint is outside or inside DA @@ -146,7 +146,7 @@ def refine_bounds(local_bounds, RING, ZCO, nturns): dmean = np.mean(local_bounds) Z0 = ZCO Z0[4] = Z0[4] + dmean - ROUT = at_wrapper.atpass(RING, Z0, nturns, len(RING)) + ROUT = at_wrapper.lattice_track(RING, Z0, nturns, len(RING)) if np.isnan(ROUT[0]): # Particle dead :( local_bounds[1] = dmean # Set abs-upper bound to midpoint else: # Particle alive :) @@ -157,7 +157,7 @@ def refine_bounds(local_bounds, RING, ZCO, nturns): def check_bounds(local_bounds, RING, ZCO, nturns): Z = np.array([ZCO, ZCO]) Z[4, :] = Z[4, :] + local_bounds[:] - ROUT = at_wrapper.atpass(RING, Z, nturns, len(RING)) + ROUT = at_wrapper.lattice_track(RING, Z, nturns, len(RING)) if np.isnan(ROUT[0, 0]) and not np.isnan(ROUT[0, 1]): LOGGER.warning('Closer-to-momentum particle is unstable. This shouldnt be!') return not np.isnan(ROUT[0, 0]) and np.isnan(ROUT[0, 1]) diff --git a/pySC/lattice_properties/response_model.py b/pySC/lattice_properties/response_model.py index 3e3f49c..5c3dea5 100644 --- a/pySC/lattice_properties/response_model.py +++ b/pySC/lattice_properties/response_model.py @@ -49,7 +49,7 @@ def SCgetModelRM(SC, BPMords, CMords, trackMode='TBT', Z0=np.zeros(6), nTurns=1, """ LOGGER.info('Calculating model response matrix') - track_methods = dict(TBT=at_wrapper.atpass, ORB=orbpass) + track_methods = dict(TBT=at_wrapper.lattice_track, ORB=orbpass) if trackMode not in track_methods.keys(): ValueError(f'Unknown track mode {trackMode}. Valid values are {track_methods.keys()}') ring = SC.IDEALRING.deepcopy() if useIdealRing else SCgetModelRING(SC) @@ -121,7 +121,7 @@ def SCgetModelDispersion(SC, BPMords, CAVords, trackMode='ORB', Z0=np.zeros(6), """ LOGGER.info('Calculating model dispersion') - track_methods = dict(TBT=at_wrapper.atpass, ORB=orbpass) + track_methods = dict(TBT=at_wrapper.lattice_track, ORB=orbpass) if trackMode not in track_methods.keys(): ValueError(f'Unknown track mode {trackMode}. Valid values are {track_methods.keys()}') ring = SC.IDEALRING.deepcopy() if useIdealRing else SCgetModelRING(SC) diff --git a/pySC/plotting/plot_phase_space.py b/pySC/plotting/plot_phase_space.py index 3ee8943..cf7333a 100644 --- a/pySC/plotting/plot_phase_space.py +++ b/pySC/plotting/plot_phase_space.py @@ -10,7 +10,7 @@ def plot_phase_space(SC, ords=np.zeros(1, dtype=int), custom_bunch=None, nPartic init_font = plt.rcParams["font.size"] plt.rcParams.update({'font.size': 18}) z_in, n_particles, n_turns = _check_input(SC, custom_bunch, nParticles, nTurns) - T = at_wrapper.atpass(SC.RING, z_in, n_turns, ords, keep_lattice=False) + T = at_wrapper.lattice_track(SC.RING, z_in, n_turns, ords, keep_lattice=False) T[:, np.isnan(T[0, :])] = np.nan label_str = [r'$\Delta x$ [$\mu$m]', r"$\Delta x'$ [$\mu$rad]", r'$\Delta y$ [$\mu$m]', r"$\Delta y'$ [$\mu$rad]", r'$\Delta S$ [m]', r'$\delta E$ $[\%]$'] diff --git a/pySC/plotting/plot_support.py b/pySC/plotting/plot_support.py index 1b9bffd..526e872 100644 --- a/pySC/plotting/plot_support.py +++ b/pySC/plotting/plot_support.py @@ -64,9 +64,9 @@ def plot_support(SC: SimulatedCommissioning, font_size: int = 8, x_lim: Tuple[fl # Longitudinal offsets and Pitch and Yaw angles not supported for BPMs pad_off, pad_roll = ((0, 0), (0, 1)), ((0, 0), (0, 2)) off_bpm = np.pad(at_wrapper.atgetfieldvalues(SC.RING, SC.ORD.BPM, "Offset"), pad_off) - roll_bpm = np.pad(at_wrapper.atgetfieldvalues(SC.RING, SC.ORD.BPM, "Roll"), pad_roll) + roll_bpm = np.pad(np.ravel(at_wrapper.atgetfieldvalues(SC.RING, SC.ORD.BPM, "Roll"))[:, np.newaxis], pad_roll) off_bpm_support = np.pad(at_wrapper.atgetfieldvalues(SC.RING, SC.ORD.BPM, "SupportOffset"), pad_off) - roll_bpm_support = np.pad(at_wrapper.atgetfieldvalues(SC.RING, SC.ORD.BPM, "SupportRoll"), pad_roll) + roll_bpm_support = np.pad(np.ravel(at_wrapper.atgetfieldvalues(SC.RING, SC.ORD.BPM, "SupportRoll"))[:, np.newaxis], pad_roll) # create figure fig, ax = plt.subplots(nrows=9, ncols=2, num=1213, sharex="all", figsize=(10, 15)) diff --git a/pySC/utils/at_wrapper.py b/pySC/utils/at_wrapper.py index 430ae18..bbbdad1 100644 --- a/pySC/utils/at_wrapper.py +++ b/pySC/utils/at_wrapper.py @@ -6,7 +6,7 @@ which are not member functions of used ``pyAT`` objects. This is due to observed side effects, such as modification of input parameters. -Tracking fuctions ``latice_pass``, ``find_orbit4``, ``find_orbit6`` +Tracking fuctions ``latice_track``, ``find_orbit4``, ``find_orbit6`` index the result the same way as ``get_s_pos``, i.e. 0 means entrance of the first element, len(elements) means end of the last element. Function ``get_value_refpts`` indexes elements as usual. @@ -21,14 +21,10 @@ from at import Lattice -def atpass(ring: Lattice, init_pos: ndarray, nturns: int, refpts: ndarray, keep_lattice: bool = False): - return at.lattice_pass(lattice=ring.copy(), r_in=init_pos.copy(), nturns=nturns, refpts=refpts, - keep_lattice=keep_lattice) - - -def patpass(ring: Lattice, init_pos: ndarray, nturns: int, refpts: ndarray, keep_lattice: bool = False): - return at.patpass(lattice=ring.copy(), r_in=init_pos.copy(), nturns=nturns, refpts=refpts, - keep_lattice=keep_lattice) +def lattice_track(ring: Lattice, init_pos: ndarray, nturns: int, refpts: ndarray, keep_lattice: bool = False, + use_mp: bool = False): + return at.lattice_track(lattice=ring.copy(), r_in=init_pos.copy(), nturns=nturns, refpts=refpts, + keep_lattice=keep_lattice, in_place=False, use_mp=use_mp)[0] def atgetfieldvalues(ring: Lattice, refpts: ndarray, attrname: str, index: int = None): diff --git a/pySC/utils/sc_tools.py b/pySC/utils/sc_tools.py index 24f7a86..ab1027d 100644 --- a/pySC/utils/sc_tools.py +++ b/pySC/utils/sc_tools.py @@ -2,8 +2,9 @@ import numpy as np from matplotlib import pyplot as plt -from numpy import ndarray +from numpy import ndarray, float64 from at import Lattice +from typing import Union from pySC.utils import at_wrapper, logging_tools @@ -11,9 +12,10 @@ LOGGER = logging_tools.get_logger(__name__) -def randnc(cut_off: float = 2, shape: tuple = (1,)) -> ndarray: +def randnc(cut_off: float = 2, shape: tuple = (1,)) -> Union[ndarray, float64]: """ Generates an array of random number(s) from normal distribution with a cut-off. + If shape = () a single float value is returned. Parameters ---------- @@ -24,15 +26,19 @@ def randnc(cut_off: float = 2, shape: tuple = (1,)) -> ndarray: Returns ------- - out : ndarray - The output array. + out : Union[ndarray, float64] + The output array (If shape = () a single float value) """ + if np.any([s < 0 for s in shape]): + raise ValueError('The shape of the output array must be positive.') out_shape = (1,) if np.sum(shape) < 1 else shape out = np.random.randn(np.prod(out_shape)) outindex = np.abs(out) > np.abs(cut_off) while np.sum(outindex): out[outindex] = np.random.randn(np.sum(outindex)) outindex = np.abs(out) > np.abs(cut_off) + if np.sum(shape) < 1: + return out[0] return out.reshape(out_shape) @@ -165,10 +171,10 @@ def _plot_singular_values(s_mat, d_mat): fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(12, 4), dpi=100, facecolor="w") ax[0].semilogy(np.diag(s_mat) / np.max(np.diag(s_mat)), 'o--') ax[0].set_xlabel('Number of SV') - ax[0].set_ylabel('$\sigma/\sigma_0$') + ax[0].set_ylabel(r'$\sigma/\sigma_0$') ax[1].plot(s_mat * d_mat, 'o--') ax[1].set_xlabel('Number of SV') - ax[1].set_ylabel('$\sigma * \sigma^+$') + ax[1].set_ylabel(r'$\sigma * \sigma^+$') ax[1].yaxis.tick_right() ax[1].yaxis.set_label_position("right") fig.show() diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..7a503a3 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,63 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[tool.hatch.version] +path = "pySC/__init__.py" + +[tool.hatch.build.targets.sdist] +exclude = [ + "/.github", + "/doc", + "/tests", +] + +[tool.hatch.build.targets.wheel] +packages = ["pySC"] + +[project] +name = "pySC" +description = "Python version of Simulated Commissioning toolkit for synchrotrons (https://github.com/ThorstenHellert/SC) " +readme = "README.md" +requires-python = ">=3.9" +dynamic = ["version"] +#license = {file = "LICENSE.txt"} +keywords = ["Accelerator", "Synchrotron", "Commissioning", ] +maintainers = [ + {name = "Lukáš Malina", email = "lukas.malina@desy.de"} +] +classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Science/Research", + "Natural Language :: English", + "Programming Language :: Python", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Scientific/Engineering :: Physics", +] + +dependencies = [ + "numpy>=2.0.0", + "scipy>=1.11.4", + "matplotlib>=3.7.3", + "accelerator-toolbox>=0.6.1" +] + +[project.optional-dependencies] +test = [ + "pytest>=7.4", + "pytest-cov>=3.0", +] +doc = [ + "sphinx", + "travis-sphinx", + "sphinx-rtd-theme" +] + +[project.urls] +Homepage = "https://github.com/lmalina/pySC" +Documentation = "https://lmalina.github.io/pySC/" +Repository = "https://github.com/lmalina/pySC.git" diff --git a/setup.py b/setup.py deleted file mode 100644 index 4d22114..0000000 --- a/setup.py +++ /dev/null @@ -1,69 +0,0 @@ -import pathlib -import setuptools - -# The directory containing this file -TOPLEVEL_DIR = pathlib.Path(__file__).parent.absolute() -ABOUT_FILE = TOPLEVEL_DIR / "pySC" / "__init__.py" -README = TOPLEVEL_DIR / "README.md" - -# Information about pySC package -ABOUT_PYSC: dict = {} -with ABOUT_FILE.open("r") as f: - exec(f.read(), ABOUT_PYSC) - -with README.open("r") as docs: - long_description = docs.read() - -# Dependencies for the package itself -DEPENDENCIES = [ - "numpy>=1.22.0", - "scipy>=1.8.0", - "matplotlib>=3.5.0", - "accelerator-toolbox>=0.4.0" - -] - -# Extra dependencies -EXTRA_DEPENDENCIES = { - "test": [ - "pytest>=7.0", - "pytest-cov>=3.0", - - - ], - "doc": [ - "sphinx", - "travis-sphinx", - "sphinx-rtd-theme" - ]} - -EXTRA_DEPENDENCIES.update( - {'all': [elem for list_ in EXTRA_DEPENDENCIES.values() for elem in list_]} -) - -setuptools.setup( - name=ABOUT_PYSC["__title__"], - version=ABOUT_PYSC["__version__"], - description=ABOUT_PYSC["__description__"], - long_description=long_description, - long_description_content_type="text/markdown", - author=ABOUT_PYSC["__author__"], - author_email=ABOUT_PYSC["__author_email__"], - url=ABOUT_PYSC["__url__"], - packages=setuptools.find_packages(exclude=["tests", "doc"]), - python_requires=">=3.8", - classifiers=[ - "Intended Audience :: Science/Research", - "Natural Language :: English", - "Programming Language :: Python", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Topic :: Scientific/Engineering :: Physics", - ], - install_requires=DEPENDENCIES, - tests_require=EXTRA_DEPENDENCIES["test"], - extras_require=EXTRA_DEPENDENCIES, -) diff --git a/tests/test_at_wrapper.py b/tests/test_at_wrapper.py index 0ee172c..0a1643e 100644 --- a/tests/test_at_wrapper.py +++ b/tests/test_at_wrapper.py @@ -5,7 +5,7 @@ from numpy.testing import assert_equal import at from at import Lattice -from pySC.utils.at_wrapper import findspos, atgetfieldvalues, atpass, patpass, findorbit6, findorbit4 +from pySC.utils.at_wrapper import findspos, atgetfieldvalues, lattice_track, findorbit6, findorbit4 @@ -25,12 +25,12 @@ def test_atgetfieldvalues(at_lattice): assert_equal(indices, np.arange(11, 450, 22, dtype=int)) -def test_atpass(at_lattice): +def test_lattice_track1(at_lattice): lattice_copy = copy.deepcopy(at_lattice) indices = np.arange(11, 450, 22, dtype=int) initial_pos = np.random.randn(6) copy_initial_pos = copy.deepcopy(initial_pos) - tracking = atpass(at_lattice, initial_pos, 3, indices,) + tracking = lattice_track(at_lattice, initial_pos, 3, indices, ) assert tracking.shape == (6, 1, 20, 3) assert_equal(initial_pos, copy_initial_pos) assert at_lattice.__repr__() == lattice_copy.__repr__() @@ -42,7 +42,7 @@ def test_patpass(at_lattice): indices = np.arange(11, 450, 22, dtype=int) initial_pos = np.random.randn(6) copy_initial_pos = copy.deepcopy(initial_pos) - tracking = patpass(at_lattice, initial_pos, 3, indices,) + tracking = lattice_track(at_lattice, initial_pos, 3, indices, use_mp=True) assert tracking.shape == (6, 1, 20, 3) assert_equal(initial_pos, copy_initial_pos) assert at_lattice.__repr__() == lattice_copy.__repr__() diff --git a/tests/test_loco.py b/tests/test_loco.py index 392e107..6b5cf42 100644 --- a/tests/test_loco.py +++ b/tests/test_loco.py @@ -30,7 +30,7 @@ def test_loco_hmba(at_ring): cav_ords = sc_tools.ords_from_regex(sc.RING, 'RFC') quads_ords = [sc_tools.ords_from_regex(sc.RING, 'QF'), sc_tools.ords_from_regex(sc.RING, 'QD')] - CMstep = np.array([1.e-4]) # correctors change [rad] + CMstep = 1.e-4 # correctors change [rad] dk = 1.e-4 # quads change RFstep = 1e3