diff --git a/applications/NXxas_new.nxdl.xml b/applications/NXxas_new.nxdl.xml
new file mode 100644
index 0000000000..ccb72a4549
--- /dev/null
+++ b/applications/NXxas_new.nxdl.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+ The symbol(s) listed here will be used below to coordinate datasets with the same shape.
+
+
+ Number of energy data points
+
+
+ Number of electronic transitions
+
+
+
+ This is an application definition for X-ray absorption spectroscopy.
+
+
+
+ Official NeXus NXDL schema to which this file conforms. TODO: replace NXxas
+
+
+
+
+
+
+ Transmission
+
+
+ Total fluorescence yield (TFY)
+
+
+ Partial fluorescence yield (PFY)
+
+
+
+ Excited element
+
+
+ Absorption edge
+
+
+ Specify if the data commes from a calculation
+
+
+ TODO
+
+
+
+
+
+ TODO
+
+
+
+
+
+ TODO
+
+
+
+
+
+
+ Descriptive name of the sample
+
+
+
+
+ Description on how :ref:`energy </NXxas_new/ENTRY/energy-field>`
+ and :ref:`intensity </NXxas_new/ENTRY/intensity-field>` were obtained
+ from the raw data.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ spacing between crystal planes of the reflection
+
+
+ Type or material of monochromating substance (Si, Ge, Multilayer).
+
+
+ Miller indices (hkl) values of nominal reflection
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ XAS intensity versus energy plot
+
+
+
+
+
+ Table like data structure common in the XAS domain.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/base_classes/NXedge.nxdl.xml b/base_classes/NXedge.nxdl.xml
new file mode 100644
index 0000000000..6f9a752cab
--- /dev/null
+++ b/base_classes/NXedge.nxdl.xml
@@ -0,0 +1,58 @@
+
+
+
+
+ Absorption edge
+
+
+ Name of the edge
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/base_classes/NXelement.nxdl.xml b/base_classes/NXelement.nxdl.xml
new file mode 100644
index 0000000000..19237a8d29
--- /dev/null
+++ b/base_classes/NXelement.nxdl.xml
@@ -0,0 +1,171 @@
+
+
+
+
+ Definition of a chemical element.
+
+
+ For each symbol, the atomic number, common English name, and standard atomic weight are also given.
+
+
+ - Z=1, name="hydrogen", standard_atomic_weight=1.0078
+ - Z=2, name="helium", standard_atomic_weight=4.0026
+ - Z=3, name="lithium", standard_atomic_weight=6.94
+ - Z=4, name="beryllium", standard_atomic_weight=9.0122
+ - Z=5, name="boron", standard_atomic_weight=10.81
+ - Z=6, name="carbon", standard_atomic_weight=12.011
+ - Z=7, name="nitrogen", standard_atomic_weight=14.007
+ - Z=8, name="oxygen", standard_atomic_weight=15.999
+ - Z=9, name="fluorine", standard_atomic_weight=18.9984
+ - Z=10, name="neon", standard_atomic_weight=20.1797
+ - Z=11, name="sodium", standard_atomic_weight=22.9898
+ - Z=12, name="magnesium", standard_atomic_weight=24.305
+ - Z=13, name="aluminum", standard_atomic_weight=26.9815
+ - Z=14, name="silicon", standard_atomic_weight=28.085
+ - Z=15, name="phosphorus", standard_atomic_weight=30.9738
+ - Z=16, name="sulfur", standard_atomic_weight=32.06
+ - Z=17, name="chlorine", standard_atomic_weight=35.453
+ - Z=18, name="argon", standard_atomic_weight=39.948
+ - Z=19, name="potassium", standard_atomic_weight=39.0983
+ - Z=20, name="calcium", standard_atomic_weight=40.078
+ - Z=21, name="scandium", standard_atomic_weight=44.9559
+ - Z=22, name="titanium", standard_atomic_weight=47.867
+ - Z=23, name="vanadium", standard_atomic_weight=50.9415
+ - Z=24, name="chromium", standard_atomic_weight=51.996
+ - Z=25, name="manganese", standard_atomic_weight=54.938
+ - Z=26, name="iron", standard_atomic_weight=55.845
+ - Z=27, name="cobalt", standard_atomic_weight=58.9332
+ - Z=28, name="nickel", standard_atomic_weight=58.6934
+ - Z=29, name="copper", standard_atomic_weight=63.546
+ - Z=30, name="zinc", standard_atomic_weight=65.38
+ - Z=31, name="gallium", standard_atomic_weight=69.72
+ - Z=32, name="germanium", standard_atomic_weight=72.63
+ - Z=33, name="arsenic", standard_atomic_weight=74.9216
+ - Z=34, name="selenium", standard_atomic_weight=78.971
+ - Z=35, name="bromine", standard_atomic_weight=79.904
+ - Z=36, name="krypton", standard_atomic_weight=83.798
+ - Z=37, name="rubidium", standard_atomic_weight=85.4678
+ - Z=38, name="strontium", standard_atomic_weight=87.62
+ - Z=39, name="yttrium", standard_atomic_weight=88.9058
+ - Z=40, name="zirconium", standard_atomic_weight=91.224
+ - Z=41, name="niobium", standard_atomic_weight=92.9064
+ - Z=42, name="molybdenum", standard_atomic_weight=95.95
+ - Z=43, name="technetium", standard_atomic_weight=97.907
+ - Z=44, name="ruthenium", standard_atomic_weight=101.07
+ - Z=45, name="rhodium", standard_atomic_weight=102.906
+ - Z=46, name="palladium", standard_atomic_weight=106.42
+ - Z=47, name="silver", standard_atomic_weight=107.868
+ - Z=48, name="cadmium", standard_atomic_weight=112.414
+ - Z=49, name="indium", standard_atomic_weight=114.818
+ - Z=50, name="tin", standard_atomic_weight=118.71
+ - Z=51, name="antimony", standard_atomic_weight=121.76
+ - Z=52, name="tellurium", standard_atomic_weight=127.6
+ - Z=53, name="iodine", standard_atomic_weight=126.905
+ - Z=54, name="xenon", standard_atomic_weight=131.293
+ - Z=55, name="cesium", standard_atomic_weight=132.905
+ - Z=56, name="barium", standard_atomic_weight=137.327
+ - Z=57, name="lanthanum", standard_atomic_weight=138.905
+ - Z=58, name="cerium", standard_atomic_weight=140.116
+ - Z=59, name="praseodymium", standard_atomic_weight=140.908
+ - Z=60, name="neodymium", standard_atomic_weight=144.242
+ - Z=61, name="promethium", standard_atomic_weight=145.0
+ - Z=62, name="samarium", standard_atomic_weight=150.36
+ - Z=63, name="europium", standard_atomic_weight=151.96
+ - Z=64, name="gadolinium", standard_atomic_weight=157.25
+ - Z=65, name="terbium", standard_atomic_weight=158.925
+ - Z=66, name="dysprosium", standard_atomic_weight=162.5
+ - Z=67, name="holmium", standard_atomic_weight=164.93
+ - Z=68, name="erbium", standard_atomic_weight=167.259
+ - Z=69, name="thulium", standard_atomic_weight=168.934
+ - Z=70, name="ytterbium", standard_atomic_weight=173.045
+ - Z=71, name="lutetium", standard_atomic_weight=174.967
+ - Z=72, name="hafnium", standard_atomic_weight=178.49
+ - Z=73, name="tantalum", standard_atomic_weight=180.948
+ - Z=74, name="tungsten", standard_atomic_weight=183.84
+ - Z=75, name="rhenium", standard_atomic_weight=186.207
+ - Z=76, name="osmium", standard_atomic_weight=190.23
+ - Z=77, name="iridium", standard_atomic_weight=192.217
+ - Z=78, name="platinum", standard_atomic_weight=195.084
+ - Z=79, name="gold", standard_atomic_weight=196.967
+ - Z=80, name="mercury", standard_atomic_weight=200.592
+ - Z=81, name="thallium", standard_atomic_weight=204.383
+ - Z=82, name="lead", standard_atomic_weight=207.2
+ - Z=83, name="bismuth", standard_atomic_weight=208.98
+ - Z=84, name="polonium", standard_atomic_weight=209.0
+ - Z=85, name="astatine", standard_atomic_weight=210.0
+ - Z=86, name="radon", standard_atomic_weight=222.0
+ - Z=87, name="francium", standard_atomic_weight=223.0
+ - Z=88, name="radium", standard_atomic_weight=226.0
+ - Z=89, name="actinium", standard_atomic_weight=227.0
+ - Z=90, name="thorium", standard_atomic_weight=232.038
+ - Z=91, name="protactinium", standard_atomic_weight=231.036
+ - Z=92, name="uranium", standard_atomic_weight=238.029
+ - Z=93, name="neptunium", standard_atomic_weight=237.048
+ - Z=94, name="plutonium", standard_atomic_weight=239.052
+ - Z=95, name="americium", standard_atomic_weight=243.0
+ - Z=96, name="curium", standard_atomic_weight=247.0
+ - Z=97, name="berkelium", standard_atomic_weight=247.0
+ - Z=98, name="californium", standard_atomic_weight=251.0
+ - Z=99, name="einsteinium", standard_atomic_weight=252
+ - Z=100, name="fermium", standard_atomic_weight=257
+ - Z=101, name="mendelevium", standard_atomic_weight=258
+ - Z=102, name="nobelium", standard_atomic_weight=259
+ - Z=103, name="lawrencium", standard_atomic_weight=266
+ - Z=104, name="rutherfordium", standard_atomic_weight=267
+ - Z=105, name="dubnium", standard_atomic_weight=268
+ - Z=106, name="seaborgium", standard_atomic_weight=269
+ - Z=107, name="bohrium", standard_atomic_weight=270
+ - Z=108, name="hassium", standard_atomic_weight=269
+ - Z=109, name="meitnerium", standard_atomic_weight=278
+ - Z=110, name="darmstadtium", standard_atomic_weight=281
+ - Z=111, name="roentgenium", standard_atomic_weight=282
+ - Z=112, name="copernicium", standard_atomic_weight=285
+ - Z=113, name="nihonium", standard_atomic_weight=286
+ - Z=114, name="flerovium", standard_atomic_weight=289
+ - Z=115, name="moscovium", standard_atomic_weight=290
+ - Z=116, name="livermorium", standard_atomic_weight=293
+ - Z=117, name="tennessine", standard_atomic_weight=294
+ - Z=118, name="oganesson", standard_atomic_weight=294
+
+
+
+ The charge number *Z* of the atomic nucleus.
+
+
+
+ *Relative atomic mass* of the element in *amu*. It can be but is not restricted to the
+ *standard atomic weight* (using the natural abundance of isotopes).
+
+
+
+ The charge of the atom after ionic approximation of its heteronuclear bonds.
+
+
diff --git a/base_classes/NXemission_lines.nxdl.xml b/base_classes/NXemission_lines.nxdl.xml
new file mode 100644
index 0000000000..395ecb2ed3
--- /dev/null
+++ b/base_classes/NXemission_lines.nxdl.xml
@@ -0,0 +1,46 @@
+
+
+
+
+ Emission lines
+
+
+ The emission lines are writen using the IUPAC notation, i.e. an
+ initial and final edge seprated by a hyphen.
+
+ TODO: Extend the enumeration to include all possible emission lines.
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/base_classes/NXpfy.nxdl.xml b/base_classes/NXpfy.nxdl.xml
new file mode 100644
index 0000000000..ae432776da
--- /dev/null
+++ b/base_classes/NXpfy.nxdl.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ Partial fluorescence yield (PFY) mode
+
diff --git a/base_classes/NXtfy.nxdl.xml b/base_classes/NXtfy.nxdl.xml
new file mode 100644
index 0000000000..ec41a7701e
--- /dev/null
+++ b/base_classes/NXtfy.nxdl.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ Total fluorescence yield (TFY) mode
+
diff --git a/base_classes/NXtrans.nxdl.xml b/base_classes/NXtrans.nxdl.xml
new file mode 100644
index 0000000000..85ed12e25f
--- /dev/null
+++ b/base_classes/NXtrans.nxdl.xml
@@ -0,0 +1,28 @@
+
+
+
+
+ Transmission mode
+
diff --git a/base_classes/NXxas_mode.nxdl.xml b/base_classes/NXxas_mode.nxdl.xml
new file mode 100644
index 0000000000..12d1fd63bb
--- /dev/null
+++ b/base_classes/NXxas_mode.nxdl.xml
@@ -0,0 +1,141 @@
+
+
+
+
+ XAS measurement mode
+
+
+ X-ray absorption spectroscopy (XAS) is a technique that measures the absorption coefficient :math:`\mu(E)` of a material as a function of energy.
+
+ The name of the XAS mode indicates the type of process being monitored to obtain the spectrum. Below is a description of the available modes, with emphasis on the expected values for the `intensity` and `monitor` fields.
+
+ 1. Transmission
+
+ The absorption coefficient is obtained by measuring the intensity of the incident :math:`I_0` and transmitted beam :math:`I`.
+
+ .. math::
+ \mu(E) = -\ln(I/I_0)
+
+ 2. Total fluorescence yield (TFY)
+
+ The absorption coefficient is obtained by measuring the intensity of the emitted fluorescence :math:`I_f` and the incident beam :math:`I_0`.
+
+ .. math::
+ \mu(E) \propto I_f/I_0
+
+ 3. Partial fluorescence yield (PFY)
+
+ 4. Inverse partial fluorescence yield (IPFY)
+
+ 5. High-energy resolution fluorescence detection (HERFD)
+
+ 6. Total electron yield (TEY)
+
+ 7. Partial electron yield (PEY)
+
+ 8. Electron energy loss (EELS)
+
+ 9. X-ray Raman Scattering (XRS)
+
+ 10. Diffraction Anomalous Fine Structure (DAFS)
+
+ 11. X-ray Excited Optical Luminescence (XEOL)
+
+ 12. Grazing Angle Reflection Extended X-ray Absorption Fine Structure (ReflEXAFS)
+
+ 13. Other
+
+
+ -
+
+ Transmission
+
+
+ -
+
+ Total Fluorescence Yield
+
+
+ -
+
+ Partial Fluorescence Yield
+
+
+ -
+
+ Inverse Partial Fluorescence Yield
+
+
+ -
+
+ High Energy Resolution Fluorescence Detected
+
+
+ -
+
+ Total Electron Yield
+
+
+ -
+
+ Partial Electron Yield
+
+
+ -
+
+ Electron Energy Loss
+
+
+ -
+
+ X-ray Raman Scattering
+
+
+ -
+
+ Diffraction Anomalous Fine Structure
+
+
+ -
+
+ X-ray Excited Optical Luminescence
+
+
+ -
+
+ Grazing Angle Reflection Extended X-ray Absorption Fine Structure
+
+
+ -
+
+ Other
+
+
+
+
+
+
+
+
diff --git a/dev_tools/docs/nxdl.py b/dev_tools/docs/nxdl.py
index ebffd22080..e1974ecd11 100644
--- a/dev_tools/docs/nxdl.py
+++ b/dev_tools/docs/nxdl.py
@@ -364,7 +364,7 @@ def _get_required_or_optional_text(self, node):
:returns: formatted text
"""
tag = node.tag.split("}")[-1]
- if tag in ("field", "group"):
+ if tag in ("field", "group", "choice"):
optional_default = not self._use_application_defaults
optional = node.get("optional", optional_default) in (True, "true", "1", 1)
recommended = node.get("recommended", None) in (True, "true", "1", 1)
@@ -624,91 +624,144 @@ def _print_full_tree(self, ns, parent, name, indent, parent_path):
:param indent: to keep track of indentation level
:param parent_path: NX class path of parent nodes
"""
- for node in parent.xpath("nx:field", namespaces=ns):
- name = node.get("name")
- formatted_name = get_rst_formatted_name(node)
- index_name = name
- dims = self._analyze_dimensions(ns, node)
-
- optional_text = self._get_required_or_optional_text(node)
- self._print(f"{indent}{self._hyperlink_target(parent_path, name, 'field')}")
- self._print(f"{indent}.. index:: {index_name} (field)\n")
- self._print(
- f"{indent}{formatted_name}: "
- f"{optional_text}"
- f"{self._format_type(node)}"
- f"{dims}"
- f"{self._format_units(node)}"
- f" {self.get_first_parent_ref(f'{parent_path}/{name}', 'field')}"
- "\n"
- )
+ # Process children in document order to preserve XML ordering.
+ for node in parent.xpath("nx:field|nx:group|nx:choice|nx:link", namespaces=ns):
+ tag = node.tag.split("}")[-1]
+
+ if tag == "field":
+ name = node.get("name")
+ formatted_name = get_rst_formatted_name(node)
+ index_name = name
+ dims = self._analyze_dimensions(ns, node)
+
+ optional_text = self._get_required_or_optional_text(node)
+ self._print(
+ f"{indent}{self._hyperlink_target(parent_path, name, 'field')}"
+ )
+ self._print(f"{indent}.. index:: {index_name} (field)\n")
+ self._print(
+ f"{indent}{formatted_name}: "
+ f"{optional_text}"
+ f"{self._format_type(node)}"
+ f"{dims}"
+ f"{self._format_units(node)}"
+ f" {self.get_first_parent_ref(f'{parent_path}/{name}', 'field')}"
+ "\n"
+ )
- self._print_if_deprecated(ns, node, indent + self._INDENTATION_UNIT)
- self._print_doc_enum(indent, ns, node)
+ self._print_if_deprecated(ns, node, indent + self._INDENTATION_UNIT)
+ self._print_doc_enum(indent, ns, node)
+
+ for subnode in node.xpath("nx:attribute", namespaces=ns):
+ optional = self._get_required_or_optional_text(subnode)
+ self._print_attribute(
+ ns,
+ "field",
+ subnode,
+ optional,
+ indent + self._INDENTATION_UNIT,
+ parent_path + "/" + name,
+ )
- for subnode in node.xpath("nx:attribute", namespaces=ns):
- optional = self._get_required_or_optional_text(subnode)
- self._print_attribute(
- ns,
- "field",
- subnode,
- optional,
- indent + self._INDENTATION_UNIT,
- parent_path + "/" + name,
+ elif tag == "group":
+ name = node.get("name", "")
+ formatted_name = get_rst_formatted_name(node)
+ typ = node.get("type", "untyped (this is an error; please report)")
+
+ optional_text = self._get_required_or_optional_text(node)
+ if typ.startswith("NX"):
+ if name == "":
+ name = typ.lstrip("NX").upper()
+ typ = f":ref:`{typ}`"
+ hTarget = self._hyperlink_target(parent_path, name, "group")
+ # target = hTarget.replace(".. _", "").replace(":\n", "")
+ # TODO: https://github.com/nexusformat/definitions/issues/1057
+ self._print(f"{indent}{hTarget}")
+ self._print(
+ f"{indent}{formatted_name}: {optional_text}{typ} "
+ f"{self.get_first_parent_ref(f'{parent_path}/{name}', 'group')}\n"
)
- for node in parent.xpath("nx:group", namespaces=ns):
- name = node.get("name", "")
- formatted_name = get_rst_formatted_name(node)
- typ = node.get("type", "untyped (this is an error; please report)")
-
- optional_text = self._get_required_or_optional_text(node)
- if typ.startswith("NX"):
- if name == "":
- name = typ.lstrip("NX").upper()
- typ = f":ref:`{typ}`"
- hTarget = self._hyperlink_target(parent_path, name, "group")
- # target = hTarget.replace(".. _", "").replace(":\n", "")
- # TODO: https://github.com/nexusformat/definitions/issues/1057
- self._print(f"{indent}{hTarget}")
- self._print(
- f"{indent}{formatted_name}: {optional_text}{typ} {self.get_first_parent_ref(f'{parent_path}/{name}', 'group')}\n"
- )
-
- self._print_if_deprecated(ns, node, indent + self._INDENTATION_UNIT)
- self._print_doc_enum(indent, ns, node)
+ self._print_if_deprecated(ns, node, indent + self._INDENTATION_UNIT)
+ self._print_doc_enum(indent, ns, node)
+
+ for subnode in node.xpath("nx:attribute", namespaces=ns):
+ optional = self._get_required_or_optional_text(subnode)
+ self._print_attribute(
+ ns,
+ "group",
+ subnode,
+ optional,
+ indent + self._INDENTATION_UNIT,
+ parent_path + "/" + name,
+ )
- for subnode in node.xpath("nx:attribute", namespaces=ns):
- optional = self._get_required_or_optional_text(subnode)
- self._print_attribute(
+ nodename = "%s/%s" % (name, node.get("type"))
+ self._print_full_tree(
ns,
- "group",
- subnode,
- optional,
+ node,
+ nodename,
indent + self._INDENTATION_UNIT,
parent_path + "/" + name,
)
- nodename = "%s/%s" % (name, node.get("type"))
- self._print_full_tree(
- ns,
- node,
- nodename,
- indent + self._INDENTATION_UNIT,
- parent_path + "/" + name,
- )
+ elif tag == "choice":
+ name = node.get("name", "")
+ hTarget = self._hyperlink_target(parent_path, name, "choice")
+ self._print(f"{indent}{hTarget}")
+ optional_text = self._get_required_or_optional_text(node).strip("() ")
+ self._print(
+ f"{indent}**{name}**: ({optional_text}) "
+ "Only one of the following groups may be present:\n"
+ )
+ self._print_doc_enum(indent, ns, node)
- for node in parent.xpath("nx:link", namespaces=ns):
- name = node.get("name")
- formatted_name = get_rst_formatted_name(node)
- self._print(f"{indent}{self._hyperlink_target(parent_path, name, 'link')}")
- self._print(
- f"{indent}{formatted_name}: "
- ":ref:`link` "
- f"(suggested target: ``{node.get('target')}``)"
- "\n"
- )
- self._print_doc_enum(indent, ns, node)
+ # Print each group option within the choice.
+ for subnode in node.xpath("nx:group", namespaces=ns):
+ subname = subnode.get("name", "")
+ typ = subnode.get(
+ "type", "untyped (this is an error; please report)"
+ )
+ if typ.startswith("NX"):
+ if subname == "":
+ subname = typ.lstrip("NX").upper()
+ typ_ref = f":ref:`{typ}`"
+ else:
+ typ_ref = typ
+ sub_indent = indent + self._INDENTATION_UNIT
+ subTarget = self._hyperlink_target(
+ parent_path + "/" + name, subname, "group"
+ )
+ self._print(f"{sub_indent}{subTarget}")
+ self._print(f"{sub_indent}**{subname}**: {typ_ref}\n")
+ self._print_doc_enum(sub_indent, ns, subnode)
+
+ # Recursively print any content within this group option.
+ nodename = "%s/%s" % (subname, subnode.get("type"))
+ self._print_full_tree(
+ ns,
+ subnode,
+ nodename,
+ sub_indent + self._INDENTATION_UNIT,
+ parent_path + "/" + name + "/" + subname,
+ )
+
+ elif tag == "link":
+ name = node.get("name")
+ formatted_name = get_rst_formatted_name(node)
+ self._print(
+ f"{indent}{self._hyperlink_target(parent_path, name, 'link')}"
+ )
+ self._print(
+ f"{indent}{formatted_name}: "
+ ":ref:`link` "
+ f"(suggested target: ``{node.get('target')}``)"
+ "\n"
+ )
+ self._print_doc_enum(indent, ns, node)
+
+ else:
+ raise ValueError(f"Unknown node type: {tag}")
def _print(self, *args, end="\n"):
# TODO: change instances of \t to proper indentation