Skip to main content
Ctrl+K

PyNX 2026.1.1 documentation

  • Changelog
  • Installation
  • Tutorials
  • Scripts Reference
  • API Reference
  • Changelog
  • Installation
  • Tutorials
  • Scripts Reference
  • API Reference

Table of Contents

  • Changelog
  • Installation
  • Tutorials
  • Scripts Reference
  • API Reference
  • CDI example: ESRF logo

CDI example: ESRF logo#

[1]:
%matplotlib widget
import os
import numpy as np
from numpy.fft import fftshift
from scipy.ndimage import gaussian_filter
from matplotlib import pyplot as plt
from matplotlib.colors import LogNorm

# This imports all necessary operators. GPU will be auto-selected
from pynx.cdi import *

Get ESRF logo diffraction data#

This dataset was recorded on at id10@ESRF, courtesy of Yuriy Chushkin

[2]:
if not os.path.exists('logo5mu_20sec.npz'):
    os.system('curl -OL https://zenodo.org/record/3451855/files/logo5mu_20sec.npz')

print(list(np.load('logo5mu_20sec.npz').keys()))
iobs = np.load('logo5mu_20sec.npz')['iobs']
mask = np.load('logo5mu_20sec.npz')['mask']
support = np.load('logo5mu_20sec.npz')['support']

plt.figure(1, figsize=(9,4))
plt.subplot(121)
plt.imshow(iobs, norm=LogNorm())
plt.colorbar()
plt.subplot(122)
plt.imshow(mask)
plt.tight_layout()
['mask', 'support', 'iobs']

Optimisation from the known support#

First create the CDI object.

Set the initial object array using random values from the existing mask.

then optimise it using 4 series with 50 cycles of HIO and 20 of ER algorithms.

It converges very easily as the support is known.

[3]:
# Create a figure here so it is displayed before computin begins in the next cell
fig_num = plt.figure().number
[4]:
################## Try first from the known support (too easy !) ################################################
cdi = CDI(fftshift(iobs), obj=None, support=fftshift(support), mask=fftshift(mask), wavelength=1e-10,
          pixel_size_detector=55e-6)

# Initial object
cdi = InitObjRandom(src="support", amin=0, amax=1, phirange=0) * cdi

# Initial scaling, required by mask
cdi = ScaleObj(method='F') * cdi

cdi = (ER(show_cdi=20,calc_llk=20, fig_num=fig_num) ** 20 * HIO(show_cdi=50, calc_llk=20, fig_num=fig_num) ** 50) ** 4 * cdi
 HIO #  0 LLK= 4612.569[free=  0.000](p), nb photons=1.100944e+09, support:nb=  7577 ( 2.890%) <obj>=    381.18 max=   1707.34, out=15.764% dt/cycle=2.1925s
 HIO # 20 LLK= 2428.830[free=  0.000](p), nb photons=1.896053e+09, support:nb=  7577 ( 2.890%) <obj>=    500.24 max=   1649.66, out=3.142% dt/cycle=0.0004s
 HIO # 40 LLK= 4135.959[free=  0.000](p), nb photons=2.136299e+09, support:nb=  7577 ( 2.890%) <obj>=    530.99 max=   1670.51, out=5.343% dt/cycle=0.0003s
  ER # 60 LLK=  65.655[free=  0.000](p), nb photons=1.655936e+09, support:nb=  7577 ( 2.890%) <obj>=    467.49 max=   1701.98, out=0.473% dt/cycle=0.0073s
 HIO # 80 LLK= 1401.642[free=  0.000](p), nb photons=1.761344e+09, support:nb=  7577 ( 2.890%) <obj>=    482.14 max=   1669.99, out=2.762% dt/cycle=0.0062s
 HIO #100 LLK= 3395.131[free=  0.000](p), nb photons=2.026046e+09, support:nb=  7577 ( 2.890%) <obj>=    517.10 max=   1655.83, out=4.783% dt/cycle=0.0006s
  ER #120 LLK= 4797.444[free=  0.000](p), nb photons=2.275491e+09, support:nb=  7577 ( 2.890%) <obj>=    548.01 max=   1705.59, out=5.659% dt/cycle=0.0005s
 HIO #140 LLK=  63.137[free=  0.000](p), nb photons=1.669586e+09, support:nb=  7577 ( 2.890%) <obj>=    469.41 max=   1718.32, out=0.461% dt/cycle=0.0060s
 HIO #160 LLK= 2514.924[free=  0.000](p), nb photons=1.902517e+09, support:nb=  7577 ( 2.890%) <obj>=    501.09 max=   1659.46, out=3.674% dt/cycle=0.0005s
 HIO #180 LLK= 4073.725[free=  0.000](p), nb photons=2.138768e+09, support:nb=  7577 ( 2.890%) <obj>=    531.29 max=   1671.91, out=4.924% dt/cycle=0.0003s
  ER #200 LLK=  70.023[free=  0.000](p), nb photons=1.672150e+09, support:nb=  7577 ( 2.890%) <obj>=    469.77 max=   1728.06, out=0.503% dt/cycle=0.0003s
 HIO #220 LLK= 1441.117[free=  0.000](p), nb photons=1.772438e+09, support:nb=  7577 ( 2.890%) <obj>=    483.66 max=   1673.88, out=2.759% dt/cycle=0.0062s
 HIO #240 LLK= 3421.004[free=  0.000](p), nb photons=2.032799e+09, support:nb=  7577 ( 2.890%) <obj>=    517.96 max=   1667.78, out=4.983% dt/cycle=0.0006s
  ER #260 LLK= 4740.464[free=  0.000](p), nb photons=2.254167e+09, support:nb=  7577 ( 2.890%) <obj>=    545.44 max=   1708.29, out=5.603% dt/cycle=0.0004s

Optimisation from a loose support#

This will use the SupportUpdate operator in addition to ER and HIO.

We use positivity to facilitate convergence towards the solution. This example is difficult to get a good convergence because the object is divided in many small parts, and it is easy to get a wrong support

We can either start from:

  • the real support expanded by a gaussian convolution.

  • from a large circle.

The second choice is more difficult as the initial support is symmetrical, and there is an ambiguity between equivalent twin solutions. For this we perform a few cycles with a halved-support to break the symmetry

The critical parameter here is the threshold value. It is either possible to give it relative the the rms value of the density inside the support, the average or the maximum value (in this case, the threshold has to be set lower than for rms or average methods). In this example rms with threshold=0.28 works well (about half executions give a good result when starting from a smoothed initial support (much fewer for a large circle)).

If the resulting object does not look good, just re-execute the cell.

[5]:
if True:
    tmp = np.arange(-len(iobs)/2, len(iobs)/2)
    y, x = np.meshgrid(tmp, tmp, indexing='ij')
    r = np.sqrt(x**2+y**2)
    sup = r<70
else:
    sup = gaussian_filter(support.copy().astype(np.float32), 6) > 0.1

if False:
    plt.figure(figsize=(5,3))
    plt.imshow(sup, origin='lower')
    plt.title('Initial support')

cdi = CDI(fftshift(iobs), obj=None, support=fftshift(sup), mask=fftshift(mask), wavelength=1e-10,
          pixel_size_detector=55e-6)
# cdi.init_free_pixels()  # We will not use free log-likelihood in this example

# Initial object
cdi = InitObjRandom(src="support", amin=0, amax=1, phirange=0) * cdi

# Initial scaling, required by mask
cdi = ScaleObj(method='F') * cdi

# Support update operator
sup = SupportUpdate(threshold_relative=0.28, method='rms', smooth_width=(2,0.5,600),
                    force_shrink=False, post_expand=None)
#sup = SupportUpdate(threshold_relative=0.07, method='max', smooth_width=(2,0.5,600),
#                    force_shrink=False, post_expand=None)

# Start with HIO, detwin with a halved support, then HIO and ER,
# with a support update every 25 cycles
cdi = (sup * HIO(calc_llk=0, positivity=True, fig_num=fig_num, show_cdi=25) ** 25)**4 * cdi

cdi = DetwinHIO(positivity=True, detwin_axis=0)**20 * cdi

cdi = (sup * HIO(calc_llk=25, positivity=True, fig_num=fig_num, show_cdi=25) ** 25)**20 * cdi

cdi = (sup * ER(calc_llk=25, positivity=True, fig_num=fig_num, show_cdi=25) ** 25)**8 * cdi
 HIO #300 LLK= 7175.238[free=  0.000](p), nb photons=2.130052e+09, support:nb= 15258 ( 5.820%) <obj>=    373.63 max=   1720.49, out=29.232% dt/cycle=0.0022s
 HIO #325 LLK= 4171.641[free=  0.000](p), nb photons=2.645668e+09, support:nb= 17122 ( 6.532%) <obj>=    393.09 max=   2185.05, out=6.120% dt/cycle=0.0063s
 HIO #350 LLK= 4173.628[free=  0.000](p), nb photons=2.808865e+09, support:nb= 16012 ( 6.108%) <obj>=    418.83 max=   2216.54, out=5.094% dt/cycle=0.0051s
 HIO #375 LLK= 4690.854[free=  0.000](p), nb photons=2.969441e+09, support:nb= 15662 ( 5.975%) <obj>=    435.43 max=   2234.87, out=5.196% dt/cycle=0.0053s
 HIO #400 LLK= 5096.825[free=  0.000](p), nb photons=3.089291e+09, support:nb= 15231 ( 5.810%) <obj>=    450.37 max=   2242.46, out=5.226% dt/cycle=0.0053s
 HIO #425 LLK= 5484.562[free=  0.000](p), nb photons=3.223694e+09, support:nb= 15499 ( 5.912%) <obj>=    456.06 max=   2245.97, out=5.313% dt/cycle=0.0055s
 HIO #450 LLK= 5363.531[free=  0.000](p), nb photons=3.263600e+09, support:nb= 14948 ( 5.702%) <obj>=    467.26 max=   2249.74, out=5.149% dt/cycle=0.0070s
 HIO #475 LLK= 5739.916[free=  0.000](p), nb photons=3.313548e+09, support:nb= 14856 ( 5.667%) <obj>=    472.28 max=   2224.20, out=5.366% dt/cycle=0.0056s
 HIO #500 LLK= 5920.529[free=  0.000](p), nb photons=3.357701e+09, support:nb= 15153 ( 5.780%) <obj>=    470.73 max=   2209.28, out=5.405% dt/cycle=0.0056s
 HIO #525 LLK= 5850.015[free=  0.000](p), nb photons=3.397564e+09, support:nb= 14736 ( 5.621%) <obj>=    480.17 max=   2207.65, out=5.304% dt/cycle=0.0054s
 HIO #550 LLK= 6107.034[free=  0.000](p), nb photons=3.411612e+09, support:nb= 14883 ( 5.677%) <obj>=    478.78 max=   2181.47, out=5.752% dt/cycle=0.0057s
 HIO #575 LLK= 6229.871[free=  0.000](p), nb photons=3.401603e+09, support:nb= 15700 ( 5.989%) <obj>=    465.47 max=   2151.75, out=5.978% dt/cycle=0.0067s
 HIO #600 LLK= 6022.861[free=  0.000](p), nb photons=3.366360e+09, support:nb= 16237 ( 6.194%) <obj>=    455.33 max=   2131.59, out=5.616% dt/cycle=0.0056s
 HIO #625 LLK= 5853.568[free=  0.000](p), nb photons=3.308860e+09, support:nb= 16045 ( 6.121%) <obj>=    454.12 max=   2108.74, out=5.568% dt/cycle=0.0057s
 HIO #650 LLK= 5739.361[free=  0.000](p), nb photons=3.339729e+09, support:nb= 14886 ( 5.679%) <obj>=    473.66 max=   2099.67, out=5.441% dt/cycle=0.0057s
 HIO #675 LLK= 5922.723[free=  0.000](p), nb photons=3.379040e+09, support:nb= 14299 ( 5.455%) <obj>=    486.12 max=   2085.98, out=5.617% dt/cycle=0.0057s
 HIO #700 LLK= 5980.330[free=  0.000](p), nb photons=3.295865e+09, support:nb= 14530 ( 5.543%) <obj>=    476.27 max=   2046.55, out=5.773% dt/cycle=0.0075s
 HIO #725 LLK= 5702.435[free=  0.000](p), nb photons=3.253677e+09, support:nb= 13792 ( 5.261%) <obj>=    485.71 max=   2027.15, out=5.369% dt/cycle=0.0056s
 HIO #750 LLK= 5915.592[free=  0.000](p), nb photons=3.248850e+09, support:nb= 14068 ( 5.367%) <obj>=    480.56 max=   2006.99, out=5.633% dt/cycle=0.0056s
 HIO #775 LLK= 5874.727[free=  0.000](p), nb photons=3.197661e+09, support:nb= 14287 ( 5.450%) <obj>=    473.09 max=   1984.56, out=5.563% dt/cycle=0.0057s
  ER #800 LLK= 5666.963[free=  0.000](p), nb photons=3.034746e+09, support:nb= 14335 ( 5.468%) <obj>=    460.11 max=   1917.43, out=5.603% dt/cycle=0.0065s
  ER #825 LLK= 102.078[free=  0.000](p), nb photons=2.309230e+09, support:nb=  7763 ( 2.961%) <obj>=    545.40 max=   1905.44, out=0.948% dt/cycle=0.0054s
  ER #850 LLK= 113.398[free=  0.000](p), nb photons=2.241071e+09, support:nb=  6970 ( 2.659%) <obj>=    567.04 max=   1862.95, out=1.071% dt/cycle=0.0067s
  ER #875 LLK= 121.286[free=  0.000](p), nb photons=2.122297e+09, support:nb=  6488 ( 2.475%) <obj>=    571.94 max=   1812.99, out=1.045% dt/cycle=0.0053s
  ER #900 LLK= 125.219[free=  0.000](p), nb photons=2.023234e+09, support:nb=  6132 ( 2.339%) <obj>=    574.41 max=   1771.89, out=1.058% dt/cycle=0.0053s
  ER #925 LLK= 128.086[free=  0.000](p), nb photons=1.938433e+09, support:nb=  5846 ( 2.230%) <obj>=    575.83 max=   1736.53, out=1.059% dt/cycle=0.0049s
  ER #950 LLK= 132.446[free=  0.000](p), nb photons=1.866448e+09, support:nb=  5576 ( 2.127%) <obj>=    578.56 max=   1704.75, out=1.101% dt/cycle=0.0058s
  ER #975 LLK= 138.214[free=  0.000](p), nb photons=1.807674e+09, support:nb=  5328 ( 2.032%) <obj>=    582.48 max=   1676.38, out=1.153% dt/cycle=0.0066s
[ ]:

On this page
  • Get ESRF logo diffraction data
  • Optimisation from the known support
  • Optimisation from a loose support
Show Source

© Copyright European Synchrotron Radiation Facility, Grenoble, France.

Created using Sphinx 8.2.3.

Built with the PyData Sphinx Theme 0.16.1.