From 09c623943ce83196679caf481976edd48616bd61 Mon Sep 17 00:00:00 2001 From: talbpw Date: Mon, 22 Apr 2024 13:20:26 -0600 Subject: [PATCH 1/5] added individual tools to README --- README.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fcad235c..b89c352e 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,28 @@ ![FORCE](assets/FORCE_logo-color.png) +The Framework for Optimization of ResourCes and Economics is a collection of software tools, models, and datasets acquired and developed under the Integrated Energy Systems (IES) program to enable analysis of technical and economic viability of myriad IES configurations. FORCE is the consolidating interface and data repository for all the IES toolsets ranging from macro technoeconomic analysis to transient process modeling and experimental validation for integrated energy systems. -# FORCE Use Cases +# Tools +The FORCE framework makes use of several distinct tools to enable technical and economic system analysis of integrated energy systems. The three main tools are: +![HYBRID](https://github.com/idaholab/HYBRID/blob/devel/doc/logos/HYBRID_Logo_color.png) + +- [HYBRID](https://github.com/idaholab/HYBRID), which includes technical models of energy systems, + +![ORCA](https://github.com/idaholab/ORCA/blob/main/docs/logo/ORCA_transparent.png) + +- [ORCA](https://github.com/idaholab/ORCA), which provides tools for the real-time optimization of integrated system control, and + +![HERON](https://github.com/idaholab/HERON/blob/devel/logos/HERON_logo_full.png) + +- [HERON](https://github.com/idaholab/HERON), for long-term system cost, portfolio sizing, and dispatch optimization. + +While FORCE is a framework that connects these tools, currently each tool can be used independently for different parts of the integrated energy systems technical and economic analysis. + +## FORCE Use Cases + +In addition to the tools available as part of FORCE, several existing use cases that demonstrate use of FORCE are included by way of example in this code base. These are listed in brief below: | SHORT NAME | DESCRIPTION | REPORT | |:-----------------------------------------:|:---------------------------------------------------------------------------------------------------------------------------:|:-------------------------------------------:| @@ -15,5 +34,5 @@ -# Notes +## Testing The FORCE repo should contain several IES tools. For the FORCE tests in "FORCE/tests/integrations_tests" to work, raven, TEAL, and HERON should be under FORCE. The FORCE tests depend on raven libraries which can be activated as follows: "conda activate raven_libraries" From 4056bcca25df39c72f1f8e23c58a7bcef5c4ce58 Mon Sep 17 00:00:00 2001 From: Dylan McDowell Date: Tue, 30 Apr 2024 13:44:23 -0600 Subject: [PATCH 2/5] Add HERON unit tests --- tests/unit_tests/__init__.py | 0 tests/unit_tests/test_heron.py | 61 ++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 tests/unit_tests/__init__.py create mode 100644 tests/unit_tests/test_heron.py diff --git a/tests/unit_tests/__init__.py b/tests/unit_tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit_tests/test_heron.py b/tests/unit_tests/test_heron.py new file mode 100644 index 00000000..75c15691 --- /dev/null +++ b/tests/unit_tests/test_heron.py @@ -0,0 +1,61 @@ +import unittest +from unittest.mock import mock_open, patch, MagicMock +import xml.etree.ElementTree as ET + +from FORCE.src.heron import create_componentsets_in_HERON + +class TestCreateComponentSetsInHERON(unittest.TestCase): + + def setUp(self): + # Example of a minimal XML structure + self.heron_xml = """ + + + + + 100 + + + + + """ + self.tree = ET.ElementTree(ET.fromstring(self.heron_xml)) + + @patch('xml.etree.ElementTree.parse') + @patch('os.listdir') + @patch('builtins.open', + new_callable=mock_open, + read_data="""{ + "Component Set Name": "NewComponent", + "Reference Driver": 1000, + "Reference Driver Power Units": "kW", + "Reference Price (USD)": 2000, + "Scaling Factor": 0.5 + }""") + def test_new_component_creation(self, mock_file, mock_listdir, mock_parse): + # Setup the mock to return an XML tree + mock_parse.return_value = self.tree + mock_listdir.return_value = ['componentSet1.json'] + + # Call the function + result_tree = create_componentsets_in_HERON("/fake/folder", "/fake/heron_input.xml") + + # Verify the XML was updated correctly + components = result_tree.findall('.//Component[@name="NewComponent"]') + self.assertEqual(len(components), 1) + economics = components[0].find('economics') + self.assertIsNotNone(economics) + + # Verify the CashFlow node was created + cashflows = economics.findall('CashFlow') + self.assertEqual(len(cashflows), 1) + self.assertEqual(cashflows[0].attrib['name'], 'NewComponent_capex') + + # Verify the reference driver and price updates + ref_driver = cashflows[0].find('./reference_driver/fixed_value') + self.assertEqual(ref_driver.text, '1.0') # The driver should have been converted from kW to MW + + # Add more tests here to cover other conditions and edge cases + +if __name__ == '__main__': + unittest.main() From ec97108589c049a3bee18fabd7c4efd13498e1ba Mon Sep 17 00:00:00 2001 From: Dylan McDowell Date: Tue, 30 Apr 2024 13:44:50 -0600 Subject: [PATCH 3/5] Adding unit tests --- src/heron.py | 10 +++++----- tests/__init__.py | 0 2 files changed, 5 insertions(+), 5 deletions(-) create mode 100644 tests/__init__.py diff --git a/src/heron.py b/src/heron.py index 8dfa37fd..9ebd3949 100644 --- a/src/heron.py +++ b/src/heron.py @@ -48,7 +48,7 @@ def create_componentsets_in_HERON(comp_sets_folder, heron_input_xml): heron_comp_list = [] # The list of compoenents for comp in component: heron_comp_list.append(comp.attrib["name"]) # The list of components found in the HERON input XML file - print(f" \n The following components are already in the HERON input XML file:'{heron_comp_list}'") + # print(f" \n The following components are already in the HERON input XML file:'{heron_comp_list}'") comp_set_files_list = os.listdir(comp_sets_folder) @@ -67,11 +67,11 @@ def create_componentsets_in_HERON(comp_sets_folder, heron_input_xml): scaling_factor = comp_set_dict.get('Scaling Factor') fit_error = comp_set_dict.get('Fitting Average Error (%)') - print(f" \n The FORCE component set '{comp_set_name}' is found") + # print(f" \n The FORCE component set '{comp_set_name}' is found") # if the component is already in the HERON file, it gets updated if comp_set_name in heron_comp_list: - print(f"The component set {comp_set_name} already exists in the HERON XML input file. The {comp_set_name} info will be updated") + #print(f"The component set {comp_set_name} already exists in the HERON XML input file. The {comp_set_name} info will be updated") for component in components_list: for comp in component: if comp.attrib["name"] == comp_set_name: @@ -80,7 +80,7 @@ def create_componentsets_in_HERON(comp_sets_folder, heron_input_xml): if node.tag == "economics": ECO_NODE_FOUND = "True" print(f"The 'economics' node is found in the component {comp.attrib['name']} and will be updated.") - + for subnode in node: # If the cashflow node is found if subnode.tag == "CashFlow": @@ -127,7 +127,7 @@ def create_componentsets_in_HERON(comp_sets_folder, heron_input_xml): else: # if the component is not already in the HERON file, it is created. - print(f"The component set '{comp_set_name}' is not found in the HERON XMl input file. The componnent node '{comp_set_name}' will be created") + # print(f"The component set '{comp_set_name}' is not found in the HERON XMl input file. The componnent node '{comp_set_name}' will be created") comp_name_dict = {'name': comp_set_name} for components in components_list: new_comp_node = ET.SubElement(components, "Component", comp_name_dict) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b From 526e6f99b1e6b0eefcd6f47729105d181ce9aeed Mon Sep 17 00:00:00 2001 From: "Botros N. Hanna" Date: Mon, 6 May 2024 08:59:39 -0600 Subject: [PATCH 4/5] change the number of samples and the relative tolerance to fix the diff error --- tests/integration_tests/Aspen_HERON_FullTest/heron_input.xml | 2 +- tests/integration_tests/Aspen_HERON_FullTest/tests | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/integration_tests/Aspen_HERON_FullTest/heron_input.xml b/tests/integration_tests/Aspen_HERON_FullTest/heron_input.xml index a1b1cf8f..ce70f21a 100644 --- a/tests/integration_tests/Aspen_HERON_FullTest/heron_input.xml +++ b/tests/integration_tests/Aspen_HERON_FullTest/heron_input.xml @@ -11,7 +11,7 @@ sweep - 3 + 5 Time 2 diff --git a/tests/integration_tests/Aspen_HERON_FullTest/tests b/tests/integration_tests/Aspen_HERON_FullTest/tests index 71ab300c..6637f62d 100644 --- a/tests/integration_tests/Aspen_HERON_FullTest/tests +++ b/tests/integration_tests/Aspen_HERON_FullTest/tests @@ -38,7 +38,7 @@ [./run_RAVEN] type = OrderedCSV output = 'Runs_o/sweep.csv' - rel_err = 5e-2 + rel_err = 1e-2 [../] [../] [] From b1aea99ed4de7a91a8ebf6b4c8d02a25a925199b Mon Sep 17 00:00:00 2001 From: "Botros N. Hanna" Date: Mon, 6 May 2024 10:04:01 -0600 Subject: [PATCH 5/5] git the sampling error --- .../gold/Runs_o/sweep.csv | 6 +- .../gold/new_heron_input.xml | 4 +- .../Aspen_HERON_FullTest/heron_input.xml | 222 +++++++++--------- .../Aspen_HERON_FullTest/tests | 4 +- 4 files changed, 119 insertions(+), 117 deletions(-) diff --git a/tests/integration_tests/Aspen_HERON_FullTest/gold/Runs_o/sweep.csv b/tests/integration_tests/Aspen_HERON_FullTest/gold/Runs_o/sweep.csv index 74581345..f4f58a36 100644 --- a/tests/integration_tests/Aspen_HERON_FullTest/gold/Runs_o/sweep.csv +++ b/tests/integration_tests/Aspen_HERON_FullTest/gold/Runs_o/sweep.csv @@ -1,3 +1,3 @@ -source_capacity,sink_capacity,mean_NPV,std_NPV,med_NPV,max_NPV,min_NPV,perc_5_NPV,perc_95_NPV,samp_NPV,var_NPV,mean_TotalActivity__source__production__a,mean_TotalActivity__sink__production__a,std_TotalActivity__source__production__a,max_TotalActivity__source__production__a,min_TotalActivity__source__production__a,perc_5_TotalActivity__source__production__a,perc_95_TotalActivity__source__production__a,samp_TotalActivity__source__production__a,var_TotalActivity__source__production__a,var_TotalActivity__sink__production__a,samp_TotalActivity__sink__production__a,perc_95_TotalActivity__sink__production__a,perc_5_TotalActivity__sink__production__a,min_TotalActivity__sink__production__a,max_TotalActivity__sink__production__a,std_TotalActivity__sink__production__a,med_TotalActivity__source__production__a,med_TotalActivity__sink__production__a,ProbabilityWeight,ProbabilityWeight-source_capacity,prefix,PointProbability -1.0,-2.0,-1027240.07054,1.42579068359e-10,-1027240.07054,-1027240.07054,-1027240.07054,-1027240.07054,-1027240.07054,3.0,2.03287907341e-20,40.0,-40.0,0.0,40.0,40.0,40.0,40.0,3.0,0.0,0.0,3.0,-40.0,-40.0,-40.0,-40.0,0.0,40.0,-40.0,0.5,0.5,1,1.0 -2.0,-2.0,-1450800.44634,0.0,-1450800.44634,-1450800.44634,-1450800.44634,-1450800.44634,-1450800.44634,3.0,0.0,80.0,-80.0,0.0,80.0,80.0,80.0,80.0,3.0,0.0,0.0,3.0,-80.0,-80.0,-80.0,-80.0,0.0,80.0,-80.0,0.5,0.5,2,1.0 +source_capacity,sink_capacity,mean_NPV,std_NPV,med_NPV,max_NPV,min_NPV,perc_5_NPV,perc_95_NPV,samp_NPV,var_NPV,mean_TotalActivity__source__production__a,mean_TotalActivity__sink__production__a,std_TotalActivity__source__production__a,max_TotalActivity__source__production__a,min_TotalActivity__source__production__a,perc_5_TotalActivity__source__production__a,perc_95_TotalActivity__source__production__a,samp_TotalActivity__source__production__a,var_TotalActivity__source__production__a,var_TotalActivity__sink__production__a,samp_TotalActivity__sink__production__a,perc_95_TotalActivity__sink__production__a,perc_5_TotalActivity__sink__production__a,min_TotalActivity__sink__production__a,max_TotalActivity__sink__production__a,std_TotalActivity__sink__production__a,med_TotalActivity__source__production__a,med_TotalActivity__sink__production__a,ProbabilityWeight-source_capacity,ProbabilityWeight,PointProbability,prefix +1.0,-2.0,-1027240.07276,1.19439600045e-10,-1027240.07276,-1027240.07276,-1027240.07276,-1027240.07276,-1027240.07276,20.0,1.4265818059e-20,40.0,-40.0,0.0,40.0,40.0,40.0,40.0,20.0,0.0,0.0,20.0,-40.0,-40.0,-40.0,-40.0,0.0,40.0,-40.0,0.5,0.5,1.0,1 +2.0,-2.0,-1450800.44949,2.38879200091e-10,-1450800.44949,-1450800.44949,-1450800.44949,-1450800.44949,-1450800.44949,20.0,5.70632722361e-20,80.0,-80.0,0.0,80.0,80.0,80.0,80.0,20.0,0.0,0.0,20.0,-80.0,-80.0,-80.0,-80.0,0.0,80.0,-80.0,0.5,0.5,1.0,2 diff --git a/tests/integration_tests/Aspen_HERON_FullTest/gold/new_heron_input.xml b/tests/integration_tests/Aspen_HERON_FullTest/gold/new_heron_input.xml index 87a0703f..1494e38c 100644 --- a/tests/integration_tests/Aspen_HERON_FullTest/gold/new_heron_input.xml +++ b/tests/integration_tests/Aspen_HERON_FullTest/gold/new_heron_input.xml @@ -14,7 +14,7 @@ sweep - 3 + 20 Time 2 @@ -58,7 +58,7 @@ - -1428015.4590150523 + -1428015.4587681948 diff --git a/tests/integration_tests/Aspen_HERON_FullTest/heron_input.xml b/tests/integration_tests/Aspen_HERON_FullTest/heron_input.xml index ce70f21a..c8e9abfe 100644 --- a/tests/integration_tests/Aspen_HERON_FullTest/heron_input.xml +++ b/tests/integration_tests/Aspen_HERON_FullTest/heron_input.xml @@ -1,111 +1,111 @@ - - - Cashflows - talbpaul - 2020-10-16 - - Tests various kinds of cashflows - - HERON - - - - sweep - 5 - - Time - 2 - 21 - - - 20 - 0.08 - 0.25 - 0.00 - 50 - - - - - - - - - - - 1, 2 - - - - 30 - - - functions - - - 10000.0 - -1 - - - 10.0 - - - 0.999 - - - - - - functions - - - 100.0 - -1 - - - 10.0 - - - 0.999 - - - - - a - - - -1 - - - - - - - - - -2 - - - - 30 - - - a - - - 10.0 - -3.14 - - - - - - - - arma_30yr.pk - functions.py - - - - - + + + Cashflows + talbpaul + 2020-10-16 + + Tests various kinds of cashflows + + HERON + + + + sweep + 20 + + Time + 2 + 21 + + + 20 + 0.08 + 0.25 + 0.00 + 50 + + + + + + + + + + + 1, 2 + + + + 30 + + + functions + + + 10000.0 + -1 + + + 10.0 + + + 0.999 + + + + + + functions + + + 100.0 + -1 + + + 10.0 + + + 0.999 + + + + + a + + + -1 + + + + + + + + + -2 + + + + 30 + + + a + + + 10.0 + -3.14 + + + + + + + + arma_30yr.pk + functions.py + + + + + diff --git a/tests/integration_tests/Aspen_HERON_FullTest/tests b/tests/integration_tests/Aspen_HERON_FullTest/tests index 6637f62d..1db6f13c 100644 --- a/tests/integration_tests/Aspen_HERON_FullTest/tests +++ b/tests/integration_tests/Aspen_HERON_FullTest/tests @@ -38,7 +38,9 @@ [./run_RAVEN] type = OrderedCSV output = 'Runs_o/sweep.csv' - rel_err = 1e-2 + rel_err = 0.01 + zero_threshold = 1e-9 + [../] [../] []