Open bjkoz opened 6 years ago
Hi,
Sorry for a delayed reply, we were enjoying a conference in Krakow last week.
To implement a mosaic crystal is not difficult but it is a bit more complex than you describe, otherwise we wouldn't get the effect of secondary extinction. We do have more requests about mosaic crystals, I will look closer to it within a few days.
Konstantin
I came across the following paper that might be useful in implementing the mosaic crystals:
"A new model for the description of X-ray diffraction from mosaic crystals for ray-tracing calculations",C. Schlesiger, L. Anklamm, W. Malzer, R. Gnewkow and B. Kanngießer, J. Appl. Cryst. (2017). 50, 1490-1497 https://doi.org/10.1107/S1600576717012626
Bernie
I've implemented mosaic crystals in the way it is done in Shadow. See a short description, tests, and a test/example script in ...tests/raycing/test_mosaic_xtal.py.
Please give it a try and comment on it.
Konstantin
I had a chance to test out the mosaic crystals. It works as expected but a few comments. There's an error when used with a source 'withAmplitudes=True' for the source. There's an undefined reference to 'att' for the mosaicity.
I also ran into trouble with plotting. There are a few locations in plotter.py where there appears to be a numerical issue. The mosaicity calculation produces reflectivity values which are very low. This causes a problem in: ` if axis.max1D > 0:
if runner.runCardVals.passNo > 0:
mult = 1.0/globalMax1D
else:
mult = 1.0/axis.max1D
xx = t1D*mult
`
The reflectivity can be very low leading to axis.max1D ~ 1e-300. Then mult becomes large creating problems. I've worked around that issue by changing if axis.max1D > 0: to if axis.max1D > 1e-100
and that seems to work. There are a also a place where self.max2D_RGB > 0 where it has a similar problem. It might make sense to define a minimum value that's non-zero.
Hi,
Thank you for the feedback!
I've fixed the missing part in the attenuation. It affects the cases when the crystal has given a thickness and the secondary extinction length is longer than the travel path in the crystal. Please confirm the fix was correct.
Thanks for identifying the problem with nearly zero histogram maxima. I've done as you suggested.
Where does the factor for the Laue case come from? The term in get_amplitude_mosaic in materials.py: else: # Laue return np.sinh(Aa) np.exp(-A*(1+a)) This looks like Eq. 18 in the Bacon paper. Does 'Transmission Method' refer to the Laue forward scattering geometry?
There's a section in the Bacon paper at Eq. 23, which replaces mu with mu_prime = 1/2 mu*(1+gamma_0/|gamma_H|), where gamma_0 and gamma_H are the incident and diffracted direction cosines. This is for, as best I can tell, the Laue Reflection case where the lattice planes are not parallel or perpendicular to the crystal surface. This isn't implemented in the code correct?
I'm curious because I have a Laue geometry with a diamond crystal <111> oriented normal to the surface, and using the reflection from the (11-1) plane at the Cu K-alpha line. The bragg angle is about 21 degrees, so the np.sinh(Aa) np.exp(-A*(1+a)) factor is flattening out the curve and giving a full-width half max that is larger than the input mosaic value. We've got measurement of this crystal in a diffractometer and the FWHM doesn't seem to match the calculation. I'm trying to determine if this is due to an error in the calculation or an error in understanding the mosaic Laue reflections.
Thanks!
Yes, this is from Eq (18) in that paper. And it is for the symmetrical case. The unsymmetrical case is in (23) and (24) which I will implement on the weekend.
Hi, I've implemented the asymmetric case. Looks reasonable but I cannot compare with XOP as it is not there. I rely on your tests. Please try it and get back with results.
Thanks.
In materials.py, get_amplitude_mosaic, line 1495 has: A = mu*self.t/g0
mu is in cm-1, while self.t is defined in mm. I believe that line needs to be divided by 10 to make the units consistent. Similarly, line 1508 should be:
return sigma/sm np.sinh(smself.t/10.) np.exp(-sGammaself.t/10.) since sm and sGamma are in cm-1 because that is how Q is defined.
In get_kappa_Q, line 1535: Qp = Qs*polFactor**2.
The Bacon paper, page 304, second column has a term that would be 0.5*(1+polFactor2). Should line 1535 be: Qp = Qs0.5(1+polFactor2) ?
Hi,
Yes, my mistake. Sorry! I've only tested the thick case and skipped the thin one. Now I've corrected the product µt and the other similar ones. Thanks for looking at it!
Polarization factor. We calculate reflectivities separately for s and p polarizations. Bacon and Lowde considered non-polarized case. I think in 1948 polarized x-rays could not be obtained (only except by 45° diffraction). In the non-polarized case the total intensity is ½(Is + Ip), and this is what Bacon and Lowde have. In xrt, the intensity calculation is given by coherency matrix, and the latter is defined by the source. So if you create a non-polarized geometric source in xrt, the ½ factor will be there automatically.
Thanks for the polarization explanation. Looks like it is working as I'd expect. Doesn't match the measurement, but that's likely due to the the simple Gaussian distribution assumption for the mosaic distribution being inaccurate rather than the code.
I spent some time working through your code and was curious about the _mosaic_normal function in oes_base.py. Was it intentional that it returns only the crystal plane normal directions and not both the crystal plane normals and the surface normal?
By the model, only the crystallites get some random orientation variation. The global normal of the crystal plate remains invariant and is defined by local_n method.
Thanks. _mosaic_normal takes in the 6-component oeNormal, but only returns 3 components into oeNormal, overwriting the original. Just wanted to make sure that was intended.
Hi. Now I see what you meant. Indeed, in this place the normal was not prepared for asymmetry. Thanks for discovering it! Please give a try to the amended version.
Hello, I was curious if there is an easy way to implement mosaic crystals. It seems like it needs to be a version of the Power material, with a limited distribution of crystal orientations.
Perhaps the easiest way would be to make a new class from OE and define local_n to return the atomic plane normal directions with a random spread around the nominal direction.