dara.search.peak_matcher module#

class PeakMatcher(peak_calc, peak_obs, intensity_resolution=0.01, angle_resolution=0.1, angle_tolerance=0.2, intensity_tolerance=2, max_intensity_tolerance=5, profile_x=None, profile_y_calc=None, profile_y_obs=None, profile_y_bkg=None, height_ratio_threshold=0.3333333333333333)[source]#

Bases: object

Peak matcher class to match the calculated peaks with the observed peaks.

Parameters:
  • peak_calc (ndarray) – the calculated peaks, (n, 2) array of peaks with [position, intensity]

  • peak_obs (ndarray) – the observed peaks, (m, 2) array of peaks with [position, intensity]

  • intensity_resolution (float) – the resolution for the intensity, default to 0.01. Filter out peaks with lower intensity

  • angle_resolution (float) – the resolution for the angle, default to 0.1

  • angle_tolerance (float) – the maximum difference in angle, default to 0.3

  • intensity_tolerance (float) – the maximum ratio of the intensities, default to 2

  • max_intensity_tolerance (float) – the maximum ratio of the intensities to be considered as missing or extra, default to 10

  • profile_x (ndarray | None) – 2θ grid (degrees) for the full diffraction profile. When this and the three profile_y_* args are all given, matched peaks are re-examined against the profile (see _reclassify_wrong_intensity_by_height and _relocate_extra_to_apex); omit all four to skip this step.

  • profile_y_calc (ndarray | None) – calculated profile on profile_x.

  • profile_y_obs (ndarray | None) – observed profile on profile_x.

  • profile_y_bkg (ndarray | None) – background profile on profile_x.

  • height_ratio_threshold (float) – passed to _reclassify_wrong_intensity_by_height; wrong_intensity pairs whose calc/obs profile-height ratio falls below this are reclassified as missing+extra instead.

property extra: ndarray#

Get the extra peaks in the calculated peaks.

get_isolated_peaks(peak_type, min_angle_difference=0.3, min_intensity_ratio=None)[source]#

Get the isolated missing peaks in the observed peaks.

The isolated missing/extra peaks are the missing/extra peaks that are not close to any other peaks in matched and wrong intensity peaks.

Parameters:
  • peak_type (Literal['missing', 'extra']) – the type of the peaks to consider, either “missing” or “extra”

  • min_angle_difference (float) – the tolerance to consider a peak as close to another peak, default to 0.3 degree

  • min_intensity_ratio (float | None) – minimum intensity relative to the observed maximum. Defaults to DEFAULT_MISSING_MIN_INTENSITY_RATIO for missing peaks and DEFAULT_EXTRA_MIN_INTENSITY_RATIO for extra peaks when None.

Return type:

ndarray

Returns:

the isolated missing peaks with [position, intensity]

jaccard_index()[source]#

Calculate the Jaccard index of the matching result.

Return type:

float

Returns:

the Jaccard index of the matching result

property matched: tuple[ndarray, ndarray]#

Get the matched peaks in both the calculated peaks and the observed peaks.

property missing: ndarray#

Get the missing peaks in the observed peaks. The shape should be (N, 2) with [position, intensity].

score(matched_coeff=1, wrong_intensity_coeff=1, missing_coeff=-0.01, extra_coeff=-1, normalize=True)[source]#

Calculate the score of the matching result.

Parameters:
  • matched_coeff (float) – the coefficient of the matched peaks

  • wrong_intensity_coeff (float) – the coefficient of the peaks with wrong intensities

  • missing_coeff (float) – the coefficient of the missing peaks

  • extra_coeff (float) – the coefficient of the extra peaks

  • normalize (bool) – whether to normalize the score by the total intensity of the observed peaks

Return type:

float

Returns:

the score of the matching result

visualize()[source]#
property wrong_intensity: tuple[ndarray, ndarray]#

Get the indices of the peaks with wrong intensities in both the calculated peaks and the observed peaks.

absolute_log_error(x, y)[source]#

Calculate the absolute error of two arrays in log space.

Parameters:
  • x (ndarray) – array 1

  • y (ndarray) – array 2

Return type:

float

Returns:

the absolute error in log space

distance_matrix(peaks1, peaks2)[source]#

Return the distance matrix between two sets of peaks.

The distance is defined as the maximum of the distance in position and the distance in intensity. The position distance is the absolute difference in position. The intensity distance is the absolute difference in log intensity.

Parameters:
  • peaks1 (ndarray) – (n, 2) array of peaks with [position, intensity]

  • peaks2 (ndarray) – (m, 2) array of peaks with [position, intensity]

Return type:

ndarray

Returns:

(n, m) distance matrix

find_best_match(peak_calc, peak_obs, angle_tolerance=0.2, intensity_tolerance=2, max_intensity_tolerance=5)[source]#

Find the best match between two sets of peaks.

Parameters:
  • peak_calc (ndarray) – the calculated peaks, (n, 2) array of peaks with [position, intensity]

  • peak_obs (ndarray) – the observed peaks, (m, 2) array of peaks with [position, intensity]

  • angle_tolerance (float) – the maximum difference in angle

  • intensity_tolerance (float) – the maximum ratio of the intensities

  • max_intensity_tolerance (float) – the maximum ratio of the intensities to be considered as

Return type:

dict[str, Any]

Returns:

missing[j]:

the indices of the missing peaks in the obs peaks

matched[i, j]:

the indices of both the matched peaks in the calculated peaks and the observed peaks extra[i]: the indices of the extra peaks in the calculated peaks

wrong_intensity[i, j]:

the indices of the peaks with wrong intensities in both the calculated peaks and the observed peaks

residual_peaks (N_peak_obs, 2):

the residual peaks after matching (not including extra peaks in peak_calc)

find_intensity_mismatch_peaks(pm, profile_x, profile_y_obs, profile_y_calc, profile_y_bkg=None, height_tolerance=0.4, area_tolerance=0.6, window=0.15)[source]#

Flag matched peaks whose profile height or area deviates beyond the respective band.

Operates only on matched pairs — missing and extra take precedence. height band: [1 - height_tolerance, 1 + height_tolerance] area band: [1 - area_tolerance, 1 + area_tolerance] Flags if either band is violated.

Parameters:
  • pm (PeakMatcher) – the PeakMatcher holding the matched calc/obs peak pairs.

  • profile_x (ndarray) – 2θ grid (degrees), uniformly spaced.

  • profile_y_obs (ndarray) – observed counts on that grid.

  • profile_y_calc (ndarray) – calculated profile on that grid.

  • profile_y_bkg (ndarray | None) – background on that grid. When None, zeros are used.

  • height_tolerance (float) – half-width of the height band (default 0.40).

  • area_tolerance (float) – half-width of the area band (default 0.60).

  • window (float) – degrees either side of the peak apex used for height/area integration (default 0.15).

Return type:

ndarray

Returns:

(N, 2) array of [obs_2theta, 0.0], same shape as missing_peaks

find_residual_regions(profile_x, profile_y_obs, profile_y_calc, profile_y_bkg=None, window_width=0.5, window_step=0.1, window_detect_fraction=0.003, integral_fraction=0.01, calc_profile_ratio=0.03, calc_coverage_ratio=0.35, matched_peak_positions=None, enabled=True)[source]#

Find regions where the integrated positive residual indicates an unfit feature.

Scans the pattern with a fixed-width sliding window. Each window’s integrated positive residual (sum of max(y_obs - y_calc, 0) * dx) is compared against a fraction of the total integrated observed intensity. Overlapping flagged windows are merged into contiguous regions.

Bragg-peak filter (corrected form): a merged region is suppressed only if the calc profile is already adequate inside it — i.e. max(y_calc - y_bkg) within the region exceeds calc_profile_ratio * max(y_obs). A tabulated Bragg peak whose calc profile stays near background does NOT suppress the region.

Parameters:
  • profile_x (ndarray) – 2θ grid (degrees), uniformly spaced.

  • profile_y_obs (ndarray) – observed counts on that grid.

  • profile_y_calc (ndarray) – calculated profile on that grid.

  • profile_y_bkg (ndarray | None) – background on that grid. When None, zeros are used (filter compares calc profile directly against obs max).

  • window_width (float) – sliding window width in degrees (default 0.5°).

  • window_step (float) – step between window centres in degrees (default 0.1°).

  • window_detect_fraction (float) – per-window detection floor for forming candidate windows and merging them into regions (default 0.003 = 0.3%). This is intentionally lower than integral_fraction so that broad features are not penalised for being diffuse.

  • integral_fraction (float) – merged-region threshold — a region is flagged only if its total integrated positive residual exceeds this fraction of the total integrated observed intensity (default 0.010 = 1.0%).

  • calc_profile_ratio (float) – suppress a window if max(y_calc - y_bkg) inside it exceeds this fraction of max(y_obs) (default 0.03 = 3%).

  • calc_coverage_ratio (float) – suppress a merged region when integrated(y_calc - y_bkg) / integrated(y_obs - y_bkg) over the merged span exceeds this fraction — the calc already accounts for this much of the observed area in that region (default 0.35).

  • matched_peak_positions (ndarray | None) – 1-D array of 2θ positions of already-identified missing or extra peaks (after all normal suppression). Any merged region whose [start, end] span contains one of these positions is dropped — the feature has already been flagged by the matcher.

  • enabled (bool) – when False, skip all computation and return an empty (0, 4) array. Default True reproduces normal behavior.

Return type:

ndarray

Returns:

Array of shape (N, 2) with [center_2theta, 0.0] for each flagged region, formatted identically to missing-peak arrays for direct concatenation.

merge_peaks(peaks, resolution=0.0)[source]#

Merge peaks that are too close to each other (smaller than resolution).

Parameters:
  • peaks (ndarray) – the peaks to merge

  • resolution (float) – the resolution to use for merging

Return type:

ndarray

Returns:

the merged peaks

suppress_coincident_marker_pairs(missing_peaks, extra_peaks, tolerance=0.06)[source]#

Suppress missing/extra marker pairs within tolerance degrees of each other.

Near-coincident missing+extra pairs indicate refinement position wobble: the model placed a reflection slightly off-angle rather than genuinely missing it. Both markers are dropped.

Return type:

tuple[ndarray, ndarray]

Returns:

(missing_peaks, extra_peaks) with coincident pairs removed, same shapes