Skip to content

Commit

Permalink
Hybrids documentation (#165)
Browse files Browse the repository at this point in the history
* add tests for updated PySSC

* add hybrids

* update hybrids and add tests

* remove set_data_ptr

* update ctypes and PySSC

* add yml for github actions CI

* update yml

* update yml

* update yml

* update yml

* update yml

* update yml

* update yml

* update yml

* remove hybrid_sandbox

* add docs for Hybrids

* fix assign function

* clear data before execute

* Initial doc revisions for PySAM hybrids

* Fix PySAM hybrids test for assign() fix to return all unassigned vars

* Doc revisions for PySAM hybrids

* Revise code examples for hybrids
* Fix broken TOC link to PySSC topic
* Add recommendation to use PySAM instead of PySSC

* Update hybrids.rst

---------

Co-authored-by: Paul Gilman <[email protected]>
  • Loading branch information
dguittet and cpaulgilman authored Apr 19, 2024
1 parent b33aa37 commit bd2d506
Show file tree
Hide file tree
Showing 25 changed files with 1,361 additions and 39 deletions.
3 changes: 3 additions & 0 deletions docs/PySSC.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ Working Directly with PySSC

PySSC is a wrapper for the `SAM Simulation Core (SSC) API <https://github.com/NREL/ssc/blob/develop/ssc/sscapi.h>`_ PySSC is part of the `SAM Software Development Kit (SDK) <https://sam.nrel.gov/sdk>`_. The PySAM package is built on PySSC.

.. note::
PySSC was the original method for running SSC from Python before PySAM was developed. Unless you are very familiar with SSC, we recommend using PySAM instead of PySSC because PySAM provides tools for creating models and accessing variables that are not available with PySSC.

The `SSC Guide <https://sam.nrel.gov/images/web_page_files/ssc_guide.pdf>`_ is a reference to SSC.

To use PySSC, import it with:
Expand Down
7 changes: 7 additions & 0 deletions docs/_static/custom.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
Fix for horizontal stacking weirdness in the RTD theme with Python properties:
https://github.com/readthedocs/sphinx_rtd_theme/issues/1301
*/
.py.property {
display: block !important;
}
4 changes: 4 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,7 @@
}

html_sidebars = { '**': [ 'about.html', 'navigation.html', 'searchbox.html' ]}

html_static_path = ['_static']

html_css_files = ["custom.css"]
225 changes: 225 additions & 0 deletions docs/hybrids.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
Hybrid Systems
==============

Use the :mod:`PySAM.Hybrids.HybridGenerator` and :mod:`PySAM.Hybrids.HybridSystem` classes for hybrid system models. These classes provide functions for creating
models with default input values or from JSON, accessing variables, and running simulations.

:mod:`HybridGenerator<PySAM.Hybrids.HybridGenerator>` is the base class for performance model modules that are available for Hybrid systems. It wraps the PySAM
module for each subsystem module and provides access to the module input and output variables.

:mod:`HybridSystem<PySAM.Hybrids.HybridSystem>` contains and organizes the performance and financial model modules and runs simulations. The simulation is executed
by :mod:`PySAM.Hybrid.Hybrid`.

.. toctree::
:maxdepth: 1

hybrids/HybridGenerator.rst
hybrids/HybridSystem.rst

Available modules
-----------------

The following modules are available for hybrid systems::

HybridSystem.pv = PVHybrid (PySAM.Pvsamv1)
HybridSystem.pvwatts = PVWattsHybrid (PySAM.Pvwattsv8)
HybridSystem.wind = WindHybrid (PySAM.Windpower)
HybridSystem.gensys = GenericSystemHybrid (PySAM.GenericSystem)
HybridSystem.battery = BatteryHybrid (PySAM.Battery)
HybridSystem.fuelcell = FuelCellHybrid (PySAM.Fuelcell)

.. note::
Be careful to use module names like `pv`, `pvwatts`, and `wind` as defined by `HybridSystem` instead of the PySAM module names like `Pvsamv1`, `Pvwattsv8`, and `Windpower`.

.. toctree::
:maxdepth: 1

hybrids/BatteryHybrid.rst
hybrids/FuelCellHybrid.rst
hybrids/GenericSystemHybrid.rst
hybrids/PVHybrid.rst
hybrids/PVWattsHybrid.rst
hybrids/WindHybrid.rst

The `Singleowner` and `HostDeveloper` financial models are available for hybrid configurations, along with the intermediate `Grid` and `Utilityrate5` modules::

HybridSystem._grid = PySAM.Grid
HybridSystem.singleowner = PySAM.Singleowner
HybridSystem.utilityrate5 = PySAM.Utilityrate5
HybridSystem.host_developer = PySAM.HostDeveloper

Accessing and setting variables
--------------------------------

Each hybrid subsystem class contains a PySAM module. Access the subsystem module inputs and outputs from the class. The following example shows different
methods to access inputs and output variables for a PVWatts Wind Battery / Single Owner hybrid system model.

.. code:: python
# import the module for each performance model
import PySAM.Battery as battery_model
import PySAM.Windpower as wind_model
import PySAM.Pvwattsv8 as pv_model
# import the hybrid system class
from PySAM.Hybrids.HybridSystem import HybridSystem
# Create the hybrid system model
m = HybridSystem([pv_model, wind_model, battery_model], 'singleowner')
# load input values from defaults for the
# PVWatts Wind Battery / Single Owner configuration
# default configuration is for a 100 MW PV system with 80 2.5 MW turbines
m.default('PVWattsWindBatteryHybridSingleOwner')
# assign values to solar and wind resource files (these are not loaded with defaults)
solar_resource_path = '/path-to-weather-file/your-solar-weather-file-goes-here.csv'
wind_resource_path = '/path-to-weather-file/your-wind-weather-file-goes-here.csv'
m.pvwatts.SolarResource.solar_resource_file = str(solar_resource_path)
m.wind.Resource.wind_resource_filename = str(wind_resource_path)
# Method 1: set variable values directly for a 8 MW PV system with four 2.5 MW turbines
# Note the module names "pvwatts" and "wind" as defined by the HybridSystem class,
# instead of PySAM module names "Pvwattsv8" and "Windpower".
m.pvwatts.SystemDesign.system_capacity = 8000
m.wind.Farm.wind_farm_xCoordinates = [0, 800, 1600, 2400]
m.wind.Farm.wind_farm_yCoordinates = [0, 0, 0, 0]
m.wind.Farm.system_capacity = 10000
# run a simulation
m.execute()
# print some outputs
print(m.pvwatts.Outputs.ac_annual)
print(m.wind.Outputs.annual_energy)
# Method 2: Use `value()` for a 4 MW PV system with two 2.5 MW turbines
m.pvwatts.value("system_capacity", 4000)
m.wind.value("wind_farm_xCoordinates", [0, 800])
m.wind.value("wind_farm_yCoordinates", [0, 0])
m.wind.value("system_capacity", 5000)
m.execute()
print(m.pvwatts.value("ac_annual"))
print(m.wind.value("annual_energy"))
# Method 3: Use `assign()` for a 6 MW PV system with three 2.5 MW turbines
inputs_dict = {
"pvwatts": {"SystemDesign": {"system_capacity": 6000} },
"wind": {"Farm": {"wind_farm_xCoordinates": [0, 800, 1600]} },
"wind": {"Farm": {"wind_farm_yCoordinates": [0, 0, 0]} },
"wind": {"Farm": {"system_capacity": 7500} }
}
m.assign(inputs_dict)
m.execute()
print(m.pvwatts.value("ac_annual"))
print(m.wind.value("annual_energy"))
Creating models
----------------

Create a hybrid system model by either first creating it in SAM and using the code generator to export inputs as JSON, or by loading defaults for the hybrid configuration
you want to model.

Example 1: Create a PVWatts Wind Battery / Single Owner hybrid model from SAM
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Before running the following code, create a hybrid system model in SAM, and use the :ref:`SAM Code Generator <sam_code_generator>` to export inputs from SAM to
a JSON file using the **JSON for inputs** option. (Do *not* use the **PySAM JSON** option.)

.. code:: python
import json
import PySAM.Pvwattsv8 as pv_model
import PySAM.Windpower as wind_model
import PySAM.Battery as battery_model
from PySAM.Hybrids.HybridSystem import HybridSystem
# JSON is from SAM code generator for a PVWatts Wind Battery / Host Developer case
inputs_file = /path-to-json-file/your-json-from-sam-code-generator.json'
with open(inputs_file, 'r') as f:
inputs = json.load(f)['input']
# create the hybrid system model using performance model names as defined by the import statements above
# use the string 'hostdeveloper' or 'singleowner' for the financial model
m = HybridSystem([pv_model, wind_model, battery_model], 'hostdeveloper')
m.new()
unassigned = m.assign(inputs) # returns a list of unassigned variables if any
print(unassigned)
# run a simulation
m.execute()
# store some outputs
# be careful to use the correct module names as defined by the HybridSystem() function:
# pv, pvwatts, wind, gensys, battery, fuelcell
# _grid, singleowner, utilityrate5, host_developer
pvannualenergy = m.pvwatts.Outputs.annual_energy
windannualenergy = m.wind.Outputs.annual_energy
battrountripefficiency = m.battery.Outputs.average_battery_roundtrip_efficiency
gridannualenergy = m._grid.SystemOutput.annual_energy
npv = m.host_developer.Outputs.npv
# print outputs
print(pvannualenergy)
print(windannualenergy)
print(battrountripefficiency)
print(gridannualenergy)
print(npv)
Example 2: Create a Photovoltaic Wind Batterty / Single Owner hybrid model from defaults
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Names of configurations available for hybrid systems are listed in the documentation for :mod:`default<PySAM.Hybrids.HybridSystem.HybridSystem.default>`

.. code:: python
# get performance model for each subsystem
import PySAM.Pvsamv1 as pv_model
import PySAM.Windpower as wind_model
import PySAM.Battery as battery_model
# get function for managing hybrid variables and simulations
from PySAM.Hybrids.HybridSystem import HybridSystem
# create the hybrid system model using performance model names as defined by the import statements above
# use the string 'hostdeveloper' or 'singleowner' for the financial model
m = HybridSystem([pv_model, wind_model, battery_model], 'singleowner')
# load defaults for the Photovoltaid Wind Battery Hybrid / Single Owner configuration
m.default('PhotovoltaicWindBatteryHybridSingleOwner')
# assign values to solar and wind resource files (these are not loaded with defaults)
solar_resource_path = '/path-to-weather-file/your-solar-weather-file-goes-here.csv'
wind_resource_path = '/path-to-weather-file/your-wind-weather-file-goes-here.csv'
m.pv.SolarResource.solar_resource_file = solar_resource_path
m.wind.Resource.wind_resource_filename = wind_resource_path
# run a simulation
print('running...')
m.execute()
# store some outputs
# be careful to use the correct module names as defined by the HybridSystem() function:
# pv, pvwatts, wind, gensys, battery, fuelcell
# _grid, singleowner, utilityrate5, host_developer
pvannualenergy = m.pv.Outputs.annual_energy
windannualenergy = m.wind.Outputs.annual_energy
battrountripefficiency = m.battery.Outputs.average_battery_roundtrip_efficiency
gridannualenergy = m._grid.SystemOutput.annual_energy
npv = m.singleowner.Outputs.project_return_aftertax_npv
# print outputs
print(pvannualenergy)
print(windannualenergy)
print(battrountripefficiency)
print(gridannualenergy)
print(npv)
Loading

0 comments on commit bd2d506

Please sign in to comment.