Contributing#
We welcome contributions to PVDeg! Whether you’re fixing bugs, adding features, improving documentation, or contributing to our material property databases, your help is valuable to the PV community.
For a quick overview, see CONTRIBUTING.md on GitHub.
This guide provides comprehensive details for contributors.
Easy Ways to Contribute#
Here are ways to contribute, even if you’re new to PVDeg, git, or Python:
Report bugs or request features via GitHub issues
Join discussions on existing issues and pull requests
Improve documentation - fix typos, clarify explanations, add examples
Enhance unit tests - increase coverage or improve test quality
Create or improve tutorials - demonstrate PVDeg in your area of expertise
Contribute to material databases - add validated degradation parameters and properties
Share your work - add your project to our wiki
Spread the word - tell colleagues about PVDeg
Getting Started#
Development Environment Setup#
Fork and clone the repository:
git clone https://github.com/YOUR-USERNAME/PVDegradationTools.git cd PVDegradationTools
Create a virtual environment:
Using venv:
python -m venv pvdeg-dev source pvdeg-dev/bin/activate # Windows: pvdeg-dev\\Scripts\\activate
Or using conda:
conda create -n pvdeg-dev python=3.11 conda activate pvdeg-dev
Install in editable mode with all dependencies:
pip install -e .[all]
Install pre-commit hooks:
pre-commit installPre-commit hooks automatically enforce code quality standards before each commit.
(Optional but required for HPC) Register Jupyter kernel:
python -m ipykernel install --user --name=pvdeg-dev
This is especially important when working on HPC systems like NREL’s Kestrel.
Pre-commit Hooks#
We use pre-commit hooks to maintain code quality and consistency.
What the Hooks Do#
Our .pre-commit-config.yaml configuration runs:
black - Python code formatter (line length: 88 characters)
flake8 - Python linter for style guide enforcement
jupytext - Syncs Jupyter notebooks with Python scripts for version control
trailing-whitespace - Removes trailing whitespace
end-of-file-fixer - Ensures files end with newline
check-yaml - Validates YAML syntax
check-added-large-files - Prevents committing large files
Running Pre-commit Manually#
Run all hooks on all files:
pre-commit run --all-files
Run hooks on specific files:
pre-commit run --files path/to/file.py
Skip hooks for a specific commit (use sparingly):
git commit --no-verify -m "commit message"
Jupytext Synchronization#
Notebooks in tutorials/ are automatically synced with Python scripts in scripts/ folders.
When you edit a notebook:
Pre-commit hook creates/updates a
.pyscript versionBoth files are staged for commit
Version control works well with notebooks (diffs show code changes, not JSON)
Manual sync:
jupytext --sync tutorials/**/*.ipynb
Code Contributions#
Code Style#
We follow standard Python conventions:
PEP 8 style guide with 88 character line length (black default)
Google-style docstrings for functions and classes (numpydoc format)
Type hints encouraged for function signatures
Descriptive variable names (avoid single letters except in loops)
Code must be compatible with Python 3.10 and above
Remove
printstatements andloggingcalls before committing (warningis acceptable)Set your editor to strip trailing whitespace
Variable naming: PVDeg uses a mix of full and abbreviated names. Prefer full names for new contributions, especially in the API. Abbreviations can be used within functions to improve readability of formulae.
Example docstring:
def calculate_degradation(temp, humidity, irradiance):
"""
Calculate degradation rate based on environmental conditions.
Parameters
----------
temp : float or array-like
Temperature in degrees Celsius.
humidity : float or array-like
Relative humidity as percentage (0-100).
irradiance : float or array-like
Irradiance in W/m².
Returns
-------
float or array-like
Degradation rate in %/year.
Notes
-----
Based on the Arrhenius equation with humidity acceleration factor.
See [1]_ for detailed methodology.
References
----------
.. [1] Author et al. (2020). "Title." Journal. DOI.
"""
pass
Generic type descriptors used in PVDeg documentation:
dict-like: dict, OrderedDict, pd.Series
numeric: scalar, np.array, pd.Series (typically int or float dtype)
array-like: np.array, pd.Series (typically int or float dtype)
Parameters that specify a specific type require that exact input type.
Testing#
All code contributions should include unit tests.
Running the test suite:
pytest tests/
Run tests with coverage report:
pytest --cov=pvdeg --cov-report=html tests/
Test specific modules:
pytest tests/test_spectral.py
Test notebooks (requires nbval):
pytest --nbval tutorials/
Writing tests:
Place tests in
tests/directoryName test files
test_<module>.pyUse descriptive test function names:
test_<function>_<scenario>Include edge cases and error conditions
Use pytest fixtures for shared test data
Mock external dependencies (weather APIs, file downloads)
New test files must be included in
tests/__init__.py
Debugging tests: Use pytest’s --pdb flag to drop into the debugger at test failures:
pytest tests/test_spectral.py --pdb
This is preferred over adding print or logging statements.
Example test:
import pytest
import numpy as np
from pvdeg import spectral
def test_spectral_degradation_basic():
"""Test spectral degradation with simple inputs."""
wavelengths = np.array([300, 400, 500, 600, 700])
spectrum = np.array([0.1, 0.3, 0.5, 0.4, 0.2])
result = spectral.calc_degradation(wavelengths, spectrum)
assert isinstance(result, float)
assert result > 0
assert result < 100 # Reasonable degradation range
def test_spectral_degradation_with_nan():
"""Test spectral degradation handles NaN values."""
wavelengths = np.array([300, 400, np.nan, 600, 700])
spectrum = np.array([0.1, 0.3, 0.5, 0.4, 0.2])
with pytest.raises(ValueError, match="NaN values"):
spectral.calc_degradation(wavelengths, spectrum)
Documentation#
Building documentation locally:
Install documentation dependencies:
pip install -e .[docs]
Build the docs:
cd docs make html
View in browser:
# Open docs/build/html/index.html
Verifying documentation: Read the Docs automatically builds documentation for each pull request. Confirm it renders correctly by following the continuous-documentation/read-the-docs link in the PR checks.
Documentation types:
API documentation: Automatically generated from docstrings
User guide: RST files in
docs/source/user_guide/Tutorials: Jupyter notebooks in
tutorials/What’s new: Release notes in
docs/source/whatsnew/
Tutorial guidelines:
Place tutorials in appropriate
tutorials/<category>/folderUse descriptive names:
01_intro_to_topic.ipynbInclude markdown cells explaining concepts
Use local data files when possible (avoid API dependencies for reproducibility)
Keep execution time under 5 minutes
Clear outputs before committing (pre-commit will help)
Notebook Validation#
When contributing notebook changes, it’s important to validate that notebooks execute correctly and produce consistent outputs across different environments.
Why validate notebooks?
Ensures reproducibility across different systems and environments
Catches environment-specific bugs before they reach users
Maintains consistent output formatting in version control
Verifies that all cells execute in the correct order
Confirms that notebooks work with current dependencies
Using nbconvert for validation
The jupyter nbconvert command executes notebooks in a clean kernel and validates outputs.
This is the recommended approach for testing notebook changes.
Execute a single notebook:
jupyter nbconvert --to notebook --execute --inplace "tutorials/01_basics/01_basics_humidity_design.ipynb"
Execute all notebooks in a category:
jupyter nbconvert --to notebook --execute --inplace "tutorials/01_basics/*.ipynb"
Execute all tutorial notebooks (use with caution - may take a long time):
jupyter nbconvert --to notebook --execute --inplace "tutorials/**/*.ipynb"
Understanding the flags:
--to notebook: Converts back to notebook format (not HTML or other formats)--execute: Executes all cells in order with a fresh kernel--inplace: Overwrites the original notebook with execution results
Using pytest with nbval
For automated testing, use pytest with the nbval plugin to validate notebooks:
# Test all notebooks
pytest --nbval tutorials/
# Test specific notebook
pytest --nbval tutorials/01_basics/01_basics_humidity_design.ipynb
# Skip output comparison (only check execution)
pytest --nbval --nbval-lax tutorials/
The --nbval-lax flag is useful when outputs may vary slightly (e.g., timestamps, random numbers)
but you still want to verify the notebook executes without errors.
Best practices for notebook contributions:
Clear outputs before committing: Use
jupyter nbconvert --ClearOutputPreprocessor.enabled=True --inplace notebook.ipynbor let pre-commit hooks handle it automaticallyTest locally first: Always run notebooks locally before pushing to verify they work
Use relative paths: Ensure data paths work from the repository root
Document dependencies: If a notebook requires optional dependencies (e.g., PySAM), note this in a markdown cell at the top
Handle API keys gracefully: Use commented-out API sections with local data alternatives, following the pattern in existing notebooks
Keep execution time reasonable: Aim for under 5 minutes per notebook. For longer analyses, consider pre-computing results or creating separate demo notebooks
Version control friendly: Clear all outputs before committing (jupytext and pre-commit help with this)
Troubleshooting notebook validation failures:
Import errors: Verify all dependencies are installed in your environment
Path errors: Check that data files exist at expected locations
Kernel errors: Ensure your Jupyter kernel is properly registered (see installation guide)
Timeout errors: Increase timeout with
--ExecutePreprocessor.timeout=600(seconds)API failures: For notebooks with API calls, use local data or mock responses in tests
Database Contributions#
One of the most valuable contributions you can make is adding validated material property data and degradation parameters to our databases.
What to Contribute#
We maintain several JSON databases in pvdeg/data/:
DegradationDatabase.json: Degradation rates, activation energies, temperature coefficients
H2Opermeation.json: Water vapor transmission rates for encapsulants and barriers
O2permeation.json: Oxygen permeation rates
AApermeation.json: Acetic acid permeation data
albedo.json: Ground albedo values for different surfaces
How to Contribute#
Locate peer-reviewed data: Published journal articles, conference proceedings, or technical reports
Prepare structured data: Follow the JSON format in existing entries
Document metadata: Include measurement conditions, equipment, uncertainties
Submit via pull request: Add your data to the appropriate JSON file with citation
Data Quality Guidelines#
Peer-reviewed sources: Prefer published research over manufacturer specs
Complete metadata: Temperature, humidity, test conditions, sample details
Uncertainty quantification: Include error bars or confidence intervals when available
Clear units: Explicitly state all units
Proper citations: Full reference with DOI when possible
Example JSON Entry#
{
"material": "EVA",
"property": "activation_energy",
"value": 0.87,
"units": "eV",
"conditions": {
"temperature_range": "60-85 C",
"test_method": "Arrhenius analysis",
"sample_thickness": "0.46 mm"
},
"uncertainty": 0.05,
"reference": {
"authors": "Smith et al.",
"title": "Degradation study of EVA encapsulants",
"journal": "Solar Energy Materials",
"year": 2020,
"doi": "10.1016/j.solmat.2020.xxxxx"
}
}
Submitting Changes#
Pull Request Process#
Create a feature branch:
git checkout -b feature/descriptive-name
Use prefixes:
feature/,bugfix/,docs/,refactor/Make changes and commit:
git add . git commit -m "Add descriptive commit message"
Write clear commit messages explaining why the change was made.
Push to your fork:
git push origin feature/descriptive-name
Open a pull request on GitHub:
Provide a clear description of changes
Reference related issues (e.g., “Closes #123”)
Ensure all CI checks pass (tests, pre-commit hooks)
Request review from maintainers or tag
@NREL/pvdeg-maintainers
Best practices:
Keep pull requests focused and manageable (preferably <50 lines of primary code)
Consider breaking large changes into smaller, incremental pull requests
Submit pull requests early if you want feedback (mark as draft if incomplete)
Be patient - reviewers bring diverse expertise and perspectives
GitHub will automatically “squash and merge” your commits into a single commit
Pull Request Checklist#
Before submitting your pull request, verify:
[ ] Code follows PEP 8 style (black formatting applied)
[ ] All tests pass locally (
pytest tests/)[ ] New functionality includes unit tests
[ ] Docstrings added/updated for new/modified functions
[ ] Type hints included for function signatures
[ ] Pre-commit hooks pass (
pre-commit run --all-files)[ ] Documentation updated if adding features
[ ] What’s new entry added if significant change
[ ] Notebooks clear outputs and sync with
.pyscripts[ ] Database entries include proper citations and metadata
Code Review Process#
Maintainers will review your pull request within a few days
Discussion and iteration are normal - don’t be discouraged
Address feedback by pushing new commits to your branch
Ping one of the pvdeg maintainers if your pull request seems forgotten
Once approved, maintainers will merge your changes
Your contribution will be included in the next release
Understanding reviews: The PV modeling community is diverse. Reviewers may focus on:
Algorithm details and scientific accuracy
Integration with existing PVDeg code
Code maintainability and style
Test coverage and documentation quality
Contributor License Agreement#
First-time contributors must sign the Contributor License Agreement (CLA). This protects both you and the project.
When you submit your first pull request, a bot will comment with instructions to sign the CLA. Simply follow the provided link.
Release Process#
For maintainers and contributors interested in the release workflow:
Versioning: We follow semantic versioning (MAJOR.MINOR.PATCH)
MAJOR: Incompatible API changes
MINOR: New features (backward compatible)
PATCH: Bug fixes (backward compatible)
Testing releases:
Pre-release tags (
v0.7.0-rc1,v0.7.0-alpha1) → TestPyPI onlyFinal tags (
v0.7.0) → TestPyPI and PyPI
What’s new: Update docs/source/whatsnew/releases/vX.Y.Z.rst with:
Enhancements
Breaking changes
Deprecations
Bug fixes
Dependency updates
Issue references (#123)
Getting Help#
If you have questions or need help:
Ask on GitHub Discussions: https://github.com/NREL/PVDegradationTools/discussions
Open an issue: For bugs or feature requests
Check the documentation: https://pvdegradationtools.readthedocs.io/
Review existing PRs: See how others approached similar problems
Community Guidelines#
Be respectful and professional
Assume positive intent in all interactions
Focus on constructive feedback
Welcome newcomers and help them learn
Give credit where it’s due
Thank you for contributing to PVDeg and supporting the PV research community! 🌞