-
Notifications
You must be signed in to change notification settings - Fork 21
add functions to allow conversions between d and tth, and d and q #154
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
Changes from all commits
9ae8d9e
4afc6a6
8667f3b
2f11634
5423c9c
5c46816
07274d4
b733b94
0534fa8
01470c1
2de70ed
638b216
a2deaa1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
**Added:** | ||
|
||
* functions to allow conversions between d and tth, and d and q. | ||
|
||
**Changed:** | ||
|
||
* <news item> | ||
|
||
**Deprecated:** | ||
|
||
* <news item> | ||
|
||
**Removed:** | ||
|
||
* <news item> | ||
|
||
**Fixed:** | ||
|
||
* <news item> | ||
|
||
**Security:** | ||
|
||
* <news item> |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,8 @@ | |
DQUANTITIES = ["d", "dspace"] | ||
XQUANTITIES = ANGLEQUANTITIES + DQUANTITIES + QQUANTITIES | ||
XUNITS = ["degrees", "radians", "rad", "deg", "inv_angs", "inv_nm", "nm-1", "A-1"] | ||
QMAX = 40 | ||
DMAX = 100 | ||
|
||
x_grid_emsg = ( | ||
"objects are not on the same x-grid. You may add them using the self.add method " | ||
|
@@ -283,7 +285,7 @@ def insert_scattering_quantity( | |
elif xtype.lower() in ANGLEQUANTITIES: | ||
self.on_tth = [np.array(xarray), np.array(yarray)] | ||
elif xtype.lower() in DQUANTITIES: | ||
self.on_tth = [np.array(xarray), np.array(yarray)] | ||
self.on_d = [np.array(xarray), np.array(yarray)] | ||
self.set_all_arrays() | ||
|
||
def q_to_tth(self): | ||
|
@@ -305,7 +307,7 @@ def q_to_tth(self): | |
Parameters | ||
---------- | ||
q : array | ||
An array of :math:`q` values | ||
The array of :math:`q` values | ||
|
||
wavelength : float | ||
Wavelength of the incoming x-rays | ||
|
@@ -315,12 +317,16 @@ def q_to_tth(self): | |
Returns | ||
------- | ||
two_theta : array | ||
An array of :math:`2\theta` values in radians | ||
The array of :math:`2\theta` values in radians | ||
""" | ||
q = self.on_q[0] | ||
q = np.asarray(q) | ||
wavelength = float(self.wavelength) | ||
pre_factor = wavelength / (4 * np.pi) | ||
if np.any(np.abs(q * pre_factor) > 1): | ||
raise ValueError( | ||
"Invalid input for arcsin: some values exceed the range [-1, 1]. " "Check wavelength or q values." | ||
) | ||
return np.rad2deg(2.0 * np.arcsin(q * pre_factor)) | ||
|
||
def tth_to_q(self): | ||
|
@@ -344,7 +350,7 @@ def tth_to_q(self): | |
Parameters | ||
---------- | ||
two_theta : array | ||
An array of :math:`2\theta` values in units of degrees | ||
The array of :math:`2\theta` values in units of degrees | ||
|
||
wavelength : float | ||
Wavelength of the incoming x-rays | ||
|
@@ -354,26 +360,134 @@ def tth_to_q(self): | |
Returns | ||
------- | ||
q : array | ||
An array of :math:`q` values in the inverse of the units | ||
The array of :math:`q` values in the inverse of the units | ||
of ``wavelength`` | ||
""" | ||
two_theta = np.asarray(np.deg2rad(self.on_tth[0])) | ||
if np.any(two_theta > np.pi): | ||
raise ValueError("Two theta exceeds 180 degrees.") | ||
wavelength = float(self.wavelength) | ||
pre_factor = (4 * np.pi) / wavelength | ||
return pre_factor * np.sin(two_theta / 2) | ||
|
||
def q_to_d(self): | ||
r""" | ||
Helper function to convert q to d using :math:`d = \frac{2 \pi}{q}`, set dmax to DMAX=100 | ||
|
||
Parameters | ||
---------- | ||
q : array | ||
The array of :math:`q` values | ||
|
||
Returns | ||
------- | ||
d : array | ||
The array of :math:`d` values in the inverse of the units of ``wavelength`` | ||
""" | ||
q = np.asarray(self.on_q[0]) | ||
d = np.where(q != 0, (2 * np.pi) / q, np.inf) | ||
d = np.minimum(d, DMAX) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not very readable. Also, I guess it can end up with a bunch of values of D that are the same. I think there is a better way to do this maybe. Also, how does the user overrid DMAX if they want? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The user can use insert_scattering_quantity to overrid or directly set the attributes. But I agree with you that this might be problematic. Also the appropriate limit seems a bit different for different wavelength. Maybe it's better to set d = 2 * previous_d if q = 0? |
||
return d[::-1] | ||
|
||
def d_to_q(self): | ||
r""" | ||
Helper function to convert d to q using :math:`q = \frac{2 \pi}{d}`, set qmax to QMAX=40 | ||
|
||
Parameters | ||
---------- | ||
d : array | ||
The array of :math:`d` values | ||
|
||
Returns | ||
------- | ||
q : array | ||
The array of :math:`q` values in the inverse of the units of ``wavelength`` | ||
""" | ||
d = np.asarray(self.on_d[0]) | ||
q = np.where(d != 0, (2 * np.pi) / d, np.inf) | ||
q = np.minimum(q, QMAX) | ||
return q[::-1] | ||
|
||
def tth_to_d(self): | ||
r""" | ||
Helper function to convert two-theta to d | ||
|
||
uses the formula .. math:: d = \frac{\lambda}{2 \sin\left(\frac{2\theta}{2}\right)}, set dmax to DMAX=100 | ||
|
||
Parameters | ||
---------- | ||
two_theta : array | ||
The array of :math:`2\theta` values in units of degrees | ||
|
||
wavelength : float | ||
Wavelength of the incoming x-rays | ||
|
||
Returns | ||
------- | ||
d : array | ||
The array of :math:`d` values in the inverse of the units | ||
of ``wavelength`` | ||
""" | ||
two_theta = np.asarray(np.deg2rad(self.on_tth[0])) | ||
if np.any(two_theta > np.pi): | ||
raise ValueError("Two theta exceeds 180 degrees.") | ||
wavelength = float(self.wavelength) | ||
sin_two_theta = np.sin(two_theta / 2) | ||
d = np.where(sin_two_theta != 0, wavelength / (2 * sin_two_theta), np.inf) | ||
d = np.minimum(d, DMAX) | ||
return d[::-1] | ||
|
||
def d_to_tth(self): | ||
r""" | ||
Helper function to convert d to two-theta | ||
|
||
uses the formula .. math:: 2\theta = 2 \arcsin\left(\frac{\lambda}{2d}\right), set tth to 180 when d=0 | ||
|
||
Parameters | ||
---------- | ||
d : array | ||
The array of :math:`d` values | ||
|
||
wavelength : float | ||
Wavelength of the incoming x-rays | ||
|
||
Returns | ||
------- | ||
two_theta : array | ||
The array of :math:`2\theta` values in radians | ||
""" | ||
d = np.asarray(self.on_d[0]) | ||
wavelength = float(self.wavelength) | ||
pre_factor = wavelength / (2 * d) | ||
if np.any(np.abs(pre_factor) > 1): | ||
raise ValueError( | ||
"Invalid input for arcsin: some values exceed the range [-1, 1]. " "Check wavelength or d values." | ||
) | ||
return np.rad2deg(2.0 * np.arcsin(pre_factor))[::-1] | ||
|
||
def set_all_arrays(self): | ||
master_array, xtype = self._get_original_array() | ||
if xtype == "q": | ||
self.on_tth[0] = self.q_to_tth() | ||
self.on_tth[1] = master_array[1] | ||
self.on_d[0] = self.q_to_d() | ||
self.on_d[1] = master_array[1] | ||
if xtype == "tth": | ||
self.on_q[0] = self.tth_to_q() | ||
self.on_q[1] = master_array[1] | ||
self.on_d[0] = self.tth_to_d() | ||
self.on_d[1] = master_array[1] | ||
if xtype == "d": | ||
self.on_tth[0] = self.d_to_tth() | ||
self.on_tth[1] = master_array[1] | ||
self.on_q[0] = self.d_to_q() | ||
self.on_q[1] = master_array[1] | ||
self.tthmin = self.on_tth[0][0] | ||
self.tthmax = self.on_tth[0][-1] | ||
self.qmin = self.on_q[0][0] | ||
self.qmax = self.on_q[0][-1] | ||
self.dmin = self.on_d[0][0] | ||
self.dmax = self.on_d[0][-1] | ||
|
||
def _get_original_array(self): | ||
if self.input_xtype in QQUANTITIES: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is too low probably.