Repository: pvlib/pvlib-python
Pull request #398 (2017-11-15 23:35:25)

make physicaliam return a Series if called with a Series

 - [x] Closes issue #397
 - [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.

@cwhanse let me know if you want me to make any more changes to the docstring. It seemed to me that much of the information was repetitive, so I deleted it.


Patch:
diff --git a/docs/sphinx/source/whatsnew/v0.5.2.rst b/docs/sphinx/source/whatsnew/v0.5.2.rst
index b82d1f5..2c2c1db 100644
--- a/docs/sphinx/source/whatsnew/v0.5.2.rst
+++ b/docs/sphinx/source/whatsnew/v0.5.2.rst
@@ -14,10 +14,12 @@ Enhancements
 Bug fixes
 ~~~~~~~~~
 * fixed redeclaration of test_simplified_solis_series_elevation (:issue:`387`)
+* physicaliam now returns a Series if called with a Series as an
+  argument. (:issue:`397`)
 
 Documentation
 ~~~~~~~~~~~~~
-*
+* Improve physicaliam doc string. (:issue:`397`)
 
 Testing
 ~~~~~~~
diff --git a/pvlib/pvsystem.py b/pvlib/pvsystem.py
index b19cce5..40ef7c2 100644
--- a/pvlib/pvsystem.py
+++ b/pvlib/pvsystem.py
@@ -746,18 +746,17 @@ def ashraeiam(aoi, b=0.05):
 def physicaliam(aoi, n=1.526, K=4., L=0.002):
     '''
     Determine the incidence angle modifier using refractive index,
-    glazing thickness, and extinction coefficient
+    extinction coefficient, and glazing thickness.
 
     physicaliam calculates the incidence angle modifier as described in
     De Soto et al. "Improvement and validation of a model for
     photovoltaic array performance", section 3. The calculation is based
-    upon a physical model of absorbtion and transmission through a
-    cover. Required information includes, incident angle, cover
-    extinction coefficient, cover thickness
+    on a physical model of absorbtion and transmission through a
+    cover.
 
     Note: The authors of this function believe that eqn. 14 in [1] is
     incorrect. This function uses the following equation in its place:
-    theta_r = arcsin(1/n * sin(theta))
+    theta_r = arcsin(1/n * sin(aoi))
 
     Parameters
     ----------
@@ -788,14 +787,8 @@ def physicaliam(aoi, n=1.526, K=4., L=0.002):
 
     Returns
     -------
-    IAM : numeric
-        The incident angle modifier as specified in eqns. 14-16 of [1].
-        IAM is a column vector with the same number of elements as the
-        largest input vector.
-
-        Theta must be a numeric scalar or vector. For any values of
-        theta where abs(aoi)>90, IAM is set to 0. For any values of aoi
-        where -90 < aoi < 0, theta is set to abs(aoi) and evaluated.
+    iam : numeric
+        The incident angle modifier
 
     References
     ----------
@@ -816,6 +809,11 @@ def physicaliam(aoi, n=1.526, K=4., L=0.002):
     '''
     zeroang = 1e-06
 
+    # hold a new reference to the input aoi object since we're going to
+    # overwrite the aoi reference below, but we'll need it for the
+    # series check at the end of the function
+    aoi_input = aoi
+
     aoi = np.where(aoi == 0, zeroang, aoi)
 
     # angle of reflection
@@ -849,8 +847,8 @@ def physicaliam(aoi, n=1.526, K=4., L=0.002):
     # for light coming from behind the plane, none can enter the module
     iam = np.where(aoi > 90, 0, iam)
 
-    if isinstance(aoi, pd.Series):
-        iam = pd.Series(iam, index=aoi.index)
+    if isinstance(aoi_input, pd.Series):
+        iam = pd.Series(iam, index=aoi_input.index)
 
     return iam
 


Test patch:
diff --git a/pvlib/test/test_pvsystem.py b/pvlib/test/test_pvsystem.py
index c7e7345..53f01ea 100644
--- a/pvlib/test/test_pvsystem.py
+++ b/pvlib/test/test_pvsystem.py
@@ -114,12 +114,18 @@ def test_PVSystem_ashraeiam():
 
 @needs_numpy_1_10
 def test_physicaliam():
-    thetas = np.array([-90. , -67.5, -45. , -22.5,   0. ,  22.5,  45. ,  67.5,  90. , np.nan])
-    iam = pvsystem.physicaliam(thetas, 1.526, 0.002, 4)
+    aoi = np.array([-90. , -67.5, -45. , -22.5,   0. ,  22.5,  45. ,  67.5,  90. , np.nan])
+    iam = pvsystem.physicaliam(aoi, 1.526, 0.002, 4)
     expected = np.array([        0,  0.8893998,  0.98797788,  0.99926198,         1,
         0.99926198,  0.98797788,  0.8893998,         0, np.nan])
     assert_allclose(iam, expected, equal_nan=True)
 
+    # GitHub issue 397
+    aoi = pd.Series(aoi)
+    iam = pvsystem.physicaliam(aoi, 1.526, 0.002, 4)
+    expected = pd.Series(expected)
+    assert_series_equal(iam, expected)
+
 
 @needs_numpy_1_10
 def test_PVSystem_physicaliam():