diff --git a/src/watertap_contrib/reflo/solar_models/surrogate/pv/data/dataset.pkl b/src/watertap_contrib/reflo/solar_models/surrogate/pv/data/dataset.pkl new file mode 100644 index 00000000..493412e9 Binary files /dev/null and b/src/watertap_contrib/reflo/solar_models/surrogate/pv/data/dataset.pkl differ diff --git a/src/watertap_contrib/reflo/solar_models/surrogate/pv/pv_surrogate.json b/src/watertap_contrib/reflo/solar_models/surrogate/pv/pv_surrogate.json new file mode 100644 index 00000000..59c6559c --- /dev/null +++ b/src/watertap_contrib/reflo/solar_models/surrogate/pv/pv_surrogate.json @@ -0,0 +1 @@ +{"model_encoding": {"annual_energy": {"attr": {"x_data_columns": ["design_size"], "x_data": [[0.707070707070707], [0.030303030303030304], [0.3131313131313131], [0.1919191919191919], [0.3535353535353535], [0.9191919191919191], [0.7474747474747474], [0.10101010101010101], [0.7676767676767676], [0.1414141414141414], [0.797979797979798], [0.2525252525252525], [0.7171717171717171], [0.6666666666666666], [0.7575757575757576], [0.06060606060606061], [0.3838383838383838], [0.3636363636363636], [0.9292929292929293], [0.40404040404040403], [0.4242424242424242], [0.1313131313131313], [0.050505050505050504], [0.5656565656565656], [0.8282828282828283], [0.0], [0.0101010101010101], [0.5252525252525252], [0.1616161616161616], [0.0808080808080808], [0.0707070707070707], [1.0], [0.24242424242424243], [0.7777777777777778], [0.9898989898989898], [0.9797979797979798], [0.8989898989898989], [0.8383838383838385], [0.5454545454545454], [0.4949494949494949], [0.7272727272727272], [0.2121212121212121], [0.696969696969697], [0.9595959595959596], [0.47474747474747475], [0.505050505050505], [0.6363636363636364], [0.1818181818181818], [0.7373737373737373], [0.8686868686868686], [0.5757575757575758], [0.23232323232323232], [0.2727272727272727], [0.6767676767676768], [0.3232323232323232], [0.5555555555555556], [0.8181818181818181], [0.46464646464646464], [0.5151515151515151], [0.0909090909090909], [0.606060606060606], [0.8080808080808081], [0.3939393939393939], [0.5353535353535354], [0.8888888888888888], [0.3434343434343434], [0.1111111111111111], [0.2222222222222222], [0.41414141414141414], [0.8787878787878787], [0.7878787878787878], [0.20202020202020202], [0.3333333333333333], [0.2626262626262626], [0.6262626262626262], [0.48484848484848486], [0.4444444444444444], [0.9090909090909091], [0.12121212121212122], [0.9393939393939393]], "centres": [[0.707070707070707], [0.030303030303030304], [0.3131313131313131], [0.1919191919191919], [0.3535353535353535], [0.9191919191919191], [0.7474747474747474], [0.10101010101010101], [0.7676767676767676], [0.1414141414141414], [0.797979797979798], [0.2525252525252525], [0.7171717171717171], [0.6666666666666666], [0.7575757575757576], [0.06060606060606061], [0.3838383838383838], [0.3636363636363636], [0.9292929292929293], [0.40404040404040403], [0.4242424242424242], [0.1313131313131313], [0.050505050505050504], [0.5656565656565656], [0.8282828282828283], [0.0], [0.0101010101010101], [0.5252525252525252], [0.1616161616161616], [0.0808080808080808], [0.0707070707070707], [1.0], [0.24242424242424243], [0.7777777777777778], [0.9898989898989898], [0.9797979797979798], [0.8989898989898989], [0.8383838383838385], [0.5454545454545454], [0.4949494949494949], [0.7272727272727272], [0.2121212121212121], [0.696969696969697], [0.9595959595959596], [0.47474747474747475], [0.505050505050505], [0.6363636363636364], [0.1818181818181818], [0.7373737373737373], [0.8686868686868686], [0.5757575757575758], [0.23232323232323232], [0.2727272727272727], [0.6767676767676768], [0.3232323232323232], [0.5555555555555556], [0.8181818181818181], [0.46464646464646464], [0.5151515151515151], [0.0909090909090909], [0.606060606060606], [0.8080808080808081], [0.3939393939393939], [0.5353535353535354], [0.8888888888888888], [0.3434343434343434], [0.1111111111111111], [0.2222222222222222], [0.41414141414141414], [0.8787878787878787], [0.7878787878787878], [0.20202020202020202], [0.3333333333333333], [0.2626262626262626], [0.6262626262626262], [0.48484848484848486], [0.4444444444444444], [0.9090909090909091], [0.12121212121212122], [0.9393939393939393]], "basis_function": "gaussian", "weights": [[7.557659474608954], [-13.580571363857871], [-0.0013114429384586401], [8.936002747402199], [18.562123829644406], [-5.191113421969931], [-15.230376695184532], [7.228545765899071], [-24.055019284009177], [-9.217174556850296], [-2.195791781767184], [20.469328475786824], [0.6792154013965046], [-10.825834495968593], [-17.389650103203167], [-20.321918088309758], [6.118492608606175], [12.88368118994913], [-3.0478884089607163], [-0.6826250540143519], [-7.544862441187433], [-3.732126722628891], [-15.647040309176646], [4.822599111117597], [-15.729523441979836], [-5.8719127886574825], [-6.301883643344354], [20.570473820982443], [-15.495274638637056], [12.252416945399546], [-19.714832850237144], [42.85383465425548], [-10.430752108819433], [-30.637398890896293], [40.70707259204937], [39.34781702843975], [1.1216636804674636], [-16.798930011224], [12.809819515798154], [-2.570614328273223], [-1.605159066948545], [2.149278554663397], [-26.83174891267845], [-2.4552845378748316], [4.701073110270954], [-8.56970857808119], [4.925748128294799], [14.592126194759658], [-8.436272208135051], [-27.631664374486718], [-1.5443324243206007], [-4.714176599261009], [13.663103518265416], [-13.088172614239738], [-5.679703028239601], [6.552610227088735], [-9.871294108343136], [10.57416181471126], [-10.026225160992908], [12.108300760472048], [-16.412098956221598], [-8.409007852547802], [5.006987513850618], [19.005955647524388], [0.33982090665085707], [24.233254239854432], [2.0473554274076378], [-3.5733766860075775], [-6.393512371443649], [4.525621414701163], [4.157110718064359], [7.824619262700253], [-11.362762508499145], [19.385104925517226], [11.620692711258016], [3.3777877848806384], [17.624797227188537], [-2.25965603471559], [1.5298592178987747], [-4.958699834096478]], "sigma": 0.5, "regularization_parameter": 1e-05, "rmse": 0.0001448967594405131, "R2": 0.9999997565062678, "x_data_min": [[10.0]], "x_data_max": [[10000.0]], "y_data_min": [25279.514640115292], "y_data_max": [22646995.556103665]}, "map": {"x_data_columns": "list", "x_data": "numpy", "centres": "numpy", "basis_function": "str", "weights": "numpy", "sigma": "str", "regularization_parameter": "str", "rmse": "str", "R2": "str", "x_data_min": "numpy", "x_data_max": "numpy", "y_data_min": "numpy", "y_data_max": "numpy"}}, "land_req": {"attr": {"x_data_columns": ["design_size"], "x_data": [[0.707070707070707], [0.030303030303030304], [0.3131313131313131], [0.1919191919191919], [0.3535353535353535], [0.9191919191919191], [0.7474747474747474], [0.10101010101010101], [0.7676767676767676], [0.1414141414141414], [0.797979797979798], [0.2525252525252525], [0.7171717171717171], [0.6666666666666666], [0.7575757575757576], [0.06060606060606061], [0.3838383838383838], [0.3636363636363636], [0.9292929292929293], [0.40404040404040403], [0.4242424242424242], [0.1313131313131313], [0.050505050505050504], [0.5656565656565656], [0.8282828282828283], [0.0], [0.0101010101010101], [0.5252525252525252], [0.1616161616161616], [0.0808080808080808], [0.0707070707070707], [1.0], [0.24242424242424243], [0.7777777777777778], [0.9898989898989898], [0.9797979797979798], [0.8989898989898989], [0.8383838383838385], [0.5454545454545454], [0.4949494949494949], [0.7272727272727272], [0.2121212121212121], [0.696969696969697], [0.9595959595959596], [0.47474747474747475], [0.505050505050505], [0.6363636363636364], [0.1818181818181818], [0.7373737373737373], [0.8686868686868686], [0.5757575757575758], [0.23232323232323232], [0.2727272727272727], [0.6767676767676768], [0.3232323232323232], [0.5555555555555556], [0.8181818181818181], [0.46464646464646464], [0.5151515151515151], [0.0909090909090909], [0.606060606060606], [0.8080808080808081], [0.3939393939393939], [0.5353535353535354], [0.8888888888888888], [0.3434343434343434], [0.1111111111111111], [0.2222222222222222], [0.41414141414141414], [0.8787878787878787], [0.7878787878787878], [0.20202020202020202], [0.3333333333333333], [0.2626262626262626], [0.6262626262626262], [0.48484848484848486], [0.4444444444444444], [0.9090909090909091], [0.12121212121212122], [0.9393939393939393]], "centres": [[0.707070707070707], [0.030303030303030304], [0.3131313131313131], [0.1919191919191919], [0.3535353535353535], [0.9191919191919191], [0.7474747474747474], [0.10101010101010101], [0.7676767676767676], [0.1414141414141414], [0.797979797979798], [0.2525252525252525], [0.7171717171717171], [0.6666666666666666], [0.7575757575757576], [0.06060606060606061], [0.3838383838383838], [0.3636363636363636], [0.9292929292929293], [0.40404040404040403], [0.4242424242424242], [0.1313131313131313], [0.050505050505050504], [0.5656565656565656], [0.8282828282828283], [0.0], [0.0101010101010101], [0.5252525252525252], [0.1616161616161616], [0.0808080808080808], [0.0707070707070707], [1.0], [0.24242424242424243], [0.7777777777777778], [0.9898989898989898], [0.9797979797979798], [0.8989898989898989], [0.8383838383838385], [0.5454545454545454], [0.4949494949494949], [0.7272727272727272], [0.2121212121212121], [0.696969696969697], [0.9595959595959596], [0.47474747474747475], [0.505050505050505], [0.6363636363636364], [0.1818181818181818], [0.7373737373737373], [0.8686868686868686], [0.5757575757575758], [0.23232323232323232], [0.2727272727272727], [0.6767676767676768], [0.3232323232323232], [0.5555555555555556], [0.8181818181818181], [0.46464646464646464], [0.5151515151515151], [0.0909090909090909], [0.606060606060606], [0.8080808080808081], [0.3939393939393939], [0.5353535353535354], [0.8888888888888888], [0.3434343434343434], [0.1111111111111111], [0.2222222222222222], [0.41414141414141414], [0.8787878787878787], [0.7878787878787878], [0.20202020202020202], [0.3333333333333333], [0.2626262626262626], [0.6262626262626262], [0.48484848484848486], [0.4444444444444444], [0.9090909090909091], [0.12121212121212122], [0.9393939393939393]], "basis_function": "gaussian", "weights": [[6.792046620499605], [-11.110192082516278], [-2.0406721779836516], [9.93113909945987], [18.91813089864445], [-3.1621413279572153], [-14.1464730396292], [6.821469805936886], [-24.337877641683008], [-7.606911239882265], [-1.6700856515781197], [22.588612776744412], [1.5211659695851267], [-9.424810870048532], [-19.27732283450314], [-18.175506377403053], [6.703716028812778], [14.849478497795644], [-4.000514174644195], [-1.4725485577473592], [-9.705113204217923], [-3.851089868188865], [-15.582507593302125], [3.3394781197421253], [-14.964698909934668], [-6.54669623938662], [-7.74771009828919], [21.83157445094548], [-15.338622949222554], [13.29062836783578], [-20.97720156388914], [44.48873911341434], [-10.549790048340583], [-29.311747901549097], [40.746509438729845], [37.79353684918169], [-0.05496240284264786], [-19.00587227028882], [12.696414615042158], [-2.1090222747916414], [-3.733678928885638], [1.7810202127184311], [-25.189752109447], [-3.1912112834033906], [6.541124050898361], [-6.4997234800575825], [6.087258191302681], [13.966627910210264], [-8.960558433485858], [-29.60454174381448], [-1.4244211148943577], [-6.432284578940198], [14.355707000700932], [-14.660829509084579], [-6.122575912697357], [8.04623641877697], [-10.712619473211817], [10.806788899448293], [-10.937962718540803], [10.131555798956015], [-16.05674630426074], [-6.273549302983156], [2.620947481449548], [17.291041404932912], [2.1418782141263364], [22.987295586875916], [3.3773014811231405], [-2.320498261588], [-5.580088462902495], [4.722055860962428], [3.07646791602383], [5.866944546540253], [-10.198740998042922], [18.470366468149223], [11.174753322302422], [2.2369223538407823], [19.23605612938627], [-1.8347135514923139], [-0.18512921195178933], [-4.311587726107973]], "sigma": 0.5, "regularization_parameter": 1e-05, "rmse": 0.00014527506200332678, "R2": 0.9999997552228744, "x_data_min": [[10.0]], "x_data_max": [[10000.0]], "y_data_min": [0.07254508590000001], "y_data_max": [64.97621527110002]}, "map": {"x_data_columns": "list", "x_data": "numpy", "centres": "numpy", "basis_function": "str", "weights": "numpy", "sigma": "str", "regularization_parameter": "str", "rmse": "str", "R2": "str", "x_data_min": "numpy", "x_data_max": "numpy", "y_data_min": "numpy", "y_data_max": "numpy"}}}, "input_labels": ["design_size"], "output_labels": ["annual_energy", "land_req"], "input_bounds": {"design_size": [1, 200000]}, "surrogate_type": "rbf"} \ No newline at end of file diff --git a/src/watertap_contrib/reflo/solar_models/surrogate/pv/pv_surrogate.py b/src/watertap_contrib/reflo/solar_models/surrogate/pv/pv_surrogate.py new file mode 100644 index 00000000..3e651bfa --- /dev/null +++ b/src/watertap_contrib/reflo/solar_models/surrogate/pv/pv_surrogate.py @@ -0,0 +1,192 @@ +############################################################################### +# WaterTAP Copyright (c) 2021, The Regents of the University of California, +# through Lawrence Berkeley National Laboratory, Oak Ridge National +# Laboratory, National Renewable Energy Laboratory, and National Energy +# Technology Laboratory (subject to receipt of any required approvals from +# the U.S. Dept. of Energy). All rights reserved. +# +# Please see the files COPYRIGHT.md and LICENSE.md for full copyright and license +# information, respectively. These files are also available online at the URL +# "https://github.com/watertap-org/watertap/" +# +############################################################################### + +import os +import sys +import re +import time +import pandas as pd +import numpy as np +from pathlib import Path +from io import StringIO +import matplotlib.pyplot as plt + +from pyomo.environ import ConcreteModel, Var, Constraint, units as pyunits, value, Param + +from idaes.core import FlowsheetBlock +from idaes.core import declare_process_block_class +from idaes.core.surrogate.surrogate_block import SurrogateBlock +from idaes.core.surrogate.pysmo_surrogate import PysmoRBFTrainer, PysmoSurrogate +from idaes.core.surrogate.sampling.data_utils import split_training_validation + +from watertap_contrib.reflo.core import SolarEnergyBaseData + +__author__ = "Zachary Binger, Matthew Boyd, Kurban Sitterley" + + +@declare_process_block_class("PVSurrogate") +class PVSurrogateData(SolarEnergyBaseData): + """ + Surrogate model for PV. + """ + + CONFIG = SolarEnergyBaseData.CONFIG() + + def build(self): + super().build() + + self._tech_type = "PV" + self.surrogate_file = os.path.join( + os.path.dirname(__file__), "pv_surrogate.json" + ) + + self.design_size = Var( + initialize=1000, + bounds=[1, 200000], + units=pyunits.kW, + doc="PV design size in kW", + ) + + self.annual_energy = Var( + initialize=1, + units=pyunits.kWh, + doc="Annual energy produced by the plant in kWh", + ) + + self.land_req = Var( + initialize=7e7, + units=pyunits.acre, + doc="Land area required by the plant in acres", + ) + + self.surrogate_inputs = [self.design_size] + self.surrogate_outputs = [self.annual_energy, self.land_req] + + self.input_labels = ["design_size"] + self.output_labels = ["annual_energy", "land_req"] + + self.electricity_constraint = Constraint( + expr=self.annual_energy + == -1 + * self.electricity + * pyunits.convert(1 * pyunits.year, to_units=pyunits.hour) + ) + + def load_surrogate(self): + print("Loading surrogate file...") + self.surrogate_file = os.path.join( + os.path.dirname(__file__), "pv_surrogate.json" + ) + + if os.path.exists(self.surrogate_file): + stream = StringIO() + oldstdout = sys.stdout + sys.stdout = stream + + self.surrogate_blk = SurrogateBlock(concrete=True) + self.surrogate = PysmoSurrogate.load_from_file(self.surrogate_file) + self.surrogate_blk.build_model( + self.surrogate, + input_vars=self.surrogate_inputs, + output_vars=self.surrogate_outputs, + ) + + # Revert back to standard output + sys.stdout = oldstdout + + def get_training_validation(self): + self.dataset_filename = os.path.join( + os.path.dirname(__file__), "data/dataset.pkl" + ) + print("Loading Training Data...\n") + time_start = time.process_time() + pkl_data = pd.read_pickle(self.dataset_filename) + data = pkl_data.sample(n=int(len(pkl_data))) # FIX default this to 100% of data + self.data_training, self.data_validation = split_training_validation( + data, self.training_fraction, seed=len(data) + ) + time_stop = time.process_time() + print("Data Loading Time:", time_stop - time_start, "\n") + + def create_surrogate( + self, + save=False, + ): + self.sample_fraction = 0.1 # fraction of the generated data to train with. More flexible than n_samples. + self.training_fraction = 0.8 + + self.get_training_validation() + time_start = time.process_time() + # Capture long output + stream = StringIO() + oldstdout = sys.stdout + sys.stdout = stream + + # Create PySMO trainer object + trainer = PysmoRBFTrainer( + input_labels=self.input_labels, + output_labels=self.output_labels, + training_dataframe=self.data_training, + ) + + # Set PySMO options + trainer.config.basis_function = "gaussian" # default = gaussian + trainer.config.solution_method = "algebraic" # default = algebraic + trainer.config.regularization = True # default = True + + # Train surrogate + rbf_train = trainer.train_surrogate() + + # Remove autogenerated 'solution.pickle' file + try: + os.remove("solution.pickle") + except FileNotFoundError: + pass + except Exception as e: + raise e + # Create callable surrogate object + xmin, xmax = [self.design_size.bounds[0]], [self.design_size.bounds[1]] + input_bounds = { + self.input_labels[i]: (xmin[i], xmax[i]) + for i in range(len(self.input_labels)) + } + rbf_surr = PysmoSurrogate( + rbf_train, self.input_labels, self.output_labels, input_bounds + ) + + # Save model to JSON + if (self.surrogate_file is not None) and (save is True): + print(f"Writing surrogate model to {self.surrogate_file}") + model = rbf_surr.save_to_file(self.surrogate_file, overwrite=True) + + # Revert back to standard output + sys.stdout = oldstdout + + time_stop = time.process_time() + print("Model Training Time:", time_stop - time_start, "\n") + + return rbf_surr + + +if __name__ == "__main__": + m = ConcreteModel() + m.fs = FlowsheetBlock(dynamic=False) + m.fs.pv = PVSurrogate() + m.fs.pv.create_surrogate(save=False) + + m.fs.pv.load_surrogate() + + results = m.fs.pv.surrogate.evaluate_surrogate( + m.fs.pv.data_validation[m.fs.pv.input_labels] + ) + print(results)