Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 57 error due to refactoring of cd to working directory by ebcpy #58

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,6 @@
- Sensitivity analysis is now usable for large models and data
- Add time dependent sensitivity analysis
- Ends support for python 3.7

- **v1.0.1**
- refactor cd to working_directory #57
2 changes: 1 addition & 1 deletion aixcalibuha/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
from .sensitivity_analysis import SobolAnalyzer, MorrisAnalyzer, FASTAnalyzer, PAWNAnalyzer, \
plotting

__version__ = "1.0.0"
__version__ = "1.0.1"
23 changes: 12 additions & 11 deletions aixcalibuha/calibration/calibrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@

import os
import json
from pathlib import Path
import time
import logging
from typing import Dict
from typing import Dict, Union
from copy import copy
import numpy as np
import pandas as pd
Expand All @@ -22,7 +23,7 @@ class Calibrator(Optimizer):
This class can Calibrator be used for single
time-intervals of calibration.

:param str,os.path.normpath cd:
:param str,Path working_directory:
Working directory
:param ebcpy.simulationapi.SimulationAPI sim_api:
Simulation-API for running the models
Expand Down Expand Up @@ -91,7 +92,7 @@ class Calibrator(Optimizer):
"""

def __init__(self,
cd: str,
working_directory: Union[Path, str],
sim_api: SimulationAPI,
calibration_class: CalibrationClass,
**kwargs):
Expand Down Expand Up @@ -133,7 +134,7 @@ def __init__(self,
f"{type(keyword_value).__name__} but should be type bool")

# %% Initialize all public parameters
super().__init__(cd, **kwargs)
super().__init__(working_directory, **kwargs)
# Set sim_api
self.sim_api = sim_api

Expand All @@ -158,21 +159,21 @@ def __init__(self,
# De-register the logger setup in the optimization class:
if self.verbose_logging:
self.logger = visualizer.CalibrationVisualizer(
cd=cd,
working_directory=working_directory,
name=self.__class__.__name__,
calibration_class=self.calibration_class,
logger=self.logger,
**visualizer_kwargs
)
else:
self.logger = visualizer.CalibrationLogger(
cd=cd,
working_directory=working_directory,
name=self.__class__.__name__,
calibration_class=self.calibration_class,
logger=self.logger
)

self.cd_of_class = cd # Single class does not need an extra folder
self.working_directory_of_class = working_directory # Single class does not need an extra folder

# Set the output interval according the the given Goals
mean_freq = self.goals.get_meas_frequency()
Expand Down Expand Up @@ -217,7 +218,7 @@ def obj(self, xk, *args):
try:
# Generate the folder name for the calibration
if self.save_files:
savepath_files = os.path.join(self.sim_api.cd,
savepath_files = os.path.join(self.sim_api.working_directory,
f"simulation_{self._counter}")
_filepath = self.sim_api.simulate(
parameters=parameters,
Expand Down Expand Up @@ -280,7 +281,7 @@ def mp_obj(self, x, *args):
_filepaths = self.sim_api.simulate(
parameters=parameter_list,
return_option="savepath",
savepath=self.sim_api.cd,
savepath=self.sim_api.working_directory,
result_file_name=result_file_names,
fail_on_error=self.fail_on_error,
inputs=self.calibration_class.inputs,
Expand Down Expand Up @@ -394,7 +395,7 @@ def calibrate(self, framework, method=None, **kwargs) -> dict:

# Setup the visualizer for plotting and logging:
self.logger.calibrate_new_class(self.calibration_class,
cd=self.cd_of_class,
working_directory=self.working_directory_of_class,
for_validation=False)
self.logger.log_initial_names()

Expand Down Expand Up @@ -521,7 +522,7 @@ def validate(self, validation_class: CalibrationClass, calibration_result: Dict,
self.sim_api.sim_setup.start_time = start_time

self.logger.calibrate_new_class(self.calibration_class,
cd=self.cd_of_class,
working_directory=self.working_directory_of_class,
for_validation=True)

# Use the results parameter vector to simulate again.
Expand Down
32 changes: 18 additions & 14 deletions aixcalibuha/calibration/multi_class_calibrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@
"""

import os
from typing import List
from pathlib import Path
from typing import List, Union
import numpy as np
from ebcpy.simulationapi import SimulationAPI

from aixcalibuha import CalibrationClass, data_types
from aixcalibuha.calibration import Calibrator

Expand Down Expand Up @@ -51,8 +54,8 @@ class MultipleClassCalibrator(Calibrator):
merge_multiple_classes = True

def __init__(self,
cd: str,
sim_api,
working_directory: Union[Path, str],
sim_api: SimulationAPI,
calibration_classes: List[CalibrationClass],
start_time_method: str = 'fixstart',
calibration_strategy: str = 'parallel',
Expand Down Expand Up @@ -85,7 +88,7 @@ def __init__(self,
self.calibration_strategy = calibration_strategy.lower()

# Instantiate parent-class
super().__init__(cd, sim_api, calibration_classes[0], **kwargs)
super().__init__(working_directory, sim_api, calibration_classes[0], **kwargs)
# Merge the multiple calibration_classes
if self.merge_multiple_classes:
self.calibration_classes = data_types.merge_calibration_classes(calibration_classes)
Expand Down Expand Up @@ -114,15 +117,15 @@ def calibrate(self, framework, method=None, **kwargs) -> dict:

# Iterate over the different existing classes
for cal_class in self.calibration_classes:
#%% Working-Directory:
# %% Working-Directory:
# Alter the working directory for saving the simulations-results
self.cd_of_class = os.path.join(self.cd,
f"{cal_class.name}_"
f"{cal_class.start_time}_"
f"{cal_class.stop_time}")
self.sim_api.set_cd(self.cd_of_class)
self.working_directory_of_class = os.path.join(self.working_directory,
f"{cal_class.name}_"
f"{cal_class.start_time}_"
f"{cal_class.stop_time}")
self.sim_api.set_working_directory(self.working_directory_of_class)

#%% Calibration-Setup
# %% Calibration-Setup
# Reset counter for new calibration
self._counter = 0
# Retrieve already calibrated parameters (i.e. calibrated in the previous classes)
Expand Down Expand Up @@ -160,11 +163,11 @@ def calibrate(self, framework, method=None, **kwargs) -> dict:
else:
self.bounds = [(0, 1) for i in range(len(self.x0))]

#%% Execution
# %% Execution
# Run the single ModelicaCalibration
super().calibrate(framework=framework, method=method, **kwargs)

#%% Post-processing
# %% Post-processing
# Append result to list for future perturbation based on older results.
self._cal_history.append({"res": self._current_best_iterate,
"cal_class": cal_class})
Expand Down Expand Up @@ -261,7 +264,8 @@ def check_intersection_of_tuner_parameters(self):
self.logger.log("The tuner parameters used for evaluation "
"are averaged as follows:\n "
"{}".format(' ,'.join([f"{tuner}={value}"
for tuner, value in average_tuner_parameter.items()])))
for tuner, value in
average_tuner_parameter.items()])))

# Create result-dictionary
res_tuner = average_tuner_parameter
Expand Down
57 changes: 35 additions & 22 deletions aixcalibuha/sensitivity_analysis/sensitivity_analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
import abc
import copy
import os
import pathlib
from pathlib import Path
import multiprocessing as mp
import warnings
from typing import List
from collections import Counter
import numpy as np
Expand Down Expand Up @@ -94,7 +95,7 @@ class SenAnalyzer(abc.ABC):
number of samples produced, but relates to the total number of samples produced in
a manner dependent on the sampler method used. See the documentation of the specific
method in the SALib for more information.
:keyword str,os.path.normpath cd:
:keyword str,Path working_directory:
The path for the current working directory.
Logger and results will be stored here.
:keyword boolean fail_on_error:
Expand All @@ -115,8 +116,8 @@ class SenAnalyzer(abc.ABC):
Supported options can be extracted
from the ebcpy.TimeSeriesData.save() function.
Default is 'pyarrow'.
:keyword str,os.path.normpath savepath_sim:
Default is cd. Own directory for the time series data sets of all simulations
:keyword str,Path savepath_sim:
Default is working_directory. Own directory for the time series data sets of all simulations
during the sensitivity analysis. The own dir can be necessary for large data sets,
because they can crash IDE during indexing when they are in the project folder.

Expand All @@ -137,16 +138,25 @@ def __init__(self,
self.suffix_files = kwargs.pop('suffix_files', 'csv')
self.parquet_engine = kwargs.pop('parquet_engine', 'pyarrow')
self.ret_val_on_error = kwargs.pop("ret_val_on_error", np.NAN)
self.cd = kwargs.pop("cd", os.getcwd())
self.savepath_sim = kwargs.pop('savepath_sim', self.cd)
self.working_directory = kwargs.pop("working_directory", os.getcwd())

if isinstance(self.cd, str):
self.cd = pathlib.Path(self.cd)
if "cd" in kwargs:
warnings.warn(
"cd was renamed to working_directory in all classes. "
"Use working_directory instead.",
category=DeprecationWarning)
self.working_directory = kwargs.pop("cd")

self.savepath_sim = kwargs.pop('savepath_sim', self.working_directory)

if isinstance(self.working_directory, str):
self.working_directory = Path(self.working_directory)
if isinstance(self.savepath_sim, str):
self.savepath_sim = pathlib.Path(self.savepath_sim)
self.savepath_sim = Path(self.savepath_sim)

# Setup the logger
self.logger = setup_logger(cd=self.cd, name=self.__class__.__name__)
self.logger = setup_logger(working_directory=self.working_directory,
name=self.__class__.__name__)

# Setup default values
self.problem: dict = None
Expand Down Expand Up @@ -236,7 +246,7 @@ def simulate_samples(self, cal_class, **kwargs):
# creat df of samples with the result_file_names as the index
result_file_names = [f"simulation_{idx}" for idx in range(len(samples))]
samples_df = pd.DataFrame(samples, columns=initial_names, index=result_file_names)
samples_df.to_csv(self.cd.joinpath(f'samples_{cal_class.name}.csv'))
samples_df.to_csv(self.working_directory.joinpath(f'samples_{cal_class.name}.csv'))

# Simulate the current values
parameters = []
Expand Down Expand Up @@ -410,7 +420,7 @@ def run(self, calibration_classes, merge_multiple_classes=True, **kwargs):
The usage of the same simulations for different
calibration classes is not supported yet.
:keyword bool save_results:
Default True. If True, all results are saved as a csv in cd.
Default True. If True, all results are saved as a csv in working_directory.
(samples, statistical measures and analysis variables).
:keyword bool plot_result:
Default True. If True, the results will be plotted.
Expand Down Expand Up @@ -513,17 +523,17 @@ def run(self, calibration_classes, merge_multiple_classes=True, **kwargs):
if len(output_verbose) > 1 and verbose:
stat_mea.update(output_verbose)

# save statistical measure and corresponding samples for each cal_class in cd
# save statistical measure and corresponding samples for each cal_class in working_directory
if save_results:
result_file_names = [f"simulation_{idx}" for idx in range(len(output_array))]
stat_mea_df = pd.DataFrame(stat_mea, index=result_file_names)
savepath_stat_mea = self.cd.joinpath(
savepath_stat_mea = self.working_directory.joinpath(
f'{cal_class.goals.statistical_measure}_{cal_class.name}.csv')
stat_mea_df.to_csv(savepath_stat_mea)
self.reproduction_files.append(savepath_stat_mea)
samples_df = pd.DataFrame(samples, columns=cal_class.tuner_paras.get_names(),
index=result_file_names)
savepath_samples = self.cd.joinpath(f'samples_{cal_class.name}.csv')
savepath_samples = self.working_directory.joinpath(f'samples_{cal_class.name}.csv')
samples_df.to_csv(savepath_samples)
self.reproduction_files.append(savepath_samples)

Expand Down Expand Up @@ -552,9 +562,11 @@ def _save(self, result: pd.DataFrame, time_dependent: bool = False):
Needs to be overwritten for Sobol results.
"""
if time_dependent:
savepath_result = self.cd.joinpath(f'{self.__class__.__name__}_results_time.csv')
savepath_result = self.working_directory.joinpath(
f'{self.__class__.__name__}_results_time.csv')
else:
savepath_result = self.cd.joinpath(f'{self.__class__.__name__}_results.csv')
savepath_result = self.working_directory.joinpath(
f'{self.__class__.__name__}_results.csv')
result.to_csv(savepath_result)
self.reproduction_files.append(savepath_result)

Expand Down Expand Up @@ -677,7 +689,7 @@ def run_time_dependent(self, cal_class: CalibrationClass, **kwargs):
they were saved from self.save_files. Currently, the name of the sim folder must be
"simulations_CAL_CLASS_NAME" and for the samples "samples_CAL_CLASS_NAME".
:keyword bool save_results:
Default True. If True, all results are saved as a csv in cd.
Default True. If True, all results are saved as a csv in working_directory.
(samples and analysis variables).
:keyword int n_steps:
Default is all time steps. If the problem is large, the evaluation of all time steps
Expand Down Expand Up @@ -865,7 +877,7 @@ def load_from_csv(path):

def save_for_reproduction(self,
title: str,
path: pathlib.Path = None,
path: Path = None,
files: list = None,
exclude_sim_files: bool = False,
remove_saved_files: bool = False,
Expand All @@ -878,8 +890,8 @@ def save_for_reproduction(self,

:param str title:
Title of the study
:param pathlib.Path path:
Where to store the .zip file. If not given, self.cd is used.
:param Path path:
Where to store the .zip file. If not given, self.working_directory is used.
:param list files:
List of files to save along the standard ones.
Examples would be plots, tables etc.
Expand All @@ -901,7 +913,8 @@ def save_for_reproduction(self,
if exclude_sim_files:
if 'simulation' in str(file_path):
continue
filename = "SenAnalyzer" + str(file_path).rsplit(self.cd.name, maxsplit=1)[-1]
filename = "SenAnalyzer" + \
str(file_path).rsplit(self.working_directory.name, maxsplit=1)[-1]
files.append(CopyFile(
sourcepath=file_path,
filename=filename,
Expand Down
4 changes: 2 additions & 2 deletions aixcalibuha/sensitivity_analysis/sobol.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ def _save(self, result: tuple, time_dependent: bool = False):
if not result[0].empty:
super()._save(result=result[0], time_dependent=time_dependent)
if time_dependent:
savepath_result_2 = self.cd.joinpath(
savepath_result_2 = self.working_directory.joinpath(
f'{self.__class__.__name__}_results_second_order_time.csv')
else:
savepath_result_2 = self.cd.joinpath(
savepath_result_2 = self.working_directory.joinpath(
f'{self.__class__.__name__}_results_second_order.csv')
if not result[1].empty:
result[1].to_csv(savepath_result_2)
Expand Down
4 changes: 2 additions & 2 deletions aixcalibuha/utils/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def write_config(filepath, config):
If the file already exists, the data is recursively
updated.

:param str,os.path.normpath filepath:
:param str,Path filepath:
Filepath with the config.
:param: dict config:
Config to be saved
Expand All @@ -195,7 +195,7 @@ def read_config(filepath):
"""
Read the given file and return the toml-config

:param str,os.path.normpath filepath:
:param str,Path filepath:
Filepath with the config.
:return: dict config:
Loaded config
Expand Down
Loading