ts_ids_components.xrd.datacube module#

Two-theta scan datacube components for XRD IDSs.

The scan modes where 2-theta is the varying dimension are called 2-Theta Scans (e.g. coupled reflection, grazing incidence, reflectivity, transmission) – as opposed to modes like rocking curves, pole figures, or reciprocal space maps, whose primary scan variable is a different axis entirely (see below). TwoThetaScanDatacube models one 2-Theta Scan’s raw per-point data: every value recorded at each step, not just a 2-theta/intensity pair:

  • Bruker D8 Advance RawData0.xml: each Datum row is effective_time_per_step, scan_point_index, 2Theta, Theta, Intensity (5 values). Theta moves in lockstep with 2Theta in the D8 Advance’s coupled Theta/Theta scan.

  • Malvern Panalytical Empyrean .xrdml: a coupled scan varies both 2Theta and Omega simultaneously, with Phi fixed.

  • Rigaku Profile*.txt: each row is 2Theta, Intensity, Weight (3 values); Weight is the RAS-format attenuation/correction factor applied when an attenuator is switched in near the direct beam. Rigaku’s wider MesurementConditions*.xml axis table also lists Omega, Chi, and other hardware axes available on the same platform.

Every 2-Theta Scan mode – regardless of vendor or specific application – varies 2-theta as its dimension with intensity as a measure; that dimension/measure shape, not “pharma powder XRD” as such, is the precise criterion TwoThetaScanDatacube supports. Scan modes with a different primary scan variable (rocking curves, pole figures, reciprocal space maps – primary dimension is omega, phi, or a reciprocal-space grid, not 2-theta) aren’t 2-Theta Scans, so they don’t fit this shape and have no datacube component defined here yet. If a customer needs one of those modes, it should get its own datacube class following the same fixed-length/ vendor-subclass pattern as TwoThetaScanDatacube below, not a variant of TwoThetaScanDatacube itself. So TwoThetaScanDatacube’s one Dimension is 2-theta itself (name="two_theta", unit="DegreeAngle", real angle values), not a synthetic index. Every other per-point column – Theta/Omega (which covary 1:1 with 2-theta rather than varying independently of it) and ancillary fields like Weight or effective_time_per_step – becomes one named XrdMeasure sharing that one 2-theta dimension: no DataCube subclass anywhere in this repo or the wider platform models a quantity that covaries with the primary axis as a second Dimension – that’s reserved for genuinely independent grid axes (e.g. chromatography’s wavelength x time PDA cube), which this data isn’t.

intensity is a required measure on every TwoThetaScanDatacube, and (as counts) a mandatory, non-optional element in Empyrean’s own XRDML schema regardless of scan mode.

ts_ids_core.schema.DataCube’s measures/dimensions fixed_length is a whole-class constant, not additive across inheritance: a vendor subclass can’t “add more measures” to an inherited count, it must restate its own total. So TwoThetaScanDatacube fixes dimensions at exactly 1 (identical for every vendor, never restated by subclasses) and provides fk_method/fk_run/fk_system/fk_sample/name/ description once for everyone, but each vendor’s own subclass still restates measures with its own total fixed_length (e.g. 4 for Bruker’s remaining Datum columns once 2-theta becomes the dimension) – the two_theta dimension name and intensity measure presence checks run on every subclass regardless, since they’re a validator, not a structural constraint:

class VendorTwoThetaScanDatacube(TwoThetaScanDatacube):
    # one XrdMeasure per raw per-point column for this vendor, other
    # than 2-theta itself (the dimension), e.g. for Bruker: theta,
    # intensity, effective_time_per_step, scan_point_index
    measures: Required[Annotated[List[XrdMeasure], fixed_length(4)]]

Every other axis is still trivially found by looking up measures by name.

See ts_ids_components.xrd.datacube_raw for RawTwoThetaScanDatacube, which preserves each datacube’s untouched raw text alongside it.

TWO_THETA_SCAN_DIMENSION_NAME = 'two theta'#

Standard name for a TwoThetaScanDatacube’s one required dimension. See the module docstring above for why 2-theta – not a synthetic index – is the dimension every vendor’s datacube shares.

Model XrdMeasure[source]#

Bases: MeasureBase

A single named per-point quantity in a TwoThetaScanDatacube (e.g. "theta", "omega", "intensity", "weight", "effective_time_per_step"), sharing the datacube’s one TWO_THETA_SCAN_DIMENSION_NAME dimension. See the module docstring above for why any axis that covaries with 2-theta – rather than varying independently of it – is modeled as a measure rather than a second dimension.

Show JSON schema
{
   "description": "A single named per-point quantity in a :py:class:`TwoThetaScanDatacube`\n(e.g. ``\"theta\"``, ``\"omega\"``, ``\"intensity\"``, ``\"weight\"``,\n``\"effective_time_per_step\"``), sharing the datacube's one\n:py:data:`TWO_THETA_SCAN_DIMENSION_NAME` dimension. See the module\ndocstring above for why any axis that covaries with 2-theta -- rather\nthan varying independently of it -- is modeled as a measure rather than\na second dimension.",
   "type": "object",
   "properties": {
      "name": {
         "type": [
            "string",
            "null"
         ]
      },
      "unit": {
         "type": [
            "string",
            "null"
         ]
      },
      "value": {
         "items": {
            "type": [
               "number",
               "null"
            ]
         },
         "type": "array"
      }
   },
   "additionalProperties": false,
   "required": [
      "name",
      "unit",
      "value"
   ]
}

Validators:
  • validate_value_shape » value

field name: Required[Nullable[str]]#
field unit: Required[Nullable[str]]#
field value: List[float | None]#
num_dimensions: ClassVar[int] = 1#
Model TwoThetaScanDatacube[source]#

Bases: DataCube

Base for 2-Theta Scan datacubes. See the module docstring above for the raw file evidence behind this shape. Carries a pk so its raw counterpart (RawTwoThetaScanDatacube <ts_ids_components.xrd.datacube_raw.RawTwoThetaScanDatacube>) can link directly back to it – see ts_ids_components.xrd.datacube_raw. Also carries four foreign keys, linking each datacube to the scan (in methods, see ts_ids_components.xrd.method) via fk_method, the run (in runs, see ts_ids_components.xrd.run) via fk_run, the system (in systems, see ts_ids_components.xrd.system) via fk_system, and the sample (in samples, see ts_ids_components.xrd.sample) via fk_sample.

Show JSON schema
{
   "description": "Base for 2-Theta Scan datacubes. See the module docstring above for the\nraw file evidence behind this shape. Carries a `pk` so its raw\ncounterpart (`RawTwoThetaScanDatacube\n<ts_ids_components.xrd.datacube_raw.RawTwoThetaScanDatacube>`) can link\ndirectly back to it -- see :py:mod:`ts_ids_components.xrd.datacube_raw`.\nAlso carries four foreign keys, linking each datacube to the scan (in\n`methods`, see :py:mod:`ts_ids_components.xrd.method`) via `fk_method`,\nthe run (in `runs`, see :py:mod:`ts_ids_components.xrd.run`) via\n`fk_run`, the system (in `systems`, see\n:py:mod:`ts_ids_components.xrd.system`) via `fk_system`, and the sample\n(in `samples`, see :py:mod:`ts_ids_components.xrd.sample`) via\n`fk_sample`.",
   "type": "object",
   "properties": {
      "name": {
         "type": "string"
      },
      "measures": {
         "items": {
            "$ref": "#/definitions/XrdMeasure"
         },
         "maxItems": 1,
         "minItems": 1,
         "type": "array"
      },
      "dimensions": {
         "items": {
            "$ref": "#/definitions/Dimension"
         },
         "maxItems": 1,
         "minItems": 1,
         "type": "array"
      },
      "pk": {
         "@primary_key": true,
         "description": "Primary key for this datacube, referenced by the raw datacube (in `datacubes_raw`) preserving its untouched source text.",
         "type": "string"
      },
      "fk_method": {
         "@foreign_key": "/properties/methods/items/properties/pk",
         "description": "Foreign key to the scan (in `methods`) that produced this datacube. A single raw file can contain multiple independent scans, e.g. repeat measurements sharing one autosampler batch submission.",
         "type": "string"
      },
      "fk_run": {
         "@foreign_key": "/properties/runs/items/properties/pk",
         "description": "Foreign key to the run (in `runs`) that produced this datacube.",
         "type": "string"
      },
      "fk_system": {
         "@foreign_key": "/properties/systems/items/properties/pk",
         "description": "Foreign key to the system (in `systems`) that produced this datacube.",
         "type": "string"
      },
      "fk_sample": {
         "@foreign_key": "/properties/samples/items/properties/pk",
         "description": "Foreign key to the sample (in `samples`) this datacube was measured on.",
         "type": "string"
      },
      "description": {
         "type": [
            "string",
            "null"
         ]
      }
   },
   "additionalProperties": false,
   "required": [
      "name",
      "measures",
      "dimensions",
      "pk",
      "fk_method",
      "fk_run",
      "fk_system",
      "fk_sample"
   ],
   "definitions": {
      "Dimension": {
         "additionalProperties": false,
         "description": "A dimension of a DataCube",
         "properties": {
            "name": {
               "type": [
                  "string",
                  "null"
               ]
            },
            "unit": {
               "type": [
                  "string",
                  "null"
               ]
            },
            "scale": {
               "items": {
                  "type": [
                     "number",
                     "null"
                  ]
               },
               "type": "array"
            }
         },
         "required": [
            "name",
            "unit",
            "scale"
         ],
         "type": "object"
      },
      "XrdMeasure": {
         "additionalProperties": false,
         "description": "A single named per-point quantity in a :py:class:`TwoThetaScanDatacube`\n(e.g. ``\"theta\"``, ``\"omega\"``, ``\"intensity\"``, ``\"weight\"``,\n``\"effective_time_per_step\"``), sharing the datacube's one\n:py:data:`TWO_THETA_SCAN_DIMENSION_NAME` dimension. See the module\ndocstring above for why any axis that covaries with 2-theta -- rather\nthan varying independently of it -- is modeled as a measure rather than\na second dimension.",
         "properties": {
            "name": {
               "type": [
                  "string",
                  "null"
               ]
            },
            "unit": {
               "type": [
                  "string",
                  "null"
               ]
            },
            "value": {
               "items": {
                  "type": [
                     "number",
                     "null"
                  ]
               },
               "type": "array"
            }
         },
         "required": [
            "name",
            "unit",
            "value"
         ],
         "type": "object"
      }
   }
}

Validators:
field description: str | None#
field dimensions: List[Dimension]#
Constraints:
  • min_length = 1

  • max_length = 1

field fk_method: str#

Foreign key to the scan (in methods) that produced this datacube. A single raw file can contain multiple independent scans, e.g. repeat measurements sharing one autosampler batch submission.

Constraints:
  • func = <function validate_uuid at 0x7f1493ac61f0>

  • json_schema_input_type = PydanticUndefined

  • ids_field_arg = primary_key

  • pk_reference_field = @foreign_key

field fk_run: str#

Foreign key to the run (in runs) that produced this datacube.

Constraints:
  • func = <function validate_uuid at 0x7f1493ac61f0>

  • json_schema_input_type = PydanticUndefined

  • ids_field_arg = primary_key

  • pk_reference_field = @foreign_key

field fk_sample: str#

Foreign key to the sample (in samples) this datacube was measured on.

Constraints:
  • func = <function validate_uuid at 0x7f1493ac61f0>

  • json_schema_input_type = PydanticUndefined

  • ids_field_arg = primary_key

  • pk_reference_field = @foreign_key

field fk_system: str#

Foreign key to the system (in systems) that produced this datacube.

Constraints:
  • func = <function validate_uuid at 0x7f1493ac61f0>

  • json_schema_input_type = PydanticUndefined

  • ids_field_arg = primary_key

  • pk_reference_field = @foreign_key

field measures: List[XrdMeasure]#
Constraints:
  • min_length = 1

  • max_length = 1

field name: str#
field pk: str#

Primary key for this datacube, referenced by the raw datacube (in datacubes_raw) preserving its untouched source text.

Constraints:
  • func = <function validate_uuid at 0x7f1493ac61f0>

  • json_schema_input_type = PydanticUndefined

validator two_theta_dimension_and_intensity_measure_present  »  all fields[source]#

Every TwoThetaScanDatacube’s one dimension must be two_theta, and intensity must be present as a measure. This is the precise criterion for what this component supports: any 2-Theta Scan, i.e. any scan with 2-theta as its dimension and intensity as a measure, not specifically pharma powder XRD. See the module docstring above for the scan modes (rocking curves, pole figures, reciprocal space maps – primary dimension is omega, phi, or a reciprocal-space grid, not 2-theta) this intentionally doesn’t support.

Validates:
  • all fields