-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #88 from Deltares/feature/DEI-141-layer-filter-rul…
…e-on-other-axis Feature/dei axis filter rule
- Loading branch information
Showing
12 changed files
with
459 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
# This file is part of D-EcoImpact | ||
# Copyright (C) 2022-2023 Stichting Deltares and D-EcoImpact contributors | ||
# This program is free software distributed under the GNU | ||
# Lesser General Public License version 2.1 | ||
# A copy of the GNU General Public License can be found at | ||
# https://github.com/Deltares/D-EcoImpact/blob/main/LICENSE.md | ||
""" | ||
Module for AxisFilterRule class | ||
Classes: | ||
AxisFilterRule | ||
""" | ||
|
||
from typing import List | ||
|
||
import xarray as _xr | ||
|
||
from decoimpact.business.entities.rules.i_array_based_rule import IArrayBasedRule | ||
from decoimpact.business.entities.rules.rule_base import RuleBase | ||
from decoimpact.crosscutting.i_logger import ILogger | ||
|
||
|
||
class AxisFilterRule(RuleBase, IArrayBasedRule): | ||
|
||
"""Implementation for the layer filter rule""" | ||
|
||
def __init__( | ||
self, | ||
name: str, | ||
input_variable_names: List[str], | ||
layer_number: int, | ||
axis_name: str, | ||
output_variable_name: str = "output", | ||
description: str = "", | ||
): | ||
super().__init__(name, input_variable_names, output_variable_name, description) | ||
self._layer_number = layer_number | ||
self._axis_name = axis_name | ||
|
||
@property | ||
def layer_number(self) -> int: | ||
"""Layer number property""" | ||
return self._layer_number | ||
|
||
@property | ||
def axis_name(self) -> str: | ||
"""Layer number property""" | ||
return self._axis_name | ||
|
||
def execute(self, value_array: _xr.DataArray, logger: ILogger) -> _xr.DataArray: | ||
|
||
"""Obtain a 2D layer from a 3D variable | ||
Args: | ||
value (float): 3D value to obtain a layer from | ||
Returns: | ||
float: 2D variable | ||
""" | ||
|
||
if self._axis_name not in value_array.dims: | ||
message = f"""Layer name is not in dim names \ | ||
[{value_array.dims}] layer_name [{self._axis_name}]""" | ||
logger.log_error(message) | ||
raise IndexError(message) | ||
|
||
if not ( | ||
self._layer_number >= 0 | ||
and self._layer_number <= len(getattr(value_array, self._axis_name)) | ||
): | ||
message = f"""Layer number should be within range \ | ||
[0,{len(getattr(value_array, self._axis_name))}]""" | ||
logger.log_error(message) | ||
raise IndexError(message) | ||
|
||
return value_array.isel({self._axis_name: self._layer_number - 1}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# This file is part of D-EcoImpact | ||
# Copyright (C) 2022-2023 Stichting Deltares | ||
# This program is free software distributed under the | ||
# GNU Affero General Public License version 3.0 | ||
# A copy of the GNU Affero General Public License can be found at | ||
# https://github.com/Deltares/D-EcoImpact/blob/main/LICENSE.md | ||
""" | ||
Module for IAxisFilterRuleData interface | ||
Interfaces: | ||
IAxisFilterRuleData | ||
""" | ||
|
||
|
||
from abc import ABC, abstractmethod | ||
|
||
from decoimpact.data.api.i_rule_data import IRuleData | ||
|
||
|
||
class IAxisFilterRuleData(IRuleData, ABC): | ||
"""Data for a axis filter rule""" | ||
|
||
@property | ||
@abstractmethod | ||
def input_variable(self) -> str: | ||
"""Property for the nput variable""" | ||
|
||
@property | ||
@abstractmethod | ||
def layer_number(self) -> int: | ||
"""Property for the layer number""" | ||
|
||
@property | ||
@abstractmethod | ||
def axis_name(self) -> str: | ||
"""Property for the dim name""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# This file is part of D-EcoImpact | ||
# Copyright (C) 2022-2023 Stichting Deltares | ||
# This program is free software distributed under the | ||
# GNU Affero General Public License version 3.0 | ||
# A copy of the GNU Affero General Public License can be found at | ||
# https://github.com/Deltares/D-EcoImpact/blob/main/LICENSE.md | ||
""" | ||
Module for AxisFilterRuleData class | ||
Classes: | ||
AxisFilterRuleData | ||
""" | ||
|
||
from decoimpact.data.api.i_axis_filter_rule_data import IAxisFilterRuleData | ||
from decoimpact.data.entities.rule_data import RuleData | ||
|
||
|
||
class AxisFilterRuleData(IAxisFilterRuleData, RuleData): | ||
"""Class for storing data related to axis filter rule rule""" | ||
|
||
def __init__( | ||
self, | ||
name: str, | ||
layer_number: int, | ||
axis_name: str, | ||
input_variable: str, | ||
output_variable: str = "output", | ||
description: str = "", | ||
): | ||
super().__init__(name, output_variable, description) | ||
self._input_variable = input_variable | ||
self._layer_number = layer_number | ||
self._axis_name = axis_name | ||
|
||
@property | ||
def input_variable(self) -> str: | ||
"""Property for the input variable""" | ||
return self._input_variable | ||
|
||
@property | ||
def layer_number(self) -> int: | ||
"""Property for the layer number""" | ||
return self._layer_number | ||
|
||
@property | ||
def axis_name(self) -> str: | ||
"""Property for the dimension name""" | ||
return self._axis_name | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
# This file is part of D-EcoImpact | ||
# Copyright (C) 2022-2023 Stichting Deltares | ||
# This program is free software distributed under the | ||
# GNU Affero General Public License version 3.0 | ||
# A copy of the GNU Affero General Public License can be found at | ||
# https://github.com/Deltares/D-EcoImpact/blob/main/LICENSE.md | ||
""" | ||
Module for ParserLayerFilterRule class | ||
Classes: | ||
ParserLayerFilterRule | ||
""" | ||
from typing import Any, Dict | ||
|
||
from decoimpact.crosscutting.i_logger import ILogger | ||
from decoimpact.data.api.i_rule_data import IRuleData | ||
from decoimpact.data.dictionary_utils import get_dict_element | ||
from decoimpact.data.entities.axis_filter_rule_data import AxisFilterRuleData | ||
from decoimpact.data.parsers.i_parser_rule_base import IParserRuleBase | ||
|
||
|
||
class ParserAxisFilterRule(IParserRuleBase): | ||
|
||
"""Class for creating a AxisFilterRuleData""" | ||
|
||
@property | ||
def rule_type_name(self) -> str: | ||
"""Type name for the rule""" | ||
return "axis_filter_rule" | ||
|
||
def parse_dict(self, dictionary: Dict[str, Any], logger: ILogger) -> IRuleData: | ||
"""Parses the provided dictionary to a IRuleData | ||
Args: | ||
dictionary (Dict[str, Any]): Dictionary holding the values | ||
for making the rule | ||
Returns: | ||
RuleBase: Rule based on the provided data | ||
""" | ||
name = get_dict_element("name", dictionary) | ||
description = get_dict_element("description", dictionary) | ||
input_variable_name = get_dict_element("input_variable", dictionary) | ||
axis_name = get_dict_element("axis_name", dictionary) | ||
if not isinstance(axis_name, str): | ||
message = ( | ||
"Dimension name should be a string, " | ||
f"received a {type(axis_name)}: {axis_name}" | ||
) | ||
raise ValueError(message) | ||
|
||
layer_number = get_dict_element("layer_number", dictionary) | ||
if not isinstance(layer_number, int): | ||
message = ( | ||
"Layer number should be an integer, " | ||
f"received a {type(layer_number)}: {layer_number}" | ||
) | ||
raise ValueError(message) | ||
output_variable_name = get_dict_element("output_variable", dictionary) | ||
|
||
return AxisFilterRuleData( | ||
name, layer_number, axis_name, input_variable_name, | ||
output_variable_name, description | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# This file is part of D-EcoImpact | ||
# Copyright (C) 2022-2023 Stichting Deltares | ||
# This program is free software distributed under the | ||
# GNU Affero General Public License version 3.0 | ||
# A copy of the GNU Affero General Public License can be found at | ||
# https://github.com/Deltares/D-EcoImpact/blob/main/LICENSE.md | ||
""" | ||
Tests for AxisFilterRule class | ||
""" | ||
import pytest | ||
import xarray as _xr | ||
from mock import Mock | ||
|
||
from decoimpact.business.entities.rules.axis_filter_rule import AxisFilterRule | ||
from decoimpact.crosscutting.i_logger import ILogger | ||
|
||
|
||
def test_create_axis_filter_rule_should_set_defaults(): | ||
"""Test creating a AxisFilterRule with defaults""" | ||
|
||
# Arrange & Act | ||
rule = AxisFilterRule("test", ["foo"], 3, "boo", "output") | ||
|
||
# Assert | ||
assert rule.name == "test" | ||
assert rule.description == "" | ||
assert rule.input_variable_names == ["foo"] | ||
assert rule.output_variable_name == "output" | ||
assert rule.layer_number == 3 | ||
assert rule.axis_name == "boo" | ||
assert isinstance(rule, AxisFilterRule) | ||
|
||
|
||
def test_execute_value_array_axis_filtered(): | ||
"""Test execute of layer filter rule""" | ||
# Arrange & Act | ||
logger = Mock(ILogger) | ||
rule = AxisFilterRule("test", ["foo"], 1, "dim_1", "output", "description") | ||
data = [[1, 2], [3, 4]] | ||
value_array = _xr.DataArray(data, dims=("dim_1","dim_2")) | ||
filtered_array = rule.execute(value_array, logger) | ||
|
||
result_data = [1,2] | ||
result_array = _xr.DataArray(result_data, dims=("dim_2")) | ||
|
||
# Assert | ||
assert _xr.testing.assert_equal(filtered_array, result_array) is None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# This file is part of D-EcoImpact | ||
# Copyright (C) 2022-2023 Stichting Deltares | ||
# This program is free software distributed under the | ||
# GNU Affero General Public License version 3.0 | ||
# A copy of the GNU Affero General Public License can be found at | ||
# https://github.com/Deltares/D-EcoImpact/blob/main/LICENSE.md | ||
""" | ||
Tests for AxisFilterRuleData class | ||
""" | ||
|
||
from decoimpact.data.api.i_rule_data import IRuleData | ||
from decoimpact.data.entities.axis_filter_rule_data import AxisFilterRuleData | ||
|
||
|
||
def test_axis_filter_rule_data_creation_logic(): | ||
"""The AxisFilterRuleData should parse the provided dictionary | ||
to correctly initialize itself during creation """ | ||
|
||
#Act | ||
data = AxisFilterRuleData("test_name", 3, "axis_name", "input", "output", "description") | ||
|
||
|
||
#Assert | ||
|
||
assert isinstance(data, IRuleData) | ||
assert data.input_variable == "input" | ||
assert data.layer_number == 3 | ||
assert data.axis_name == "axis_name" |
Oops, something went wrong.