pyextal.optimize

Attributes

Classes

CoarseOptimize

Class for coarse optimization of thickness, orientation, and gl.

FineOptimize

Class for fine optimization of the structure factor.

Functions

selectBeams(gInclude[, beams, maxPanels])

Chooses which reflections a display method draws.

panelGrid(npanels[, rowsPerPanel, ncols, size])

Lays out npanels panels on a wrapped grid.

voigt_2d(sigma, gamma, radius)

Generates a 2D Voigt profile.

Module Contents

pyextal.optimize.MAX_PANELS = 24
pyextal.optimize.PANEL_COLS = 8
pyextal.optimize.selectBeams(gInclude, beams=None, maxPanels=MAX_PANELS)

Chooses which reflections a display method draws.

Parameters:
  • gInclude (Sequence) – The ROI’s reflections, in template order.

  • beams (Sequence | str, optional) – Positions in gInclude and/or (h, k, l) tuples to draw, or 'all'. Defaults to None, the first maxPanels reflections.

  • maxPanels (int, optional) – Cap applied when beams is None. Defaults to MAX_PANELS.

Returns:

Positions in gInclude.

Return type:

List[int]

pyextal.optimize.panelGrid(npanels, rowsPerPanel=1, ncols=PANEL_COLS, size=(3.0, 3.0))

Lays out npanels panels on a wrapped grid.

Parameters:
  • npanels (int) – Number of panels.

  • rowsPerPanel (int, optional) – Axes stacked vertically per panel, e.g. 2 for an experiment-over-simulation pair. Defaults to 1.

  • ncols (int, optional) – Panels per row. Defaults to PANEL_COLS.

  • size (tuple, optional) – (width, height) in inches of one axes.

Returns:

(fig, panels) where panels[p] is the list of rowsPerPanel axes of panel p. Unused grid cells are removed.

Return type:

tuple

class pyextal.optimize.CoarseOptimize(dinfo: pyextal.dinfo.BaseDiffractionInfo, roi: pyextal.roi.BaseROI, searchRadius: float = None, nx: int = None, backend: str = 'numpy')

Class for coarse optimization of thickness, orientation, and gl.

Variables:
  • dinfo (BaseDiffractionInfo) – Diffraction information object.

  • param (SimParams) – Bloch simulation from dinfo.

  • roi (BaseROI) – The region of interest object.

  • thickness (float) – The sample thickness from dinfo.

  • gl (float) – geometric scaling factor from dinfo.

  • indices (List[int]) – List of indices matching reflections to the exitwave.

  • exitwave (np.ndarray) – The simulated exitwave.

  • side (float) – The side length of the simulation used for tilt mapping.

  • scale_factor (float) – The scale factor from LARBED calibration between simulation and experiment.

  • templates (np.ndarray) – The experimental templates extracted from the ROI.

dinfo
backend = 'numpy'
param
roi
thickness
gl
indices = []
exitwave
templates
correlate(exitwave, templates, margin=2)

Cross-correlates a simulation against the experimental templates.

The full search covers every offset of the templates within the zoomed simulation – on the SrTiO3 example a 459x459 space, and 56% of the cost of one temperature-factor evaluation. Once the orientation is known, re-searching all of it to re-find the same peak is wasted work, so setting searchWindow restricts the search to a box around the previous peak.

Parameters:
  • exitwave (np.ndarray) – (nbeam, ny, nx) zoomed simulation.

  • templates (np.ndarray) – (nbeam, ty, tx) experimental templates.

  • margin (int, optional) – How close to a window edge a peak may sit before the window is judged too small. Defaults to 2.

Returns:

(total, origin) – the correlation volume and the (row, col) offset of its origin within the full search space, so a peak position maps back as loc + origin.

Return type:

tuple

Note

searchWindow defaults to None, the full search, which is what every caller gets unless it opts in.

The window is only trusted when its peak sits away from an edge that the full search would have seen past. An edge that coincides with the edge of the whole search space is not suspicious – on the SrTiO3 example the peak really does sit in column 0 – but an interior one means the true peak may lie outside, and the full search is repeated. The check lives here rather than in the caller because thicknessTarget reads this correlation too: a window that silently clipped the peak would corrupt every value in the inner thickness search, and no later check could undo that.

optimizeOrientationGeometry(target: Callable, targetValue: float) → float

Optimizes a single parameter (thickness or gl) and the sample orientation.

This method uses scipy.optimize.minimize_scalar to find the optimal value for a given target function (e.g., thickness or gl). After finding the best parameter value, it determines the optimal sample tilt by finding the location of the maximum correlation in the template matching result.

Parameters:
  • target (Callable) – The target function to minimize (e.g., thicknessTarget or glTarget).

  • targetValue (float) – The initial guess for the parameter being optimized.

Returns:

The optimized value for the target parameter.

Return type:

float

optimizeOrientationThickness(filter=None, threshold=None) → None

Optimizes the thickness and orientation of the experimental pattern.

optimizeOrientationGL(filter=None, threshold=None) → None

Optimizes the gl and orientation of the experimental pattern.

static thicknessTarget(x0, *args)

Error function for thickness optimization.

Parameters:
  • x0 (float) – Thickness value.

  • *args – CoarseOptimize instance.

Returns:

The optimization error, calculated as 1 - max_correlation.

Return type:

float

static glTarget(x0, *args)

Error function for gl optimization.

Parameters:
  • x0 (float) – gl value.

  • *args – CoarseOptimize instance.

Returns:

The optimization error, calculated as 1 - max_correlation.

Return type:

float

optimizeDWF(aniso=False, group='atom', method=None, options=None, refit_xtol=None, window=None, verbose=True) → None

Optimizes the temperature factors against the cross-correlation.

Each evaluation costs a full re-diagonalization – the temperature factors enter Ugh, so there is no way to avoid bloch_run – plus the inner thickness/orientation refit that keeps the comparison fair. Everything here is therefore aimed at needing fewer evaluations and making each one cheaper, rather than at the search itself.

Parameters:
  • aniso (bool, optional) – Refine the symmetry-allowed anisotropic components of each site instead of one isotropic B. The number of parameters is set by site symmetry, not by hand: see pyextal.adp.allowed_beta_basis(). Defaults to False.

  • group (str | list, optional) – 'atom' for one parameter set per asymmetric-unit atom, 'type' to tie atoms of the same element together, or an explicit list of index lists. Defaults to 'atom'.

  • method (str, optional) – scipy solver. Defaults to constant['coarse_DWF']['method'].

  • options (dict, optional) – scipy solver options. Defaults to constant['coarse_DWF']['options'], filtered to the ones the chosen solver actually accepts.

  • refit_xtol (float, optional) – Temporarily loosens the tolerance of the inner thickness fit for the duration of the search. Brent reads it as a relative tolerance, so the configured 1e-3 is already only about half an Angstrom at a typical thickness.

  • window (int, optional) – Half-width, in pixels, of the correlation search box held around the known peak, via searchWindow. Opt-in, and off by default: the full search is the largest single cost here (56% of an evaluation on the SrTiO3 example, against 15% for bloch_run), and a window of 24 px cuts an evaluation from 56 s to 25 s – but it is not free. The inner thickness fit is not bracketed, so a single evaluation can walk the thickness by 20 Angstrom, far enough for the best template offset to leave a small box, and on the SrTiO3 example that changed the first evaluation’s score from 0.31104 to 0.31362. Set it when the orientation is already converged and the speed matters, and read the drift warning printed at the end.

  • verbose (bool, optional) – Report each evaluation. Defaults to True.

Warning

On the SrTiO3 LARBED example this target has no interior minimum. 1 - corr falls monotonically as B(Sr) goes 0.62 -> 2.0 and every atom ends pinned against the 2.0 Angstrom^2 bound, from starting values of 0.62 / 0.44 / 0.80 – physically wrong for SrTiO3 at room temperature. The correlation prefers more thermal damping without limit, so what comes back is the bound rather than a measurement. A warning is printed when that happens. Check it before quoting any number from here, and prefer the chi-squared metrics of FineOptimize or the JAX stage for temperature factors.

Note

The local sensitivity is tiny too – a 23% change in B(Sr) moves the objective by 5e-5 – so a tight convergence tolerance mostly buys noise on top of a target that is already pointing the wrong way.

static _dwfOptions(method, options, n)

Translates the configured options into ones the solver accepts.

constant['coarse_DWF']['options'] is written in Nelder-Mead spellings (fatol, xatol, adaptive) while the configured method is Powell, which discards them – so the tolerances never reached the solver and it ran on scipy’s defaults. This maps them across.

Parameters:
  • method (str) – scipy solver name.

  • options (dict) – Requested options.

  • n (int) – Number of free parameters.

Returns:

Options the solver accepts.

Return type:

dict

Note

Scaling Powell’s direc does not shrink its line search here, which is worth stating because it looks like it should. With bounds given, _linesearch_powell takes the _minimize_scalar_bounded branch and searches the whole feasible interval along each direction, so the direction’s magnitude only rescales the step variable. It does rescale the tolerance, which is measured in that variable: a smaller direc therefore converges tighter and costs more evaluations. Control the cost with xtol and ftol, which are in the units of the parameters and the objective.

static callbackDWF(y0)

Prints the current parameter vector.

Parameters:

y0 (np.ndarray) – Current parameters.

Note

Kept for callers that pass it explicitly. optimizeDWF() reports per evaluation instead, which is the granularity that matters when one evaluation is a simulation.

static correlationTargetDWF(y0, *args)

Error function for DWF optimization.

Parameters:
  • y0 (np.ndarray) – Temperature-factor coefficients in the active pyextal.adp.DWFModel parameterization. For the default isotropic per-atom refinement these are the B values, one per asymmetric-unit atom, exactly as before.

  • *args – a CoarseOptimize instance.

Returns:

The optimization error, calculated as 1 - max_correlation.

Return type:

float

optimizeXYZ() → None

Optimizes the atomic (x, y, z) coordinates for all atoms.

This method uses scipy.optimize.minimize to find the optimal atomic positions that maximize the correlation between simulated and experimental patterns.

static callbackXYZ(y0)
static correlationTargetXYZ(y0, *args)

Error function for XYZ coordinate optimization.

Parameters:
  • y0 (np.ndarray) – XYZ coordinates for each atom.

  • *args – a CoarseOptimize instance.

Returns:

The optimization error, calculated as 1 - max_correlation.

Return type:

float

optimizeCell() → None

Optimizes the cell parameters.

Currently, this method optimizes ‘a’ and ‘c’ for a tetragonal/hexagonal system, assuming a=b. It uses scipy.optimize.minimize to find the optimal cell parameters that maximize the correlation.

static callbackCell(y0)
static correlationTargetCell(y0, *args)

Error function for cell parameter optimization.

Parameters:
  • y0 (np.ndarray) – Cell parameters.

  • *args – a CoarseOptimize instance.

Returns:

The optimization error, calculated as 1 - max_correlation.

Return type:

float

optimizeHV(filter=None, threshold=None) → None

Optimizes the high voltage (HV).

static HVTarget(x0, *args)

Error function for HV optimization.

Parameters:
  • x0 (float) – High voltage value.

  • *args – a CoarseOptimize instance.

Returns:

The correlation error.

Return type:

float

displayCoarseSearch(filter=None, threshold=None, beams=None)

Displays the result of the coarse search.

Parameters:
  • filter (Callable, optional) – Filter applied to both images.

  • threshold (Callable, optional) – Threshold applied to both images.

  • beams (Sequence | str, optional) – Reflections to draw, as positions in roi.gInclude and/or (h, k, l) tuples, or 'all'. Defaults to the first MAX_PANELS.

class pyextal.optimize.FineOptimize(dinfo: pyextal.dinfo.BaseDiffractionInfo, roi: pyextal.roi.BaseROI, reflections: List[Tuple[int, int, int]], sfMask: numpy.ndarray, noncentro: bool = False, errorFunc: pyextal.gof.BaseGOF = None, perturbROI: bool = False, shiftDisk: bool = False, symUpdate=False, probe: Tuple[float, float] = None, refineProbe: bool = True, backend: str = 'numpy')

Class for fine optimization of the structure factor.

Variables:
  • dinfo (BaseDiffractionInfo) – The main diffraction information object.

  • thickness (float) – The thickness of the sample in Angstroms from dinfo.

  • lastParam (SimParams) – The last used simulation parameters.

  • roi (BaseROI) – The region of interest object for refinement.

  • refineProbe (bool) – Flag to indicate if probe parameters should be refined.

  • reflections (List[Tuple[int, int, int]]) – List of (h, k, l) Miller indices for the reflections being optimized.

  • sfMask (np.ndarray) – Mask to select which structure factor components to optimize.

  • noncentro (bool) – Flag for non-centrosymmetric structures.

  • errorFunc (BaseGOF) – The goodness-of-fit function used for optimization.

  • symUpdate (bool) – Flag to update Ugh matrix with symmetry equivalents.

  • history (List) – A list to store the optimization history.

dinfo
thickness
lastParam
roi
_probe = None
refineProbe = True
backend = 'numpy'
reflections
sfMask
noncentro = False
errorFunc = None
_perturbROI = False
_shiftDisk = False
symUpdate = False
history = []
_nfit = 0
property perturbROI

Flag to indicate if ROI parameters (thickness, gl, rotation) should be refined.

Type:

bool

property probe

Probe parameters (sigma, gamma) for convolution.

Type:

tuple[float, float] | None

property shiftDisk

Flag to indicate if individual disk shifts should be refined.

Type:

bool

calDOF() → int

Calculates the degrees of freedom for the optimization.

Returns:

the degree of freedom for the optimization.

Return type:

int

getx0(x0=None) → None

Gets the initial guess for the optimization.

Parameters:

x0 (np.ndarray, optional) – Initial guess for structure factors. Shape (len(reflections), 4) for non-centro, (len(reflections), 2) for centro. Defaults to None.

getRange(x0Range=None) → None

Sets the range to normalize the structure factor.

normalizeX0()

Normalizes the structure factor and applies the mask.

denormalizeX0(x0)

Denormalizes the structure factor and removes the mask.

static canBlit(canvas) → bool

True if canvas implements the blitting API the live plot uses.

Only the Agg-derived canvases (Qt5Agg, TkAgg, Agg, …) provide copy_from_bbox/restore_region. A bare FigureCanvasBase, which is what a figure carries under some notebook backends, does not — blitting into one raises AttributeError.

Parameters:

canvas – The figure canvas to probe.

Returns:

True if the canvas can blit.

Return type:

bool

optimize(x0: numpy.ndarray = None, x0Range: numpy.ndarray = None, refineSF: bool = True, beams=None) → None

Runs the fine optimization.

Parameters:
  • x0 (np.ndarray, optional) – Initial guess for structure factors. Defaults to None.

  • x0Range (np.ndarray, optional) – Range for structure factor normalization. Defaults to None.

  • refineSF (bool, optional) – If False, the structure factors are held at x0 and only the geometry (thickness, and gl/rotation/shift, disk shifts and probe when those are enabled) is refined, by a single evaluation of SFtarget. Defaults to True.

  • beams (Sequence | str, optional) – Reflections drawn in the live plot, as positions in roi.gInclude and/or (h, k, l) tuples, or 'all'. Defaults to the first MAX_PANELS; every reflection is refined either way.

evaluateSF(x0: numpy.ndarray) → None

Evaluates the structure factor and solve for the eigenvector/values.

Parameters:

x0 (np.ndarray) – Structure factor values.

evaluateParam(thickness=None)

Evaluates CBED intensity based on Bloch simulation results and geometry.

Parameters:

thickness (float, optional) – Sample thickness. Defaults to None.

Returns:

Simulated CBED pattern.

Return type:

np.ndarray

display(lines=(), savedir=None, beams=None, ncols=PANEL_COLS)

Displays the optimization result.

Parameters:
  • lines (List[int], optional) – Rows of each disk to plot as line profiles. Defaults to none.

  • savedir (str, optional) – Directory to save the plot. Defaults to None.

  • beams (Sequence | str, optional) – Reflections to draw, as positions in roi.gInclude and/or (h, k, l) tuples, or 'all'. Defaults to the first MAX_PANELS. The returned patterns always hold every reflection.

  • ncols (int, optional) – Reflections per figure; the rest go on further figures, saved as region_<n>_<page>.png. Defaults to PANEL_COLS.

Returns:

Experimental and simulated

regional patterns.

Return type:

Tuple[List[np.ndarray], List[np.ndarray]]

static SFtarget(x0, *args)

Error function for structure factor optimization.

Parameters:
  • x0 (np.ndarray) – Structure factor values.

  • *args – Variable length argument list, expects a FineOptimize instance.

Returns:

The optimization error.

Return type:

float

static ROItarget(x0, *args)

Error function for ROI optimization.

Parameters:
  • x0 (np.ndarray) – ROI parameters (thickness, gl, rotation, allshift).

  • *args – a FineOptimize instance.

Returns:

The goodness of fit.

Return type:

float

static ShiftTarget(x0, *args)

Error function for disk shift optimization.

Parameters:
  • x0 (np.ndarray) – Disk shift values.

  • *args – a FineOptimize instance and the simulated CBED pattern.

Returns:

The optimization error.

Return type:

float

static callback(intermediate_result, self=None)

Callback function for optimization visualization.

pyextal.optimize.voigt_2d(sigma, gamma, radius)

Generates a 2D Voigt profile.

Parameters:
  • sigma (float) – Standard deviation for the Gaussian component.

  • gamma (float) – Half-width at half-maximum for the Lorentzian component.

  • radius (int) – Half-width of the kernel in pixels; the kernel is (2*radius+1) x (2*radius+1).

Returns:

A 2D array representing the Voigt profile.

Return type:

np.ndarray