Repository: pvlib/pvlib-python
Pull request #495 (2018-06-28 21:45:13)

Contributing guidelines improvements
It's become clear to me that our contributing guidelines are insufficient, out-of-date, and/or unknown. My hope is that improved, more visible guidelines will allow for a more productive, enjoyable experience for everyone. So, here are some proposed changes. They are aimed at everyone from novice to expert, first time contributor to project maintainer. I stress that these are guidelines, not hard rules.

I wrote these guidelines in response to pull requests that are valuable but languishing, pull requests that are active but represent a huge review burden, and discussions in other issues. Please review the changes knowing that my intention is only to help set more useful, concrete guidelines. I do not mean to criticize any prior work or approaches. Nor do I expect all contributions can be made to fit within these guidelines. 

That being said, the contributing page with proposed changes is rendered here:

https://wholmgren-pvlib-python-new.readthedocs.io/en/contributing/contributing.html

The diff does not quite show the first couple of unchanged sentences, but I don't want them to be forgotten: 

"Encouraging more people to help develop pvlib-python is essential to our success. Therefore, we want to make it easy and rewarding for you to contribute." 

Note that I also reordered the checklist in the pull request template and added a new item: "I am familiar with the [contributing guidelines](http://pvlib-python.readthedocs.io/en/latest/contributing.html)". My hope is that even the most frequent contributors (myself included) will occasionally choose to follow the link if it's right in front of them. The new checklist is used below, though much of it does not apply for a documentation-only update.

I also added a new ``.github/CONTRIBUTING.md`` file that only links to the rendered documentation. It's another one of those special github files, see [here](https://help.github.com/articles/setting-guidelines-for-repository-contributors/). I don't know if it's ultimately useful or not, but I don't think it hurts.

**I am very interested in suggestions for how to improve this document.**

 - [ ] Closes #xxxx
 - [x] I am familiar with the [contributing guidelines](http://pvlib-python.readthedocs.io/en/latest/contributing.html).
 - [ ] Fully tested. Added and/or modified tests to ensure correct behavior for all reasonable inputs. Tests (usually) must pass on the TravisCI and Appveyor testing services.
 - [ ] Updates entries to `docs/sphinx/source/api.rst` for API changes.
 - [x] Adds description and name entries in the appropriate `docs/sphinx/source/whatsnew` file for all changes.
 - [ ] Code quality and style is sufficient. Passes ``git diff upstream/master -u -- "*.py" | flake8 --diff``
 - [ ] New code is fully documented. Includes sphinx/numpydoc compliant docstrings and comments in the code where necessary.
 - [x] Pull request is nearly complete and ready for detailed review.

mikofski: LGTM. Thanks for writing this up.
wholmgren: @thunderfish24 @adriesse any objections or suggestions for these proposed changes to ``contributing.rst``? No worries if you don't have the time/interest, I only want to make sure that the most frequent contributors are aware of the proposal.
adriesse: Sorry, where/what is `contributing.rst`?  (Gives you an idea what level I'm at...)
wholmgren: https://github.com/pvlib/pvlib-python/pull/495/files#diff-de7ce680a9d255c08c48841ed58d845b
adriesse: Seems fine to me.
thunderfish24: I should be able to take a real look over lunch today.
wholmgren: Thanks @adriesse and @thunderfish24 for your reviews!

> A general comment: Is there a place for using gist's instead of PR's for contributors that want to get a preliminary discussion about architecture and implementation options/choices/changes?

If by "place" you mean "is it ok to share code like this?" this yes, absolutely. I've done that a number of times, though it's hard for me to say how effective it's been because I usually don't get comments on them. But if you're asking about something like an "organization gist" then, no, not that I am aware of. I only know of gist.github.com which I believe is specific to your personal account and cannot be used with organizations. 

Patch:
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
new file mode 100644
index 0000000..d1dc84f
--- /dev/null
+++ b/.github/CONTRIBUTING.md
@@ -0,0 +1,4 @@
+Contributing
+============
+
+We welcome your contributions! Please see the [contributing](http://pvlib-python.readthedocs.io/en/latest/contributing.html) page for information about how to contribute.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 7e3cb86..eb39df0 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,17 +1,19 @@
 pvlib python pull request guidelines
 ====================================
 
-Thank you for your contribution to pvlib python!
+Thank you for your contribution to pvlib python! You may delete all of these instructions except for the list below.
 
-You may submit a pull request with your code at any stage of completion, however, before the code can be merged the following items must be addressed:
+You may submit a pull request with your code at any stage of completion.
+
+The following items must be addressed before the code can be merged. Please don't hesitate to ask for help if you're unsure of how to accomplish any of the items below:
 
  - [ ] Closes issue #xxxx
- - [ ] Fully tested. Added and/or modified tests to ensure correct behavior for all reasonable inputs. Tests must pass on the TravisCI and Appveyor testing services.
- - [ ] Code quality and style is sufficient. Passes ``git diff upstream/master -u -- "*.py" | flake8 --diff`` and/or landscape.io linting service.
- - [ ] New code is fully documented. Includes sphinx/numpydoc compliant docstrings and comments in the code where necessary.
+ - [ ] I am familiar with the [contributing guidelines](http://pvlib-python.readthedocs.io/en/latest/contributing.html).
+ - [ ] Fully tested. Added and/or modified tests to ensure correct behavior for all reasonable inputs. Tests (usually) must pass on the TravisCI and Appveyor testing services.
  - [ ] Updates entries to `docs/sphinx/source/api.rst` for API changes.
  - [ ] Adds description and name entries in the appropriate `docs/sphinx/source/whatsnew` file for all changes.
-
-Please don't hesitate to ask for help if you're unsure of how to accomplish any of the above. You may delete all of these instructions except for the list above.
+ - [ ] Code quality and style is sufficient. Passes ``git diff upstream/master -u -- "*.py" | flake8 --diff``
+ - [ ] New code is fully documented. Includes sphinx/numpydoc compliant docstrings and comments in the code where necessary.
+ - [ ] Pull request is nearly complete and ready for detailed review.
 
 Brief description of the problem and proposed solution (if not already fully described in the issue linked to above):
diff --git a/docs/sphinx/source/api.rst b/docs/sphinx/source/api.rst
index 4070ed5..5909db3 100644
--- a/docs/sphinx/source/api.rst
+++ b/docs/sphinx/source/api.rst
@@ -202,6 +202,7 @@ Functions relevant for the single diode model.
    :toctree: generated/
 
    pvsystem.calcparams_desoto
+   pvsystem.calcparams_pvsyst
    pvsystem.i_from_v
    pvsystem.singlediode
    pvsystem.v_from_i
diff --git a/docs/sphinx/source/contributing.rst b/docs/sphinx/source/contributing.rst
index 77af3bc..2819a20 100644
--- a/docs/sphinx/source/contributing.rst
+++ b/docs/sphinx/source/contributing.rst
@@ -7,17 +7,27 @@ Encouraging more people to help develop pvlib-python is essential to our
 success. Therefore, we want to make it easy and rewarding for you to
 contribute.
 
+There is a lot of material in this section, aimed at a variety of
+contributors from novice to expert. Don't worry if you don't (yet)
+understand parts of it.
+
 
 Easy ways to contribute
 ~~~~~~~~~~~~~~~~~~~~~~~
 
-Here are a few ideas for you can contribute, even if you are new to
+Here are a few ideas for how you can contribute, even if you are new to
 pvlib-python, git, or Python:
 
+* Ask and answer `pvlib questions on StackOverflow <http://stackoverflow.com/questions/tagged/pvlib>`_
+  and participate in discussions in the `pvlib-python google group <https://groups.google.com/forum/#!forum/pvlib-python>`_.
 * Make `GitHub issues <https://github.com/pvlib/pvlib-python/issues>`_
-  and contribute to the conversation about how to resolve them.
+  and contribute to the conversations about how to resolve them.
 * Read issues and pull requests that other people created and
   contribute to the conversation about how to resolve them.
+  Look for issues tagged with
+  `good first issue <https://github.com/pvlib/pvlib-python/labels/good%20first%20issue>`_,
+  `easy <https://github.com/pvlib/pvlib-python/labels/easy>`_,
+  or `help wanted <https://github.com/pvlib/pvlib-python/labels/help%20wanted>`_.
 * Improve the documentation and the unit tests.
 * Improve the IPython/Jupyter Notebook tutorials or write new ones that
   demonstrate how to use pvlib-python in your area of expertise.
@@ -35,6 +45,9 @@ pvlib-python, git, or Python:
 How to contribute new code
 ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+The basics
+----------
+
 Contributors to pvlib-python use GitHub's pull requests to add/modify
 its source code. The GitHub pull request process can be intimidating for
 new users, but you'll find that it becomes straightforward once you use
@@ -53,16 +66,11 @@ process. Here's an outline of the process:
    request.
 
 The Pandas project maintains an excellent `contributing page
-<https://github.com/pydata/pandas/wiki/Contributing>`_ that goes into
-detail on each of these steps. Also see GitHub's `Set Up Git
+<http://pandas.pydata.org/pandas-docs/stable/contributing.html>`_ that goes
+into detail on each of these steps. Also see GitHub's `Set Up Git
 <https://help.github.com/articles/set-up-git/>`_ and `Using Pull
 Requests <https://help.github.com/articles/using-pull-requests/>`_.
 
-Note that you do not need to make all of your changes before creating a
-pull request. Your pull requests will automatically be updated when you
-commit new changes and push them to GitHub. This gives everybody an easy
-way to comment on the code and can make the process more efficient.
-
 We strongly recommend using virtual environments for development.
 Virtual environments make it trivial to switch between different
 versions of software. This `astropy guide
@@ -73,17 +81,187 @@ environment.
 
 You must include documentation and unit tests for any new or improved
 code. We can provide help and advice on this after you start the pull
-request.
+request. See the Testing section below.
+
+
+.. _pull-request-scope:
+
+Pull request scope
+------------------
+
+This section can be summed up as "less is more".
+
+A pull request can quickly become unmanageable if too many lines are
+added or changed. "Too many" is hard to define, but as a rule of thumb,
+we encourage contributions that contain less than 50 lines of primary code.
+50 lines of primary code will typically need at least 250 lines
+of documentation and testing. This is about the limit of what the
+maintainers can review on a regular basis.
+
+A pull request can also quickly become unmanageable if it proposes
+changes to the API in order to implement another feature. Consider
+clearly and concisely documenting all proposed API changes before
+implementing any code. Modifying
+`api.rst <https://github.com/pvlib/pvlib-python/blob/master/docs/sphinx/source/api.rst>`_
+and/or the latest `whatsnew file <https://github.com/pvlib/pvlib-python/tree/master/docs/sphinx/source/whatsnew>`_
+can help formalize this process.
+
+Questions about related issues frequently come up in the process of
+addressing implementing code for a pull request. Please try to avoid
+expanding the scope of your pull request (this also applies to
+reviewers!). We'd rather see small, well-documented additions to the
+project's technical debt than see a pull request languish because its
+scope expanded beyond what the reviewer community is capable of
+processing.
+
+Of course, sometimes it is necessary to make a large pull request. We
+only ask that you take a few minutes to consider how to break it into
+smaller chunks before proceeding.
+
+pvlib-python contains :ref:`3 "layers" of code <modeling-paradigms>`:
+functions, PVSystem/Location, and ModelChain. We recommend that
+contributors focus their work on only one or two of those layers in a
+single pull request. New models are *not* required to be available to
+the higher-level API!
+
+
+When should I submit a pull request?
+------------------------------------
+
+The short answer: anytime.
+
+The long answer: it depends. If in doubt, go ahead and submit. You do
+not need to make all of your changes before creating a pull request.
+Your pull requests will automatically be updated when you commit new
+changes and push them to GitHub.
+
+There are pros and cons to submitting incomplete pull-requests. On the
+plus side, it gives everybody an easy way to comment on the code and can
+make the process more efficient. On the minus side, it's easy for an
+incomplete pull request to grow into a multi-month saga that leaves
+everyone unhappy. If you submit an incomplete pull request, please be
+very clear about what you would like feedback on and what we should
+ignore. Alternatives to incomplete pull requests include creating a
+`gist <https://gist.github.com>`_ or experimental branch and linking to
+it in the corresponding issue.
+
+The best way to ensure that a pull request will be reviewed and merged in
+a timely manner is to:
+
+#. Start by creating an issue. The issue should be well-defined and
+   actionable.
+#. Ask the maintainers to tag the issue with the appropriate milestone.
+#. Make a limited-scope pull request. It can be a lot of work to check all of
+   the boxes in `pull request guidelines
+   <https://github.com/pvlib/pvlib-python/blob/master/.github/PULL_REQUEST_TEMPLATE.md>`_,
+   especially for pull requests with a lot of new primary code.
+   See :ref:`pull-request-scope`.
+#. Tag pvlib community members or ``@pvlib/maintainer`` when the pull
+   request is ready for review. (see :ref:`pull-request-reviews`)
+
+
+.. _pull-request-reviews:
+
+Pull request reviews
+--------------------
+
+The pvlib community and maintainers will review your pull request in a
+timely fashion. Please "ping" ``@pvlib/maintainer`` if it seems that
+your pull request has been forgotten at any point in the pull request
+process.
+
+Keep in mind that the PV modeling community is diverse and each pvlib
+community member brings a different perspective when reviewing code.
+Some reviewers bring years of expertise in the sub-field that your code
+contributes to and will focus on the details of the algorithm. Other
+reviewers will be more focused on integrating your code with the rest of
+pvlib, ensuring that it is feasible to maintain, that it meets the
+:ref:`code style <code-style>` guidelines, and that it is
+:ref:`comprehensively tested <testing>`. Limiting the scope of the pull
+request makes it much more likely that all of these reviews can be
+conducted and any issues can be resolved in a timely fashion.
+
+Sometimes it's hard for reviewers to be immediately available, so the
+right amount of patience is to be expected. That said, interested
+reviewers should do their best to not wait until the last minute to put
+in their two cents.
+
+
+.. _code-style:
+
+Code style
+~~~~~~~~~~
+
+pvlib python generally follows the `PEP 8 -- Style Guide for Python Code
+<https://www.python.org/dev/peps/pep-0008/>`_. Maximum line length for code
+is 79 characters.
+
+Code must be compatible with python 2.7 and 3.4+.
+
+pvlib python uses a mix of full and abbreviated variable names. See
+:ref:`variables_style_rules`. We could be better about consistency.
+Prefer full names for new contributions. This is especially important
+for the API. Abbreviations can be used within a function to improve the
+readability of formulae.
+
+Set your editor to strip extra whitespace from line endings. This
+prevents the git commit history from becoming cluttered with whitespace
+changes.
+
+Please see :ref:`Documentation` for information specific to documentation
+style.
+
+Remove any ``logging`` calls and ``print`` statements that you added
+during development. ``warning`` is ok.
+
+We typically use GitHub's
+"`squash and merge` <https://help.github.com/articles/about-pull-request-merges/#squash-and-merge-your-pull-request-commits>_"
+feature to merge your pull request into pvlib. GitHub will condense the
+commit history of your branch into a single commit when merging into
+pvlib-python/master (the commit history on your branch remains
+unchanged). Therefore, you are free to make commits that are as big or
+small as you'd like while developing your pull request.
+
+
+.. _documentation:
 
-The maintainers will follow same procedures, rather than making direct
-commits to the main repo. Exceptions may be made for extremely minor
-changes, such as fixing documentation typos.
+Documentation
+~~~~~~~~~~~~~
 
+Documentation must be written in
+`numpydoc format <https://numpydoc.readthedocs.io/>`_.
+
+The numpydoc format includes a specification for the allowable input
+types. Python's `duck typing <https://en.wikipedia.org/wiki/Duck_typing>`_
+allows for multiple input types to work for many parameters. pvlib uses
+the following generic descriptors as short-hand to indicate which
+specific types may be used:
+
+* 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 specific input type.
+
+A relatively easy way to test your documentation is to build it on
+`readthedocs.org <https://readthedocs.org>` by following their
+`Import Your Docs <http://docs.readthedocs.io/en/stable/getting_started.html#import-your-docs>`_
+instructions and enabling your branch on the readthedocs
+`versions admin page <http://docs.readthedocs.io/en/stable/features.html#versions>`_.
+
+Another option is to install the required dependencies in your virtual/conda
+environment. See
+`docs/environment.yml <https://github.com/pvlib/pvlib-python/blob/master/docs/environment.yml>`_
+for the latest dependences for building the complete documentation. Some
+doc files can be compiled with fewer dependencies, but this is beyond
+the scope of this guide.
+
+.. _testing:
 
 Testing
 ~~~~~~~
 
-pvlib's unit tests can easily be run by executing ``py.test`` on the
+pvlib's unit tests can easily be run by executing ``pytest`` on the
 pvlib directory:
 
 ``pytest pvlib``
@@ -96,7 +274,16 @@ or, for a single test:
 
 ``pytest pvlib/test/test_clearsky.py::test_ineichen_nans``
 
-Use the ``--pdb`` flag to debug failures and avoid using ``print``.
+We suggest using pytest's ``--pdb`` flag to debug test failures rather
+than using ``print`` or ``logging`` calls. For example:
+
+``pytest pvlib --pdb``
+
+will drop you into the
+`pdb debugger <https://docs.python.org/3/library/pdb.html>`_ at the
+location of a test failure. As described in :ref:`code-style`, pvlib
+code does not use ``print`` or ``logging`` calls, and this also applies
+to the test suite (with rare exceptions).
 
 New unit test code should be placed in the corresponding test module in
 the pvlib/test directory.
@@ -106,7 +293,7 @@ modifications to pvlib.
 
 pvlib-python contains 3 "layers" of code: functions, PVSystem/Location,
 and ModelChain. Contributors will need to add tests that correspond to
-the layer that they modify.
+the layers that they modify.
 
 Functions
 ---------
@@ -148,6 +335,7 @@ in fact, happen. Finally, we check that the output of the method call is
 reasonable.
 
 .. code-block:: python
+
     def test_PVSystem_ashraeiam(mocker):
         # mocker is a pytest-mock object.
         # mocker.spy adds code to a function to keep track of how it is called
@@ -189,6 +377,7 @@ The example below shows how mock can be used to assert that the correct
 PVSystem method is called through ``ModelChain.run_model``.
 
 .. code-block:: python
+
     def test_modelchain_dc_model(mocker):
         # set up location and system for model chain
         location = location.Location(32, -111)
@@ -220,5 +409,5 @@ This documentation
 
 If this documentation is unclear, help us improve it! Consider looking
 at the `pandas
-documentation <http://pandas.pydata.org/pandas-docs/version/0.18.1/
+documentation <http://pandas.pydata.org/pandas-docs/stable/
 contributing.html>`_ for inspiration.
diff --git a/docs/sphinx/source/package_overview.rst b/docs/sphinx/source/package_overview.rst
index 3a245e3..f8dd897 100644
--- a/docs/sphinx/source/package_overview.rst
+++ b/docs/sphinx/source/package_overview.rst
@@ -282,10 +282,8 @@ change something about pvlib, then please make an issue on our
 
 How do I contribute?
 --------------------
-We're so glad you asked! Please see our
-`wiki <https://github.com/pvlib/pvlib-python/wiki/Contributing-to-pvlib-python>`_
-for information and instructions on how to contribute.
-We really appreciate it!
+We're so glad you asked! Please see :ref:`Contributing` for information and
+instructions on how to contribute. We really appreciate it!
 
 
 Credits
diff --git a/docs/sphinx/source/whatsnew/v0.6.0.rst b/docs/sphinx/source/whatsnew/v0.6.0.rst
index 5eec801..5f8d938 100644
--- a/docs/sphinx/source/whatsnew/v0.6.0.rst
+++ b/docs/sphinx/source/whatsnew/v0.6.0.rst
@@ -14,6 +14,7 @@ Enhancements
 * Add sea surface albedo in irradiance.py (:issue:`458`)
 * Implement first_solar_spectral_loss in modelchain.py (:issue:`359`)
 * Clarify arguments Egref and dEgdT for calcparams_desoto (:issue:`462`)
+* Add pvsystem.calcparams_pvsyst to compute values for the single diode equation using the PVsyst v6 model (:issue:'470')
 
 
 Bug fixes
@@ -33,6 +34,7 @@ Documentation
   objects, and ModelChain.
 * Updated several incorrect statements in ModelChain documentation regarding
   implementation status and default values. (:issue:`480`)
+* Expanded general contributing and pull request guidelines.
 
 
 Testing
diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py
index 96ac7d3..9d3bea8 100644
--- a/pvlib/pvsystem.py
+++ b/pvlib/pvsystem.py
@@ -302,11 +302,40 @@ class PVSystem(object):
         """
 
         kwargs = _build_kwargs(['a_ref', 'I_L_ref', 'I_o_ref', 'R_sh_ref',
-                                'R_s', 'alpha_sc', 'EgRef', 'dEgdT'],
+                                'R_s', 'alpha_sc', 'EgRef', 'dEgdT',
+                                'irrad_ref', 'temp_ref'],
                                 self.module_parameters)
-        
+
         return calcparams_desoto(effective_irradiance, temp_cell, **kwargs)
 
+    def calcparams_pvsyst(self, effective_irradiance, temp_cell):
+        """
+        Use the :py:func:`calcparams_pvsyst` function, the input
+        parameters and ``self.module_parameters`` to calculate the
+        module currents and resistances.
+
+        Parameters
+        ----------
+        effective_irradiance : numeric
+            The irradiance (W/m2) that is converted to photocurrent.
+
+        temp_cell : float or Series
+            The average cell temperature of cells within a module in C.
+
+        Returns
+        -------
+        See pvsystem.calcparams_pvsyst for details
+        """
+
+        kwargs = _build_kwargs(['gamma_ref', 'mu_gamma', 'I_L_ref', 'I_o_ref',
+                                'R_sh_ref', 'R_sh_0', 'R_sh_exp',
+                                'R_s', 'alpha_sc', 'EgRef',
+                                'irrad_ref', 'temp_ref',
+                                'cells_in_series'],
+                                self.module_parameters)
+
+        return calcparams_pvsyst(effective_irradiance, temp_cell, **kwargs)
+
     def sapm(self, effective_irradiance, temp_cell, **kwargs):
         """
         Use the :py:func:`sapm` function, the input parameters,
@@ -462,7 +491,7 @@ class PVSystem(object):
             coefficients = None
 
         return atmosphere.first_solar_spectral_correction(pw,
-                                                          airmass_absolute, 
+                                                          airmass_absolute,
                                                           module_type,
                                                           coefficients)
 
@@ -946,12 +975,12 @@ def physicaliam(aoi, n=1.526, K=4., L=0.002):
 
 
 def calcparams_desoto(effective_irradiance, temp_cell,
-                      alpha_sc, a_ref, I_L_ref, I_o_ref, R_sh_ref, R_s, 
+                      alpha_sc, a_ref, I_L_ref, I_o_ref, R_sh_ref, R_s,
                       EgRef=1.121, dEgdT=-0.0002677,
                       irrad_ref=1000, temp_ref=25):
     '''
-    Calculates five parameter values for the single diode equation at 
-    effective irradiance and cell temperature using the De Soto et al. 
+    Calculates five parameter values for the single diode equation at
+    effective irradiance and cell temperature using the De Soto et al.
     model described in [1]. The five values returned by calcparams_desoto
     can be used by singlediode to calculate an IV curve.
 
@@ -968,34 +997,34 @@ def calcparams_desoto(effective_irradiance, temp_cell,
         module in units of A/C.
 
     a_ref : float
-        The product of the usual diode ideality factor (n, unitless), 
+        The product of the usual diode ideality factor (n, unitless),
         number of cells in series (Ns), and cell thermal voltage at reference
         conditions, in units of V.
 
     I_L_ref : float
         The light-generated current (or photocurrent) at reference conditions,
         in amperes.
-        
+
     I_o_ref : float
         The dark or diode reverse saturation current at reference conditions,
         in amperes.
-        
+
     R_sh_ref : float
         The shunt resistance at reference conditions, in ohms.
-        
+
     R_s : float
         The series resistance at reference conditions, in ohms.
 
     EgRef : float
         The energy bandgap at reference temperature in units of eV.
-        1.121 eV for crystalline silicon. EgRef must be >0.  For parameters 
+        1.121 eV for crystalline silicon. EgRef must be >0.  For parameters
         from the SAM CEC module database, EgRef=1.121 is implicit for all
         cell types in the parameter estimation algorithm used by NREL.
 
     dEgdT : float
         The temperature dependence of the energy bandgap at reference
-        conditions in units of 1/K. May be either a scalar value 
-        (e.g. -0.0002677 as in [1]) or a DataFrame (this may be useful if 
+        conditions in units of 1/K. May be either a scalar value
+        (e.g. -0.0002677 as in [1]) or a DataFrame (this may be useful if
         dEgdT is a modeled as a function of temperature). For parameters from
         the SAM CEC module database, dEgdT=-0.0002677 is implicit for all cell
         types in the parameter estimation algorithm used by NREL.
@@ -1011,28 +1040,21 @@ def calcparams_desoto(effective_irradiance, temp_cell,
     Tuple of the following results:
 
     photocurrent : numeric
-        Light-generated current in amperes at irradiance=S and
-        cell temperature=Tcell.
+        Light-generated current in amperes
 
     saturation_current : numeric
-        Diode saturation curent in amperes at irradiance
-        S and cell temperature Tcell.
+        Diode saturation curent in amperes
 
     resistance_series : float
-        Series resistance in ohms at irradiance S and cell temperature
-        Tcell.
+        Series resistance in ohms
 
     resistance_shunt : numeric
-        Shunt resistance in ohms at irradiance S and cell temperature
-        Tcell.
+        Shunt resistance in ohms
 
     nNsVth : numeric
-        Modified diode ideality factor at irradiance S and cell
-        temperature Tcell. Note that in source [1] nNsVth = a (equation
-        2). nNsVth is the product of the usual diode ideality factor
-        (n), the number of series-connected cells in the module (Ns),
-        and the thermal voltage of a cell in the module (Vth) at a cell
-        temperature of Tcell.
+        The product of the usual diode ideality factor (n, unitless),
+        number of cells in series (Ns), and cell thermal voltage at
+        specified effective irradiance and cell temperature.
 
     References
     ----------
@@ -1051,8 +1073,6 @@ def calcparams_desoto(effective_irradiance, temp_cell,
 
     See Also
     --------
-    sapm
-    sapm_celltemp
     singlediode
     retrieve_sam
 
@@ -1143,7 +1163,7 @@ def calcparams_desoto(effective_irradiance, temp_cell,
 
     # Boltzmann constant in eV/K
     k = 8.617332478e-05
-    
+
     # reference temperature
     Tref_K = temp_ref + 273.15
     Tcell_K = temp_cell + 273.15
@@ -1152,9 +1172,9 @@ def calcparams_desoto(effective_irradiance, temp_cell,
 
     nNsVth = a_ref * (Tcell_K / Tref_K)
 
-    # In the equation for IL, the single factor effective_irradiance is 
-    # used, in place of the product S*M in [1]. effective_irradiance is 
-    # equivalent to the product of S (irradiance reaching a module's cells) * 
+    # In the equation for IL, the single factor effective_irradiance is
+    # used, in place of the product S*M in [1]. effective_irradiance is
+    # equivalent to the product of S (irradiance reaching a module's cells) *
     # M (spectral adjustment factor) as described in [1].
     IL = effective_irradiance / irrad_ref * \
               (I_L_ref + alpha_sc * (Tcell_K - Tref_K))
@@ -1164,7 +1184,7 @@ def calcparams_desoto(effective_irradiance, temp_cell,
     # Rsh = Rsh_ref * (S_ref / S) where S is broadband irradiance reaching
     # the module's cells. If desired this model behavior can be duplicated
     # by applying reflection and soiling losses to broadband plane of array
-    # irradiance and not applying a spectral loss modifier, i.e., 
+    # irradiance and not applying a spectral loss modifier, i.e.,
     # spectral_modifier = 1.0.
     Rsh = R_sh_ref * (irrad_ref / effective_irradiance)
     Rs = R_s
@@ -1172,6 +1192,143 @@ def calcparams_desoto(effective_irradiance, temp_cell,
     return IL, I0, Rs, Rsh, nNsVth
 
 
+def calcparams_pvsyst(effective_irradiance, temp_cell,
+                      alpha_sc, gamma_ref, mu_gamma,
+                      I_L_ref, I_o_ref,
+                      R_sh_ref, R_sh_0, R_s,
+                      cells_in_series,
+                      R_sh_exp=5.5,
+                      EgRef=1.121,
+                      irrad_ref=1000, temp_ref=25):
+    '''
+    Calculates five parameter values for the single diode equation at
+    effective irradiance and cell temperature using the PVsyst v6
+    model described in [1,2,3]. The five values returned by calcparams_pvsyst
+    can be used by singlediode to calculate an IV curve.
+
+    Parameters
+    ----------
+    effective_irradiance : numeric
+        The irradiance (W/m2) that is converted to photocurrent.
+
+    temp_cell : numeric
+        The average cell temperature of cells within a module in C.
+
+    alpha_sc : float
+        The short-circuit current temperature coefficient of the
+        module in units of A/C.
+
+    gamma_ref : float
+        The diode ideality factor
+
+    mu_gamma : float
+        The temperature coefficient for the diode ideality factor, 1/K
+
+    I_L_ref : float
+        The light-generated current (or photocurrent) at reference conditions,
+        in amperes.
+
+    I_o_ref : float
+        The dark or diode reverse saturation current at reference conditions,
+        in amperes.
+
+    R_sh_ref : float
+        The shunt resistance at reference conditions, in ohms.
+
+    R_sh_0 : float
+        The shunt resistance at zero irradiance conditions, in ohms.
+
+    R_s : float
+        The series resistance at reference conditions, in ohms.
+
+    cells_in_series : integer
+        The number of cells connected in series.
+
+    R_sh_exp : float
+        The exponent in the equation for shunt resistance, unitless. Defaults
+        to 5.5.
+
+    EgRef : float
+        The energy bandgap at reference temperature in units of eV.
+        1.121 eV for crystalline silicon. EgRef must be >0.
+
+    irrad_ref : float (optional, default=1000)
+        Reference irradiance in W/m^2.
+
+    temp_ref : float (optional, default=25)
+        Reference cell temperature in C.
+
+    Returns
+    -------
+    Tuple of the following results:
+
+    photocurrent : numeric
+        Light-generated current in amperes
+
+    saturation_current : numeric
+        Diode saturation current in amperes
+
+    resistance_series : float
+        Series resistance in ohms
+
+    resistance_shunt : numeric
+        Shunt resistance in ohms
+
+    nNsVth : numeric
+        The product of the usual diode ideality factor (n, unitless),
+        number of cells in series (Ns), and cell thermal voltage at
+        specified effective irradiance and cell temperature.
+
+    References
+    ----------
+    [1] K. Sauer, T. Roessler, C. W. Hansen, Modeling the Irradiance and
+     Temperature Dependence of Photovoltaic Modules in PVsyst,
+     IEEE Journal of Photovoltaics v5(1), January 2015.
+
+    [2] A. Mermoud, PV modules modelling, Presentation at the 2nd PV
+     Performance Modeling Workshop, Santa Clara, CA, May 2013
+
+    [3] A. Mermoud, T. Lejeune, Performance Assessment of a Simulation Model
+     for PV modules of any available technology, 25th European Photovoltaic
+     Solar Energy Conference, Valencia, Spain, Sept. 2010
+
+    See Also
+    --------
+    calcparams_desoto
+    singlediode
+
+    '''
+
+    # Boltzmann constant in J/K
+    k = 1.38064852e-23
+
+    # elementary charge in coulomb
+    q = 1.6021766e-19
+
+    # reference temperature
+    Tref_K = temp_ref + 273.15
+    Tcell_K = temp_cell + 273.15
+
+    gamma = gamma_ref + mu_gamma * (Tcell_K - Tref_K)
+    nNsVth = gamma * k / q * cells_in_series * Tcell_K
+
+    IL = effective_irradiance / irrad_ref * \
+              (I_L_ref + alpha_sc * (Tcell_K - Tref_K))
+
+    I0 = I_o_ref * ((Tcell_K / Tref_K) ** 3) * \
+          (np.exp((q * EgRef) / (k * gamma) * (1 / Tref_K - 1 / Tcell_K)))
+
+    Rsh_tmp = (R_sh_ref - R_sh_0 * np.exp(-R_sh_exp)) / (1.0 - np.exp(-R_sh_exp))
+    Rsh_base = np.maximum(0.0, Rsh_tmp)
+
+    Rsh = Rsh_base + (R_sh_0 - Rsh_base) * \
+              np.exp(-R_sh_exp * effective_irradiance / irrad_ref)
+
+    Rs = R_s
+
+    return IL, I0, Rs, Rsh, nNsVth
+
+
 def retrieve_sam(name=None, path=None):
     '''
     Retrieve latest module and inverter info from a local file or the


Test patch:
diff --git a/pvlib/test/test_pvsystem.py b/pvlib/test/test_pvsystem.py
index 289b0f6..6931543 100644
--- a/pvlib/test/test_pvsystem.py
+++ b/pvlib/test/test_pvsystem.py
@@ -174,6 +174,23 @@ def cec_module_params(sam_data):
     return module_parameters
 
 
+@pytest.fixture()
+def pvsyst_module_params():
+    module_parameters = {}
+    module_parameters['gamma_ref'] = 1.05
+    module_parameters['mu_gamma'] = 0.001
+    module_parameters['I_L_ref'] = 6.0
+    module_parameters['I_o_ref'] = 5e-9
+    module_parameters['EgRef'] = 1.121
+    module_parameters['R_sh_ref'] = 300
+    module_parameters['R_sh_0'] = 1000
+    module_parameters['R_s'] = 0.5
+    module_parameters['R_sh_exp'] = 5.5
+    module_parameters['cells_in_series'] = 60
+    module_parameters['alpha_sc'] = 0.001
+    return module_parameters
+
+
 def test_sapm(sapm_module_params):
 
     times = pd.DatetimeIndex(start='2015-01-01', periods=5, freq='12H')
@@ -386,6 +403,35 @@ def test_calcparams_desoto(cec_module_params):
     assert_allclose(nNsVth, 0.473)
 
 
+def test_calcparams_pvsyst(pvsyst_module_params):
+    times = pd.DatetimeIndex(start='2015-01-01', periods=2, freq='12H')
+    effective_irradiance = pd.Series([0.0, 800.0], index=times)
+    temp_cell = pd.Series([25, 50], index=times)
+
+    IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_pvsyst(
+                                  effective_irradiance,
+                                  temp_cell,
+                                  alpha_sc=pvsyst_module_params['alpha_sc'],
+                                  gamma_ref=pvsyst_module_params['gamma_ref'],
+                                  mu_gamma=pvsyst_module_params['mu_gamma'],
+                                  I_L_ref=pvsyst_module_params['I_L_ref'],
+                                  I_o_ref=pvsyst_module_params['I_o_ref'],
+                                  R_sh_ref=pvsyst_module_params['R_sh_ref'],
+                                  R_sh_0=pvsyst_module_params['R_sh_0'],
+                                  R_s=pvsyst_module_params['R_s'],
+                    cells_in_series=pvsyst_module_params['cells_in_series'],
+                                  EgRef=pvsyst_module_params['EgRef'])
+
+    assert_series_equal(np.round(IL, 3), pd.Series([0.0, 4.8200], index=times))
+    assert_series_equal(np.round(I0, 3),
+                        pd.Series([0.0, 1.47e-7], index=times))
+    assert_allclose(Rs, 0.500)
+    assert_series_equal(np.round(Rsh, 3),
+                        pd.Series([1000.0, 305.757], index=times))
+    assert_series_equal(np.round(nNsVth, 4),
+                        pd.Series([1.6186, 1.7961], index=times))
+
+
 def test_PVSystem_calcparams_desoto(cec_module_params, mocker):
     mocker.spy(pvsystem, 'calcparams_desoto')
     module_parameters = cec_module_params.copy()
@@ -414,6 +460,36 @@ def test_PVSystem_calcparams_desoto(cec_module_params, mocker):
     assert_allclose(nNsVth, 0.5, atol=0.1)
 
 
+def test_PVSystem_calcparams_pvsyst(pvsyst_module_params, mocker):
+    mocker.spy(pvsystem, 'calcparams_pvsyst')
+    module_parameters = pvsyst_module_params.copy()
+    system = pvsystem.PVSystem(module_parameters=module_parameters)
+    effective_irradiance = np.array([0, 800])
+    temp_cell = np.array([25, 50])
+    IL, I0, Rs, Rsh, nNsVth = system.calcparams_pvsyst(effective_irradiance,
+                                                       temp_cell)
+    pvsystem.calcparams_pvsyst.assert_called_once_with(
+                                  effective_irradiance,
+                                  temp_cell,
+                                  alpha_sc=pvsyst_module_params['alpha_sc'],
+                                  gamma_ref=pvsyst_module_params['gamma_ref'],
+                                  mu_gamma=pvsyst_module_params['mu_gamma'],
+                                  I_L_ref=pvsyst_module_params['I_L_ref'],
+                                  I_o_ref=pvsyst_module_params['I_o_ref'],
+                                  R_sh_ref=pvsyst_module_params['R_sh_ref'],
+                                  R_sh_0=pvsyst_module_params['R_sh_0'],
+                                  R_s=pvsyst_module_params['R_s'],
+                    cells_in_series=pvsyst_module_params['cells_in_series'],
+                                  EgRef=pvsyst_module_params['EgRef'],
+                                  R_sh_exp=pvsyst_module_params['R_sh_exp'])
+
+    assert_allclose(IL, np.array([0.0, 4.8200]), atol=1)
+    assert_allclose(I0, np.array([0.0, 1.47e-7]), atol=1.0e-5)
+    assert_allclose(Rs, 0.5, atol=0.1)
+    assert_allclose(Rsh, np.array([1000, 305.757]), atol=50)
+    assert_allclose(nNsVth, np.array([1.6186, 1.7961]), atol=0.1)
+
+
 @pytest.fixture(params=[
     {  # Can handle all python scalar inputs
      'Rsh': 20.,