Repository: oemof/oemof-solph
Issue: Flow's argument"fix" is silently ignored when no nominal_value is given

**Describe the bug**
Flow's argument "fix" is silently ignored when no nominal_value is given.

**Current behaviour**
```Python
solph.flows.Flow(fix=0.5)
```
leads to a flow with a non-fixed value without any feedback given.

**Expected behaviour**
As there is no `nominal_value` given, the Flow cannot be fixed. Thus, an error should be thrown.



Changed files:
tests/test_solph_network_classes.py, tests/flow_tests.py, tests/test_components.py, src/oemof/solph/flows/_flow.py

diff --git a/src/oemof/solph/flows/_flow.py b/src/oemof/solph/flows/_flow.py
index cab05db4..9fdf9e48 100644
--- a/src/oemof/solph/flows/_flow.py
+++ b/src/oemof/solph/flows/_flow.py
@@ -14,7 +14,7 @@ SPDX-FileCopyrightText: jmloenneberga
 SPDX-License-Identifier: MIT
 
 """
-
+import math
 from warnings import warn
 
 from oemof.network import network as on
@@ -87,10 +87,6 @@ class Flow(on.Edge):
         The costs associated with one unit of the flow. If this is set the
         costs will be added to the objective expression of the optimization
         problem.
-    fixed : boolean
-        Boolean value indicating if a flow is fixed during the optimization
-        problem to its ex-ante set value. Used in combination with the
-        :attr:`fix`.
     investment : :class:`Investment <oemof.solph.options.Investment>`
         Object indicating if a nominal_value of the flow is determined by
         the optimization problem. Note: This will refer all attributes to an
@@ -121,7 +117,7 @@ class Flow(on.Edge):
     --------
     Creating a fixed flow object:
 
-    >>> f = Flow(fix=[10, 4, 4], variable_costs=5)
+    >>> f = Flow(nominal_value=2, fix=[10, 4, 4], variable_costs=5)
     >>> f.variable_costs[2]
     5
     >>> f.fix[2]
@@ -172,6 +168,17 @@ class Flow(on.Edge):
             "positive_gradient": {"ub": None},
             "negative_gradient": {"ub": None},
         }
+        need_nominal_value = [
+            "fix",
+            "full_load_time_max",
+            "full_load_time_min",
+            "max",
+            "min",
+            # --- BEGIN: To be removed for versions >= v0.6 ---
+            "summed_max",
+            "summed_min",
+            # --- END ---
+        ]
         keys = [k for k in kwargs if k != "label"]
 
         if "fixed_costs" in keys:
@@ -199,7 +206,7 @@ class Flow(on.Edge):
             kwargs.get("min") is not None or kwargs.get("max") is not None
         ):
             raise AttributeError(
-                "It is not allowed to define min/max if fix is defined."
+                "It is not allowed to define `min`/`max` if `fix` is defined."
             )
 
         # Set default value for min and max
@@ -250,6 +257,24 @@ class Flow(on.Edge):
                 + "nonconvex flows!"
             )
 
+        infinite_error_msg = (
+            "{} must be a finite value. Passing an infinite "
+            "value is not allowed."
+        )
+        if not self.investment:
+            if self.nominal_value is None:
+                for attr in need_nominal_value:
+                    if kwargs.get(attr) is not None:
+                        raise AttributeError(
+                            "If {} is set in a flow (except InvestmentFlow), "
+                            "nominal_value must be set as well.\\n"
+                            "Otherwise, it won't have any effect.".format(attr)
+                        )
+            elif not math.isfinite(self.nominal_value):
+                raise ValueError(infinite_error_msg.format("nominal_value"))
+        if not math.isfinite(self.max[0]):
+            raise ValueError(infinite_error_msg.format("max"))
+
         # Checking for impossible gradient combinations
         if self.nonconvex:
             if self.nonconvex.positive_gradient["ub"][0] is not None and (
diff --git a/tests/flow_tests.py b/tests/flow_tests.py
index 3e29b8a5..ba662ea9 100644
--- a/tests/flow_tests.py
+++ b/tests/flow_tests.py
@@ -28,7 +28,7 @@ def test_summed_max_future_warning():
     """Can be removed with v0.6."""
     msg = "The parameter 'summed_max' ist deprecated and will be removed"
     with warnings.catch_warnings(record=True) as w:
-        Flow(summed_max=2)
+        Flow(nominal_value=1, summed_max=2)
         assert len(w) == 1
         assert msg in str(w[-1].message)
 
@@ -37,10 +37,10 @@ def test_summed_min_future_warning():
     """Can be removed with v0.6."""
     msg = "The parameter 'summed_min' ist deprecated and will be removed"
     with warnings.catch_warnings(record=True) as w:
-        Flow(summed_min=2)
+        Flow(nominal_value=1, summed_min=2)
         assert len(w) == 1
         assert msg in str(w[-1].message)
 
 
 def test_source_with_full_load_time_max():
-    Flow(full_load_time_max=2)
+    Flow(nominal_value=1, full_load_time_max=2)
diff --git a/tests/test_components.py b/tests/test_components.py
index d3a66c35..45f0b5ae 100644
--- a/tests/test_components.py
+++ b/tests/test_components.py
@@ -15,7 +15,7 @@ import pytest
 from oemof.tools.debugging import SuspiciousUsageWarning
 
 from oemof.solph import Investment
-from oemof.solph import components as components
+from oemof.solph import components
 from oemof.solph.buses import Bus
 from oemof.solph.flows import Flow
 from oemof.solph.flows import NonConvexFlow
diff --git a/tests/test_solph_network_classes.py b/tests/test_solph_network_classes.py
index 10e114f0..cd3c13c8 100644
--- a/tests/test_solph_network_classes.py
+++ b/tests/test_solph_network_classes.py
@@ -83,7 +83,7 @@ def test_error_of_deprecated_fixed_costs():
 
 
 def test_flow_with_fix_and_min_max():
-    msg = "It is not allowed to define min/max if fix is defined."
+    msg = "It is not allowed to define `min`/`max` if `fix` is defined."
     with pytest.raises(AttributeError, match=msg):
         solph.flows.Flow(fix=[1, 3], min=[0, 5])
     with pytest.raises(AttributeError, match=msg):
@@ -92,14 +92,49 @@ def test_flow_with_fix_and_min_max():
         solph.flows.Flow(fix=[1, 3], max=[0, 5], min=[4, 9])
 
 
+def test_infinite_values():
+    msg1 = "nominal_value must be a finite value"
+    msg2 = "max must be a finite value"
+    with pytest.raises(ValueError, match=msg1):
+        solph.flows.Flow(nominal_value=float("+inf"))
+    with pytest.raises(ValueError, match=msg2):
+        solph.flows.Flow(nominal_value=1, max=float("+inf"))
+
+
+def test_attributes_needing_nominal_value_get_it():
+    with pytest.raises(AttributeError, match="If fix is set in a flow "):
+        solph.flows.Flow(fix=0.3)
+
+    with pytest.raises(AttributeError, match="If max is set in a flow "):
+        solph.flows.Flow(max=0.3)
+
+    with pytest.raises(AttributeError, match="If min is set in a flow "):
+        solph.flows.Flow(min=0.3)
+
+    with pytest.raises(
+        AttributeError, match="If full_load_time_max is set in a flow "
+    ):
+        solph.flows.Flow(full_load_time_max=0.3)
+
+    with pytest.raises(
+        AttributeError, match="If full_load_time_min is set in a flow "
+    ):
+        solph.flows.Flow(full_load_time_min=0.3)
+
+
 def test_min_max_values_for_bidirectional_flow():
-    a = solph.flows.Flow(bidirectional=True)  # use default values
-    b = solph.flows.Flow(bidirectional=True, min=-0.9, max=0.9)
+    a = solph.flows.Flow(
+        bidirectional=True,
+    )  # use default values
+    b = solph.flows.Flow(
+        bidirectional=True, nominal_value=1, min=-0.8, max=0.9
+    )
     assert a.bidirectional
     assert a.max[0] == 1
     assert a.min[0] == -1
+    assert b.bidirectional
     assert b.max[0] == 0.9
-    assert b.min[0] == -0.9
+    assert b.min[0] == -0.8
 
 
 def test_deprecated_actual_value():
@@ -117,6 +152,6 @@ def test_warning_fixed_still_used():
         "The `fixed` attribute does not change anything."
     )
     with warnings.catch_warnings(record=True) as w:
-        solph.flows.Flow(fixed=True)
+        solph.flows.Flow(nominal_value=1, fixed=True)
         assert len(w) != 0
         assert msg == str(w[-1].message)