Open rowlesmr opened 1 year ago
As far as I can tell, multi-pixel detector geometry is completely covered by the imgCIF dictionary, including laying out all of the relevant axes. Once our raw powder data working group starts up as part of an IUCr journals project, we'll have a better idea of what is missing and we can feed back that information here.
Mirrors are an excellent idea. We should be able to recreate a geometrical layout of the instrument suitable for simulation calculations.
Moved from #162
(https://github.com/COMCIFS/Powder_Dictionary/pull/162#issuecomment-1610825834)
_pd_instr_mirror
can then reference_order_along_beam
to locate the mirror it is describing.
That's not going to work, as _pd_instr_mono
needs to give a mono angle, as well as reference into the list.
.
First pass at something (all names are probably terrible, and there is at least one thing @jamesrhester doesn't like*):
The inner details could also be hidden, a la how PD_INSTR
and PD_INSTR_DETECTOR
currently do it with datanames not being \<category>.\<object>.
PD_INSTR_ORDER
: Loop category. Indexed on _pd_instr.id
, order
, optic_type
, and optic_value
.
Dataitems:
_pd_instr_order.order
: Integer indicating an ordering of optics along the beam path. By convention the source
is item 0
. Items can have the same order; it means they occur at the same place. The only thing that can be before the source is the virtual source. The last "optic" is the specimen, spec
._pd_instr_order.optic_type
: an enumerated list of options_pd_instr_order.optic_value
: *this one. the value associated with the optic; monochromator angle, divergence, slit opening, beam size... It's interpretation depends on the optic_type
_pd_instr_order.optic_value_mm
and _pd_instr_order.optic_value_deg
. Then at least the units are consistent in the data item. It also cuts down on two enumeration values, as ax|eq_divg
is just ax|eq_slit
with a value in degress, rather than millimetres._pd_instr_order.instr_id
: because you need to detail which instrument this belongs to._pd_instr_order.distance_from_previous
: The distance from the previous optic to the current optic in millimetres. This is a straight-line distance._pd_instr_order.distance_from_source
: The distance from the source to the current optic in millimetres. This be an along-the-beam-path distance._pd_instr_order.distance_from_virt_source
: The distance from the virtual source to the current optic in millimetres. This is an along-the-beam-path distance.The enumeration values of _pd_instr_order.optic_type
would be:
source
: the physical place where the X-rays/neutrons come from. The corresponding optic_value
would be .
.ax|eq_source_size
: This represents two values, ax_source_size
and eq_source_size
. It is the size of the source of the X-rays in the axial and equatorial directions, respectively.virt_source
: the virtual source. If I am the specimen, and I look up to see where the X-rays are coming from, where do I see them coming from? The corresponding optic_value
would be .
.mono
: a monochromator. The corresponding optic_value
would be in deg 2Th.mirror
: A mirror. The corresponding optic_value
would be in millimetres (see above).ax|eq_slit
: A slit. eg a pair of W wires held some distance apart. The corresponding optic_value
would be in millimetres.ax|eq_Soller
: A set of parallel plates to reduce divergence. The corresponding optic_value
would be in degrees.ax|eq_divg
: A slit, as above, but measured in degrees.eq_cons_illum_len
: A variable slit such that the length of the beam on the specimen is a constant. The corresponding optic_value
would be in millimetres.ax|eq_spec_beam_size
: The size of the beam at the specimen position. The corresponding optic_value
would be in millimetres.spec
: The specimen. The corresponding optic_value
would be .
.A similar thing would apply for PD_INSTR_ORDER_DETECTOR
: Loop category. Indexed on _pd_instr_detector.id
, order
, optic_type
, and optic_value
. 0th optic is the specimen. The last optic is the detector. (or should it be the other way around?)
Examples:
data_first
_pd_instr.id UUID
loop_
_pd_instr_order.order
_pd_instr_order.optic_type
_pd_instr_order.optic_value
0 source . # X-rays come from here.
1 eq_divg 0.3 # There is a divergence slit set to 0.3°.
2 eq_divg 0.6 # There is an anti-scatter slit set to 0.6°.
3 ax_soller 3.5 # A set of axial Soller slits at 3.5°.
4 ax_slit 10.0 # A mask to cut the beam off at 10.0 mm wide.
5 ax_spec_beam_size 10.7 # The beam width at the specimen is 10.7 mm.
5 spec . # The specimen.
data_second
_pd_instr.id UUID2
loop_
_pd_instr_order.order
_pd_instr_order.optic_type
_pd_instr_order.optic_value
_pd_instr_order.distance_from_virt_source
0 source . -40.0 # X-rays come from here.
0 ax_source_size 12.0 -40.0 # LFF tube, so 12 mm is a std size
0 eq_source_size 0.4 -40.0 # at the normal takeoff angle, 0.4 mm is about right
1 ax_soller 5.0 -35.0 # A set of axial Soller slits at 5.0° between the source and mono
2 eq_divg 0.5 -30.5 # There is a divergence slit set to 0.5° between the source and mono
2 ax_slit 12.0 -30.5 # A mask to cut the beam off at 12.0 mm wide between the source and mono
3 mono 26.6 -20.5 # A mono set at 26.6° 2\q
4 eq_slit 0.1 0.0 # 0.1 mm slit which is on the detector circle.
4 virt_source . 0.0 # This is a "standard" BB instr with a pre-spec mono, so "here" is where the x-rays come from
5 eq_divg 0.3 15.0 # There is a divergence slit set to 0.3°.
6 ax_soller 3.5 20.0 # A set of axial Soller slits at 3.5°.
7 ax_slit 10.0 25.0 # A mask to cut the beam off at 10.0 mm wide.
8 ax_spec_beam_size 10.7 250.0 # The beam width at the specimen is 10.7 mm.
8 spec . 250.0 # The specimen.
data_third
_pd_instr.id UUID3
loop_
_pd_instr_order.order
_pd_instr_order.optic_type
_pd_instr_order.optic_value_mm
_pd_instr_order.optic_value_deg
0 source . .
0 ax_source_size 12.0 .
0 eq_source_size 0.4 .
1 ax_soller . 5.0
2 eq_slit . 0.5
2 ax_slit 12.0 .
3 mono . 26.6
4 eq_slit 0.1 .
4 virt_source . .
5 eq_slit . 0.3
6 eq_slit . 0.6
7 ax_soller . 3.5
8 ax_slit 10.0 .
9 ax_spec_beam_size 10.7 .
9 spec . .
OK. So some comments.
pd_instr_layout
as the name, or even pd_instr_component
_pd_instr_component.id
as one of the key data names, as order
is not unique and the combination of order
and optic_type
, which could be unique, I guess, means that other categories would also need to use child data names of these two in order to refer to a component (see next point). Also, are we really willing to assert that no two optical elements at the same position will have the same type (because value is not a good idea, see next point)?_pd_instr_order.optic_value
is a big no-no, with the interpretation of the item depending on the value of some other item. The correct way to do this is for _pd_instr_component.id
to be referred to in the relevant other loops describing the mono/mirror/slits/doohickey. That way you're not limited to one value, can describe each component in glorious detail, have a lot more per-component flexibility. In this scheme optic_type
is a bit superfluous, but a useful check._pd_instr.id
has to be linked and one of the keys.But actually it's not that far off being pretty fit for purpose. The only danger is that we'll end up defining a whole separate dictionary that is useful for general beamline description that "everyone" will want to use.
the relevant other loops describing the mono/mirror/slits/doohickey
This is the bit I couldn't figure out how to do without having essentially a diagonal loop, and why I went with the evil solution.
Given a component ordering:
data_fourth
_pd_instr.id UUID4
loop_
_pd_instr_component.id
_pd_instr_component.order
a 0 # source . .
b 0 # ax_source_size 12.0 .
c 0 # eq_source_size 0.4 .
d 1 # ax_soller . 5.0
e 2 # eq_slit . 0.5
f 2 # ax_slit 12.0 .
g 3 # mono . 26.6
h 4 # eq_slit 0.1 .
i 4 # virt_source . .
j 5 # eq_divg . 0.3
k 6 # eq_divg . 0.6
l 7 # ax_soller . 3.5
m 8 # ax_slit 10.0 .
n 9 # ax_spec_beam_size 10.7 .
o 9 # spec . .
How to assign a value to the component and associate it with its order?
One way is to have one big loop
# single category solution
loop_
_pd_instr_details.component_id
_pd_instr_details.source
_pd_instr_details.ax_source_size
_pd_instr_details.eq_source_size
_pd_instr_details.ax_soller
_pd_instr_details.eq_slit
_pd_instr_details.ax_slit
_pd_instr_details.mono
_pd_instr_details.virt_source
_pd_instr_details.eq_divg
_pd_instr_details.ax_spec_beam_size
_pd_instr_details.spec
a Cu . . . . . . . . . .
b . 12.0 . . . . . . . . .
c . . 0.4 . . . . . . . .
d . . . 5.0 . . . . . . .
e . . . . 0.5 . . . . . .
f . . . . . 12.0 . . . . .
g . . . . . . 26.6 . . . .
h . . . . 0.1 . . . . . .
i . . . . . . . 1 . . .
j . . . . . . . . 0.3 . .
k . . . . . . . . 0.6 . .
l . . . 3.5 . . . . . . .
m . . . . . 10.0 . . . . .
n . . . . . . . . . 10.7 .
o . . . . . . . . . . 1
But it is nearly diagonal, wastes a lot of space and is hard to write and read.
The second way is to have many categories:
# many category solution
loop_
_pd_instr_source.component_id
_pd_instr_source.source
_pd_instr_source.ax_size
_pd_instr_source.eq_size
a Cu . .
b . 12.0 .
c . . 0.4
loop_
_pd_instr_soller.component_id
_pd_instr_soller.ax
d 5.0
l 3.5
loop_
_pd_instr_slit.component_id
_pd_instr_slit.eq
_pd_instr_slit.ax
e 0.5 .
f . 12.0
h 0.1 .
m . 10.0
loop_
_pd_instr_mono.component_id
_pd_instr_mono.angle
g 26.6
loop_
_pd_instr_vsrc.component_id
_pd_instr_vsrc.vsrc
i 1
loop_
_pd_instr_divg.component_id
_pd_instr_divg.eq
j 0.3
k 0.6
loop_
_pd_instr_spec.component_id
_pd_instr_spec.ax_beam_size
_pd_instr_spec.spec
n 10.7 .
o . 1
which has it's own problems in terms of managing the number of loops.
The many categories approach is preferable, because it is robust to extension. Conceivably these categories could expand in the future with geometric descriptions, manufacturing details, whatever. There is no harm in having many categories, and that just reflects the fact that these are all different things with different needs. We could consider placing all slits into a single category, though.
This could very quickly lead down the path of a thing for a separate dictionary!
This could very quickly lead down the path of a thing for a separate dictionary!
Yep. At which point one asks oneself what is most important to get done first.
Yeah, nah.
There needs at least parallel and elliptical focussing mirrors, as well as more dataitems to describe the detector
mirrors
PD_INSTR
has_pd_instr.2theta_monochr_pre
andPD_INSTR_DETECTOR
has_pd_instr.2theta_monochr_post
which have the value of the mono angle.There could be
_pd_instr.2theta_mirror_pre
and_pd_instr.2theta_mirror_post
, which takes the value 'parallel' or 'focussing', where it is assumed that the focus is on the detector (or source for a diffracted beam focussing mirror, whatever that means...).An alternate value is to give the distance of the focal point from the optic; parallel == 0, and focussing == some finite value. This allows for mirrors that don't focus on the detector.
Detectors
There needs to be more dataitems to describe strip detectors. These are small, linear position-sensitive detectors which have ~100-300 channels. The channels are normally opaque to the user, and you just get one, pre-made diffraction pattern, rather than a bunch you need to merge.
Suggestions:
_pd_instr.ax_size_detc
and_pd_instr.eq_size_detc
_pd_instr.dist_spec_detc
, so it should be possible to interconvert. There is potential perceived overlap with_pd_instr.slit_ax|eq_spec_detc
: this data item is the slit width in mm defining the collimation in the axial/equatorial direction between the specimen and detector. In the event of a linear detector oriented normally (ie strips running up in 2Th),_pd_instr.eq_size_detc
is exactly analagous with_pd_instr.slit_eq_spec_detc
_pd_instr.ax_pixels_detc
and_pd_instr.eq_pixels_detc
(or maybechannels
instead ofpixels
)_pd_instr.ax_pixels_detc 200ish
and_pd_instr.eq_pixels_detc 1
_pd_instr.detc_type
point
,linear
,curved_linear
, andarea
.point
is_pd_instr.ax_pixels_detc 1
and_pd_instr.eq_pixels_detc 1
linear
has one of_pd_instr.ax|eq_pixels_detc 1
and the other_pd_instr.eq|ax_pixels_detc >1
and is physically straight.curved_linear
has one of_pd_instr.ax|eq_pixels_detc 1
and the other_pd_instr.eq|ax_pixels_detc >1
and is curved in the direction of the larger_pd_instr.ax|eq_size_detc
dimension such that the spec-detc distance is constant.area
has both_pd_instr.ax_pixels_detc >1
and_pd_instr.eq_pixels_detc >1
and is physically flat.