├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── component_import.py ├── config.py ├── pv3_main.py ├── pv3_pvlib_sam_data.ipynb ├── pv3_pvlib_sonnja.py ├── pv3_results.py ├── pv3_sonnja_pvlib.py ├── pv3_sonnja_results.ipynb ├── pv3_tools.py ├── pv3_weatherdata.py ├── requirements.yml └── settings.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | # PyCharm 132 | .idea/ 133 | 134 | # Data 135 | data/ -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | The format is inspired from [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 5 | and the versioning aim to respect [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 6 | 7 | Here is a template for new release sections 8 | 9 | ``` 10 | ## [_._._] - 20XX-MM-DD 11 | 12 | ### Added 13 | - 14 | ### Changed 15 | - 16 | ### Removed 17 | - 18 | ``` 19 | 20 | ## [1.0.0] 21 | 22 | ### Added 23 | * Make pvlib model executable 24 | * Add all pv modules and converters by adding parameter functions 25 | * Add documentation 26 | * Weather data export for POLYSUN and PVSOL 27 | * Result visualisations 28 | 29 | ### Changed 30 | * Change pvlib model file 31 | 32 | ### Removed 33 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Development 2 | 3 | ### Prerequisites 4 | 5 | - [Git](https://git-scm.com/) 6 | 7 | ### Contributions 8 | ### Workflow 9 | 10 | The development of a feature for this repository is inspired from the workflow described 11 | by [Vincent Driessen](https://nvie.com/posts/a-successful-git-branching-model/): 12 | 13 | 1. Create [an issue](https://help.github.com/en/articles/creating-an-issue) on the github repository 14 | 15 | Discussion about the implementation details should occur within this issue. 16 | 17 | 2. Checkout `develop` and pull the latest changes 18 | ```bash 19 | git checkout develop 20 | ``` 21 | ```bash 22 | git pull 23 | ``` 24 | 3. Create a branch from `develop` to work on your issue (see below, the "Branch name convention" section) 25 | ```bash 26 | git checkout -b feature/myfeature 27 | ``` 28 | 4. Push your local branch on the remote server `origin` 29 | ```bash 30 | git push 31 | ``` 32 | If your branch does not exist on the remote server yet, git will provide you with instructions, simply follow them 33 | 5. Submit a pull request (PR) 34 | - Follow the [steps](https://help.github.com/en/articles/creating-a-pull-request) of the github help to create the PR. 35 | - Please note that you PR should be directed from your branch (for example `myfeature`) towards the branch `develop` 36 | 6. Describe briefly (i.e. in one or two lines) what you changed in the `CHANGELOG.md` file. End the description by the number in parenthesis `(#)` 37 | 7. Commit the changes to the `CHANGELOG.md` file 38 | 8. Write the PR number in the corresponding issue so that they are linked. Write it with one of the [special keywords](https://help.github.com/en/github/managing-your-work-on-github/closing-issues-using-keywords) so that the issue will be automatically closed when the PR is merged (example: `Closes #`) 39 | 9. [Ask](https://help.github.com/en/github/managing-your-work-on-github/assigning-issues-and-pull-requests-to-other-github-users) for review of your PR 40 | 41 | 10. Check that, after this whole process, you branch does not have conflict with `develop` (github prevents you to merge if there are conflicts). In case of conflicts you are responsible to fix them on your branch before your merge (see below "Fixing merge conflicts" section) 42 | 43 | 11. (if approved) Merge the PR into `develop` and delete the branch on which you were working. In the merge message on github, you can notify people who are currently working on other branches that you just merged into `develop`, so they know they have to check for potential conflicts with `develop` 44 | 45 | 46 | ### Fixing merge conflicts 47 | 48 | 49 | Avoid large merge conflict by merging the updated `develop` versions in your branch. 50 | 51 | In case of conflicts between your branch and `develop` you must solve them locally. 52 | 53 | 1. Get the latest version of `develop` 54 | ```bash 55 | git checkout develop 56 | ``` 57 | 58 | ```bash 59 | git pull 60 | ``` 61 | 62 | 2. Switch to your branch 63 | 64 | ```bash 65 | git checkout 66 | ``` 67 | 68 | 3. Merge `develop` into your branch 69 | ```bash 70 | git merge develop 71 | ``` 72 | 73 | 4. The conflicts have to be [manually](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/resolving-a-merge-conflict-using-the-command-line) resolved 74 | 75 | 76 | 77 | ### Branch name convention 78 | The convention is to always have `feature-#-myfeature` in the branch name. 79 | The `#` is the issue number. 80 | The `myfeature` part should describe shortly what the feature is about (separate words with `-`). 81 | 82 | Try to follow [these conventions](https://chris.beams.io/posts/git-commit) for commit messages: 83 | - Keep the subject line [short](https://chris.beams.io/posts/git-commit/#limit-50) (i.e. do not commit more than a few changes at the time) 84 | - Use [imperative](https://chris.beams.io/posts/git-commit/#imperative) for commit messages 85 | - Do not end the commit message with a [period](https://chris.beams.io/posts/git-commit/#end) 86 | You can use 87 | ```bash 88 | git commit --amend 89 | ``` 90 | to edit the commit message of your latest commit (provided it is not already pushed on the remote server). 91 | With `--amend` you can even add/modify changes to the commit. 92 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2020, HTW - PV3 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PV3 - SonnJA pvlib model 2 | 3 | PV3 4 | 5 | ## License / Copyright 6 | 7 | This repository is licensed under [BSD 3-Clause License (BSD-3-Clause)](https://www.gnu.org/licenses/agpl-3.0.en.html) 8 | 9 | ## Research object 10 | 11 | The test object is the PV system SonnJA!, which was planned by students of the HTW Berlin and the organization einleuchtend e.V.. 12 | It was planned in between 2010 and 2013 and is placed on about 620 m^2 of the roof area of the building G of the Wilheminenhof campus. 13 | The produced electricity of this 16 kWp power plant is fed into one phase of the university internal grid of HTW Berlin and remunerated according to the EEG. 14 | The special quality of this PV system is its conception as a research system: the system has three different module technologies, two types of inverters and a comprehensive monitoring system with its own weather station. 15 | 16 | ## Installation 17 | 18 | ### Setup environment 19 | 20 | `conda env create -f requirements.yml`
21 | `activate d_py38_pv3` 22 | 23 | 24 | ### required packages for this REPO 25 | 26 | csv, colorlover, getpass, glob, IPython.display, json, matplotlib, plotly, pylab, os, pandas, scipy, scipy.interpolate,seaborn, sqalchemy, sys,pvlib 27 | 28 | ### How to start and execute the pvlib 29 | 30 | Start: 31 | 32 | - open cmd and activate your env -> conda activate d_py37_vis 33 | - open pgAdmin and log in to database "sonnJA" 34 | - open git bash in D:\git\github\htw-pv3\pvlib-python-pv3 35 | - update your repository! -> git pull 36 | - open PyCharm and open project "pvlib" 37 | 38 | Your pvlib is now setup and you are ready to run or work in the pvlib! (make sure to create a local branch for changes) 39 | 40 | Execute: 41 | 42 | - if you want to create new export files, make sure to remove the "#" at the start of each "Export Data" line in pv3_main.py 43 | - run pv3_main 44 | - PyCharm will ask you for the password of the database -> type it in and the pvlib will continue 45 | - new csv- and dat-files will be created and added to D:\git\github\htw-pv3\pvlib-python-pv3\data 46 | 47 | ### Setup folder and data 48 | 49 | Create a folder _data_ and _data/pv3_2015_ 50 | Run SQL scripts to create and fill database with weather data: https://github.com/htw-pv3/weather-data/tree/master/postgresql 51 | 52 | Note: The data used is not provided due to licensing issues.
53 | Please contact @Ludee for further information. 54 | 55 | ### Database of pvlib 56 | 57 | To find solar modules or inverter in the database of pvlib open pv3_pvlib_sam_data.ipynb in jupyter notebook. 58 | In this file you will find an examples of the existing database's and which components are included. Furthermore the electrical specification 59 | 60 | ### Setup PV-Model 61 | 62 | Steps to simulate a pv-model with pvlib: 63 | - Define location of the object with latitude, longitude, timezone, altitude, name 64 | - Load module and inverter specification with `pvlib.pvsystem.retrieve_sam`function from Sandia or CEC Database 65 | - If module or inverter are not available in Database, the parameters can be changed with the function `module.copy()` 66 | - Setup PVsystem with: module technologies, inverters types, surface_tilt, surface_azimuth, albedo, modules_per_string, strings_per_inverter 67 | - Build and setup a ModelChain composed of location and PVsystem 68 | - Run a basic model with `run_modelchain(mc, weather_data)` -> function returns output mc.ac and mc.dc Power in watts 69 | 70 | more infos and functions here: https://pvlib-python.readthedocs.io/en/stable/index.html 71 | 72 | -------------------------------------------------------------------------------- /component_import.py: -------------------------------------------------------------------------------- 1 | import pvlib 2 | import numpy as np 3 | 4 | 5 | def get_sma_sb_3000hf(): 6 | """ 7 | Import the Inverter SMA SUNNY BOY 3000HF to pvlib 8 | 9 | :return: 10 | inverter dictionary, type: sandia model 11 | """ 12 | # inverter efficiency at different power points (source: SMA WirkungDerat-TI-de-36 | Version 3.6) 13 | eta_min = [0, 0.942, 0.95, 0.951, 0.94, 0.932] # P/P_max = 0, 0.2, 0.3, 0.5, 0.75, 1; U = 210V 14 | eta_nom = [0, 0.953, 0.961, 0.963, 0.96, 0.954] # P/P_max = 0, 0.2, 0.3, 0.5, 0.75, 1; U = 530V 15 | eta_max = [0, 0.951, 0.959, 0.96, 0.96, 0.955] # P/P_max = 0, 0.2, 0.3, 0.5, 0.75, 1; U = 560V 16 | # dc voltage at min, nom and max 17 | dc_voltage = [[210.], [530.], [560.]] 18 | # calculate dc power 19 | p_dc_nom = 3150 20 | p_dc = [0, 0.2 * p_dc_nom, 0.3 * p_dc_nom, 0.5 * p_dc_nom, 0.75 * p_dc_nom, 1 * p_dc_nom] 21 | p_ac_min = [] 22 | p_ac_nom = [] 23 | p_ac_max = [] 24 | val_count = len(eta_min) 25 | 26 | # calculate ac power 27 | for i in range(val_count): 28 | p_ac_min.append(p_dc[i] * eta_min[i]) 29 | p_ac_nom.append(p_dc[i] * eta_nom[i]) 30 | p_ac_max.append(p_dc[i] * eta_max[i]) 31 | 32 | ac_power = np.array(p_ac_min + p_ac_nom + p_ac_max) 33 | 34 | # save all necessary inverter data to a dictionary 35 | sma_sb_data = { 36 | "ac_power": ac_power, 37 | "dc_power": np.array(p_dc + p_dc + p_dc), # Annahme: Strom bleibt in allen Punkten gleich 38 | "dc_voltage": np.array(dc_voltage[0] * val_count + dc_voltage[1] * val_count + dc_voltage[2] * val_count), 39 | "dc_voltage_level": np.array(["Vmin"] * val_count + ["Vnom"] * val_count + ["Vmax"] * val_count), 40 | "p_ac_0": 3000., 41 | "p_nt": 1. 42 | } 43 | 44 | # call method that creates sandia inverter model 45 | inverter = pvlib.inverter.fit_sandia(sma_sb_data["ac_power"], sma_sb_data["dc_power"], sma_sb_data["dc_voltage"], 46 | sma_sb_data["dc_voltage_level"], sma_sb_data["p_ac_0"], sma_sb_data["p_nt"]) 47 | return inverter 48 | 49 | 50 | def get_danfoss_dlx_2_9(): 51 | """ 52 | Import the Inverter Danfoss DLX 2.9 to pvlib 53 | 54 | :return: 55 | inverter dictionary, type: sandia model 56 | """ 57 | # inverter efficiency at different power points (source: PV*SOL) 58 | eta_min = [0, 0.953, 0.959, 0.963, 0.9612, 0.959] # P/P_max = 0, 0.2, 0.3, 0.5, 0.75, 1; U = 210V 59 | eta_nom = [0, 0.961, 0.967, 0.971, 0.969, 0.967] # P/P_max = 0, 0.2, 0.3, 0.5, 0.75, 1; U = 530V 60 | eta_max = [0, 0.952, 0.958, 0.962, 0.96, 0.958] # P/P_max = 0, 0.2, 0.3, 0.5, 0.75, 1; U = 560V 61 | # dc voltage at min, nom and max 62 | dc_voltage = [[230.], [350.], [480.]] 63 | # calculate dc power 64 | p_dc_nom = 3750 65 | p_dc = [0, 0.2 * p_dc_nom, 0.3 * p_dc_nom, 0.5 * p_dc_nom, 0.75 * p_dc_nom, 1 * p_dc_nom] 66 | p_ac_min = [] 67 | p_ac_nom = [] 68 | p_ac_max = [] 69 | val_count = len(eta_min) 70 | 71 | # calculate ac power 72 | for i in range(val_count): 73 | p_ac_min.append(p_dc[i] * eta_min[i]) 74 | p_ac_nom.append(p_dc[i] * eta_nom[i]) 75 | p_ac_max.append(p_dc[i] * eta_max[i]) 76 | 77 | ac_power = np.array(p_ac_min + p_ac_nom + p_ac_max) 78 | 79 | # save all necessary inverter data to a dictionary 80 | sma_sb_data = { 81 | "ac_power": ac_power, 82 | "dc_power": np.array(p_dc + p_dc + p_dc), # Annahme: Strom bleibt in allen Punkten gleich 83 | "dc_voltage": np.array(dc_voltage[0] * val_count + dc_voltage[1] * val_count + dc_voltage[2] * val_count), 84 | "dc_voltage_level": np.array(["Vmin"] * val_count + ["Vnom"] * val_count + ["Vmax"] * val_count), 85 | "p_ac_0": 2900., 86 | "p_nt": 1. # power consumed while inverter is not delivering AC power 87 | } 88 | 89 | # call method that creates sandia inverter model 90 | inverter = pvlib.inverter.fit_sandia(sma_sb_data["ac_power"], sma_sb_data["dc_power"], sma_sb_data["dc_voltage"], 91 | sma_sb_data["dc_voltage_level"], sma_sb_data["p_ac_0"], sma_sb_data["p_nt"]) 92 | return inverter 93 | 94 | 95 | def get_aleo_s18_240(): 96 | """Import Aleo S18 240 W PV-Modul""" 97 | sam_cec_mod = pvlib.pvsystem.retrieve_sam('CECMod') 98 | aleo_s18_240 = sam_cec_mod['Aleo_Solar_S18y250'].copy() 99 | aleo_s18_240['STC'] = 240. 100 | aleo_s18_240['PTC'] = 215.04 101 | aleo_s18_240['V_mp_ref'] = 29.5 102 | aleo_s18_240['V_oc_ref'] = 37.0 103 | aleo_s18_240['I_mp_ref'] = 8.13 104 | aleo_s18_240['I_sc_ref'] = 8.65 105 | aleo_s18_240['alpha_sc'] = 0.04 106 | aleo_s18_240['beta_oc'] = -0.34 107 | aleo_s18_240['gamma_r'] = -0.46 108 | return aleo_s18_240 109 | # The PTC value was calculated by dividing the STC of the created module 110 | # by the STC of the reference module and multiplying it by the PTC of the reference module. 111 | # All other values were taken from the data sheet. 112 | 113 | # adding the specific Modul parameters for aleo_s19_245 114 | def get_aleo_s19_245(): 115 | """Import Aleo S19 245 W PV-Modul""" 116 | sam_cec_mod = pvlib.pvsystem.retrieve_sam('CECMod') 117 | aleo_s19_245 = sam_cec_mod['Aleo_Solar_S19Y270'].copy() 118 | aleo_s19_245['STC'] = 245. 119 | aleo_s19_245['PTC'] = 220. 120 | aleo_s19_245['V_mp_ref'] = 31.3 121 | aleo_s19_245['V_oc_ref'] = 37.1 122 | aleo_s19_245['I_mp_ref'] = 7.84 123 | aleo_s19_245['I_sc_ref'] = 8.48 124 | aleo_s19_245['alpha_sc'] = 0.03 125 | aleo_s19_245['beta_oc'] = -0.34 126 | aleo_s19_245['gamma_r'] = -0.48 127 | return aleo_s19_245 128 | # The PTC value was calculated by dividing the STC of the created module 129 | # by the STC of the reference module and multiplying it by the PTC of the reference module. 130 | # All other values were taken from the data sheet. 131 | 132 | # adding data for aleo_s19_285, even though the module is in the CEC-Database 133 | def get_aleo_s19_285(): 134 | """Import Aleo S19 285 W PV-Modul""" 135 | sam_cec_mod = pvlib.pvsystem.retrieve_sam('CECMod') 136 | aleo_s19_285 = sam_cec_mod['Aleo_Solar_S19y285'].copy() 137 | aleo_s19_285['STC'] = 285. 138 | aleo_s19_285['PTC'] = 261.25 139 | aleo_s19_285['V_mp_ref'] = 31.3 140 | aleo_s19_285['V_oc_ref'] = 39.2 141 | aleo_s19_285['I_mp_ref'] = 9.10 142 | aleo_s19_285['I_sc_ref'] = 9.73 143 | aleo_s19_285['alpha_sc'] = 0.05 144 | aleo_s19_285['beta_oc'] = -0.30 145 | aleo_s19_285['gamma_r'] = -0.43 146 | return aleo_s19_285 147 | # The PTC value was calculated by dividing the STC of the created module 148 | # by the STC of the reference module and multiplying it by the PTC of the reference module. 149 | # All other values were taken from the data sheet. 150 | 151 | def get_schott_asi_105(): 152 | """Import Schott a-Si 105 W PV-Modul""" 153 | sam_cec_mod = pvlib.pvsystem.retrieve_sam('CECMod') 154 | schott = sam_cec_mod['Bosch_Solar_Thin_Film_um_Si_plus_105'].copy() 155 | schott['I_sc_ref'] = 3.98 156 | schott['V_oc_ref'] = 41.0 157 | schott['I_mp_ref'] = 3.38 158 | schott['V_mp_ref'] = 31.1 159 | schott['STC'] = 105 160 | schott['PTC'] = 95 161 | schott['alpha_sc'] = 0.08 162 | schott['beta_oc'] = -0.33 163 | schott['gamma_r'] = -0.2 164 | schott['Length'] = 1.308 165 | schott['Width'] = 1.108 166 | schott['T_NOCT'] = 49 167 | return schott 168 | # The PTC value was calculated by dividing the STC of the created module 169 | # by the STC of the reference module and multiplying it by the PTC of the reference module. 170 | # All other values were taken from the data sheet. 171 | 172 | if __name__ == "__main__": 173 | print('Show inverters') 174 | sma = get_sma_sb_3000hf() 175 | print(sma) 176 | dan = get_danfoss_dlx_2_9() 177 | print(dan) 178 | 179 | aleo_s18_240 = get_aleo_s18_240 180 | print(aleo_s18_240) 181 | aleo_s19_245 = get_aleo_s19_245 182 | print(aleo_s19_245) 183 | aleo_s19_285 = get_aleo_s19_285() 184 | print(aleo_s19_285) 185 | aleo_asi_105 = get_schott_asi_105() 186 | print(aleo_asi_105) 187 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | HTW-PV3 - Config file functions (not used atm) 6 | 7 | Create and handle a config file for database connection 8 | 9 | SPDX-License-Identifier: AGPL-3.0-or-later 10 | """ 11 | 12 | __copyright__ = "© Ludwig Hülk" 13 | __license__ = "GNU Affero General Public License Version 3 (AGPL-3.0)" 14 | __url__ = "https://www.gnu.org/licenses/agpl-3.0.en.html" 15 | __author__ = "Ludee;" 16 | __version__ = "v0.0.2" 17 | 18 | import os 19 | import configparser as cp 20 | 21 | """parameter""" 22 | cfg = cp.RawConfigParser() 23 | config_file = 'config.ini' 24 | 25 | # Datenbankzugriffe, Host, Port, User, Passwort, ... 26 | def config_section_set(config_section, host, port, user, pw): 27 | """Create a config file. 28 | 29 | Sets input values to a [db_section] key - pair. 30 | 31 | Parameters 32 | ---------- 33 | config_section : str 34 | Section in config file = database_name. 35 | host : str 36 | The database host = localhost. 37 | port : str 38 | The database port. 39 | user : str 40 | The database user. 41 | pw : str 42 | The PW. 43 | """ 44 | 45 | with open(config_file, 'w') as config: # save 46 | if not cfg.has_section(config_section): 47 | cfg.add_section(config_section) 48 | cfg.set(config_section, 'host', host) 49 | cfg.set(config_section, 'port', port) 50 | cfg.set(config_section, 'user', user) 51 | cfg.set(config_section, 'pw', pw) 52 | cfg.write(config) 53 | 54 | # Einlesen der Datenbankzugriffe 55 | def config_file_load(): 56 | """Load the username and pw from config file.""" 57 | 58 | if os.path.isfile(config_file): 59 | config_file_init() 60 | else: 61 | config_file_not_found_message() 62 | 63 | # Initialisieren und checken der Datenbankzugriffe 64 | def config_file_init(): 65 | """Read config file.""" 66 | 67 | try: 68 | # print('Load ' + config_file) 69 | cfg.read(config_file) 70 | global _loaded 71 | _loaded = True 72 | except FileNotFoundError: 73 | config_file_not_found_message() 74 | 75 | # Setting auslesen 76 | def config_file_get(config_section, port): 77 | """Read data from config file. 78 | 79 | Parameters 80 | ---------- 81 | config_section : str 82 | Section in config file. 83 | port : str 84 | Config entries. 85 | """ 86 | 87 | if not _loaded: 88 | config_file_init() 89 | try: 90 | return cfg.getfloat(config_section, port) 91 | except Exception: 92 | try: 93 | return cfg.getint(config_section, port) 94 | except: 95 | try: 96 | return cfg.getboolean(config_section, port) 97 | except: 98 | return cfg.get(config_section, port) 99 | 100 | # Ausagebemessage, wenn file nicht gefunden wurde 101 | def config_file_not_found_message(): 102 | """Show error message if file not found.""" 103 | 104 | print(f'The config file "{config_file}" could not be found') 105 | 106 | # Erstellen der Postgres-Session(gleiche Funktion, wie bei Juypter Notebook) 107 | def setup_config(): 108 | """Access config.ini. 109 | 110 | Returns 111 | ------- 112 | user : str 113 | marktakteurMastrNummer (value). 114 | token : str 115 | API token (key). 116 | """ 117 | config_section = 'MaStR' 118 | 119 | # user 120 | try: 121 | config_file_load() 122 | user = config_file_get(config_section, 'user') 123 | # print('Hello ' + user) 124 | except: 125 | user = input('Please provide your MaStR Nummer:') 126 | 127 | # token 128 | try: 129 | from settings import config_file_get 130 | token = config_file_get(config_section, 'token') 131 | except: 132 | import sys 133 | token = input('Token:') 134 | # token = getpass.getpass(prompt='apiKey: ', 135 | # stream=sys.stderr) 136 | config_section_set(config_section, value=user, key=token) 137 | print('Config file created.') 138 | return user, token 139 | -------------------------------------------------------------------------------- /pv3_main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | HTW-PV3 - Main file 6 | 7 | Export weatherdata for PVSOL and POLYSUN 8 | Run pvlib modell 9 | 10 | SPDX-License-Identifier: AGPL-3.0-or-later 11 | """ 12 | 13 | __copyright__ = "© Ludwig Hülk" 14 | __license__ = "GNU Affero General Public License Version 3 (AGPL-3.0)" 15 | __url__ = "https://www.gnu.org/licenses/agpl-3.0.en.html" 16 | __author__ = "Ludee;" 17 | __version__ = "v0.0.2" 18 | 19 | from settings import setup_logger, postgres_session, query_database, read_from_csv, write_to_csv, HTW_LON, HTW_LAT 20 | from pv3_sonnja_pvlib import setup_pvlib_location_object, setup_modelchain, run_modelchain, setup_htw_pvsystem_wr3, \ 21 | setup_htw_pvsystem_wr4, setup_htw_pvsystem_wr2, setup_htw_pvsystem_wr1, setup_htw_pvsystem_wr5 22 | from pv3_weatherdata import calculate_diffuse_irradiation 23 | from pv3_results import results_modelchain, results_modelchain_annual_yield, results_modelchain_per_month 24 | 25 | import pandas as pd 26 | from sqlalchemy import * 27 | 28 | import time 29 | 30 | 31 | DATA_VERSION = 'htw_pv3_v0.0.1' 32 | 33 | if __name__ == "__main__": 34 | 35 | """logging""" 36 | log = setup_logger() 37 | start_time = time.time() 38 | 39 | """database""" 40 | con = postgres_session() 41 | log.info(f'PV3 model started with data version: {DATA_VERSION}') 42 | 43 | """Read data""" 44 | # read htw weatherdata from file 45 | # fn_htw = r'.\data\pv3_2015\pv3_weather_2015_filled_mview.csv' 46 | # df_htw_file = read_from_csv(fn_htw) 47 | # fn_fred = r'.\data\pv3_2015\openfred_weatherdata_2015_htw.csv' 48 | # df_fred_file = read_from_csv(fn_fred, sep=',') 49 | 50 | # read htw weatherdata from sonnja_db 51 | # ToDO: Create function for weather data import 52 | schema = 'pv3' 53 | table = 'pv3_weather_2015_filled_mview' 54 | df_htw = query_database(con, schema, table) 55 | 56 | htw_weatherdata_names = {"g_hor_si": "ghi", 57 | 'v_wind': "wind_speed", 58 | 't_luft': "temp_air", 59 | } 60 | df_htw = df_htw.rename(columns=htw_weatherdata_names) 61 | df_dhi = calculate_diffuse_irradiation(df_htw, "ghi", HTW_LAT, HTW_LON) 62 | df_htw = df_htw.merge(df_dhi[['dhi', 'dni']], left_index=True, right_index=True) 63 | df_htw_select = df_htw.loc[:, ["ghi", "dhi", 'dni', "wind_speed", "temp_air"]] 64 | df_htw_pvlib = df_htw_select.resample('H').mean() 65 | df_htw_pvlib = df_htw_pvlib.round(1) 66 | 67 | # read open_FRED weatherdata from sonnja_db 68 | schema = 'pv3' 69 | table = 'openfred_weatherdata_2015_htw' 70 | df_fred = query_database(con, schema, table) 71 | df_fred_select = df_fred.loc[:, ["ghi", "dhi", 'dni', "wind_speed", "temp_air"]] 72 | df_fred_pvlib = df_fred_select.resample('H').mean() 73 | df_fred_pvlib = df_fred_pvlib.round(1) 74 | 75 | """Run pvlib model""" 76 | # location 77 | htw_location = setup_pvlib_location_object() 78 | 79 | # pv system 80 | wr1 = setup_htw_pvsystem_wr1() 81 | wr2 = setup_htw_pvsystem_wr2() 82 | wr3 = setup_htw_pvsystem_wr3() 83 | wr4 = setup_htw_pvsystem_wr4() 84 | wr5 = setup_htw_pvsystem_wr5() 85 | pv_systems = [wr1, wr2, wr3, wr4, wr5] 86 | weather = ['fred', 'htw'] 87 | # ToDo: include second loop with weather 88 | 89 | # model chain 90 | for idx, system in enumerate(pv_systems): 91 | # setup Modelchain 92 | mc_fred = setup_modelchain(system, htw_location) 93 | mc_htw = setup_modelchain(system, htw_location) 94 | 95 | # run modelchain 96 | run_modelchain(mc_fred, df_fred_pvlib) 97 | run_modelchain(mc_htw, df_htw_pvlib) 98 | 99 | 100 | """Export results""" 101 | df_fred = results_modelchain(mc_fred, 'fred') 102 | df_month_fred = results_modelchain_per_month(mc_fred, df_fred, 'fred') 103 | annual_yield_fred = results_modelchain_annual_yield(mc_fred, 'fred') 104 | 105 | df_htw = results_modelchain(mc_htw, 'htw') 106 | df_month_htw = results_modelchain_per_month(mc_htw, df_htw, 'htw') 107 | annual_yield_htw = results_modelchain_annual_yield(mc_htw, 'htw') 108 | 109 | 110 | """close""" 111 | log.info('PV3 SonnJA pvlib model successfully executed in {:.2f} seconds' 112 | .format(time.time() - start_time)) 113 | -------------------------------------------------------------------------------- /pv3_pvlib_sam_data.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# PV3 PVLIB technology database (modules and inverters)\n", 8 | "\n", 9 | "\n", 10 | "\n", 11 | "__copyright__ \t= \"© Reiner Lemoine Institut\"
\n", 12 | "__license__ \t= \"GNU Affero General Public License Version 3 (AGPL-3.0)\"
\n", 13 | "__url__ \t\t= \"https://www.gnu.org/licenses/agpl-3.0.en.html\"
\n", 14 | "__author__ \t\t= \"Julian Endres, Ludwig Hülk\"
" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Documentation\n", 22 | "\n", 23 | "https://pvlib-python.readthedocs.io/en/stable/generated/pvlib.pvsystem.retrieve_sam.html
\n", 24 | "https://sam.nrel.gov/photovoltaic/pv-publications" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "### Imports" 32 | ] 33 | }, 34 | { 35 | "cell_type": "code", 36 | "execution_count": 1, 37 | "metadata": {}, 38 | "outputs": [], 39 | "source": [ 40 | "import json\n", 41 | "import pandas as pd\n", 42 | "import pvlib\n", 43 | "from pvlib import pvsystem" 44 | ] 45 | }, 46 | { 47 | "cell_type": "markdown", 48 | "metadata": {}, 49 | "source": [ 50 | "### Retrieve SAM dataset" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": 2, 56 | "metadata": {}, 57 | "outputs": [], 58 | "source": [ 59 | "sam_cec_inv = pvlib.pvsystem.retrieve_sam('CECInverter')\n", 60 | "sam_adr_inv = pvlib.pvsystem.retrieve_sam('ADRInverter')\n", 61 | "sam_inv_list = ['sam_cec_inv', 'sam_adr_inv']\n", 62 | "\n", 63 | "sam_cec_mod = pvlib.pvsystem.retrieve_sam('CECMod')\n", 64 | "sam_sandia_mod = pvlib.pvsystem.retrieve_sam('SandiaMod')\n", 65 | "sam_mod_list = ['sam_cec_mod', 'sam_sandia_mod']" 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": {}, 71 | "source": [ 72 | "### Query for manufacturer" 73 | ] 74 | }, 75 | { 76 | "cell_type": "code", 77 | "execution_count": 3, 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "# Inverters\n", 82 | "sam_inv_dict = {}\n", 83 | "sam_inv_dict['cec'] = {}\n", 84 | "sam_inv_dict['adr'] = {}\n", 85 | "\n", 86 | "indices = [i for i, s in enumerate(list(sam_cec_inv.columns)) if 'sma' in s.lower()]\n", 87 | "sam_inv_dict['cec']['sma'] = [list(sam_cec_inv.columns)[i] for i in indices]\n", 88 | "\n", 89 | "indices = [i for i, s in enumerate(list(sam_cec_inv.columns)) if 'danfoss' in s.lower()]\n", 90 | "sam_inv_dict['cec']['danfoss'] = [list(sam_cec_inv.columns)[i] for i in indices]\n", 91 | "\n", 92 | "indices = [i for i, s in enumerate(list(sam_adr_inv.columns)) if 'sma' in s.lower()]\n", 93 | "sam_inv_dict['adr']['sma'] = [list(sam_adr_inv.columns)[i] for i in indices]\n", 94 | "\n", 95 | "indices = [i for i, s in enumerate(list(sam_adr_inv.columns)) if 'danfoss' in s.lower()]\n", 96 | "sam_inv_dict['adr']['danfoss'] = [list(sam_adr_inv.columns)[i] for i in indices]" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 4, 102 | "metadata": {}, 103 | "outputs": [ 104 | { 105 | "data": { 106 | "text/plain": [ 107 | "['SMA_America__SB_240_US_10__240V_',\n", 108 | " 'SMA_America__SB10000TL_US__208V_',\n", 109 | " 'SMA_America__SB10000TL_US__240V_',\n", 110 | " 'SMA_America__SB10000TL_US_12__208V_',\n", 111 | " 'SMA_America__SB10000TL_US_12__240V_',\n", 112 | " 'SMA_America__SB11000TL_US__240V_',\n", 113 | " 'SMA_America__SB11000TL_US_12__240V_',\n", 114 | " 'SMA_America__SB1100U__240V_',\n", 115 | " 'SMA_America__SB1100U_SBD__240V_',\n", 116 | " 'SMA_America__SB2000HFUS_30__208V_',\n", 117 | " 'SMA_America__SB2000HFUS_30__240V_',\n", 118 | " 'SMA_America__SB2500HFUS_30__208V_',\n", 119 | " 'SMA_America__SB2500HFUS_30__240V_',\n", 120 | " 'SMA_America__SB3_0_1SP_US_40__208V_',\n", 121 | " 'SMA_America__SB3_0_1SP_US_40__240V_',\n", 122 | " 'SMA_America__SB3_0_1TP_US_40__208V_',\n", 123 | " 'SMA_America__SB3_0_1TP_US_40__240V_',\n", 124 | " 'SMA_America__SB3_8_1SP_US_40__208V_',\n", 125 | " 'SMA_America__SB3_8_1SP_US_40__240V_',\n", 126 | " 'SMA_America__SB3_8_1TP_US_40__208V_',\n", 127 | " 'SMA_America__SB3_8_1TP_US_40__240V_',\n", 128 | " 'SMA_America__SB3000HFUS_30__208V_',\n", 129 | " 'SMA_America__SB3000HFUS_30__240V_',\n", 130 | " 'SMA_America__SB3000TL_US_22__208V_',\n", 131 | " 'SMA_America__SB3000TL_US_22__240V_',\n", 132 | " 'SMA_America__SB3000US__208V_',\n", 133 | " 'SMA_America__SB3000US__240V_',\n", 134 | " 'SMA_America__SB3000US_12__208V_',\n", 135 | " 'SMA_America__SB3000US_12__240V_',\n", 136 | " 'SMA_America__SB3300U__240V_',\n", 137 | " 'SMA_America__SB3800TL_US_22__208V_',\n", 138 | " 'SMA_America__SB3800TL_US_22__240V_',\n", 139 | " 'SMA_America__SB3800U__208V_',\n", 140 | " 'SMA_America__SB3800U__240V_',\n", 141 | " 'SMA_America__SB3800US__240V_',\n", 142 | " 'SMA_America__SB3800US_12__240V_',\n", 143 | " 'SMA_America__SB4000TL_US_22__208V_',\n", 144 | " 'SMA_America__SB4000TL_US_22__240V_',\n", 145 | " 'SMA_America__SB4000US__208V_',\n", 146 | " 'SMA_America__SB4000US__240V_',\n", 147 | " 'SMA_America__SB4000US_CL___208V_',\n", 148 | " 'SMA_America__SB4000US_CL___240V_',\n", 149 | " 'SMA_America__SB4000US_12__208V_',\n", 150 | " 'SMA_America__SB4000US_12__240V_',\n", 151 | " 'SMA_America__SB5_0_1SP_US_40__208V_',\n", 152 | " 'SMA_America__SB5_0_1SP_US_40__240V_',\n", 153 | " 'SMA_America__SB5_0_1TP_US_40__208V_',\n", 154 | " 'SMA_America__SB5_0_1TP_US_40__240V_',\n", 155 | " 'SMA_America__SB5000TL_US_22__208V_',\n", 156 | " 'SMA_America__SB5000TL_US_22__240V_',\n", 157 | " 'SMA_America__SB5000US__208V_',\n", 158 | " 'SMA_America__SB5000US__240V_',\n", 159 | " 'SMA_America__SB5000US__277V_',\n", 160 | " 'SMA_America__SB5000US_11__208V_',\n", 161 | " 'SMA_America__SB5000US_11__240V_',\n", 162 | " 'SMA_America__SB5000US_11__277V_',\n", 163 | " 'SMA_America__SB5000US_12__208V_',\n", 164 | " 'SMA_America__SB5000US_12__240V_',\n", 165 | " 'SMA_America__SB5000US_12__277V_',\n", 166 | " 'SMA_America__SB6_0_1SP_US_40__208V_',\n", 167 | " 'SMA_America__SB6_0_1SP_US_40__240V_',\n", 168 | " 'SMA_America__SB6_0_1TP_US_40__208V_',\n", 169 | " 'SMA_America__SB6_0_1TP_US_40__240V_',\n", 170 | " 'SMA_America__SB6000TL_US__208V_',\n", 171 | " 'SMA_America__SB6000TL_US__240V_',\n", 172 | " 'SMA_America__SB6000TL_US_12__208V_',\n", 173 | " 'SMA_America__SB6000TL_US_12__240V_',\n", 174 | " 'SMA_America__SB6000TL_US_22__208V_',\n", 175 | " 'SMA_America__SB6000TL_US_22__240V_',\n", 176 | " 'SMA_America__SB6000U__208V_',\n", 177 | " 'SMA_America__SB6000U__240V_',\n", 178 | " 'SMA_America__SB6000U__277V_',\n", 179 | " 'SMA_America__SB6000US__208V_',\n", 180 | " 'SMA_America__SB6000US__240V_',\n", 181 | " 'SMA_America__SB6000US__277V_',\n", 182 | " 'SMA_America__SB6000US_11__208V_',\n", 183 | " 'SMA_America__SB6000US_11__240V_',\n", 184 | " 'SMA_America__SB6000US_11__277V_',\n", 185 | " 'SMA_America__SB6000US_12__208V_',\n", 186 | " 'SMA_America__SB6000US_12__240V_',\n", 187 | " 'SMA_America__SB6000US_12__277V_',\n", 188 | " 'SMA_America__SB7_0_1SP_US_40__208V_',\n", 189 | " 'SMA_America__SB7_0_1SP_US_40__240V_',\n", 190 | " 'SMA_America__SB7_0_1TP_US_40__208V_',\n", 191 | " 'SMA_America__SB7_0_1TP_US_40__240V_',\n", 192 | " 'SMA_America__SB7_7_1SP_US_40__208V_',\n", 193 | " 'SMA_America__SB7_7_1SP_US_40__240V_',\n", 194 | " 'SMA_America__SB7_7_1TP_US_40__208V_',\n", 195 | " 'SMA_America__SB7_7_1TP_US_40__240V_',\n", 196 | " 'SMA_America__SB7000TL_US__208V_',\n", 197 | " 'SMA_America__SB7000TL_US__240V_',\n", 198 | " 'SMA_America__SB7000TL_US_12__208V_',\n", 199 | " 'SMA_America__SB7000TL_US_12__240V_',\n", 200 | " 'SMA_America__SB7000TL_US_22__208V_',\n", 201 | " 'SMA_America__SB7000TL_US_22__240V_',\n", 202 | " 'SMA_America__SB7000US__208V_',\n", 203 | " 'SMA_America__SB7000US__240V_',\n", 204 | " 'SMA_America__SB7000US__277V_',\n", 205 | " 'SMA_America__SB7000US_11__208V_',\n", 206 | " 'SMA_America__SB7000US_11__240V_',\n", 207 | " 'SMA_America__SB7000US_11__277V_',\n", 208 | " 'SMA_America__SB7000US_12__208V_',\n", 209 | " 'SMA_America__SB7000US_12__240V_',\n", 210 | " 'SMA_America__SB7000US_12__277V_',\n", 211 | " 'SMA_America__SB700U__120V_',\n", 212 | " 'SMA_America__SB700U_SBD__120V_',\n", 213 | " 'SMA_America__SB7700TL_US_22__208V_',\n", 214 | " 'SMA_America__SB7700TL_US_22__240V_',\n", 215 | " 'SMA_America__SB8000TL_US__240V_',\n", 216 | " 'SMA_America__SB8000TL_US_12__208V_',\n", 217 | " 'SMA_America__SB8000TL_US_12__240V_',\n", 218 | " 'SMA_America__SB8000US__240V_',\n", 219 | " 'SMA_America__SB8000US__277V_',\n", 220 | " 'SMA_America__SB8000US_11__240V_',\n", 221 | " 'SMA_America__SB8000US_11__277V_',\n", 222 | " 'SMA_America__SB8000US_12__240V_',\n", 223 | " 'SMA_America__SB8000US_12__277V_',\n", 224 | " 'SMA_America__SB9000TL_US__208V_',\n", 225 | " 'SMA_America__SB9000TL_US__240V_',\n", 226 | " 'SMA_America__SB9000TL_US_12__208V_',\n", 227 | " 'SMA_America__SB9000TL_US_12__240V_',\n", 228 | " 'SMA_America__SBS3_8_US_10__240V_',\n", 229 | " 'SMA_America__SBS5_0_US_10__240V_',\n", 230 | " 'SMA_America__SBS6_0_US_10__240V_',\n", 231 | " 'SMA_America__SC_2500_EV_US__550V_',\n", 232 | " 'SMA_America__SC_2750_EV_US__600V_',\n", 233 | " 'SMA_America__SC_1850_US__385V_',\n", 234 | " 'SMA_America__SC_2200_US__385V_',\n", 235 | " 'SMA_America__SC125U__208V_',\n", 236 | " 'SMA_America__SC125U__480V_',\n", 237 | " 'SMA_America__SC250U__480V_',\n", 238 | " 'SMA_America__SC500CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 239 | " 'SMA_America__SC500CP_US_600V__with_ABB_transformer_',\n", 240 | " 'SMA_America__SC500HE_US_MV__with_Cooper_transformer_',\n", 241 | " 'SMA_America__SC500HE_US_MV__with_NEMA_TP_1_transformer_',\n", 242 | " 'SMA_America__SC630CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 243 | " 'SMA_America__SC720CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 244 | " 'SMA_America__SC750CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 245 | " 'SMA_America__SC800CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 246 | " 'SMA_America__SC850CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 247 | " 'SMA_America__SC900CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 248 | " 'SMA_America__ST36__208V_',\n", 249 | " 'SMA_America__ST36__240V_',\n", 250 | " 'SMA_America__ST36__277V_',\n", 251 | " 'SMA_America__ST42__208V_',\n", 252 | " 'SMA_America__ST42__240V_',\n", 253 | " 'SMA_America__ST42__277V_',\n", 254 | " 'SMA_America__ST48__240V_',\n", 255 | " 'SMA_America__ST48__277V_',\n", 256 | " 'SMA_America__STP_33_US_41__480V_',\n", 257 | " 'SMA_America__STP_50_US_41__480V_',\n", 258 | " 'SMA_America__STP_60_US_10__400V_',\n", 259 | " 'SMA_America__STP_60_US_10__480V_',\n", 260 | " 'SMA_America__STP_62_US_41__480V_',\n", 261 | " 'SMA_America__STP12000TL_US_10__480V_',\n", 262 | " 'SMA_America__STP15000TL_US_10__480V_',\n", 263 | " 'SMA_America__STP20000TL_US_10__480V_',\n", 264 | " 'SMA_America__STP24000TL_US_10__480V_',\n", 265 | " 'SMA_America__STP30000TL_US_10__480V_',\n", 266 | " 'SMA_America__STP50_US_40__480V_',\n", 267 | " 'SMA_America__SWR1800U__120V_',\n", 268 | " 'SMA_America__SWR1800U_SBD__120V_',\n", 269 | " 'SMA_America__SWR2100U__240V_',\n", 270 | " 'SMA_America__SWR2100U_SBD__240V_',\n", 271 | " 'SMA_America__SWR2500U__208V_',\n", 272 | " 'SMA_America__SWR2500U__240V_',\n", 273 | " 'SMA_America__SWR2500U_SBD__208V_',\n", 274 | " 'SMA_America__SWR2500U_SBD__240V_',\n", 275 | " 'SMA_America__Sunny_Island_SI6048']" 276 | ] 277 | }, 278 | "execution_count": 4, 279 | "metadata": {}, 280 | "output_type": "execute_result" 281 | } 282 | ], 283 | "source": [ 284 | "sam_inv_dict['cec']['sma']" 285 | ] 286 | }, 287 | { 288 | "cell_type": "code", 289 | "execution_count": 5, 290 | "metadata": {}, 291 | "outputs": [ 292 | { 293 | "data": { 294 | "text/plain": [ 295 | "['Schuco_USA_L_P___Original_Mfg___SMA_America___SB700U_120V__CEC_2010_',\n", 296 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB700U_SBD_120V__CEC_2010_',\n", 297 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB3000US__208V__208V__CEC_NaN_',\n", 298 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB3000US__240V__240V__CEC_NaN_',\n", 299 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB3300U__240V__240V__CEC_2006_',\n", 300 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB3800U__208V__208V__CEC_2006_',\n", 301 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB3800U__240V__240V__CEC_2006_',\n", 302 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB4000US__208V__208V__CEC_NaN_',\n", 303 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB4000US__240V__240V__CEC_NaN_',\n", 304 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB5000US__208V__208V__CEC_NaN_',\n", 305 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB5000US__240V__240V__CEC_NaN_',\n", 306 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB5000US__277V__277V__CEC_NaN_',\n", 307 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB6000U__208V__208V__CEC_2006_',\n", 308 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB6000U__240V__240V__CEC_2006_',\n", 309 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB6000U__277V__277V__CEC_2006_',\n", 310 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB6000US__208V__208V__CEC_2006_',\n", 311 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB6000US__240V__240V__CEC_2006_',\n", 312 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB6000US__277V__277V__CEC_2006_',\n", 313 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB7000US__208V__208V__CEC_2007_',\n", 314 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB7000US__240V__240V__CEC_2007_',\n", 315 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB7000US__277V__277V__CEC_2007_',\n", 316 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB8000US__240V__240V__CEC_2010_',\n", 317 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SB8000US__277V__277V__CEC_2010_',\n", 318 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___ST42__208__208V__CEC_2008_',\n", 319 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___ST42__277__277V__CEC_2008_',\n", 320 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SWR1800U_SBD_120V__CEC_2005_',\n", 321 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SWR2100U_240V__CEC_2006_',\n", 322 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SWR2500U__208V__208V__CEC_2005_',\n", 323 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SWR2500U__240V__240V__CEC_2006_',\n", 324 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SWR2500U_SBD__208V__208V__CEC_2005_',\n", 325 | " 'Schuco_USA_L_P___Original_Mfg___SMA_America___SWR2500U_SBD__240V__240V__CEC_2006_',\n", 326 | " 'SMA_America__SB1100U_240V__CEC_2005_',\n", 327 | " 'SMA_America__SB3000US_208V__CEC_2007_',\n", 328 | " 'SMA_America__SB3000US_240V__CEC_2007_',\n", 329 | " 'SMA_America__SB3300U_240V__CEC_2006_',\n", 330 | " 'SMA_America__SB3800U_208V__CEC_2005_',\n", 331 | " 'SMA_America__SB3800U_240V__CEC_2005_',\n", 332 | " 'SMA_America__SB4000US_208V__CEC_2007_',\n", 333 | " 'SMA_America__SB4000US_240V__CEC_2007_',\n", 334 | " 'SMA_America__SB5000US_208V__CEC_2007_',\n", 335 | " 'SMA_America__SB5000US_240V__CEC_2007_',\n", 336 | " 'SMA_America__SB5000US_277V__CEC_2007_',\n", 337 | " 'SMA_America__SB6000U_208V__CEC_2005_',\n", 338 | " 'SMA_America__SB6000U_240V__CEC_2005_',\n", 339 | " 'SMA_America__SB6000U_277V__CEC_2005_',\n", 340 | " 'SMA_America__SB6000US_208V__CEC_2007_',\n", 341 | " 'SMA_America__SB6000US_240V__CEC_2007_',\n", 342 | " 'SMA_America__SB6000US_277V__CEC_2007_',\n", 343 | " 'SMA_America__SB7000US_208V__CEC_2007_',\n", 344 | " 'SMA_America__SB7000US_240V__CEC_2007_',\n", 345 | " 'SMA_America__SB7000US_277V__CEC_2007_',\n", 346 | " 'SMA_America__SB700U_120V__CEC_2005_',\n", 347 | " 'SMA_America__SB8000US_240V__CEC_2010_',\n", 348 | " 'SMA_America__SB8000US_277V__CEC_2010_',\n", 349 | " 'SMA_America__SC125U_208V__CEC_2005_',\n", 350 | " 'SMA_America__SC125U_480V__CEC_2005_',\n", 351 | " 'SMA_America__SC250U_480V__CEC_NaN_',\n", 352 | " 'SMA_America__SC_500HE_US_200V__CEC_2010_',\n", 353 | " 'SMA_America__SC_500HE_US___transformer__MV_Cooper__480V__CEC_2010_',\n", 354 | " 'SMA_America__SC_500HE_US___transformer__MV_TP1__480V__CEC_2010_',\n", 355 | " 'SMA_America__SC500U_480V__CEC_2009_',\n", 356 | " 'SMA_America__ST36__208__208V__CEC_2008_',\n", 357 | " 'SMA_America__ST36__240__240V__CEC_2010_',\n", 358 | " 'SMA_America__ST36__277__277V__CEC_2008_',\n", 359 | " 'SMA_America__ST42__208__208V__CEC_2008_',\n", 360 | " 'SMA_America__ST42__240__208V__CEC_2010_',\n", 361 | " 'SMA_America__ST42__277__277V__CEC_2008_',\n", 362 | " 'SMA_America__ST48__277__277V__CEC_2010_',\n", 363 | " 'SMA_America__SWR1800U_120V__CEC_2005_',\n", 364 | " 'SMA_America__SWR2100U_208V__CEC_2006_',\n", 365 | " 'SMA_America__SWR2500U_208V__CEC_2005_',\n", 366 | " 'SMA_America__SWR2500U_240V__CEC_2005_',\n", 367 | " 'SMA_Solar_Technology_AG__SB_2000HFUS_30_208V_208V__CEC_2011_',\n", 368 | " 'SMA_Solar_Technology_AG__SB2000HFUS_30_240V_240V__CEC_2011_',\n", 369 | " 'SMA_Solar_Technology_AG__SB2500HFUS_30_208V_208V__CEC_2011_',\n", 370 | " 'SMA_Solar_Technology_AG__SB_2500HFUS_30__240V_240V__CEC_2011_',\n", 371 | " 'SMA_Solar_Technology_AG__SB3000HFUS_30__208V_208V__CEC_2011_',\n", 372 | " 'SMA_Solar_Technology_AG__SB3000HFUS_30___240V_240V__CEC_2011_',\n", 373 | " 'SMA_Solar_Technology_AG__SB8000TL_US_208V__CEC_2010_',\n", 374 | " 'SMA_Solar_Technology_AG__SB9000TL_US_208V__CEC_2010_',\n", 375 | " 'SMA_Solar_Technology_AG__SB10000TL_US_208V__CEC_2010_',\n", 376 | " 'SMA_Technology_AG__SB3800_US_240V__CEC_2010_',\n", 377 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_3000m__208V__208V__CEC_2007_',\n", 378 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_3000m__240V__240V__CEC_2007_',\n", 379 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_4000m__208V__208V__CEC_2007_',\n", 380 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_4000m__240V__240V__CEC_2007_',\n", 381 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_5000m__208V__208V__CEC_2007_',\n", 382 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_5000m__240V__240V__CEC_2007_',\n", 383 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_5000m__277V__277V__CEC_2007_',\n", 384 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_6000m__208V__208V__CEC_2007_',\n", 385 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_6000m__240V__240V__CEC_2007_',\n", 386 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_6000m__277V__277V__CEC_2007_',\n", 387 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_7000m__208V__208V__CEC_2007_',\n", 388 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_7000m__240V__240V__CEC_2007_',\n", 389 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_7000m__277V__277V__CEC_2007_',\n", 390 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_8000m_240V__CEC_2010_',\n", 391 | " 'SunPower_Corp__Original_Mfg___SMA_America___SPR_8000m_277V__CEC_2010_',\n", 392 | " 'SMA_America__SB5000US_11_208V__CEC_2007_',\n", 393 | " 'SMA_America__SB5000US_11_240V__CEC_2007_',\n", 394 | " 'SMA_America__SB5000US_11_277V__CEC_2007_',\n", 395 | " 'SMA_America__SB6000US_11_208V__CEC_2007_',\n", 396 | " 'SMA_America__SB6000US_11_240V__CEC_2007_',\n", 397 | " 'SMA_America__SB6000US_11_277V__CEC_2007_',\n", 398 | " 'SMA_America__SB7000US_11_208V__CEC_2007_',\n", 399 | " 'SMA_America__SB7000US_11_240V__CEC_2007_',\n", 400 | " 'SMA_America__SB7000US_11_277V__CEC_2007_',\n", 401 | " 'SMA_America__SB8000US_11_240V__CEC_2010_',\n", 402 | " 'SMA_America__SB8000US_11_277V__CEC_2010_',\n", 403 | " 'SMA_America__SB10000TL_US_12_208V__CEC_2012_',\n", 404 | " 'SMA_America__SB5000US__208V__w___11_or__12_208V__CEC_2012_',\n", 405 | " 'SMA_America__SB5000US__240V__w___11_or__12_240V__CEC_2012_',\n", 406 | " 'SMA_America__SB5000US__277V__w___11_or__12_277V__CEC_2012_',\n", 407 | " 'SMA_America__SB6000US__208V__w___11_or__12_208V__CEC_2012_',\n", 408 | " 'SMA_America__SB6000US__240V__w___11_or__12_240V__CEC_2012_',\n", 409 | " 'SMA_America__SB6000US__277V__w___11_or__12_277V__CEC_2012_',\n", 410 | " 'SMA_America__SB7000US__208V__w___11_or__12_208V__CEC_2012_',\n", 411 | " 'SMA_America__SB7000US__240V__w___11_or__12_240V__CEC_2012_',\n", 412 | " 'SMA_America__SB7000US__277V__w___11_or__12_277V__CEC_2012_',\n", 413 | " 'SMA_America__SB8000TL_US_12_208V__CEC_2012_',\n", 414 | " 'SMA_America__SB8000US__240V__w___11_or__12_240V__CEC_2012_',\n", 415 | " 'SMA_America__SB8000US__277V__w___11_or__12_277V__CEC_2012_',\n", 416 | " 'SMA_America__SB9000TL_US_12_208V__CEC_2012_',\n", 417 | " 'SMA_America__SC250U__480V__480V__CEC_2012_',\n", 418 | " 'SMA_America__SC500CP_US_270V__CEC_2012_',\n", 419 | " 'SMA_America__SC630CP_US_315V__CEC_2012_',\n", 420 | " 'SMA_America__SC720CP_US_324V__CEC_2012_',\n", 421 | " 'SMA_America__SC750CP_US_342V__CEC_2012_',\n", 422 | " 'SMA_America__SC800CP_US_360V__CEC_2012_',\n", 423 | " 'SMA_America__SB6000TL_US__208V__208V__CEC_2012_',\n", 424 | " 'SMA_America__SB6000TL_US__240V__240V__CEC_2012_',\n", 425 | " 'SMA_America__SB6000TL_US_12__208V__208V__CEC_2012_',\n", 426 | " 'SMA_America__SB6000TL_US_12__240V__240V__CEC_2012_',\n", 427 | " 'SMA_America__SB7000TL_US__208V__208V__CEC_2012_',\n", 428 | " 'SMA_America__SB7000TL_US__240V__240V__CEC_2012_',\n", 429 | " 'SMA_America__SB7000TL_US_12__208V__208V__CEC_2012_',\n", 430 | " 'SMA_America__SB7000TL_US_12__240V__240V__CEC_2012_',\n", 431 | " 'SMA_America__SB8000TL_US__240V__240V__CEC_2012_',\n", 432 | " 'SMA_America__SB8000TL_US_12__208V__208V__CEC_2012_',\n", 433 | " 'SMA_America__SB8000TL_US_12__240V__240V__CEC_2012_',\n", 434 | " 'SMA_America__SB9000TL_US__240V__240V__CEC_2012_',\n", 435 | " 'SMA_America__SB9000TL_US_12__208V__208V__CEC_2012_',\n", 436 | " 'SMA_America__SB9000TL_US_12__240V__240V__CEC_2012_',\n", 437 | " 'SMA_America__SB10000TL_US__240V__240V__CEC_2012_',\n", 438 | " 'SMA_America__SB10000TL_US_12__208V__208V__CEC_2012_',\n", 439 | " 'SMA_America__SB10000TL_US_12__240V__240V__CEC_2012_',\n", 440 | " 'SMA_America__SB11000TL_US__240V__240V__CEC_2012_',\n", 441 | " 'SMA_America__SB11000TL_US_12__240V__240V__CEC_2012_',\n", 442 | " 'SMA_America__Sunny_Island_SI4548_120V__CEC_2012_',\n", 443 | " 'SMA_America__Sunny_Island_SI6048_120V__CEC_2012_',\n", 444 | " 'SMA_America__SB3000TL_US_22__208V__208V__CEC_2013_',\n", 445 | " 'SMA_America__SB3000TL_US_22__240V__240V__CEC_2013_',\n", 446 | " 'SMA_America__SB3800TL_US_22__208V__208V__CEC_2013_',\n", 447 | " 'SMA_America__SB3800TL_US_22__240V__240V__CEC_2013_',\n", 448 | " 'SMA_America__SB4000TL_US_22__208V__208V__CEC_2013_',\n", 449 | " 'SMA_America__SB4000TL_US_22__240V__240V__CEC_2013_',\n", 450 | " 'SMA_America__SB5000TL_US_22__208V__208V__CEC_2013_',\n", 451 | " 'SMA_America__SB5000TL_US_22__240V__240V__CEC_2013_',\n", 452 | " 'SMA_America__SB_240_US_10_240V__CEC_2013_',\n", 453 | " 'SMA_America__SC500CP_US_600V__w__ABB_xfmr__200V__CEC_2013_',\n", 454 | " 'SMA_America__STP12000TL_US_10__480V__480V__CEC_2013_',\n", 455 | " 'SMA_America__STP15000TL_US_10__480V__480V__CEC_2013_',\n", 456 | " 'SMA_America__STP20000TL_US_10__480V__480V__CEC_2013_',\n", 457 | " 'SMA_America__STP24000TL_US_10__480V__480V__CEC_2013_',\n", 458 | " 'SMA_America__SB_240_US_10__240V_',\n", 459 | " 'SMA_America__SB10000TL_US__208V_',\n", 460 | " 'SMA_America__SB10000TL_US__240V_',\n", 461 | " 'SMA_America__SB10000TL_US_12__208V_',\n", 462 | " 'SMA_America__SB10000TL_US_12__240V_',\n", 463 | " 'SMA_America__SB11000TL_US__240V_',\n", 464 | " 'SMA_America__SB11000TL_US_12__240V_',\n", 465 | " 'SMA_America__SB1100U__240V_',\n", 466 | " 'SMA_America__SB1100U_SBD__240V_',\n", 467 | " 'SMA_America__SB2000HFUS_30__208V_',\n", 468 | " 'SMA_America__SB2000HFUS_30__240V_',\n", 469 | " 'SMA_America__SB2500HFUS_30__208V_',\n", 470 | " 'SMA_America__SB2500HFUS_30__240V_',\n", 471 | " 'SMA_America__SB3_0_1SP_US_40__208V_',\n", 472 | " 'SMA_America__SB3_0_1SP_US_40__240V_',\n", 473 | " 'SMA_America__SB3_0_1TP_US_40__208V_',\n", 474 | " 'SMA_America__SB3_0_1TP_US_40__240V_',\n", 475 | " 'SMA_America__SB3_8_1SP_US_40__208V_',\n", 476 | " 'SMA_America__SB3_8_1SP_US_40__240V_',\n", 477 | " 'SMA_America__SB3_8_1TP_US_40__208V_',\n", 478 | " 'SMA_America__SB3_8_1TP_US_40__240V_',\n", 479 | " 'SMA_America__SB3000HFUS_30__208V_',\n", 480 | " 'SMA_America__SB3000HFUS_30__240V_',\n", 481 | " 'SMA_America__SB3000TL_US_22__208V_',\n", 482 | " 'SMA_America__SB3000TL_US_22__240V_',\n", 483 | " 'SMA_America__SB3000US__208V_',\n", 484 | " 'SMA_America__SB3000US__240V_',\n", 485 | " 'SMA_America__SB3000US_12__208V_',\n", 486 | " 'SMA_America__SB3000US_12__240V_',\n", 487 | " 'SMA_America__SB3300U__240V_',\n", 488 | " 'SMA_America__SB3800TL_US_22__208V_',\n", 489 | " 'SMA_America__SB3800TL_US_22__240V_',\n", 490 | " 'SMA_America__SB3800U__208V_',\n", 491 | " 'SMA_America__SB3800U__240V_',\n", 492 | " 'SMA_America__SB3800US__240V_',\n", 493 | " 'SMA_America__SB3800US_12__240V_',\n", 494 | " 'SMA_America__SB4000TL_US_22__208V_',\n", 495 | " 'SMA_America__SB4000TL_US_22__240V_',\n", 496 | " 'SMA_America__SB4000US__208V_',\n", 497 | " 'SMA_America__SB4000US__240V_',\n", 498 | " 'SMA_America__SB4000US_CL___208V_',\n", 499 | " 'SMA_America__SB4000US_CL___240V_',\n", 500 | " 'SMA_America__SB4000US_12__208V_',\n", 501 | " 'SMA_America__SB4000US_12__240V_',\n", 502 | " 'SMA_America__SB5_0_1SP_US_40__208V_',\n", 503 | " 'SMA_America__SB5_0_1SP_US_40__240V_',\n", 504 | " 'SMA_America__SB5_0_1TP_US_40__208V_',\n", 505 | " 'SMA_America__SB5_0_1TP_US_40__240V_',\n", 506 | " 'SMA_America__SB5000TL_US_22__208V_',\n", 507 | " 'SMA_America__SB5000TL_US_22__240V_',\n", 508 | " 'SMA_America__SB5000US__208V_',\n", 509 | " 'SMA_America__SB5000US__240V_',\n", 510 | " 'SMA_America__SB5000US__277V_',\n", 511 | " 'SMA_America__SB5000US_11__208V_',\n", 512 | " 'SMA_America__SB5000US_11__240V_',\n", 513 | " 'SMA_America__SB5000US_11__277V_',\n", 514 | " 'SMA_America__SB5000US_12__208V_',\n", 515 | " 'SMA_America__SB5000US_12__240V_',\n", 516 | " 'SMA_America__SB5000US_12__277V_',\n", 517 | " 'SMA_America__SB6_0_1SP_US_40__208V_',\n", 518 | " 'SMA_America__SB6_0_1SP_US_40__240V_',\n", 519 | " 'SMA_America__SB6_0_1TP_US_40__208V_',\n", 520 | " 'SMA_America__SB6_0_1TP_US_40__240V_',\n", 521 | " 'SMA_America__SB6000TL_US__208V_',\n", 522 | " 'SMA_America__SB6000TL_US__240V_',\n", 523 | " 'SMA_America__SB6000TL_US_12__208V_',\n", 524 | " 'SMA_America__SB6000TL_US_12__240V_',\n", 525 | " 'SMA_America__SB6000TL_US_22__208V_',\n", 526 | " 'SMA_America__SB6000TL_US_22__240V_',\n", 527 | " 'SMA_America__SB6000U__208V_',\n", 528 | " 'SMA_America__SB6000U__240V_',\n", 529 | " 'SMA_America__SB6000U__277V_',\n", 530 | " 'SMA_America__SB6000US__208V_',\n", 531 | " 'SMA_America__SB6000US__240V_',\n", 532 | " 'SMA_America__SB6000US__277V_',\n", 533 | " 'SMA_America__SB6000US_11__208V_',\n", 534 | " 'SMA_America__SB6000US_11__240V_',\n", 535 | " 'SMA_America__SB6000US_11__277V_',\n", 536 | " 'SMA_America__SB6000US_12__208V_',\n", 537 | " 'SMA_America__SB6000US_12__240V_',\n", 538 | " 'SMA_America__SB6000US_12__277V_',\n", 539 | " 'SMA_America__SB7_0_1SP_US_40__208V_',\n", 540 | " 'SMA_America__SB7_0_1SP_US_40__240V_',\n", 541 | " 'SMA_America__SB7_0_1TP_US_40__208V_',\n", 542 | " 'SMA_America__SB7_0_1TP_US_40__240V_',\n", 543 | " 'SMA_America__SB7_7_1SP_US_40__208V_',\n", 544 | " 'SMA_America__SB7_7_1SP_US_40__240V_',\n", 545 | " 'SMA_America__SB7_7_1TP_US_40__208V_',\n", 546 | " 'SMA_America__SB7_7_1TP_US_40__240V_',\n", 547 | " 'SMA_America__SB7000TL_US__208V_',\n", 548 | " 'SMA_America__SB7000TL_US__240V_',\n", 549 | " 'SMA_America__SB7000TL_US_12__208V_',\n", 550 | " 'SMA_America__SB7000TL_US_12__240V_',\n", 551 | " 'SMA_America__SB7000TL_US_22__208V_',\n", 552 | " 'SMA_America__SB7000TL_US_22__240V_',\n", 553 | " 'SMA_America__SB7000US__208V_',\n", 554 | " 'SMA_America__SB7000US__240V_',\n", 555 | " 'SMA_America__SB7000US__277V_',\n", 556 | " 'SMA_America__SB7000US_11__208V_',\n", 557 | " 'SMA_America__SB7000US_11__240V_',\n", 558 | " 'SMA_America__SB7000US_11__277V_',\n", 559 | " 'SMA_America__SB7000US_12__208V_',\n", 560 | " 'SMA_America__SB7000US_12__240V_',\n", 561 | " 'SMA_America__SB7000US_12__277V_',\n", 562 | " 'SMA_America__SB700U__120V_',\n", 563 | " 'SMA_America__SB700U_SBD__120V_',\n", 564 | " 'SMA_America__SB7700TL_US_22__208V_',\n", 565 | " 'SMA_America__SB7700TL_US_22__240V_',\n", 566 | " 'SMA_America__SB8000TL_US__240V_',\n", 567 | " 'SMA_America__SB8000TL_US_12__208V_',\n", 568 | " 'SMA_America__SB8000TL_US_12__240V_',\n", 569 | " 'SMA_America__SB8000US__240V_',\n", 570 | " 'SMA_America__SB8000US__277V_',\n", 571 | " 'SMA_America__SB8000US_11__240V_',\n", 572 | " 'SMA_America__SB8000US_11__277V_',\n", 573 | " 'SMA_America__SB8000US_12__240V_',\n", 574 | " 'SMA_America__SB8000US_12__277V_',\n", 575 | " 'SMA_America__SB9000TL_US__208V_',\n", 576 | " 'SMA_America__SB9000TL_US__240V_',\n", 577 | " 'SMA_America__SB9000TL_US_12__208V_',\n", 578 | " 'SMA_America__SB9000TL_US_12__240V_',\n", 579 | " 'SMA_America__SBS3_8_US_10__240V_',\n", 580 | " 'SMA_America__SBS5_0_US_10__240V_',\n", 581 | " 'SMA_America__SBS6_0_US_10__240V_',\n", 582 | " 'SMA_America__SC_2500_EV_US__550V_',\n", 583 | " 'SMA_America__SC_2750_EV_US__600V_',\n", 584 | " 'SMA_America__SC_1850_US__385V_',\n", 585 | " 'SMA_America__SC_2200_US__385V_',\n", 586 | " 'SMA_America__SC125U__208V_',\n", 587 | " 'SMA_America__SC125U__480V_',\n", 588 | " 'SMA_America__SC250U__480V_',\n", 589 | " 'SMA_America__SC500CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 590 | " 'SMA_America__SC500CP_US_600V__with_ABB_transformer_',\n", 591 | " 'SMA_America__SC500HE_US_MV__with_Cooper_transformer_',\n", 592 | " 'SMA_America__SC500HE_US_MV__with_NEMA_TP_1_transformer_',\n", 593 | " 'SMA_America__SC630CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 594 | " 'SMA_America__SC720CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 595 | " 'SMA_America__SC750CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 596 | " 'SMA_America__SC800CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 597 | " 'SMA_America__SC850CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 598 | " 'SMA_America__SC900CP_US__with_ABB_EcoDry_Ultra_transformer_',\n", 599 | " 'SMA_America__ST36__208V_',\n", 600 | " 'SMA_America__ST36__240V_',\n", 601 | " 'SMA_America__ST36__277V_',\n", 602 | " 'SMA_America__ST42__208V_',\n", 603 | " 'SMA_America__ST42__240V_',\n", 604 | " 'SMA_America__ST42__277V_',\n", 605 | " 'SMA_America__ST48__240V_',\n", 606 | " 'SMA_America__ST48__277V_',\n", 607 | " 'SMA_America__STP_33_US_41__480V_',\n", 608 | " 'SMA_America__STP_50_US_41__480V_',\n", 609 | " 'SMA_America__STP_60_US_10__400V_',\n", 610 | " 'SMA_America__STP_60_US_10__480V_',\n", 611 | " 'SMA_America__STP_62_US_41__480V_',\n", 612 | " 'SMA_America__STP12000TL_US_10__480V_',\n", 613 | " 'SMA_America__STP15000TL_US_10__480V_',\n", 614 | " 'SMA_America__STP20000TL_US_10__480V_',\n", 615 | " 'SMA_America__STP24000TL_US_10__480V_',\n", 616 | " 'SMA_America__STP30000TL_US_10__480V_',\n", 617 | " 'SMA_America__STP50_US_40__480V_',\n", 618 | " 'SMA_America__SWR1800U__120V_',\n", 619 | " 'SMA_America__SWR1800U_SBD__120V_',\n", 620 | " 'SMA_America__SWR2100U__240V_',\n", 621 | " 'SMA_America__SWR2100U_SBD__240V_',\n", 622 | " 'SMA_America__SWR2500U__208V_',\n", 623 | " 'SMA_America__SWR2500U__240V_',\n", 624 | " 'SMA_America__SWR2500U_SBD__208V_',\n", 625 | " 'SMA_America__SWR2500U_SBD__240V_',\n", 626 | " 'SMA_America__Sunny_Island_SI6048']" 627 | ] 628 | }, 629 | "execution_count": 5, 630 | "metadata": {}, 631 | "output_type": "execute_result" 632 | } 633 | ], 634 | "source": [ 635 | "sam_inv_dict['adr']['sma']" 636 | ] 637 | }, 638 | { 639 | "cell_type": "code", 640 | "execution_count": 6, 641 | "metadata": {}, 642 | "outputs": [ 643 | { 644 | "data": { 645 | "text/plain": [ 646 | "['Danfoss_Solar__DLX_2_0_UL__208V_',\n", 647 | " 'Danfoss_Solar__DLX_2_0_UL__240V_',\n", 648 | " 'Danfoss_Solar__DLX_2_9_UL__208V_',\n", 649 | " 'Danfoss_Solar__DLX_2_9_UL__240V_',\n", 650 | " 'Danfoss_Solar__DLX_3_8_UL__208V_',\n", 651 | " 'Danfoss_Solar__DLX_3_8_UL__240V_',\n", 652 | " 'Danfoss_Solar__DLX_4_4_UL__208V_',\n", 653 | " 'Danfoss_Solar__DLX_4_4_UL__240V_',\n", 654 | " 'Danfoss_Solar__MLX_400V__400V_',\n", 655 | " 'Danfoss__MLX_480V__480V_']" 656 | ] 657 | }, 658 | "execution_count": 6, 659 | "metadata": {}, 660 | "output_type": "execute_result" 661 | } 662 | ], 663 | "source": [ 664 | "sam_inv_dict['cec']['danfoss']" 665 | ] 666 | }, 667 | { 668 | "cell_type": "code", 669 | "execution_count": 7, 670 | "metadata": {}, 671 | "outputs": [ 672 | { 673 | "data": { 674 | "text/plain": [ 675 | "['Danfoss_Solar__DLX_3_8_UL__208V__208V__CEC_2012_',\n", 676 | " 'Danfoss_Solar__DLX_3_8_UL__240V__240V__CEC_2012_',\n", 677 | " 'Danfoss_Solar__DLX_4_4_UL__208V__208V__CEC_2012_',\n", 678 | " 'Danfoss_Solar__DLX_4_4_UL__240V__240V__CEC_2012_',\n", 679 | " 'Danfoss_Solar__DLX_2_0_UL__208V__208V__CEC_2013_',\n", 680 | " 'Danfoss_Solar__DLX_2_0_UL__240V__240V__CEC_2013_',\n", 681 | " 'Danfoss_Solar__DLX_2_9_UL__208V__208V__CEC_2013_',\n", 682 | " 'Danfoss_Solar__DLX_2_9_UL__240V__240V__CEC_2013_',\n", 683 | " 'Danfoss_Solar__DLX_2_0_UL__208V_',\n", 684 | " 'Danfoss_Solar__DLX_2_0_UL__240V_',\n", 685 | " 'Danfoss_Solar__DLX_2_9_UL__208V_',\n", 686 | " 'Danfoss_Solar__DLX_2_9_UL__240V_',\n", 687 | " 'Danfoss_Solar__DLX_3_8_UL__208V_',\n", 688 | " 'Danfoss_Solar__DLX_3_8_UL__240V_',\n", 689 | " 'Danfoss_Solar__DLX_4_4_UL__208V_',\n", 690 | " 'Danfoss_Solar__DLX_4_4_UL__240V_',\n", 691 | " 'Danfoss_Solar__MLX_400V__400V_',\n", 692 | " 'Danfoss__MLX_480V__480V_']" 693 | ] 694 | }, 695 | "execution_count": 7, 696 | "metadata": {}, 697 | "output_type": "execute_result" 698 | } 699 | ], 700 | "source": [ 701 | "sam_inv_dict['adr']['danfoss']" 702 | ] 703 | }, 704 | { 705 | "cell_type": "code", 706 | "execution_count": 8, 707 | "metadata": { 708 | "scrolled": false 709 | }, 710 | "outputs": [], 711 | "source": [ 712 | "# Modules\n", 713 | "sam_mod_dict = {}\n", 714 | "sam_mod_dict['cec'] = {}\n", 715 | "sam_mod_dict['sandia'] = {}\n", 716 | "\n", 717 | "indices = [i for i, s in enumerate(list(sam_cec_mod.columns)) if 'aleo' in s.lower()]\n", 718 | "sam_mod_dict['cec']['aleo'] = [list(sam_cec_mod.columns)[i] for i in indices]\n", 719 | "\n", 720 | "indices = [i for i, s in enumerate(list(sam_cec_mod.columns)) if 'schott' in s.lower()]\n", 721 | "sam_mod_dict['cec']['schott'] = [list(sam_cec_mod.columns)[i] for i in indices]\n", 722 | "\n", 723 | "indices = [i for i, s in enumerate(list(sam_sandia_mod.columns)) if 'aleo' in s.lower()]\n", 724 | "sam_mod_dict['sandia']['aleo'] = [list(sam_sandia_mod.columns)[i] for i in indices]\n", 725 | "\n", 726 | "indices = [i for i, s in enumerate(list(sam_sandia_mod.columns)) if 'schott' in s.lower()]\n", 727 | "sam_mod_dict['sandia']['schott'] = [list(sam_sandia_mod.columns)[i] for i in indices]" 728 | ] 729 | }, 730 | { 731 | "cell_type": "code", 732 | "execution_count": 9, 733 | "metadata": {}, 734 | "outputs": [ 735 | { 736 | "data": { 737 | "text/plain": [ 738 | "['Aleo_Solar_P18y250',\n", 739 | " 'Aleo_Solar_S18y250',\n", 740 | " 'Aleo_Solar_P18y255',\n", 741 | " 'Aleo_Solar_S18y255',\n", 742 | " 'Aleo_Solar_P18y260',\n", 743 | " 'Aleo_Solar_S18y260',\n", 744 | " 'Aleo_Solar_P18Y265',\n", 745 | " 'Aleo_Solar_S18y265',\n", 746 | " 'Aleo_Solar_S19Y270',\n", 747 | " 'Aleo_Solar_S79y270',\n", 748 | " 'Aleo_Solar_P19Y275',\n", 749 | " 'Aleo_Solar_S19y275',\n", 750 | " 'Aleo_Solar_S79y275',\n", 751 | " 'Aleo_Solar_S19y280',\n", 752 | " 'Aleo_Solar_S59y280',\n", 753 | " 'Aleo_Solar_S79y280',\n", 754 | " 'Aleo_Solar_P19Y285',\n", 755 | " 'Aleo_Solar_S19y285',\n", 756 | " 'Aleo_Solar_S59y285',\n", 757 | " 'Aleo_Solar_S79y285',\n", 758 | " 'Aleo_Solar_P19Y290',\n", 759 | " 'Aleo_Solar_S19y290',\n", 760 | " 'Aleo_Solar_S59y290',\n", 761 | " 'Aleo_Solar_S79Y290',\n", 762 | " 'Aleo_Solar_P19Y295',\n", 763 | " 'Aleo_Solar_S19Y295',\n", 764 | " 'Aleo_Solar_S59Y295',\n", 765 | " 'Aleo_Solar_S79Y295',\n", 766 | " 'Aleo_Solar_P19Y300',\n", 767 | " 'Aleo_Solar_S19Y300',\n", 768 | " 'Aleo_Solar_S59Y300',\n", 769 | " 'Aleo_Solar_S79Y300',\n", 770 | " 'Aleo_Solar_P19Y305',\n", 771 | " 'Aleo_Solar_S19Y305',\n", 772 | " 'Aleo_Solar_S59Y305',\n", 773 | " 'Aleo_Solar_S79Y305',\n", 774 | " 'Aleo_Solar_P19Y310',\n", 775 | " 'Aleo_Solar_S19Y310',\n", 776 | " 'Aleo_Solar_S59Y310']" 777 | ] 778 | }, 779 | "execution_count": 9, 780 | "metadata": {}, 781 | "output_type": "execute_result" 782 | } 783 | ], 784 | "source": [ 785 | "sam_mod_dict['cec']['aleo']" 786 | ] 787 | }, 788 | { 789 | "cell_type": "code", 790 | "execution_count": null, 791 | "metadata": {}, 792 | "outputs": [], 793 | "source": [ 794 | "sam_mod_dict['cec']['schott']" 795 | ] 796 | }, 797 | { 798 | "cell_type": "code", 799 | "execution_count": null, 800 | "metadata": {}, 801 | "outputs": [], 802 | "source": [ 803 | "sam_mod_dict['sandia']['aleo']" 804 | ] 805 | }, 806 | { 807 | "cell_type": "code", 808 | "execution_count": null, 809 | "metadata": {}, 810 | "outputs": [], 811 | "source": [ 812 | "sam_mod_dict['sandia']['schott']" 813 | ] 814 | }, 815 | { 816 | "cell_type": "markdown", 817 | "metadata": {}, 818 | "source": [ 819 | "### Export as json file" 820 | ] 821 | }, 822 | { 823 | "cell_type": "code", 824 | "execution_count": null, 825 | "metadata": {}, 826 | "outputs": [], 827 | "source": [ 828 | "with open('./data/sam_inverters.json', 'w') as fp:\n", 829 | " json.dump(sam_inv_dict, fp, sort_keys=True, indent=4)\n", 830 | " \n", 831 | "with open('./data/sam_modules.json', 'w') as fp:\n", 832 | " json.dump(sam_mod_dict, fp, sort_keys=True, indent=4)" 833 | ] 834 | }, 835 | { 836 | "cell_type": "markdown", 837 | "metadata": {}, 838 | "source": [ 839 | "### View SonnJA technologies" 840 | ] 841 | }, 842 | { 843 | "cell_type": "code", 844 | "execution_count": null, 845 | "metadata": {}, 846 | "outputs": [], 847 | "source": [ 848 | "sam_cec_inv_smasb3000 = sam_cec_inv.SMA_America__SB3000HFUS_30__208V_\n", 849 | "sam_cec_inv_smasb3000" 850 | ] 851 | }, 852 | { 853 | "cell_type": "code", 854 | "execution_count": null, 855 | "metadata": {}, 856 | "outputs": [], 857 | "source": [ 858 | "sam_adr_inv_smasb3000 = sam_adr_inv.SMA_Solar_Technology_AG__SB3000HFUS_30___240V_240V__CEC_2011_\n", 859 | "sam_adr_inv_smasb3000" 860 | ] 861 | }, 862 | { 863 | "cell_type": "code", 864 | "execution_count": null, 865 | "metadata": { 866 | "scrolled": true 867 | }, 868 | "outputs": [], 869 | "source": [ 870 | "sam_cec_mod['Aleo_Solar_S18y250']" 871 | ] 872 | }, 873 | { 874 | "cell_type": "code", 875 | "execution_count": null, 876 | "metadata": {}, 877 | "outputs": [], 878 | "source": [ 879 | "aleo_s18_240 = sam_cec_mod['Aleo_Solar_S18y250'].copy()\n", 880 | "aleo_s18_240['STC'] = 240.\n", 881 | "aleo_s18_240['PTC'] = 215.04\n", 882 | "aleo_s18_240['V_mp_ref'] = 29.5\n", 883 | "aleo_s18_240['V_oc_ref'] = 37.0\n", 884 | "aleo_s18_240['I_mp_ref'] = 8.13\n", 885 | "aleo_s18_240['I_sc_ref'] = 8.65\n", 886 | "aleo_s18_240['alpha_sc'] = 0.04\n", 887 | "aleo_s18_240['beta_oc'] = -0.34\n", 888 | "aleo_s18_240['gamma_r'] = -0.46\n", 889 | "aleo_s18_240" 890 | ] 891 | }, 892 | { 893 | "cell_type": "code", 894 | "execution_count": null, 895 | "metadata": {}, 896 | "outputs": [], 897 | "source": [ 898 | "aleo_s19_245 = sam_cec_mod['Aleo_Solar_S19Y270'].copy()\n", 899 | "aleo_s19_245['STC'] = 245.\n", 900 | "aleo_s19_245['PTC'] = 220.\n", 901 | "aleo_s19_245['V_mp_ref'] = 31.3\n", 902 | "aleo_s19_245['V_oc_ref'] = 37.1\n", 903 | "aleo_s19_245['I_mp_ref'] = 7.84\n", 904 | "aleo_s19_245['I_sc_ref'] = 8.48\n", 905 | "aleo_s19_245['alpha_sc'] = 0.03\n", 906 | "aleo_s19_245['beta_oc'] = -0.34\n", 907 | "aleo_s19_245['gamma_r'] = -0.48\n", 908 | "aleo_s19_245" 909 | ] 910 | }, 911 | { 912 | "cell_type": "code", 913 | "execution_count": null, 914 | "metadata": {}, 915 | "outputs": [], 916 | "source": [ 917 | "schott = sam_sandia_mod['Schott_Solar_ASE_100_ATF_17__100___1999__E__'].copy()\n", 918 | "schott" 919 | ] 920 | }, 921 | { 922 | "cell_type": "code", 923 | "execution_count": null, 924 | "metadata": {}, 925 | "outputs": [], 926 | "source": [ 927 | "schott = sam_sandia_mod['Schott_Solar_ASE_100_ATF_17__100___1999__E__'].copy()\n", 928 | "schott['Vmpo'] = 31.1\n", 929 | "schott['Voco'] = 41.0\n", 930 | "schott['Imp'] = 3.38\n", 931 | "schott['Isco'] = 3.98\n" 932 | ] 933 | } 934 | ], 935 | "metadata": { 936 | "kernelspec": { 937 | "display_name": "Python 3 (ipykernel)", 938 | "language": "python", 939 | "name": "python3" 940 | }, 941 | "language_info": { 942 | "codemirror_mode": { 943 | "name": "ipython", 944 | "version": 3 945 | }, 946 | "file_extension": ".py", 947 | "mimetype": "text/x-python", 948 | "name": "python", 949 | "nbconvert_exporter": "python", 950 | "pygments_lexer": "ipython3", 951 | "version": "3.8.10" 952 | } 953 | }, 954 | "nbformat": 4, 955 | "nbformat_minor": 4 956 | } 957 | -------------------------------------------------------------------------------- /pv3_pvlib_sonnja.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import matplotlib.pyplot as mpl 3 | import numpy as np 4 | import os 5 | from collections import OrderedDict 6 | 7 | import pvlib 8 | 9 | from pvlib.modelchain import ModelChain 10 | from pvlib import irradiance 11 | 12 | import read_htw_data 13 | import get_weather_data 14 | import analysis_tools 15 | import tools 16 | 17 | 18 | def reindl(ghi, i0_h, elevation): 19 | """ 20 | Reindl model to calculate DNI and DHI from GHI and I0_h. 21 | 22 | Parameters 23 | ----------- 24 | ghi : :pandas:`DataFrame` or :numpy:`array` 25 | Time series for global horizontal irradiance in W/m². 26 | i0_h : :pandas:`DataFrame` or :numpy:`array` 27 | Time series for irradiance on top of atmosphere in W/m². 28 | elevation : :obj:`float` 29 | Elevation of location in m. 30 | 31 | Returns 32 | ------- 33 | :collections:`OrderedDict` 34 | Dictionary with time series for DNI, DHI and clearness index kt. 35 | 36 | """ 37 | 38 | elevation = pvlib.tools.sind(elevation) 39 | 40 | # calculate clearness index kt 41 | kt = np.maximum(0, ghi / (i0_h * elevation)) 42 | 43 | # calculate diffuse fraction DHI/GHI 44 | # for kt <= 0.3 45 | df = 1.02 - 0.254 * kt + 0.0123 * elevation 46 | # for kt > 0.3 and kt <= 0.78 47 | df = np.where((kt > 0.3) & (kt <= 0.78), 48 | np.fmin(0.97, np.fmax( 49 | 0.1, 1.4 - 1.794 * kt + 0.177 * elevation)), 50 | df) 51 | # for kt > 0.78 52 | df = np.where(kt > 0.78, np.fmax(0.1, 0.486 * kt + 0.182 * elevation), df) 53 | 54 | # eliminate extreme data according to limits Case 1 and Case 2 in Reindl 55 | df = np.where(((df < 0.9) & (kt < 0.2)) | 56 | ((df > 0.8) & (kt > 0.6)) | 57 | (df > 1) | (ghi - i0_h > 0), 0, df) 58 | 59 | dhi = df * ghi 60 | dni = (ghi - dhi) / elevation 61 | 62 | data = OrderedDict() 63 | data['dni'] = dni 64 | data['dhi'] = dhi 65 | data['kt'] = kt 66 | 67 | if isinstance(ghi, pd.Series): 68 | data = pd.DataFrame(data) 69 | 70 | return data 71 | 72 | 73 | def apply_decomposition_model(weather_df, model, location): 74 | """ 75 | Uses the specified decomposition model to calculate DNI and DHI. 76 | 77 | Parameters 78 | ---------- 79 | weather_df : :pandas:`DataFrame` 80 | Weather DataFrame containing all variables needed to apply the 81 | decomposition model. See model functions for more information. 82 | model : :obj:`str` 83 | Decomposition model to use. Choose from 'reindl', 'erbs' or 'disc'. 84 | location : :pvlib:`Location` 85 | 86 | Returns 87 | ------- 88 | :pandas:`DataFrame` 89 | DataFrame with DNI and DHI. 90 | 91 | """ 92 | 93 | solar_position = location.get_solarposition( 94 | weather_df.index, pressure=weather_df['pressure'].mean(), 95 | temperature=weather_df['temp_air'].mean()) 96 | 97 | if model == 'reindl': 98 | 99 | solar_position = location.get_solarposition( 100 | weather_df.index, pressure=weather_df['pressure'].mean(), 101 | temperature=weather_df['temp_air'].mean()) 102 | 103 | df = reindl(weather_df.ghi, weather_df.i0_h, solar_position.elevation) 104 | df['dni_corrected'] = irradiance.dni( 105 | weather_df['ghi'], df['dhi'], solar_position.zenith, 106 | clearsky_dni=location.get_clearsky( 107 | weather_df.index, solar_position=solar_position).dni, 108 | clearsky_tolerance=1.1, 109 | zenith_threshold_for_zero_dni=88.0, 110 | zenith_threshold_for_clearsky_limit=80.0) 111 | 112 | elif model == 'erbs': 113 | 114 | df = irradiance.erbs(weather_df.ghi, solar_position.zenith, 115 | weather_df.index) 116 | df['dni_corrected'] = irradiance.dni( 117 | weather_df['ghi'], df['dhi'], solar_position.zenith, 118 | clearsky_dni=location.get_clearsky( 119 | weather_df.index, solar_position=solar_position).dni, 120 | clearsky_tolerance=1.1, 121 | zenith_threshold_for_zero_dni=88.0, 122 | zenith_threshold_for_clearsky_limit=80.0) 123 | 124 | elif model == 'disc': 125 | 126 | df = irradiance.disc(weather_df.ghi, solar_position.zenith, 127 | weather_df.index, weather_df.pressure.mean()) 128 | df['dhi'] = weather_df.ghi - df.dni * pvlib.tools.cosd( 129 | solar_position.zenith) 130 | df['gni'] = df.dni + df.dhi 131 | 132 | return df 133 | 134 | 135 | def compare_decomposition_models(merra_df, location, htw_weather_df, 136 | plot=False, 137 | plot_directory='plot/decomposition'): 138 | """ 139 | Compares the decomposition models Reindl, Erbs and Disc. Calculates 140 | correlation and RMSE and optionally plots these plus a winter and summer 141 | week. 142 | 143 | Parameters 144 | ---------- 145 | merra_df : :pandas:`DataFrame` 146 | MERRA weather DataFrame. 147 | location : :pvlib:`Location` 148 | htw_weather_df : :pandas:`DataFrame` 149 | HTW weather DataFrame. 150 | plot : Boolean 151 | If true plots are created. Default: False. 152 | plot_directory : :obj:`str` 153 | Path to directory plot is saved to. 154 | 155 | Returns 156 | ------- 157 | :pandas:`DataFrame` 158 | DataFrame with GNI and corrected GNI of the three models. 159 | 160 | """ 161 | # hard-coded inputs 162 | weather_data = 'MERRA' 163 | measured_data = 'HTW' 164 | weeks = [('1/25/2015', '2/1/2015'), ('6/2/2015', '6/8/2015')] 165 | resample_rule = '1W' 166 | 167 | # reindl 168 | df_reindl = apply_decomposition_model(merra_df, 'reindl', 169 | location=location) 170 | df_reindl['gni'] = (df_reindl.dni + df_reindl.dhi).fillna(0) 171 | df_reindl['gni_corrected'] = (df_reindl.dni_corrected + 172 | df_reindl.dhi).fillna(0) 173 | 174 | # erbs 175 | df_erbs = apply_decomposition_model(merra_df, 'erbs', location=location) 176 | df_erbs['gni'] = df_erbs.dni + df_erbs.dhi 177 | df_erbs['gni_corrected'] = df_erbs.dni_corrected + df_erbs.dhi 178 | 179 | # disc 180 | df_disc = apply_decomposition_model(merra_df, 'disc', location=location) 181 | 182 | # combine dataframes 183 | df_comp = df_reindl.loc[:, ['gni', 'gni_corrected']].join( 184 | df_erbs.loc[:, ['gni', 'gni_corrected']], 185 | how='outer', rsuffix='_erbs', lsuffix='_reindl') 186 | df_comp = df_comp.join(df_disc.gni.rename('gni_disc').to_frame(), 187 | how='outer', rsuffix='_disc') 188 | 189 | # calculate correlation and rmse 190 | parameter_list = ['gni_disc', 'gni_corrected_reindl', 'gni_corrected_erbs'] 191 | count = 0 192 | for param in parameter_list: 193 | df = htw_weather_df['gni'].to_frame().join( 194 | df_comp[param].to_frame(), how='outer') 195 | corr = analysis_tools.correlation_tmp( 196 | df, resample_rule, min_count=100).rename( 197 | 'corr_gni_htw_{}'.format(param)) 198 | var = analysis_tools.variability( 199 | df, resample_rule, min_count=100).rename( 200 | 'rmse_gni_htw_{}'.format(param)) 201 | corr_year = np.round(analysis_tools.correlation_tmp(df, '1Y').iloc[0], 202 | 2) 203 | var_year = np.round(analysis_tools.variability(df, '1Y').iloc[0], 2) 204 | if plot: 205 | for week in weeks: 206 | filename = 'decomposition_comparison_week_{}_to_{}_{}_{}_{}_' \ 207 | 'annual_corr_{}_annual_RMSE_{}'.format( 208 | week[0].replace('/', '_'), week[1].replace('/', '_'), 209 | param, weather_data, measured_data, corr_year, var_year) 210 | plot_time_range(df.fillna(0), week, filename, plot_directory, 211 | weather_data) 212 | if count == 0: 213 | corr_df = corr.to_frame() 214 | var_df = var.to_frame() 215 | else: 216 | corr_df = corr_df.join(corr.to_frame()) 217 | var_df = var_df.join(var.to_frame()) 218 | count += 1 219 | 220 | if plot: 221 | # plot correlation 222 | corr_df.plot(title='Correlation') 223 | mpl.ylabel('Correlation coefficient') 224 | mpl.savefig( 225 | os.path.join( 226 | plot_directory, 'decomposition_comparison_correlation_' 227 | '{}_{}_{}.png'.format( 228 | resample_rule, weather_data, measured_data))) 229 | mpl.clf() 230 | # plot RMSE 231 | var_df.plot(title='RMSE') 232 | mpl.ylabel('RMSE in W/m²') 233 | mpl.savefig( 234 | os.path.join( 235 | plot_directory, 'decomposition_comparison_RMSE_' 236 | '{}_{}_{}.png'.format( 237 | resample_rule, weather_data, measured_data))) 238 | # plot weeks 239 | df_week = df_comp.loc[:, ['gni_disc', 'gni_corrected_reindl', 240 | 'gni_corrected_erbs']].fillna(0).join( 241 | htw_weather_df['gni'].to_frame()) 242 | for week in weeks: 243 | filename = 'decomposition_comparison_week_{}_to_{}_' \ 244 | 'GNI_all_models_{}_{}'.format( 245 | week[0].replace('/', '_'), week[1].replace('/', '_'), 246 | weather_data, measured_data) 247 | plot_time_range(df_week, week, filename, plot_directory, 248 | weather_data) 249 | return df_comp 250 | 251 | 252 | def load_merra_data(year, lat, lon, directory): 253 | """ 254 | Loads MERRA weather data. 255 | 256 | Parameters 257 | ----------- 258 | year : :obj:`int` 259 | lat : :obj:`float` 260 | lon : :obj:`float` 261 | directory : :obj:`str` 262 | Path to MERRA csv file. 263 | 264 | Returns 265 | -------- 266 | :pandas:`DataFrame` 267 | DataFrame with weather data. 268 | 269 | """ 270 | # read csv file 271 | merra_df = pd.read_csv( 272 | os.path.join(directory, 'weather_data_GER_{}.csv'.format(year)), 273 | header=[0], index_col=[0], parse_dates=True) 274 | # get closest coordinates to given location 275 | lat_lon = tools.get_closest_coordinates(merra_df, [lat, lon]) 276 | # get weather data for closest location 277 | df = merra_df[(merra_df['lon'] == lat_lon['lon']) & 278 | (merra_df['lat'] == lat_lon['lat'])] 279 | # convert time index to local time 280 | df.index = df.index.tz_localize('UTC').tz_convert('Europe/Berlin') 281 | # rename columns to fit needs of pvlib 282 | df.rename(columns={'T': 'temp_air', 'v_50m': 'wind_speed', 'p': 'pressure', 283 | 'SWTDN': 'i0_h', 'SWGDN': 'ghi'}, inplace=True) 284 | # convert temperature to °C 285 | df.loc[:, 'temp_air'] = df.temp_air - 273.15 286 | return df 287 | 288 | 289 | def get_index(start_date, end_date, weather_data): 290 | """ 291 | Sets up index to select date range from data set. 292 | 293 | Parameters 294 | ----------- 295 | start_date : :obj:`str` 296 | String with start of date range, e.g. '1/25/2015'. 297 | end_date : :obj:`str` 298 | String with end of date range. 299 | weather_data : :obj:`str` 300 | Weather data set used. Possible choices are 'MERRA' or 'open_FRED'. 301 | 302 | Returns 303 | ------- 304 | :pandas:`DateTimeIndex` 305 | 306 | """ 307 | if weather_data == 'open_FRED': 308 | index = pd.date_range(start=start_date, end=end_date, 309 | freq='30Min', tz='UTC') \ 310 | - pd.Timedelta(minutes=15) 311 | elif weather_data == 'MERRA': 312 | index = pd.date_range(start=start_date, end=end_date, 313 | freq='60Min', tz='UTC') 314 | return index 315 | 316 | 317 | def plot_time_range(data, time_range, filename, plot_directory, 318 | weather_data, ylabel=None, legend_loc=None, title=None): 319 | """ 320 | Plots data for the given time range. 321 | 322 | Parameters 323 | ----------- 324 | data : :pandas:`DataFrame` 325 | Data to plot. 326 | time_range : :obj:`tuple` 327 | Tuple with start and end date, e.g. ('1/25/2015', '2/1/2015'). 328 | filename : :obj:`str` 329 | plot_directory : :obj:`str` 330 | Path to directory plot is saved to. 331 | weather_data : :obj:`str` 332 | Weather data set used. Possible choices are 'MERRA' or 'open_FRED'. 333 | ylabel : :obj:`str`, optional 334 | Label of y-axis. Default: None. 335 | legend_loc : :obj:`int`, optional 336 | Location of legend. 337 | title : :obj:`str`, optional 338 | 339 | """ 340 | 341 | # set frequency of index 342 | index = get_index(time_range[0], time_range[1], weather_data) 343 | 344 | data.loc[index, :].plot(title=title) 345 | if ylabel: 346 | mpl.ylabel(ylabel) 347 | if legend_loc: 348 | mpl.legend(loc=legend_loc) 349 | mpl.savefig(os.path.join(plot_directory, '{}.png'.format(filename))) 350 | 351 | 352 | def compare_parameters_2(dict, parameter, resample_rule, plot_directory): 353 | """ 354 | Calculates and plots correlation and RMSE between three time series. 355 | 356 | :param df: 357 | :param parameter: 358 | :param resample_rule: 359 | :param plot_directory: 360 | :return: 361 | """ 362 | corr = {} 363 | corr_annual = {} 364 | rmse = {} 365 | rmse_annual = {} 366 | for key in dict.keys(): 367 | 368 | # calculate correlation 369 | corr[key] = analysis_tools.correlation_tmp( 370 | dict[key], resample_rule=resample_rule) 371 | corr_annual[key] = np.round(analysis_tools.correlation_tmp( 372 | dict[key], resample_rule='1Y').iloc[0], 2) 373 | 374 | # calculate RMSE 375 | rmse[key] = analysis_tools.variability( 376 | dict[key], resample_rule=resample_rule) 377 | rmse_annual[key] = np.round(analysis_tools.variability( 378 | dict[key], resample_rule='1Y').iloc[0], 2) 379 | 380 | # plot correlation 381 | corr['MERRA'].plot(legend=True) 382 | corr['open_FRED'].plot(legend=True, grid=True, 383 | title='Correlation {}'.format(corr_annual)) 384 | mpl.savefig(os.path.join( 385 | plot_directory, '{}_correlation_{}.png'.format( 386 | parameter, resample_rule))) 387 | mpl.clf() 388 | 389 | # plot RMSE 390 | rmse['MERRA'].plot(legend=True) 391 | rmse['open_FRED'].plot(legend=True, grid=True, 392 | title='RMSE {}'.format(rmse_annual)) 393 | mpl.savefig(os.path.join( 394 | plot_directory, '{}_rmse_{}.png'.format( 395 | parameter, resample_rule))) 396 | mpl.clf() 397 | 398 | 399 | def plot_time_range_multiple_datasets(data_dict, column, time_range, filename, 400 | plot_directory, figsize=None): 401 | """ 402 | Plots data for the given time range and weather data sets. 403 | 404 | Parameters 405 | ----------- 406 | data_dict : :obj:`dict` 407 | Dictionary where keys specify the weather data set and the 408 | corresponding values are :pandas:`DataFrame` with data to plot. 409 | time_range : :obj:`tuple` 410 | Tuple with start and end date, e.g. ('1/25/2015', '2/1/2015'). 411 | filename : :obj:`str` 412 | plot_directory : :obj:`str` 413 | Path to directory plot is saved to. 414 | figsize : :obj:`list`, optional 415 | List with height and breadth of figure, e.g. [20, 15]. Default: None. 416 | 417 | """ 418 | 419 | weather_data_sets = data_dict.keys() 420 | 421 | # set frequency of index 422 | index = {} 423 | for data_set in weather_data_sets: 424 | index[data_set] = get_index(time_range[0], time_range[1], data_set) 425 | 426 | data_dict[data_set].loc[index[data_set], :].plot( 427 | legend=True, figsize=figsize) 428 | for data_set in weather_data_sets[1:-1]: 429 | data_dict[data_set].loc[index[data_set], column].plot( 430 | legend=True, grid=True) 431 | mpl.savefig(os.path.join(plot_directory, '{}.png'.format(filename))) 432 | 433 | 434 | def calculate_dni_pvlib(weather_df, corrected=True): 435 | """ 436 | Calculates DNI from open_FRED GHI and DHI using the pvlib. 437 | 438 | :param weather_df: 439 | :param corrected: 440 | :return: 441 | """ 442 | 443 | # calculate DNI 444 | times = weather_df.index 445 | location = read_htw_data.setup_pvlib_location_object() 446 | solarposition = location.get_solarposition( 447 | times, pressure=None, temperature=weather_df['temp_air']) 448 | if corrected: 449 | # calculate corrected DNI 450 | clearsky = location.get_clearsky(times, solar_position=solarposition) 451 | dni = irradiance.dni(weather_df['ghi'], weather_df['dhi'], 452 | zenith=solarposition['zenith'], 453 | clearsky_dni=clearsky['dni'], 454 | clearsky_tolerance=1.1, 455 | zenith_threshold_for_zero_dni=88.0, 456 | zenith_threshold_for_clearsky_limit=80.0) 457 | else: 458 | dni = (weather_df['ghi'] - weather_df['dhi']) / np.cos( 459 | np.radians(solarposition['zenith'])) 460 | 461 | # setup df with calculated and Fred DNI 462 | dni.name = 'dni' 463 | df = weather_df['dni'].to_frame().join( 464 | dni.to_frame(), lsuffix='_fred', rsuffix='_pvlib') 465 | dni.set_index('time', inplace=True) 466 | 467 | return df 468 | 469 | 470 | def setup_and_run_modelchain(pv_system, location, weather_data): 471 | 472 | mc = ModelChain(system=pv_system, location=location, 473 | aoi_model='no_loss', spectral_model='no_loss') 474 | mc.run_model(weather_data.index, weather=weather_data) 475 | return mc 476 | 477 | 478 | def compare_weather_data_fred_htw(fred_weather_data): 479 | 480 | def setup_correlation_df(htw_weather_data_df, reanalysis_weather_data_df, 481 | parameter, weather_data='open_FRED', 482 | corrected=True): 483 | # Note: in case of DNI FRED DNI and calculated DNI (calculated from FRED 484 | # GHI and DHI) are compared; in case of GHI and GNI HTW (measured) values 485 | # are compared to FRED (calculated) values 486 | 487 | # setup dataframe with given parameter of HTW and FRED weather dataset 488 | if parameter == 'dni': 489 | df = calculate_dni_pvlib(reanalysis_weather_data_df, weather_data, 490 | corrected) 491 | else: 492 | df = reanalysis_weather_data_df[parameter].to_frame().join( 493 | htw_weather_data_df[parameter].to_frame(), 494 | lsuffix='_fred', rsuffix='_htw') 495 | return df 496 | 497 | def compare_parameters(df, parameter, resample_rule, plot_directory): 498 | """ 499 | Calculates and plots correlation and RMSE between two time series. 500 | 501 | :param df: 502 | :param parameter: 503 | :param resample_rule: 504 | :param plot_directory: 505 | :return: 506 | """ 507 | # calculate correlation 508 | corr = analysis_tools.correlation_tmp(df, resample_rule=resample_rule) 509 | 510 | # plot correlation 511 | corr.plot() 512 | mpl.savefig(os.path.join( 513 | plot_directory, '{}_correlation_{}.png'.format( 514 | parameter, resample_rule))) 515 | 516 | # calculate RMSE 517 | rmse = analysis_tools.variability(df, resample_rule=resample_rule) 518 | 519 | # plot correlation 520 | rmse.plot() 521 | mpl.savefig(os.path.join( 522 | plot_directory, '{}_rmse_{}.png'.format( 523 | parameter, resample_rule))) 524 | 525 | # ghi 526 | parameter = 'ghi' 527 | resample_rule = '1M' 528 | df = setup_correlation_df(htw_weather_data, fred_weather_data, parameter, 529 | weather_data) 530 | compare_parameters(df, parameter, resample_rule, plot_directory) 531 | # winter_week = ('1/25/2015', '2/1/2015'), 532 | # summer_week = ('6/2/2015', '6/8/2015') 533 | plot_week(parameter, weather_data, measured_data, plot_directory) 534 | 535 | # gni 536 | parameter = 'gni' 537 | resample_rule = '1M' 538 | df = setup_correlation_df(htw_weather_data, fred_weather_data, parameter, 539 | weather_data) 540 | compare_parameters(df, parameter, resample_rule, plot_directory) 541 | plot_week(parameter, weather_data, measured_data, plot_directory) 542 | 543 | # dni 544 | parameter = 'dni' 545 | resample_rule = '1M' 546 | weather_data = 'open_FRED' 547 | corrected = True 548 | df = setup_correlation_df(htw_weather_data, fred_weather_data, parameter, 549 | weather_data, corrected=corrected) 550 | compare_parameters(df, parameter + '_corrected', resample_rule, 551 | plot_directory) 552 | plot_week(parameter + '_corrected', weather_data, plot_directory) 553 | 554 | corrected = False 555 | df = setup_correlation_df(htw_weather_data, fred_weather_data, parameter, 556 | weather_data, corrected=corrected) 557 | compare_parameters(df, parameter + '_uncorrected', resample_rule, 558 | plot_directory) 559 | plot_week(parameter + '_uncorrected', weather_data, plot_directory) 560 | 561 | 562 | def compare_feedin_htw(converters, weather_data_sets): 563 | plot_directory = 'plot' 564 | resample_rule = '1W' 565 | 566 | ########################################################################### 567 | # read HTW converter data 568 | ########################################################################### 569 | 570 | htw_wr_data = {} 571 | for converter in converters: 572 | htw_wr_data[converter] = {} 573 | for weather_data_set in weather_data_sets: 574 | htw_wr_data[converter][weather_data_set] = \ 575 | read_htw_data.setup_converter_dataframe( 576 | converter, weather_data_set) 577 | 578 | ########################################################################### 579 | # get weather data HTW 580 | ########################################################################### 581 | 582 | htw_weather_data = {} 583 | for weather_data_set in weather_data_sets: 584 | htw_weather_data[weather_data_set] = \ 585 | read_htw_data.setup_weather_dataframe(weather_data_set) 586 | 587 | ########################################################################### 588 | # setup location 589 | ########################################################################### 590 | 591 | location = read_htw_data.setup_pvlib_location_object() 592 | 593 | ########################################################################### 594 | # get weather data 595 | ########################################################################### 596 | 597 | weather_data_dict = {} 598 | # open_FRED 599 | path = 'data/Fred/BB_2015' 600 | filename = 'fred_data_2015_htw.csv' 601 | weather_data_dict['open_FRED'] = \ 602 | get_weather_data.read_of_weather_df_pvlib_from_csv( 603 | path, filename, coordinates=None) 604 | 605 | # MERRA 606 | weather_data_dict['MERRA'] = load_merra_data( 607 | 2015, location.latitude, location.longitude, 'data/Merra') 608 | decomposition_df = apply_decomposition_model( 609 | weather_data_dict['MERRA'], 'erbs', location) 610 | try: 611 | weather_data_dict['MERRA']['dni'] = \ 612 | decomposition_df.dni_corrected.fillna(0) 613 | except: 614 | weather_data_dict['MERRA']['dni'] = \ 615 | decomposition_df.dni.fillna(0) 616 | weather_data_dict['MERRA']['dhi'] = decomposition_df.dhi.fillna(0) 617 | weather_data_dict['MERRA']['dirhi'] = \ 618 | weather_data_dict['MERRA'].ghi - weather_data_dict['MERRA'].dhi 619 | weather_data_dict['MERRA']['gni'] = \ 620 | weather_data_dict['MERRA'].dhi + weather_data_dict['MERRA'].dni 621 | 622 | gni_dict = {} 623 | gni_dict['MERRA'] = weather_data_dict['MERRA'].gni.to_frame().join( 624 | htw_weather_data['MERRA'].gni.to_frame(), rsuffix='_htw', 625 | lsuffix='_merra') 626 | weather_data_dict['open_FRED']['gni'] = \ 627 | weather_data_dict['open_FRED']['dni'] + \ 628 | weather_data_dict['open_FRED']['dhi'] 629 | gni_dict['open_FRED'] = weather_data_dict['open_FRED'].gni.to_frame().join( 630 | htw_weather_data['open_FRED'].gni.to_frame(), rsuffix='_htw', 631 | lsuffix='_open_FRED') 632 | gni_dict['open_FRED'] = \ 633 | gni_dict['open_FRED'].loc[ 634 | gni_dict['open_FRED'].index.year == 2015] 635 | compare_parameters_2( 636 | gni_dict, 'GNI', resample_rule, plot_directory) 637 | 638 | winter_week = ('3/9/2015', '3/16/2015') 639 | index = {} 640 | index['open_FRED'] = pd.date_range( 641 | start=winter_week[0], end=winter_week[1], freq='30Min', tz='UTC') \ 642 | - pd.Timedelta(minutes=15) 643 | index['MERRA'] = pd.date_range(start=winter_week[0], end=winter_week[1], 644 | freq='60Min', tz='UTC') 645 | 646 | gni_dict['MERRA'].loc[index['MERRA'], :].plot(legend=True) 647 | gni_dict['open_FRED'].loc[index['open_FRED'], 648 | 'gni_open_FRED'].plot(legend=True, grid=True) 649 | mpl.savefig(os.path.join(plot_directory, '{}_march_week.png'.format( 650 | 'GNI'))) 651 | 652 | # dhi_monthly_sums = {} 653 | # dhi_monthly_sums['MERRA'] = weather_data_dict['MERRA'].dhi.resample( 654 | # '1M').sum() 655 | # dhi_monthly_sums['open_FRED'] = weather_data_dict[ 656 | # 'open_FRED'].dhi.resample('1H').mean().resample('1M').sum() 657 | #htw_weather_data['open_FRED'].gni.resample('1H').mean().resample('1M').sum() 658 | 659 | ########################################################################### 660 | # setup modules 661 | ########################################################################### 662 | 663 | modules = {} 664 | for converter in converters: 665 | modules[converter] = read_htw_data.setup_htw_pvlib_pvsystem(converter) 666 | 667 | ########################################################################### 668 | # call modelchain with reanalysis data 669 | ########################################################################### 670 | 671 | feedin = {} 672 | for converter in converters: 673 | feedin[converter] = {} 674 | for weather_data_set in weather_data_sets: 675 | # set up modelchain 676 | mc = setup_and_run_modelchain( 677 | modules[converter], location, 678 | weather_data_dict[weather_data_set]) 679 | 680 | # set up feed-in 681 | feedin[converter][weather_data_set] = mc.dc.p_mp.to_frame().join( 682 | htw_wr_data[converter][weather_data_set]['P_DC'].to_frame()) 683 | feedin[converter][weather_data_set].rename( 684 | columns={'p_mp': 'energy_calculated_{}'.format( 685 | weather_data_set), 686 | 'P_DC': 'energy_measured'}, 687 | inplace=True) 688 | feedin[converter][weather_data_set] = \ 689 | feedin[converter][weather_data_set].loc[ 690 | feedin[converter][weather_data_set].index.year == 2015] 691 | 692 | # calculate monthly correlation and RMSE for feed-in 693 | parameter = 'pv_feedin_{}'.format(converter) 694 | compare_parameters_2( 695 | feedin[converter], parameter, resample_rule, plot_directory) 696 | 697 | plot_week_2(feedin[converter], parameter, plot_directory) 698 | 699 | # compare energy 700 | monthly_energy = {} 701 | monthly_energy['MERRA'] = feedin[converter][ 702 | 'MERRA'].resample(resample_rule).sum() 703 | monthly_energy['open_FRED'] = feedin[converter][ 704 | 'open_FRED'].resample(resample_rule).sum() / 2 705 | monthly_energy['MERRA'].plot(legend=True) 706 | monthly_energy['open_FRED'].loc[:, 'energy_calculated_open_FRED'].plot( 707 | legend=True, grid=True, title='Energy feed-in') 708 | mpl.savefig(os.path.join(plot_directory, 709 | 'pv_feedin_{}_energy.png'.format( 710 | converter))) 711 | mpl.clf() 712 | 713 | ########################################################################### 714 | # call modelchain with HTW data 715 | ########################################################################### 716 | 717 | htw_weather_data_modified = {} 718 | for weather_data_set in weather_data_sets: 719 | htw_weather_data_modified[weather_data_set] = weather_data_dict[ 720 | weather_data_set].copy() 721 | htw_weather_data_modified[weather_data_set]['ghi'] = \ 722 | htw_weather_data[weather_data_set]['ghi'] 723 | htw_weather_data_modified[weather_data_set]['dhi'] = \ 724 | htw_weather_data_modified[weather_data_set]['ghi'] - \ 725 | htw_weather_data_modified[weather_data_set]['dirhi'] 726 | 727 | for converter in converters: 728 | for weather_data_set in weather_data_sets: 729 | # set up modelchain 730 | mc = setup_and_run_modelchain( 731 | modules[converter], location, 732 | htw_weather_data_modified[weather_data_set]) 733 | 734 | # set up feed-in 735 | feedin[converter][weather_data_set] = mc.dc.p_mp.to_frame().join( 736 | htw_wr_data[converter][weather_data_set]['P_DC'].to_frame()) 737 | feedin[converter][weather_data_set].rename( 738 | columns={'p_mp': 'energy_calculated_{}'.format( 739 | weather_data_set), 740 | 'P_DC': 'energy_measured'}, 741 | inplace=True) 742 | feedin[converter][weather_data_set] = \ 743 | feedin[converter][weather_data_set].loc[ 744 | feedin[converter][weather_data_set].index.year == 2015] 745 | 746 | # calculate monthly correlation and RMSE for feed-in 747 | parameter = 'pv_feedin_{}_htw'.format(converter) 748 | compare_parameters_2( 749 | feedin[converter], parameter, resample_rule, plot_directory) 750 | 751 | plot_week_2(feedin[converter], parameter, plot_directory) 752 | 753 | # compare energy 754 | monthly_energy = {} 755 | monthly_energy['MERRA'] = feedin[converter][ 756 | 'MERRA'].resample(resample_rule).sum() 757 | monthly_energy['open_FRED'] = feedin[converter][ 758 | 'open_FRED'].resample( 759 | resample_rule).sum() / 2 760 | monthly_energy['MERRA'].plot(legend=True) 761 | monthly_energy['open_FRED'].loc[:, 762 | 'energy_calculated_open_FRED'].plot( 763 | legend=True, grid=True, title='Energy feed-in') 764 | mpl.savefig(os.path.join(plot_directory, 765 | 'pv_feedin_{}_energy_htw.png'.format( 766 | converter))) 767 | mpl.clf() 768 | 769 | 770 | if __name__ == '__main__': 771 | 772 | # weather_data_sets = ['MERRA', 'open_FRED'] 773 | # converters = ['wr3', 'wr4'] 774 | # compare_feedin_htw(converters, weather_data_sets) 775 | 776 | year = 2015 777 | location = read_htw_data.setup_pvlib_location_object() 778 | merra_df = load_merra_data(year, location.latitude, location.longitude, 779 | 'data/Merra') 780 | fred_df = get_weather_data.read_of_weather_df_pvlib_from_csv( 781 | 'data/Fred/BB_2015', 'fred_data_2015_htw.csv', coordinates=None) 782 | htw_weather_data = read_htw_data.setup_weather_dataframe( 783 | weather_data='MERRA') 784 | df_comp = compare_decomposition_models( 785 | merra_df, location, htw_weather_data, plot=True) 786 | # fred_df['gni_fred'] = fred_df.dni + fred_df.dhi 787 | # fred_df.ghi.to_frame().plot() 788 | # df_comp.loc[:, ['gni_disc', 'gni_corrected_reindl', 'gni_corrected_erbs']].plot() 789 | # mpl.savefig(os.path.join('plot/decomposition', 'test.png')) 790 | 791 | 792 | 793 | # ############################################################################## 794 | # # compare FRED and HTW weather data 795 | # ############################################################################## 796 | # 797 | # # ghi 798 | # parameter = 'ghi' 799 | # resample_rule = '1M' 800 | # df = setup_correlation_df(htw_weather_data, fred_weather_data, parameter, 801 | # weather_data) 802 | # compare_parameters(df, parameter, resample_rule, plot_directory) 803 | # plot_week(parameter, weather_data, measured_data, plot_directory) 804 | # 805 | # # gni 806 | # parameter = 'gni' 807 | # resample_rule = '1M' 808 | # df = setup_correlation_df(htw_weather_data, fred_weather_data, parameter, 809 | # weather_data) 810 | # compare_parameters(df, parameter, resample_rule, plot_directory) 811 | # plot_week(parameter, weather_data, measured_data, plot_directory) 812 | # 813 | # # dni 814 | # parameter = 'dni' 815 | # resample_rule = '1M' 816 | # weather_data = 'open_FRED' 817 | # corrected = True 818 | # df = setup_correlation_df(htw_weather_data, fred_weather_data, parameter, 819 | # weather_data, corrected=corrected) 820 | # compare_parameters(df, parameter + '_corrected', resample_rule, 821 | # plot_directory) 822 | # plot_week(parameter + '_corrected', weather_data, plot_directory) 823 | # 824 | # corrected = False 825 | # df = setup_correlation_df(htw_weather_data, fred_weather_data, parameter, 826 | # weather_data, corrected=corrected) 827 | # compare_parameters(df, parameter + '_uncorrected', resample_rule, 828 | # plot_directory) 829 | # plot_week(parameter + '_uncorrected', weather_data, plot_directory) 830 | # 831 | -------------------------------------------------------------------------------- /pv3_results.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | Service functions 6 | 7 | Configure console and file logging; 8 | Create and handle config file for database connection; 9 | 10 | SPDX-License-Identifier: AGPL-3.0-or-later 11 | """ 12 | 13 | __copyright__ = "© Ludwig Hülk" 14 | __license__ = "GNU Affero General Public License Version 3 (AGPL-3.0)" 15 | __url__ = "https://www.gnu.org/licenses/agpl-3.0.en.html" 16 | __author__ = "Ludee;" 17 | __version__ = "v0.0.2" 18 | 19 | from settings import setup_logger, write_to_csv 20 | 21 | import pandas as pd 22 | 23 | """logging""" 24 | log = setup_logger() 25 | 26 | 27 | def results_modelchain(mc, weather): 28 | system_name = mc.system.name 29 | li_mc_ac = mc.ac 30 | li_mc_temp = mc.cell_temperature 31 | df_mc_dc = mc.dc 32 | df_mc_dc.index.name = 'timestamp' 33 | df_mc_weather = mc.weather 34 | df_mc_weather.index.name = 'timestamp' 35 | 36 | df = pd.DataFrame({'ac': li_mc_ac, 37 | 'cell_temperature': li_mc_temp, 38 | }) 39 | df.index.name = 'timestamp' 40 | 41 | df = df.merge(df_mc_dc, on='timestamp', how='right') 42 | df = df.merge(df_mc_weather, on='timestamp', how='right') 43 | 44 | filename = f'pv3_pvlib_{weather}_{system_name}' 45 | write_to_csv(f'./data/{filename}.csv', df, append=False) 46 | 47 | return df 48 | 49 | 50 | def results_modelchain_per_month(mc, df, weather): 51 | system_name = mc.system.name 52 | df_month = df[['ac', 'p_mp']].resample('M').sum() 53 | df_month.insert(0, "weather", weather, True) 54 | df_month.insert(0, "system_name", system_name, True) 55 | 56 | write_to_csv(f'./data/pv3_pvlib_month.csv', df_month, append=True) 57 | 58 | return df_month 59 | 60 | 61 | def results_modelchain_annual_yield(mc, weather): 62 | mc_ac = mc.ac 63 | system_name = mc.system.name 64 | 65 | annual_yield = round(mc_ac.sum() / 1000, 3) 66 | df = pd.DataFrame([[weather, system_name, annual_yield]], 67 | columns=['weather', 'system', 'annual_yield']) 68 | df.set_index(["weather", 'system'], inplace=True) 69 | 70 | write_to_csv('./data/pv3_pvlib_annual.csv', df) 71 | 72 | log.info(f'Annual yield for {system_name}: {annual_yield}') 73 | 74 | return annual_yield 75 | -------------------------------------------------------------------------------- /pv3_sonnja_pvlib.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | HTW-PV3 - Create pvlib model for SONNJA 6 | 7 | 8 | 9 | SPDX-License-Identifier: AGPL-3.0-or-later 10 | """ 11 | 12 | __copyright__ = "© Ludwig Hülk" 13 | __license__ = "GNU Affero General Public License Version 3 (AGPL-3.0)" 14 | __url__ = "https://www.gnu.org/licenses/agpl-3.0.en.html" 15 | __author__ = "Ludee;" 16 | __version__ = "v0.0.2" 17 | 18 | import pvlib 19 | from pvlib.location import Location 20 | from pvlib.pvsystem import PVSystem 21 | from pvlib.modelchain import ModelChain 22 | from pvlib.temperature import TEMPERATURE_MODEL_PARAMETERS 23 | 24 | from settings import HTW_LAT, HTW_LON 25 | 26 | from component_import import get_sma_sb_3000hf, get_danfoss_dlx_2_9, get_aleo_s18_240, get_aleo_s19_245, get_aleo_s19_285, get_schott_asi_105 27 | 28 | import logging 29 | log = logging.getLogger(__name__) 30 | 31 | temperature_model_parameters = TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass'] 32 | 33 | 34 | def setup_pvlib_location_object(): 35 | """ 36 | Sets up pvlib Location object for HTW. 37 | 38 | Returns 39 | ------- 40 | :pvlib:`Location` 41 | 42 | """ 43 | return Location(latitude=HTW_LAT, longitude=HTW_LON, 44 | tz='Europe/Berlin', altitude=80, name='HTW Berlin') 45 | 46 | 47 | def setup_htw_pvlib_pvsystems(converter_number): 48 | """ 49 | Sets up pvlib PVSystem for HTW Modules. 50 | 51 | Parameters 52 | ----------- 53 | converter_number : :obj:`str` 54 | HTW converter number. Possible options are 'wr1', 'wr2', 'wr3', 'wr4', 55 | 'wr5'. 56 | 57 | Returns 58 | ------- 59 | :pvlib:`PVSystem` 60 | 61 | """ 62 | 63 | # get module and inverter parameters 64 | sandia_modules = pvlib.pvsystem.retrieve_sam('SandiaMod') 65 | sandia_inverters = pvlib.pvsystem.retrieve_sam('sandiainverter') 66 | CEC_modules = pvlib.pvsystem.retrieve_sam('CECMod') 67 | CEC_inverters = pvlib.pvsystem.retrieve_sam('sandiainverter') 68 | 69 | inv_sma = 'SMA_Solar_Technology_AG__SB3000HFUS_30___240V_240V__CEC_2011_' 70 | inv_danfoss = 'Danfoss_Solar__DLX_2_9_UL__240V__240V__CEC_2013_' 71 | 72 | # module 1 - Schott aSi 105W / Danfoss DLX 2.9 73 | if converter_number == 'wr1': 74 | pv_module = PVSystem(module='schott_aSi_105', inverter=inv_danfoss, 75 | module_parameters=CEC_modules[ 76 | 'schott_aSi_105'], 77 | inverter_parameters=CEC_inverters[inv_danfoss], 78 | surface_tilt=14.57, surface_azimuth=215., 79 | albedo=0.2, 80 | modules_per_string=10, strings_per_inverter=3, 81 | name='HTW_module_1') 82 | pv_module.module_parameters['EgRef'] = 1.121 # The energy bandgap at reference temperature in eV. 83 | pv_module.module_parameters['dEgdT'] = -0.0002677 #The temperature dependence of EgRef at reference conditions in 1/K. 84 | pv_module.module_parameters['alpha_sc'] = 0.04 # The short-circuit current temperature coefficient 85 | 86 | # module 2 - Aleo S19 285W / Danfoss DLX 2.9 'Aleo_Solar_S19H270' CEC 87 | elif converter_number == 'wr2': 88 | pv_module = PVSystem(module='aleo_solar_S19_285', inverter=inv_danfoss, 89 | module_parameters=CEC_modules[ 90 | 'aleo_solar_S19_285'], 91 | inverter_parameters=CEC_inverters[inv_danfoss], 92 | surface_tilt=14.57, surface_azimuth=215., 93 | albedo=0.2, 94 | modules_per_string=11, strings_per_inverter=1, 95 | name='HTW_module_2') 96 | pv_module.module_parameters['EgRef'] = 1.121 97 | pv_module.module_parameters['dEgdT'] = -0.0002677 98 | pv_module.module_parameters['alpha_sc'] = 0.04 99 | 100 | # module 3 - Aleo S18 240W / Danfoss DLX 2.9 101 | elif converter_number == 'wr3': 102 | pv_module = PVSystem(module='aleo_solar_S18_240', inverter=inv_danfoss, 103 | module_parameters=CEC_modules[ 104 | 'aleo_solar_S18_240'], 105 | inverter_parameters=CEC_inverters[inv_danfoss], 106 | surface_tilt=14.57, surface_azimuth=215., 107 | albedo=0.2, 108 | modules_per_string=14, strings_per_inverter=1, 109 | name='HTW_module_3') 110 | pv_module.module_parameters['EgRef'] = 1.121 111 | pv_module.module_parameters['dEgdT'] = -0.0002677 112 | pv_module.module_parameters['alpha_sc'] = 0.04 113 | 114 | # module 4 - Aleo S19 245W / SMA SB 3000HF-30 115 | elif converter_number == 'wr4': 116 | pv_module = PVSystem(module='Aleo_Solar_S19U245_ulr', inverter=inv_sma, 117 | module_parameters=CEC_modules[ 118 | 'Aleo_Solar_S19U245_ulr'], 119 | inverter_parameters=CEC_inverters[inv_sma], 120 | surface_tilt=14.57, surface_azimuth=215., 121 | albedo=0.2, 122 | modules_per_string=13, strings_per_inverter=1, 123 | name='HTW_module_4') 124 | pv_module.module_parameters['EgRef'] = 1.121 125 | pv_module.module_parameters['dEgdT'] = -0.0002677 126 | pv_module.module_parameters['alpha_sc'] = 0.03 127 | # module 5 - Schott aSi 105W / SMA SB 3000HF-30 128 | elif converter_number == 'wr5': 129 | pv_module = PVSystem(module='schott_aSi_105', inverter=inv_danfoss, 130 | module_parameters=CEC_modules[ 131 | 'schott_aSi_105'], 132 | inverter_parameters=CEC_inverters[inv_danfoss], 133 | surface_tilt=14.57, surface_azimuth=215., 134 | albedo=0.2, 135 | modules_per_string=10, strings_per_inverter=3, 136 | name='HTW_module_5') 137 | pv_module.module_parameters['EgRef'] = 1.121 138 | pv_module.module_parameters['dEgdT'] = -0.0002677 139 | pv_module.module_parameters['alpha_sc'] = 0.04 140 | return pv_module 141 | 142 | 143 | def setup_htw_pvsystem_wr1(): 144 | 145 | inv = 'Danfoss_Solar__DLX_2_9' 146 | inv_data = get_danfoss_dlx_2_9() 147 | wr1_module = 'Schott a-Si 105 W' 148 | module_data = get_schott_asi_105() 149 | 150 | model_wr1 = PVSystem(module=wr1_module, 151 | inverter=inv, 152 | module_parameters=module_data, 153 | inverter_parameters=inv_data, 154 | surface_tilt=14.57, 155 | surface_azimuth=215., 156 | albedo=0.2, 157 | modules_per_string=10, 158 | strings_per_inverter=3, 159 | temperature_model_parameters=temperature_model_parameters, 160 | name='wr1') 161 | 162 | return model_wr1 163 | 164 | 165 | def setup_htw_pvsystem_wr2(): 166 | 167 | # Download parameters for pv 168 | cec_modules = pvlib.pvsystem.retrieve_sam('CECMod') 169 | 170 | inv = 'Danfoss_Solar__DLX_2_9' 171 | inv_data = get_danfoss_dlx_2_9() 172 | wr2_module = 'Aleo_Solar_S19y285' 173 | 174 | model_wr2 = PVSystem(module=wr2_module, 175 | inverter=inv, 176 | module_parameters=cec_modules[wr2_module], 177 | inverter_parameters=inv_data, 178 | surface_tilt=14.57, 179 | surface_azimuth=215., 180 | albedo=0.2, 181 | modules_per_string=11, 182 | strings_per_inverter=1, 183 | temperature_model_parameters=temperature_model_parameters, 184 | name='wr2') 185 | 186 | return model_wr2 187 | 188 | 189 | def setup_htw_pvsystem_wr3(): 190 | 191 | inv = 'Danfoss_Solar__DLX_2_9' 192 | inv_data = get_danfoss_dlx_2_9() 193 | pv3_module = 'aleo_solar_s18_240' 194 | module_data = get_aleo_s18_240() 195 | 196 | model_wr3 = PVSystem(module=pv3_module, 197 | inverter=inv, 198 | module_parameters=module_data, 199 | inverter_parameters=inv_data, 200 | surface_tilt=14.57, 201 | surface_azimuth=215., 202 | albedo=0.2, 203 | modules_per_string=14, 204 | strings_per_inverter=1, 205 | temperature_model_parameters=temperature_model_parameters, 206 | name='wr3') 207 | 208 | return model_wr3 209 | 210 | 211 | def setup_htw_pvsystem_wr4(): 212 | 213 | inv = 'SMA_SB_3000HF_30' 214 | inv_data = get_sma_sb_3000hf() 215 | pv3_module = 'aleo_solar_s19_245' 216 | module_data = get_aleo_s19_245() 217 | 218 | model_wr4 = PVSystem(module=pv3_module, 219 | inverter=inv, 220 | module_parameters=module_data, 221 | inverter_parameters=inv_data, 222 | surface_tilt=14.57, 223 | surface_azimuth=215., 224 | albedo=0.2, 225 | modules_per_string=13, 226 | strings_per_inverter=1, 227 | temperature_model_parameters=temperature_model_parameters, 228 | name='wr4') 229 | 230 | return model_wr4 231 | 232 | 233 | def setup_htw_pvsystem_wr5(): 234 | 235 | inv = 'SMA_SB_3000HF_30' 236 | inv_data = get_sma_sb_3000hf() 237 | wr5_module = 'Schott a-Si 105 W' 238 | module_data = get_schott_asi_105() 239 | 240 | model_wr5 = PVSystem(module=wr5_module, 241 | inverter=inv, 242 | module_parameters=module_data, 243 | inverter_parameters=inv_data, 244 | surface_tilt=14.57, 245 | surface_azimuth=215., 246 | albedo=0.2, 247 | modules_per_string=10, 248 | strings_per_inverter=3, 249 | temperature_model_parameters=temperature_model_parameters, 250 | name='wr5') 251 | 252 | return model_wr5 253 | 254 | 255 | def setup_modelchain(pv_system, location): 256 | 257 | mc = ModelChain(system=pv_system, location=location, 258 | aoi_model='no_loss', spectral_model='no_loss') 259 | return mc 260 | 261 | 262 | def run_modelchain(mc, weather_data): 263 | 264 | mc.run_model(weather=weather_data) 265 | 266 | return mc 267 | -------------------------------------------------------------------------------- /pv3_sonnja_results.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# PV3 Result visualisations\n", 8 | "\n", 9 | "\n", 10 | "\n", 11 | "__copyright__ \t= \"© Reiner Lemoine Institut\"
\n", 12 | "__license__ \t= \"GNU Affero General Public License Version 3 (AGPL-3.0)\"
\n", 13 | "__url__ \t\t= \"https://www.gnu.org/licenses/agpl-3.0.en.html\"
\n", 14 | "__author__ \t\t= \"Ludwig Hülk\"
" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "# Imports" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 1, 27 | "metadata": {}, 28 | "outputs": [ 29 | { 30 | "data": { 31 | "text/html": [ 32 | " \n", 47 | " " 48 | ] 49 | }, 50 | "metadata": {}, 51 | "output_type": "display_data" 52 | } 53 | ], 54 | "source": [ 55 | "import sys\n", 56 | "import os\n", 57 | "import getpass\n", 58 | "import pandas as pd\n", 59 | "import numpy as np\n", 60 | "import json\n", 61 | "from sqlalchemy import *\n", 62 | "# plot\n", 63 | "import matplotlib.pyplot as plt\n", 64 | "import matplotlib.ticker as mticker\n", 65 | "import plotly.graph_objs as go\n", 66 | "import plotly.offline as pltly\n", 67 | "import colorlover as cl\n", 68 | "import seaborn as sns\n", 69 | "# notebook\n", 70 | "from IPython.display import Image\n", 71 | "from IPython.core.display import HTML \n", 72 | "\n", 73 | "pltly.init_notebook_mode(connected=True)\n", 74 | "%matplotlib inline\n", 75 | "\n", 76 | "version = 'v1 (jupyter)'\n", 77 | "project = 'pv3'" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "# Read Data" 85 | ] 86 | }, 87 | { 88 | "cell_type": "markdown", 89 | "metadata": {}, 90 | "source": [ 91 | "Add results files as CSV in the data folder.\n", 92 | "Must contain two columns: month, value." 93 | ] 94 | }, 95 | { 96 | "cell_type": "code", 97 | "execution_count": 2, 98 | "metadata": {}, 99 | "outputs": [ 100 | { 101 | "data": { 102 | "text/html": [ 103 | "
\n", 104 | "\n", 117 | "\n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | " \n", 157 | " \n", 158 | " \n", 159 | " \n", 160 | " \n", 161 | " \n", 162 | " \n", 163 | " \n", 164 | " \n", 165 | " \n", 166 | " \n", 167 | " \n", 168 | " \n", 169 | " \n", 170 | " \n", 171 | " \n", 172 | " \n", 173 | " \n", 174 | " \n", 175 | " \n", 176 | " \n", 177 | " \n", 178 | "
Einspeisung in kWh
Monat
Jan211
Feb758
Mrz1199
Apr1920
Mai2176
Jun2270
Jul2399
Aug2365
Sep1449
Okt918
Nov386
Dez326
\n", 179 | "
" 180 | ], 181 | "text/plain": [ 182 | " Einspeisung in kWh\n", 183 | "Monat \n", 184 | "Jan 211\n", 185 | "Feb 758\n", 186 | "Mrz 1199\n", 187 | "Apr 1920\n", 188 | "Mai 2176\n", 189 | "Jun 2270\n", 190 | "Jul 2399\n", 191 | "Aug 2365\n", 192 | "Sep 1449\n", 193 | "Okt 918\n", 194 | "Nov 386\n", 195 | "Dez 326" 196 | ] 197 | }, 198 | "execution_count": 2, 199 | "metadata": {}, 200 | "output_type": "execute_result" 201 | } 202 | ], 203 | "source": [ 204 | "file_name = 'data/2015_SonnJA_Abrechnung_Einspeisung.csv'\n", 205 | "df_feedin_billing = pd.read_csv(file_name, encoding='latin1', sep=';', index_col=0, parse_dates=True)\n", 206 | "df_feedin_billing" 207 | ] 208 | }, 209 | { 210 | "cell_type": "markdown", 211 | "metadata": {}, 212 | "source": [ 213 | "# Metadata\n", 214 | "\n", 215 | "The important information from the above select (**df**) is collected in a Dictionary (**info_dict**)." 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": 3, 221 | "metadata": {}, 222 | "outputs": [], 223 | "source": [ 224 | "# Facts dict\n", 225 | "info_dict = {}\n", 226 | "info_dict['Filename'] = ['{}_pv3_sonnja_results'.format(pd.to_datetime('today').strftime(\"%Y-%m-%d\"))]\n", 227 | "info_dict['Value'] = ['Einspeisung (E_AC)']\n", 228 | "info_dict['Unit'] = ['kWh']\n", 229 | "info_dict['Y-Axis'] = ['{} in {}'.format(*info_dict['Value'], *info_dict['Unit'])]\n", 230 | "info_dict['X-Axis'] = ['Monat']\n", 231 | "info_dict['Title'] = ['Einspeisung pro Monat']\n", 232 | "# info_dict['Metadata'] = [meta_str]\n", 233 | "\n", 234 | "# Print facts\n", 235 | "# for x in info_dict:\n", 236 | "# print(x,':',info_dict[x])" 237 | ] 238 | }, 239 | { 240 | "cell_type": "markdown", 241 | "metadata": {}, 242 | "source": [ 243 | "## Plot with Metadata" 244 | ] 245 | }, 246 | { 247 | "cell_type": "code", 248 | "execution_count": 4, 249 | "metadata": {}, 250 | "outputs": [ 251 | { 252 | "data": { 253 | "text/plain": [ 254 | "(0.0, 2518.95)" 255 | ] 256 | }, 257 | "execution_count": 4, 258 | "metadata": {}, 259 | "output_type": "execute_result" 260 | }, 261 | { 262 | "data": { 263 | "image/png": "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4+c//zl/+tOfGDZsGB/5yEc488wzefe7373guMsvv5xXvvKVXHrppQA88cQTTeO/4447uPLKK5kzZw4bbbQRH/7wh7nppps4//zzueGGG5g3bx6bbbYZm2++edNzzZs3j2uvvZbLLruMI488kt/+9rcN95s2bRof//jHueiii1hnnXXYeuutOeqooxbc+5FHHslxxx23YN+JEycuOPbBBx9k6tSp3HHHHey+++7svffeTeNqxmRbkiRpCdVfM5JaSy+99IK2yptvvjlXXHEFABMnTuSggw5in332Ya+99lqw/w477LCg2cRee+3F1KlTGTp0KDNmzGCLLbYAiiR/tdVWe9F1Xv/61/O5z32OQw45hF133ZU3vvGNTePfZZddGD58OMOHD2e11VbjoYceYurUqeyxxx4ss8wyAOy2224t/Sz67mHzzTfn3nvvbbjP7bffzpQpU/jNb37DK1/5SgDGjx/PDTfcwNNPP81zzz3H8ssvz/rrr8/MmTOZNm0an/3sZxccv+eee7LUUkux8cYbL3hC8FKZbEuSJHWxYcOGLRiSbsiQIcybNw8oOhj++c9/5tJLL2Xs2LELkvb64esigszkwAMP5Gtf+1q/19lwww2ZMWMGl112GYcddhhvectb+NKXvsTQoUN5/vnnARaabXP48OELlvtiy1y8J1N956q9x3prrLEGc+fO5YYbbliQbC+77LK8+tWv5tRTT2WzzTYDYMKECVx22WU8/PDDbLTRRg3jXdw469lmW5IkqQf99a9/Zcstt+Soo45i5MiR3H///QBcccUVPPbYYzzzzDNceOGFTJw4ke23357zzjuPhx9+GIDHHnuMv/3tby863wMPPMCyyy7L/vvvz+c+9zmuv/56oGizPWPGDADOP//8pnFts802XHLJJcydO5ennnpqQbOUdnjFK17BpZdeyhe+8AWuuuqqBeUTJ07kuOOOY6uttgJgq6224vjjj2fChAmVj6VuzbYkSc3YJl3Qkd9LfZvtHXfcccHwf80cfPDB3HXXXWQm22+/PWPGjOHGG29km2224YADDmDmzJnst99+jBs3DoCvfOUrvOUtb+H5559n2LBhfO9732PdddddcL6bb76Zgw8+mKWWWophw4Zx4oknAnD44Yfzvve9j69+9atsueWWTePaYost2H333RkzZgzrrrsu48aNY6WVVlqE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\n", 264 | "text/plain": [ 265 | "
" 266 | ] 267 | }, 268 | "metadata": { 269 | "needs_background": "light" 270 | }, 271 | "output_type": "display_data" 272 | } 273 | ], 274 | "source": [ 275 | "# Bar plot\n", 276 | "mfig_feedin = plt.figure(figsize=(12, 5))\n", 277 | "ax = plt.subplot()\n", 278 | "plt.title(*info_dict['Title'], fontsize=16) # Title from info\n", 279 | "plt.ylabel(*info_dict['Y-Axis']) # Label from info\n", 280 | "df_feedin_billing.plot.bar(ax=ax, color='orange')\n", 281 | "ax.set_ylim(ymin=0)" 282 | ] 283 | }, 284 | { 285 | "cell_type": "markdown", 286 | "metadata": {}, 287 | "source": [ 288 | "## Interactive Plot with Metadata" 289 | ] 290 | }, 291 | { 292 | "cell_type": "code", 293 | "execution_count": 5, 294 | "metadata": {}, 295 | "outputs": [ 296 | { 297 | "data": { 298 | "application/vnd.plotly.v1+json": { 299 | "config": { 300 | "linkText": "Export to plot.ly", 301 | "plotlyServerURL": "https://plot.ly", 302 | "showLink": false 303 | }, 304 | "data": [ 305 | { 306 | "name": "Einspeisung Abrechnung", 307 | "type": "bar", 308 | "x": [ 309 | "Jan", 310 | "Feb", 311 | "Mrz", 312 | "Apr", 313 | "Mai", 314 | "Jun", 315 | "Jul", 316 | "Aug", 317 | "Sep", 318 | "Okt", 319 | "Nov", 320 | "Dez" 321 | ], 322 | "y": [ 323 | 211, 324 | 758, 325 | 1199, 326 | 1920, 327 | 2176, 328 | 2270, 329 | 2399, 330 | 2365, 331 | 1449, 332 | 918, 333 | 386, 334 | 326 335 | ] 336 | }, 337 | { 338 | "mode": "lines", 339 | "name": "Einspeisung Abrechnung", 340 | "type": "scatter", 341 | "x": [ 342 | "Jan", 343 | "Feb", 344 | "Mrz", 345 | "Apr", 346 | "Mai", 347 | "Jun", 348 | "Jul", 349 | "Aug", 350 | "Sep", 351 | "Okt", 352 | "Nov", 353 | "Dez" 354 | ], 355 | "y": [ 356 | 211, 357 | 758, 358 | 1199, 359 | 1920, 360 | 2176, 361 | 2270, 362 | 2399, 363 | 2365, 364 | 1449, 365 | 918, 366 | 386, 367 | 326 368 | ] 369 | } 370 | ], 371 | "layout": { 372 | "template": { 373 | "data": { 374 | "bar": [ 375 | { 376 | "error_x": { 377 | "color": "#2a3f5f" 378 | }, 379 | "error_y": { 380 | "color": "#2a3f5f" 381 | }, 382 | "marker": { 383 | "line": { 384 | "color": "#E5ECF6", 385 | "width": 0.5 386 | } 387 | }, 388 | "type": "bar" 389 | } 390 | ], 391 | "barpolar": [ 392 | { 393 | "marker": { 394 | "line": { 395 | "color": "#E5ECF6", 396 | "width": 0.5 397 | } 398 | }, 399 | "type": "barpolar" 400 | } 401 | ], 402 | "carpet": [ 403 | { 404 | "aaxis": { 405 | "endlinecolor": "#2a3f5f", 406 | "gridcolor": "white", 407 | "linecolor": "white", 408 | "minorgridcolor": "white", 409 | "startlinecolor": "#2a3f5f" 410 | }, 411 | "baxis": { 412 | "endlinecolor": "#2a3f5f", 413 | "gridcolor": "white", 414 | "linecolor": "white", 415 | "minorgridcolor": "white", 416 | "startlinecolor": "#2a3f5f" 417 | }, 418 | "type": "carpet" 419 | } 420 | ], 421 | "choropleth": [ 422 | { 423 | "colorbar": { 424 | "outlinewidth": 0, 425 | "ticks": "" 426 | }, 427 | "type": "choropleth" 428 | } 429 | ], 430 | "contour": [ 431 | { 432 | "colorbar": { 433 | "outlinewidth": 0, 434 | "ticks": "" 435 | }, 436 | "colorscale": [ 437 | [ 438 | 0, 439 | "#0d0887" 440 | ], 441 | [ 442 | 0.1111111111111111, 443 | "#46039f" 444 | ], 445 | [ 446 | 0.2222222222222222, 447 | "#7201a8" 448 | ], 449 | [ 450 | 0.3333333333333333, 451 | "#9c179e" 452 | ], 453 | [ 454 | 0.4444444444444444, 455 | "#bd3786" 456 | ], 457 | [ 458 | 0.5555555555555556, 459 | "#d8576b" 460 | ], 461 | [ 462 | 0.6666666666666666, 463 | "#ed7953" 464 | ], 465 | [ 466 | 0.7777777777777778, 467 | "#fb9f3a" 468 | ], 469 | [ 470 | 0.8888888888888888, 471 | "#fdca26" 472 | ], 473 | [ 474 | 1, 475 | "#f0f921" 476 | ] 477 | ], 478 | "type": "contour" 479 | } 480 | ], 481 | "contourcarpet": [ 482 | { 483 | "colorbar": { 484 | "outlinewidth": 0, 485 | "ticks": "" 486 | }, 487 | "type": "contourcarpet" 488 | } 489 | ], 490 | "heatmap": [ 491 | { 492 | "colorbar": { 493 | "outlinewidth": 0, 494 | "ticks": "" 495 | }, 496 | "colorscale": [ 497 | [ 498 | 0, 499 | "#0d0887" 500 | ], 501 | [ 502 | 0.1111111111111111, 503 | "#46039f" 504 | ], 505 | [ 506 | 0.2222222222222222, 507 | "#7201a8" 508 | ], 509 | [ 510 | 0.3333333333333333, 511 | "#9c179e" 512 | ], 513 | [ 514 | 0.4444444444444444, 515 | "#bd3786" 516 | ], 517 | [ 518 | 0.5555555555555556, 519 | "#d8576b" 520 | ], 521 | [ 522 | 0.6666666666666666, 523 | "#ed7953" 524 | ], 525 | [ 526 | 0.7777777777777778, 527 | "#fb9f3a" 528 | ], 529 | [ 530 | 0.8888888888888888, 531 | "#fdca26" 532 | ], 533 | [ 534 | 1, 535 | "#f0f921" 536 | ] 537 | ], 538 | "type": "heatmap" 539 | } 540 | ], 541 | "heatmapgl": [ 542 | { 543 | "colorbar": { 544 | "outlinewidth": 0, 545 | "ticks": "" 546 | }, 547 | "colorscale": [ 548 | [ 549 | 0, 550 | "#0d0887" 551 | ], 552 | [ 553 | 0.1111111111111111, 554 | "#46039f" 555 | ], 556 | [ 557 | 0.2222222222222222, 558 | "#7201a8" 559 | ], 560 | [ 561 | 0.3333333333333333, 562 | "#9c179e" 563 | ], 564 | [ 565 | 0.4444444444444444, 566 | "#bd3786" 567 | ], 568 | [ 569 | 0.5555555555555556, 570 | "#d8576b" 571 | ], 572 | [ 573 | 0.6666666666666666, 574 | "#ed7953" 575 | ], 576 | [ 577 | 0.7777777777777778, 578 | "#fb9f3a" 579 | ], 580 | [ 581 | 0.8888888888888888, 582 | "#fdca26" 583 | ], 584 | [ 585 | 1, 586 | "#f0f921" 587 | ] 588 | ], 589 | "type": "heatmapgl" 590 | } 591 | ], 592 | "histogram": [ 593 | { 594 | "marker": { 595 | "colorbar": { 596 | "outlinewidth": 0, 597 | "ticks": "" 598 | } 599 | }, 600 | "type": "histogram" 601 | } 602 | ], 603 | "histogram2d": [ 604 | { 605 | "colorbar": { 606 | "outlinewidth": 0, 607 | "ticks": "" 608 | }, 609 | "colorscale": [ 610 | [ 611 | 0, 612 | "#0d0887" 613 | ], 614 | [ 615 | 0.1111111111111111, 616 | "#46039f" 617 | ], 618 | [ 619 | 0.2222222222222222, 620 | "#7201a8" 621 | ], 622 | [ 623 | 0.3333333333333333, 624 | "#9c179e" 625 | ], 626 | [ 627 | 0.4444444444444444, 628 | "#bd3786" 629 | ], 630 | [ 631 | 0.5555555555555556, 632 | "#d8576b" 633 | ], 634 | [ 635 | 0.6666666666666666, 636 | "#ed7953" 637 | ], 638 | [ 639 | 0.7777777777777778, 640 | "#fb9f3a" 641 | ], 642 | [ 643 | 0.8888888888888888, 644 | "#fdca26" 645 | ], 646 | [ 647 | 1, 648 | "#f0f921" 649 | ] 650 | ], 651 | "type": "histogram2d" 652 | } 653 | ], 654 | "histogram2dcontour": [ 655 | { 656 | "colorbar": { 657 | "outlinewidth": 0, 658 | "ticks": "" 659 | }, 660 | "colorscale": [ 661 | [ 662 | 0, 663 | "#0d0887" 664 | ], 665 | [ 666 | 0.1111111111111111, 667 | "#46039f" 668 | ], 669 | [ 670 | 0.2222222222222222, 671 | "#7201a8" 672 | ], 673 | [ 674 | 0.3333333333333333, 675 | "#9c179e" 676 | ], 677 | [ 678 | 0.4444444444444444, 679 | "#bd3786" 680 | ], 681 | [ 682 | 0.5555555555555556, 683 | "#d8576b" 684 | ], 685 | [ 686 | 0.6666666666666666, 687 | "#ed7953" 688 | ], 689 | [ 690 | 0.7777777777777778, 691 | "#fb9f3a" 692 | ], 693 | [ 694 | 0.8888888888888888, 695 | "#fdca26" 696 | ], 697 | [ 698 | 1, 699 | "#f0f921" 700 | ] 701 | ], 702 | "type": "histogram2dcontour" 703 | } 704 | ], 705 | "mesh3d": [ 706 | { 707 | "colorbar": { 708 | "outlinewidth": 0, 709 | "ticks": "" 710 | }, 711 | "type": "mesh3d" 712 | } 713 | ], 714 | "parcoords": [ 715 | { 716 | "line": { 717 | "colorbar": { 718 | "outlinewidth": 0, 719 | "ticks": "" 720 | } 721 | }, 722 | "type": "parcoords" 723 | } 724 | ], 725 | "pie": [ 726 | { 727 | "automargin": true, 728 | "type": "pie" 729 | } 730 | ], 731 | "scatter": [ 732 | { 733 | "marker": { 734 | "colorbar": { 735 | "outlinewidth": 0, 736 | "ticks": "" 737 | } 738 | }, 739 | "type": "scatter" 740 | } 741 | ], 742 | "scatter3d": [ 743 | { 744 | "line": { 745 | "colorbar": { 746 | "outlinewidth": 0, 747 | "ticks": "" 748 | } 749 | }, 750 | "marker": { 751 | "colorbar": { 752 | "outlinewidth": 0, 753 | "ticks": "" 754 | } 755 | }, 756 | "type": "scatter3d" 757 | } 758 | ], 759 | "scattercarpet": [ 760 | { 761 | "marker": { 762 | "colorbar": { 763 | "outlinewidth": 0, 764 | "ticks": "" 765 | } 766 | }, 767 | "type": "scattercarpet" 768 | } 769 | ], 770 | "scattergeo": [ 771 | { 772 | "marker": { 773 | "colorbar": { 774 | "outlinewidth": 0, 775 | "ticks": "" 776 | } 777 | }, 778 | "type": "scattergeo" 779 | } 780 | ], 781 | "scattergl": [ 782 | { 783 | "marker": { 784 | "colorbar": { 785 | "outlinewidth": 0, 786 | "ticks": "" 787 | } 788 | }, 789 | "type": "scattergl" 790 | } 791 | ], 792 | "scattermapbox": [ 793 | { 794 | "marker": { 795 | "colorbar": { 796 | "outlinewidth": 0, 797 | "ticks": "" 798 | } 799 | }, 800 | "type": "scattermapbox" 801 | } 802 | ], 803 | "scatterpolar": [ 804 | { 805 | "marker": { 806 | "colorbar": { 807 | "outlinewidth": 0, 808 | "ticks": "" 809 | } 810 | }, 811 | "type": "scatterpolar" 812 | } 813 | ], 814 | "scatterpolargl": [ 815 | { 816 | "marker": { 817 | "colorbar": { 818 | "outlinewidth": 0, 819 | "ticks": "" 820 | } 821 | }, 822 | "type": "scatterpolargl" 823 | } 824 | ], 825 | "scatterternary": [ 826 | { 827 | "marker": { 828 | "colorbar": { 829 | "outlinewidth": 0, 830 | "ticks": "" 831 | } 832 | }, 833 | "type": "scatterternary" 834 | } 835 | ], 836 | "surface": [ 837 | { 838 | "colorbar": { 839 | "outlinewidth": 0, 840 | "ticks": "" 841 | }, 842 | "colorscale": [ 843 | [ 844 | 0, 845 | "#0d0887" 846 | ], 847 | [ 848 | 0.1111111111111111, 849 | "#46039f" 850 | ], 851 | [ 852 | 0.2222222222222222, 853 | "#7201a8" 854 | ], 855 | [ 856 | 0.3333333333333333, 857 | "#9c179e" 858 | ], 859 | [ 860 | 0.4444444444444444, 861 | "#bd3786" 862 | ], 863 | [ 864 | 0.5555555555555556, 865 | "#d8576b" 866 | ], 867 | [ 868 | 0.6666666666666666, 869 | "#ed7953" 870 | ], 871 | [ 872 | 0.7777777777777778, 873 | "#fb9f3a" 874 | ], 875 | [ 876 | 0.8888888888888888, 877 | "#fdca26" 878 | ], 879 | [ 880 | 1, 881 | "#f0f921" 882 | ] 883 | ], 884 | "type": "surface" 885 | } 886 | ], 887 | "table": [ 888 | { 889 | "cells": { 890 | "fill": { 891 | "color": "#EBF0F8" 892 | }, 893 | "line": { 894 | "color": "white" 895 | } 896 | }, 897 | "header": { 898 | "fill": { 899 | "color": "#C8D4E3" 900 | }, 901 | "line": { 902 | "color": "white" 903 | } 904 | }, 905 | "type": "table" 906 | } 907 | ] 908 | }, 909 | "layout": { 910 | "annotationdefaults": { 911 | "arrowcolor": "#2a3f5f", 912 | "arrowhead": 0, 913 | "arrowwidth": 1 914 | }, 915 | "autotypenumbers": "strict", 916 | "coloraxis": { 917 | "colorbar": { 918 | "outlinewidth": 0, 919 | "ticks": "" 920 | } 921 | }, 922 | "colorscale": { 923 | "diverging": [ 924 | [ 925 | 0, 926 | "#8e0152" 927 | ], 928 | [ 929 | 0.1, 930 | "#c51b7d" 931 | ], 932 | [ 933 | 0.2, 934 | "#de77ae" 935 | ], 936 | [ 937 | 0.3, 938 | "#f1b6da" 939 | ], 940 | [ 941 | 0.4, 942 | "#fde0ef" 943 | ], 944 | [ 945 | 0.5, 946 | "#f7f7f7" 947 | ], 948 | [ 949 | 0.6, 950 | "#e6f5d0" 951 | ], 952 | [ 953 | 0.7, 954 | "#b8e186" 955 | ], 956 | [ 957 | 0.8, 958 | "#7fbc41" 959 | ], 960 | [ 961 | 0.9, 962 | "#4d9221" 963 | ], 964 | [ 965 | 1, 966 | "#276419" 967 | ] 968 | ], 969 | "sequential": [ 970 | [ 971 | 0, 972 | "#0d0887" 973 | ], 974 | [ 975 | 0.1111111111111111, 976 | "#46039f" 977 | ], 978 | [ 979 | 0.2222222222222222, 980 | "#7201a8" 981 | ], 982 | [ 983 | 0.3333333333333333, 984 | "#9c179e" 985 | ], 986 | [ 987 | 0.4444444444444444, 988 | "#bd3786" 989 | ], 990 | [ 991 | 0.5555555555555556, 992 | "#d8576b" 993 | ], 994 | [ 995 | 0.6666666666666666, 996 | "#ed7953" 997 | ], 998 | [ 999 | 0.7777777777777778, 1000 | "#fb9f3a" 1001 | ], 1002 | [ 1003 | 0.8888888888888888, 1004 | "#fdca26" 1005 | ], 1006 | [ 1007 | 1, 1008 | "#f0f921" 1009 | ] 1010 | ], 1011 | "sequentialminus": [ 1012 | [ 1013 | 0, 1014 | "#0d0887" 1015 | ], 1016 | [ 1017 | 0.1111111111111111, 1018 | "#46039f" 1019 | ], 1020 | [ 1021 | 0.2222222222222222, 1022 | "#7201a8" 1023 | ], 1024 | [ 1025 | 0.3333333333333333, 1026 | "#9c179e" 1027 | ], 1028 | [ 1029 | 0.4444444444444444, 1030 | "#bd3786" 1031 | ], 1032 | [ 1033 | 0.5555555555555556, 1034 | "#d8576b" 1035 | ], 1036 | [ 1037 | 0.6666666666666666, 1038 | "#ed7953" 1039 | ], 1040 | [ 1041 | 0.7777777777777778, 1042 | "#fb9f3a" 1043 | ], 1044 | [ 1045 | 0.8888888888888888, 1046 | "#fdca26" 1047 | ], 1048 | [ 1049 | 1, 1050 | "#f0f921" 1051 | ] 1052 | ] 1053 | }, 1054 | "colorway": [ 1055 | "#636efa", 1056 | "#EF553B", 1057 | "#00cc96", 1058 | "#ab63fa", 1059 | "#FFA15A", 1060 | "#19d3f3", 1061 | "#FF6692", 1062 | "#B6E880", 1063 | "#FF97FF", 1064 | "#FECB52" 1065 | ], 1066 | "font": { 1067 | "color": "#2a3f5f" 1068 | }, 1069 | "geo": { 1070 | "bgcolor": "white", 1071 | "lakecolor": "white", 1072 | "landcolor": "#E5ECF6", 1073 | "showlakes": true, 1074 | "showland": true, 1075 | "subunitcolor": "white" 1076 | }, 1077 | "hoverlabel": { 1078 | "align": "left" 1079 | }, 1080 | "hovermode": "closest", 1081 | "mapbox": { 1082 | "style": "light" 1083 | }, 1084 | "paper_bgcolor": "white", 1085 | "plot_bgcolor": "#E5ECF6", 1086 | "polar": { 1087 | "angularaxis": { 1088 | "gridcolor": "white", 1089 | "linecolor": "white", 1090 | "ticks": "" 1091 | }, 1092 | "bgcolor": "#E5ECF6", 1093 | "radialaxis": { 1094 | "gridcolor": "white", 1095 | "linecolor": "white", 1096 | "ticks": "" 1097 | } 1098 | }, 1099 | "scene": { 1100 | "xaxis": { 1101 | "backgroundcolor": "#E5ECF6", 1102 | "gridcolor": "white", 1103 | "gridwidth": 2, 1104 | "linecolor": "white", 1105 | "showbackground": true, 1106 | "ticks": "", 1107 | "zerolinecolor": "white" 1108 | }, 1109 | "yaxis": { 1110 | "backgroundcolor": "#E5ECF6", 1111 | "gridcolor": "white", 1112 | "gridwidth": 2, 1113 | "linecolor": "white", 1114 | "showbackground": true, 1115 | "ticks": "", 1116 | "zerolinecolor": "white" 1117 | }, 1118 | "zaxis": { 1119 | "backgroundcolor": "#E5ECF6", 1120 | "gridcolor": "white", 1121 | "gridwidth": 2, 1122 | "linecolor": "white", 1123 | "showbackground": true, 1124 | "ticks": "", 1125 | "zerolinecolor": "white" 1126 | } 1127 | }, 1128 | "shapedefaults": { 1129 | "line": { 1130 | "color": "#2a3f5f" 1131 | } 1132 | }, 1133 | "ternary": { 1134 | "aaxis": { 1135 | "gridcolor": "white", 1136 | "linecolor": "white", 1137 | "ticks": "" 1138 | }, 1139 | "baxis": { 1140 | "gridcolor": "white", 1141 | "linecolor": "white", 1142 | "ticks": "" 1143 | }, 1144 | "bgcolor": "#E5ECF6", 1145 | "caxis": { 1146 | "gridcolor": "white", 1147 | "linecolor": "white", 1148 | "ticks": "" 1149 | } 1150 | }, 1151 | "title": { 1152 | "x": 0.05 1153 | }, 1154 | "xaxis": { 1155 | "automargin": true, 1156 | "gridcolor": "white", 1157 | "linecolor": "white", 1158 | "ticks": "", 1159 | "title": { 1160 | "standoff": 15 1161 | }, 1162 | "zerolinecolor": "white", 1163 | "zerolinewidth": 2 1164 | }, 1165 | "yaxis": { 1166 | "automargin": true, 1167 | "gridcolor": "white", 1168 | "linecolor": "white", 1169 | "ticks": "", 1170 | "title": { 1171 | "standoff": 15 1172 | }, 1173 | "zerolinecolor": "white", 1174 | "zerolinewidth": 2 1175 | } 1176 | } 1177 | }, 1178 | "title": { 1179 | "text": "Einspeisung pro Monat" 1180 | }, 1181 | "xaxis": { 1182 | "title": { 1183 | "text": "Monat" 1184 | } 1185 | }, 1186 | "yaxis": { 1187 | "title": { 1188 | "text": "Einspeisung (E_AC) in kWh" 1189 | } 1190 | } 1191 | } 1192 | }, 1193 | "text/html": [ 1194 | "
" 1219 | ] 1220 | }, 1221 | "metadata": {}, 1222 | "output_type": "display_data" 1223 | } 1224 | ], 1225 | "source": [ 1226 | "# Interactive bar plot\n", 1227 | "sns.set_style('ticks')\n", 1228 | "trace_line = go.Scatter(x=df_feedin_billing.index.tolist(), \n", 1229 | " y=df_feedin_billing['Einspeisung in kWh'].tolist(), \n", 1230 | " name='Einspeisung Abrechnung', line=dict(), mode='lines')\n", 1231 | "trace_bar = go.Bar(x=df_feedin_billing.index.tolist(), \n", 1232 | " y=df_feedin_billing['Einspeisung in kWh'].tolist(), \n", 1233 | " name='Einspeisung Abrechnung', marker=dict())\n", 1234 | "layout = go.Layout(\n", 1235 | " title='Einspeisung pro Monat',\n", 1236 | " yaxis=dict(title=''.join(info_dict['Y-Axis'])),\n", 1237 | " xaxis=dict(title=''.join(info_dict['X-Axis']))\n", 1238 | ")\n", 1239 | "ifig_feedin = go.Figure(data=[trace_bar, trace_line], layout=layout)\n", 1240 | "pltly.iplot(ifig_feedin)" 1241 | ] 1242 | }, 1243 | { 1244 | "cell_type": "markdown", 1245 | "metadata": {}, 1246 | "source": [ 1247 | "## Save results to files\n", 1248 | "\n", 1249 | "The results are saved to cooresponding files in a folder named **data**.
\n", 1250 | "The **info_dict** is saved to a text file (txt).
\n", 1251 | "The **data** is saved to a table (csv).
\n", 1252 | "The **plot** is saved as an image (png).
\n", 1253 | "The **interactive plot** is saved as a webpage (html). It will also open in a new tab of your browser." 1254 | ] 1255 | }, 1256 | { 1257 | "cell_type": "code", 1258 | "execution_count": 6, 1259 | "metadata": {}, 1260 | "outputs": [ 1261 | { 1262 | "name": "stdout", 1263 | "output_type": "stream", 1264 | "text": [ 1265 | "Facts saved to file: data/2021-07-13_pv3_sonnja_results.txt\n", 1266 | "Plot saved to file: data/2021-07-13_pv3_sonnja_results_mfig_feedin.png\n", 1267 | "Plot saved to file: data/2021-07-13_pv3_sonnja_results_ifig_feedin.html\n" 1268 | ] 1269 | } 1270 | ], 1271 | "source": [ 1272 | "# Write facts to textfile\n", 1273 | "txtname = ('data/{}.txt').format(*info_dict['Filename'])\n", 1274 | "with open(txtname,'w') as tfile:\n", 1275 | " for i in info_dict.keys():\n", 1276 | " tfile.write(i + \": \" + ', '.join([str(x) for x in info_dict[i]]) + \"\\n\")\n", 1277 | "tfile.close()\n", 1278 | "print(\"Facts saved to file:\", txtname)\n", 1279 | "\n", 1280 | "# Save plot as file\n", 1281 | "plotname = 'data/{}_mfig_feedin.png' .format(*info_dict['Filename'])\n", 1282 | "mfig_feedin.savefig(plotname, bbox_inches='tight')\n", 1283 | "print(\"Plot saved to file:\", plotname)\n", 1284 | "\n", 1285 | "# Save interactive plot as file\n", 1286 | "htmlname = 'data/{}_ifig_feedin.html' .format(*info_dict['Filename'])\n", 1287 | "pltly.plot(ifig_feedin, filename=htmlname)\n", 1288 | "print(\"Plot saved to file:\", htmlname)" 1289 | ] 1290 | }, 1291 | { 1292 | "cell_type": "markdown", 1293 | "metadata": {}, 1294 | "source": [ 1295 | "## Annual yield" 1296 | ] 1297 | }, 1298 | { 1299 | "cell_type": "code", 1300 | "execution_count": 7, 1301 | "metadata": {}, 1302 | "outputs": [ 1303 | { 1304 | "name": "stdout", 1305 | "output_type": "stream", 1306 | "text": [ 1307 | "16377\n" 1308 | ] 1309 | } 1310 | ], 1311 | "source": [ 1312 | "res_feedin_billing = df_feedin_billing['Einspeisung in kWh'].sum()\n", 1313 | "print(round(res_feedin_billing,1))" 1314 | ] 1315 | }, 1316 | { 1317 | "cell_type": "code", 1318 | "execution_count": null, 1319 | "metadata": {}, 1320 | "outputs": [], 1321 | "source": [] 1322 | }, 1323 | { 1324 | "cell_type": "code", 1325 | "execution_count": null, 1326 | "metadata": {}, 1327 | "outputs": [], 1328 | "source": [] 1329 | } 1330 | ], 1331 | "metadata": { 1332 | "kernelspec": { 1333 | "display_name": "Python 3", 1334 | "language": "python", 1335 | "name": "python3" 1336 | }, 1337 | "language_info": { 1338 | "codemirror_mode": { 1339 | "name": "ipython", 1340 | "version": 3 1341 | }, 1342 | "file_extension": ".py", 1343 | "mimetype": "text/x-python", 1344 | "name": "python", 1345 | "nbconvert_exporter": "python", 1346 | "pygments_lexer": "ipython3", 1347 | "version": "3.8.10" 1348 | } 1349 | }, 1350 | "nbformat": 4, 1351 | "nbformat_minor": 2 1352 | } 1353 | -------------------------------------------------------------------------------- /pv3_tools.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | PDX-License-Identifier: AGPL-3.0-or-later 6 | """ 7 | 8 | 9 | import json 10 | import pandas as pd 11 | import pvlib as pvl 12 | import re 13 | import os 14 | 15 | from settings import setup_logger 16 | 17 | """logging""" 18 | log = setup_logger() 19 | 20 | 21 | def search_dbs(path): 22 | """interactive db search tool 23 | parameters 24 | ___________ 25 | path : 'str' 26 | relative directory to save results in as json 27 | 28 | """ 29 | DB_NAMES = ['CECInverter', 'CECMod', 'SandiaMod', 'ADRInverter'] 30 | dbs = {} 31 | for db in DB_NAMES: 32 | dbs[db] = pvl.pvsystem.retrieve_sam(db) 33 | 34 | print("enter 'str' to extend keywordlist to search dbs") 35 | print("enter '-' to clear keywordlist") 36 | print("enter 'DONE' to export results as json") 37 | print("enter 'STOP' to stop") 38 | 39 | keywordlist = [] 40 | input_key = input() 41 | while input_key not in ['SAVE', 'STOP']: 42 | for char in input_key: 43 | if not isinstance(char, str): 44 | print('no good input key! will pass empty str') 45 | input_key = '' 46 | if input_key == '-': 47 | keywordlist = [] 48 | print('Cleared keyword list') 49 | else: 50 | input_key = re.split(',| |_', input_key) 51 | if len(input_key) < 2: 52 | keywordlist.extend(input_key) 53 | else: 54 | keywordlist.extend(input_key) 55 | 56 | print('#########') 57 | print(keywordlist) 58 | 59 | results = {} 60 | for name, db in dbs.items(): 61 | temp = [col for col, specs in db.iteritems() if all(key in col for key in keywordlist)] 62 | if len(temp) >= 1: 63 | results[name] = temp 64 | 65 | for name, db in results.items(): 66 | print('---------') 67 | print(name) 68 | print('---------') 69 | print(db) 70 | input_key = input() 71 | if input_key == 'STOP': 72 | print('operation aborted') 73 | if input_key == 'SAVE': 74 | 75 | output_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), path) 76 | if not os.path.isdir(output_dir): 77 | os.makedirs(output_dir) 78 | 79 | with open(output_dir + '/db_results.json', 'w') as fp: 80 | json.dump(results, fp, sort_keys=True, indent=4) 81 | log.info('Saved results to %s'%output_dir) 82 | -------------------------------------------------------------------------------- /pv3_weatherdata.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | HTW-PV3 - Weatherdata functions 6 | 7 | 8 | 9 | SPDX-License-Identifier: AGPL-3.0-or-later 10 | """ 11 | 12 | __copyright__ = "© Ludwig Hülk" 13 | __license__ = "GNU Affero General Public License Version 3 (AGPL-3.0)" 14 | __url__ = "https://www.gnu.org/licenses/agpl-3.0.en.html" 15 | __author__ = "Ludee;" 16 | __version__ = "v0.0.2" 17 | 18 | import datetime 19 | 20 | import pandas as pd 21 | import os 22 | from datetime import timedelta 23 | from collections import OrderedDict 24 | import pvlib 25 | from pvlib import tools 26 | import numpy as np 27 | 28 | from pvlib.irradiance import clearness_index, get_extra_radiation 29 | 30 | 31 | def calculate_diffuse_irradiation(df, parameter_name, lat, lon): 32 | """ 33 | Calculate diffuse irradiation 34 | 35 | Parameters 36 | ---------- 37 | df : DataFrame 38 | Global Horizontal Irradiance (GHI) 39 | parameter_name : str 40 | Name of column with GHI 41 | lat : float 42 | Latitude 43 | lon : float 44 | Longitude 45 | Returns 46 | ------- 47 | df_irradiance : DataFrame 48 | Calculated 49 | dni: the modeled direct normal irradiance in W/m^2. 50 | dhi: the modeled diffuse horizontal irradiance in W/m^2. 51 | kt: ratio of global to extraterrestrial irradiance on a horizontal plane. 52 | """ 53 | 54 | # calculate dhi and dni for htw weatherdata 55 | df_solarpos = pvlib.solarposition.spa_python(df.index, lat, lon) 56 | 57 | # Calculate dhi and dni from parameter 58 | df_irradiance = pvlib.irradiance.erbs(ghi=df.loc[:, parameter_name], 59 | zenith=df_solarpos.zenith, 60 | datetime_or_doy=df.index.dayofyear) 61 | 62 | # Setup DataFrame 63 | df_irradiance = pd.DataFrame(df_irradiance) 64 | 65 | return df_irradiance 66 | 67 | 68 | def setup_converter_dataframe(converter, weather_data): 69 | """ 70 | Reads HTW converter data from original files for given converter and sets 71 | up a dataframe. 72 | 73 | Parameters 74 | ---------- 75 | converter : String 76 | Converter to set up the dataframe for. Possible choices are 'wr1', 77 | 'wr2', 'wr3', 'wr4' and 'wr5'. 78 | weather_data : String 79 | Weather data that is used for calculated feed-in. The HTW data 80 | is resampled depending on the weather data. Possible choices are 81 | 'open_FRED' and 'MERRA'. 82 | 83 | Returns 84 | -------- 85 | pandas.DataFrame 86 | DataFrame with time series for feed-in etc.. 87 | 88 | """ 89 | file_directory = 'data/htw_2015/einleuchtend_data_2015' 90 | data = pd.read_csv( 91 | os.path.join(file_directory, 92 | 'einleuchtend_wrdata_2015_{}.csv'.format(converter)), 93 | sep=';', header=[0], index_col=[0], parse_dates=True) 94 | # resample to same resolution as weather data 95 | if weather_data == 'open_FRED': 96 | data = data.resample('30Min', loffset=timedelta(hours=0.25)).mean() 97 | elif weather_data == 'MERRA': 98 | data = data.resample('60Min', base=30, 99 | loffset=timedelta(hours=0.5)).mean() 100 | data = data.tz_localize('Etc/GMT-1') 101 | data = data.tz_convert('Europe/Berlin') 102 | return data 103 | 104 | 105 | def setup_weather_dataframe(weather_data): 106 | """ 107 | Reads HTW weather data from original file and sets up a dataframe. 108 | 109 | Parameters 110 | ---------- 111 | weather_data : String 112 | Weather data that is used for calculated feed-in. The HTW data 113 | is resampled depending on the weather data. Possible choices are 114 | 'open_FRED' and 'MERRA'. 115 | 116 | Returns 117 | -------- 118 | pandas.DataFrame 119 | DataFrame with time series for GHI and GNI in W/m², wind speed in m/s 120 | and air temperature in °C. 121 | 122 | """ 123 | file_directory = 'data/pv3_2015' 124 | data = pd.read_csv( 125 | os.path.join(file_directory, 'htw_wetter_weatherdata_2015.csv'), 126 | sep=';', header=[0], index_col=[0], parse_dates=True) 127 | 128 | # select and rename columns 129 | columns = {'G_hor_CMP6': 'ghi', 130 | 'G_gen_CMP11': 'gni', 131 | 'v_Wind': 'wind_speed', 132 | 'T_Luft': 'temp_air'} 133 | data = data[list(columns.keys())] 134 | data.rename(columns=columns, inplace=True) 135 | # resample to same resolution as weather data 136 | if weather_data == 'open_FRED': 137 | data = data.resample('30Min', loffset=timedelta(hours=0.25)).mean() 138 | elif weather_data == 'MERRA': 139 | data = data.resample('60Min', base=30, 140 | loffset=timedelta(hours=0.5)).mean() 141 | data = data.tz_localize('Etc/GMT-1') # GMT+1?? 142 | data = data.tz_convert('Europe/Berlin') 143 | return data 144 | 145 | # def erbs (ghi, zenith,datetime_or_doy, min_cos_zenith=0.065, max_zenith=87): 146 | # dni_extra = get_extra_radiation(datetime_or_doy) 147 | 148 | # kt = clearness_index(ghi, zenith, dni_extra, min_cos_zenith=min_cos_zenith, 149 | # max_clearness_index=1) 150 | 151 | # For Kt <= 0.22, set the diffuse fraction 152 | # df = 1 - 0.09*kt 153 | 154 | # For Kt > 0.22 and Kt <= 0.8, set the diffuse fraction 155 | # df = np.where((kt > 0.22) & (kt <= 0.8), 156 | # 0.9511 - 0.1604*kt + 4.388*kt**2 - 157 | # 16.638*kt**3 + 12.336*kt**4, 158 | # df) 159 | 160 | # For Kt > 0.8, set the diffuse fraction 161 | # df = np.where(kt > 0.8, 0.165, df) 162 | 163 | # dhi = df * ghi 164 | 165 | # dni = (ghi - dhi) / tools.cosd(zenith) 166 | # bad_values = (zenith > max_zenith) | (ghi < 0) | (dni < 0) 167 | # dni = np.where(bad_values, 0, dni) 168 | # ensure that closure relationship remains valid 169 | # dhi = np.where(bad_values, ghi, dhi) 170 | 171 | # data = OrderedDict() 172 | # data['dni'] = dni 173 | # data['dhi'] = dhi 174 | # data['kt'] = kt 175 | 176 | # if isinstance(datetime_or_doy, pd.DatetimeIndex): 177 | # data = pd.DataFrame(data, index=datetime_or_doy) 178 | 179 | # return data 180 | -------------------------------------------------------------------------------- /requirements.yml: -------------------------------------------------------------------------------- 1 | name: d_py38_pv3 2 | dependencies: 3 | - python=3.8 4 | - jupyter 5 | - matplotlib 6 | - pandas 7 | - plotly 8 | - sqlalchemy 9 | - seaborn 10 | - xlrd 11 | - openpyxl 12 | - psycopg2 13 | - pip: 14 | - pvlib -------------------------------------------------------------------------------- /settings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | Service functions 6 | 7 | Configure console and file logging; 8 | Create and handle config file for database connection; 9 | 10 | SPDX-License-Identifier: AGPL-3.0-or-later 11 | """ 12 | 13 | __copyright__ = "© Ludwig Hülk" 14 | __license__ = "GNU Affero General Public License Version 3 (AGPL-3.0)" 15 | __url__ = "https://www.gnu.org/licenses/agpl-3.0.en.html" 16 | __author__ = "Ludee;" 17 | __version__ = "v0.0.2" 18 | 19 | import os 20 | import pandas as pd 21 | from sqlalchemy import * 22 | 23 | import logging 24 | 25 | log = logging.getLogger(__name__) 26 | 27 | """parameter""" 28 | log_file = 'pv3.log' 29 | 30 | HTW_LAT = 52.45544 31 | HTW_LON = 13.52481 32 | 33 | 34 | def setup_logger(): 35 | """Configure logging in console and log file. 36 | 37 | Returns 38 | ------- 39 | rl : logger 40 | Logging in console (ch) and file (fh). 41 | """ 42 | 43 | rl = logging.getLogger() 44 | rl.setLevel(logging.INFO) 45 | rl.propagate = False 46 | 47 | # set format 48 | formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s', 49 | datefmt='%Y-%m-%d %H:%M:%S') 50 | 51 | # console handler (ch) 52 | ch = logging.StreamHandler() 53 | ch.setLevel(logging.INFO) 54 | ch.setFormatter(formatter) 55 | 56 | # file handler (fh) 57 | fh = logging.FileHandler(log_file) 58 | fh.setLevel(logging.INFO) 59 | fh.setFormatter(formatter) 60 | 61 | rl.handlers = [ch, fh] 62 | 63 | return rl 64 | 65 | 66 | def postgres_session(): 67 | """SQLAlchemy session object with valid connection to local database 68 | Inputs 69 | ------- 70 | port : int 71 | Database port 72 | password : str 73 | Database password 74 | Returns 75 | ------- 76 | con : connection 77 | SQLAlchemy connection object. 78 | """ 79 | 80 | print('Please provide connection parameters to database:\n' + 81 | 'Hit [Enter] to take defaults') 82 | host = 'localhost' # input('host (default 127.0.0.1): ') 83 | port = int(input('port (default 5432): ') or 5432) # port = '5435' 84 | database = 'sonnja_db' # input("database name (default 'sonnja_db'): ") 85 | user = 'sonnja' # input('user (default postgres): ') 86 | password = input('password: ') 87 | # password = getpass.getpass(prompt='password: ', 88 | # stream=sys.stderr) 89 | con = create_engine( 90 | 'postgresql://' + '%s:%s@%s:%s/%s' % (user, 91 | password, 92 | host, 93 | port, 94 | database)).connect() 95 | print('Password correct! Database connection established.') 96 | return con 97 | 98 | 99 | def query_database(con, schema_name, table_name): 100 | sql_query = text(f""" 101 | SELECT * 102 | FROM {schema_name}.{table_name} 103 | """) 104 | df = pd.read_sql_query(sql_query, con) 105 | df = df.set_index('timestamp') 106 | print(f'Query database {schema_name}.{table_name}') 107 | return df 108 | 109 | 110 | def query_database_metadata(con, schema_name, table_name): 111 | sql_query = text( 112 | f"""SELECT obj_description('{schema_name}.{table_name}'::regclass);""") 113 | meta_str = pd.read_sql_query(sql_query, con).loc[0, 'obj_description'] 114 | 115 | return meta_str 116 | 117 | 118 | def read_from_csv(file_name, sep=';'): 119 | df = pd.read_csv(file_name, encoding='latin1', sep=sep, index_col=0, 120 | parse_dates=True) # , skiprows=3) 121 | 122 | return df 123 | 124 | 125 | def write_to_csv(csv_name, df, append=True, index=True, sep=';'): 126 | """Create CSV file or append data to it. 127 | 128 | Parameters 129 | ---------- 130 | csv_name : str 131 | Name of file. 132 | df : DataFrame 133 | Sata saved to file. 134 | append : bool 135 | If False create a new CSV file (default), else append to it. 136 | index : bool 137 | If False do not write index into CSV file 138 | sep : str 139 | seperator to be used while writing csv. Semicolon ';' is standard 140 | """ 141 | # if os.path.exists(os.path.dirname(csv_name)): 142 | # os.remove(os.path.dirname(csv_name)) 143 | 144 | if append: 145 | mode = 'a' 146 | else: 147 | mode = 'w' 148 | 149 | if not os.path.exists(os.path.dirname(csv_name)): 150 | os.makedirs(os.path.dirname(csv_name)) 151 | 152 | with open(csv_name, mode=mode, encoding='utf-8') as file: 153 | df.to_csv(file, sep=sep, 154 | mode=mode, 155 | header=file.tell() == 0, 156 | line_terminator='\n', 157 | encoding='utf-8', 158 | index=index 159 | ) 160 | 161 | log.info(f'Write data to file: {csv_name} with append-mode={append}') 162 | --------------------------------------------------------------------------------