Skip to content

Commit

Permalink
Version 1.3.0 Changes (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
fsoubelet authored May 16, 2023
1 parent e7065e3 commit 173106d
Show file tree
Hide file tree
Showing 14 changed files with 160 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/cron.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04, ubuntu-22.04, macos-latest, windows-latest]
os: [ubuntu-22.04, macos-latest, windows-latest]
python-version: [3.8, 3.9, "3.10", "3.11", 3.x] # crons should always run latest python hence 3.x
# exclude:
# - os: windows-latest # scipy deps issues
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,32 @@ jobs:
steps:

- name: Check Out Repo
uses: actions/checkout@v2
uses: actions/checkout@v3

- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@v2

- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@v2

- name: Cache Docker layers
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Login to Docker Hub
uses: docker/login-action@v1
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_ID }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push image
id: docker_build
uses: docker/build-push-action@v2
uses: docker/build-push-action@v4
with:
context: ./
file: ./docker/Dockerfile
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
name: ${{ matrix.os }} / ${{ matrix.python-version }}
runs-on: ${{ matrix.os }}
strategy:
matrix: # only lowest supported python on ubuntu-latest
matrix:
os: [ubuntu-latest]
python-version: [3.9]

Expand Down Expand Up @@ -65,8 +65,8 @@ jobs:

- name: Upload documentation to gh-pages
if: success() && github.ref == 'refs/heads/master' # only for pushes to master
uses: JamesIves/github-pages-deploy-action@3.7.1
uses: JamesIves/github-pages-deploy-action@v4
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages
FOLDER: doc_build
folder: doc_build
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Now default
# BRANCH: gh-pages # now default
4 changes: 2 additions & 2 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04, ubuntu-22.04, macos-latest, windows-latest]
os: [ubuntu-22.04, macos-latest, windows-latest]
python-version: [3.8, 3.9, "3.10", "3.11"]
fail-fast: false

Expand All @@ -41,7 +41,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-20.04, ubuntu-22.04, macos-latest, windows-latest]
os: [ubuntu-22.04, macos-latest, windows-latest]
python-version: [3.8, 3.9, "3.10", "3.11"]
fail-fast: false

Expand Down
8 changes: 8 additions & 0 deletions docs/release.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ Release Notes

The full list of releases can be found in the GitHub repository's `releases page <https://github.com/fsoubelet/PyhDToolkit/releases>`_.

Version 1.3.0
-------------

.. toctree::
:maxdepth: 2

releases/v1.3.0

Version 1.2.0
-------------

Expand Down
28 changes: 28 additions & 0 deletions docs/releases/v1.3.0.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.. _release_1.3.0:

1.3.0
-----

Release `1.3.0` brings a few additions and bug fixes.

Enhancements
~~~~~~~~~~~~

* The `pyhdtoolkit.plotting.aperture.plot_physical_apertures` now has an ``xoffset`` argument similar to the one of the other plotting functions.
* The `pyhdtoolkit.plotting.envelope.plot_beam_envelope` now has an ``xoffset`` argument similar to the one of the other plotting functions.
* The `pyhdtoolkit.plotting.layout` module has a new public function, `scale_patches`, to enable easy scaling of the element patches.

Bug Fixes
~~~~~~~~~

* The `pyhdtoolkit.plotting.layout.plot_machine_layout` function will now plot skew elements too, with a hatching pattern to differentiate them from their normal counterparts.

Maintenance
~~~~~~~~~~~

* The `pyhdtoolkit.plotting.styles.paper.SINGLE_COLUMN` matplotlib style has been adjusted to be tighter at the edges of the figure when saving to a file.
* Relaxed the tolerance of some coupling correction tests as the routine seems to perform slightly worse on the new MAD-X version.
* Removed deprecated workers versions from the CI configuration.
* Updated the CI configuration to use the latest versions of the docker actions.

See `v1.3.0 release notes on GitHub <https://github.com/fsoubelet/PyhDToolkit/releases/tag/1.3.0>`_ and the `full changes since v1.2.0 <https://github.com/fsoubelet/PyhDToolkit/compare/1.2.0...1.3.0>`_.
35 changes: 27 additions & 8 deletions pyhdtoolkit/plotting/aperture.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,13 @@ def plot_aperture(


def plot_physical_apertures(
madx, /, plane: str, scale: float = 1, xlimits: Tuple[float, float] = None, **kwargs
madx,
/,
plane: str,
scale: float = 1,
xoffset: float = 0,
xlimits: Tuple[float, float] = None,
**kwargs,
) -> None:
"""
.. versionadded:: 1.2.0
Expand All @@ -213,6 +219,11 @@ def plot_physical_apertures(
scale (float): a scaling factor to apply to the beam orbit and beam
enveloppe, for the user to adjust to their wanted scale. Defaults
to 1 (values in [m]).
xoffset (float): An offset applied to the ``S`` coordinate before
plotting. This is useful if you want to center a plot around a
specific point or element, which would then become located
at :math:`s = 0`. Beware this offset is applied before applying
the *xlimits*. Defaults to 0.
xlimits (Tuple[float, float]): will implement xlim (for the ``s``
coordinate) if this is not ``None``, using the tuple passed.
Defaults to ``None``.
Expand Down Expand Up @@ -249,10 +260,9 @@ def plot_physical_apertures(
logger.debug("Plotting real element apertures")
axis, kwargs = maybe_get_ax(**kwargs)

if xlimits is not None:
axis.set_xlim(xlimits)

positions, apertures = _get_positions_and_real_apertures(madx, plane, xlimits, **kwargs)
positions, apertures = _get_positions_and_real_apertures(madx, plane, **kwargs)
logger.trace(f"Applying scale ({scale}) and offset ({xoffset})")
positions = positions - xoffset
apertures = apertures * scale

logger.trace("Plotting apertures")
Expand All @@ -262,12 +272,16 @@ def plot_physical_apertures(
axis.plot(positions, apertures, "k", label="_nolegend_")
axis.plot(positions, -1 * apertures, "k", label="_nolegend_")

if xlimits:
logger.trace("Setting xlim for longitudinal coordinate")
axis.set_xlim(xlimits)


# ----- Helpers ----- #


def _get_positions_and_real_apertures(
madx, /, plane: str, xlimits: Tuple[float, float] = None, **kwargs
madx, /, plane: str, xoffset: float = 0, xlimits: Tuple[float, float] = None, **kwargs
) -> Tuple[np.ndarray, np.ndarray]:
"""
.. versionadded:: 1.2.0
Expand All @@ -288,6 +302,11 @@ def _get_positions_and_real_apertures(
Positional only.
plane (str): the physical plane to plot for, should be either `x`,
`horizontal`, `y` or `vertical`, and is case-insensitive.
xoffset (float): An offset applied to the ``S`` coordinate before
plotting. This is useful if you want to center a plot around a
specific point or element, which would then become located
at :math:`s = 0`. Beware this offset is applied before applying
the *xlimits*. Defaults to 0.
xlimits (Tuple[float, float]): will implement xlim (for the ``s``
coordinate) if this is not ``None``, using the tuple passed.
Defaults to ``None``.
Expand All @@ -303,6 +322,7 @@ def _get_positions_and_real_apertures(
madx.command.select(flag="twiss", column=["aper_1", "aper_2"]) # make sure we to get these two
twiss_df = madx.twiss(**kwargs).dframe()
madx.command.select(flag="twiss", clear=True) # clean up
twiss_df.s = twiss_df.s - xoffset

logger.trace("Determining aperture column to use")
plane_number = 1 if plane.lower() in ("x", "horizontal") else 2
Expand All @@ -325,7 +345,7 @@ def _get_positions_and_real_apertures(
indices = list(reversed(indices))

logger.trace("Extrapolating data at beginning of elements")
counter = 0# Keep track of exact position in new array with counter
counter = 0 # Keep track of exact position in new array with counter
for j in indices:
new_pos.insert(j + counter, (twiss_df.s[j] - twiss_df.l[j]))
counter += 1
Expand All @@ -334,5 +354,4 @@ def _get_positions_and_real_apertures(
apertures = np.array(new_aper)
apertures[apertures == 0] = np.nan
positions = np.array(new_pos)

return positions, apertures
8 changes: 8 additions & 0 deletions pyhdtoolkit/plotting/envelope.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ def plot_beam_envelope(
plane: str,
nsigma: float = 1,
scale: float = 1,
xoffset: float = 0,
xlimits: Tuple[float, float] = None,
**kwargs,
) -> None:
Expand All @@ -48,6 +49,11 @@ def plot_beam_envelope(
scale (float): a scaling factor to apply to the beam orbit and beam
enveloppe, for the user to adjust to their wanted scale. Defaults
to 1 (values in [m]).
xoffset (float): An offset applied to the ``S`` coordinate before
plotting. This is useful if you want to center a plot around a
specific point or element, which would then become located
at :math:`s = 0`. Beware this offset is applied before applying
the *xlimits*. Defaults to 0.
xlimits (Tuple[float, float]): will implement xlim (for the ``s``
coordinate) if this is not ``None``, using the tuple passed.
Defaults to ``None``.
Expand Down Expand Up @@ -87,6 +93,8 @@ def plot_beam_envelope(
logger.debug("Getting Twiss dframe from MAD-X")
plane_letter = "x" if plane.lower() in ("x", "horizontal") else "y"
twiss_df = madx.twiss(**kwargs).dframe()
twiss_df.s = twiss_df.s - xoffset

if xlimits is not None:
axis.set_xlim(xlimits)
twiss_df = twiss_df[twiss_df.s.between(*xlimits)]
Expand Down
49 changes: 43 additions & 6 deletions pyhdtoolkit/plotting/layout.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import matplotlib
import matplotlib.axes
import matplotlib.patches as patches
import numpy as np
import pandas as pd

from cpymad.madx import Madx
Expand Down Expand Up @@ -172,7 +173,8 @@ def plot_machine_layout(
dipole_patches_axis = axis.twinx()
dipole_patches_axis.set_ylabel("$\\theta=K_{0}L$ $[rad]$", color="royalblue") # dipoles in blue
dipole_patches_axis.tick_params(axis="y", labelcolor="royalblue")
dipole_patches_axis.set_ylim(k0l_lim)
if not np.nan in k0l_lim:
dipole_patches_axis.set_ylim(k0l_lim)
dipole_patches_axis.grid(False)

if plot_dipoles: # beware 'sbend' and 'rbend' have an 'angle' value and not a 'k0l'
Expand Down Expand Up @@ -210,12 +212,14 @@ def plot_machine_layout(
plotted_elements = 0
for quadrupole_name, quadrupole in quadrupoles_df.iterrows():
logger.trace(f"Plotting quadrupole element '{quadrupole_name}'")
element_k = quadrupole.k1l if quadrupole.k1l != 0 else quadrupole.k1sl # can be skew quadrupole
_plot_lattice_series(
axis,
quadrupole,
height=quadrupole.k1l,
v_offset=quadrupole.k1l / 2,
height=element_k,
v_offset=element_k / 2,
color="r",
hatch=None if quadrupole.k1l != 0 else "///", # hatch skew quadrupoles
label="MQ" if plotted_elements == 0 else None, # avoid duplicating legend labels
**kwargs,
)
Expand All @@ -235,12 +239,14 @@ def plot_machine_layout(
plotted_elements = 0
for sextupole_name, sextupole in sextupoles_df.iterrows():
logger.trace(f"Plotting sextupole element '{sextupole_name}'")
element_k = sextupole.k2l if sextupole.k2l != 0 else sextupole.k2sl # can be skew sextupole
_plot_lattice_series(
sextupoles_patches_axis,
sextupole,
height=sextupole.k2l,
v_offset=sextupole.k2l / 2,
height=element_k,
v_offset=element_k / 2,
color="goldenrod",
hatch=None if sextupole.k2l != 0 else "\\\\\\", # hatch skew sextupoles
label="MS" if plotted_elements == 0 else None, # avoid duplicating legend labels
**kwargs,
)
Expand All @@ -263,12 +269,14 @@ def plot_machine_layout(
plotted_elements = 0
for octupole_name, octupole in octupoles_df.iterrows():
logger.trace(f"Plotting octupole element '{octupole_name}'")
element_k = octupole.k3l if octupole.k3l else octupole.k3sl # can be skew octupole
_plot_lattice_series(
octupoles_patches_axis,
octupole,
height=octupole.k3l,
v_offset=octupole.k3l / 2,
color="forestgreen",
hatch=None if octupole.k3l != 0 else "xxx", # hatch skew octupoles
label="MO" if plotted_elements == 0 else None, # avoid duplicating legend labels
**kwargs,
)
Expand Down Expand Up @@ -314,6 +322,35 @@ def plot_machine_layout(
bpm_patches_axis.grid(False)


def scale_patches(scale: float, ylabel: str, **kwargs) -> None:
"""
.. versionadded:: 1.3.0
This is a convenience function to update the scale of the elements layout
patches as well as the corresponding y-axis label.
Args:
scale (float): the scale factor to apply to the patches. The new
height of the patches will be ``scale * original_height``.
ylabel (str): the new label for the y-axis.
**kwargs: If either `ax` or `axis` is found in the kwargs, the
corresponding value is used as the axis object to plot on,
otherwise the current axis is used.
Example:
.. code-block:: python
>>> fig, ax = plt.subplots(figsize=(6, 2))
>>> plot_machine_layout(madx, title="Machine Elements", lw=3)
>>> scale_patches(ax=fig.axes[0], scale=100, ylabel=r"$K_{1}L$ $[10^{-2} m^{-1}]$")
"""
axis, kwargs = maybe_get_ax(**kwargs)
axis.set_ylabel(ylabel)
for patch in axis.patches:
h = patch.get_height()
patch.set_height(scale * h)


# ----- Helpers ----- #


Expand Down Expand Up @@ -399,7 +436,7 @@ def _determine_default_knl_lim(df: pd.DataFrame, col: str, coeff: float) -> Tupl
Determine the default limits for the ``knl`` axis, when plotting machine
layout. This is in case `None` are provided by the user, to make sure the
plot still looks coherent and symmetric in
plot still looks coherent and symmetric in
`~.plotting.utils.plot_machine_layout`.
The limits are determined symmetric, using the maximum absolute value of
Expand Down
4 changes: 2 additions & 2 deletions pyhdtoolkit/plotting/styles/paper.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
"figure.figsize": (11, 7), # Size of the figure
"figure.titlesize": 20, # Size of the figure title
"figure.subplot.left": 0.13, # Left side limit of the subplots of the figure
"figure.subplot.top": 0.92, # Top side limit of the subplots of the figure
"figure.subplot.bottom": 0.15, # Bottom side limit of the subplots of the figure
"figure.subplot.top": 0.9, # Top side limit of the subplots of the figure
"figure.subplot.bottom": 0.1, # Bottom side limit of the subplots of the figure
# ------ Saving ------ #
"savefig.dpi": 400, # Saved figure dots per inch
"savefig.format": "pdf", # Saved figure file format
Expand Down
2 changes: 1 addition & 1 deletion pyhdtoolkit/version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = "1.2.0"
VERSION = "1.3.0"


def version_info() -> str:
Expand Down
Loading

0 comments on commit 173106d

Please sign in to comment.