Skip to content
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

PD_INSTR and PD_INSTR_DETECTOR extension #157

Open
rowlesmr opened this issue Jun 17, 2023 · 8 comments
Open

PD_INSTR and PD_INSTR_DETECTOR extension #157

rowlesmr opened this issue Jun 17, 2023 · 8 comments

Comments

@rowlesmr
Copy link
Collaborator

rowlesmr commented Jun 17, 2023

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 and PD_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
    • Axial/equatorial size of the detector. Should it be in degrees or millimetres? I think degrees. The spec-detc distance can be specified with _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 maybe channels instead of pixels)
    • The number of pixels in the axial/equatorial directions. For a conventional strip detector, it would be _pd_instr.ax_pixels_detc 200ish and _pd_instr.eq_pixels_detc 1
  • _pd_instr.detc_type
    • An enumeration of point, linear, curved_linear, and area.
    • 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.
@jamesrhester
Copy link
Contributor

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.

@rowlesmr
Copy link
Collaborator Author

Moved from #162

(#162 (comment)) _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
    • an alternative would be to have _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                 .      .

@jamesrhester
Copy link
Contributor

OK. So some comments.

  1. It is going in the right direction
  2. I prefer pd_instr_layout as the name, or even pd_instr_component
  3. There should be a separate _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)?
  4. As you correctly asterisk, _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.
  5. The distances should definitely be along the beam direction, not straight line. If straight line, then you need a direction as well in order to locate it.
  6. Good catch that _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.

@rowlesmr
Copy link
Collaborator Author

rowlesmr commented Jul 1, 2023

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.

@jamesrhester
Copy link
Contributor

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.

@rowlesmr
Copy link
Collaborator Author

rowlesmr commented Jul 6, 2023

This could very quickly lead down the path of a thing for a separate dictionary!

@jamesrhester
Copy link
Contributor

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.

@rowlesmr
Copy link
Collaborator Author

rowlesmr commented Jul 8, 2023

Yeah, nah.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants