Skip to content

ModelChainResult.__repr__ - #1236

Merged
kandersolar merged 12 commits into
pvlib:mainfrom
cwhanse:mcres_repr
Jun 23, 2023
Merged

ModelChainResult.__repr__#1236
kandersolar merged 12 commits into
pvlib:mainfrom
cwhanse:mcres_repr

Conversation

@cwhanse

@cwhansecwhanse commented May 18, 2021

Copy link
Copy Markdown
Member
  • ClosesImprove ModelChainResult.__repr__ #1110
  • I am familiar with the contributing guidelines
  • [ ] Tests added
  • Updates entries to docs/sphinx/source/api.rst for API changes.
  • [ ] Adds description and name entries in the appropriate "what's new" file in docs/sphinx/source/whatsnew for all changes. Includes link to the GitHub Issue with :issue:`num` or this Pull Request with :pull:`num`. Includes contributor name and/or GitHub username (link with :ghuser:`user`).
  • New code is fully documented. Includes numpydoc compliant docstrings, examples, and comments where necessary.
  • Pull request is nearly complete and ready for detailed review.
  • Maintainer: Appropriate GitHub Labels and Milestone are assigned to the Pull Request and linked Issue.

@cwhanse

Copy link
Copy Markdown
MemberAuthor

I'm not unhappy with the print of ModelChainResult here. The code is clumsy, because ModelChainResult doesn't hew to any standards for the type of each attribute (e.g., with 2 Arrays, the value can be None, a single float, or a tuple of something).

Here's what the report looks like for a simple ModelChain (system with one Array). I'm "head"ing any Series or DataFrames.

Any if you read this far, look at the name of the last Series for ModelChainResult.ac.

=== ModelChainResult === weather ghi dhi ... temp_air wind_speed
2023-06-10 10:00:00-07:00 775.999173 108.933862 ... 25 0
2023-06-10 11:00:00-07:00 898.985531 116.633882 ... 25 0
2023-06-10 12:00:00-07:00 969.592761 120.879109 ... 25 0
2023-06-10 13:00:00-07:00 982.786788 121.660833 ... 25 0
2023-06-10 14:00:00-07:00 937.637996 118.971374 ... 25 0
[5 rows x 5 columns] solar_position apparent_zenith ... equation_of_time
2023-06-10 10:00:00-07:00 37.382226 ... 0.539325
2023-06-10 11:00:00-07:00 25.474558 ... 0.530968
2023-06-10 12:00:00-07:00 15.254955 ... 0.522605
2023-06-10 13:00:00-07:00 12.488151 ... 0.514235
2023-06-10 14:00:00-07:00 20.492312 ... 0.505857
[5 rows x 6 columns] airmass airmass_relative airmass_absolute
2023-06-10 10:00:00-07:00 1.257469 1.257469
2023-06-10 11:00:00-07:00 1.107109 1.107109
2023-06-10 12:00:00-07:00 1.036112 1.036112
2023-06-10 13:00:00-07:00 1.023853 1.023853
2023-06-10 14:00:00-07:00 1.067070 1.067070 Number of Arrays: 1 ------------------- Array 0 ------------------- tracking None aoi 2023-06-10 10:00:00-07:00 37.382226
2023-06-10 11:00:00-07:00 25.474558
2023-06-10 12:00:00-07:00 15.254955
2023-06-10 13:00:00-07:00 12.488151
2023-06-10 14:00:00-07:00 20.492312
Freq: H, Name: aoi, dtype: float64 aoi_modifier 1.0 total_irrad poa_global ... poa_ground_diffuse
2023-06-10 10:00:00-07:00 775.994182 ... 0.0
2023-06-10 11:00:00-07:00 898.983256 ... 0.0
2023-06-10 12:00:00-07:00 969.591954 ... 0.0
2023-06-10 13:00:00-07:00 982.786249 ... 0.0
2023-06-10 14:00:00-07:00 937.636532 ... 0.0
[5 rows x 5 columns] spectral_modifier 1 effective_irradiance 2023-06-10 10:00:00-07:00 775.994182
2023-06-10 11:00:00-07:00 898.983256
2023-06-10 12:00:00-07:00 969.591954
2023-06-10 13:00:00-07:00 982.786249
2023-06-10 14:00:00-07:00 937.636532
Freq: H, dtype: float64 cell_temperature 2023-06-10 10:00:00-07:00 51.474617
2023-06-10 11:00:00-07:00 55.670639
2023-06-10 12:00:00-07:00 58.079598
2023-06-10 13:00:00-07:00 58.529749
2023-06-10 14:00:00-07:00 56.989374
Freq: H, dtype: float64 dc 2023-06-10 10:00:00-07:00 173.454396
2023-06-10 11:00:00-07:00 197.173423
2023-06-10 12:00:00-07:00 210.324276
2023-06-10 13:00:00-07:00 212.743986
2023-06-10 14:00:00-07:00 204.414727
Freq: H, Name: p_mp, dtype: float64 dc_ohmic_losses None End of Arrays ------------------- losses 1 ac 2023-06-10 10:00:00-07:00 166.923393
2023-06-10 11:00:00-07:00 189.648371
2023-06-10 12:00:00-07:00 202.216782
2023-06-10 13:00:00-07:00 204.526893
2023-06-10 14:00:00-07:00 196.571725
Freq: H, Name: p_mp, dtype: float64 

@cwhanse
cwhanse marked this pull request as ready for review June 22, 2023 16:42
@cwhanse

Copy link
Copy Markdown
MemberAuthor

@kandersolar your call if this is for v0.10 or later.

@kandersolar

Copy link
Copy Markdown
Member

I think using head for each attribute takes up a ton of space in the output just to display what is going to be mostly boring nighttime values for most simulations. How about just showing the type and shape of the data, but not any actual values? For example, something like this:

ModelChainResult:
weather: DataFrame (145 rows x 5 columns)
solar_position: DataFrame (145 rows x 6 columns)
airmass: DataFrame (145 rows x 2 columns)
tracking: None
aoi: Tuple (Series (length 145), Series (length 145))
aoi_modifier: Tuple (Series (length 145), Series (length 145))
total_irrad: Tuple (DataFrame (145 rows x 5 columns), DataFrame (145 rows x 5 columns))
spectral_modifier: Tuple (1, 1)
effective_irradiance: Tuple (Series (length 145), Series (length 145))
cell_temperature: Tuple (Series (length 145), Series (length 145))
dc: Tuple (Series (length 145), Series (length 145))
dc_ohmic_losses: None
losses: 1
ac: Series (length 145)

Code for the above:

def_mcr_repr(obj):
ifisinstance(obj, tuple):
return"Tuple ("+", ".join([_mcr_repr(o) foroinobj]) +")"ifisinstance(obj, pd.DataFrame):
return"DataFrame ({} rows x {} columns)".format(*obj.shape)
ifisinstance(obj, pd.Series):
return"Series (length {})".format(len(obj))
# scalar, None, other?returnrepr(obj)
def__repr__(self):
lines= ['ModelChainResult:']
attrs= [
'weather', 'solar_position', 'airmass',
'tracking', 'aoi', 'aoi_modifier', 'total_irrad', 'spectral_modifier',
'effective_irradiance', 'cell_temperature', 'dc', 'dc_ohmic_losses', 'losses', 'ac'
]
forattrinattrs:
lines.append(f" {attr}: "+_mcr_repr(getattr(self, attr)))
return"\n".join(lines)

@cwhanse

cwhanse commented Jun 23, 2023

Copy link
Copy Markdown
MemberAuthor

I had three outcomes in mind:

  • report number of Arrays
  • report attributes and their shape. I was doing this by writing a report for each Array, but beyond 2 or 3 Arrays, that will be text barf on the screen.
  • provide a summary of key data, e.g., the DatetimeIndex. I could do that once rather than using head() for each DataFrame or Series.

So I'll drop the head except for times

@cwhanse

Copy link
Copy Markdown
MemberAuthor

Code I'm using to display the report for different PVSystems

import pytz
import pandas as pd
import pvlib
loc = pvlib.location.Location(35, -116)
dr = pd.date_range(start='2023-06-10 10:00:00', end='2023-06-11 10:00:00',
freq='H', tz=pytz.timezone('Etc/GMT+7'))
weather = loc.get_clearsky(dr)
weather['temp_air'] = 25
module_parameters = {'pdc0': 250, 'gamma_pdc': -0.004}
inverter_parameters = {'pdc0': 250}
temperature_parameters = pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_glass']
pvs = pvlib.pvsystem.PVSystem(module_parameters=module_parameters,
inverter_parameters=inverter_parameters,
temperature_model_parameters=temperature_parameters)
mc = pvlib.modelchain.ModelChain(pvs, loc, aoi_model='no_loss',
spectral_model='no_loss',
temperature_model='sapm')
mc.run_model(weather)
mcres = mc.results
print(mcres)
mount = pvlib.pvsystem.FixedMount(surface_tilt=30, surface_azimuth=180,
racking_model='open_rack')
array = pvlib.pvsystem.Array(mount=mount, albedo=0.3,
module_parameters=module_parameters,
temperature_model_parameters=temperature_parameters)
pvs2 = pvlib.pvsystem.PVSystem(arrays=(array, array),
inverter_parameters=inverter_parameters)
mc2 = pvlib.modelchain.ModelChain(pvs2, loc, aoi_model='no_loss',
spectral_model='no_loss',
temperature_model='sapm')
mc2.run_model(weather)
mcres2 = mc2.results
print(mcres2)
mc3 = pvlib.modelchain.ModelChain(pvs2, loc, aoi_model='no_loss',
spectral_model='no_loss',
temperature_model='sapm')
mc3.run_model((weather, weather))
mcres3 = mc3.results
print(mcres3)

@kandersolarkandersolar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably worth a test? We used to have a ModelChain.__repr__ test, but it looks like I incorrectly removed it in #1181, oops. We should probably bring that back.

Comment threadpvlib/modelchain.py
Comment threadpvlib/modelchain.py
desc2 = (f'Number of Arrays: {num_arrays} \n')
attr = 'times'
desc3 = ('Times (first 3)\n' +
f'{_head(_getmcattr(self, attr))}' +

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
f'{_head(_getmcattr(self, attr))}'+
f'{self.times[:3]}'+

Seems like this should be fine as long as it's safe to assume self.times is a DatetimeIndex

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't work if times is a DatetimeStamp. Maybe that can't happen, idk.

Comment threadpvlib/modelchain.py Outdated
@cwhanse

Copy link
Copy Markdown
MemberAuthor

Probably worth a test? We used to have a ModelChain.__repr__ test, but it looks like I incorrectly removed it in #1181, oops. We should probably bring that back.

I added the Modelchain.__repr__ test back.

For the ModelChainResult.__repr__ test, I'm checking that all the non-private attributes appear. That provides some future-proofing, without a cumbersome string==string check.

@kandersolarkandersolar added this to the 0.10.0 milestone Jun 23, 2023
Comment threadpvlib/tests/test_modelchain.py Outdated
Comment on lines +2068 to +2070
@pytest.mark.parametrize('strategy, strategy_str', [
('south_at_latitude_tilt', 'south_at_latitude_tilt'),
(None, 'None')]) # GitHub issue 352

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for putting this test back. I think this decorator is no longer needed and can be deleted.

Comment threadpvlib/modelchain.py
'aoi_modifier', 'total_irrad', 'spectral_modifier',
'effective_irradiance', 'cell_temperature', 'diode_params',
'dc', 'dc_ohmic_losses', 'losses', 'ac']
mc_attrs = dir(self)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using dir sorts the list of attributes alphabetically instead of conceptually. Not necessarily a downside.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, once I saw the alphabetized list my thought was "that's easier to use"

@kandersolar
kandersolar merged commit 209376e into pvlib:mainJun 23, 2023
@kandersolar

Copy link
Copy Markdown
Member

Thanks @cwhanse!

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve ModelChainResult.__repr__

2 participants

@cwhanse@kandersolar