Repository: duartegroup/autodE

Issue:
Division and multiplication of `autode.values.Value` creates wrong units
**Describe the bug**
<!-- A clear and concise description of what the bug is. -->

Multiplication and division do not generate autode.values with the correct units. As a simple fix multiplication could return a float, given it's (potentially) an uncommon occurrence.

**To Reproduce**
<!-- Steps to reproduce the behaviour: code with output -->


```python
>>> import autode as ade
>>> e = ade.values.PotentialEnergy(1)
>>> e
Energy(1.0 Ha)
>>> e * e
Energy(1.0 Ha)
>>> e / e
Energy(1.0 Ha)
>>> # Addition and subtraction are okay
>>> e + e
Energy(2.0 Ha)
>>> e - e
Energy(0.0 Ha)
```

**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->

Division results in no units and multiplication Ha^2

**Environment**
<!-- please complete the following information. -->
 - autodE version: 1.3.4


Comments:

Patch:
diff --git a/autode/values.py b/autode/values.py
index dcf4c09..295444d 100644
--- a/autode/values.py
+++ b/autode/values.py
@@ -62,7 +62,7 @@ def _to(value: Union["Value", "ValueArray"], units: Union[Unit, str]):
 
     except StopIteration:
         raise TypeError(
-            f"No viable unit conversion from {value.units} " f"-> {units}"
+            f"No viable unit conversion from {value.units} -> {units}"
         )
 
     # Convert to the base unit, then to the new units
@@ -214,16 +214,22 @@ class Value(ABC, float):
             float(self) + self._other_same_units(other), units=self.units
         )
 
-    def __mul__(self, other) -> "Value":
+    def __mul__(self, other) -> Union[float, "Value"]:
         """Multiply this value with another"""
         if isinstance(other, np.ndarray):
             return other * float(self)
 
+        if isinstance(other, Value):
+            logger.warning(
+                "Multiplying autode.Value returns a float with no units"
+            )
+            return float(self) * self._other_same_units(other)
+
         return self.__class__(
             float(self) * self._other_same_units(other), units=self.units
         )
 
-    def __rmul__(self, other) -> "Value":
+    def __rmul__(self, other) -> Union[float, "Value"]:
         return self.__mul__(other)
 
     def __radd__(self, other) -> "Value":
@@ -232,16 +238,19 @@ class Value(ABC, float):
     def __sub__(self, other) -> "Value":
         return self.__add__(-other)
 
-    def __floordiv__(self, other):
-        raise NotImplementedError(
-            "Integer division is not supported by " "autode.values.Value"
-        )
+    def __floordiv__(self, other) -> Union[float, "Value"]:
+        x = float(self) // self._other_same_units(other)
+        if isinstance(other, Value):
+            return x
 
-    def __truediv__(self, other) -> "Value":
-        return self.__class__(
-            float(self) / float(self._other_same_units(other)),
-            units=self.units,
-        )
+        return self.__class__(x, units=self.units)
+
+    def __truediv__(self, other) -> Union[float, "Value"]:
+        x = float(self) / self._other_same_units(other)
+        if isinstance(other, Value):
+            return x
+
+        return self.__class__(x, units=self.units)
 
     def __abs__(self) -> "Value":
         """Absolute value"""
diff --git a/doc/changelog.rst b/doc/changelog.rst
index ab9c69a..8303c13 100644
--- a/doc/changelog.rst
+++ b/doc/changelog.rst
@@ -19,6 +19,8 @@ Functionality improvements
 Bug Fixes
 *********
 - Fixes :code:`ERROR` logging level being ignored from environment variable :code:`AUTODE_LOG_LEVEL`
+- Fixes :code:`autode.values.Value` instances generating items with units on division, and throw a warning if multiplying
+
 
 1.3.4
 --------


Test patch:
diff --git a/tests/test_value.py b/tests/test_value.py
index 924939e..d2d23a0 100644
--- a/tests/test_value.py
+++ b/tests/test_value.py
@@ -266,3 +266,15 @@ def test_to_wrong_type():
 
     with pytest.raises(Exception):
         _to(Tmp(), units="Å")
+
+
+def test_div_mul_generate_floats():
+
+    e = PotentialEnergy(1.0)
+    assert isinstance(e / e, float)
+    assert isinstance(e // e, float)
+
+    assert e // e == 1
+
+    # Note: this behaviour is not ideal. But it is better than having the wrong units
+    assert isinstance(e * e, float)