From 7368ee511ecfcd23e571a5341f67ae5fdf19089f Mon Sep 17 00:00:00 2001 From: vhirtham Date: Fri, 29 Oct 2021 11:34:47 +0200 Subject: [PATCH 01/21] Add set_parameters and optimize code --- weldx/core.py | 33 +++++++++++++-------------------- weldx/tests/test_core.py | 2 +- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/weldx/core.py b/weldx/core.py index c05a7158d..d134b5d80 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -49,18 +49,18 @@ def __init__( ) self._parameters = {} if parameters is not None: - if not isinstance(parameters, dict): - raise ValueError( - f'"parameters" must be dictionary, got {type(parameters)}' - ) - parameters = {k: Q_(v) for k, v in parameters.items()} - variable_names = self.get_variable_names() - for key in parameters: - if key not in variable_names: - raise ValueError( - f'The expression does not have a parameter "{key}"' - ) - self._parameters = parameters + self.set_parameters(parameters) + + def set_parameters(self, parameters): + if not isinstance(parameters, dict): + raise ValueError(f'"parameters" must be dictionary, got {type(parameters)}') + variable_names = [str(v) for v in self._expression.free_symbols] + for k, v in parameters.items(): + v = Q_(v) + if k not in variable_names: + raise ValueError(f'The expression does not have a parameter "{k}"') + + self._parameters[k] = v def __repr__(self): """Give __repr__ output.""" @@ -155,14 +155,7 @@ def set_parameter(self, name, value): Parameter value. This can be number, array or pint.Quantity """ - if not isinstance(name, str): - raise TypeError(f'Parameter "name" must be a string, got {type(name)}') - if name not in str(self._expression.free_symbols): - raise ValueError( - f'The expression "{self._expression}" does not have a ' - f'parameter with name "{name}".' - ) - self._parameters[name] = value + self.set_parameters({name: value}) @property def num_parameters(self): diff --git a/weldx/tests/test_core.py b/weldx/tests/test_core.py index 93f393146..b326ef4d5 100644 --- a/weldx/tests/test_core.py +++ b/weldx/tests/test_core.py @@ -110,7 +110,7 @@ def test_set_parameter(self): "name, value, exception_type, test_name", [ ("k", 1, ValueError, "# parameter not in expression"), - (33, 1, TypeError, "# wrong type as name #1"), + (33, 1, ValueError, "# wrong type as name #1"), ({"a": 1}, 1, TypeError, "# wrong type as name #2"), ], ids=get_test_name, From 4c339cbcf2386c948189344f0a7d7a98398cb9f7 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Fri, 29 Oct 2021 14:11:32 +0200 Subject: [PATCH 02/21] Start updating TimeSeries --- weldx/core.py | 37 ++-- weldx/tests/test_core.py | 412 ++++++++++++++++++++------------------- 2 files changed, 231 insertions(+), 218 deletions(-) diff --git a/weldx/core.py b/weldx/core.py index d134b5d80..63790a7ff 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -56,9 +56,10 @@ def set_parameters(self, parameters): raise ValueError(f'"parameters" must be dictionary, got {type(parameters)}') variable_names = [str(v) for v in self._expression.free_symbols] for k, v in parameters.items(): - v = Q_(v) if k not in variable_names: raise ValueError(f'The expression does not have a parameter "{k}"') + if not isinstance(v, xr.DataArray): + v = xr.DataArray(Q_(v)) self._parameters[k] = v @@ -239,7 +240,12 @@ def evaluate(self, **kwargs) -> Any: raise ValueError( f"The variables {intersection} are already defined as parameters." ) - inputs = {**kwargs, **self._parameters} + variables = {} + for k, v in kwargs.items(): + if not isinstance(v, xr.DataArray): + v = xr.DataArray(Q_(v)) + variables[k] = v + inputs = {**variables, **self._parameters} return self.function(**inputs) @@ -361,6 +367,8 @@ def _check_data_array(data_array: xr.DataArray): def _create_data_array( data: Union[pint.Quantity, xr.DataArray], time: Time ) -> xr.DataArray: + if isinstance(data, xr.DataArray): + return data return ( xr.DataArray(data=data) .rename({"dim_0": "time"}) @@ -395,6 +403,8 @@ def _initialize_discrete( time = Time(time) self._reference_time = time.reference_time + print(data) + print(time) self._data = self._create_data_array(data, time) self.interpolation = interpolation @@ -409,7 +419,7 @@ def _init_expression(self, data): # check that the expression can be evaluated with a time quantity time_var_name = data.get_variable_names()[0] try: - eval_data = data.evaluate(**{time_var_name: Q_(1, "second")}) + eval_data = data.evaluate(**{time_var_name: Q_(1, "second")}).data self._units = eval_data.units if np.iterable(eval_data): self._shape = eval_data.shape @@ -451,21 +461,21 @@ def _interp_time_discrete(self, time: Time) -> xr.DataArray: def _interp_time_expression(self, time: Time, time_unit: str) -> xr.DataArray: """Interpolate the time series if its data is a mathematical expression.""" - time_q = time.as_quantity(unit=time_unit) + time_q = xr.DataArray(time.as_quantity(unit=time_unit), dims=["time"]) - if len(self.shape) > 1 and np.iterable(time_q): - while len(time_q.shape) < len(self.shape): - time_q = time_q[:, np.newaxis] + # if len(self.shape) > 1 and np.iterable(time_q): + # while len(time_q.shape) < len(self.shape): + # time_q = time_q[:, np.newaxis] # evaluate expression data = self._data.evaluate(**{self._time_var_name: time_q}) - data = data.astype(float).to_reduced_units() # float conversion before reduce! + # data = data.astype(float).to_reduced_units() # float conversion before reduce! # create data array - if not np.iterable(data): # make sure quantity is not scalar value - data = np.expand_dims(data, 0) - - return self._create_data_array(data, time) + # if not np.iterable(data): # make sure quantity is not scalar value + # data = np.expand_dims(data, 0) + data = data.assign_coords({"time": time.as_timedelta_index()}) + return data # self._create_data_array(data, time) @property def data(self) -> Union[pint.Quantity, MathematicalExpression]: @@ -595,10 +605,11 @@ def interp_time( if isinstance(self._data, xr.DataArray): dax = self._interp_time_discrete(time_interp) + ts = TimeSeries(data=dax.data, time=time, interpolation=self.interpolation) else: dax = self._interp_time_expression(time_interp, time_unit) + ts = TimeSeries(data=dax, interpolation=self.interpolation) - ts = TimeSeries(data=dax.data, time=time, interpolation=self.interpolation) ts._interp_counter = self._interp_counter + 1 return ts diff --git a/weldx/tests/test_core.py b/weldx/tests/test_core.py index b326ef4d5..8b3a97cc8 100644 --- a/weldx/tests/test_core.py +++ b/weldx/tests/test_core.py @@ -213,23 +213,23 @@ class TestTimeSeries: DTI = pd.DatetimeIndex TDI = pd.TimedeltaIndex TS = TimeSeries - - time_discrete = pd.TimedeltaIndex([0, 1, 2, 3, 4], unit="s") - value_constant = Q_(1, "m") - values_discrete = Q_(np.array([10, 11, 12, 14, 16]), "mm") - me_expr_str = "a*t + b" - me_params = {"a": Q_(2, "m/s"), "b": Q_(-2, "m")} - - me_params_vec = {"a": Q_([[2, 0, 1]], "m/s"), "b": Q_([[-2, 3, 0]], "m")} - - ts_constant = TimeSeries(value_constant) - ts_disc_step = TimeSeries(values_discrete, time_discrete, "step") - ts_disc_linear = TimeSeries(values_discrete, time_discrete, "linear") - ts_expr = TimeSeries(ME(me_expr_str, me_params)) - ts_expr_vec = TimeSeries(ME(me_expr_str, me_params_vec)) - - # test_construction_discrete ------------------------------------------------------- - + # + # time_discrete = pd.TimedeltaIndex([0, 1, 2, 3, 4], unit="s") + # value_constant = Q_(1, "m") + # values_discrete = Q_(np.array([10, 11, 12, 14, 16]), "mm") + # me_expr_str = "a*t + b" + # me_params = {"a": Q_(2, "m/s"), "b": Q_(-2, "m")} + # + # me_params_vec = {"a": Q_([[2, 0, 1]], "m/s"), "b": Q_([[-2, 3, 0]], "m")} + # + # ts_constant = TimeSeries(value_constant) + # ts_disc_step = TimeSeries(values_discrete, time_discrete, "step") + # ts_disc_linear = TimeSeries(values_discrete, time_discrete, "linear") + # ts_expr = TimeSeries(ME(me_expr_str, me_params)) + # ts_expr_vec = TimeSeries(ME(me_expr_str, me_params_vec)) + # + # # test_construction_discrete ------------------------------------------------------- + # @staticmethod @pytest.mark.parametrize( "data, time, interpolation, shape_exp", @@ -292,192 +292,194 @@ def test_construction_expression(data, shape_exp, unit_exp): assert ts.data_array is None assert U_(unit_exp).is_compatible_with(ts.units) - # test_init_data_array ------------------------------------------------------------- - - @staticmethod - @pytest.mark.parametrize( - "data, dims, coords, exception_type", - [ - (Q_([1, 2, 3], "m"), "time", dict(time=TDI([1, 2, 3])), None), - (Q_([1, 2, 3], "m"), "a", dict(a=TDI([1, 2, 3])), KeyError), - (Q_([[1, 2]], "m"), ("a", "time"), dict(a=[2], time=TDI([1, 2])), None), - (Q_([1, 2, 3], "m"), "time", None, KeyError), - (Q_([1, 2, 3], "m"), "time", dict(time=[1, 2, 3]), TypeError), - ([1, 2, 3], "time", dict(time=TDI([1, 2, 3])), TypeError), - ], - ) - def test_init_data_array(data, dims, coords, exception_type): - """Test the `__init__` method with an xarray as data parameter.""" - da = xr.DataArray(data=data, dims=dims, coords=coords) - if exception_type is not None: - with pytest.raises(exception_type): - TimeSeries(da) - else: - ts = TimeSeries(da) - assert ts.data_array.dims[0] == "time" - - # test_construction_exceptions ----------------------------------------------------- - - values_def = Q_([5, 7, 3, 6, 8], "m") - time_def = Q_([0, 1, 2, 3, 4], "s") - me_too_many_vars = ME("a*t + b", {}) - me_param_units = ME("a*t + b", {"a": Q_(2, "1/s"), "b": Q_(-2, "m")}) - me_time_vec = ME("a*t + b", {"a": Q_([2, 3, 4], "1/s"), "b": Q_([-2, 3, 1], "")}) - @staticmethod - @pytest.mark.parametrize( - "data, time, interpolation, exception_type, test_name", - [ - (values_def, time_def, "int", ValueError, "# unknown interpolation"), - (values_def, time_def.magnitude, "step", TypeError, "# invalid time type"), - (me_too_many_vars, None, None, Exception, "# too many free variables"), - (me_param_units, None, None, Exception, "# incompatible parameter units"), - (me_time_vec, None, None, Exception, "# not compatible with time vectors"), - ("a string", None, None, TypeError, "# wrong data type"), - ], - ids=get_test_name, - ) - def test_construction_exceptions( - data, time, interpolation, exception_type, test_name - ): - """Test the exceptions of the 'set_parameter' method.""" - with pytest.raises(exception_type): - TimeSeries(data=data, time=time, interpolation=interpolation) - - # test_comparison ------------------------------------- - - time_wrong_values = TDI([0, 1, 2, 3, 5], unit="s") - values_discrete_wrong = Q_(np.array([10, 11, 12, 15, 16]), "mm") - values_unit_wrong = Q_(np.array([10, 11, 12, 14, 16]), "s") - values_unit_prefix_wrong = Q_(np.array([10, 11, 12, 14, 16]), "m") - params_wrong_values = {"a": Q_(2, "1/s"), "b": Q_(-1, "")} - params_wrong_unit = {"a": Q_(2, "g/s"), "b": Q_(-2, "g")} - params_wrong_unit_prefix = {"a": Q_(2, "m/ms"), "b": Q_(-2, "m")} - - @staticmethod - @pytest.mark.parametrize( - "ts, ts_other, result_exp", - [ - (ts_constant, TS(value_constant), True), - (ts_disc_step, TS(values_discrete, time_discrete, "step"), True), - (ts_expr, TS(ME(me_expr_str, me_params)), True), - (ts_constant, ts_disc_step, False), - (ts_constant, ts_expr, False), - (ts_disc_step, ts_expr, False), - (ts_constant, 1, False), - (ts_disc_step, 1, False), - (ts_expr, 1, False), - (ts_constant, "wrong", False), - (ts_disc_step, "wrong", False), - (ts_expr, "wrong", False), - (ts_constant, TS(Q_(1337, "m")), False), - (ts_constant, TS(Q_(1, "mm")), False), - (ts_constant, TS(Q_(1, "s")), False), - (ts_disc_step, TS(values_discrete, time_wrong_values, "step"), False), - (ts_disc_step, TS(values_discrete_wrong, time_discrete, "step"), False), - (ts_disc_step, TS(values_unit_prefix_wrong, time_discrete, "step"), False), - (ts_disc_step, TS(values_discrete, time_discrete, "linear"), False), - (ts_expr, TS(ME("a*t + 2*b", me_params)), False), - (ts_expr, TS(ME(me_expr_str, params_wrong_values)), False), - (ts_expr, TS(ME(me_expr_str, params_wrong_unit)), False), - (ts_expr, TS(ME(me_expr_str, params_wrong_unit_prefix)), False), - ], - ) - def test_comparison(ts, ts_other, result_exp): - """Test the TimeSeries comparison methods.""" - assert (ts == ts_other) is result_exp - assert (ts != ts_other) is not result_exp - - # test_interp_time ----------------------------------------------------------------- - - time_single = pd.TimedeltaIndex([2.1], "s") - time_single_q = Q_(2.1, "s") - time_mul = pd.TimedeltaIndex([-3, 0.7, 1.1, 1.9, 2.5, 3, 4, 7], "s") - time_mul_q = Q_([-3, 0.7, 1.1, 1.9, 2.5, 3, 4, 7], "s") - results_exp_vec = [ - [-8, 3, -3], - [-0.6, 3, 0.7], - [0.2, 3, 1.1], - [1.8, 3, 1.9], - [3, 3, 2.5], - [4, 3, 3], - [6, 3, 4], - [12, 3, 7], - ] - - @staticmethod - @pytest.mark.parametrize( - "ts, time, magnitude_exp, unit_exp", - [ - (ts_constant, time_single, 1, "m"), - (ts_constant, time_single_q, 1, "m"), - (ts_constant, time_mul, [1, 1, 1, 1, 1, 1, 1, 1], "m"), - ( - ts_constant, - time_mul + pd.Timestamp("2020"), - [1, 1, 1, 1, 1, 1, 1, 1], - "m", - ), - (ts_constant, time_mul_q, [1, 1, 1, 1, 1, 1, 1, 1], "m"), - (ts_disc_step, time_single, 12, "mm"), - (ts_disc_step, time_single_q, 12, "mm"), - (ts_disc_step, time_mul, [10, 10, 11, 11, 12, 14, 16, 16], "mm"), - (ts_disc_step, time_mul_q, [10, 10, 11, 11, 12, 14, 16, 16], "mm"), - (ts_disc_linear, time_single, 12.2, "mm"), - (ts_disc_linear, time_single_q, 12.2, "mm"), - (ts_disc_linear, time_mul, [10, 10.7, 11.1, 11.9, 13, 14, 16, 16], "mm"), - (ts_disc_linear, time_mul_q, [10, 10.7, 11.1, 11.9, 13, 14, 16, 16], "mm"), - (ts_expr, time_single, 2.2, "m"), - (ts_expr, time_single_q, 2.2, "m"), - (ts_expr, time_mul, [-8, -0.6, 0.2, 1.8, 3, 4, 6, 12], "m"), - (ts_expr, time_mul_q, [-8, -0.6, 0.2, 1.8, 3, 4, 6, 12], "m"), - (ts_expr_vec, time_single, [[2.2, 3, 2.1]], "m"), - (ts_expr_vec, time_single_q, [[2.2, 3, 2.1]], "m"), - (ts_expr_vec, time_mul, results_exp_vec, "m"), - ], - ) - def test_interp_time(ts, time, magnitude_exp, unit_exp): - """Test the interp_time function.""" - result = ts.interp_time(time) - - assert np.all(np.isclose(result.data.magnitude, magnitude_exp)) - assert result.units == U_(unit_exp) - - time = Time(time) - if len(time) == 1: - assert result.time is None - else: - assert np.all(Time(result.time, result._reference_time) == time) - - # test_interp_time_warning --------------------------------------------------------- - - @staticmethod - def test_interp_time_warning(): - """Test if a warning is emitted when interpolating already interpolated data.""" - ts = TimeSeries(data=Q_([1, 2, 3], "m"), time=Q_([0, 1, 2], "s")) - with pytest.warns(None) as recorded_warnings: - ts_interp = ts.interp_time(Q_([0.25, 0.5, 0.75, 1], "s")) - assert len(recorded_warnings) == 0 - - with pytest.warns(UserWarning): - ts_interp.interp_time(Q_([0.4, 0.6], "s")) - - # test_interp_time_exceptions ------------------------------------------------------ - - @staticmethod - @pytest.mark.parametrize("ts", [ts_constant, ts_disc_step, ts_disc_linear, ts_expr]) - @pytest.mark.parametrize( - "time, exception_type, test_name", - [ - # (DTI(["2010-10-10"]), ValueError, "# wrong type #1"), - ("a string", TypeError, "# wrong type #2"), - ([1, 2, 3], TypeError, "# wrong type #3"), - (1, TypeError, "# wrong type #4"), - (Q_(2, "s/m"), Exception, "# wrong type #5"), - ], - ids=get_test_name, - ) - def test_interp_time_exceptions(ts, time, exception_type, test_name): - """Test the exceptions of the 'set_parameter' method.""" - with pytest.raises(exception_type): - ts.interp_time(time) +# +# # test_init_data_array ------------------------------------------------------------- +# +# @staticmethod +# @pytest.mark.parametrize( +# "data, dims, coords, exception_type", +# [ +# (Q_([1, 2, 3], "m"), "time", dict(time=TDI([1, 2, 3])), None), +# (Q_([1, 2, 3], "m"), "a", dict(a=TDI([1, 2, 3])), KeyError), +# (Q_([[1, 2]], "m"), ("a", "time"), dict(a=[2], time=TDI([1, 2])), None), +# (Q_([1, 2, 3], "m"), "time", None, KeyError), +# (Q_([1, 2, 3], "m"), "time", dict(time=[1, 2, 3]), TypeError), +# ([1, 2, 3], "time", dict(time=TDI([1, 2, 3])), TypeError), +# ], +# ) +# def test_init_data_array(data, dims, coords, exception_type): +# """Test the `__init__` method with an xarray as data parameter.""" +# da = xr.DataArray(data=data, dims=dims, coords=coords) +# if exception_type is not None: +# with pytest.raises(exception_type): +# TimeSeries(da) +# else: +# ts = TimeSeries(da) +# assert ts.data_array.dims[0] == "time" +# +# # test_construction_exceptions ----------------------------------------------------- +# +# values_def = Q_([5, 7, 3, 6, 8], "m") +# time_def = Q_([0, 1, 2, 3, 4], "s") +# me_too_many_vars = ME("a*t + b", {}) +# me_param_units = ME("a*t + b", {"a": Q_(2, "1/s"), "b": Q_(-2, "m")}) +# me_time_vec = ME("a*t + b", {"a": Q_([2, 3, 4], "1/s"), "b": Q_([-2, 3, 1], "")}) +# +# @staticmethod +# @pytest.mark.parametrize( +# "data, time, interpolation, exception_type, test_name", +# [ +# (values_def, time_def, "int", ValueError, "# unknown interpolation"), +# (values_def, time_def.magnitude, "step", TypeError, "# invalid time type"), +# (me_too_many_vars, None, None, Exception, "# too many free variables"), +# (me_param_units, None, None, Exception, "# incompatible parameter units"), +# (me_time_vec, None, None, Exception, "# not compatible with time vectors"), +# ("a string", None, None, TypeError, "# wrong data type"), +# ], +# ids=get_test_name, +# ) +# def test_construction_exceptions( +# data, time, interpolation, exception_type, test_name +# ): +# """Test the exceptions of the 'set_parameter' method.""" +# with pytest.raises(exception_type): +# TimeSeries(data=data, time=time, interpolation=interpolation) +# +# # test_comparison ------------------------------------- +# +# time_wrong_values = TDI([0, 1, 2, 3, 5], unit="s") +# values_discrete_wrong = Q_(np.array([10, 11, 12, 15, 16]), "mm") +# values_unit_wrong = Q_(np.array([10, 11, 12, 14, 16]), "s") +# values_unit_prefix_wrong = Q_(np.array([10, 11, 12, 14, 16]), "m") +# params_wrong_values = {"a": Q_(2, "1/s"), "b": Q_(-1, "")} +# params_wrong_unit = {"a": Q_(2, "g/s"), "b": Q_(-2, "g")} +# params_wrong_unit_prefix = {"a": Q_(2, "m/ms"), "b": Q_(-2, "m")} +# +# @staticmethod +# @pytest.mark.parametrize( +# "ts, ts_other, result_exp", +# [ +# (ts_constant, TS(value_constant), True), +# (ts_disc_step, TS(values_discrete, time_discrete, "step"), True), +# (ts_expr, TS(ME(me_expr_str, me_params)), True), +# (ts_constant, ts_disc_step, False), +# (ts_constant, ts_expr, False), +# (ts_disc_step, ts_expr, False), +# (ts_constant, 1, False), +# (ts_disc_step, 1, False), +# (ts_expr, 1, False), +# (ts_constant, "wrong", False), +# (ts_disc_step, "wrong", False), +# (ts_expr, "wrong", False), +# (ts_constant, TS(Q_(1337, "m")), False), +# (ts_constant, TS(Q_(1, "mm")), False), +# (ts_constant, TS(Q_(1, "s")), False), +# (ts_disc_step, TS(values_discrete, time_wrong_values, "step"), False), +# (ts_disc_step, TS(values_discrete_wrong, time_discrete, "step"), False), +# (ts_disc_step, TS(values_unit_prefix_wrong, time_discrete, "step"), False), +# (ts_disc_step, TS(values_discrete, time_discrete, "linear"), False), +# (ts_expr, TS(ME("a*t + 2*b", me_params)), False), +# (ts_expr, TS(ME(me_expr_str, params_wrong_values)), False), +# (ts_expr, TS(ME(me_expr_str, params_wrong_unit)), False), +# (ts_expr, TS(ME(me_expr_str, params_wrong_unit_prefix)), False), +# ], +# ) +# def test_comparison(ts, ts_other, result_exp): +# """Test the TimeSeries comparison methods.""" +# assert (ts == ts_other) is result_exp +# assert (ts != ts_other) is not result_exp +# +# # test_interp_time ----------------------------------------------------------------- +# +# time_single = pd.TimedeltaIndex([2.1], "s") +# time_single_q = Q_(2.1, "s") +# time_mul = pd.TimedeltaIndex([-3, 0.7, 1.1, 1.9, 2.5, 3, 4, 7], "s") +# time_mul_q = Q_([-3, 0.7, 1.1, 1.9, 2.5, 3, 4, 7], "s") +# results_exp_vec = [ +# [-8, 3, -3], +# [-0.6, 3, 0.7], +# [0.2, 3, 1.1], +# [1.8, 3, 1.9], +# [3, 3, 2.5], +# [4, 3, 3], +# [6, 3, 4], +# [12, 3, 7], +# ] +# +# @staticmethod +# @pytest.mark.parametrize( +# "ts, time, magnitude_exp, unit_exp", +# [ +# (ts_constant, time_single, 1, "m"), +# (ts_constant, time_single_q, 1, "m"), +# (ts_constant, time_mul, [1, 1, 1, 1, 1, 1, 1, 1], "m"), +# ( +# ts_constant, +# time_mul + pd.Timestamp("2020"), +# [1, 1, 1, 1, 1, 1, 1, 1], +# "m", +# ), +# (ts_constant, time_mul_q, [1, 1, 1, 1, 1, 1, 1, 1], "m"), +# (ts_disc_step, time_single, 12, "mm"), +# (ts_disc_step, time_single_q, 12, "mm"), +# (ts_disc_step, time_mul, [10, 10, 11, 11, 12, 14, 16, 16], "mm"), +# (ts_disc_step, time_mul_q, [10, 10, 11, 11, 12, 14, 16, 16], "mm"), +# (ts_disc_linear, time_single, 12.2, "mm"), +# (ts_disc_linear, time_single_q, 12.2, "mm"), +# (ts_disc_linear, time_mul, [10, 10.7, 11.1, 11.9, 13, 14, 16, 16], "mm"), +# (ts_disc_linear, time_mul_q, [10, 10.7, 11.1, 11.9, 13, 14, 16, 16], "mm"), +# (ts_expr, time_single, 2.2, "m"), +# (ts_expr, time_single_q, 2.2, "m"), +# (ts_expr, time_mul, [-8, -0.6, 0.2, 1.8, 3, 4, 6, 12], "m"), +# (ts_expr, time_mul_q, [-8, -0.6, 0.2, 1.8, 3, 4, 6, 12], "m"), +# (ts_expr_vec, time_single, [[2.2, 3, 2.1]], "m"), +# (ts_expr_vec, time_single_q, [[2.2, 3, 2.1]], "m"), +# (ts_expr_vec, time_mul, results_exp_vec, "m"), +# ], +# ) +# def test_interp_time(ts, time, magnitude_exp, unit_exp): +# """Test the interp_time function.""" +# result = ts.interp_time(time) +# +# assert np.all(np.isclose(result.data.magnitude, magnitude_exp)) +# assert result.units == U_(unit_exp) +# +# time = Time(time) +# if len(time) == 1: +# assert result.time is None +# else: +# assert np.all(Time(result.time, result._reference_time) == time) +# +# # test_interp_time_warning --------------------------------------------------------- +# +# @staticmethod +# def test_interp_time_warning(): +# """Test if a warning is emitted when interpolating already interpolated data.""" +# ts = TimeSeries(data=Q_([1, 2, 3], "m"), time=Q_([0, 1, 2], "s")) +# with pytest.warns(None) as recorded_warnings: +# ts_interp = ts.interp_time(Q_([0.25, 0.5, 0.75, 1], "s")) +# assert len(recorded_warnings) == 0 +# +# with pytest.warns(UserWarning): +# ts_interp.interp_time(Q_([0.4, 0.6], "s")) +# +# # test_interp_time_exceptions ------------------------------------------------------ +# +# @staticmethod +# @pytest.mark.parametrize("ts", [ts_constant, ts_disc_step, ts_disc_linear, ts_expr]) +# @pytest.mark.parametrize( +# "time, exception_type, test_name", +# [ +# # (DTI(["2010-10-10"]), ValueError, "# wrong type #1"), +# ("a string", TypeError, "# wrong type #2"), +# ([1, 2, 3], TypeError, "# wrong type #3"), +# (1, TypeError, "# wrong type #4"), +# (Q_(2, "s/m"), Exception, "# wrong type #5"), +# ], +# ids=get_test_name, +# ) +# def test_interp_time_exceptions(ts, time, exception_type, test_name): +# """Test the exceptions of the 'set_parameter' method.""" +# with pytest.raises(exception_type): +# ts.interp_time(time) From 361fedfad6063190b5af3862076d63e4870b6b72 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Fri, 29 Oct 2021 14:14:43 +0200 Subject: [PATCH 03/21] Uncomment tests --- weldx/tests/test_core.py | 412 +++++++++++++++++++-------------------- 1 file changed, 205 insertions(+), 207 deletions(-) diff --git a/weldx/tests/test_core.py b/weldx/tests/test_core.py index 8b3a97cc8..b326ef4d5 100644 --- a/weldx/tests/test_core.py +++ b/weldx/tests/test_core.py @@ -213,23 +213,23 @@ class TestTimeSeries: DTI = pd.DatetimeIndex TDI = pd.TimedeltaIndex TS = TimeSeries - # - # time_discrete = pd.TimedeltaIndex([0, 1, 2, 3, 4], unit="s") - # value_constant = Q_(1, "m") - # values_discrete = Q_(np.array([10, 11, 12, 14, 16]), "mm") - # me_expr_str = "a*t + b" - # me_params = {"a": Q_(2, "m/s"), "b": Q_(-2, "m")} - # - # me_params_vec = {"a": Q_([[2, 0, 1]], "m/s"), "b": Q_([[-2, 3, 0]], "m")} - # - # ts_constant = TimeSeries(value_constant) - # ts_disc_step = TimeSeries(values_discrete, time_discrete, "step") - # ts_disc_linear = TimeSeries(values_discrete, time_discrete, "linear") - # ts_expr = TimeSeries(ME(me_expr_str, me_params)) - # ts_expr_vec = TimeSeries(ME(me_expr_str, me_params_vec)) - # - # # test_construction_discrete ------------------------------------------------------- - # + + time_discrete = pd.TimedeltaIndex([0, 1, 2, 3, 4], unit="s") + value_constant = Q_(1, "m") + values_discrete = Q_(np.array([10, 11, 12, 14, 16]), "mm") + me_expr_str = "a*t + b" + me_params = {"a": Q_(2, "m/s"), "b": Q_(-2, "m")} + + me_params_vec = {"a": Q_([[2, 0, 1]], "m/s"), "b": Q_([[-2, 3, 0]], "m")} + + ts_constant = TimeSeries(value_constant) + ts_disc_step = TimeSeries(values_discrete, time_discrete, "step") + ts_disc_linear = TimeSeries(values_discrete, time_discrete, "linear") + ts_expr = TimeSeries(ME(me_expr_str, me_params)) + ts_expr_vec = TimeSeries(ME(me_expr_str, me_params_vec)) + + # test_construction_discrete ------------------------------------------------------- + @staticmethod @pytest.mark.parametrize( "data, time, interpolation, shape_exp", @@ -292,194 +292,192 @@ def test_construction_expression(data, shape_exp, unit_exp): assert ts.data_array is None assert U_(unit_exp).is_compatible_with(ts.units) + # test_init_data_array ------------------------------------------------------------- + + @staticmethod + @pytest.mark.parametrize( + "data, dims, coords, exception_type", + [ + (Q_([1, 2, 3], "m"), "time", dict(time=TDI([1, 2, 3])), None), + (Q_([1, 2, 3], "m"), "a", dict(a=TDI([1, 2, 3])), KeyError), + (Q_([[1, 2]], "m"), ("a", "time"), dict(a=[2], time=TDI([1, 2])), None), + (Q_([1, 2, 3], "m"), "time", None, KeyError), + (Q_([1, 2, 3], "m"), "time", dict(time=[1, 2, 3]), TypeError), + ([1, 2, 3], "time", dict(time=TDI([1, 2, 3])), TypeError), + ], + ) + def test_init_data_array(data, dims, coords, exception_type): + """Test the `__init__` method with an xarray as data parameter.""" + da = xr.DataArray(data=data, dims=dims, coords=coords) + if exception_type is not None: + with pytest.raises(exception_type): + TimeSeries(da) + else: + ts = TimeSeries(da) + assert ts.data_array.dims[0] == "time" + + # test_construction_exceptions ----------------------------------------------------- + + values_def = Q_([5, 7, 3, 6, 8], "m") + time_def = Q_([0, 1, 2, 3, 4], "s") + me_too_many_vars = ME("a*t + b", {}) + me_param_units = ME("a*t + b", {"a": Q_(2, "1/s"), "b": Q_(-2, "m")}) + me_time_vec = ME("a*t + b", {"a": Q_([2, 3, 4], "1/s"), "b": Q_([-2, 3, 1], "")}) -# -# # test_init_data_array ------------------------------------------------------------- -# -# @staticmethod -# @pytest.mark.parametrize( -# "data, dims, coords, exception_type", -# [ -# (Q_([1, 2, 3], "m"), "time", dict(time=TDI([1, 2, 3])), None), -# (Q_([1, 2, 3], "m"), "a", dict(a=TDI([1, 2, 3])), KeyError), -# (Q_([[1, 2]], "m"), ("a", "time"), dict(a=[2], time=TDI([1, 2])), None), -# (Q_([1, 2, 3], "m"), "time", None, KeyError), -# (Q_([1, 2, 3], "m"), "time", dict(time=[1, 2, 3]), TypeError), -# ([1, 2, 3], "time", dict(time=TDI([1, 2, 3])), TypeError), -# ], -# ) -# def test_init_data_array(data, dims, coords, exception_type): -# """Test the `__init__` method with an xarray as data parameter.""" -# da = xr.DataArray(data=data, dims=dims, coords=coords) -# if exception_type is not None: -# with pytest.raises(exception_type): -# TimeSeries(da) -# else: -# ts = TimeSeries(da) -# assert ts.data_array.dims[0] == "time" -# -# # test_construction_exceptions ----------------------------------------------------- -# -# values_def = Q_([5, 7, 3, 6, 8], "m") -# time_def = Q_([0, 1, 2, 3, 4], "s") -# me_too_many_vars = ME("a*t + b", {}) -# me_param_units = ME("a*t + b", {"a": Q_(2, "1/s"), "b": Q_(-2, "m")}) -# me_time_vec = ME("a*t + b", {"a": Q_([2, 3, 4], "1/s"), "b": Q_([-2, 3, 1], "")}) -# -# @staticmethod -# @pytest.mark.parametrize( -# "data, time, interpolation, exception_type, test_name", -# [ -# (values_def, time_def, "int", ValueError, "# unknown interpolation"), -# (values_def, time_def.magnitude, "step", TypeError, "# invalid time type"), -# (me_too_many_vars, None, None, Exception, "# too many free variables"), -# (me_param_units, None, None, Exception, "# incompatible parameter units"), -# (me_time_vec, None, None, Exception, "# not compatible with time vectors"), -# ("a string", None, None, TypeError, "# wrong data type"), -# ], -# ids=get_test_name, -# ) -# def test_construction_exceptions( -# data, time, interpolation, exception_type, test_name -# ): -# """Test the exceptions of the 'set_parameter' method.""" -# with pytest.raises(exception_type): -# TimeSeries(data=data, time=time, interpolation=interpolation) -# -# # test_comparison ------------------------------------- -# -# time_wrong_values = TDI([0, 1, 2, 3, 5], unit="s") -# values_discrete_wrong = Q_(np.array([10, 11, 12, 15, 16]), "mm") -# values_unit_wrong = Q_(np.array([10, 11, 12, 14, 16]), "s") -# values_unit_prefix_wrong = Q_(np.array([10, 11, 12, 14, 16]), "m") -# params_wrong_values = {"a": Q_(2, "1/s"), "b": Q_(-1, "")} -# params_wrong_unit = {"a": Q_(2, "g/s"), "b": Q_(-2, "g")} -# params_wrong_unit_prefix = {"a": Q_(2, "m/ms"), "b": Q_(-2, "m")} -# -# @staticmethod -# @pytest.mark.parametrize( -# "ts, ts_other, result_exp", -# [ -# (ts_constant, TS(value_constant), True), -# (ts_disc_step, TS(values_discrete, time_discrete, "step"), True), -# (ts_expr, TS(ME(me_expr_str, me_params)), True), -# (ts_constant, ts_disc_step, False), -# (ts_constant, ts_expr, False), -# (ts_disc_step, ts_expr, False), -# (ts_constant, 1, False), -# (ts_disc_step, 1, False), -# (ts_expr, 1, False), -# (ts_constant, "wrong", False), -# (ts_disc_step, "wrong", False), -# (ts_expr, "wrong", False), -# (ts_constant, TS(Q_(1337, "m")), False), -# (ts_constant, TS(Q_(1, "mm")), False), -# (ts_constant, TS(Q_(1, "s")), False), -# (ts_disc_step, TS(values_discrete, time_wrong_values, "step"), False), -# (ts_disc_step, TS(values_discrete_wrong, time_discrete, "step"), False), -# (ts_disc_step, TS(values_unit_prefix_wrong, time_discrete, "step"), False), -# (ts_disc_step, TS(values_discrete, time_discrete, "linear"), False), -# (ts_expr, TS(ME("a*t + 2*b", me_params)), False), -# (ts_expr, TS(ME(me_expr_str, params_wrong_values)), False), -# (ts_expr, TS(ME(me_expr_str, params_wrong_unit)), False), -# (ts_expr, TS(ME(me_expr_str, params_wrong_unit_prefix)), False), -# ], -# ) -# def test_comparison(ts, ts_other, result_exp): -# """Test the TimeSeries comparison methods.""" -# assert (ts == ts_other) is result_exp -# assert (ts != ts_other) is not result_exp -# -# # test_interp_time ----------------------------------------------------------------- -# -# time_single = pd.TimedeltaIndex([2.1], "s") -# time_single_q = Q_(2.1, "s") -# time_mul = pd.TimedeltaIndex([-3, 0.7, 1.1, 1.9, 2.5, 3, 4, 7], "s") -# time_mul_q = Q_([-3, 0.7, 1.1, 1.9, 2.5, 3, 4, 7], "s") -# results_exp_vec = [ -# [-8, 3, -3], -# [-0.6, 3, 0.7], -# [0.2, 3, 1.1], -# [1.8, 3, 1.9], -# [3, 3, 2.5], -# [4, 3, 3], -# [6, 3, 4], -# [12, 3, 7], -# ] -# -# @staticmethod -# @pytest.mark.parametrize( -# "ts, time, magnitude_exp, unit_exp", -# [ -# (ts_constant, time_single, 1, "m"), -# (ts_constant, time_single_q, 1, "m"), -# (ts_constant, time_mul, [1, 1, 1, 1, 1, 1, 1, 1], "m"), -# ( -# ts_constant, -# time_mul + pd.Timestamp("2020"), -# [1, 1, 1, 1, 1, 1, 1, 1], -# "m", -# ), -# (ts_constant, time_mul_q, [1, 1, 1, 1, 1, 1, 1, 1], "m"), -# (ts_disc_step, time_single, 12, "mm"), -# (ts_disc_step, time_single_q, 12, "mm"), -# (ts_disc_step, time_mul, [10, 10, 11, 11, 12, 14, 16, 16], "mm"), -# (ts_disc_step, time_mul_q, [10, 10, 11, 11, 12, 14, 16, 16], "mm"), -# (ts_disc_linear, time_single, 12.2, "mm"), -# (ts_disc_linear, time_single_q, 12.2, "mm"), -# (ts_disc_linear, time_mul, [10, 10.7, 11.1, 11.9, 13, 14, 16, 16], "mm"), -# (ts_disc_linear, time_mul_q, [10, 10.7, 11.1, 11.9, 13, 14, 16, 16], "mm"), -# (ts_expr, time_single, 2.2, "m"), -# (ts_expr, time_single_q, 2.2, "m"), -# (ts_expr, time_mul, [-8, -0.6, 0.2, 1.8, 3, 4, 6, 12], "m"), -# (ts_expr, time_mul_q, [-8, -0.6, 0.2, 1.8, 3, 4, 6, 12], "m"), -# (ts_expr_vec, time_single, [[2.2, 3, 2.1]], "m"), -# (ts_expr_vec, time_single_q, [[2.2, 3, 2.1]], "m"), -# (ts_expr_vec, time_mul, results_exp_vec, "m"), -# ], -# ) -# def test_interp_time(ts, time, magnitude_exp, unit_exp): -# """Test the interp_time function.""" -# result = ts.interp_time(time) -# -# assert np.all(np.isclose(result.data.magnitude, magnitude_exp)) -# assert result.units == U_(unit_exp) -# -# time = Time(time) -# if len(time) == 1: -# assert result.time is None -# else: -# assert np.all(Time(result.time, result._reference_time) == time) -# -# # test_interp_time_warning --------------------------------------------------------- -# -# @staticmethod -# def test_interp_time_warning(): -# """Test if a warning is emitted when interpolating already interpolated data.""" -# ts = TimeSeries(data=Q_([1, 2, 3], "m"), time=Q_([0, 1, 2], "s")) -# with pytest.warns(None) as recorded_warnings: -# ts_interp = ts.interp_time(Q_([0.25, 0.5, 0.75, 1], "s")) -# assert len(recorded_warnings) == 0 -# -# with pytest.warns(UserWarning): -# ts_interp.interp_time(Q_([0.4, 0.6], "s")) -# -# # test_interp_time_exceptions ------------------------------------------------------ -# -# @staticmethod -# @pytest.mark.parametrize("ts", [ts_constant, ts_disc_step, ts_disc_linear, ts_expr]) -# @pytest.mark.parametrize( -# "time, exception_type, test_name", -# [ -# # (DTI(["2010-10-10"]), ValueError, "# wrong type #1"), -# ("a string", TypeError, "# wrong type #2"), -# ([1, 2, 3], TypeError, "# wrong type #3"), -# (1, TypeError, "# wrong type #4"), -# (Q_(2, "s/m"), Exception, "# wrong type #5"), -# ], -# ids=get_test_name, -# ) -# def test_interp_time_exceptions(ts, time, exception_type, test_name): -# """Test the exceptions of the 'set_parameter' method.""" -# with pytest.raises(exception_type): -# ts.interp_time(time) + @staticmethod + @pytest.mark.parametrize( + "data, time, interpolation, exception_type, test_name", + [ + (values_def, time_def, "int", ValueError, "# unknown interpolation"), + (values_def, time_def.magnitude, "step", TypeError, "# invalid time type"), + (me_too_many_vars, None, None, Exception, "# too many free variables"), + (me_param_units, None, None, Exception, "# incompatible parameter units"), + (me_time_vec, None, None, Exception, "# not compatible with time vectors"), + ("a string", None, None, TypeError, "# wrong data type"), + ], + ids=get_test_name, + ) + def test_construction_exceptions( + data, time, interpolation, exception_type, test_name + ): + """Test the exceptions of the 'set_parameter' method.""" + with pytest.raises(exception_type): + TimeSeries(data=data, time=time, interpolation=interpolation) + + # test_comparison ------------------------------------- + + time_wrong_values = TDI([0, 1, 2, 3, 5], unit="s") + values_discrete_wrong = Q_(np.array([10, 11, 12, 15, 16]), "mm") + values_unit_wrong = Q_(np.array([10, 11, 12, 14, 16]), "s") + values_unit_prefix_wrong = Q_(np.array([10, 11, 12, 14, 16]), "m") + params_wrong_values = {"a": Q_(2, "1/s"), "b": Q_(-1, "")} + params_wrong_unit = {"a": Q_(2, "g/s"), "b": Q_(-2, "g")} + params_wrong_unit_prefix = {"a": Q_(2, "m/ms"), "b": Q_(-2, "m")} + + @staticmethod + @pytest.mark.parametrize( + "ts, ts_other, result_exp", + [ + (ts_constant, TS(value_constant), True), + (ts_disc_step, TS(values_discrete, time_discrete, "step"), True), + (ts_expr, TS(ME(me_expr_str, me_params)), True), + (ts_constant, ts_disc_step, False), + (ts_constant, ts_expr, False), + (ts_disc_step, ts_expr, False), + (ts_constant, 1, False), + (ts_disc_step, 1, False), + (ts_expr, 1, False), + (ts_constant, "wrong", False), + (ts_disc_step, "wrong", False), + (ts_expr, "wrong", False), + (ts_constant, TS(Q_(1337, "m")), False), + (ts_constant, TS(Q_(1, "mm")), False), + (ts_constant, TS(Q_(1, "s")), False), + (ts_disc_step, TS(values_discrete, time_wrong_values, "step"), False), + (ts_disc_step, TS(values_discrete_wrong, time_discrete, "step"), False), + (ts_disc_step, TS(values_unit_prefix_wrong, time_discrete, "step"), False), + (ts_disc_step, TS(values_discrete, time_discrete, "linear"), False), + (ts_expr, TS(ME("a*t + 2*b", me_params)), False), + (ts_expr, TS(ME(me_expr_str, params_wrong_values)), False), + (ts_expr, TS(ME(me_expr_str, params_wrong_unit)), False), + (ts_expr, TS(ME(me_expr_str, params_wrong_unit_prefix)), False), + ], + ) + def test_comparison(ts, ts_other, result_exp): + """Test the TimeSeries comparison methods.""" + assert (ts == ts_other) is result_exp + assert (ts != ts_other) is not result_exp + + # test_interp_time ----------------------------------------------------------------- + + time_single = pd.TimedeltaIndex([2.1], "s") + time_single_q = Q_(2.1, "s") + time_mul = pd.TimedeltaIndex([-3, 0.7, 1.1, 1.9, 2.5, 3, 4, 7], "s") + time_mul_q = Q_([-3, 0.7, 1.1, 1.9, 2.5, 3, 4, 7], "s") + results_exp_vec = [ + [-8, 3, -3], + [-0.6, 3, 0.7], + [0.2, 3, 1.1], + [1.8, 3, 1.9], + [3, 3, 2.5], + [4, 3, 3], + [6, 3, 4], + [12, 3, 7], + ] + + @staticmethod + @pytest.mark.parametrize( + "ts, time, magnitude_exp, unit_exp", + [ + (ts_constant, time_single, 1, "m"), + (ts_constant, time_single_q, 1, "m"), + (ts_constant, time_mul, [1, 1, 1, 1, 1, 1, 1, 1], "m"), + ( + ts_constant, + time_mul + pd.Timestamp("2020"), + [1, 1, 1, 1, 1, 1, 1, 1], + "m", + ), + (ts_constant, time_mul_q, [1, 1, 1, 1, 1, 1, 1, 1], "m"), + (ts_disc_step, time_single, 12, "mm"), + (ts_disc_step, time_single_q, 12, "mm"), + (ts_disc_step, time_mul, [10, 10, 11, 11, 12, 14, 16, 16], "mm"), + (ts_disc_step, time_mul_q, [10, 10, 11, 11, 12, 14, 16, 16], "mm"), + (ts_disc_linear, time_single, 12.2, "mm"), + (ts_disc_linear, time_single_q, 12.2, "mm"), + (ts_disc_linear, time_mul, [10, 10.7, 11.1, 11.9, 13, 14, 16, 16], "mm"), + (ts_disc_linear, time_mul_q, [10, 10.7, 11.1, 11.9, 13, 14, 16, 16], "mm"), + (ts_expr, time_single, 2.2, "m"), + (ts_expr, time_single_q, 2.2, "m"), + (ts_expr, time_mul, [-8, -0.6, 0.2, 1.8, 3, 4, 6, 12], "m"), + (ts_expr, time_mul_q, [-8, -0.6, 0.2, 1.8, 3, 4, 6, 12], "m"), + (ts_expr_vec, time_single, [[2.2, 3, 2.1]], "m"), + (ts_expr_vec, time_single_q, [[2.2, 3, 2.1]], "m"), + (ts_expr_vec, time_mul, results_exp_vec, "m"), + ], + ) + def test_interp_time(ts, time, magnitude_exp, unit_exp): + """Test the interp_time function.""" + result = ts.interp_time(time) + + assert np.all(np.isclose(result.data.magnitude, magnitude_exp)) + assert result.units == U_(unit_exp) + + time = Time(time) + if len(time) == 1: + assert result.time is None + else: + assert np.all(Time(result.time, result._reference_time) == time) + + # test_interp_time_warning --------------------------------------------------------- + + @staticmethod + def test_interp_time_warning(): + """Test if a warning is emitted when interpolating already interpolated data.""" + ts = TimeSeries(data=Q_([1, 2, 3], "m"), time=Q_([0, 1, 2], "s")) + with pytest.warns(None) as recorded_warnings: + ts_interp = ts.interp_time(Q_([0.25, 0.5, 0.75, 1], "s")) + assert len(recorded_warnings) == 0 + + with pytest.warns(UserWarning): + ts_interp.interp_time(Q_([0.4, 0.6], "s")) + + # test_interp_time_exceptions ------------------------------------------------------ + + @staticmethod + @pytest.mark.parametrize("ts", [ts_constant, ts_disc_step, ts_disc_linear, ts_expr]) + @pytest.mark.parametrize( + "time, exception_type, test_name", + [ + # (DTI(["2010-10-10"]), ValueError, "# wrong type #1"), + ("a string", TypeError, "# wrong type #2"), + ([1, 2, 3], TypeError, "# wrong type #3"), + (1, TypeError, "# wrong type #4"), + (Q_(2, "s/m"), Exception, "# wrong type #5"), + ], + ids=get_test_name, + ) + def test_interp_time_exceptions(ts, time, exception_type, test_name): + """Test the exceptions of the 'set_parameter' method.""" + with pytest.raises(exception_type): + ts.interp_time(time) From ac63523cc8afcb51c860affbdb8d3c6cec24185b Mon Sep 17 00:00:00 2001 From: vhirtham Date: Mon, 1 Nov 2021 10:23:03 +0100 Subject: [PATCH 04/21] Fix some tests --- weldx/core.py | 29 +++++++++++++++-------------- weldx/measurement.py | 2 +- weldx/tests/test_core.py | 4 +--- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/weldx/core.py b/weldx/core.py index 63790a7ff..6c0f36dcf 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -59,7 +59,7 @@ def set_parameters(self, parameters): if k not in variable_names: raise ValueError(f'The expression does not have a parameter "{k}"') if not isinstance(v, xr.DataArray): - v = xr.DataArray(Q_(v)) + v = Q_(v) self._parameters[k] = v @@ -245,7 +245,14 @@ def evaluate(self, **kwargs) -> Any: if not isinstance(v, xr.DataArray): v = xr.DataArray(Q_(v)) variables[k] = v - inputs = {**variables, **self._parameters} + + parameters = {} + for k, v in self._parameters.items(): + if not isinstance(v, xr.DataArray): + v = xr.DataArray(v) + parameters[k] = v + + inputs = {**variables, **parameters} return self.function(**inputs) @@ -461,21 +468,15 @@ def _interp_time_discrete(self, time: Time) -> xr.DataArray: def _interp_time_expression(self, time: Time, time_unit: str) -> xr.DataArray: """Interpolate the time series if its data is a mathematical expression.""" - time_q = xr.DataArray(time.as_quantity(unit=time_unit), dims=["time"]) + time_q = time.as_quantity(unit=time_unit) + if len(time_q.shape) == 0: + time_q = np.expand_dims(time_q, 0) - # if len(self.shape) > 1 and np.iterable(time_q): - # while len(time_q.shape) < len(self.shape): - # time_q = time_q[:, np.newaxis] + time_xr = xr.DataArray(time_q, dims=["time"]) # evaluate expression - data = self._data.evaluate(**{self._time_var_name: time_q}) - # data = data.astype(float).to_reduced_units() # float conversion before reduce! - - # create data array - # if not np.iterable(data): # make sure quantity is not scalar value - # data = np.expand_dims(data, 0) - data = data.assign_coords({"time": time.as_timedelta_index()}) - return data # self._create_data_array(data, time) + data = self._data.evaluate(**{self._time_var_name: time_xr}) + return data.assign_coords({"time": time.as_timedelta_index()}) @property def data(self) -> Union[pint.Quantity, MathematicalExpression]: diff --git a/weldx/measurement.py b/weldx/measurement.py index 7d8c3058e..0b5092689 100644 --- a/weldx/measurement.py +++ b/weldx/measurement.py @@ -546,7 +546,7 @@ def _determine_output_signal_unit( "The provided function is incompatible with the input signals unit." f" \nThe test raised the following exception:\n{e}" ) - return test_output.units + return test_output.data.units return input_unit diff --git a/weldx/tests/test_core.py b/weldx/tests/test_core.py index b326ef4d5..1d5584225 100644 --- a/weldx/tests/test_core.py +++ b/weldx/tests/test_core.py @@ -220,7 +220,7 @@ class TestTimeSeries: me_expr_str = "a*t + b" me_params = {"a": Q_(2, "m/s"), "b": Q_(-2, "m")} - me_params_vec = {"a": Q_([[2, 0, 1]], "m/s"), "b": Q_([[-2, 3, 0]], "m")} + me_params_vec = {"a": Q_([2, 0, 1], "m/s"), "b": Q_([-2, 3, 0], "m")} ts_constant = TimeSeries(value_constant) ts_disc_step = TimeSeries(values_discrete, time_discrete, "step") @@ -322,7 +322,6 @@ def test_init_data_array(data, dims, coords, exception_type): time_def = Q_([0, 1, 2, 3, 4], "s") me_too_many_vars = ME("a*t + b", {}) me_param_units = ME("a*t + b", {"a": Q_(2, "1/s"), "b": Q_(-2, "m")}) - me_time_vec = ME("a*t + b", {"a": Q_([2, 3, 4], "1/s"), "b": Q_([-2, 3, 1], "")}) @staticmethod @pytest.mark.parametrize( @@ -332,7 +331,6 @@ def test_init_data_array(data, dims, coords, exception_type): (values_def, time_def.magnitude, "step", TypeError, "# invalid time type"), (me_too_many_vars, None, None, Exception, "# too many free variables"), (me_param_units, None, None, Exception, "# incompatible parameter units"), - (me_time_vec, None, None, Exception, "# not compatible with time vectors"), ("a string", None, None, TypeError, "# wrong data type"), ], ids=get_test_name, From 0f003eb38fd9ae01aa3aa8338f1e02978e0e06e6 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Mon, 1 Nov 2021 11:22:50 +0100 Subject: [PATCH 05/21] Fix tests --- weldx/core.py | 2 -- weldx/tests/transformations/test_cs_manager.py | 4 ++-- weldx/tests/transformations/test_local_cs.py | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/weldx/core.py b/weldx/core.py index 6c0f36dcf..d2d186a6a 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -410,8 +410,6 @@ def _initialize_discrete( time = Time(time) self._reference_time = time.reference_time - print(data) - print(time) self._data = self._create_data_array(data, time) self.interpolation = interpolation diff --git a/weldx/tests/transformations/test_cs_manager.py b/weldx/tests/transformations/test_cs_manager.py index 40dce1285..e6af3c693 100644 --- a/weldx/tests/transformations/test_cs_manager.py +++ b/weldx/tests/transformations/test_cs_manager.py @@ -1438,7 +1438,7 @@ def test_get_local_coordinate_system_timeseries( The expected rotation angles around the z-axis """ - me = MathematicalExpression("a*t", {"a": Q_([[0, 1, 0]], "mm/s")}) + me = MathematicalExpression("a*t", {"a": Q_([0, 1, 0], "mm/s")}) ts = TimeSeries(me) rotation = WXRotation.from_euler("z", [0, 90], degrees=True).as_matrix() translation = [[1, 0, 0], [2, 0, 0]] @@ -1535,7 +1535,7 @@ def test_get_cs_exception_timeseries(lcs, in_lcs, exp_exception): Set to `True` if the transformation should raise """ - me = MathematicalExpression("a*t", {"a": Q_([[0, 1, 0]], "mm/s")}) + me = MathematicalExpression("a*t", {"a": Q_([0, 1, 0], "mm/s")}) ts = TimeSeries(me) translation = [[1, 0, 0], [2, 0, 0]] diff --git a/weldx/tests/transformations/test_local_cs.py b/weldx/tests/transformations/test_local_cs.py index 3dd43eb02..60026b5da 100644 --- a/weldx/tests/transformations/test_local_cs.py +++ b/weldx/tests/transformations/test_local_cs.py @@ -175,7 +175,7 @@ def test_init_expr_time_series_as_coord(time, time_ref, angles): """ coordinates = MathematicalExpression( - expression="a*t+b", parameters=dict(a=Q_([[1, 0, 0]], "1/s"), b=[1, 2, 3]) + expression="a*t+b", parameters=dict(a=Q_([1, 0, 0], "1/s"), b=[1, 2, 3]) ) ts_coord = TimeSeries(data=coordinates) @@ -607,7 +607,7 @@ def test_interp_time_timeseries_as_coords( # create expression expr = "a*t+b" - param = dict(a=Q_([[1, 0, 0]], "mm/s"), b=Q_([1, 1, 1], "mm")) + param = dict(a=Q_([1, 0, 0], "mm/s"), b=Q_([1, 1, 1], "mm")) me = MathematicalExpression(expression=expr, parameters=param) # create orientation and time of LCS From a6876dce7430ab82fe90bbb9ee8646124ed10703 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Mon, 1 Nov 2021 11:32:12 +0100 Subject: [PATCH 06/21] Fix pre-commit --- weldx/core.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/weldx/core.py b/weldx/core.py index d2d186a6a..54c492047 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -51,16 +51,23 @@ def __init__( if parameters is not None: self.set_parameters(parameters) - def set_parameters(self, parameters): - if not isinstance(parameters, dict): - raise ValueError(f'"parameters" must be dictionary, got {type(parameters)}') + def set_parameters(self, params: Dict[str, Union[pint.Quantity, xr.DataArray]]): + """Set the expressions parameters. + + Parameters + ---------- + paras: + Dictionary that contains the values for the specified parameters. + + """ + if not isinstance(params, dict): + raise ValueError(f'"parameters" must be dictionary, got {type(params)}') variable_names = [str(v) for v in self._expression.free_symbols] - for k, v in parameters.items(): + for k, v in params.items(): if k not in variable_names: raise ValueError(f'The expression does not have a parameter "{k}"') if not isinstance(v, xr.DataArray): v = Q_(v) - self._parameters[k] = v def __repr__(self): From a1ca3d297ca161b83fe92ee2db1f857c25be7b81 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Mon, 1 Nov 2021 13:48:31 +0100 Subject: [PATCH 07/21] Fix notebooks --- tutorials/experiment_design_01.ipynb | 12 ++++++------ tutorials/timeseries_01.ipynb | 6 +++--- tutorials/welding_example_02_weaving.ipynb | 8 ++++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tutorials/experiment_design_01.ipynb b/tutorials/experiment_design_01.ipynb index 274208498..7b10ef291 100644 --- a/tutorials/experiment_design_01.ipynb +++ b/tutorials/experiment_design_01.ipynb @@ -234,11 +234,11 @@ "metadata": {}, "outputs": [], "source": [ - "sine_y = sine(f=Q_(1, \"Hz\"), amp=Q_([[0, 1, 0]], \"mm\"))\n", - "csm.add_cs(\n", + "sine_y = sine(f=Q_(1, \"Hz\"), amp=Q_([0, 1, 0], \"mm\"))\n", + "csm.create_cs(\n", " coordinate_system_name=\"tcp_sine_y\",\n", " reference_system_name=\"tcp_wire\",\n", - " lcs=LCS(coordinates=sine_y),\n", + " coordinates=sine_y,\n", ")" ] }, @@ -255,11 +255,11 @@ "metadata": {}, "outputs": [], "source": [ - "sine_z = sine(f=Q_(1, \"Hz\"), amp=Q_([[0, 0, 2]], \"mm\"), bias=Q_([0, 0, 0], \"mm\"))\n", - "csm.add_cs(\n", + "sine_z = sine(f=Q_(1, \"Hz\"), amp=Q_([0, 0, 2], \"mm\"), bias=Q_([0, 0, 0], \"mm\"))\n", + "csm.create_cs(\n", " coordinate_system_name=\"tcp_sine_z\",\n", " reference_system_name=\"tcp_wire\",\n", - " lcs=LCS(coordinates=sine_z),\n", + " coordinates=sine_z,\n", ")" ] }, diff --git a/tutorials/timeseries_01.ipynb b/tutorials/timeseries_01.ipynb index 1556e605b..fbe52eb88 100644 --- a/tutorials/timeseries_01.ipynb +++ b/tutorials/timeseries_01.ipynb @@ -338,8 +338,8 @@ "source": [ "expr_string = \"a*sin(o*t)+b*t\"\n", "parameters = {\n", - " \"a\": Q_(np.asarray([[1, 0, 0]]), \"m\"),\n", - " \"b\": Q_([[0, 1, 0]], \"m/s\"),\n", + " \"a\": Q_(np.asarray([1, 0, 0]), \"m\"),\n", + " \"b\": Q_([0, 1, 0], \"m/s\"),\n", " \"o\": Q_(\"36 deg/s\"),\n", "}\n", "expr = MathematicalExpression(expression=expr_string, parameters=parameters)\n", @@ -383,7 +383,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.8" + "version": "3.8.11" } }, "nbformat": 4, diff --git a/tutorials/welding_example_02_weaving.ipynb b/tutorials/welding_example_02_weaving.ipynb index d7b0b4626..224d08e48 100644 --- a/tutorials/welding_example_02_weaving.ipynb +++ b/tutorials/welding_example_02_weaving.ipynb @@ -252,7 +252,7 @@ "metadata": {}, "outputs": [], "source": [ - "ts_sine = sine(f=Q_(0.5 * 2 * np.pi, \"Hz\"), amp=Q_([[0, 0.75, 0]], \"mm\"))" + "ts_sine = sine(f=Q_(0.5 * 2 * np.pi, \"Hz\"), amp=Q_([0, 0.75, 0], \"mm\"))" ] }, { @@ -488,7 +488,7 @@ "metadata": {}, "outputs": [], "source": [ - "ts_sine = sine(f=Q_(1 / 8 * 2 * np.pi, \"Hz\"), amp=Q_([[0, 0, 1]], \"mm\"))" + "ts_sine = sine(f=Q_(1 / 8 * 2 * np.pi, \"Hz\"), amp=Q_([0, 0, 1], \"mm\"))" ] }, { @@ -622,7 +622,7 @@ "kernelspec": { "display_name": "weldx", "language": "python", - "name": "weldx-dev" + "name": "weldx" }, "language_info": { "codemirror_mode": { @@ -634,7 +634,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.2" + "version": "3.8.11" } }, "nbformat": 4, From ef09dc05c3f279a0da471e8407c86a78e61f41b1 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Mon, 1 Nov 2021 13:52:52 +0100 Subject: [PATCH 08/21] Fix mypy issue --- weldx/core.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/weldx/core.py b/weldx/core.py index 54c492047..40a48625f 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -47,7 +47,8 @@ def __init__( self.function = sympy.lambdify( tuple(self._expression.free_symbols), self._expression, "numpy" ) - self._parameters = {} + + self._parameters: Dict[str, Union[pint.Quantity, xr.DataArray]] = {} if parameters is not None: self.set_parameters(parameters) From 38c16f7ecb1635e87e5b2aa47316ba1207a1bb2a Mon Sep 17 00:00:00 2001 From: vhirtham Date: Mon, 1 Nov 2021 14:17:56 +0100 Subject: [PATCH 09/21] Fix docs mistake --- weldx/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weldx/core.py b/weldx/core.py index 40a48625f..67f32b92d 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -57,7 +57,7 @@ def set_parameters(self, params: Dict[str, Union[pint.Quantity, xr.DataArray]]): Parameters ---------- - paras: + params: Dictionary that contains the values for the specified parameters. """ From 1c4675a8b7e48d90f47fdda7d4396c2b968369ad Mon Sep 17 00:00:00 2001 From: vhirtham Date: Tue, 2 Nov 2021 09:08:21 +0100 Subject: [PATCH 10/21] Apply suggestion from PR --- weldx/core.py | 4 ++-- weldx/time.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/weldx/core.py b/weldx/core.py index 67f32b92d..bb0f7c1b7 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -466,7 +466,7 @@ def _interp_time_discrete(self, time: Time) -> xr.DataArray: """Interpolate the time series if its data is composed of discrete values.""" return ut.xr_interp_like( self._data, - {"time": time.as_timedelta()}, + {"time": time.as_timedelta_index()}, method=self.interpolation, assume_sorted=False, broadcast_missing=False, @@ -482,7 +482,7 @@ def _interp_time_expression(self, time: Time, time_unit: str) -> xr.DataArray: # evaluate expression data = self._data.evaluate(**{self._time_var_name: time_xr}) - return data.assign_coords({"time": time.as_timedelta_index()}) + return data.assign_coords({"time": time.as_data_array()}) @property def data(self) -> Union[pint.Quantity, MathematicalExpression]: diff --git a/weldx/time.py b/weldx/time.py index bfc0e0e16..88e9e8640 100644 --- a/weldx/time.py +++ b/weldx/time.py @@ -492,7 +492,8 @@ def as_pandas_index(self) -> Union[pd.TimedeltaIndex, pd.DatetimeIndex]: def as_data_array(self) -> DataArray: """Return the data as `xarray.DataArray`.""" - da = xr.DataArray(self._time, coords={"time": self._time}, dims=["time"]) + time = self.as_pandas_index() + da = xr.DataArray(time, coords={"time": time}, dims=["time"]) da.time.attrs["time_ref"] = self.reference_time return da From 9e8bfcabf116a46f2b9463cdee17a7810a1600e5 Mon Sep 17 00:00:00 2001 From: Cagtay Fabry <43667554+CagtayFabry@users.noreply.github.com> Date: Tue, 2 Nov 2021 09:20:16 +0100 Subject: [PATCH 11/21] use timedelta values in Time.as_data_array by default --- weldx/tests/test_time.py | 2 +- weldx/time.py | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/weldx/tests/test_time.py b/weldx/tests/test_time.py index 8f34f83cd..03aafc191 100644 --- a/weldx/tests/test_time.py +++ b/weldx/tests/test_time.py @@ -680,7 +680,7 @@ def test_convert_util(): assert np.all(time_q == Q_(range(10), "s")) assert time_q.time_ref == ts - arr2 = time.as_data_array().weldx.time_ref_restore() + arr2 = time.as_data_array() assert arr.time.identical(arr2.time) # test_duration -------------------------------------------------------------------- diff --git a/weldx/time.py b/weldx/time.py index bfc0e0e16..2c286ea2d 100644 --- a/weldx/time.py +++ b/weldx/time.py @@ -490,9 +490,22 @@ def as_pandas_index(self) -> Union[pd.TimedeltaIndex, pd.DatetimeIndex]: return pd.TimedeltaIndex([self._time]) return self._time - def as_data_array(self) -> DataArray: - """Return the data as `xarray.DataArray`.""" - da = xr.DataArray(self._time, coords={"time": self._time}, dims=["time"]) + def as_data_array(self, timedelta_base: bool = True) -> DataArray: + """Return the time data as a `xarray.DataArray` coordinate. + + By default the format is timedelta values with reference time as attribute. + + Parameters + ---------- + timedelta_base + If true (the default) the values of the xarray will always be timedeltas. + + """ + if timedelta_base: + t = self.as_timedelta_index() + else: + t = self._time + da = xr.DataArray(t, coords={"time": t}, dims=["time"]) da.time.attrs["time_ref"] = self.reference_time return da From 1f005e190b1a9e2282c465cdb7097d9bf6e99d3c Mon Sep 17 00:00:00 2001 From: Cagtay Fabry <43667554+CagtayFabry@users.noreply.github.com> Date: Tue, 2 Nov 2021 09:22:35 +0100 Subject: [PATCH 12/21] always use index type --- weldx/time.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weldx/time.py b/weldx/time.py index 2c286ea2d..1f6f209b7 100644 --- a/weldx/time.py +++ b/weldx/time.py @@ -504,7 +504,7 @@ def as_data_array(self, timedelta_base: bool = True) -> DataArray: if timedelta_base: t = self.as_timedelta_index() else: - t = self._time + t = self.index da = xr.DataArray(t, coords={"time": t}, dims=["time"]) da.time.attrs["time_ref"] = self.reference_time return da From ab145aa9355d84eb2b1f5f52d3130716fbb7f653 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Tue, 2 Nov 2021 10:39:09 +0100 Subject: [PATCH 13/21] Update changelog --- CHANGELOG.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5d5964982..a7bd92d21 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -43,6 +43,12 @@ changes `None`, the data will be transformed and stored at this coordinate system. `[#612] `__ +- The `MathematicalExpression` now supports `xarray.DataArray` as + parameters. Furthermore, multidimensional parameters of a + `MathematicalExpression` that is passed to a `TimeSeries` are + no longer required to have an extra dimension that represents time. + `[#621] `__ + fixes ===== From d1eb63496be8ca89981841ff1a6375d28d92e502 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Tue, 2 Nov 2021 10:55:06 +0100 Subject: [PATCH 14/21] Update scheme --- .../weldx/core/mathematical_expression-0.1.0.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/weldx/schemas/weldx.bam.de/weldx/core/mathematical_expression-0.1.0.yaml b/weldx/schemas/weldx.bam.de/weldx/core/mathematical_expression-0.1.0.yaml index f06dedf35..e3798f4fb 100644 --- a/weldx/schemas/weldx.bam.de/weldx/core/mathematical_expression-0.1.0.yaml +++ b/weldx/schemas/weldx.bam.de/weldx/core/mathematical_expression-0.1.0.yaml @@ -32,7 +32,9 @@ properties: description: | List of constant parameters that to be set in the mathematical expression. type: object - wx_property_tag: "asdf://weldx.bam.de/weldx/tags/units/quantity-0.1.*" + anyOf: + - wx_property_tag: "asdf://weldx.bam.de/weldx/tags/core/data_array-0.1.*" + - wx_property_tag: "asdf://weldx.bam.de/weldx/tags/units/quantity-0.1.*" required: [expression] propertyOrder: [expression, parameters] From d859ae974484b334d25278a094db7143743d921c Mon Sep 17 00:00:00 2001 From: vhirtham Date: Tue, 2 Nov 2021 10:57:10 +0100 Subject: [PATCH 15/21] Add some enhancements --- weldx/core.py | 62 +++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/weldx/core.py b/weldx/core.py index bb0f7c1b7..76b494281 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -52,25 +52,6 @@ def __init__( if parameters is not None: self.set_parameters(parameters) - def set_parameters(self, params: Dict[str, Union[pint.Quantity, xr.DataArray]]): - """Set the expressions parameters. - - Parameters - ---------- - params: - Dictionary that contains the values for the specified parameters. - - """ - if not isinstance(params, dict): - raise ValueError(f'"parameters" must be dictionary, got {type(params)}') - variable_names = [str(v) for v in self._expression.free_symbols] - for k, v in params.items(): - if k not in variable_names: - raise ValueError(f'The expression does not have a parameter "{k}"') - if not isinstance(v, xr.DataArray): - v = Q_(v) - self._parameters[k] = v - def __repr__(self): """Give __repr__ output.""" representation = ( @@ -166,6 +147,27 @@ def set_parameter(self, name, value): """ self.set_parameters({name: value}) + def set_parameters(self, params: Dict[str, Union[pint.Quantity, xr.DataArray]]): + """Set the expressions parameters. + + Parameters + ---------- + params: + Dictionary that contains the values for the specified parameters. + + """ + if not isinstance(params, dict): + raise ValueError(f'"parameters" must be dictionary, got {type(params)}') + + variable_names = [str(v) for v in self._expression.free_symbols] + + for k, v in params.items(): + if k not in variable_names: + raise ValueError(f'The expression does not have a parameter "{k}"') + if not isinstance(v, xr.DataArray): + v = Q_(v) + self._parameters[k] = v + @property def num_parameters(self): """Get the expressions number of parameters. @@ -248,20 +250,18 @@ def evaluate(self, **kwargs) -> Any: raise ValueError( f"The variables {intersection} are already defined as parameters." ) - variables = {} - for k, v in kwargs.items(): - if not isinstance(v, xr.DataArray): - v = xr.DataArray(Q_(v)) - variables[k] = v - parameters = {} - for k, v in self._parameters.items(): - if not isinstance(v, xr.DataArray): - v = xr.DataArray(v) - parameters[k] = v + variables = { + k: v if isinstance(v, xr.DataArray) else xr.DataArray(Q_(v)) + for k, v in kwargs.items() + } + + parameters = { + k: v if isinstance(v, xr.DataArray) else xr.DataArray(v) + for k, v in self._parameters.items() + } - inputs = {**variables, **parameters} - return self.function(**inputs) + return self.function(**variables, **parameters) # TimeSeries --------------------------------------------------------------------------- From 1e03a838d6e7e4d9b29537cf8c507dab305aabd6 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Tue, 2 Nov 2021 11:02:46 +0100 Subject: [PATCH 16/21] Add blank line --- weldx/core.py | 1 + 1 file changed, 1 insertion(+) diff --git a/weldx/core.py b/weldx/core.py index 76b494281..85b54b126 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -44,6 +44,7 @@ def __init__( if not isinstance(expression, sympy.Expr): expression = sympy.sympify(expression) self._expression = expression + self.function = sympy.lambdify( tuple(self._expression.free_symbols), self._expression, "numpy" ) From 64d2a9193daee78fc45b2701209fe9137312f7f6 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Tue, 2 Nov 2021 15:54:15 +0100 Subject: [PATCH 17/21] Restore old schema version --- .../weldx/core/mathematical_expression-0.1.0.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/weldx/schemas/weldx.bam.de/weldx/core/mathematical_expression-0.1.0.yaml b/weldx/schemas/weldx.bam.de/weldx/core/mathematical_expression-0.1.0.yaml index e3798f4fb..45a38b987 100644 --- a/weldx/schemas/weldx.bam.de/weldx/core/mathematical_expression-0.1.0.yaml +++ b/weldx/schemas/weldx.bam.de/weldx/core/mathematical_expression-0.1.0.yaml @@ -32,9 +32,7 @@ properties: description: | List of constant parameters that to be set in the mathematical expression. type: object - anyOf: - - wx_property_tag: "asdf://weldx.bam.de/weldx/tags/core/data_array-0.1.*" - - wx_property_tag: "asdf://weldx.bam.de/weldx/tags/units/quantity-0.1.*" + wx_property_tag: "asdf://weldx.bam.de/weldx/tags/units/quantity-0.1.*" required: [expression] propertyOrder: [expression, parameters] From 68a955568cdf29d2c3f408bea56f5468b4a9cee3 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Tue, 2 Nov 2021 17:27:48 +0100 Subject: [PATCH 18/21] Test metadata dims --- weldx/core.py | 2 +- .../core/mathematical_expression-0.1.0.yaml | 2 +- weldx/tags/core/mathematical_expression.py | 26 +++++++++++++--- weldx/tests/asdf_tests/test_asdf_core.py | 31 +++++++++++++++++++ 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/weldx/core.py b/weldx/core.py index 85b54b126..b2f795bbb 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -467,7 +467,7 @@ def _interp_time_discrete(self, time: Time) -> xr.DataArray: """Interpolate the time series if its data is composed of discrete values.""" return ut.xr_interp_like( self._data, - {"time": time.as_timedelta_index()}, + {"time": time.as_data_array()}, method=self.interpolation, assume_sorted=False, broadcast_missing=False, diff --git a/weldx/schemas/weldx.bam.de/weldx/core/mathematical_expression-0.1.0.yaml b/weldx/schemas/weldx.bam.de/weldx/core/mathematical_expression-0.1.0.yaml index 45a38b987..f06dedf35 100644 --- a/weldx/schemas/weldx.bam.de/weldx/core/mathematical_expression-0.1.0.yaml +++ b/weldx/schemas/weldx.bam.de/weldx/core/mathematical_expression-0.1.0.yaml @@ -32,7 +32,7 @@ properties: description: | List of constant parameters that to be set in the mathematical expression. type: object - wx_property_tag: "asdf://weldx.bam.de/weldx/tags/units/quantity-0.1.*" + wx_property_tag: "asdf://weldx.bam.de/weldx/tags/units/quantity-0.1.*" required: [expression] propertyOrder: [expression, parameters] diff --git a/weldx/tags/core/mathematical_expression.py b/weldx/tags/core/mathematical_expression.py index 7da76535a..d12912d84 100644 --- a/weldx/tags/core/mathematical_expression.py +++ b/weldx/tags/core/mathematical_expression.py @@ -1,4 +1,5 @@ import sympy +from xarray import DataArray from weldx.asdf.types import WeldxConverter from weldx.core import MathematicalExpression @@ -15,12 +16,27 @@ class MathematicalExpressionConverter(WeldxConverter): def to_yaml_tree(self, obj: MathematicalExpression, tag: str, ctx) -> dict: """Convert to python dict.""" - tree = {"expression": obj.expression.__str__(), "parameters": obj.parameters} - return tree + parameters = {} + for k, v in obj.parameters.items(): + if isinstance(v, DataArray): + dims = v.dims + v = v.data + v.wx_metadata = dict(dims=dims) + parameters[k] = v + + return {"expression": obj.expression.__str__(), "parameters": parameters} def from_yaml_tree(self, node: dict, tag: str, ctx): """Construct from tree.""" - obj = MathematicalExpression( - sympy.sympify(node["expression"]), parameters=node["parameters"] + + parameters = {} + for k, v in node["parameters"].items(): + if hasattr(v, "wx_metadata"): + dims = v.wx_metadata["dims"] + delattr(v, "wx_metadata") + v = DataArray(v, dims=dims) + parameters[k] = v + + return MathematicalExpression( + sympy.sympify(node["expression"]), parameters=parameters ) - return obj diff --git a/weldx/tests/asdf_tests/test_asdf_core.py b/weldx/tests/asdf_tests/test_asdf_core.py index 88ae9c8a8..1af2bd523 100644 --- a/weldx/tests/asdf_tests/test_asdf_core.py +++ b/weldx/tests/asdf_tests/test_asdf_core.py @@ -753,3 +753,34 @@ def test_graph_serialization(): assert all(e in g.edges for e in g2.edges) assert all(n in g.nodes for n in g2.nodes) + + +# -------------------------------------------------------------------------------------- +# MathematicalExpression +# -------------------------------------------------------------------------------------- + + +class TestMathematicalExpression: + @staticmethod + @pytest.mark.parametrize( + "a, b", + [ + (Q_([1, 2, 3], "m"), Q_([4, 5, 6], "m")), + ( + xr.DataArray(Q_([1, 2], "m"), dims=["a"]), + xr.DataArray(Q_([3, 4], "m"), dims=["b"]), + ), + ( + Q_([1, 2], "m"), + xr.DataArray(Q_([3, 4], "m"), dims=["b"]), + ), + ], + ) + def test_parameters(a, b): + expression = "a*x + b" + parameters = dict(a=a, b=b) + + me = ME(expression, parameters) + me_2 = write_read_buffer({"me": me})["me"] + + assert me == me_2 From 7df08930b44b6c8a1a05fede1ad8abd2326773b4 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Wed, 3 Nov 2021 14:39:21 +0100 Subject: [PATCH 19/21] Add tuple parameters --- weldx/core.py | 11 ++++++++--- weldx/tags/core/mathematical_expression.py | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/weldx/core.py b/weldx/core.py index b2f795bbb..e2ab5a708 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -20,13 +20,16 @@ __all__ = ["MathematicalExpression", "TimeSeries"] +_me_parameter_types = Union[pint.Quantity, str, Tuple[pint.Quantity, str], xr.DataArray] + + class MathematicalExpression: """Mathematical expression using sympy syntax.""" def __init__( self, expression: Union[sympy.Expr, str], - parameters: Dict[str, Union[pint.Quantity, str]] = None, + parameters: _me_parameter_types = None, ): """Construct a MathematicalExpression. @@ -49,7 +52,7 @@ def __init__( tuple(self._expression.free_symbols), self._expression, "numpy" ) - self._parameters: Dict[str, Union[pint.Quantity, xr.DataArray]] = {} + self._parameters: _me_parameter_types = {} if parameters is not None: self.set_parameters(parameters) @@ -148,7 +151,7 @@ def set_parameter(self, name, value): """ self.set_parameters({name: value}) - def set_parameters(self, params: Dict[str, Union[pint.Quantity, xr.DataArray]]): + def set_parameters(self, params: _me_parameter_types): """Set the expressions parameters. Parameters @@ -165,6 +168,8 @@ def set_parameters(self, params: Dict[str, Union[pint.Quantity, xr.DataArray]]): for k, v in params.items(): if k not in variable_names: raise ValueError(f'The expression does not have a parameter "{k}"') + if isinstance(v, tuple): + v = xr.DataArray(v[0], dims=v[1]) if not isinstance(v, xr.DataArray): v = Q_(v) self._parameters[k] = v diff --git a/weldx/tags/core/mathematical_expression.py b/weldx/tags/core/mathematical_expression.py index d12912d84..78e79d39f 100644 --- a/weldx/tags/core/mathematical_expression.py +++ b/weldx/tags/core/mathematical_expression.py @@ -34,7 +34,7 @@ def from_yaml_tree(self, node: dict, tag: str, ctx): if hasattr(v, "wx_metadata"): dims = v.wx_metadata["dims"] delattr(v, "wx_metadata") - v = DataArray(v, dims=dims) + v = (v, dims) parameters[k] = v return MathematicalExpression( From 45c872544f4695de26465cee83157cf121b952e3 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Wed, 3 Nov 2021 14:44:16 +0100 Subject: [PATCH 20/21] Fix mypy issue --- weldx/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/weldx/core.py b/weldx/core.py index e2ab5a708..c15033499 100644 --- a/weldx/core.py +++ b/weldx/core.py @@ -52,7 +52,7 @@ def __init__( tuple(self._expression.free_symbols), self._expression, "numpy" ) - self._parameters: _me_parameter_types = {} + self._parameters: Union[pint.Quantity, xr.DataArray] = {} if parameters is not None: self.set_parameters(parameters) From e2f0e39eadca5d8b4c26ced0ef37de52d49004e4 Mon Sep 17 00:00:00 2001 From: vhirtham Date: Wed, 3 Nov 2021 14:52:14 +0100 Subject: [PATCH 21/21] Add warning if coordinates are dropped --- weldx/tags/core/mathematical_expression.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/weldx/tags/core/mathematical_expression.py b/weldx/tags/core/mathematical_expression.py index 78e79d39f..83f390267 100644 --- a/weldx/tags/core/mathematical_expression.py +++ b/weldx/tags/core/mathematical_expression.py @@ -1,3 +1,5 @@ +import warnings + import sympy from xarray import DataArray @@ -19,6 +21,8 @@ def to_yaml_tree(self, obj: MathematicalExpression, tag: str, ctx) -> dict: parameters = {} for k, v in obj.parameters.items(): if isinstance(v, DataArray): + if len(v.coords) > 0: + warnings.warn("Coordinates are dropped during serialization.") dims = v.dims v = v.data v.wx_metadata = dict(dims=dims)