Skip to content

Commit

Permalink
Merge pull request #122 from RWTH-EBC/120_model_name_setting [PYPI-RE…
Browse files Browse the repository at this point in the history
…LEASE]

fix: only set model name if the model really changes and refactor to cwd
  • Loading branch information
FWuellhorst authored Feb 16, 2024
2 parents 7a2cbac + 6a9b9ed commit 7fa8cc4
Show file tree
Hide file tree
Showing 17 changed files with 191 additions and 97 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion ebcpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@
from .optimization import Optimizer


__version__ = '0.3.13'
__version__ = '0.3.14'
11 changes: 9 additions & 2 deletions ebcpy/data_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions ebcpy/modelica/simres.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
41 changes: 29 additions & 12 deletions ebcpy/optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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)

Expand Down Expand Up @@ -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]]:
Expand Down
59 changes: 43 additions & 16 deletions ebcpy/simulationapi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand All @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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))
Expand All @@ -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():
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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]:
Expand Down
Loading

0 comments on commit 7fa8cc4

Please sign in to comment.