How to use the ad_hoc solver#
This guide shows how to create a diffractometer with the ad_hoc
solver, orient a crystalline sample, and compute reciprocal-space
positions. It assumes you have already installed the
package.
The ad_hoc solver wraps the ad_hoc_diffractometer library. This library
provides 10 diffractometer geometries ranging from Eulerian four-circle to
six-circle, kappa, and surface configurations. See ad_hoc solver for
the full list.
Create a diffractometer#
Four-circle vertical (the default geometry):
import hklpy2
fourc = hklpy2.creator(
solver="ad_hoc",
geometry="fourcv",
name="fourc",
)
The object fourc has four real axes (omega, chi, phi,
ttheta) and three pseudo axes (h, k, l).
Six-circle (psic):
psic = hklpy2.creator(
solver="ad_hoc",
geometry="psic",
name="psic",
)
Kappa geometry (set the kappa tilt angle via solver_kwargs):
kappa = hklpy2.creator(
solver="ad_hoc",
geometry="kappa4cv",
name="kappa",
solver_kwargs={"kappa_alpha_deg": 50},
)
Set the crystal lattice#
fourc.add_sample(name="silicon", a=hklpy2.SI_LATTICE_PARAMETER)
fourc.beam.wavelength.put(1.0)
Add orientation reflections#
Provide two reflections measured at known motor positions:
import math
theta = math.degrees(math.asin(1.0 / (2 * 5.431)))
tth = 2 * theta
r1 = fourc.add_reflection(
pseudos={"h": 1, "k": 0, "l": 0},
reals={"omega": theta, "chi": 0, "phi": 0, "ttheta": tth},
wavelength=1.0,
name="r1",
)
r2 = fourc.add_reflection(
pseudos={"h": 0, "k": 1, "l": 0},
reals={"omega": theta, "chi": 0, "phi": 90, "ttheta": tth},
wavelength=1.0,
name="r2",
)
Calculate the UB matrix#
fourc.core.calc_UB(r1, r2)
Choose an operating mode#
The default mode for fourcv is bisecting. To change it:
fourc.core.mode = "fixed_phi"
See ad_hoc solver for the full mode tables for each geometry.
Compute motor positions (forward)#
fourc.forward(1, 0, 0)
This returns a single chosen motor-position solution for the given
(h, k, l) (an Hklpy2DiffractometerRealPos). The underlying
solver’s forward() may return multiple solutions; the
diffractometer picks one according to the policy assigned to
fourc._forward_solution (defaults to
hklpy2.utils.pick_first_solution()). The complete list of
solutions can be returned from fourc.core.forward((1, 0, 0)).
See the upstream hklpy2 guide How to Choose the Default forward()
Solution
for details.
Tip
The two call shapes differ: fourc.forward(1, 0, 0) takes
h, k, l as separate positional arguments, while
fourc.core.forward((1, 0, 0)) takes a single sequence
(tuple / list / ndarray) or dict (e.g. {"h": 1, "k": 0, "l": 0}).
Compute (h, k, l) from motor positions (inverse)#
fourc.inverse(fourc.real_position)
This returns the (h, k, l) values computed from the supplied
motor positions. fourc.real_position is the current readout of
all real axes; pass a different set of values to compute (h, k, l)
at a hypothetical position instead.
Available geometries at a glance#
Geometry |
Real axes |
Modes |
Default mode |
|---|---|---|---|
omega, chi, phi, ttheta |
6 |
bisecting |
|
omega, chi, phi, ttheta |
6 |
bisecting |
|
mu, eta, chi, phi, nu, delta |
24 |
bisecting_vertical |
|
alpha, omega, chi, phi, delta, gamma |
6 |
bisecting_4c |
|
mu, omega, chi, phi, ttheta |
5 |
bisecting_4c |
|
komega, kappa, kphi, ttheta |
7 |
bisecting |
|
komega, kappa, kphi, ttheta |
6 |
bisecting |
|
mu, komega, kappa, kphi, nu, delta |
14 |
bisecting_vertical |
|
alpha, Z, delta, gamma |
2 |
zaxis |
|
mu, Z, nu, delta |
2 |
fixed_mu |
Register a custom YAML geometry#
Since ad_hoc_diffractometer 0.10.0 (issue
#267),
geometries are described in declarative YAML files. You can extend the
ad_hoc solver with your own geometry by registering a YAML file
before creating the diffractometer. The
AdHocSolver discovers geometries
dynamically from the library’s registry, so no wrapper change is
required.
import ad_hoc_diffractometer as ahd
import hklpy2
# Register a YAML geometry from disk under the name 'mybeamline'.
ahd.register_geometry_file("/path/to/mybeamline.yml", name="mybeamline")
# Or load and inspect without registering:
geom = ahd.load_geometry_file("/path/to/mybeamline.yml")
# The new geometry is now discoverable through the ad_hoc solver.
diff = hklpy2.creator(
solver="ad_hoc",
geometry="mybeamline",
name="mybeamline",
)
The name argument is optional; when omitted, the geometry is
registered under the name: field declared inside the YAML file.
See the
ad_hoc_diffractometer schema
for the YAML format.
Third-party packages can alternatively contribute geometries via the
"ad_hoc_diffractometer.geometries" entry-point group; those are
discovered automatically the first time
ad_hoc_diffractometer.list_geometries() is called.
See also
ad_hoc solver — full reference for all geometries and modes
How to benchmark a solver geometry — measure solver throughput
hklpy2 user guide — full hklpy2 documentation