Repository: pvlib/pvlib-python (python)

Issue:
klucher results different between pandas and numpy
**Describe the bug**
call `pvlib.irradiance.klucher` with `dhi`, `ghi`, `solar_zenith`, `solar_azimuth` as `pd.Series` and you get different answers than if you user `np.array`

**To Reproduce**
Steps to reproduce the behavior:
```python
import pandas as pd
import numpy as np
import pvlib

surface_tilt = 32.0
surface_azimuth = 180.0
```
#### NumPy Array
```python
nda_apparent_zenith = np.array([
    124.039086298488, 82.8545704390216,10.5641356171064, 72.4168712240143
])  # solar zenith
nda_azimuth = np.array([
    352.695506991832, 66.7141033780672, 144.76567753998, 287.041041278537
])  # solar azimuth
nda_ghi = np.array([0, 79.8826605157945, 1042.48125969315, 257.25820554723])
nda_dhi = np.array([0, 40.4911557248134, 118.458383320548, 62.0343739267192])
# calculate klucher transposition
sky_np = pvlib.irradiance.klucher(
    surface_tilt=surface_tilt,
    surface_azimuth=surface_azimuth,
    dhi=nda_dhi,
    ghi=nda_ghi,
    solar_zenith=nda_apparent_zenith,
    solar_azimuth=nda_azimuth
)
# array([  0.        ,  37.41480162, 109.45839488,  57.32125332])
```
#### Pandas Series
```python
times = pd.date_range(start='2014-06-24', freq='6H', periods=4, tz='US/Arizona')
apparent_zenith = pd.Series(nda_apparent_zenith, index=times)
azimuth = pd.Series(nda_azimuth, index=times)
ghi = pd.Series(nda_ghi, index=times)
dhi = pd.Series(nda_dhi, index=times)
# calculate klucher transposition
sky_pd = pvlib.irradiance.klucher(
    surface_tilt=surface_tilt,
    surface_azimuth=surface_azimuth,
    dhi=dhi,
    ghi=ghi,
    solar_zenith=apparent_zenith,
    solar_azimuth=azimuth
)
# 2014-06-24 00:00:00-07:00      0.000000
# 2014-06-24 06:00:00-07:00     38.286085
# 2014-06-24 12:00:00-07:00    112.287559
# 2014-06-24 18:00:00-07:00     59.009638
# Freq: 6H, dtype: float64
```

**Expected behavior**
There is no difference in results between using Pandas and NumPy

**Versions:**
 - ``pvlib.__version__``: 0.5.1, 0.5.2
 - ``pandas.__version__``: 0.23.3
- `np.__version__`: 1.14.5
 - Python: 3.6.6 |Anaconda, Inc.| (default, Jun 28 2018, 11:27:44) [MSC v.1900 64 bit (AMD64)]

**Additional context**
[Issue is caused by different treatment of `NaN`.](../blob/v0.5.2/pvlib/irradiance.py#L624-L629) specifically if the GHI and DHI are both zero, then if the quotient is undefined or `NaN` - these lines try to use `pd.DataFrame.fillna(0)` which fails for NumPy, and the exception sets the `F` term to zero, instead of just the `NaN` values.

the fix is perhaps:
```python
   F = 1 - ((dhi / ghi) ** 2)
    try:
        # fails with single point input
        F.fillna(0, inplace=True)
    except AttributeError:
        F = np.where(np.isnan(F), 0, F)
```

Pull request description:
BUG: fix klucher nan output for numpy
* fixes #508
* use `F = np.where(np.isnan(F), 0, F)` to only replace `nan` with zero
* previously if numpy array with nan, then entire array was zeroed so output differed from pandas series input

pvlib python pull request guidelines
====================================

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.

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:

 - [x] Closes issue #xxxx
 - [ ] 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.
 - [ ] 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.

Brief description of the problem and proposed solution (if not already fully described in the issue linked to above):


Patch:
diff --git a/docs/sphinx/source/whatsnew/v0.6.0.rst b/docs/sphinx/source/whatsnew/v0.6.0.rst
index 009f015..1aa535c 100644
--- a/docs/sphinx/source/whatsnew/v0.6.0.rst
+++ b/docs/sphinx/source/whatsnew/v0.6.0.rst
@@ -59,7 +59,8 @@ Bug fixes
   Location.get_clearsky. Fixed. (:issue:`481`)
 * Add User-Agent specification to TMY3 remote requests to avoid rejection.
   (:issue:`493`)
-
+* Fix ``pvlib.irradiance.klucher`` output is different for Pandas Series vs.
+  floats and NumPy arrays. (:issue:`508`)
 
 Documentation
 ~~~~~~~~~~~~~
diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py
index fd03c3f..3006071 100644
--- a/pvlib/irradiance.py
+++ b/pvlib/irradiance.py
@@ -629,7 +629,7 @@ def klucher(surface_tilt, surface_azimuth, dhi, ghi, solar_zenith,
         # fails with single point input
         F.fillna(0, inplace=True)
     except AttributeError:
-        F = 0
+        F = np.where(np.isnan(F), 0, F)
 
     term1 = 0.5 * (1 + tools.cosd(surface_tilt))
     term2 = 1 + F * (tools.sind(0.5 * surface_tilt) ** 3)


Test patch:
diff --git a/pvlib/test/test_irradiance.py b/pvlib/test/test_irradiance.py
index ef9599e..31ebbcb 100644
--- a/pvlib/test/test_irradiance.py
+++ b/pvlib/test/test_irradiance.py
@@ -114,8 +114,20 @@ def test_isotropic_series():
 
 
 def test_klucher_series_float():
-    result = irradiance.klucher(40, 180, 100, 900, 20, 180)
-    assert_allclose(result, 88.3022221559)
+    # klucher inputs
+    surface_tilt, surface_azimuth = 40.0, 180.0
+    dhi, ghi = 100.0, 900.0
+    solar_zenith, solar_azimuth = 20.0, 180.0
+    # expect same result for floats and pd.Series
+    expected = irradiance.klucher(
+        surface_tilt, surface_azimuth,
+        pd.Series(dhi), pd.Series(ghi),
+        pd.Series(solar_zenith), pd.Series(solar_azimuth)
+    )  # 94.99429931664851
+    result = irradiance.klucher(
+        surface_tilt, surface_azimuth, dhi, ghi, solar_zenith, solar_azimuth
+    )
+    assert_allclose(result, expected[0])
 
 
 def test_klucher_series():
@@ -123,6 +135,12 @@ def test_klucher_series():
                        ephem_data['apparent_zenith'],
                        ephem_data['azimuth'])
     assert_allclose(result, [0, 37.446276, 109.209347, 56.965916], atol=1e-4)
+    # expect same result for np.array and pd.Series
+    expected = irradiance.klucher(
+        40, 180, irrad_data['dhi'].values, irrad_data['ghi'].values,
+        ephem_data['apparent_zenith'].values, ephem_data['azimuth'].values
+    )
+    assert_allclose(result, expected, atol=1e-4)
 
 
 def test_haydavies():