# -*- coding: utf-8 -*-
"""
Example for Optimization of a heat pump (heat_pump_comp) using scipy.optimize

Composition and high pressure (condenser) of the working fluid, and the low
temperature of the double tank cold storage are optimization variables. All
other parameters are fixed in a yaml file (io-cycle-data.yaml).

Created on Mon Aug  4 13:12:24 2025

@author: atakan
Universität Duisburg-Essen, Germany

In the framework of the Priority Programme: "Carnot Batteries: Inverse Design from
Markets to Molecules" (SPP 2403)
https://www.uni-due.de/spp2403/
https://git.uni-due.de/spp-2403/residuals_weather_storage

"""


import numpy as np
import pandas as pd
import carbatpy as cb
import datetime
from pathlib import Path
import shutil
import yaml
import pickle

# Konfiguration und Konstanten (diese können außerhalb des main-Blocks stehen)
current_date = datetime.datetime.now().strftime("%Y-%m-%d-%H-%M-")
OPTI = True
HOW_OPT = "dif_evol"  # "local" #
STORE_FILENAME = (
    cb.CB_DEFAULTS["General"]["RES_DIR"] + "\\" + current_date + "hp_opt_results"
)

DIR = cb.CB_DEFAULTS["General"]["CB_DATA"]

file_config = DIR + "\\io-hp-data.yaml"

# Ordner erstellen und YAML schreiben
dir_res = Path(STORE_FILENAME)
dir_res.mkdir(exist_ok=True)

datei = dir_res / "config_bound.yaml"
res_dat = dir_res / "opt_res.yaml"
file_res = dir_res / (current_date + "hp_opti_res.csv")
# optimization variables, must be present in the file above
conf_m = {
    "cold_storage": {"temp_low": 270.0},
    "compressor": {"dt_superheat": 5},
    "working_fluid": {"p_high": 1.65e6, "p_low": 1.67e5, "fractions": [0.80, 0.2]},
}
# bounds of the optimization variables
bounds_m = {
    "cold_storage": {"temp_low": [265, 277]},
    "compressor": {"dt_superheat": [3, 20]},
    "working_fluid": {
        "p_high": [5e5, 2.1e6],
        "p_low": [1e5, 4e5],
        "fractions": [[0.7, 1.0], [0.0, 0.4]],
    },
}

# Run heat pump without optimization, with the configuration conf_m:
if __name__ == "__main__":
    res_m = cb.hp_comp.heat_pump(
        file_config, config=conf_m, verbose=True, plotting=True
    )
    if any(ns.value != 0 for ns in res_m["warnings"].values()):
        print(f"Check Warnings, at least one deviates from 0!\n {res_m['warnings']}")

    if OPTI:
        # for optimization:

        opt_res, paths = cb.opti_cycle_comp_helpers.optimize_wf_heat_pump(
            file_config,
            conf_m,
            bounds_m,
            optimize_global=HOW_OPT,
            workers=1,
            maxiter=50,
            verbose=True,
        )
        print(opt_res)

        with open(dir_res / "paths.pkl", "wb") as pf:
            pickle.dump(paths, pf)
        co_n = cb.opti_cycle_comp_helpers.insert_optim_data(conf_m, opt_res.x, paths)
        res_ = cb.hp_comp.heat_pump(file_config, config=co_n, plotting=True)
        col_names = cb.opti_cycle_comp_helpers.extract_cycle_column_names_from_config(
            res_["output"]["config"], paths
        ) + ["COP"]
        file_fig = dir_res / (current_date + "_hp_opti_res.png")
        res_["figure"].savefig(file_fig)
        if HOW_OPT == "dif_evol":
            res_combi = np.column_stack(
                [opt_res.population, opt_res.population_energies]
            )
            df = pd.DataFrame(res_combi, columns=col_names)
            df.to_csv(file_res, sep=",", index=False)

        res_dict = {
            "x": (opt_res.x).tolist(),
            "fun": float(opt_res.fun),
            "success": opt_res.success,
            "message": opt_res.message,
            "results": dict(zip(col_names, (opt_res.x).tolist())),
        }
        with res_dat.open("w") as f:
            yaml.dump(res_dict, f, default_flow_style=False, sort_keys=False)
