Skip to content
This repository has been archived by the owner on Nov 7, 2024. It is now read-only.

Ecdc 3331 nxoff geometry #1040

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion nexus_constructor/common_attrs.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class TransformationType:
NX_SAMPLE = "NXsample"
NX_USER = "NXuser"
NX_TRANSFORMATIONS = "NXtransformations"
GEOMETRY_NX_CLASS = "NXgeometry"
# GEOMETRY_NX_CLASS = "NXgeometry" # depreceated
NX_BOX = "nxbox"
SIZE = "size"
TRANSFORMATIONS = "transformations"
Expand Down
2 changes: 1 addition & 1 deletion nexus_constructor/component_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"NXfilter",
"NXflipper",
"NXfresnel_zone_plate",
"NXgeometry",
# "NXgeometry", # depreceated
"NXgrating",
"NXguide",
"NXinsertion_device",
Expand Down
42 changes: 19 additions & 23 deletions nexus_constructor/json/shape_reader.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
from typing import Any, Dict, List, Union
from typing import Any, Dict, List, Optional

import numpy as np
from PySide6.QtGui import QVector3D

from nexus_constructor.common_attrs import (
CYLINDRICAL_GEOMETRY_NX_CLASS,
GEOMETRY_NX_CLASS,
NX_BOX,
OFF_GEOMETRY_NX_CLASS,
PIXEL_SHAPE_GROUP_NAME,
SHAPE_GROUP_NAME,
Expand Down Expand Up @@ -84,13 +82,6 @@ def add_shape_to_component(self):
self._add_off_shape_to_component()
elif shape_type == CYLINDRICAL_GEOMETRY_NX_CLASS:
self._add_cylindrical_shape_to_component()
elif shape_type == GEOMETRY_NX_CLASS:
for child in self.shape_info[CommonKeys.CHILDREN][0][CommonKeys.CHILDREN]:
if (
child[NodeType.CONFIG][CommonKeys.NAME] == SHAPE_GROUP_NAME
and child[NodeType.CONFIG][CommonKeys.VALUES] == NX_BOX
):
self._add_box_shape_to_component()
Comment on lines -87 to -93
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that this will break the loading of most existing instrument templates, because they tend to use NXgeometry in some places.

Do we need to drop support for NXgeometry? Or should we just move away from it in newly created files but still load old files correctly?

else:
self.warnings.append(
InvalidShape(
Expand Down Expand Up @@ -203,9 +194,11 @@ def _add_box_shape_to_component(self):
information can be found and passes validation then the geometry is created and written to the component,
otherwise the function just returns without changing the component.
"""
children = self.children[0][CommonKeys.CHILDREN]
name = self.name
if not children:
children = False
if self.children and self.children[0][CommonKeys.CHILDREN]:
children = self.children[0][CommonKeys.CHILDREN]
else:
return
tmp_dict = {}
for child in children:
Expand All @@ -217,7 +210,7 @@ def _add_box_shape_to_component(self):
size = tmp_dict[SIZE][CommonKeys.VALUES]
box_geometry = BoxGeometry(size[0], size[1], size[2], name, units)
self.component[name] = box_geometry
self.shape = box_geometry # type:ignore
self.shape = box_geometry

@staticmethod
def __get_units(children):
Expand All @@ -226,7 +219,7 @@ def __get_units(children):
for attr in child[CommonKeys.ATTRIBUTES]:
if attr[CommonKeys.NAME] == CommonAttrs.UNITS:
return attr[CommonKeys.VALUES]
return None
return ""

def _add_cylindrical_shape_to_component(self):
"""
Expand Down Expand Up @@ -297,7 +290,7 @@ def __create_cylindrical_geometry(

def _get_shape_dataset_from_list(
self, dataset_name: str, children: List[Dict], warning: bool = True
) -> Union[Dict, None]:
) -> Optional[Dict]:
"""
Tries to find a given shape dataset from a list of datasets.
:param dataset_name: The name of the dataset that the function will search for.
Expand All @@ -320,7 +313,7 @@ def _get_shape_dataset_from_list(

def _find_and_validate_data_type(
self, dataset: Dict, expected_types: List[str], parent_name: str
) -> Union[str, None]:
) -> Optional[str]:
"""
Checks if the type in the dataset attribute has an expected value. Failing this check does not stop the geometry
creation.
Expand Down Expand Up @@ -358,7 +351,7 @@ def _find_and_validate_data_type(

return None

def _find_and_validate_units(self, vertices_dataset: Dict) -> Union[str, None]:
def _find_and_validate_units(self, vertices_dataset: Dict) -> Optional[str]:
"""
Attempts to retrieve and validate the units data.
:param vertices_dataset: The vertices dataset.
Expand Down Expand Up @@ -438,9 +431,7 @@ def _all_in_list_have_expected_type(
)
return False

def _get_values_attribute(
self, dataset: Dict, parent_name: str
) -> Union[List, None]:
def _get_values_attribute(self, dataset: Dict, parent_name: str) -> Optional[List]:
"""
Attempts to get the values attribute in a dataset. Creates an error message if it cannot be found.
:param dataset: The dataset we hope to find the values attribute in.
Expand Down Expand Up @@ -475,7 +466,7 @@ def _attribute_is_a_list(self, attribute: Any, parent_name: str) -> bool:
return False

@property
def children(self) -> Union[List, None]:
def children(self) -> Optional[List]:
"""
Attempts to get the children list from the shape dictionary.
:return: The children list if it could be found, otherwise None is returned.
Expand Down Expand Up @@ -508,7 +499,7 @@ def name(self) -> str:

def _find_and_validate_values_list(
self, dataset: Dict, expected_types: List[str], attribute_name: str
) -> Union[List, None]:
) -> Optional[List]:
"""
Attempts to find and validate the contents of the values attribute from the dataset.
:param dataset: The dataset containing the values list.
Expand Down Expand Up @@ -582,7 +573,12 @@ def _handle_mapping(self, children: List[Dict]):
detector_faces_dataset = self._get_shape_dataset_from_list(
DETECTOR_FACES, shape_group[CommonKeys.CHILDREN], False
)
self.shape.detector_faces = detector_faces_dataset[CommonKeys.VALUES]
if (
detector_faces_dataset
and not isinstance(self.shape, BoxGeometry)
and not isinstance(self.shape, CylindricalGeometry)
):
self.shape.detector_faces = detector_faces_dataset[CommonKeys.VALUES]

def _find_and_add_pixel_offsets_to_component(
self, offset_name: str, children: List[Dict]
Expand Down
6 changes: 3 additions & 3 deletions nexus_constructor/model/geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from PySide6.QtGui import QMatrix4x4, QVector3D

from nexus_constructor.common_attrs import (
GEOMETRY_NX_CLASS,
OFF_GEOMETRY_NX_CLASS,
NX_BOX,
SHAPE_GROUP_NAME,
SHAPE_NX_CLASS,
Expand Down Expand Up @@ -191,11 +191,11 @@ def __init__(
Group.__init__(self, name)
self._size = [length, width, height]
self._units = units
self.nx_class = GEOMETRY_NX_CLASS
self.nx_class = OFF_GEOMETRY_NX_CLASS
self._create_datasets_and_add_to_shape_group()
Comment on lines +194 to 195
Copy link
Contributor

@danesss danesss Sep 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method _create_datasets_and_add_to_shape_group(self) makes use of SHAPE_NX_CLASS. Is that still adequate when using NXoff_geometry?

If not, then this file may need a bigger change to translate all NXshape geometries to use NXoff_geometry


@property
def detector_number(self) -> List[int]:
def detector_number(self) -> Optional[List[int]]:
if self._detector is None:
return None
return self._detector.tolist()
Expand Down
4 changes: 3 additions & 1 deletion nexus_constructor/model/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,9 @@ def nx_class(self):
def nx_class(self, new_nx_class: str):
self.attributes.set_attribute_value(CommonAttrs.NX_CLASS, new_nx_class)

def set_field_value(self, name: str, value: Any, dtype: str, unit: str = ""):
def set_field_value(
self, name: str, value: Any, dtype: Optional[str], unit: str = ""
):
self[name] = Dataset(parent_node=self, name=name, type=dtype, values=value)
if unit:
self[name].attributes.set_attribute_value(CommonAttrs.UNITS, unit)
Expand Down
2 changes: 1 addition & 1 deletion nexus_constructor/model/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def as_nexus(self, nexus_node, error_collector: List[str]):
class Dataset(FileWriterModule):
name: str = attr.ib()
values: Union[List[ValueType], ValueType] = attr.ib()
type: str = attr.ib(default=None)
type: Optional[str] = attr.ib(default=None)
writer_module: str = attr.ib(default=WriterModules.DATASET.value, init=False)

def as_dict(self, error_collector: List[str]):
Expand Down
2 changes: 1 addition & 1 deletion nx-class-documentation/html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ <h1>User Manual and Reference Documentation<a class="headerlink" href="#user-man
</div>
<hr class="docutils" />
<p class="rubric">Publishing Information</p>
<p>This manual built Sep 21, 2023.</p>
<p>This manual built Sep 26, 2023.</p>
<div class="admonition seealso">
<p class="admonition-title">See also</p>
<p>This document is available in these formats online:</p>
Expand Down
2 changes: 1 addition & 1 deletion nx-class-documentation/html/searchindex.js

Large diffs are not rendered by default.

117 changes: 77 additions & 40 deletions tests/json/shape_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,54 +278,91 @@ def off_shape_json() -> Dict:
def box_shape_json() -> dict:
box_shape = """
{
"name": "geometry",
"type": "group",
"attributes": [
"name":"geometry",
"attributes":[
{
"name": "NX_class",
"dtype": "string",
"values": "NXgeometry"
"name":"NX_class",
"type":"string",
"values":"NXoff_geometry"
}
],
"children": [
"type":"group",
"children":[
{
"name": "shape",
"type": "group",
"attributes": [
"module":"dataset",
"config":{
"name":"faces",
"type":"int32",
"values":[
0, 4, 8, 12, 16, 20
]
}
},
{
"module":"dataset",
"attributes":[
{
"name": "NX_class",
"dtype": "string",
"values": "NXshape"
"name":"units",
"type":"string",
"values":"m"
}
],
"children": [
{
"module": "dataset",
"config": {
"name": "size",
"values": [
6.0,
12.0,
15.0
],
"type": "double"
},
"attributes": [
{
"name": "units",
"dtype": "string",
"values": "m"
}
"config":{
"name":"vertices",
"type":"float",
"values":[
[
0.0,
0.0,
0.0
],
[
1.0,
0.0,
0.0
],
[
1.0,
0.0,
1.0
],
[
0.0,
0.0,
1.0
],
[
0.0,
1.0,
0.0
],
[
1.0,
1.0,
0.0
],
[
1.0,
1.0,
1.0
],
[
0.0,
1.0,
1.0
]
},
{
"module": "dataset",
"config": {
"name": "shape",
"values": "nxbox"
}
}
]
]
}
},
{
"module":"dataset",
"config":{
"name":"winding_order",
"type":"int32",
"values":[
0, 1, 2, 3, 4, 5, 6, 7, 0, 3, 7, 4, 1, 2, 6, 5, 0, 1, 5, 4, 3, 2, 6, 7
]
}
}
]
}
Expand Down
11 changes: 5 additions & 6 deletions tests/json/test_shape_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from nexus_constructor.common_attrs import (
CYLINDRICAL_GEOMETRY_NX_CLASS,
GEOMETRY_GROUP_NAME,
GEOMETRY_NX_CLASS,
OFF_GEOMETRY_NX_CLASS,
PIXEL_SHAPE_GROUP_NAME,
SHAPE_GROUP_NAME,
Expand Down Expand Up @@ -714,14 +713,14 @@ def test_GIVEN_valid_pixel_mapping_and_cylindrical_shape_WHEN_reading_pixel_data
def test_GIVEN_box_shape_json_WHEN_reading_shape_THEN_geometry_object_has_expected_properties(
box_shape_reader, box_shape_json, mock_component
):
# no detector faces
name = box_shape_json[CommonKeys.NAME]
box_shape_reader.add_shape_to_component()
shape = mock_component[name]
assert isinstance(shape, BoxGeometry)
assert isinstance(shape, OFFGeometryNexus)
assert shape.name == name
assert shape.nx_class == GEOMETRY_NX_CLASS
assert shape.size[0] == 6.0
assert shape.size[1] == 12.0
assert shape.size[2] == 15.0
assert shape.nx_class == OFF_GEOMETRY_NX_CLASS
assert len(shape.faces[0]) == 4
assert len(shape.faces) == 6
Comment on lines +723 to +724
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shall we assert the dimensions of the shape like length/width/height?

assert shape.units == "m"
assert shape.name == GEOMETRY_GROUP_NAME