Click here to go to the corresponding page for the latest version of DIALS
Source code for dxtbx.model.beam
from __future__ import absolute_import, division
#!/usr/bin/env python
# beam.py
# Copyright (C) 2011 Diamond Light Source, Graeme Winter
#
# This code is distributed under the BSD license, a copy of which is
# included in the root directory of this package.
#
# A model for the beam for the "updated experimental model" project documented
# in internal ticket #1555. This is not designed to be used outside of the
# XSweep classes.
import math
import pycbf
from dxtbx_model_ext import Beam
import libtbx.phil
beam_phil_scope = libtbx.phil.parse(
"""
beam
.expert_level = 1
.short_caption = "Beam overrides"
{
wavelength = None
.type = float
.help = "Override the beam wavelength"
direction = None
.type = floats(size=3)
.help = "Override the sample to source direction"
.short_caption = "Sample to source direction"
polarization_normal = None
.type = floats(size=3)
.help = "Override the polarization normal"
.short_caption = "Polarization normal"
polarization_fraction = None
.type = float(value_min=0.0, value_max=1.0)
.help = "Override the polarization fraction"
.short_caption = "Polarization fraction"
}
"""
)
[docs]class BeamFactory:
"""A factory class for beam objects, which encapsulate standard beam
models. In cases where a full cbf description is available this
will be used, otherwise simplified descriptions can be applied."""
def __init__(self):
pass
[docs] @staticmethod
def from_phil(params, reference=None):
"""
Convert the phil parameters into a beam model
"""
# Check the input
if reference is None:
beam = Beam()
else:
beam = reference
# Set the parameters
if params.beam.wavelength is not None:
beam.set_wavelength(params.beam.wavelength)
elif reference is None:
raise RuntimeError("No wavelength set")
if params.beam.direction is not None:
beam.set_direction(params.beam.direction)
elif reference is None:
raise RuntimeError("No beam direction set")
if params.beam.polarization_normal is not None:
beam.set_polarization_normal(params.beam.polarization_normal)
if params.beam.polarization_fraction is not None:
beam.set_polarization_fraction(params.beam.polarization_fraction)
# Return the model
return beam
[docs] @staticmethod
def from_dict(d, t=None):
"""Convert the dictionary to a beam model
Params:
d The dictionary of parameters
t The template dictionary to use
Returns:
The beam model
"""
from dxtbx.model import Beam
# If None, return None
if d == None:
if t == None:
return None
else:
return from_dict(t, None)
elif t != None:
d = dict(t.items() + d.items())
# Create the model from the dictionary
return Beam.from_dict(d)
[docs] @staticmethod
def make_beam(
sample_to_source=None,
wavelength=None,
s0=None,
unit_s0=None,
divergence=None,
sigma_divergence=None,
):
if divergence is None or sigma_divergence is None:
divergence = 0.0
sigma_divergence = 0.0
if sample_to_source:
assert wavelength
return Beam(
tuple(map(float, sample_to_source)),
float(wavelength),
float(divergence),
float(sigma_divergence),
)
elif unit_s0:
assert wavelength
return Beam(
tuple(map(lambda x: -x, map(float, unit_s0))),
float(wavelength),
float(divergence),
float(sigma_divergence),
)
else:
assert s0
return Beam(tuple(map(float, s0)))
[docs] @staticmethod
def make_polarized_beam(
sample_to_source=None,
wavelength=None,
s0=None,
unit_s0=None,
polarization=None,
polarization_fraction=None,
divergence=None,
sigma_divergence=None,
flux=None,
transmission=None,
):
assert polarization
assert polarization_fraction >= 0.0
assert polarization_fraction <= 1.0
if divergence == None or sigma_divergence == None:
divergence = 0.0
sigma_divergence = 0.0
if flux is None:
flux = 0
if transmission is None:
transmission = 1.0
if sample_to_source:
assert wavelength
return Beam(
tuple(map(float, sample_to_source)),
float(wavelength),
float(divergence),
float(sigma_divergence),
tuple(map(float, polarization)),
float(polarization_fraction),
float(flux),
float(transmission),
)
elif unit_s0:
assert wavelength
return Beam(
tuple(map(lambda x: -x, map(float, unit_s0))),
float(wavelength),
float(divergence),
float(sigma_divergence),
tuple(map(float, polarization)),
float(polarization_fraction),
float(flux),
float(transmission),
)
else:
assert s0
return Beam(
tuple(map(float, s0)),
float(divergence),
float(sigma_divergence),
tuple(map(float, polarization)),
float(polarization_fraction),
float(flux),
float(transmission),
)
[docs] @staticmethod
def simple(wavelength):
"""Construct a beam object on the principle that the beam is aligned
with the +z axis, as is quite normal. Also assume the beam has
polarization fraction 0.999 and is polarized in the x-z plane."""
return BeamFactory.make_beam(
sample_to_source=(0.0, 0.0, 1.0), wavelength=wavelength
)
[docs] @staticmethod
def simple_directional(sample_to_source, wavelength):
"""Construct a beam with direction and wavelength."""
return BeamFactory.make_beam(
sample_to_source=sample_to_source, wavelength=wavelength
)
[docs] @staticmethod
def complex(
sample_to_source, polarization_fraction, polarization_plane_normal, wavelength
):
"""Full access to the constructor for cases where we do know everything
that we need..."""
return BeamFactory.make_polarized_beam(
sample_to_source=sample_to_source,
wavelength=wavelength,
polarization=polarization_plane_normal,
polarization_fraction=polarization_fraction,
)
[docs] @staticmethod
def imgCIF(cif_file):
"""Initialize a detector model from an imgCIF file. N.B. the
definition of the polarization plane is not completely helpful
in this - it is the angle between the polarization plane and the
+Y laboratory frame vector."""
d2r = math.pi / 180.0
cbf_handle = pycbf.cbf_handle_struct()
cbf_handle.read_file(cif_file, pycbf.MSG_DIGEST)
cbf_handle.find_category("axis")
# find record with equipment = source
cbf_handle.find_column("equipment")
cbf_handle.find_row("source")
# then get the vector and offset from this
direction = []
for j in range(3):
cbf_handle.find_column("vector[%d]" % (j + 1))
direction.append(cbf_handle.get_doublevalue())
# and the wavelength
wavelength = cbf_handle.get_wavelength()
# and information about the polarization - FIXME this should probably
# be a rotation about the beam not about the Z axis.
try:
polar_fraction, polar_angle = cbf_handle.get_polarization()
except Exception:
polar_fraction = 0.999
polar_angle = 0.0
polar_plane_normal = (
math.sin(polar_angle * d2r),
math.cos(polar_angle * d2r),
0.0,
)
return BeamFactory.make_polarized_beam(
sample_to_source=direction,
wavelength=wavelength,
polarization=polar_plane_normal,
polarization_fraction=polar_fraction,
)
[docs] @staticmethod
def imgCIF_H(cbf_handle):
"""Initialize a detector model from an imgCIF file. N.B. the
definition of the polarization plane is not completely helpful
in this - it is the angle between the polarization plane and the
+Y laboratory frame vector. This example works from a cbf_handle,
which is already configured."""
d2r = math.pi / 180.0
cbf_handle.find_category("axis")
# find record with equipment = source
cbf_handle.find_column("equipment")
cbf_handle.find_row("source")
# then get the vector and offset from this
direction = []
for j in range(3):
cbf_handle.find_column("vector[%d]" % (j + 1))
direction.append(cbf_handle.get_doublevalue())
# and the wavelength
wavelength = cbf_handle.get_wavelength()
# and information about the polarization - FIXME this should probably
# be a rotation about the beam not about the Z axis.
try:
polar_fraction, polar_angle = cbf_handle.get_polarization()
except Exception:
polar_fraction = 0.999
polar_angle = 0.0
polar_plane_normal = (
math.sin(polar_angle * d2r),
math.cos(polar_angle * d2r),
0.0,
)
return BeamFactory.make_polarized_beam(
sample_to_source=direction,
wavelength=wavelength,
polarization=polar_plane_normal,
polarization_fraction=polar_fraction,
)