-
Notifications
You must be signed in to change notification settings - Fork 97
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Multigeometry integration issue for inclined detector geometries and radial distance #1990
Comments
Can you provide some snippet or a working example ? |
I zipped up a demo. It doesn't look like there is an example I can pull from documentation that would demonstrate the issue. |
For what it is worth, the issue is not unique to multigeometry. Also, I just tried the geometry inversion and it worked. I wonder if it's not actually an issue and the resulting plot is just the r from a tilted detector (i.e. r_detector does not correspond to a single distance from the sample and is not expected to be similar to 2theta). from pyFAI import load
id = 0
ai = load(poni_files[id])
print(ai)
res3 = ai.integrate2d(img_data[id], 3000,mask=mask_data[id],unit="2th_deg")
res4 = ai.integrate2d(img_data[id], 3000,mask=mask_data[id],unit="r_m")
jupyter.plot2d(res3)
pass
jupyter.plot2d(res4)
pass |
Hi Daniel, What are you actually trying to achieve ? Maybe I can help you finding a work around. |
Thanks Jerome for getting back. The problem I'm dealing with is getting high quality Rietveld analysis of patterns collected with differently tilted multigeometry detectors (like in the example I sent). When the azimuthal coverage of a single detector is suboptimal, the PONI calibration is sometimes not ideal. One way to address this issue is using the methodology of MAUD Integration wherein the integrated intensities are represented in detector coordinates (instead of radial and azimuthal position) and the geometry can be refined in the Rietveld software. The tilted geometry detector in MAUD has a direct relationship to PONI. Below is an example of a pyFAI integration in detector coordinates and the geometry being refined underneath. ![]() I've attempted to do the integration in a way that leverages pyfai's integration and then maps each element back to detector coordinates. Luca Lutterotti's methodology for integration is to bin position while binning intensity, which I haven't tried with pyFAI. Seems like both methods would give rise to small artifacts. My hacked together version using pyFAI's geometry inversion is below. I would definitely be curious if there is a better way to approach getting the detector coordinates of an integration element. You can see I'm not worried too much by the speed of the inversion if it can be saved and reused. def cake2MAUD(ai, result, sigmas, fname_detector):
"""cake2MAUD converts histograms (e.g. 2theta vs intensity) to detector position vs intensity.
Args:
ai (object): Integrator object.
result (object): pyFAI 2d result integration objection
sigmas (np.array): Uncertainty in intensity.
fname_detector (str): Detector coordinates file name.
Returns:
intensity (np.array): Intensity.
X (np.array): X position on detector.
Y (np.array): Y position on detector.
sigmas (np.array): Uncertainty in intensity.
"""
def in_hull(p, hull):
"""
Test if points in `p` are in `hull`
`p` should be a `NxK` coordinates of `N` points in `K` dimensions
`hull` is either a scipy.spatial.Delaunay object or the `MxK` array of the
coordinates of `M` points in `K`dimensions for which Delaunay triangulation
will be computed
"""
from scipy.spatial import Delaunay
if not isinstance(hull,Delaunay):
hull = Delaunay(hull)
return hull.find_simplex(p)>=0
def export_interpolation(result,ai,fname):
"""Interpolate detector position and angles."""
print("Regenerating can take some time (usually 2-6 minutes per detector instance depending on detector size).")
# For each pixel center get the radius in meters and azimuthal angle in radians
r=ai.rArray()
c=ai.chiArray()
# Its important for a multigeometry the covers most of the azimuthal range to limit the azimuthal and radial range to that relevant to the detector
radial = result.radial
azimuthal = np.deg2rad(result.azimuthal)
radial_bin,chi_bin = np.meshgrid(radial,azimuthal)
mask = (radial_bin<np.min(r)) | (radial_bin>np.max(r)) | (chi_bin<np.min(c)) | (chi_bin>np.max(c) )
radial_bint = np.ma.masked_array(radial_bin, mask).compressed()
chi_bint = np.ma.masked_array(chi_bin, mask).compressed()
# Build hull and exclude points near the edge of the detector
shape=ai.get_shape()
x,y = np.meshgrid(np.linspace(1.5,shape[0]-1.5),np.linspace(1.5,shape[1]-1.5))
ai_hull = np.column_stack((y.ravel(),x.ravel()))
# Invert geometry and get the pixel coordinates
ig = InvertGeometry(r,c)
t = ig.many(radial_bint,chi_bint,refined=True)
t[~in_hull(t, ai_hull)]=np.nan
ty = np.empty(np.shape(radial_bin))
ty[:] = np.nan
ty[~mask] = t[:,0]
tx = np.empty(np.shape(radial_bin))
tx[:] = np.nan
tx[~mask] = t[:,1]
#t contain y,x. y in pyFAI is corresponds to poni1
Y_bin = 1e3*(ty*ai.pixel1-ai.poni1+ai.pixel1/2.0)
X_bin = 1e3*(tx*ai.pixel2-ai.poni2+ai.pixel2/2.0)
# Store so only a one time cost
with open(fname, 'wb') as f:
pickle.dump(result.radial, f)
pickle.dump(result.azimuthal, f)
pickle.dump(X_bin, f)
pickle.dump(Y_bin, f)
return X_bin, Y_bin
def load_interpolation(fname):
with open(fname, 'rb') as f:
radial_stored = pickle.load(f)
azimuthal_stored = pickle.load(f)
X_bin = pickle.load(f)
Y_bin = pickle.load(f)
return X_bin, Y_bin, radial_stored, azimuthal_stored
def get_bin_detector_location(result, ai, fname):
"""Compare key metrics to see if interpolation is good."""
if Path(fname).is_file():
X_bin, Y_bin, radial_stored, azimuthal_stored = load_interpolation(
fname)
if all(radial_stored == result.radial) and all(azimuthal_stored == result.azimuthal):
return X_bin, Y_bin
return export_interpolation(result, ai, fname)
# Using a cache for the detector/extract bin locations
X_bin,Y_bin = get_bin_detector_location(result, ai, fname = fname_detector)
# Create a bin level mask
imask = np.ma.masked_invalid(X_bin).mask | np.ma.masked_invalid(
Y_bin).mask | np.ma.masked_invalid(result.intensity).mask | (result.intensity == 0)
X_bin = np.ma.masked_array(X_bin, imask)
Y_bin = np.ma.masked_array(Y_bin, imask)
intensity = np.ma.masked_array(result.intensity, imask)
sigmas = np.ma.masked_array(sigmas, imask)
return intensity, X_bin, Y_bin, sigmas |
Related issue: #1873 Just one idea until then:
|
Hi,
I'm using the invert geometry capability in pyfai to move integrated patterns back into detector coordinates . That requires radial units. The inbuilt 2theta to r_m, unit conversion are not physically related to the detector. This makes sense since the unit conversion doesn't consider the detector geometry. My work around was just to do the integration in radial units; however, there appears to be a major bug for inclined multigeometries and integration using radial units. I observe the same issue in the 1d and 2d integrator.
With 2theta units I get the correct multi geometry integration

All things equal but with radial units yields

The text was updated successfully, but these errors were encountered: