diff --git a/.bumpversion.cfg b/.bumpversion.cfg index bf393e5b..19d844f3 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 3.5.7 +current_version = 3.6.0 commit = True tag = True diff --git a/.cookiecutterrc b/.cookiecutterrc index 0433782c..c10fa5b6 100644 --- a/.cookiecutterrc +++ b/.cookiecutterrc @@ -54,7 +54,7 @@ default_context: sphinx_doctest: "no" sphinx_theme: "sphinx-py3doc-enhanced-theme" test_matrix_separate_coverage: "no" - version: 3.5.7 + version: 3.6.0 version_manager: "bump2version" website: "https://github.com/NREL" year_from: "2023" diff --git a/.gitignore b/.gitignore index 6e6d6d1c..657ac0d3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ tests/__pycache__ # requirements defined in setup.py requirements.txt -# Temp files +# Temp/output files .*.sw[po] *~ *.bak @@ -15,6 +15,13 @@ requirements.txt *.json all_messages_conf.log HDR.out +src/geophires_x/*.png +src/geophires_x/*.html +*HEATING_COOLING*.png +*CASHFLOW_PROFILE*.png +Geothermal_district_heating_system_with_peaking_boilers.png +*.html +!docs/*.html # C extensions *.so diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 21e743fb..e7b057e9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -5,6 +5,22 @@ Changelog GEOPHIRES-X (2023-2024) ------------------------ +3.6 +^^^ + +`release `__ | `diff `__ + +Changes default output file path to the original working directory instead of the the GEOPHIRES module source directory (usually ``geophires-x`` or ``src/geophires_x``, depending on package installation type). +This affects: + +1. Users who call GEOPHIRES as a script from a working directory outside of the module source directory and pass no output file argument or a non-absolute output file argument e.g. ``python ./geophires-x/GEOPHIRESv3.py my-input.txt``. In prior versions, the output file would have been generated at ``./geophires_x/HDR.out``; in v.3.6 it is generated at ``./HDR.out`` instead. (Users who call GEOPHIRES as a module – ``python -m geophires_x my-input.txt`` – will see no change since the module has always output relative to the working directory.) + +2. Inputs with ``HTML Output File`` and/or ``Improved Text Output File`` parameters specified as non-absolute paths. The associated output files will now be generated relative to the working directory instead of the GEOPHIRES module source directory. + + +Affected users who do not want the new behavior can specify absolute output paths instead of relative ones e.g. ``python ./geophires-x/GEOPHIRESv3.py my-input.txt /home/user/my-geophires-project/geophires-x/HDR.out`` +(Most users are expected to be unaffected.) + 3.5 ^^^ diff --git a/README.rst b/README.rst index ff091e15..dbb86640 100644 --- a/README.rst +++ b/README.rst @@ -51,9 +51,9 @@ Free software: `MIT license `__ :alt: Supported implementations :target: https://pypi.org/project/geophires-x -.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.5.7.svg +.. |commits-since| image:: https://img.shields.io/github/commits-since/softwareengineerprogrammer/GEOPHIRES-X/v3.6.0.svg :alt: Commits since latest release - :target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.5.7...main + :target: https://github.com/softwareengineerprogrammer/GEOPHIRES-X/compare/v3.6.0...main .. |docs| image:: https://readthedocs.org/projects/GEOPHIRES-X/badge/?style=flat :target: https://nrel.github.io/GEOPHIRES-X diff --git a/docs/conf.py b/docs/conf.py index b5eda9bf..0e706ab2 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -18,7 +18,7 @@ year = '2024' author = 'NREL' copyright = f'{year}, {author}' -version = release = '3.5.7' +version = release = '3.6.0' pygments_style = 'trac' templates_path = ['./templates'] diff --git a/setup.py b/setup.py index 34b6d93f..fd546b08 100755 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ def read(*names, **kwargs): setup( name='geophires-x', - version='3.5.7', + version='3.6.0', license='MIT', description='GEOPHIRES is a free and open-source geothermal techno-economic simulator.', long_description='{}\n{}'.format( diff --git a/src/geophires_x/GEOPHIRESv3.py b/src/geophires_x/GEOPHIRESv3.py index 2692f8de..3f22f8e5 100644 --- a/src/geophires_x/GEOPHIRESv3.py +++ b/src/geophires_x/GEOPHIRESv3.py @@ -19,6 +19,8 @@ def main(enable_geophires_logging_config=True): logging will be configured in the Model class. :return: None """ + original_cwd:Path = Path.cwd().absolute() + # set the starting directory to be the directory that this file is in os.chdir(os.path.dirname(os.path.abspath(__file__))) @@ -33,7 +35,7 @@ def main(enable_geophires_logging_config=True): model = Model.Model(enable_geophires_logging_config=enable_geophires_logging_config) # read the parameters that apply to the model - model.read_parameters() + model.read_parameters(default_output_path=original_cwd) # Calculate the entire model model.Calculate() @@ -61,7 +63,7 @@ def main(enable_geophires_logging_config=True): supress_warnings=True) json_merged = {**json_merged, **json.loads(json_sdacgt)} - json_outputfile = 'HDR.json' + json_outputfile = Path(original_cwd, 'HDR.json') if len(sys.argv) > 2: output_arg = str(sys.argv[2]) output_arg_path = Path(output_arg) @@ -71,7 +73,7 @@ def main(enable_geophires_logging_config=True): # if the user has asked for it, copy the output file to the screen if model.outputs.printoutput: - outputfile = 'HDR.out' + outputfile = Path(original_cwd, 'HDR.out') if len(sys.argv) > 2: outputfile = sys.argv[2] diff --git a/src/geophires_x/Model.py b/src/geophires_x/Model.py index 96c463e3..63a48dd9 100644 --- a/src/geophires_x/Model.py +++ b/src/geophires_x/Model.py @@ -1,4 +1,5 @@ import sys +from email.policy import default from pathlib import Path import logging import time @@ -196,9 +197,10 @@ def __init__(self, enable_geophires_logging_config=True, input_file=None): def __str__(self): return "Model" - def read_parameters(self) -> None: + def read_parameters(self, default_output_path: Path = None) -> None: """ The read_parameters function reads the parameters from the input file and stores them in a dictionary. + :param default_output_path: Relative path for non-absolute output path parameters :return: None """ self.logger.info(f'Init {__class__}: {__name__}') @@ -209,17 +211,17 @@ def read_parameters(self) -> None: self.wellbores.read_parameters(self) self.surfaceplant.read_parameters(self) self.economics.read_parameters(self) - self.outputs.read_parameters(self) + self.outputs.read_parameters(self, default_output_path=default_output_path) # having read in the parameters, we now need to set up the objects that are specific to the user's choices # if we find out we have an add-ons, read the parameters if self.economics.DoAddOnCalculations.value: self.addeconomics.read_parameters(self) - self.addoutputs.read_parameters(self) + self.addoutputs.read_parameters(self, default_output_path=default_output_path) # if we find out we have an S-DAC-GT calculation, read for the parameters if self.economics.DoSDACGTCalculations.value: self.sdacgteconomics.read_parameters(self) - self.sdacgtoutputs.read_parameters(self) + self.sdacgtoutputs.read_parameters(self, default_output_path=default_output_path) # Once we are done reading and processing parameters, # we reset the objects to more specific objects based on user choices diff --git a/src/geophires_x/Outputs.py b/src/geophires_x/Outputs.py index 006e0125..271c7bac 100644 --- a/src/geophires_x/Outputs.py +++ b/src/geophires_x/Outputs.py @@ -22,6 +22,7 @@ from geophires_x.OptionList import EndUseOptions, EconomicModel, ReservoirModel, FractureShape, ReservoirVolume, \ PlantType from geophires_x.GeoPHIRESUtils import UpgradeSymbologyOfUnits, render_default, InsertImagesIntoHTML +from geophires_x.Parameter import Parameter NL = '\n' validFilenameChars = "-_.() %s%s" % (string.ascii_letters, string.digits) @@ -635,28 +636,34 @@ class Outputs: """ This class handles all the outputs for the GEOPHIRESv3 model. """ + def __init__(self, model:Model, output_file:str ='HDR.out'): model.logger.info(f'Init {__class__!s}: {__name__}') self.ParameterDict = {} self.OutputParameterDict = {} + self.filepath_parameter_names = [] + + def filepath_parameter(p: Parameter) -> Parameter: + self.filepath_parameter_names.append(p.Name) + return p - self.text_output_file = self.ParameterDict[self.text_output_file.Name] = strParameter( + self.text_output_file = self.ParameterDict[self.text_output_file.Name] = filepath_parameter(strParameter( 'Improved Text Output File', DefaultValue='GEOPHIRES_Text.html', Required=False, Provided=False, ErrMessage='assume no improved text output', ToolTipText='Provide a improved text output name if you want to have improved text output (no output if not provided)', - ) + )) - self.html_output_file = self.ParameterDict[self.html_output_file.Name] = strParameter( + self.html_output_file = self.ParameterDict[self.html_output_file.Name] = filepath_parameter(strParameter( 'HTML Output File', DefaultValue='GEOPHIRES.html', Required=False, Provided=False, ErrMessage='assume no HTML output', ToolTipText='Provide a HTML output name if you want to have HTML output (no output if not provided)', - ) + )) self.printoutput = self.ParameterDict[self.printoutput.Name] = boolParameter( 'Print Output to Console', @@ -677,7 +684,7 @@ def __init__(self, model:Model, output_file:str ='HDR.out'): def __str__(self): return 'Outputs' - def read_parameters(self, model:Model) -> None: + def read_parameters(self, model: Model, default_output_path: Path = None) -> None: """ The read_parameters function reads in the parameters from a dictionary and stores them in the parameters. It also handles special cases that need to be handled after a value has been read in and checked. @@ -692,6 +699,8 @@ def read_parameters(self, model:Model) -> None: to call this method from you class, which can effectively modify all these superclass parameters in your class. :param model: The container class of the application, giving access to everything else, including the logger :type model: :class:`~geophires_x.Model.Model` + :param default_output_path: Relative path for non-absolute output path parameters + :type default_output_path: pathlib.Path :return: None """ model.logger.info(f'Init {__class__!s}: {__name__}') @@ -702,6 +711,15 @@ def read_parameters(self, model:Model) -> None: key = ParameterToModify.Name.strip() if key in model.InputParameters: ParameterReadIn = model.InputParameters[key] + + if key in self.filepath_parameter_names: + if not Path(ParameterReadIn.sValue).is_absolute() and default_output_path is not None: + original_val = ParameterReadIn.sValue + ParameterReadIn.sValue = str( + default_output_path.joinpath(Path(ParameterReadIn.sValue)).absolute()) + model.logger.info(f'Adjusted {key} path to {ParameterReadIn.sValue} because original value ' + f'({original_val}) was not an absolute path.') + # Before we change the parameter, let's assume that the unit preferences will match # - if they don't, the later code will fix this. ParameterToModify.CurrentUnits = ParameterToModify.PreferredUnits @@ -724,8 +742,6 @@ def read_parameters(self, model:Model) -> None: if key.startswith('Units:'): self.ParameterDict[key.replace('Units:', '')] = LookupUnits(model.InputParameters[key].sValue)[0] - # handle special cases - model.logger.info(f'Complete {__class__!s}: {__name__}') def PrintOutputs(self, model: Model): diff --git a/src/geophires_x/SUTRAOutputs.py b/src/geophires_x/SUTRAOutputs.py index 023adea3..b6c2a15c 100644 --- a/src/geophires_x/SUTRAOutputs.py +++ b/src/geophires_x/SUTRAOutputs.py @@ -5,13 +5,13 @@ import geophires_x import numpy as np import geophires_x.Model as Model -from .Parameter import LookupUnits +from geophires_x.Outputs import Outputs from .OptionList import EconomicModel NL="\n" -class SUTRAOutputs: - """TODO should inherit from Outputs""" + +class SUTRAOutputs(Outputs): def __init__(self, model:Model, output_file:str ='HDR.out'): """ @@ -35,45 +35,8 @@ def __init__(self, model:Model, output_file:str ='HDR.out'): model.logger.info(f'Complete {str(__class__)}: {sys._getframe().f_code.co_name}') def __str__(self): - return 'Outputs' + return 'SUTRAOutputs' - def read_parameters(self, model:Model) -> None: - """ - The read_parameters function reads in the parameters from a dictionary and stores them in the parameters. - It also handles special cases that need to be handled after a value has been read in and checked. - If you choose to subclass this master class, you can also choose to override this method (or not), and if you do - Deals with all the parameter values that the user has provided. They should really only provide values that - they want to change from the default values, but they can provide a value that is already set because it is a - default value set in __init__. It will ignore those. - This also deals with all the special cases that need to be taken care of after a value has been read in - and checked. - If you choose to subclass this master class, you can also choose to override this method (or not), - and if you do, do it before or after you call you own version of this method. If you do, you can also choose - to call this method from you class, which can effectively modify all these superclass parameters in your class. - :param model: The container class of the application, giving access to everything else, including the logger - :type model: :class:`~geophires_x.Model.Model` - :return: None - """ - model.logger.info(f'Init {str(__class__)}: {sys._getframe().f_code.co_name}') - - if len(model.InputParameters) > 0: - # if the user wants it, we need to know if the user wants to copy the contents of the - # output file to the screen - this serves as the screen report - if "Print Output to Console" in model.InputParameters: - ParameterReadIn = model.InputParameters["Print Output to Console"] - if ParameterReadIn.sValue == "0": - self.printoutput = False - - # loop through all the parameters that the user wishes to set, looking for parameters that contain the - # prefix "Units:" - that means we want to set a special case for converting this - # output parameter to new units - for key in model.InputParameters.keys(): - if key.startswith("Units:"): - self.ParameterDict[key.replace("Units:", "")] = LookupUnits(model.InputParameters[key].sValue)[0] - - # handle special cases - - model.logger.info(f'Complete {str(__class__)}: {sys._getframe().f_code.co_name}') def PrintOutputs(self, model: Model): """ @@ -84,30 +47,8 @@ def PrintOutputs(self, model: Model): """ model.logger.info(f'Init {str(__class__)}: {sys._getframe().f_code.co_name}') - # Deal with converting Units back to PreferredUnits, if required. - # before we write the outputs, we go thru all the parameters for all of the objects and set the values back - # to the units that the user entered the data in - # We do this because the value may be displayed in the output, and we want the user to recognize their value, - # not some converted value - # for obj in [model.reserv, model.wellbores, model.surfaceplant, model.economics]: - # for key in obj.ParameterDict: - # param = obj.ParameterDict[key] - # if not param.UnitsMatch: ConvertUnitsBack(param, model) - - # now we need to loop through all thw output parameters to update their units to - # whatever units the user has specified. - # i.e., they may have specified that all LENGTH results must be in feet, so we need to convert those - # from whatever LENGTH unit they are to feet. - # same for all the other classes of units (TEMPERATURE, DENSITY, etc). - - #for obj in [model.reserv, model.wellbores, model.surfaceplant, model.economics]: - # for key in obj.OutputParameterDict: - # if key in self.ParameterDict: - # if self.ParameterDict[key] != obj.OutputParameterDict[key].CurrentUnits: - # ConvertOutputUnits(obj.OutputParameterDict[key], self.ParameterDict[key], model) # write results to output file and screen - try: with open(self.output_file,'w', encoding='UTF-8') as f: f.write(' *****************\n') @@ -218,10 +159,10 @@ def PrintOutputs(self, model: Model): except BaseException as ex: tb = sys.exc_info()[2] print(str(ex)) - print("Error: GEOPHIRES Failed to write the output file. Exiting....Line %i" % tb.tb_lineno) + msg = "Error: GEOPHIRES Failed to write the output file. Exiting....Line %i" % tb.tb_lineno + print(msg) model.logger.critical(str(ex)) - model.logger.critical("Error: GEOPHIRES Failed to write the output file. Exiting....Line %i" % tb.tb_lineno) - # FIXME raise exception instead of sys.exit() - sys.exit() + model.logger.critical(msg) + raise RuntimeError(msg) model.logger.info(f'Complete {str(__class__)}: {sys._getframe().f_code.co_name}') diff --git a/src/geophires_x/__init__.py b/src/geophires_x/__init__.py index aa89269e..826cf62c 100644 --- a/src/geophires_x/__init__.py +++ b/src/geophires_x/__init__.py @@ -1 +1 @@ -__version__ = '3.5.7' +__version__ = '3.6.0' diff --git a/tests/examples/Beckers_et_al_2023_Tabulated_Database_Coaxial_water_heat.txt b/tests/examples/Beckers_et_al_2023_Tabulated_Database_Coaxial_water_heat.txt index 24962050..2c5caec2 100644 --- a/tests/examples/Beckers_et_al_2023_Tabulated_Database_Coaxial_water_heat.txt +++ b/tests/examples/Beckers_et_al_2023_Tabulated_Database_Coaxial_water_heat.txt @@ -15,7 +15,7 @@ Exploration Capital Cost, 0 Production Flow Rate per Well, 20, ---- kg/s for water / 40 kg/s for sCO2 Cylindrical Reservoir Input Depth, 3.0, -----kilometers Gradient 1, 60.0, ----deg.c/km -Total Nonvertical Length, 9000, ----- m +Nonvertical Length per Multilateral Section, 9000, ----- m Production Well Diameter,8.5, --- [inch] Reservoir Depth, 3.0, -----kilometers Injection Temperature, 60.0, -----deg.C diff --git a/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_sCO2_elec.txt b/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_sCO2_elec.txt index ee3bc36a..d4e54693 100644 --- a/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_sCO2_elec.txt +++ b/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_sCO2_elec.txt @@ -15,7 +15,7 @@ All-in Nonvertical Drilling Costs, 1000.0 Production Flow Rate per Well, 40, ---- kg/s for water / 40 kg/s for sCO2 Cylindrical Reservoir Input Depth, 3000.0 meter, Gradient 1, 60.0, ----deg.c/km -Total Nonvertical Length, 9000 +Nonvertical Length per Multilateral Section, 9000 Production Well Diameter,8.5, --- [inch] Injection Temperature, 60.0, -----deg.C Plant Lifetime, 40, --- years diff --git a/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_sCO2_heat.txt b/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_sCO2_heat.txt index 3ef8ddda..83c05451 100644 --- a/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_sCO2_heat.txt +++ b/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_sCO2_heat.txt @@ -16,7 +16,7 @@ Exploration Capital Cost, 0 Production Flow Rate per Well, 40, ---- kg/s for water / 40 kg/s for sCO2 Cylindrical Reservoir Input Depth, 3.0, -----kilometers Gradient 1, 60.0, ----deg.c/km -Total Nonvertical Length, 9000, ----- m +Nonvertical Length per Multilateral Section, 9000, ----- m Production Well Diameter,8.5, --- [inch] Injection Temperature, 60.0, -----deg.C Plant Lifetime, 40, --- years diff --git a/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_water_elec.txt b/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_water_elec.txt index 4b709ee3..80eb0d2e 100644 --- a/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_water_elec.txt +++ b/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_water_elec.txt @@ -15,7 +15,7 @@ Production Flow Rate per Well, 20, ---- kg/s for water / 40 kg/s for sCO2 Cylindrical Reservoir Input Depth, 3000.0 meter, Reservoir Depth, 3.0, -----kilometers Gradient 1, 60.0, ----deg.c/km -Total Nonvertical Length, 9000, ----- m +Nonvertical Length per Multilateral Section, 9000, ----- m Production Well Diameter,8.5, --- [inch] Injection Temperature, 60.0, -----deg.C Plant Lifetime, 40, --- years diff --git a/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_water_heat.txt b/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_water_heat.txt index 2bdd5f9d..310adcc6 100644 --- a/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_water_heat.txt +++ b/tests/examples/Beckers_et_al_2023_Tabulated_Database_Uloop_water_heat.txt @@ -15,7 +15,7 @@ Exploration Capital Cost, 0 Production Flow Rate per Well, 20, ---- kg/s for water / 40 kg/s for sCO2 Cylindrical Reservoir Input Depth, 3.0, -----kilometers Gradient 1, 60.0, ----deg.c/km -Total Nonvertical Length, 9000, ----- m +Nonvertical Length per Multilateral Section, 9000, ----- m Production Well Diameter,8.5, --- [inch] Reservoir Depth, 3.0, -----kilometers Injection Temperature, 60.0, -----deg.C diff --git a/tests/examples/Fervo_Norbeck_Latimer_2023.txt b/tests/examples/Fervo_Norbeck_Latimer_2023.txt index 2b0309f0..c22658f3 100644 --- a/tests/examples/Fervo_Norbeck_Latimer_2023.txt +++ b/tests/examples/Fervo_Norbeck_Latimer_2023.txt @@ -31,7 +31,7 @@ Well Geometry Configuration, 4 Has Nonvertical Section, True Multilaterals Cased, True Number of Multilateral Sections, 2, Two parallel horizontal sections -Total Nonvertical Length, 3250 feet, per the paper +Nonvertical Length per Multilateral Section, 3250 feet, per the paper Well Drilling Cost Correlation, 10, per the drill cost paper - works out to $400/ft Horizontal Well Drilling Cost Correlation, 10, per the drill cost paper - works out to $400/ft Production Flow Rate per Well, 41.02, =650 gpm per the paper - per the paper the maximum flow rate was 63 L/s but the range was 550-750 gpm diff --git a/tests/examples/Fervo_Project_Cape.txt b/tests/examples/Fervo_Project_Cape.txt index 5f8e45a4..f241f781 100644 --- a/tests/examples/Fervo_Project_Cape.txt +++ b/tests/examples/Fervo_Project_Cape.txt @@ -21,7 +21,7 @@ Well Geometry Configuration, 4 Has Nonvertical Section, True Multilaterals Cased, True Number of Multilateral Sections, 2 -Total Nonvertical Length, 5000 feet +Nonvertical Length per Multilateral Section, 5000 feet Production Flow Rate per Well, 98 Production Well Diameter, 8 Injection Well Diameter, 8 diff --git a/tests/examples/Wanju_Yuan_Closed-Loop_Geothermal_Energy_Recovery.txt b/tests/examples/Wanju_Yuan_Closed-Loop_Geothermal_Energy_Recovery.txt index 8c890d9c..fcc9fb69 100644 --- a/tests/examples/Wanju_Yuan_Closed-Loop_Geothermal_Energy_Recovery.txt +++ b/tests/examples/Wanju_Yuan_Closed-Loop_Geothermal_Energy_Recovery.txt @@ -12,7 +12,7 @@ Multilaterals Cased, True Well Geometry Configuration, 1, ----U-loop (could be Eavor style) Plant Lifetime, 40, ---Years Water Thermal Conductivity, 0.65 -Total Nonvertical Length, 5001.0 +Nonvertical Length per Multilateral Section, 5001.0 Nonvertical Wellbore Diameter, 0.23495, -----m Cylindrical Reservoir Radius of Effect Factor, 5.0 Closed Loop Calculation Start Year, 0.1 diff --git a/tests/examples/example12_DH.txt b/tests/examples/example12_DH.txt index 48955c28..d121470f 100644 --- a/tests/examples/example12_DH.txt +++ b/tests/examples/example12_DH.txt @@ -60,3 +60,4 @@ Fracture Height, 300 Fracture Width, 200 Fracture Shape, 4 Well Drilling and Completion Capital Cost, 12 +HTML Output File, example12_DH.html diff --git a/tests/geophires_x_tests/test_outputs.py b/tests/geophires_x_tests/test_outputs.py new file mode 100644 index 00000000..5cd6c9a2 --- /dev/null +++ b/tests/geophires_x_tests/test_outputs.py @@ -0,0 +1,45 @@ +import os +import sys +from pathlib import Path + +from geophires_x.Model import Model +from geophires_x_client import GeophiresInputParameters +from tests.base_test_case import BaseTestCase + + +class OutputsTestCase(BaseTestCase): + + def test_relative_output_file_path(self): + input_file = GeophiresInputParameters({'HTML Output File': 'foo.html'}).as_file_path() + m = self._new_model(input_file=input_file, original_cwd=Path('/tmp/')) # noqa: S108 + html_filepath = Path(m.outputs.html_output_file.value) + self.assertTrue(html_filepath.is_absolute()) + self.assertEqual(str(html_filepath).replace('D:', ''), str(Path('/tmp/foo.html'))) # noqa: S108 + + def test_absolute_output_file_path(self): + input_file = GeophiresInputParameters( + {'HTML Output File': '/home/user/my-geophires-project/foo.html'} + ).as_file_path() + m = self._new_model(input_file=input_file, original_cwd=Path('/tmp/')) # noqa: S108 + html_filepath = Path(m.outputs.html_output_file.value) + self.assertTrue(html_filepath.is_absolute()) + self.assertEqual(str(html_filepath).replace('D:', ''), str(Path('/home/user/my-geophires-project/foo.html'))) + + def _new_model(self, input_file=None, original_cwd=None) -> Model: + stash_cwd = Path.cwd() + stash_sys_argv = sys.argv + + sys.argv = [''] + + if input_file is not None: + sys.argv.append(input_file) + + m = Model(enable_geophires_logging_config=False) + + if input_file is not None: + m.read_parameters(default_output_path=original_cwd) + + sys.argv = stash_sys_argv + os.chdir(stash_cwd) + + return m