Repository: OSeMOSYS/otoole

Issue:
[Bug]: Calculation of `CapitalInvestment` fails if `DiscountRateIdv` not defined in configuration file 
### The Issue

When running otoole to convert UTOPIA results calculated by CBC I get an error. When putting a print statement in `result_package.py` in line 315 for the `DiscountRate` the df seems to be empty. 

### Expected Behavior

In UTOPIA the `DiscountRateIdv` is not defined. Hence, otoole should take the `DiscountRate`.

### Steps To Reproduce

_No response_

### Log output

_No response_

### Operating System

MacOS

### What version of otoole are you running?

1.1.2.post1.dev25+gc3331f2

### Possible Solution

_No response_

### Anything else?

_No response_

Discussion:

Patch:
diff --git a/src/otoole/results/result_package.py b/src/otoole/results/result_package.py
index c961d5e..8a70bdd 100644
--- a/src/otoole/results/result_package.py
+++ b/src/otoole/results/result_package.py
@@ -307,11 +307,14 @@ class ResultsPackage(Mapping):
             capital_cost = self["CapitalCost"]
             new_capacity = self["NewCapacity"]
             operational_life = self["OperationalLife"]
+            discount_rate = self["DiscountRate"]
 
             if "DiscountRateIdv" in self.keys():
-                discount_rate = self["DiscountRateIdv"]
+                discount_rate_idv = self["DiscountRateIdv"]
+                if discount_rate_idv.empty:
+                    discount_rate_idv = self["DiscountRate"]
             else:
-                discount_rate = self["DiscountRate"]
+                discount_rate_idv = self["DiscountRate"]
 
             regions = self["REGION"]["VALUE"].to_list()
             technologies = self.get_unique_values_from_index(
@@ -326,7 +329,7 @@ class ResultsPackage(Mapping):
             raise KeyError(self._msg("CapitalInvestment", str(ex)))
 
         crf = capital_recovery_factor(
-            regions, technologies, discount_rate, operational_life
+            regions, technologies, discount_rate_idv, operational_life
         )
         pva = pv_annuity(regions, technologies, discount_rate, operational_life)
         capital_investment = capital_cost.mul(new_capacity, fill_value=0.0)


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index d22edb5..b2522d4 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -68,7 +68,7 @@ def discount_rate():
 @fixture
 def discount_rate_idv():
     df = pd.DataFrame(
-        data=[["SIMPLICITY", "GAS_EXTRACTION", 0.05], ["SIMPLICITY", "DUMMY", 0.05]],
+        data=[["SIMPLICITY", "GAS_EXTRACTION", 0.10], ["SIMPLICITY", "DUMMY", 0.10]],
         columns=["REGION", "TECHNOLOGY", "VALUE"],
     ).set_index(["REGION", "TECHNOLOGY"])
     return df
diff --git a/tests/results/test_results_package.py b/tests/results/test_results_package.py
index 418599c..a597d4e 100644
--- a/tests/results/test_results_package.py
+++ b/tests/results/test_results_package.py
@@ -177,6 +177,22 @@ def total_capacity():
     return data
 
 
+@fixture
+def capital_cost():
+    df = pd.DataFrame(
+        data=[
+            ["SIMPLICITY", "GAS_EXTRACTION", 2014, 1.23],
+            ["SIMPLICITY", "GAS_EXTRACTION", 2015, 2.34],
+            ["SIMPLICITY", "GAS_EXTRACTION", 2016, 3.45],
+            ["SIMPLICITY", "DUMMY", 2014, 4.56],
+            ["SIMPLICITY", "DUMMY", 2015, 5.67],
+            ["SIMPLICITY", "DUMMY", 2016, 6.78],
+        ],
+        columns=["REGION", "TECHNOLOGY", "YEAR", "VALUE"],
+    ).set_index(["REGION", "TECHNOLOGY", "YEAR"])
+    return df
+
+
 @fixture
 def fixed_cost():
     data = pd.DataFrame(
@@ -621,6 +637,108 @@ class TestComputeTotalAnnualCapacity:
         )
 
 
+class TestCapitalInvestment:
+    def test_calculate_captital_investment_with_dr_idv(
+        self,
+        capital_cost,
+        new_capacity,
+        operational_life,
+        region,
+        year,
+        discount_rate,
+        discount_rate_idv,
+    ):
+
+        results = {
+            "CapitalCost": capital_cost,
+            "NewCapacity": new_capacity,
+            "OperationalLife": operational_life,
+            "REGION": region,
+            "YEAR": year,
+            "DiscountRate": discount_rate,
+            "DiscountRateIdv": discount_rate_idv,
+        }
+
+        package = ResultsPackage(results)
+        actual = package.capital_investment()
+        expected = pd.DataFrame(
+            data=[
+                ["SIMPLICITY", "DUMMY", 2014, 4.2898413],
+                ["SIMPLICITY", "GAS_EXTRACTION", 2014, 1.6352585],
+                ["SIMPLICITY", "GAS_EXTRACTION", 2016, 5.6451702],
+            ],
+            columns=["REGION", "TECHNOLOGY", "YEAR", "VALUE"],
+        ).set_index(["REGION", "TECHNOLOGY", "YEAR"])
+
+        assert_frame_equal(actual, expected)
+
+    def test_calculate_captital_investment_empty_dr_idv(
+        self,
+        capital_cost,
+        new_capacity,
+        operational_life,
+        region,
+        year,
+        discount_rate,
+        discount_rate_idv_empty,
+    ):
+
+        results = {
+            "CapitalCost": capital_cost,
+            "NewCapacity": new_capacity,
+            "OperationalLife": operational_life,
+            "REGION": region,
+            "YEAR": year,
+            "DiscountRate": discount_rate,
+            "DiscountRateIdv": discount_rate_idv_empty,
+        }
+
+        package = ResultsPackage(results)
+        actual = package.capital_investment()
+        expected = pd.DataFrame(
+            data=[
+                ["SIMPLICITY", "DUMMY", 2014, 4.104],
+                ["SIMPLICITY", "GAS_EXTRACTION", 2014, 1.599],
+                ["SIMPLICITY", "GAS_EXTRACTION", 2016, 5.52],
+            ],
+            columns=["REGION", "TECHNOLOGY", "YEAR", "VALUE"],
+        ).set_index(["REGION", "TECHNOLOGY", "YEAR"])
+
+        assert_frame_equal(actual, expected)
+
+    def test_calculate_captital_investment_no_dr_idv(
+        self,
+        capital_cost,
+        new_capacity,
+        operational_life,
+        region,
+        year,
+        discount_rate,
+    ):
+
+        results = {
+            "CapitalCost": capital_cost,
+            "NewCapacity": new_capacity,
+            "OperationalLife": operational_life,
+            "REGION": region,
+            "YEAR": year,
+            "DiscountRate": discount_rate,
+        }
+
+        package = ResultsPackage(results)
+        actual = package.capital_investment()
+        expected = pd.DataFrame(
+            data=[
+                ["SIMPLICITY", "DUMMY", 2014, 4.104],
+                ["SIMPLICITY", "GAS_EXTRACTION", 2014, 1.599],
+                ["SIMPLICITY", "GAS_EXTRACTION", 2016, 5.52],
+            ],
+            columns=["REGION", "TECHNOLOGY", "YEAR", "VALUE"],
+        ).set_index(["REGION", "TECHNOLOGY", "YEAR"])
+
+        assert_frame_equal(actual, expected)
+
+
 class TestCapitalRecoveryFactor:
     def test_crf(self, region, discount_rate_idv, operational_life):
 
@@ -632,8 +750,8 @@ class TestCapitalRecoveryFactor:
 
         expected = pd.DataFrame(
             data=[
-                ["SIMPLICITY", "GAS_EXTRACTION", 0.512195121],
-                ["SIMPLICITY", "DUMMY", 0.349722442],
+                ["SIMPLICITY", "GAS_EXTRACTION", 0.523809523],
+                ["SIMPLICITY", "DUMMY", 0.365558912],
             ],
             columns=["REGION", "TECHNOLOGY", "VALUE"],
         ).set_index(["REGION", "TECHNOLOGY"])