Repository: bo4e/BO4E-python (language: python)

Issue:
Implement COM Sigmoidparameter
https://www.bo4e.de/dokumentation/komponenten/com-sigmoidparameter


Discussion / hints:

Fix patch:
diff --git a/src/bo4e/com/sigmoidparameter.py b/src/bo4e/com/sigmoidparameter.py
new file mode 100644
index 000000000..04b2ff653
--- /dev/null
+++ b/src/bo4e/com/sigmoidparameter.py
@@ -0,0 +1,52 @@
+"""
+Contains Sigmoidparameter class and corresponding marshmallow schema for de-/serialization
+"""
+
+# pylint: disable=too-few-public-methods
+from decimal import Decimal
+
+import attr
+from marshmallow import fields, post_load
+
+from bo4e.com.com import COM, COMSchema
+
+
+# pylint:disable=invalid-name
+@attr.s(auto_attribs=True, kw_only=True)
+class Sigmoidparameter(COM):
+    """
+    Die Sigmoid-Funktion, beispielsweise zur Berechnung eines Leistungspreises hat die Form:
+    LP=A/(1+(P/B)^C)+D
+    """
+
+    # required attributes
+    A: Decimal = attr.ib(validator=attr.validators.instance_of(Decimal))  #: Briefmarke Ortsverteilnetz (EUR/kWh)
+    B: Decimal = attr.ib(validator=attr.validators.instance_of(Decimal))  #: Wendepunkt für die bepreiste Menge (kW)
+    C: Decimal = attr.ib(validator=attr.validators.instance_of(Decimal))  #: Exponent (einheitenlos)
+    D: Decimal = attr.ib(validator=attr.validators.instance_of(Decimal))  #: Briefmarke Transportnetz (EUR/kWh)
+
+    def calculate(self, leistung: Decimal) -> Decimal:
+        """
+        calculates LP
+        :param p: Leistung in Kilowatt
+        :return: den Sigmoidparameter LP in EUR/kWh
+        """
+        return self.A / (1 + (leistung / self.B) ** self.C) + self.D
+
+
+class SigmoidparameterSchema(COMSchema):
+    """
+    Schema for de-/serialization of Sigmoidparameter.
+    """
+
+    # required attributes
+    A = fields.Decimal(as_string=True)
+    B = fields.Decimal(as_string=True)
+    C = fields.Decimal(as_string=True)
+    D = fields.Decimal(as_string=True)
+
+    # pylint: disable=no-self-use, unused-argument
+    @post_load
+    def deserialize(self, data, **kwargs) -> Sigmoidparameter:
+        """Deserialize JSON to Sigmoidparameter object"""
+        return Sigmoidparameter(**data)


Test patch:
diff --git a/tests/test_sigmoidparameter.py b/tests/test_sigmoidparameter.py
new file mode 100644
index 000000000..0cb647906
--- /dev/null
+++ b/tests/test_sigmoidparameter.py
@@ -0,0 +1,53 @@
+from decimal import Decimal
+
+import pytest  # type:ignore[import]
+
+from bo4e.com.sigmoidparameter import Sigmoidparameter, SigmoidparameterSchema
+from tests.serialization_helper import assert_serialization_roundtrip  # type:ignore[import]
+
+
+class TestSigmoidparameter:
+    @pytest.mark.parametrize(
+        "sigmoidparameter, expected_json_dict",
+        [
+            pytest.param(
+                Sigmoidparameter(
+                    A=Decimal(1),
+                    B=Decimal(2),
+                    C=Decimal(3),
+                    D=Decimal(4),
+                ),
+                {"a": "1", "b": "2", "c": "3", "d": "4"},
+            ),
+        ],
+    )
+    def test_sigmoidparameter_serialization_roundtrip(
+        self, sigmoidparameter: Sigmoidparameter, expected_json_dict: dict
+    ):
+        """
+        Test de-/serialisation of Sigmoidparameter with minimal attributes.
+        """
+        assert_serialization_roundtrip(sigmoidparameter, SigmoidparameterSchema(), expected_json_dict)
+
+    def test_sigmoidparameter_missing_required_attribute(self):
+        with pytest.raises(TypeError) as excinfo:
+            _ = Sigmoidparameter()
+        assert "missing 4 required" in str(excinfo.value)
+
+    @pytest.mark.parametrize(
+        "sigmoidparameter, leistung, expected_lp",
+        [
+            pytest.param(
+                Sigmoidparameter(
+                    A=Decimal(1),
+                    B=Decimal(3),
+                    C=Decimal(3),
+                    D=Decimal(4),
+                ),
+                Decimal(3),
+                Decimal(4.5),
+            ),
+        ],
+    )
+    def test_lp_calculation(self, sigmoidparameter: Sigmoidparameter, leistung: Decimal, expected_lp: Decimal):
+        assert sigmoidparameter.calculate(leistung) == expected_lp