Repository: OSeMOSYS/otoole

Issue:
[Bug]: Discount Factor calculation fails if multiple regions are defined 
### The Issue

If you run a multiple region model, the discount factor calculation fails 

### Expected Behavior

_No response_

### Steps To Reproduce

run this test 

```
    def test_df_two_regions(self, region_multiple, year, discount_rate_multiple):

        regions = region_multiple["VALUE"].to_list()
        years = year["VALUE"].to_list()
        actual = discount_factor(regions, years, discount_rate_multiple, 0.0)

        expected = pd.DataFrame(
            data=[
                ["SIMPLICITY", 2014, 1],
                ["SIMPLICITY", 2015, 1.05],
                ["SIMPLICITY", 2016, 1.1025],
                ["SIMPLICITY", 2017, 1.157625],
                ["SIMPLICITY", 2018, 1.21550625],
                ["SIMPLICITY", 2019, 1.276281562],
                ["SIMPLICITY", 2020, 1.340095640],
                ["DUMMY", 2014, 1],
                ["DUMMY", 2015, 1.05],
                ["DUMMY", 2016, 1.1025],
                ["DUMMY", 2017, 1.157625],
                ["DUMMY", 2018, 1.21550625],
                ["DUMMY", 2019, 1.276281562],
                ["DUMMY", 2020, 1.340095640],
            ],
            columns=["REGION", "YEAR", "VALUE"],
        ).set_index(["REGION", "YEAR"])

        assert_frame_equal(actual, expected)
```

with these fixtures 

```
@fixture
def region_multiple():
    return pd.DataFrame(data=["SIMPLICITY", "DUMMY"], columns=["VALUE"])

@fixture
def year():
    return pd.DataFrame(
        data=[2014, 2015, 2016, 2017, 2018, 2019, 2020], columns=["VALUE"]
    )

@fixture
def discount_rate_multiple():
    df = pd.DataFrame(
        data=[
            ["SIMPLICITY", 0.05],
            ["DUMMY", 0.05],
        ],
        columns=["REGION", "VALUE"],
    ).set_index(["REGION"])
    return df
```

### Log output

```shell
FAILED tests/results/test_results_package.py::TestDiscountFactor::test_df_two_regions - ValueError: Length of values (1) does not match length of index (2)
```


### Operating System

Linux

### What version of otoole are you running?

1.1.4

### Possible Solution

_No response_

### Anything else?

_No response_

Discussion:

Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 75233c7..d057917 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -2,6 +2,10 @@
 Changelog
 =========
 
+Version 1.1.5
+=============
+- Correct discount factor calculation for multiple regions
+
 Version 1.1.4
 =============
 - Add result calculations for ``DiscountedCapitalInvestment``, ``DiscountedCostByTechnology``, and ``DiscountedOperationalCost``
diff --git a/src/otoole/results/result_package.py b/src/otoole/results/result_package.py
index acf1b56..d884c5f 100644
--- a/src/otoole/results/result_package.py
+++ b/src/otoole/results/result_package.py
@@ -1216,7 +1216,7 @@ def discount_factor(
         )
 
     if regions and years:
-        discount_rate["YEAR"] = [years]
+        discount_rate["YEAR"] = [years] * len(discount_rate)
         discount_factor = discount_rate.explode("YEAR").reset_index(level="REGION")
         discount_factor["YEAR"] = discount_factor["YEAR"].astype("int64")
         discount_factor["NUM"] = discount_factor["YEAR"] - discount_factor["YEAR"].min()


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index b2522d4..958b3d7 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -65,6 +65,18 @@ def discount_rate():
     return df
 
 
+@fixture
+def discount_rate_multiple_regions():
+    df = pd.DataFrame(
+        data=[
+            ["SIMPLICITY", 0.05],
+            ["DUMMY", 0.05],
+        ],
+        columns=["REGION", "VALUE"],
+    ).set_index(["REGION"])
+    return df
+
+
 @fixture
 def discount_rate_idv():
     df = pd.DataFrame(
diff --git a/tests/results/test_results_package.py b/tests/results/test_results_package.py
index 8b90d5c..3484c90 100644
--- a/tests/results/test_results_package.py
+++ b/tests/results/test_results_package.py
@@ -127,6 +127,11 @@ def region():
     return pd.DataFrame(data=["SIMPLICITY"], columns=["VALUE"])
 
 
+@fixture
+def region_multiple():
+    return pd.DataFrame(data=["SIMPLICITY", "DUMMY"], columns=["VALUE"])
+
+
 @fixture
 def storage():
     return pd.DataFrame(data=["DAM"], columns=["VALUE"])
@@ -1485,6 +1490,36 @@ class TestDiscountFactor:
         with raises(ValueError):
             discount_factor(regions, years, discount_rate_empty, 1.0)
 
+    def test_df_two_regions(
+        self, region_multiple, year, discount_rate_multiple_regions
+    ):
+
+        regions = region_multiple["VALUE"].to_list()
+        years = year["VALUE"].to_list()
+        actual = discount_factor(regions, years, discount_rate_multiple_regions, 0.0)
+
+        expected = pd.DataFrame(
+            data=[
+                ["SIMPLICITY", 2014, 1],
+                ["SIMPLICITY", 2015, 1.05],
+                ["SIMPLICITY", 2016, 1.1025],
+                ["SIMPLICITY", 2017, 1.157625],
+                ["SIMPLICITY", 2018, 1.21550625],
+                ["SIMPLICITY", 2019, 1.276281562],
+                ["SIMPLICITY", 2020, 1.340095640],
+                ["DUMMY", 2014, 1],
+                ["DUMMY", 2015, 1.05],
+                ["DUMMY", 2016, 1.1025],
+                ["DUMMY", 2017, 1.157625],
+                ["DUMMY", 2018, 1.21550625],
+                ["DUMMY", 2019, 1.276281562],
+                ["DUMMY", 2020, 1.340095640],
+            ],
+            columns=["REGION", "YEAR", "VALUE"],
+        ).set_index(["REGION", "YEAR"])
+
+        assert_frame_equal(actual, expected)
+
 
 class TestDiscountFactorStorage:
     def test_dfs_start(self, region, year, discount_rate_storage):