Repository: pvlib/pvlib-python (python)

Issue:
Implement PVsyst single diode model
I've heard a number of requests for this capability, which we have in MATLAB but not here.  Requires calcparams_PVsyst and an example set of module_parameters.

Pull request description:
Implement calcparams_pvsyst and tests
pvlib python pull request guidelines
====================================

Thank you for your contribution to pvlib python!

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:

 - [x] Closes #470 
 - [x] 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.
 - [x] Code quality and style is sufficient. Passes ``git diff upstream/master -u -- "*.py" | flake8 --diff`` and/or landscape.io linting service.
 - [x] New code is fully documented. Includes sphinx/numpydoc compliant docstrings and comments in the code where necessary.
 - [x] 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.

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.

Brief description of the problem and proposed solution (if not already fully described in the issue linked to above):

Implement `calcparams_pvsyst` for use with `singlediode`

Patch:
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/whatsnew/v0.6.0.rst b/docs/sphinx/source/whatsnew/v0.6.0.rst
index 2f205ed..c4fce7a 100644
--- a/docs/sphinx/source/whatsnew/v0.6.0.rst
+++ b/docs/sphinx/source/whatsnew/v0.6.0.rst
@@ -6,6 +6,7 @@ v0.6.0 (___, 2018)
 API Changes
 ~~~~~~~~~~~
 * pvsystem.calcparams_desoto now requires arguments for each module model parameter.
+* removed irradiance parameter from ModelChain.run_model and ModelChain.prepare_inputs
 
 
 Enhancements
@@ -13,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
@@ -20,12 +22,18 @@ Bug fixes
 * Unset executable bits of irradiance.py and test_irradiance.py (:issue:`460`)
 * Fix failing tests due to column order on Python 3.6+ and Pandas 0.23+
   (:issue:`464`)
+* ModelChain.prepare_inputs failed to pass solar_position and airmass to
+  Location.get_clearsky. Fixed. (:issue:`481`)
+* Add User-Agent specification to TMY3 remote requests to avoid rejection.
+  (:issue:`493`)
 
 
 Documentation
 ~~~~~~~~~~~~~
 * Expand testing section with guidelines for functions, PVSystem/Location
   objects, and ModelChain.
+* Updated several incorrect statements in ModelChain documentation regarding
+  implementation status and default values. (:issue:`480`)
 
 
 Testing
@@ -41,4 +49,5 @@ Contributors
 * Will Holmgren
 * Yu Cao
 * Cliff Hansen
+* Alan Mathew
 
diff --git a/pvlib/modelchain.py b/pvlib/modelchain.py
index 29f4cfa..a71f72b 100644
--- a/pvlib/modelchain.py
+++ b/pvlib/modelchain.py
@@ -216,12 +216,9 @@ def get_orientation(strategy, **kwargs):
 
 class ModelChain(object):
     """
-    An experimental class that represents all of the modeling steps
-    necessary for calculating power or energy for a PV system at a given
-    location using the SAPM.
-
-    CEC module specifications and the single diode model are not yet
-    supported.
+    The ModelChain class to provides a standardized, high-level
+    interface for all of the modeling steps necessary for calculating PV
+    power from a time series of weather inputs.
 
     Parameters
     ----------
@@ -233,7 +230,7 @@ class ModelChain(object):
         A :py:class:`~pvlib.location.Location` object that represents
         the physical location at which to evaluate the model.
 
-    orientation_strategy : None or str, default 'south_at_latitude_tilt'
+    orientation_strategy : None or str, default None
         The strategy for aligning the modules. If not None, sets the
         ``surface_azimuth`` and ``surface_tilt`` properties of the
         ``system``. Allowed strategies include 'flat',
@@ -260,9 +257,9 @@ class ModelChain(object):
     ac_model: None, str, or function, default None
         If None, the model will be inferred from the contents of
         system.inverter_parameters and system.module_parameters. Valid
-        strings are 'snlinverter', 'adrinverter' (not implemented),
-        'pvwatts'. The ModelChain instance will be passed as the first
-        argument to a user-defined function.
+        strings are 'snlinverter', 'adrinverter', 'pvwatts'. The
+        ModelChain instance will be passed as the first argument to a
+        user-defined function.
 
     aoi_model: None, str, or function, default None
         If None, the model will be inferred from the contents of
@@ -273,9 +270,8 @@ class ModelChain(object):
     spectral_model: None, str, or function, default None
         If None, the model will be inferred from the contents of
         system.module_parameters. Valid strings are 'sapm',
-        'first_solar', 'no_loss'. The ModelChain instance will be passed 
-        as the first argument to a user-defined
-        function.
+        'first_solar', 'no_loss'. The ModelChain instance will be passed
+        as the first argument to a user-defined function.
 
     temp_model: str or function, default 'sapm'
         Valid strings are 'sapm'. The ModelChain instance will be passed
@@ -301,9 +297,7 @@ class ModelChain(object):
                  airmass_model='kastenyoung1989',
                  dc_model=None, ac_model=None, aoi_model=None,
                  spectral_model=None, temp_model='sapm',
-                 losses_model='no_loss',
-                 name=None,
-                 **kwargs):
+                 losses_model='no_loss', name=None, **kwargs):
 
         self.name = name
         self.system = system
@@ -713,7 +707,7 @@ class ModelChain(object):
 
         return self
 
-    def prepare_inputs(self, times=None, irradiance=None, weather=None):
+    def prepare_inputs(self, times=None, weather=None):
         """
         Prepare the solar position, irradiance, and weather inputs to
         the model.
@@ -723,8 +717,6 @@ class ModelChain(object):
         times : None or DatetimeIndex, default None
             Times at which to evaluate the model. Can be None if
             attribute `times` is already set.
-        irradiance : None or DataFrame
-            This parameter is deprecated. Please use `weather` instead.
         weather : None or DataFrame, default None
             If None, the weather attribute is used. If the weather
             attribute is also None assumes air temperature is 20 C, wind
@@ -747,19 +739,6 @@ class ModelChain(object):
         if self.weather is None:
             self.weather = pd.DataFrame()
 
-        # The following part could be removed together with the irradiance
-        # parameter at version v0.5 or v0.6.
-        # **** Begin ****
-        wrn_txt = ("The irradiance parameter will be removed soon.\n" +
-                   "Please use the weather parameter to pass a DataFrame " +
-                   "with irradiance (ghi, dni, dhi), wind speed and " +
-                   "temp_air.\n")
-        if irradiance is not None:
-            warnings.warn(wrn_txt, FutureWarning)
-            for column in irradiance.columns:
-                self.weather[column] = irradiance[column]
-        # **** End ****
-
         if times is not None:
             self.times = times
 
@@ -772,8 +751,8 @@ class ModelChain(object):
         if not any([x in ['ghi', 'dni', 'dhi'] for x in self.weather.columns]):
             self.weather[['ghi', 'dni', 'dhi']] = self.location.get_clearsky(
                 self.solar_position.index, self.clearsky_model,
-                zenith_data=self.solar_position['apparent_zenith'],
-                airmass_data=self.airmass['airmass_absolute'])
+                solar_position=self.solar_position,
+                airmass_absolute=self.airmass['airmass_absolute'])
 
         if not {'ghi', 'dni', 'dhi'} <= set(self.weather.columns):
             raise ValueError(
@@ -824,7 +803,7 @@ class ModelChain(object):
             self.weather['temp_air'] = 20
         return self
 
-    def run_model(self, times=None, irradiance=None, weather=None):
+    def run_model(self, times=None, weather=None):
         """
         Run the model.
 
@@ -833,8 +812,6 @@ class ModelChain(object):
         times : None or DatetimeIndex, default None
             Times at which to evaluate the model. Can be None if
             attribute `times` is already set.
-        irradiance : None or DataFrame
-            This parameter is deprecated. Please use `weather` instead.
         weather : None or DataFrame, default None
             If None, assumes air temperature is 20 C, wind speed is 0
             m/s and irradiation calculated from clear sky data. Column
@@ -852,7 +829,7 @@ class ModelChain(object):
         aoi_modifier, spectral_modifier, dc, ac, losses.
         """
 
-        self.prepare_inputs(times, irradiance, weather)
+        self.prepare_inputs(times, weather)
         self.aoi_model()
         self.spectral_model()
         self.effective_irradiance_model()
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
diff --git a/pvlib/tmy.py b/pvlib/tmy.py
index 111f2ba..371bd93 100644
--- a/pvlib/tmy.py
+++ b/pvlib/tmy.py
@@ -7,9 +7,9 @@ import datetime
 import dateutil
 import io
 try:
-    from urllib2 import urlopen
+    from urllib2 import urlopen, Request
 except ImportError:
-    from urllib.request import urlopen
+    from urllib.request import urlopen, Request
 
 import pandas as pd
 
@@ -164,14 +164,23 @@ def readtmy3(filename=None, coerce_year=None, recolumn=True):
 
     head = ['USAF', 'Name', 'State', 'TZ', 'latitude', 'longitude', 'altitude']
 
-    try:
-        csvdata = open(filename, 'r')
-    except IOError:
-        response = urlopen(filename)
+    if filename.startswith('http'):
+        request = Request(filename, headers={'User-Agent':
+            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_5) '
+            'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 '
+            'Safari/537.36'})
+        response = urlopen(request)
         csvdata = io.StringIO(response.read().decode(errors='ignore'))
+    else:
+        # assume it's accessible via the file system
+        csvdata = open(filename, 'r')
+
+    # read in file metadata, advance buffer to second line
+    firstline = csvdata.readline()
+    if 'Request Rejected' in firstline:
+        raise IOError('Remote server rejected TMY file request')
 
-    # read in file metadata
-    meta = dict(zip(head, csvdata.readline().rstrip('\n').split(",")))
+    meta = dict(zip(head, firstline.rstrip('\n').split(",")))
 
     # convert metadata strings to numeric types
     meta['altitude'] = float(meta['altitude'])
@@ -180,8 +189,12 @@ def readtmy3(filename=None, coerce_year=None, recolumn=True):
     meta['TZ'] = float(meta['TZ'])
     meta['USAF'] = int(meta['USAF'])
 
+    # use pandas to read the csv file/stringio buffer
+    # header is actually the second line in file, but tell pandas to look for
+    # header information on the 1st line (0 indexing) because we've already
+    # advanced past the true first line with the readline call above.
     data = pd.read_csv(
-        filename, header=1,
+        csvdata, header=0,
         parse_dates={'datetime': ['Date (MM/DD/YYYY)', 'Time (HH:MM)']},
         date_parser=lambda *x: _parsedate(*x, year=coerce_year),
         index_col='datetime')


Test patch:
diff --git a/pvlib/test/test_modelchain.py b/pvlib/test/test_modelchain.py
index de8ba04..225063d 100644
--- a/pvlib/test/test_modelchain.py
+++ b/pvlib/test/test_modelchain.py
@@ -463,21 +463,6 @@ def test_ModelChain___repr__(system, location, strategy, strategy_str):
     assert mc.__repr__() == expected
 
 
-@requires_scipy
-def test_weather_irradiance_input(system, location):
-    """Test will raise a warning and should be removed in future versions."""
-    mc = ModelChain(system, location)
-    times = pd.date_range('2012-06-01 12:00:00', periods=2, freq='H')
-    i = pd.DataFrame({'dni': [2, 3], 'dhi': [4, 6], 'ghi': [9, 5]}, index=times)
-    w = pd.DataFrame({'wind_speed': [11, 5], 'temp_air': [30, 32]}, index=times)
-    mc.run_model(times, irradiance=i, weather=w)
-
-    assert_series_equal(mc.weather['dni'],
-                        pd.Series([2, 3], index=times, name='dni'))
-    assert_series_equal(mc.weather['wind_speed'],
-                        pd.Series([11, 5], index=times, name='wind_speed'))
-
-
 @requires_scipy
 def test_complete_irradiance_clean_run(system, location):
     """The DataFrame should not change if all columns are passed"""
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.,