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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules/
dist/
docs/
*/jats/*
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@

`simshady` is a package for shading simulation and PV yield estimation based on 3D meshes. It runs on the GPU using WebGL. See it in action at [openpv.de](https://openpv.de).

## When to use `simshady`

You want to

- build an application for solar (photovoltaic) yield estimation. These estimations tell you how much electricity a solar panel can produce at a specific location. Since this is influenced a lot by the shadows of surrounding buildings and trees, you want to have a shading simulation. Use `simshady`.
- use 3D data of buildings, terrain, or trees to calculate shading. You have this data in formats that can be converted to `three.js`-Meshes, like `.obj`, `.stl`, or `.citygml`. Use `simshady`.

## Installation

To install the package, run
Expand Down Expand Up @@ -53,7 +60,7 @@ We publish our documentation at https://open-pv.github.io/simshady/. Additionall

## Contributing

You are welcome to contribute to this project, either by adding code or creating Issues. As a first step, you might check out our [contributing guidelines](https://github.com/open-pv/simshady/blob/main/CONTRIBUTING.md).
You are welcome to contribute to this project, either by adding code or creating Issues. For major changes, please open an issue first to discuss what you would like to change. As a first step, you might check out our [contributing guidelines](https://github.com/open-pv/simshady/blob/main/CONTRIBUTING.md).

## Sponsors

Expand Down
Binary file added documents/assets/Gorski2024_Healpix.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed documents/assets/Gorski2024_Healpix.png
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 27 additions & 8 deletions documents/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ title: Getting Started

# Getting Started

> 💡 A minimal example App using 'simshady' can be found [here](https://github.com/open-pv/minimalApp).

## Installation

Install the package using your preferred package manager:
Expand All @@ -14,35 +16,50 @@ npm install @openpv/simshady

## Basic Usage

1. **Initialize the Scene**
### **1. Initialize the Scene**

Begin by creating a new [`ShadingScene`](/simshady/classes/index.ShadingScene.html) instance:
Begin by creating a new [`ShadingScene`](/simshady/classes/index.ShadingScene.html) object:

```javascript
import ShadingScene from '@openpv/simshady';

const scene = new ShadingScene();
```

2. **Add Geometries**
<br/>
<br/>

### **2. Add Geometries**

Add one or more simulation geometries—such as buildings or PV panels—using [`addSimulationGeometry`](/simshady/classes/index.ShadingScene.html#addsimulationgeometry).
Add shading geometries using [`addShadingGeometry`](/simshady/classes/index.ShadingScene.html#addshadinggeometry):
Add one or more simulation geometries — such as buildings or PV panels — using [`addSimulationGeometry`](/simshady/classes/index.ShadingScene.html#addsimulationgeometry). Add shading geometries using [`addShadingGeometry`](/simshady/classes/index.ShadingScene.html#addshadinggeometry):

```javascript
scene.addShadingGeometry(someShadingGeometry);
scene.addSimulationGeometry(someSimulationGeometry);
```

3. **Add Solar Irradiance Data**
In _Figure 1_, the difference between the two types of geometries is shown. The simulation geometry, represented by the colored building, is the main focus where PV yield is calculated. The shading geometries, shown in grey-brown, are included in the simulation to account for shading effects due to their close proximity.

![Screenshot from openpv.de showing simulation and shading geometries](assets/screenshot-simulation-geometry.jpg)

_Figure 1: Screenshot from openpv.de showing both simulation geometries (colored) and shading geometries (grey-brown)._

These geometries need to [Three.js Buffer Geometries](https://threejs.org/docs/#api/en/core/BufferGeometry). You can use a variety of [Three.js Loaders](https://threejs.org/manual/#en/loading-3d-models) to load different 3D file formats to BufferGeometries.
<br/>
<br/>

### **3. Add Solar Irradiance Data**

Include irradiance data in the [required format](/simshady/types/utils.SolarIrradianceData.html) via [`addSolarIrradiance`](/simshady/classes/index.ShadingScene.html#addsolarirradiance). This data should contain time series for both direct and diffuse irradiance:

```javascript
scene.addSolarIrradiance(someSolarIrradianceData);
```

4. **Run the Simulation**
<br/>
<br/>

### **4. Run the Simulation**

Call the [`calculate`](/simshady/classes/index.ShadingScene.html#calculate) method to perform the simulation. It returns a [Three.js Mesh](https://threejs.org/docs/#api/en/objects/Mesh), which can be used directly in a Three.js scene:

Expand All @@ -54,4 +71,6 @@ let mesh = await scene.calculate({
showThreeJS(mesh);
```

> 💡 You can see a real-world usage example at [openpv.de](https://openpv.de).
<br/>
<br/>
> 💡 You can see simshady in action at [openpv.de](https://openpv.de).
2 changes: 1 addition & 1 deletion documents/how_does_simshady_work.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ PV system output is heavily influenced by shading from nearby objects—such as

Simshady uses time-series data of Global Horizontal Irradiance (GHI) and Direct Normal Irradiance (DNI) from [NREL](https://nsrdb.nrel.gov/) for locations in Germany. These datasets do not include directional irradiance information, so Simshady reconstructs it using the [HEALPix](https://doi.org/10.1086/427976) framework, which divides the sky dome into 96 equal-area segments.

![HEALPix sky segmentation](./assets/Gorski2024_Healpix.png)
![HEALPix sky segmentation](./assets/Gorski2024_Healpix.jpg)

_Figure 1: Sky discretization using HEALPix, from Gorski et al._

Expand Down
93 changes: 93 additions & 0 deletions joss-paper/paper.bib
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
@misc{IEA2023,
author = {{International Energy Agency}},
title = {Tripling renewable power capacity by 2030 is vital to keep the 1.5°C goal within reach},
year = {2023},
howpublished = {\url{https://www.iea.org/commentaries/tripling-renewable-power-capacity-by-2030-is-vital-to-keep-the-150c-goal-within-reach}},
note = {IEA, Paris. Licence: CC BY 4.0}
}
@article{anderson2023pvlib,
title={pvlib python: 2023 project update},
author={Anderson, Kevin S and Hansen, Clifford W and Holmgren, William F and Jensen, Adam R and Mikofski, Mark A and Driesse, Anton},
journal={Journal of Open Source Software},
volume={8},
number={92},
pages={5994},
year={2023},
doi={10.21105/joss.05994}
}
@inproceedings{holmgren2018review,
title={Review of open source tools for PV modeling},
author={Holmgren, William F and Hansen, Clifford W and Stein, Joshua S and Mikofski, Mark A},
booktitle={2018 IEEE 7th World Conference on Photovoltaic Energy Conversion (WCPEC)(A Joint Conference of 45th IEEE PVSC, 28th PVSEC \& 34th EU PVSEC)},
pages={2557--2560},
year={2018},
organization={IEEE},
doi={10.1109/PVSC.2018.8548231}
}
@article{psomopoulos2015comparative,
title={A comparative evaluation of photovoltaic electricity production assessment software (PVGIS, PVWatts and RETScreen)},
author={Psomopoulos, Constantinos S and Ioannidis, George Ch and Kaminaris, Stavros D and Mardikis, Kostas D and Katsikas, Nikolaos G},
journal={Environmental Processes},
volume={2},
pages={175--189},
year={2015},
publisher={Springer},
doi={10.1007/s40710-015-0092-4}
}
@article{jakica2018state,
title={State-of-the-art review of solar design tools and methods for assessing daylighting and solar potential for building-integrated photovoltaics},
author={Jakica, Nebojsa},
journal={Renewable and Sustainable Energy Reviews},
volume={81},
pages={1296--1328},
year={2018},
publisher={Elsevier},
doi={10.1016/j.rser.2017.05.080}
}
@misc{pvfactors2025,
title = {pvfactors: Open-source view-factor model for diffuse shading and bifacial PV modeling},
year = {2022},
month = {February},
version = {1.5.2},
url = {https://github.com/SunPower/pvfactors},
note = {Accessed: 2025-05-28}
}
@inproceedings{anoma_view_2017,
location = {Washington, {DC}, {USA}},
title = {View Factor Model and Validation for Bifacial {PV} and Diffuse Shade on Single-Axis Trackers},
rights = {https://doi.org/10.15223/policy-029},
isbn = {978-1-5090-5605-7},
url = {https://ieeexplore.ieee.org/document/8366704/},
doi = {10.1109/PVSC.2017.8366704},
eventtitle = {2017 {IEEE} 44th Photovoltaic Specialists Conference ({PVSC})},
pages = {1549--1554},
booktitle = {2017 {IEEE} 44th Photovoltaic Specialist Conference ({PVSC})},
publisher = {{IEEE}},
author = {Anoma, Marc Abou and Jacob, David and Bourne, Ben C. and Scholl, Jonathan A. and Riley, Daniel M. and Hansen, Clifford W.},
urldate = {2025-05-27},
date = {2017-06},
}
@article{zonca2019healpy,
title={healpy: equal area pixelization and spherical harmonics transforms for data on the sphere in Python},
author={Zonca, Andrea and Singer, Leo and Lenz, Daniel and Reinecke, Martin and Rosset, Cyrille and Hivon, Eric and Gorski, Krzysztof},
journal={Journal of Open Source Software},
volume={4},
number={35},
pages={1298},
year={2019},
doi = {10.21105/joss.01298}
}
@article{Górski_2005,
doi = {10.1086/427976},
url = {https://dx.doi.org/10.1086/427976},
year = {2005},
month = {apr},
publisher = {},
volume = {622},
number = {2},
pages = {759},
author = {Górski, K. M. and Hivon, E. and Banday, A. J. and Wandelt, B. D. and Hansen, F. K. and Reinecke, M. and Bartelmann, M.},
title = {HEALPix: A Framework for High-Resolution Discretization and Fast Analysis of Data Distributed on the Sphere},
journal = {The Astrophysical Journal},
abstract = {HEALPix—the Hierarchical Equal Area isoLatitude Pixelization—is a versatile structure for the pixelization of data on the sphere. An associated library of computational algorithms and visualization software supports fast scientific applications executable directly on discretized spherical maps generated from very large volumes of astronomical data. Originally developed to address the data processing and analysis needs of the present generation of cosmic microwave background experiments (e.g., BOOMERANG, WMAP), HEALPix can be expanded to meet many of the profound challenges that will arise in confrontation with the observational output of future missions and experiments, including, e.g., Planck, Herschel, SAFIR, and the Beyond Einstein inflation probe. In this paper we consider the requirements and implementation constraints on a framework that simultaneously enables an efficient discretization with associated hierarchical indexation and fast analysis/synthesis of functions defined on the sphere. We demonstrate how these are explicitly satisfied by HEALPix.}
}
73 changes: 73 additions & 0 deletions joss-paper/paper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
---
title: 'openpv/simshady: A Javascript Package for Photovoltaic Yield Estimation Based on 3D Meshes'
tags:
- TypeScript
- JavaScript
- energy
- solar
- photovoltaic
- energy system
authors:
- name: Florian Kotthoff
orcid: 0000-0003-3666-6122
corresponding: true
affiliation: '1,2' # (Multiple affiliations must be quoted)
- name: Konrad Heidler
orcid: 0000-0001-8226-0727
corresponding: false
affiliation: 1 # (Multiple affiliations must be quoted)
- name: Martin Großhauser
orcid: 0000-0003-2637-3828
corresponding: false
affiliation: 1 # (Multiple affiliations must be quoted)
- name: Korbinian Pöppel
orcid: 0009-0002-4734-1040
corresponding: false
affiliation: 1 # (Multiple affiliations must be quoted)
affiliations:
- name: OpenPV GbR, ADRESS
index: 1
- name: OFFIS Institute for Information Technology, Escherweg 2, 26121 Oldenburg, Germany
index: 2

date: 01 November 2024
bibliography: paper.bib
#This paper compiles with the following command: docker run --rm --volume .:/data --user $(id -u):$(id -g) --env JOURNAL=joss openjournals/inara
---

# Summary

openpv/simshady is a JavaScript package for simulating photovoltaic (PV) energy yields. It integrates local climate data and 3D objects into its shading simulation, utilizing Three.js meshes for geometric modeling. The package performs shading analysis using a WebGL-parallelized implementation of the Möller-Trumbore intersection algorithm, producing color-coded Three.js meshes that represent the expected PV yield.

# Statement of need

To meet global climate targets, solar photovoltaic (PV) capacity must expand significantly. Tripling renewable energy capacity by 2030 is essential to limit global warming to 1.5°C [@IEA2023]. The expansion of PV plays a crucial role, and PV systems offer an additional benefit: small-scale house-mounted PV systems enable public participation and legitimize the energy transition.

For calculating the yield of PV systems, various factors are important, including the location of the planned installation, local climate, surrounding objects such as houses or trees, and terrain. To provide accurate estimates of expected yields, simulation tools are essential in both research and practical PV system planning.

For these reasons, a variety of software tools for simulating photovoltaic systems already exist [@holmgren2018review; @jakica2018state]. One widely used software is the Python package pvlib [@anderson2023pvlib], which offers a range of functionalities. However, the rather niche topic of shading simulation with 3D objects is not included in this package. Another Python-based software that enables irradiance modeling in two dimensions is pvfactors [@pvfactors2025; @anoma_view_2017].

Web-based tools for solar panel simulations, such as PVGIS, PVWatts, and RETScreen, provide an accessible means for non-technical individuals to estimate energy yields based on geographic location and building geometry [@psomopoulos2015comparative]. However, these tools lack the capability to perform shading simulations using 3D geometries.

# Package description

`openpv/simshady` simulates the yield of photovoltaic (PV) systems by considering weather/climate data and shading from local 3D geometry. The model represents the environment through a 3D scene setup, comprising primary objects for simulation (e.g., PV panels or target buildings) and surrounding objects that may cast shadows (e.g., neighboring buildings, trees). Weather and climate data are integrated using Global Horizontal Irradiance (GHI) and Direct Normal Irradiance (DNI) datasets, which are reconstructed to include directional irradiance information using the HEALPix framework [@Górski_2005; @zonca2019healpy].

The simulation utilizes the Möller-Trumbore intersection algorithm to determine if any shading objects obstruct the view between a sky pixel and the main simulation geometry. For each triangle in the simulation geometry, a shading mask is generated, indicating whether an object blocks the line of sight from the sky pixel to the triangle. The shading mask values range from 0 to 1, where 0 indicates that an object shades the triangle, 1 signifies that there is no obstruction and the line of sight is perpendicular to the triangle, and values between 0 and 1 represent cases where there is no obstruction but the angle of incidence is not perpendicular. The aggregated radiance values from all sky dome pixels are then multiplied by the corresponding shading mask values and summed to calculate the total energy received by each triangle. This computation is fully parallelizable and has been implemented using WebGL, allowing for GPU acceleration.

# Conclusion

The `openpv/simshady` package serves two primary purposes: it provides a solution for scientific calculations of PV yield, while also facilitating science communication through interactive and user-friendly simulations that can be run directly within a web browser. This eliminates the need for specialized software or programming knowledge, making it accessible to a broader range of users. Furthermore, by implementing the main algorithm in WebGL, the package achieves higher performance than a pure Javascript implementation, and it offers a JavaScript wrapper around PV simulation in WebGL. This is particularly beneficial because WebGL is a language that is not widely known among scientists, and thus can be challenging for them to implement their own code, making the `openpv/simshady` package a valuable tool for simplifying this process.

# CRediT Authorship Statement

FK: Conceptualization, Software, Funding acquisition, Writing – original draft
MG: Conceptualization, Software, Funding acquisition, Writing – review & editing
KH: Conceptualization, Software, Funding acquisition, Writing – review & editing
KP: Conceptualization, Software, Funding acquisition, Writing – review & editing

# Acknowledgements

The authors acknowledge support by ... (how do we name Prototypefund here?)

# References
Binary file added joss-paper/paper.pdf
Binary file not shown.
6 changes: 6 additions & 0 deletions src/colormaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Color, ColorMap } from './utils';

/**
* The viridis color Map, as defined in https://observablehq.com/@flimsyhat/webgl-color-maps
* Use colormaps in the {@link ShadingScene.addColorMap} method to define the colors of the returned
* Three.js geometry.
* @param t parameter in [0,1] to go through viridis color map
* @returns
*/
Expand All @@ -23,6 +25,8 @@ export function viridis(t: number): Color {

/**
* Creates a color map function that interpolates between two colors.
* Use colormaps in the {@link ShadingScene.addColorMap} method to define the colors of the returned
* Three.js geometry.
* @param {Object} colors - The input colors.
* @param {Color} colors.c0 - The starting color.
* @param {Color} colors.c1 - The ending color.
Expand All @@ -46,6 +50,8 @@ export function interpolateTwoColors(colors: { c0: Color; c1: Color }): ColorMap

/**
* Creates a color map function that interpolates between three colors using quadratic interpolation.
* Use colormaps in the {@link ShadingScene.addColorMap} method to define the colors of the returned
* Three.js geometry.
* @param {Object} colors - The input colors.
* @param {Color} colors.c0 - The first color.
* @param {Color} colors.c1 - The second color.
Expand Down
10 changes: 5 additions & 5 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import { rayTracingWebGL } from './rayTracingWebGL.js';
/**
* This class holds all information about the scene that is simulated.
* A ShadingScene is typically equipped with the following attributes:
* * Simulation geometry, where the PV potential is calculated
* * Simulation geometry, where the PV potential is calculated.
* * Shading geometry, where no PV potential is calculated but which are
* responsible for shading
* responsible for shading.
* * Solar Irradiance Data that contains information about incoming irradiance
* in the format of sky domes
* in the format of sky domes.
* The Usage of this class and its methods is explained in the "Getting Started" Section
* of this site.
*/
Expand Down Expand Up @@ -64,7 +64,7 @@ export class ShadingScene {
* This geometry will also be used as a shading geometry, hence
* it is not needed to additionally add it by using `addShadingGeometry`.
*
* @param geometry Flat Buffer Array of a Three.js geometry, where three
* @param geometry [BufferGeometry](https://threejs.org/docs/#api/en/core/BufferGeometry) of a Three.js geometry, where three
* consecutive numbers of the array represent one 3D point and nine consecutive
* numbers represent one triangle.
*/
Expand All @@ -86,7 +86,7 @@ export class ShadingScene {
* Adds a geometry as an outer geometry for the shading simulation.
* These geometries are responsible for shading.
*
* @param geometry Flat Buffer Array of a Three.js geometry, where three
* @param geometry [BufferGeometry](https://threejs.org/docs/#api/en/core/BufferGeometry) of a Three.js geometry, where three
* consecutive numbers of the array represent one 3D point and nine consecutive
* numbers represent one triangle.
*/
Expand Down
Loading