diff --git a/CHANGELOG.md b/CHANGELOG.md index e44216e9..3d6ea59e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -88,3 +88,11 @@ - Fix bug in function clean_and_space_equally_time_series #111 - v0.3.11 - Add dymola_exe_path to set of kwargs in DymolaAPI #115 +- v0.3.12 + - Port handling Add dymola_exe_path to set of kwargs in DymolaAPI #118 +- v0.3.13 + - Fixes in simulate options and add Dymola CI tests #28, #113, #117 +- v0.3.14 + - Fix retranslation #121 + - refactor cd to working_directory #61 + - Propagate `names` of simres to TimeSeriesData to speed up mat-loading diff --git a/ebcpy/__init__.py b/ebcpy/__init__.py index 890890b6..11110b7c 100644 --- a/ebcpy/__init__.py +++ b/ebcpy/__init__.py @@ -8,4 +8,4 @@ from .optimization import Optimizer -__version__ = '0.3.13' +__version__ = '0.3.14' diff --git a/ebcpy/data_types.py b/ebcpy/data_types.py index 6414a8fd..811d7fb8 100644 --- a/ebcpy/data_types.py +++ b/ebcpy/data_types.py @@ -82,7 +82,10 @@ class TimeSeriesData(pd.DataFrame): :keyword str engine: Chose the engine for reading .parquet files. Default is 'pyarrow' Other option is 'fastparquet' (python>=3.9). - + :keyword list variable_names: + List of variable names to load from .mat file. If you + know which variables you want to plot, this may speed up + loading significantly, and reduce memory size drastically. Examples: @@ -317,7 +320,11 @@ def _load_df_from_file(self, file): header=self._loader_kwargs.get("header", _hea_def) ) elif file.suffix == ".mat": - df = sr.mat_to_pandas(fname=file, with_unit=False) + df = sr.mat_to_pandas( + fname=file, + with_unit=False, + names=self._loader_kwargs.get("variable_names") + ) elif file.suffix in ['.xlsx', '.xls', '.odf', '.ods', '.odt']: sheet_name = self._loader_kwargs.get("sheet_name") if sheet_name is None: diff --git a/ebcpy/modelica/simres.py b/ebcpy/modelica/simres.py index d3731954..dad8320e 100644 --- a/ebcpy/modelica/simres.py +++ b/ebcpy/modelica/simres.py @@ -294,6 +294,10 @@ def mat_to_pandas(fname='dsres.mat', if names: if 'Time' not in names: names.append('Time') + non_existing_variables = list(set(names).difference(_variables.keys())) + if non_existing_variables: + raise KeyError(f"The following variable names are not in the given .mat file: " + f"{', '.join(non_existing_variables)}") else: names = _variables.keys() diff --git a/ebcpy/optimization.py b/ebcpy/optimization.py index 213f2394..1f13b5bf 100644 --- a/ebcpy/optimization.py +++ b/ebcpy/optimization.py @@ -3,6 +3,8 @@ Calibrator.""" import os +from pathlib import Path +import warnings from typing import List, Tuple, Union from collections import namedtuple from abc import abstractmethod @@ -24,7 +26,7 @@ class Optimizer: self.optimize(). - :param str,os.path.normpath cd: + :param str,Path working_directory: Directory for storing all output of optimization via a logger. :keyword list bounds: The boundaries for the optimization variables. @@ -40,14 +42,17 @@ class Optimizer: # Can be used, but will enlarge runtime _obj_his = [] - def __init__(self, cd=None, **kwargs): + def __init__(self, working_directory: Union[Path, str] = None, **kwargs): """Instantiate class parameters""" - if cd is None: - self._cd = None + if working_directory is None and "cd" in kwargs: + warnings.warn("cd was renamed to working_directory in all classes. Use working_directory instead.", category=DeprecationWarning) + self.working_directory = kwargs["cd"] + elif working_directory is None: + self._working_directory = None else: - self.cd = cd + self.working_directory = working_directory - self.logger = setup_logger(cd=self.cd, name=self.__class__.__name__) + self.logger = setup_logger(working_directory=self.working_directory, name=self.__class__.__name__) # Set kwargs self.bounds = kwargs.get("bounds", None) @@ -93,15 +98,27 @@ def supported_frameworks(self): "pymoo"] @property - def cd(self) -> str: + def working_directory(self) -> Path: """The current working directory""" - return self._cd + return self._working_directory - @cd.setter - def cd(self, cd: str): + @working_directory.setter + def working_directory(self, working_directory: Union[Path, str]): """Set current working directory""" - os.makedirs(cd, exist_ok=True) - self._cd = cd + if isinstance(working_directory, str): + working_directory = Path(working_directory) + os.makedirs(working_directory, exist_ok=True) + self._working_directory = working_directory + + @property + def cd(self) -> Path: + warnings.warn("cd was renamed to working_directory in all classes. Use working_directory instead instead.", category=DeprecationWarning) + return self.working_directory + + @cd.setter + def cd(self, cd: Union[Path, str]): + warnings.warn("cd was renamed to working_directory in all classes. Use working_directory instead instead.", category=DeprecationWarning) + self.working_directory = cd @property def bounds(self) -> List[Union[Tuple, List]]: diff --git a/ebcpy/simulationapi/__init__.py b/ebcpy/simulationapi/__init__.py index a75d9b71..a904a952 100644 --- a/ebcpy/simulationapi/__init__.py +++ b/ebcpy/simulationapi/__init__.py @@ -10,6 +10,7 @@ import sys import itertools import time +from pathlib import Path from datetime import timedelta from typing import Dict, Union, TypeVar, Any, List from abc import abstractmethod @@ -145,7 +146,7 @@ class SimulationAPI: """Base-class for simulation apis. Every simulation-api class must inherit from this class. It defines the structure of each class. - :param str,os.path.normpath cd: + :param str,Path working_directory: Working directory path :param str model_name: Name of the model being simulated. @@ -162,13 +163,18 @@ class SimulationAPI: 'pool', ] - def __init__(self, cd, model_name, **kwargs): + def __init__(self, working_directory: Union[Path, str], model_name: str, **kwargs): # Private helper attrs for multiprocessing self._n_sim_counter = 0 self._n_sim_total = 0 self._progress_int = 0 + # Handle deprecation warning + self.working_directory = working_directory + self.logger = setup_logger( + working_directory=self.working_directory, + name=self.__class__.__name__ + ) # Setup the logger - self.logger = setup_logger(cd=cd, name=self.__class__.__name__) self.logger.info(f'{"-" * 25}Initializing class {self.__class__.__name__}{"-" * 25}') # Check multiprocessing self.n_cpu = kwargs.get("n_cpu", 1) @@ -185,7 +191,6 @@ def __init__(self, cd, model_name, **kwargs): self.use_mp = False # Setup the model self._sim_setup = self._sim_setup_class() - self.cd = cd self.inputs: Dict[str, Variable] = {} # Inputs of model self.outputs: Dict[str, Variable] = {} # Outputs of model self.parameters: Dict[str, Variable] = {} # Parameter of model @@ -258,7 +263,7 @@ def simulate(self, Only variables specified in result_names will be returned. - 'savepath': Returns the savepath where the results are stored. Depending on the API, different kwargs may be used to specify file type etc. - :keyword str,os.path.normpath savepath: + :keyword str,Path savepath: If path is provided, the relevant simulation results will be saved in the given directory. For multiple parameter variations also a list of savepaths for each parameterset can be specified. @@ -302,14 +307,14 @@ def simulate(self, # Handle special case for saving files: if return_option == "savepath" and n_simulations > 1: savepath = kwargs.get("savepath", []) - if isinstance(savepath, (str, os.PathLike)): + if isinstance(savepath, (str, os.PathLike, Path)): savepath = [savepath] * n_simulations result_file_name = kwargs.get("result_file_name", []) if isinstance(result_file_name, str): result_file_name = [result_file_name] * n_simulations if len(savepath) != len(result_file_name): raise ValueError("Given savepath and result_file_name " - "have not the same lenght.") + "have not the same length.") joined_save_paths = [] for _single_save_path, _single_result_name in zip(savepath, result_file_name): joined_save_paths.append(os.path.join(_single_save_path, _single_result_name)) @@ -318,7 +323,7 @@ def simulate(self, "Simulating multiple parameter set's on " "the same combination of savepath and result_file_name " "will override results or even cause errors. " - "Specify a unqiue result_file_name-savepath combination " + "Specify a unique result_file_name-savepath combination " "for each parameter combination" ) for key, value in kwargs.items(): @@ -448,6 +453,9 @@ def model_name(self, model_name): Set new model_name and trigger further functions to load parameters etc. """ + # Only update if the model_name actually changes + if hasattr(self, "_model_name") and self._model_name == model_name: + return self._model_name = model_name # Only update model if it's the first setup. On multiprocessing, # all objects are duplicated and thus this setter is triggered again. @@ -478,20 +486,39 @@ def _update_model(self): raise NotImplementedError(f'{self.__class__.__name__}._update_model ' f'function is not defined') - def set_cd(self, cd): + def set_working_directory(self, working_directory: Union[Path, str]): """Base function for changing the current working directory.""" - self.cd = cd + self.working_directory = working_directory @property - def cd(self) -> str: + def working_directory(self) -> Path: """Get the current working directory""" - return self._cd + return self._working_directory - @cd.setter - def cd(self, cd: str): + @working_directory.setter + def working_directory(self, working_directory: Union[Path, str]): """Set the current working directory""" - os.makedirs(cd, exist_ok=True) - self._cd = cd + if isinstance(working_directory, str): + working_directory = Path(working_directory) + os.makedirs(working_directory, exist_ok=True) + self._working_directory = working_directory + + def set_cd(self, cd: Union[Path, str]): + warnings.warn("cd was renamed to working_directory in all classes. " + "Use working_directory instead instead.", category=DeprecationWarning) + self.working_directory = cd + + @property + def cd(self) -> Path: + warnings.warn("cd was renamed to working_directory in all classes. " + "Use working_directory instead instead.", category=DeprecationWarning) + return self.working_directory + + @cd.setter + def cd(self, cd: Union[Path, str]): + warnings.warn("cd was renamed to working_directory in all classes. " + "Use working_directory instead instead.", category=DeprecationWarning) + self.working_directory = cd @property def result_names(self) -> List[str]: diff --git a/ebcpy/simulationapi/dymola_api.py b/ebcpy/simulationapi/dymola_api.py index 7c78a016..153c0499 100644 --- a/ebcpy/simulationapi/dymola_api.py +++ b/ebcpy/simulationapi/dymola_api.py @@ -10,6 +10,7 @@ import json import time import socket +from pathlib import Path from contextlib import closing from typing import Union, List @@ -45,7 +46,7 @@ class DymolaAPI(SimulationAPI): """ API to a Dymola instance. - :param str,os.path.normpath cd: + :param str,Path working_directory: Dirpath for the current working directory of dymola :param str model_name: Name of the model to be simulated @@ -123,7 +124,7 @@ class DymolaAPI(SimulationAPI): >>> from ebcpy import DymolaAPI >>> # Specify the model name >>> model_name = "Modelica.Thermal.FluidHeatFlow.Examples.PumpAndValve" - >>> dym_api = DymolaAPI(cd=os.getcwd(), + >>> dym_api = DymolaAPI(working_directory=os.getcwd(), >>> model_name=model_name, >>> packages=[], >>> show_window=True) @@ -152,7 +153,13 @@ class DymolaAPI(SimulationAPI): "time_delay_between_starts" ] - def __init__(self, cd, model_name, packages=None, **kwargs): + def __init__( + self, + working_directory: Union[Path, str], + model_name: str, + packages: List[Union[Path, str]] = None, + **kwargs + ): """Instantiate class objects.""" self.dymola = None # Avoid key-error in get-state. Instance attribute needs to be there. # Update kwargs with regard to what kwargs are supported. @@ -187,7 +194,7 @@ def __init__(self, cd, model_name, packages=None, **kwargs): if self.mos_script_post is not None: self.mos_script_post = self._make_modelica_normpath(self.mos_script_post) - super().__init__(cd=cd, + super().__init__(working_directory=working_directory, model_name=model_name, n_cpu=kwargs.pop("n_cpu", 1)) @@ -226,7 +233,7 @@ def __init__(self, cd, model_name, packages=None, **kwargs): self.packages = [] if packages is not None: for package in packages: - if isinstance(package, pathlib.Path): + if isinstance(package, Path): self.packages.append(str(package)) elif isinstance(package, str): self.packages.append(package) @@ -540,7 +547,7 @@ def _single_simulation(self, kwargs): log = self.dymola.getLastErrorLog() # Only print first part as output is sometimes to verbose. self.logger.error(log[:10000]) - dslog_path = os.path.join(self.cd, 'dslog.txt') + dslog_path = self.working_directory.joinpath('dslog.txt') try: with open(dslog_path, "r") as dslog_file: dslog_content = dslog_file.read() @@ -557,12 +564,12 @@ def _single_simulation(self, kwargs): if return_option == "savepath": _save_name_dsres = f"{result_file_name}.mat" - # Get the cd of the current dymola instance + # Get the working_directory of the current dymola instance self.dymola.cd() # Get the value and convert it to a 100 % fitting str-path - dymola_cd = str(pathlib.Path(self.dymola.getLastErrorLog().replace("\n", ""))) - if savepath is None or str(savepath) == dymola_cd: - return os.path.join(dymola_cd, _save_name_dsres) + dymola_working_directory = str(Path(self.dymola.getLastErrorLog().replace("\n", ""))) + if savepath is None or str(savepath) == dymola_working_directory: + return os.path.join(dymola_working_directory, _save_name_dsres) os.makedirs(savepath, exist_ok=True) for filename in [_save_name_dsres]: # Copying dslogs and dsfinals can lead to errors, @@ -574,9 +581,9 @@ def _single_simulation(self, kwargs): except OSError: pass # Move files - shutil.copy(os.path.join(dymola_cd, filename), + shutil.copy(os.path.join(dymola_working_directory, filename), os.path.join(savepath, filename)) - os.remove(os.path.join(dymola_cd, filename)) + os.remove(os.path.join(dymola_working_directory, filename)) return os.path.join(savepath, _save_name_dsres) data = res[1] # Get data @@ -682,19 +689,26 @@ def import_initial(self, filepath): else: raise Exception("Could not load dsfinal into Dymola.") - @SimulationAPI.cd.setter - def cd(self, cd): + @SimulationAPI.working_directory.setter + def working_directory(self, working_directory: Union[Path, str]): """Set the working directory to the given path""" - self._cd = cd + if isinstance(working_directory, str): + working_directory = Path(working_directory) + self._working_directory = working_directory if self.dymola is None: # Not yet started return - # Also set the cd in the dymola api + # Also set the working_directory in the dymola api self.set_dymola_cd(dymola=self.dymola, - cd=cd) + cd=working_directory) if self.use_mp: - self.logger.warning("Won't set the cd for all workers, " + self.logger.warning("Won't set the working_directory for all workers, " "not yet implemented.") + @SimulationAPI.cd.setter + def cd(self, cd): + warnings.warn("cd was renamed to working_directory in all classes. Use working_directory instead.", category=DeprecationWarning) + self.working_directory = cd + def set_dymola_cd(self, dymola, cd): """ Set the cd of the Dymola Instance. @@ -865,7 +879,7 @@ def get_packages(self): self.logger.error("Could not load packages from Dymola, using self.packages") packages = [] for pack in self.packages: - pack = pathlib.Path(pack) + pack = Path(pack) if pack.name == "package.mo": packages.append(pack.parent.name) valid_packages = [] @@ -877,13 +891,13 @@ def get_packages(self): if not isinstance(pack_path, str): self.logger.error("Could not load model resource for package %s", pack) if os.path.isfile(pack_path): - valid_packages.append(pathlib.Path(pack_path).parent) + valid_packages.append(Path(pack_path).parent) return valid_packages def save_for_reproduction( self, title: str, - path: pathlib.Path = None, + path: Path = None, files: list = None, save_total_model: bool = True, export_fmu: bool = True, @@ -952,7 +966,7 @@ def save_for_reproduction( # Total model if save_total_model: _total_model_name = f"Dymola/{self.model_name.replace('.', '_')}_total.mo" - _total_model = pathlib.Path(self.cd).joinpath(_total_model_name) + _total_model = Path(self.cd).joinpath(_total_model_name) os.makedirs(_total_model.parent, exist_ok=True) # Create to ensure model can be saved. res = self.dymola.saveTotalModel( fileName=str(_total_model), @@ -1001,7 +1015,7 @@ def _save_to_fmu(self, fail_on_error): if fail_on_error: raise Exception(msg) else: - path = pathlib.Path(self.cd).joinpath(res + ".fmu") + path = Path(self.cd).joinpath(res + ".fmu") return path @staticmethod @@ -1016,7 +1030,7 @@ def _make_modelica_normpath(path): :return: str Path readable in dymola """ - if isinstance(path, pathlib.Path): + if isinstance(path, Path): path = str(path) path = path.replace("\\", "/") diff --git a/ebcpy/simulationapi/fmu.py b/ebcpy/simulationapi/fmu.py index 543be3e6..6890090b 100644 --- a/ebcpy/simulationapi/fmu.py +++ b/ebcpy/simulationapi/fmu.py @@ -74,7 +74,7 @@ class FMU_API(simulationapi.SimulationAPI): int: np.int_ } - def __init__(self, cd, model_name, **kwargs): + def __init__(self, working_directory, model_name, **kwargs): """Instantiate class parameters""" # Init instance attributes self._model_description = None @@ -88,9 +88,9 @@ def __init__(self, cd, model_name, **kwargs): model_name = str(model_name) if not model_name.lower().endswith(".fmu"): raise ValueError(f"{model_name} is not a valid fmu file!") - if cd is None: - cd = os.path.dirname(model_name) - super().__init__(cd, model_name, **kwargs) + if working_directory is None: + working_directory = os.path.dirname(model_name) + super().__init__(working_directory, model_name, **kwargs) # Register exit option atexit.register(self.close) @@ -265,7 +265,7 @@ def _single_simulation(self, kwargs): if return_option == "savepath": if savepath is None: - savepath = self.cd + savepath = self.working_directory os.makedirs(savepath, exist_ok=True) filepath = os.path.join(savepath, f"{result_file_name}.{result_file_suffix}") @@ -289,7 +289,7 @@ def setup_fmu_instance(self): """ self.logger.info("Extracting fmu and reading fmu model description") # First load model description and extract variables - self._single_unzip_dir = os.path.join(self.cd, + self._single_unzip_dir = os.path.join(self.working_directory, os.path.basename(self.model_name)[:-4] + "_extracted") os.makedirs(self._single_unzip_dir, exist_ok=True) self._single_unzip_dir = fmpy.extract(self.model_name, diff --git a/ebcpy/utils/__init__.py b/ebcpy/utils/__init__.py index 0df6df36..9fdd0414 100644 --- a/ebcpy/utils/__init__.py +++ b/ebcpy/utils/__init__.py @@ -4,10 +4,12 @@ """ import logging import os +from pathlib import Path +from typing import Union def setup_logger(name: str, - cd: str = None, + working_directory: Union[Path, str] = None, level=logging.DEBUG): """ Setup an class or module specific logger instance @@ -15,7 +17,7 @@ def setup_logger(name: str, :param str name: The name of the logger instance - :param str cd: + :param str,Path working_directory: The path where to store the logfile. If None is given, logs are not stored. :param str level: @@ -35,9 +37,9 @@ def setup_logger(name: str, console = logging.StreamHandler() console.setFormatter(fmt=formatter) logger.addHandler(hdlr=console) - if cd is not None: - os.makedirs(cd, exist_ok=True) - file_handler = logging.FileHandler(filename=os.path.join(cd, f"{name}.log")) + if working_directory is not None: + os.makedirs(working_directory, exist_ok=True) + file_handler = logging.FileHandler(filename=working_directory.joinpath(f"{name}.log")) file_handler.setFormatter(fmt=formatter) logger.addHandler(hdlr=file_handler) return logger diff --git a/examples/e2_fmu_example.py b/examples/e2_fmu_example.py index 85d79329..aba056c3 100644 --- a/examples/e2_fmu_example.py +++ b/examples/e2_fmu_example.py @@ -17,7 +17,7 @@ def main( - cd=None, + working_directory=None, n_cpu=1, log_fmu=True, n_sim=5, @@ -26,7 +26,7 @@ def main( ): """ Arguments of this example: - :param str cd: + :param str working_directory: Path in which to store the output. Default is the examples\results folder :param int n_cpu: @@ -42,14 +42,14 @@ def main( """ # General settings - if cd is None: - cd = pathlib.Path(__file__).parent.joinpath("results") + if working_directory is None: + working_directory = pathlib.Path(__file__).parent.joinpath("results") # ######################### Simulation API Instantiation ########################## # %% Setup the FMU-API: model_name = pathlib.Path(__file__).parent.joinpath("data", "HeatPumpSystemWithInput.fmu") fmu_api = FMU_API(model_name=model_name, - cd=cd, + working_directory=working_directory, n_cpu=n_cpu, log_fmu=log_fmu) print("Number of variables:", len(fmu_api.variables)) diff --git a/examples/e3_dymola_example.py b/examples/e3_dymola_example.py index da446fbb..05a35aaa 100644 --- a/examples/e3_dymola_example.py +++ b/examples/e3_dymola_example.py @@ -16,7 +16,7 @@ def main( aixlib_mo, - cd=None, + working_directory=None, n_cpu=1, with_plot=True ): @@ -25,7 +25,7 @@ def main( :param str aixlib_mo: Path to the package.mo of the AixLib. This example was tested for AixLib version 1.0.0. - :param str cd: + :param str working_directory: Path in which to store the output. Default is the examples\results folder :param int n_cpu: @@ -35,14 +35,14 @@ def main( """ # General settings - if cd is None: - cd = pathlib.Path(__file__).parent.joinpath("results") + if working_directory is None: + working_directory = pathlib.Path(__file__).parent.joinpath("results") # ######################### Simulation API Instantiation ########################## # %% Setup the Dymola-API: dym_api = DymolaAPI( model_name="AixLib.Systems.HeatPumpSystems.Examples.HeatPumpSystem", - cd=cd, + working_directory=working_directory, n_cpu=n_cpu, packages=[aixlib_mo], show_window=True, diff --git a/pylintrc b/pylintrc index 0547cae5..4c77e9e2 100644 --- a/pylintrc +++ b/pylintrc @@ -239,7 +239,6 @@ good-names=i, y, xk, x0, - cd, ax, DymolaInterface, DymolaConnectionException, diff --git a/tests/test_data_types.py b/tests/test_data_types.py index 75d09371..6ee9a12c 100644 --- a/tests/test_data_types.py +++ b/tests/test_data_types.py @@ -157,6 +157,16 @@ def test_time_series_data(self): self.assertIsInstance( time_series_data, type(pd.DataFrame())) + # Load with variable names: + variable_names = ["combiTimeTable.y[6]"] + time_series_data = data_types.TimeSeriesData( + self.example_data_mat_path, variable_names=variable_names + ) + self.assertIsInstance( + time_series_data, + type(pd.DataFrame())) + self.assertEqual(len(time_series_data.columns), 1) + self.assertEqual(time_series_data.to_df().columns[0], variable_names[0]) # Test load and set df functions: df = time_series_data self.assertIsInstance( diff --git a/tests/test_optimizer.py b/tests/test_optimizer.py index bb4be8f2..6586b093 100644 --- a/tests/test_optimizer.py +++ b/tests/test_optimizer.py @@ -4,6 +4,7 @@ import unittest import os import shutil +import pathlib import logging import numpy as np from ebcpy.optimization import Optimizer @@ -39,13 +40,16 @@ def test_optimizer_choose_function(self): with self.assertRaises(TypeError): opt._choose_framework("not_supported_framework") - def test_set_and_delete_cd(self): - """Test the cd and delete functions""" + def test_set_and_delete_working_directory(self): + """Test the working_directory and delete functions""" + example_dir_as_pathlib_path = pathlib.Path(self.example_opt_dir) opt = Optimizer() - self.assertIsNone(opt.cd) - opt = Optimizer(cd=self.example_opt_dir) - self.assertEqual(opt.cd, self.example_opt_dir) - shutil.rmtree(opt.cd) + self.assertIsNone(opt.working_directory) + opt = Optimizer(working_directory=self.example_opt_dir) + self.assertEqual(opt.working_directory, example_dir_as_pathlib_path) + opt = Optimizer(working_directory=example_dir_as_pathlib_path) + self.assertEqual(opt.working_directory, example_dir_as_pathlib_path) + shutil.rmtree(opt.working_directory) def test_custom_optimizer(self): """Test-case for the customization of the optimization-base-class.""" diff --git a/tests/test_simulationapi.py b/tests/test_simulationapi.py index c9e985e7..a317f160 100644 --- a/tests/test_simulationapi.py +++ b/tests/test_simulationapi.py @@ -127,12 +127,14 @@ def test_savepath_handling(self): self.assertTrue(os.path.isfile(r)) self.assertIsInstance(r, str) - - def test_set_cd(self): - """Test set_cd functionality of dymola api""" + def test_set_working_directory(self): + """Test set_working_directory functionality of dymola api""" # Test the setting of the function - self.sim_api.set_cd(self.data_dir) - self.assertEqual(self.data_dir, self.sim_api.cd) + self.sim_api.set_working_directory(self.data_dir) + self.assertEqual(self.data_dir, self.sim_api.working_directory) + # Test setting a str: + self.sim_api.set_working_directory(str(self.data_dir)) + self.assertEqual(self.data_dir, self.sim_api.working_directory) def test_set_sim_setup(self): """Test set_sim_setup functionality of fmu api""" @@ -188,7 +190,7 @@ def setUp(self) -> None: dymola_exe_path = None try: self.sim_api = dymola_api.DymolaAPI( - cd=self.example_sim_dir, + working_directory=self.example_sim_dir, model_name=model_name, packages=packages, dymola_exe_path=dymola_exe_path, @@ -283,7 +285,7 @@ def setUp(self): else: model_name = self.data_dir.joinpath("PumpAndValve_linux.fmu") - self.sim_api = fmu.FMU_API(cd=self.example_sim_dir, + self.sim_api = fmu.FMU_API(working_directory=self.example_sim_dir, model_name=model_name) def test_close(self): diff --git a/tests/test_utils.py b/tests/test_utils.py index 3462d345..66384947 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -205,7 +205,7 @@ def setUp(self): """Called before every test. Used to setup relevant paths and APIs etc.""" self.example_dir = Path(__file__).parent.joinpath("test_logger") - self.logger = setup_logger(cd=self.example_dir, + self.logger = setup_logger(working_directory=self.example_dir, name="test_logger") def test_logging(self): @@ -233,18 +233,18 @@ def setUp(self): Used to setup relevant paths and APIs etc.""" self.data_dir = Path(__file__).parent.joinpath("data") self.save_dir = self.data_dir.joinpath('testzone', 'reproduction_tests') - self.cd_files = [] + self.working_directory_files = [] def test_save_reproduction_archive(self): os.getlogin = lambda: "test_login" # test no input reproduction.input = lambda _: "" zip_file = reproduction.save_reproduction_archive() - # for tearDown of the files which will be saved in cd when no path is given - self.cd_files.append(zip_file) + # for tearDown of the files which will be saved in working_directory when no path is given + self.working_directory_files.append(zip_file) file = Path(sys.modules['__main__'].__file__).absolute().name.replace(".py", "") logger_name = f"Study_log_{file}.txt" - self.cd_files.append(logger_name) + self.working_directory_files.append(logger_name) self.assertTrue(zipfile.is_zipfile(zip_file)) # create a file to remove with CopyFile but leave it open for executing except block f = open(self.data_dir.joinpath('remove.txt'), 'w') @@ -294,7 +294,7 @@ def tearDown(self) -> None: """Delete saved files""" try: shutil.rmtree(self.save_dir, ignore_errors=True) - for file in self.cd_files: + for file in self.working_directory_files: os.remove(file) except Exception: pass diff --git a/tutorial/tutorial.ipynb b/tutorial/tutorial.ipynb index 2e648e09..91d273ae 100644 --- a/tutorial/tutorial.ipynb +++ b/tutorial/tutorial.ipynb @@ -334,7 +334,7 @@ "\n", "DYM_API = dymola_api.DymolaAPI(\n", " # Used for saving simulation files etc.\n", - " cd=os.path.join(os.getcwd(), \"data\"),\n", + " working_directory=os.path.join(os.getcwd(), \"data\"),\n", " # Name of the model you want to simulate\n", " model_name=\"Modelica.Thermal.FluidHeatFlow.Examples.PumpAndValve\",\n", " # All package.mo files required.\n",