Skip to content

Commit

Permalink
Add spatial_data to csm serialization (#364)
Browse files Browse the repository at this point in the history
Co-authored-by: Cagtay Fabry <[email protected]>
  • Loading branch information
vhirtham and CagtayFabry authored Jun 22, 2021
1 parent a98a4bd commit f1cebd2
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 17 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
- add `core/graph/di_node`, `core/graph/di_edge` & `core/graph/di_graph` for implementing a
generic `networkx.DiGraph` [[#330]](https://github.com/BAMWelDX/weldx/pull/330)
- compatibility with ASDF-2.8 [[#355]](https://github.com/BAMWelDX/weldx/pull/355)
- data attached to an instance of the `CoordinateSystemManger` is now also stored in a WelDX file
[[#364]](https://github.com/BAMWelDX/weldx/pull/339)
- replace references to base asdf tags with `-1.*` version wildcard [[#373]](https://github.com/BAMWelDX/weldx/pull/373)
- update `single-pass-weldx.1.0.0.schema` to allow groove types by
wildcard [[#373]](https://github.com/BAMWelDX/weldx/pull/373)
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ This research is funded by the Federal Ministry of Education and Research of Ger

[![pytest](https://github.com/BAMWelDX/weldx/workflows/pytest/badge.svg?branch=master)](https://github.com/BAMWelDX/weldx/actions?query=workflow%3Apytest+branch%3Amaster)
[![conda build](https://github.com/BAMWelDX/weldx/workflows/conda%20build/badge.svg?branch=master)](https://github.com/BAMWelDX/weldx/actions?query=workflow%3A%22conda+build%22+branch%3Amaster)
[![](https://travis-ci.com/BAMWelDX/weldx.svg?branch=master)](https://travis-ci.com/BAMWelDX/weldx)
[![Build status](https://ci.appveyor.com/api/projects/status/6yvswkpj7mmdbrk1/branch/master?svg=true)](https://ci.appveyor.com/project/BAMWelDX/weldx/branch/master)

### Code Status
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,20 @@ properties:
items:
tag: "tag:weldx.bam.de:weldx/core/transformations/coordinate_transformation-1.0.0"

propertyOrder: [name, root_system_name, reference_time, subsystems, subsystem_data, coordinate_systems]
spatial_data:
type: array
items:
type: object
properties:
coordinate_system:
type: string
name:
type: string
data:
tag: "tag:weldx.bam.de:weldx/core/geometry/spatial_data-1.*"
required: [coordinate_system, name, data]

propertyOrder: [name, root_system_name, reference_time, subsystems, subsystem_data, coordinate_systems, spatial_data]
required: [name, root_system_name, coordinate_systems]
flowStyle: block
...
4 changes: 4 additions & 0 deletions weldx/asdf/tags/weldx/core/geometry/spatial_data.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from copy import deepcopy

import numpy as np

from weldx.asdf.types import WeldxType
from weldx.geometry import SpatialData

Expand Down Expand Up @@ -57,4 +59,6 @@ def from_tree(cls, tree, ctx) -> SpatialData:
An instance of the 'weldx.geometry.point_cloud' type.
"""
if "coordinates" in tree:
tree["coordinates"] = np.asarray(tree["coordinates"])
return SpatialData(**tree)
Original file line number Diff line number Diff line change
Expand Up @@ -406,13 +406,21 @@ def to_tree(cls, node: CoordinateSystemManager, ctx):
if subsystem.parent_system == node.name
]

spatial_data = None
if len(node._data) > 0:
spatial_data = [
dict(name=k, coordinate_system=v.coordinate_system_name, data=v.data)
for k, v in node._data.items()
]

tree = {
"name": node.name,
"reference_time": node.reference_time,
"subsystem_names": subsystems,
"subsystems": subsystem_data,
"root_system_name": node.root_system_name,
"coordinate_systems": coordinate_system_data,
"spatial_data": spatial_data,
}
return tree

Expand Down Expand Up @@ -458,4 +466,8 @@ def from_tree(cls, tree, ctx):
cls._add_coordinate_systems_to_subsystems(tree, csm, subsystem_data_list)
cls._merge_subsystems(tree, csm, subsystem_data_list)

if (spatial_data := tree.get("spatial_data")) is not None:
for item in spatial_data:
csm.assign_data(item["data"], item["name"], item["coordinate_system"])

return csm
63 changes: 50 additions & 13 deletions weldx/tests/asdf_tests/test_asdf_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import weldx.transformations as tf
from weldx.asdf.tags.weldx.core.file import ExternalFile
from weldx.asdf.util import _write_buffer, _write_read_buffer
from weldx.asdf.util import _write_buffer, write_read_buffer
from weldx.constants import WELDX_QUANTITY as Q_
from weldx.core import MathematicalExpression as ME # nopep8
from weldx.core import TimeSeries
Expand Down Expand Up @@ -52,7 +52,7 @@
],
)
def test_rotation(inputs):
data = _write_read_buffer({"rot": inputs})
data = write_read_buffer({"rot": inputs})
r = data["rot"]
assert np.allclose(r.as_quat(), inputs.as_quat())
if hasattr(inputs, "wx_meta"):
Expand All @@ -79,7 +79,7 @@ def test_rotation_euler_prefix(inputs):
"""Test unit prefix handling."""
degrees = "degree" in str(inputs.u)
rot = WXRotation.from_euler(seq="x", angles=inputs)
data = _write_read_buffer({"rot": rot})
data = write_read_buffer({"rot": rot})
r = data["rot"].as_euler("xyz", degrees=degrees)[0]
r = Q_(r, "degree") if degrees else Q_(r, "rad")
assert np.allclose(inputs, r)
Expand Down Expand Up @@ -118,7 +118,7 @@ def test_xarray_data_array(copy_arrays, lazy_load):
"""Test ASDF read/write of xarray.DataArray."""
dax = get_xarray_example_data_array()
tree = {"dax": dax}
dax_file = _write_read_buffer(
dax_file = write_read_buffer(
tree, open_kwargs={"copy_arrays": copy_arrays, "lazy_load": lazy_load}
)["dax"]
assert dax.identical(dax_file)
Expand Down Expand Up @@ -168,7 +168,7 @@ def get_xarray_example_dataset():
def test_xarray_dataset(copy_arrays, lazy_load):
dsx = get_xarray_example_dataset()
tree = {"dsx": dsx}
dsx_file = _write_read_buffer(
dsx_file = write_read_buffer(
tree, open_kwargs={"copy_arrays": copy_arrays, "lazy_load": lazy_load}
)["dsx"]
assert dsx.identical(dsx_file)
Expand Down Expand Up @@ -227,7 +227,7 @@ def test_local_coordinate_system(
):
"""Test (de)serialization of LocalCoordinateSystem in ASDF."""
lcs = get_local_coordinate_system(time_dep_orientation, time_dep_coordinates)
data = _write_read_buffer(
data = write_read_buffer(
{"lcs": lcs}, open_kwargs={"copy_arrays": copy_arrays, "lazy_load": lazy_load}
)
assert data["lcs"] == lcs
Expand Down Expand Up @@ -299,7 +299,7 @@ def get_example_coordinate_system_manager():
def test_coordinate_system_manager(copy_arrays, lazy_load):
csm = get_example_coordinate_system_manager()
tree = {"cs_hierarchy": csm}
data = _write_read_buffer(
data = write_read_buffer(
tree, open_kwargs={"copy_arrays": copy_arrays, "lazy_load": lazy_load}
)
csm_file = data["cs_hierarchy"]
Expand Down Expand Up @@ -361,7 +361,7 @@ def get_coordinate_system_manager_with_subsystems(nested: bool):
def test_coordinate_system_manager_with_subsystems(copy_arrays, lazy_load, nested):
csm = get_coordinate_system_manager_with_subsystems(nested)
tree = {"cs_hierarchy": csm}
data = _write_read_buffer(
data = write_read_buffer(
tree, open_kwargs={"copy_arrays": copy_arrays, "lazy_load": lazy_load}
)
csm_file = data["cs_hierarchy"]
Expand Down Expand Up @@ -403,13 +403,50 @@ def test_coordinate_system_manager_time_dependencies(
csm_root.merge(csm_sub_2)

tree = {"cs_hierarchy": csm_root}
data = _write_read_buffer(
data = write_read_buffer(
tree, open_kwargs={"copy_arrays": copy_arrays, "lazy_load": lazy_load}
)
csm_file = data["cs_hierarchy"]
assert csm_root == csm_file


@pytest.mark.parametrize("copy_arrays", [True, False])
@pytest.mark.parametrize("lazy_load", [True, False])
def test_coordinate_system_manager_with_data(copy_arrays, lazy_load):
"""Test if data attached to a CSM is stored and read correctly."""
csm = tf.CoordinateSystemManager("root", "csm")
csm.create_cs("cs_1", "root", coordinates=[1, 1, 1])
csm.create_cs("cs_2", "root", coordinates=[-1, -1, -1])
csm.create_cs("cs_11", "cs_1", coordinates=[1, 1, 1])

data_11 = SpatialData(coordinates=np.array([[1.0, 2.0, 3.0], [3.0, 2.0, 1.0]]))
data_2 = SpatialData(
coordinates=np.array(
[
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[1.0, 1.0, 0.0],
[0.0, 1.0, 0.0],
]
),
triangles=np.array([[0, 1, 2], [0, 2, 3]], dtype="uint32"),
)

csm.assign_data(data_11, "data_11", "cs_11")
csm.assign_data(data_2, "data_2", "cs_2")

tree = {"csm": csm}
buffer = write_read_buffer(
tree, open_kwargs={"copy_arrays": copy_arrays, "lazy_load": lazy_load}
)
csm_buffer = buffer["csm"]

for data_name in csm.data_names:
sd = csm.get_data(data_name)
sd_buffer = csm_buffer.get_data(data_name)
assert sd == sd_buffer


# --------------------------------------------------------------------------------------
# TimeSeries
# --------------------------------------------------------------------------------------
Expand All @@ -428,7 +465,7 @@ def test_coordinate_system_manager_time_dependencies(
],
)
def test_time_series_discrete(ts, copy_arrays, lazy_load):
ts_file = _write_read_buffer(
ts_file = write_read_buffer(
{"ts": ts}, open_kwargs={"copy_arrays": copy_arrays, "lazy_load": lazy_load}
)["ts"]
if isinstance(ts.data, ME):
Expand Down Expand Up @@ -616,7 +653,7 @@ def test_asdf_serialization(copy_arrays, lazy_load, store_content):
asdf_save_content=store_content,
)
tree = {"file": ef}
ef_file = _write_read_buffer(
ef_file = write_read_buffer(
tree, open_kwargs={"copy_arrays": copy_arrays, "lazy_load": lazy_load}
)["file"]

Expand Down Expand Up @@ -661,7 +698,7 @@ def test_asdf_serialization(copy_arrays, lazy_load):

pc = SpatialData(coordinates=coordinates, triangles=triangles)
tree = {"point_cloud": pc}
pc_file = _write_read_buffer(
pc_file = write_read_buffer(
tree, open_kwargs={"copy_arrays": copy_arrays, "lazy_load": lazy_load}
)["point_cloud"]

Expand All @@ -678,7 +715,7 @@ def test_graph_serialization():
g.add_edges_from(
[("A", "B"), ("A", "C"), ("A", "F"), ("D", "C"), ("B", "H"), ("X", "A")]
)
g2 = _write_read_buffer({"graph": g})["graph"]
g2 = write_read_buffer({"graph": g})["graph"]

assert all(e in g.edges for e in g2.edges)
assert all(n in g.nodes for n in g2.nodes)
55 changes: 54 additions & 1 deletion weldx/tests/test_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import math
from pathlib import Path
from tempfile import TemporaryDirectory
from typing import List, Union
from typing import Dict, List, Union

import numpy as np
import pint
Expand Down Expand Up @@ -2906,6 +2906,8 @@ def test_class_creation(arguments):
if len(arguments) > 1 and arguments[1] is not None:
np.all(arguments[1] == pc.triangles)

# test_class_creation_exceptions ---------------------------------------------------

@staticmethod
@pytest.mark.parametrize(
"arguments, exception_type, test_name",
Expand All @@ -2931,6 +2933,57 @@ def test_class_creation_exceptions(arguments, exception_type, test_name):
with pytest.raises(exception_type):
SpatialData(*arguments)

# test_comparison ------------------------------------------------------------------

@staticmethod
@pytest.mark.parametrize(
"kwargs_mod, expected_result",
[
({}, True),
(dict(coordinates=[[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 1]]), False),
(dict(coordinates=[[0, 0, 0], [1, 0, 0], [1, 1, 0]]), False),
(dict(triangles=[[0, 1, 2], [2, 3, 1]]), False),
(dict(triangles=[[0, 1, 2], [2, 3, 1], [2, 3, 1]]), False),
(dict(triangles=[[0, 1, 2]]), False),
(dict(triangles=None), False),
(dict(attributes=dict(data=[2, 2, 3])), False),
(dict(attributes=dict(dat=[1, 2, 3])), False),
# uncomment once issue #376 is resolved
# (dict(attributes=dict(data=[1, 2, 3], more=[1, 2, 5])), False),
(dict(attributes={}), False),
(dict(attributes=None), False),
],
)
def test_comparison(kwargs_mod: Dict, expected_result: bool):
"""Test the comparison operator by comparing two instances.
Parameters
----------
kwargs_mod :
A dictionary of key word arguments that is used to overwrite the default
values in the RHS `SpatialData`. If an empty dict is passed, LHS and RHS
are constructed with the same values.
expected_result :
Expected result of the comparison
"""
from copy import deepcopy

default_kwargs = dict(
coordinates=[[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]],
triangles=[[0, 1, 2], [2, 3, 0]],
attributes=dict(data=[1, 2, 3]),
)
reference = SpatialData(**default_kwargs)

kwargs_other = deepcopy(default_kwargs)
kwargs_other.update(kwargs_mod)
other = SpatialData(**kwargs_other)

assert (reference == other) == expected_result

# test_read_write_file -------------------------------------------------------------

@staticmethod
@pytest.mark.parametrize(
"filename",
Expand Down
2 changes: 1 addition & 1 deletion weldx/transformations/cs_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,7 @@ def data_names(self) -> List[str]:

def get_data(
self, data_name, target_coordinate_system_name=None
) -> Union[np.ndarray, xr.DataArray]:
) -> Union[np.ndarray, SpatialData]:
"""Get the specified data, optionally transformed into any coordinate system.
Parameters
Expand Down

0 comments on commit f1cebd2

Please sign in to comment.