Program of the workshop Wednesday: 9:00-10:00 Introduction to - - PowerPoint PPT Presentation
Program of the workshop Wednesday: 9:00-10:00 Introduction to - - PowerPoint PPT Presentation
Program of the workshop Wednesday: 9:00-10:00 Introduction to pyFAI 10:00-10:30 Software installation on laptop computers 10:30-11:00 Coffee break 11:00-12:30 Demonstration of the user interfaces 12:30-14:00 Lunch at the
07/06/2017 PyFAI Page 2
Program of the workshop
Wednesday:
–
9:00-10:00 Introduction to pyFAI
–
10:00-10:30 Software installation on laptop computers
–
10:30-11:00 Coffee break
–
11:00-12:30 Demonstration of the user interfaces
–
12:30-14:00 Lunch at the canteen
–
14:00-15:00 Spotlight on application: beam-line presentation
–
15:00-16:00 Discussions about needs
–
16:00-16:30 Coffee break
–
16:30-17:30 Tutorials: Jupyter Thursday:
–
9:00-10:00 Tutorials: geometry, detector distortion and calibration
–
10:00-10:30 Coffee break
–
10:30-12:30 Tutorials: multi-geometry, goniometer, inpainting
–
12:30-14:00 Lunch at the canteen
–
14:00-17:00 Coding camp
07/06/2017 PyFAI Page 3
Fast azimuthal integration … in Python
While speed is only needed at large facilities … … proper calculation is needed for any scientific application
07/06/2017 PyFAI Page 4
PyFAI workshop
General introduction to PyFAI
07/06/2017 PyFAI Page 5
Introduction to Azimuthal integration
- Allows the use of area detectors for
–
Small angle scattering
–
Powder diffraction, PDF, ...
- Better harvesting of X-ray photons (large solid angle)
- The devil is hidden in the details (of implementation)
- PyFAI is:
–
Open source
–
Open to contribution
–
Open to discussion
–
Free
–
Fast Azimuthal integration But many other tools exists:
- FIT2D
- DataSqueeze
- XRDUA
- Foxtrot
- Maud
- GSAS-II
07/06/2017 PyFAI Page 6
PyFAI is fast
24/04/2017 PyFAI Page 7
Concepts in PyFAI
- Image
2D array of pixels as numpy array read using silx, fabio, h5py, ...
- Azimuthal integrator: core object
- powder diagram using integrate1d
- “cake” image, azimuthally regrouped using integrate2d
- Detector
- Calculates the pixel position (center and corners)
- Calculate the mask
- Contains the flat-field correction.
- Geometry
Position of the detector from the sample & incoming beam → saved as PONI-file
http://www.silx.org/doc/pyFAI/pyFAI.html#experiment-description
07/06/2017 PyFAI Page 8
About the geometry used in PyFAI
From the sample's point of view, Looking at the detector : rot1 ↑ : move detector to the right rot2 ↑ : move detector downwards rot3 ↑ : move detector clockwise
Incoming X-Ray beam
Origin : sample position
x3 x1 x2
- 3 distances in meter: dist, poni1, poni2
- 3 rotation in radians: rot1, rot2, rot3
- wavelength / energy
Distance
Point Of Normal Incidence : PONI = (P1, P2, P3=0)
d1 d2 d3 rot1 rot3 S c a t t e r e d b e a m 2θ Area detector
Detector's origin: lower left, looking from the sample
PONI-file
24/04/2017 PyFAI Page 9
What happens during an integration
1) Get the pixel coordinates from the detector, in meter. There are 3 coordinates par pixel corner, and usually 4 corners per pixel. 1Mpix image → 48 Mbyte ! 2) Offset the detector's origin to the PONI and rotate around the sample 3) Calculate the radial (2θ) and azimuthal (χ) positions of each corner 4) Assign each pixel to one or multiple bins. If a look-up table is used, just store the fraction of the pixel. Then for each bin sum the content of all contributing pixels. 5) Histogram bin position with associated intensities 6) Histogram bin position with solid angle (and other normalization) 7) Return bin position and the ratio of sum of intensities / sum of Ω
24/04/2017 PyFAI Page 10
- The determination of the geometry is also known as calibration
–
The prerequisite is:
- detector geometry and mask,
- calibrant (LaB6, CeO2, AgBh, …)
- wavelength or energy used
–
Only the position of the detector and the rotation needs to be refined:
- 3 translations: dist, poni1 and poni2
- 3 rotations: rot1, rot2, rot3
- It is divided into 4 major steps:
1) Extraction of groups of peaks 2) Identification of peaks and groups of peaks belonging to same ring 3) Least-squares refinement of the geometry parameters on peak position 4) Validation by an human being of the geometry
- PyFAI assumes this setup does not change during the experiment
- Tutorial:
http://www.silx.org/doc/pyFAI/usage/cookbook/calibrate.html
Calibration in pyFAI
24/04/2017 PyFAI Page 11
PyFAI is a library & an application ...
Library
–
Re-usable code
–
Needs the definition of an API
–
Faster to develop
–
Easier to test and maintain
Graphical application
–
Easier to use
–
Looks better
–
Only one application
–
Harder for re-use
- PyFAI is itself relying on the Scientific Python stack:
–
NumPy
–
SciPy
–
Matplotlib
–
H5Py
–
Cython
–
FabIO + PyQt5 + silx
≠
24/04/2017 PyFAI Page 12
Examples of other application relying on pyFAI
- NanoPeakCell: Serial crystallography pre-processing
–
Nicolas Coquelle, IBS Grenoble
- PySaxs: data analysis for SAXS experimental station
–
Olivier Tache, CEA Saclay
- Dpdak: online data analysis for Saxs data
–
Gunthard Benecke, Petra III
- Dioptas: offline data analysis for high pressure diffraction
–
Clemens Percher, APS → Germany
- Bubble: online data analysis for Saxs/Waxs data
–
Vadim Diadkin, Dubble & SNBL CRG beamlines
- Project for materials and strain analysis
–
Jozef Keckes, Loeben university, Austria
- xPDFsuite
–
- Prof. Simon Billinge, U. of Columbia
http://www.silx.org/doc/pyFAI/ecosystem.html
24/04/2017 PyFAI Page 13
PyFAI mailing list subscribers
grouped by country
ESRF France Germany Google/hotmail United Kingdom System Spain USA Italy Sweden Netherlands
User community of pyFAI
- PyFAI is used in most European and American synchrotons/FELs
- User support is provided via the mailing list: pyFAI@esrf.fr
–
Direct contact with authors is discouraged
http://www.silx.org/doc/pyFAI/project.html#getting-help
07/06/2017 PyFAI Page 14
Layers in pyFAI
- Applications level:
–
GUI applications: pyFAI-calib, pyFAI-integrate, diff_map
–
Scriptable applications:pyFAI-average, pyFAI-saxs, pyFAI-waxs, diff_tomo, …
- Python interface:
–
Top level: azimuthal integrator
–
Mid level: calibrant, detector, geometry, calibration
–
Low level: rebinning/histogramming engines (Cython or OpenCL)
- Question: how to define the right balance ?
It is up to you ! F l e x i b i l i t y E a s e
- f
u s e
07/06/2017 PyFAI Page 15
Silx-kit
The silx ecosystem
07/11/2016 Jérôme Kieffer | data analaysis unit | ESRF Page 16
silx-kit: join efforts, share the maintenance
07/11/2016 Jérôme Kieffer | data analaysis unit | ESRF Page 17
Management of the silx-kit project
- Public project hosted at github
https://github.com/silx-kit/silx
- Continuous testing
Linux, Windows and macOS
- Nightly builds
–
Debian packages
- Weekly meetings
- Quarterly releases
- Code camps before release
- Continuous documentation
http://www.silx.org/doc/silx/
07/11/2016 Jérôme Kieffer | data analaysis unit | ESRF Page 18
silx-kit project and the silx library
Mainly Henri Payno Mainly Jérôme Kieffer … and Valentin Valls Mainly Pierre Knobel … Mainly Thomas Vincent
07/11/2016 Jérôme Kieffer | data analaysis unit | ESRF Page 19
Dahu: Online data analysis server
Dahu is a lightweight plugin based framework... ... technically a JSON-RPC server over Tango written in Python
- The dahu server executes jobs
–
Each job lives in its own thread.
–
Each jobs execute one plugin
–
The job is responsible for de/serializing JSON string coming from Tango
- Plugins are Python classes or functions
–
Plugins are dynamically loaded from python modules
–
Plugins have a single input and output: simple dictionaries.
- Jobs can be re-processed off-line
- Lightweight means limited overhead:
–
1 µs for a dummy plugin execution
–
150 µs for a dummy job
–
<0.3 ms when called from Tango Available on https://github.com/kif/dahu
07/11/2016 Jérôme Kieffer | data analaysis unit | ESRF Page 20
Applications in pyFAI
07/06/2017 PyFAI Page 21
Description of applications in pyFAI:
- Preprocessing
- Mask drawing tool
- Calibration
- Integration
- Diffraction mapping
- Other features
07/06/2017 PyFAI Page 22
Image pre-processing: pyFAI-average
- A tool for filtering a stack of images :
–
Used to merge multiple input images (can be a multiframe nexus)
–
Merging methods available:
min, max, mean, std, median, sum, quantiles, cutoff
–
Correct for dark-current & flat-field
–
Normalize for a monitor value (from headers)
–
Exports in multiple formats (see FabIO)
- Can be used to convert image format (NeXus → TIF)
http://www.silx.org/doc/pyFAI/man/pyFAI-average.html
07/06/2017 PyFAI Page 23
Mask drawing tool: pyFAI-drawmask
http://www.silx.org/doc/pyFAI/man/pyFAI-drawmask.html Click here when your done
07/06/2017 PyFAI Page 24
Calibration: pyFAI-calib (CLI) & pyFAI-calib2 (GUI)
- The determination of the geometry is also known as calibration
–
The prerequisite is:
- detector geometry and mask,
- calibrant (LaB6, CeO2, AgBh, …)
- wavelength or energy used
–
Only the position of the detector and the rotation needs to be refined:
- 3 translations: dist, poni1 and poni2
- 3 rotations: rot1, rot2, rot3
- PyFAI assumes this setup does not change during the experiment
- It is divided into 4 major steps:
–
Extraction of groups of peaks
–
Identification of peaks and groups of peaks belonging to same ring
–
Least-squares refinement of the geometry parameters on peak position
–
Validation by an human being of the geometry http://www.silx.org/doc/pyFAI/man/pyFAI-calib.html
07/06/2017 PyFAI Page 25
Graphical application pyFAI-calib2
- See Valentin's talk:
07/06/2017 PyFAI Page 26
Azimuthal integration tool: pyFAI-integrate
From PONI file Define the output space Can now be used in command line mode without Qt
07/06/2017 PyFAI Page 27
Diffraction imaging offline tool: diff-map
07/06/2017 PyFAI Page 28
Diffraction imaging visualization using silx (2D slicing)
07/06/2017 PyFAI Page 29
Diffraction imaging visualization using silx (3D slicing)
07/06/2017 PyFAI Page 31
Past & Future: What are the projects ?
07/06/2017 PyFAI Page 32
PyFAI: Past ...
- Looking back:
–
2011: Basic idea: geometry, refinement, histograms
–
2012: Dimitris Karkoulis: histogramming in OpenCL, Pixel splitting
–
2013: Zubair Nawaz: spline calculation in OpenCL, Look-up table
–
2014: Aurore Deschildre: blob pixel detection Giannis Ashiotis: CSR sparse matrix multiplication
–
2015: Frederic Sulzman pixel-detector description
–
2016 - 2019: Valentin Valls: graphical interface for pyFAI Silx collaboration (GUI mainly)
07/06/2017 PyFAI Page 33
PyFAI: Present & Future ...
- Recently done:
–
OpenCL port of “separate” and other “sorts” on GPU (ID13)
–
Detector distortion, correction, NeXus representation (ID15, ID02, BM02)
–
Diffraction imaging (ID21, ID13, BM02)
–
Multi-detector integrators & goniometer calibration (BM02, BM20, ID31)
–
log(q) & other user defined output spaces (ID02)
–
Image inpainting (ID15, ID31)
–
Prototype for GUI (ID15, ID16, ID21, ID22)
- On the radar
–
GUI interface : single application (silx)
–
Sensor thickness effects (ID31)
–
Auto-calibration (without human intervention)
–
User defined variance (ID02)
- You have ideas ? We are open to collaboration !
07/06/2017 PyFAI Page 34
PyFAI as a library
Introduction to the Pythonic side of pyFAI
07/06/2017 PyFAI Page 35
Installation
Installation of the Python scientific stack
07/06/2017 PyFAI Page 36
Fresh install using Anaconda
- Install Anaconda3 (from the USB-stick)
- Install the silx tools:
–
pip install silx-*.whl
–
pip install fabio*.whl
–
pip install pyFAI*.whl
- If you need pyopencl (for GPU computing)
–
conda install -c conda-forge pyopencl
07/06/2017 PyFAI Page 37
Using an existing Python installation
- Using Python 2.7, 3.4, 3.5 or 3.6
–
Ensure pip, setuptools and wheel are up to date
–
Use virtualenv (or pyvenv under python3)
- Create a Virtual environment:
–
pyvenv pyfai-tuto
–
. pyfai-tuto/bin/activate
–
python -m pip install pip --upgrade
–
pip install setuptools wheel –upgrade
–
pip install numpy scipy matplotlib numexpr h5py
- -trusted-host www.silx.org --find-links http://www.silx.org/pub/wheelhouse/
- Install the silx stack
–
pip install …/silx*.whl
–
pip install …/fabio*.whl
–
pip install …/pyFAI*.whl
07/06/2017 PyFAI Page 38
Program of the workshop
Wednesday:
–
9:00-10:00 Introduction to pyFAI
–
10:00-10:30 Software installation on laptop computers
–
10:30-11:00 Coffee break
–
11:00-12:30 Demonstration of the user interfaces
–
12:30-14:00 Lunch at the canteen
–
14:00-15:00 Spotlight on application: beam-line presentation
–
15:00-16:00 Discussions about needs
–
16:00-16:30 Coffee break
–
16:30-17:30 Tutorials: Jupyter Thursday:
–
9:00-10:00 Tutorials: geometry, detector distortion and calibration
–
10:00-10:30 Coffee break
–
10:30-12:30 Tutorials: multi-geometry, goniometer, inpainting
–
12:30-14:00 Lunch at the canteen
–
14:00-17:00 Coding camp
07/06/2017 PyFAI Page 39
Description of the Python API
- Top level API:
–
AzimuthalIntegrator
- Method for azimuthal averaging: integrate1d
- Method for azimuthal regrouping: integrate2d
–
Distortion
- Correct and uncorrect methods
- Mid level API:
–
Geometry: Parent class of AzimuthalIntegrator
–
Detector: Calculate the pixel position & masks
–
Calibrant: provide 2θ as function of the wavelength
- Low level API: different rebinning engines
–
OCL_LUT_Integrator, OCL_CSR_Integrator, ...
–
SplitBBoxLUT, splitBBoxCSR, ...
F l e x i b i l i t y E a s e
- f
u s e
07/06/2017 PyFAI Page 40
Description of the Python API
- Detector
- Distortion
- Azimuthal integrator
- Geometry
- Calibrant
- Geometry refinement
- Calibration
- Worker (online data analysis)
- Multi-geometry integrator
- Goniometer
07/06/2017 PyFAI Page 41
Detectors
- Detector are 2D array of pixel, they contain:
–
pixel size
–
mask
–
A way to calculate where a pixel is located in space (3D)
- PyFAI provides 120 (56 unique) detectors pre-defined
–
Dectris, ImXpad, Rayonix, Dexela, Perkin-Elmer, …
- Detectors can easily be specialized:
–
With their specific masks
–
With their specific pixel positions
–
Then saved to a NeXus file
- Detector can be contiguous or not ...
- Detectors can be flat or not ...
07/06/2017 PyFAI Page 42
Example of non-contiguous detectors:
- Xpad are module based pixel-detectors
–
The S540 is 8 strips of 7 modules each
–
Gaps between modules within a strip are small (few pixels)
–
Gaps between strips are large (hundreds of pixels)
- Can be challenging to calibrate !
–
Calibrant: LaB6 at 18.57keV
07/06/2017 PyFAI Page 43
Detector: Creation
Detector is a base-class defining any kind of 2D-detectors. There are about 56 specialized detectors: Pilatus, Xpad, Rayonix …
- Usage: there is a factory to instantiate a detector from its name:
det = pyFAI.detector_factory("pilatus1M")
- Important methods:
–
get_mask(): calculate and cache the mask for this detector
–
save(nexusfile): save the detector configuration into HDF5
–
get_pixel_corners(): in cartesian position -> 4D array (Ny,Nx,Nc,3) http://www.silx.org/doc/pyFAI/api/pyFAI.html#module-pyFAI.detectors
07/06/2017 PyFAI Page 44
Distortion
Use the rebinning engines to perform distortion correction of detectors
- Usage:
dis = pyFAI.distortion.Distortion(detector)
- Important method:
–
correct(img): re-distribute intensity on a regular grid.
–
uncorrect(img): reverse a correction, for masks in Fit2D
- Nota:
Because of the great regularity of this rebinning, LUT is faster than CSR http://www.silx.org/doc/pyFAI/api/pyFAI.html#module-pyFAI.distortion
07/06/2017 PyFAI Page 45
Distortion correction, just an example
Fast (ms) Slow (s) WOS detector, courtesy of D2AM CRG beamline import pyFAI, fabio from pyFAI.distortion import Distortion wos = pyFAI.detector_factory('wos.h5') dis = Distortion(wos, resize=True) Raw = fabio.open('image.edf').data cor = dis.correct(raw) uncor = dis.uncorrect(cor)
07/06/2017 PyFAI Page 47
Azimuthal Integrator
Performs the azimuthal regrouping in 1&2D. Inherits Geometry, composes Detector, Integrators
- Creation: import a PONI-file:
ai=pyFAI.load(ponifile)
- Important methods (note many deprecated methods):
–
Integrate1d; integrate2d; separate; inpainting
- Common arguments:
- data (ndarray) – 2D array from the Detector/CCD camera
- npt – number of points in the output pattern # npt_rad, npt_azim
- filename (str) – output filename in 2 column ascii format (3 col with errors)
- correctSolidAngle (bool) – correct for solid angle of each pixel if True
- variance (ndarray) – array containing the variance of the data. If not available, no error propagation is done
- error_model (str) – i.e. “poisson” (variance = I), “azimuthal” (variance = (I-<I>)^2)
- radial_range (float, float) – The lower and upper range of the radial unit.
- azimuth_range (float, float) – The lower and upper range of the azimuthal angle in degree.
- mask (ndarray) – array (same size as image) with 1 for masked pixels, and 0 for valid pixels
- dummy (float) – value for dead/masked pixels
- delta_dummy (float) – precision for dummy value
- polarization_factor (float) – polarization factor -1 (vertical), 0 (circular) +1 (horizontal), None for no correction
- dark (ndarray) – dark noise image
- flat (ndarray) – flat field image
- method (str) – can be “numpy”, “BBox” or “splitpixel”, “lut”, “csr”, “nosplit_csr”, “full_csr”, “lut_ocl” and “csr_ocl”
- unit (pyFAI.units.Enum) – Output units, can be “q_nm^-1”, “q_A^-1”, “2th_deg”, “r_mm” …
- normalization_factor (float) – Value of a normalization monitor
- Returns:
–
Integrate result: looks like a tuple with intensity and bin-center coordinates
http://www.silx.org/doc/pyFAI/api/pyFAI.html#pyFAI.azimuthalIntegrator.AzimuthalIntegrator
07/06/2017 PyFAI Page 48
Geometry
In charge of calculating the 2th/q/r/chi position for a point in space, handles array caching and locking. Contains the detector (composition)
- Usage:
–
Not directly: Usually via ai objects (inherited by AzimuthalIntegrator)
- Important methods:
–
calcfrom1d(tth,I): back-project powder pattern in a 2D image
–
get/set|PyFAI/SPD/Fit2D: exchange geometries with other programs
–
load(ponifile): instanciate geometry/aifrom a poni-file
–
reset(): empty all caches
- Warning:
–
may be re-implemented one day with pluggable geometry-engines to have them interchangeable http://www.silx.org/doc/pyFAI/api/pyFAI.html#module-pyFAI.geometry
07/06/2017 PyFAI Page 49
About the geometry used in PyFAI
From the sample's point of view, Looking at the detector : rot1 ↑ : move detector to the right rot2 ↑ : move detector downwards rot3 ↑ : move detector clockwise
Incoming X-Ray beam
Origin : sample position
x3 x1 x2
- 3 distances in meter: dist, poni1, poni2
- 3 rotation in radians: rot1, rot2, rot3
- wavelength / energy
Distance
Point Of Normal Incidence : PONI = (P1, P2, P3=0)
d1 d2 d3 rot1 rot3 S c a t t e r e d b e a m 2θ Area detector
Detector's origin: lower left, looking from the sample
PONI-file
07/06/2017 PyFAI Page 51
Calibrants: provide aperture of Debye-Scherrer cones
- PyFAI ships 15 reference samples (decreasing 2θ of first ring) + variants:
–
Au: Gold
–
ZnO: Blende
–
CeO2: Ceria
–
Si: Silicon
–
NaCl: Salt
–
alpha_Al2O3: Corundum
–
Cristobaltite and Quartz (SiO2)
–
Cr2O3 and CrOx : Chromium oxide (the later being the undefined oxide used on MX beamlines)
–
LaB6: Lantanide hexaboride
–
PBBA: Para Bromo Benzoic Acid
–
C14H30O: tetradecanol
–
AgBh: Silver Behenate
- But you can provide your d-spacing file if you prefer:
–
Ascii text files with d-spacing written in Angstrom (like FIT2D)
–
Use the American Minaralogist database:
- http://rruff.geo.arizona.edu/AMS/amcsd.php
07/06/2017 PyFAI Page 52
Calibrant
A calibrant is a reference compound where the d-spacings (interplanar distances) are known. The Calibrant class loads them from a file and contains the wavelength.
- Usage:
–
LaB6 = pyFAI.calibrant.get_calibrant(“LaB6”)
–
Pt = pyFAI.calibrant.Calibrant(dspacing=[2.265,1.962,1.387,1.183,1.133])
- Important method
–
set_wavelength(1e-10): write once !!!!
–
get_2th(): get the position in 2theta of the reflection
–
fake_calibration_image(ai): simulate a calibration image given the geometry and the detector in ai http://www.silx.org/doc/pyFAI/api/pyFAI.html#module-pyFAI.calibrant
07/06/2017 PyFAI Page 53
Geometry Refinement
Given a set of points (x,y) and associated ring number, refines the parameter of the PONI-file. Inherits from AzimuthalIntegrator. Contains a calibrant
- Usage:
–
Used by calibration
- Important methods:
–
Simplex, Refine1, Refine2: wraps scipy.optimize.fmin function
- Warning:
–
should not inherit from AzimuthalIntegrator but compose Geometry
http://www.silx.org/doc/pyFAI/api/pyFAI.html#module-pyFAI.geometryRefinement
07/06/2017 PyFAI Page 54
Calibration
Command line interface for calibration
- Usage:
–
Used from pyFAI-calib script.
- Alternative:
–
There is a procedural interface to Calibration:
ai = pyFAI.calibration.calib(img, calibrant, detector)
–
Can be used, for example, in Jupyter notebooks or from NexPy http://www.silx.org/doc/pyFAI/api/pyFAI.html#module-pyFAI.calibration
07/06/2017 PyFAI Page 55
Worker: for online data analysis scripts
Set of classes to perform azimuthal integration, distortion correction or normalization, repetitively on a set of files.
- Usages:
w = pyFAI.worker.Worker(ai) w = pyFAI.worker.DistortionWorker(detector) w = pyFAI.worker.PixelwiseWorker(dark, flat, mask)
- Important method:
–
w.process(img) http://www.silx.org/doc/pyFAI/api/pyFAI.html#module-pyFAI.worker
07/06/2017 PyFAI Page 56
Multi-geometry integrator
- Assemble multiple images taken at various position into a single pattern
Documented on: http://www.silx.org/doc/pyFAI/usage/tutorial/multi-geometry.html
Courtesy of D2AM CRG
Takes care of solid-angle normalization between detector
07/06/2017 PyFAI Page 57
Goniometer: defintion
- Define a detector's position mounted on a goniometer arm:
–
PONI = function (motor positions, parameters) from pyFAI.goniometer import GeometryTransformation goniotrans = GeometryTransformation(param_names=["dist", "poni1", "poni2", "rot1", "rot2", "scale2"], dist_expr="dist", poni1_expr="poni1", poni2_expr="poni2", rot1_expr="rot1", rot2_expr="scale2 * pos + rot2", rot3_expr="0.0")
- Refine parameters from multiple position in space
- Save to JSON file and retrieve from disk
- Generate a multi-geometry integrator as needed
–