Repository: pvlib/pvlib-python (python)

Issue:
pvwatts_ac returns values less than 0
**Describe the bug**
The pvwatts ac power model is proportional to the quantity ``eta`` as defined by

```
zeta = pdc / pdc0
eta = -0.0162*zeta - 0.0059/zeta + 0.9858
```

``eta`` is negative for ``eta < 0.006`` or so. While ac power less than 0 is not unphysical, I don't think the intention was for the PVWatts AC model to yield these values. I don't see any explicit reference to this in the PVWatts manual.

**To Reproduce**
Run ``pvwatts_ac`` with a pdc value that is less than 0.006 of pdc0.

**Expected behavior**
0 should be returned for these values instead.

**Screenshots**

![download-5](https://user-images.githubusercontent.com/4383303/44425810-d16f7500-a541-11e8-86db-026d8324f30f.png)


**Versions:**
 - ``pvlib.__version__``: '0.5.2+35.g0aa4d2e'
 - ``pandas.__version__``: n/a
 - python: n/a



Pull request description:
limit pvwatts_ac results to greater than equal to 0
 - [x] Closes #541 
 - [x] I am familiar with the [contributing guidelines](http://pvlib-python.readthedocs.io/en/latest/contributing.html).
 - [x] 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.
 - [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.
 - [x] Code quality and style is sufficient. Passes ``git diff upstream/master -u -- "*.py" | flake8 --diff``
 - [x] 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.

I confirmed that the new test fails without the fix.


Patch:
diff --git a/docs/sphinx/source/index.rst b/docs/sphinx/source/index.rst
index f1106b1..894cccd 100644
--- a/docs/sphinx/source/index.rst
+++ b/docs/sphinx/source/index.rst
@@ -71,6 +71,7 @@ Contents
    :maxdepth: 1
 
    package_overview
+   introexamples
    whatsnew
    installation
    contributing
diff --git a/docs/sphinx/source/introexamples.rst b/docs/sphinx/source/introexamples.rst
new file mode 100644
index 0000000..56f11cc
--- /dev/null
+++ b/docs/sphinx/source/introexamples.rst
@@ -0,0 +1,255 @@
+.. _introexamples:
+
+Intro Examples
+==============
+
+This page contains introductory examples of pvlib python usage.
+
+.. _modeling-paradigms:
+
+Modeling paradigms
+------------------
+
+The backbone of pvlib-python
+is well-tested procedural code that implements PV system models.
+pvlib-python also provides a collection of classes for users
+that prefer object-oriented programming.
+These classes can help users keep track of data in a more organized way,
+provide some "smart" functions with more flexible inputs,
+and simplify the modeling process for common situations.
+The classes do not add any algorithms beyond what's available
+in the procedural code, and most of the object methods
+are simple wrappers around the corresponding procedural code.
+
+Let's use each of these pvlib modeling paradigms
+to calculate the yearly energy yield for a given hardware
+configuration at a handful of sites listed below.
+
+.. ipython:: python
+
+    import pandas as pd
+    import matplotlib.pyplot as plt
+
+    naive_times = pd.DatetimeIndex(start='2015', end='2016', freq='1h')
+
+    # very approximate
+    # latitude, longitude, name, altitude, timezone
+    coordinates = [(30, -110, 'Tucson', 700, 'Etc/GMT+7'),
+                   (35, -105, 'Albuquerque', 1500, 'Etc/GMT+7'),
+                   (40, -120, 'San Francisco', 10, 'Etc/GMT+8'),
+                   (50, 10, 'Berlin', 34, 'Etc/GMT-1')]
+
+    import pvlib
+
+    # get the module and inverter specifications from SAM
+    sandia_modules = pvlib.pvsystem.retrieve_sam('SandiaMod')
+    sapm_inverters = pvlib.pvsystem.retrieve_sam('cecinverter')
+    module = sandia_modules['Canadian_Solar_CS5P_220M___2009_']
+    inverter = sapm_inverters['ABB__MICRO_0_25_I_OUTD_US_208_208V__CEC_2014_']
+
+    # specify constant ambient air temp and wind for simplicity
+    temp_air = 20
+    wind_speed = 0
+
+
+Procedural
+^^^^^^^^^^
+
+The straightforward procedural code can be used for all modeling
+steps in pvlib-python.
+
+The following code demonstrates how to use the procedural code
+to accomplish our system modeling goal:
+
+.. ipython:: python
+
+    system = {'module': module, 'inverter': inverter,
+              'surface_azimuth': 180}
+
+    energies = {}
+
+    for latitude, longitude, name, altitude, timezone in coordinates:
+        times = naive_times.tz_localize(timezone)
+        system['surface_tilt'] = latitude
+        solpos = pvlib.solarposition.get_solarposition(times, latitude, longitude)
+        dni_extra = pvlib.irradiance.get_extra_radiation(times)
+        airmass = pvlib.atmosphere.get_relative_airmass(solpos['apparent_zenith'])
+        pressure = pvlib.atmosphere.alt2pres(altitude)
+        am_abs = pvlib.atmosphere.get_absolute_airmass(airmass, pressure)
+        tl = pvlib.clearsky.lookup_linke_turbidity(times, latitude, longitude)
+        cs = pvlib.clearsky.ineichen(solpos['apparent_zenith'], am_abs, tl,
+                                     dni_extra=dni_extra, altitude=altitude)
+        aoi = pvlib.irradiance.aoi(system['surface_tilt'], system['surface_azimuth'],
+                                   solpos['apparent_zenith'], solpos['azimuth'])
+        total_irrad = pvlib.irradiance.get_total_irradiance(system['surface_tilt'],
+                                                            system['surface_azimuth'],
+                                                            solpos['apparent_zenith'],
+                                                            solpos['azimuth'],
+                                                            cs['dni'], cs['ghi'], cs['dhi'],
+                                                            dni_extra=dni_extra,
+                                                            model='haydavies')
+        temps = pvlib.pvsystem.sapm_celltemp(total_irrad['poa_global'],
+                                             wind_speed, temp_air)
+        effective_irradiance = pvlib.pvsystem.sapm_effective_irradiance(
+            total_irrad['poa_direct'], total_irrad['poa_diffuse'],
+            am_abs, aoi, module)
+        dc = pvlib.pvsystem.sapm(effective_irradiance, temps['temp_cell'], module)
+        ac = pvlib.pvsystem.snlinverter(dc['v_mp'], dc['p_mp'], inverter)
+        annual_energy = ac.sum()
+        energies[name] = annual_energy
+
+    energies = pd.Series(energies)
+
+    # based on the parameters specified above, these are in W*hrs
+    print(energies.round(0))
+
+    energies.plot(kind='bar', rot=0)
+    @savefig proc-energies.png width=6in
+    plt.ylabel('Yearly energy yield (W hr)')
+    @suppress
+    plt.close();
+
+
+.. _object-oriented:
+
+Object oriented (Location, PVSystem, ModelChain)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The first object oriented paradigm uses a model where a
+:py:class:`~pvlib.pvsystem.PVSystem` object represents an assembled
+collection of modules, inverters, etc., a
+:py:class:`~pvlib.location.Location` object represents a particular
+place on the planet, and a :py:class:`~pvlib.modelchain.ModelChain`
+object describes the modeling chain used to calculate PV output at that
+Location. This can be a useful paradigm if you prefer to think about the
+PV system and its location as separate concepts or if you develop your
+own ModelChain subclasses. It can also be helpful if you make extensive
+use of Location-specific methods for other calculations. pvlib-python
+also includes a :py:class:`~pvlib.tracking.SingleAxisTracker` class that
+is a subclass of :py:class:`~pvlib.pvsystem.PVSystem`.
+
+The following code demonstrates how to use
+:py:class:`~pvlib.location.Location`,
+:py:class:`~pvlib.pvsystem.PVSystem`, and
+:py:class:`~pvlib.modelchain.ModelChain` objects to accomplish our
+system modeling goal. ModelChain objects provide convenience methods
+that can provide default selections for models and can also fill
+necessary input data with modeled data. In our example below, we use
+convenience methods. For example, no irradiance data is provided as
+input, so the ModelChain object substitutes irradiance from a clear-sky
+model via the prepare_inputs method. Also, no irradiance transposition
+model is specified (keyword argument `transposition` for ModelChain) so
+the ModelChain defaults to the `haydavies` model. In this example,
+ModelChain infers the DC power model from the module provided by
+examining the parameters defined for module.
+
+.. ipython:: python
+
+    from pvlib.pvsystem import PVSystem
+    from pvlib.location import Location
+    from pvlib.modelchain import ModelChain
+
+    system = PVSystem(module_parameters=module,
+                      inverter_parameters=inverter)
+
+    energies = {}
+    for latitude, longitude, name, altitude, timezone in coordinates:
+        times = naive_times.tz_localize(timezone)
+        location = Location(latitude, longitude, name=name, altitude=altitude,
+                            tz=timezone)
+        # very experimental
+        mc = ModelChain(system, location,
+                        orientation_strategy='south_at_latitude_tilt')
+        # model results (ac, dc) and intermediates (aoi, temps, etc.)
+        # assigned as mc object attributes
+        mc.run_model(times)
+        annual_energy = mc.ac.sum()
+        energies[name] = annual_energy
+
+    energies = pd.Series(energies)
+
+    # based on the parameters specified above, these are in W*hrs
+    print(energies.round(0))
+
+    energies.plot(kind='bar', rot=0)
+    @savefig modelchain-energies.png width=6in
+    plt.ylabel('Yearly energy yield (W hr)')
+    @suppress
+    plt.close();
+
+
+Object oriented (LocalizedPVSystem)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The second object oriented paradigm uses a model where a
+:py:class:`~pvlib.pvsystem.LocalizedPVSystem` represents a PV system at
+a particular place on the planet. This can be a useful paradigm if
+you're thinking about a power plant that already exists.
+
+The :py:class:`~pvlib.pvsystem.LocalizedPVSystem` inherits from both
+:py:class:`~pvlib.pvsystem.PVSystem` and
+:py:class:`~pvlib.location.Location`, while the
+:py:class:`~pvlib.tracking.LocalizedSingleAxisTracker` inherits from
+:py:class:`~pvlib.tracking.SingleAxisTracker` (itself a subclass of
+:py:class:`~pvlib.pvsystem.PVSystem`) and
+:py:class:`~pvlib.location.Location`. The
+:py:class:`~pvlib.pvsystem.LocalizedPVSystem` and
+:py:class:`~pvlib.tracking.LocalizedSingleAxisTracker` classes may
+contain bugs due to the relative difficulty of implementing multiple
+inheritance. The :py:class:`~pvlib.pvsystem.LocalizedPVSystem` and
+:py:class:`~pvlib.tracking.LocalizedSingleAxisTracker` may be deprecated
+in a future release. We recommend that most modeling workflows implement
+:py:class:`~pvlib.location.Location`,
+:py:class:`~pvlib.pvsystem.PVSystem`, and
+:py:class:`~pvlib.modelchain.ModelChain`.
+
+The following code demonstrates how to use a
+:py:class:`~pvlib.pvsystem.LocalizedPVSystem` object to accomplish our
+modeling goal:
+
+.. ipython:: python
+
+    from pvlib.pvsystem import LocalizedPVSystem
+
+    energies = {}
+    for latitude, longitude, name, altitude, timezone in coordinates:
+        localized_system = LocalizedPVSystem(module_parameters=module,
+                                             inverter_parameters=inverter,
+                                             surface_tilt=latitude,
+                                             surface_azimuth=180,
+                                             latitude=latitude,
+                                             longitude=longitude,
+                                             name=name,
+                                             altitude=altitude,
+                                             tz=timezone)
+        times = naive_times.tz_localize(timezone)
+        clearsky = localized_system.get_clearsky(times)
+        solar_position = localized_system.get_solarposition(times)
+        total_irrad = localized_system.get_irradiance(solar_position['apparent_zenith'],
+                                                      solar_position['azimuth'],
+                                                      clearsky['dni'],
+                                                      clearsky['ghi'],
+                                                      clearsky['dhi'])
+        temps = localized_system.sapm_celltemp(total_irrad['poa_global'],
+                                               wind_speed, temp_air)
+        aoi = localized_system.get_aoi(solar_position['apparent_zenith'],
+                                       solar_position['azimuth'])
+        airmass = localized_system.get_airmass(solar_position=solar_position)
+        effective_irradiance = localized_system.sapm_effective_irradiance(
+            total_irrad['poa_direct'], total_irrad['poa_diffuse'],
+            airmass['airmass_absolute'], aoi)
+        dc = localized_system.sapm(effective_irradiance, temps['temp_cell'])
+        ac = localized_system.snlinverter(dc['v_mp'], dc['p_mp'])
+        annual_energy = ac.sum()
+        energies[name] = annual_energy
+
+    energies = pd.Series(energies)
+
+    # based on the parameters specified above, these are in W*hrs
+    print(energies.round(0))
+
+    energies.plot(kind='bar', rot=0)
+    @savefig localized-pvsystem-energies.png width=6in
+    plt.ylabel('Yearly energy yield (W hr)')
+    @suppress
+    plt.close();
diff --git a/docs/sphinx/source/package_overview.rst b/docs/sphinx/source/package_overview.rst
index 540e153..a5cf1eb 100644
--- a/docs/sphinx/source/package_overview.rst
+++ b/docs/sphinx/source/package_overview.rst
@@ -10,278 +10,10 @@ The core mission of pvlib-python is to provide open, reliable,
 interoperable, and benchmark implementations of PV system models.
 
 There are at least as many opinions about how to model PV systems as
-there are modelers of PV systems, so
-pvlib-python provides several modeling paradigms.
-
-
-.. _modeling-paradigms:
-
-Modeling paradigms
-------------------
-
-The backbone of pvlib-python
-is well-tested procedural code that implements PV system models.
-pvlib-python also provides a collection of classes for users
-that prefer object-oriented programming.
-These classes can help users keep track of data in a more organized way,
-provide some "smart" functions with more flexible inputs,
-and simplify the modeling process for common situations.
-The classes do not add any algorithms beyond what's available
-in the procedural code, and most of the object methods
-are simple wrappers around the corresponding procedural code.
-
-Let's use each of these pvlib modeling paradigms
-to calculate the yearly energy yield for a given hardware
-configuration at a handful of sites listed below.
-
-.. ipython:: python
-
-    import pandas as pd
-    import matplotlib.pyplot as plt
-
-    naive_times = pd.DatetimeIndex(start='2015', end='2016', freq='1h')
-
-    # very approximate
-    # latitude, longitude, name, altitude, timezone
-    coordinates = [(30, -110, 'Tucson', 700, 'Etc/GMT+7'),
-                   (35, -105, 'Albuquerque', 1500, 'Etc/GMT+7'),
-                   (40, -120, 'San Francisco', 10, 'Etc/GMT+8'),
-                   (50, 10, 'Berlin', 34, 'Etc/GMT-1')]
-
-    import pvlib
-
-    # get the module and inverter specifications from SAM
-    sandia_modules = pvlib.pvsystem.retrieve_sam('SandiaMod')
-    sapm_inverters = pvlib.pvsystem.retrieve_sam('cecinverter')
-    module = sandia_modules['Canadian_Solar_CS5P_220M___2009_']
-    inverter = sapm_inverters['ABB__MICRO_0_25_I_OUTD_US_208_208V__CEC_2014_']
-
-    # specify constant ambient air temp and wind for simplicity
-    temp_air = 20
-    wind_speed = 0
-
-
-Procedural
-^^^^^^^^^^
-
-The straightforward procedural code can be used for all modeling
-steps in pvlib-python.
-
-The following code demonstrates how to use the procedural code
-to accomplish our system modeling goal:
-
-.. ipython:: python
-
-    system = {'module': module, 'inverter': inverter,
-              'surface_azimuth': 180}
-
-    energies = {}
-
-    for latitude, longitude, name, altitude, timezone in coordinates:
-        times = naive_times.tz_localize(timezone)
-        system['surface_tilt'] = latitude
-        solpos = pvlib.solarposition.get_solarposition(times, latitude, longitude)
-        dni_extra = pvlib.irradiance.get_extra_radiation(times)
-        dni_extra = pd.Series(dni_extra, index=times)
-        airmass = pvlib.atmosphere.get_relative_airmass(solpos['apparent_zenith'])
-        pressure = pvlib.atmosphere.alt2pres(altitude)
-        am_abs = pvlib.atmosphere.get_absolute_airmass(airmass, pressure)
-        tl = pvlib.clearsky.lookup_linke_turbidity(times, latitude, longitude)
-        cs = pvlib.clearsky.ineichen(solpos['apparent_zenith'], am_abs, tl,
-                                     dni_extra=dni_extra, altitude=altitude)
-        aoi = pvlib.irradiance.aoi(system['surface_tilt'], system['surface_azimuth'],
-                                   solpos['apparent_zenith'], solpos['azimuth'])
-        total_irrad = pvlib.irradiance.get_total_irradiance(system['surface_tilt'],
-                                                            system['surface_azimuth'],
-                                                            solpos['apparent_zenith'],
-                                                            solpos['azimuth'],
-                                                            cs['dni'], cs['ghi'], cs['dhi'],
-                                                            dni_extra=dni_extra,
-                                                            model='haydavies')
-        temps = pvlib.pvsystem.sapm_celltemp(total_irrad['poa_global'],
-                                             wind_speed, temp_air)
-        effective_irradiance = pvlib.pvsystem.sapm_effective_irradiance(
-            total_irrad['poa_direct'], total_irrad['poa_diffuse'],
-            am_abs, aoi, module)
-        dc = pvlib.pvsystem.sapm(effective_irradiance, temps['temp_cell'], module)
-        ac = pvlib.pvsystem.snlinverter(dc['v_mp'], dc['p_mp'], inverter)
-        annual_energy = ac.sum()
-        energies[name] = annual_energy
-
-    energies = pd.Series(energies)
-
-    # based on the parameters specified above, these are in W*hrs
-    print(energies.round(0))
-
-    energies.plot(kind='bar', rot=0)
-    @savefig proc-energies.png width=6in
-    plt.ylabel('Yearly energy yield (W hr)')
-    @suppress
-    plt.close();
-
-pvlib-python provides a :py:func:`~pvlib.modelchain.basic_chain`
-function that implements much of the code above. Use this function with
-a full understanding of what it is doing internally!
-
-.. ipython:: python
-
-    from pvlib.modelchain import basic_chain
-
-    energies = {}
-    for latitude, longitude, name, altitude, timezone in coordinates:
-        dc, ac = basic_chain(naive_times.tz_localize(timezone),
-                             latitude, longitude,
-                             module, inverter,
-                             altitude=altitude,
-                             orientation_strategy='south_at_latitude_tilt')
-        annual_energy = ac.sum()
-        energies[name] = annual_energy
-
-    energies = pd.Series(energies)
-
-    # based on the parameters specified above, these are in W*hrs
-    print(energies.round(0))
-
-    energies.plot(kind='bar', rot=0)
-    @savefig basic-chain-energies.png width=6in
-    plt.ylabel('Yearly energy yield (W hr)')
-    @suppress
-    plt.close();
-
-
-.. _object-oriented:
-
-Object oriented (Location, PVSystem, ModelChain)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The first object oriented paradigm uses a model where a
-:py:class:`~pvlib.pvsystem.PVSystem` object represents an assembled
-collection of modules, inverters, etc., a
-:py:class:`~pvlib.location.Location` object represents a particular
-place on the planet, and a :py:class:`~pvlib.modelchain.ModelChain`
-object describes the modeling chain used to calculate PV output at that
-Location. This can be a useful paradigm if you prefer to think about the
-PV system and its location as separate concepts or if you develop your
-own ModelChain subclasses. It can also be helpful if you make extensive
-use of Location-specific methods for other calculations. pvlib-python
-also includes a :py:class:`~pvlib.tracking.SingleAxisTracker` class that
-is a subclass of :py:class:`~pvlib.pvsystem.PVSystem`.
-
-The following code demonstrates how to use
-:py:class:`~pvlib.location.Location`,
-:py:class:`~pvlib.pvsystem.PVSystem`, and
-:py:class:`~pvlib.modelchain.ModelChain` objects to accomplish our
-system modeling goal:
-
-.. ipython:: python
-
-    from pvlib.pvsystem import PVSystem
-    from pvlib.location import Location
-    from pvlib.modelchain import ModelChain
-
-    system = PVSystem(module_parameters=module,
-                      inverter_parameters=inverter)
-
-    energies = {}
-    for latitude, longitude, name, altitude, timezone in coordinates:
-        location = Location(latitude, longitude, name=name, altitude=altitude,
-                            tz=timezone)
-        # very experimental
-        mc = ModelChain(system, location,
-                        orientation_strategy='south_at_latitude_tilt')
-        # model results (ac, dc) and intermediates (aoi, temps, etc.)
-        # assigned as mc object attributes
-        mc.run_model(naive_times.tz_localize(timezone))
-        annual_energy = mc.ac.sum()
-        energies[name] = annual_energy
-
-    energies = pd.Series(energies)
-
-    # based on the parameters specified above, these are in W*hrs
-    print(energies.round(0))
-
-    energies.plot(kind='bar', rot=0)
-    @savefig modelchain-energies.png width=6in
-    plt.ylabel('Yearly energy yield (W hr)')
-    @suppress
-    plt.close();
-
-
-Object oriented (LocalizedPVSystem)
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The second object oriented paradigm uses a model where a
-:py:class:`~pvlib.pvsystem.LocalizedPVSystem` represents a PV system at
-a particular place on the planet. This can be a useful paradigm if
-you're thinking about a power plant that already exists.
-
-The :py:class:`~pvlib.pvsystem.LocalizedPVSystem` inherits from both
-:py:class:`~pvlib.pvsystem.PVSystem` and
-:py:class:`~pvlib.location.Location`, while the
-:py:class:`~pvlib.tracking.LocalizedSingleAxisTracker` inherits from
-:py:class:`~pvlib.tracking.SingleAxisTracker` (itself a subclass of
-:py:class:`~pvlib.pvsystem.PVSystem`) and
-:py:class:`~pvlib.location.Location`. The
-:py:class:`~pvlib.pvsystem.LocalizedPVSystem` and
-:py:class:`~pvlib.tracking.LocalizedSingleAxisTracker` classes may
-contain bugs due to the relative difficulty of implementing multiple
-inheritance. The :py:class:`~pvlib.pvsystem.LocalizedPVSystem` and
-:py:class:`~pvlib.tracking.LocalizedSingleAxisTracker` may be deprecated
-in a future release. We recommend that most modeling workflows implement
-:py:class:`~pvlib.location.Location`,
-:py:class:`~pvlib.pvsystem.PVSystem`, and
-:py:class:`~pvlib.modelchain.ModelChain`.
-
-The following code demonstrates how to use a
-:py:class:`~pvlib.pvsystem.LocalizedPVSystem` object to accomplish our
-modeling goal:
-
-.. ipython:: python
-
-    from pvlib.pvsystem import LocalizedPVSystem
-
-    energies = {}
-    for latitude, longitude, name, altitude, timezone in coordinates:
-        localized_system = LocalizedPVSystem(module_parameters=module,
-                                             inverter_parameters=inverter,
-                                             surface_tilt=latitude,
-                                             surface_azimuth=180,
-                                             latitude=latitude,
-                                             longitude=longitude,
-                                             name=name,
-                                             altitude=altitude,
-                                             tz=timezone)
-        times = naive_times.tz_localize(timezone)
-        clearsky = localized_system.get_clearsky(times)
-        solar_position = localized_system.get_solarposition(times)
-        total_irrad = localized_system.get_irradiance(solar_position['apparent_zenith'],
-                                                      solar_position['azimuth'],
-                                                      clearsky['dni'],
-                                                      clearsky['ghi'],
-                                                      clearsky['dhi'])
-        temps = localized_system.sapm_celltemp(total_irrad['poa_global'],
-                                               wind_speed, temp_air)
-        aoi = localized_system.get_aoi(solar_position['apparent_zenith'],
-                                       solar_position['azimuth'])
-        airmass = localized_system.get_airmass(solar_position=solar_position)
-        effective_irradiance = localized_system.sapm_effective_irradiance(
-            total_irrad['poa_direct'], total_irrad['poa_diffuse'],
-            airmass['airmass_absolute'], aoi)
-        dc = localized_system.sapm(effective_irradiance, temps['temp_cell'])
-        ac = localized_system.snlinverter(dc['v_mp'], dc['p_mp'])
-        annual_energy = ac.sum()
-        energies[name] = annual_energy
-
-    energies = pd.Series(energies)
-
-    # based on the parameters specified above, these are in W*hrs
-    print(energies.round(0))
-
-    energies.plot(kind='bar', rot=0)
-    @savefig localized-pvsystem-energies.png width=6in
-    plt.ylabel('Yearly energy yield (W hr)')
-    @suppress
-    plt.close();
+there are modelers of PV systems, so pvlib-python provides several
+modeling paradigms: functions, the Location/PVSystem classes, and the
+ModelChain class. Read more about this in the :ref:`introexamples`
+section.
 
 
 User extensions
@@ -318,8 +50,10 @@ Credits
 The pvlib-python community thanks Sandia National Lab
 for developing PVLIB Matlab and for supporting
 Rob Andrews of Calama Consulting to port the library to Python.
-Will Holmgren thanks the DOE EERE Postdoctoral Fellowship program
-for support from 2014-2016.
+Will Holmgren thanks the Department of Energy's Energy
+Efficiency and Renewable Energy Postdoctoral Fellowship Program
+(2014-2016), the University of Arizona Institute for Energy Solutions (2017-2018),
+and the DOE Solar Forecasting 2 program (2018).
 The pvlib-python maintainers thank all of pvlib's contributors of issues
 and especially pull requests.
 The pvlib-python community thanks all of the
diff --git a/docs/sphinx/source/whatsnew/v0.6.0.rst b/docs/sphinx/source/whatsnew/v0.6.0.rst
index e992c81..df8b307 100644
--- a/docs/sphinx/source/whatsnew/v0.6.0.rst
+++ b/docs/sphinx/source/whatsnew/v0.6.0.rst
@@ -118,6 +118,7 @@ Bug fixes
   Hay-Davies diffuse sky algorithms. (:issue:`432`)
 * Fix argument order of longitude and latitude when querying weather forecasts
   by lonlat bounding box (:issue:`521`)
+* Limit pvwatts_ac results to be greater than or equal to 0. (:issue:`541`)
 
 
 Documentation
@@ -132,6 +133,8 @@ Documentation
 * Minor improvements and updates to installation documentation. (:issue:`531`)
 * Improve LocalizedPVSystem and LocalizedSingleAxisTracker documentation.
   (:issue:`532`)
+* Move the "Getting Started"/"Modeling Paradigms" section to a new
+  top-level "Intro Examples" page.
 * Copy pvlib documentation's "Getting support" section to README.md.
 
 
diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py
index 99e1d0f..a7283d1 100644
--- a/pvlib/pvsystem.py
+++ b/pvlib/pvsystem.py
@@ -2693,9 +2693,11 @@ def pvwatts_ac(pdc, pdc0, eta_inv_nom=0.96, eta_inv_ref=0.9637):
     pac0 = eta_inv_nom * pdc0
     zeta = pdc / pdc0
 
+    # eta < 0 if zeta < 0.006. pac is forced to be >= 0 below. GH 541
     eta = eta_inv_nom / eta_inv_ref * (-0.0162*zeta - 0.0059/zeta + 0.9858)
 
     pac = eta * pdc
     pac = np.minimum(pac0, pac)
+    pac = np.maximum(0, pac)     # GH 541
 
     return pac


Test patch:
diff --git a/pvlib/test/test_pvsystem.py b/pvlib/test/test_pvsystem.py
index 91b90dd..9315d73 100644
--- a/pvlib/test/test_pvsystem.py
+++ b/pvlib/test/test_pvsystem.py
@@ -1275,6 +1275,14 @@ def test_pvwatts_ac_scalars():
     assert_allclose(out, expected)
 
 
+def test_pvwatts_ac_possible_negative():
+    # pvwatts_ac could return a negative value for (pdc / pdc0) < 0.006
+    # unless it is clipped. see GH 541 for more
+    expected = 0
+    out = pvsystem.pvwatts_ac(0.001, 1)
+    assert_allclose(out, expected)
+
+
 @needs_numpy_1_10
 def test_pvwatts_ac_arrays():
     pdc = np.array([[np.nan], [50], [100]])