pvlib-python icon indicating copy to clipboard operation
pvlib-python copied to clipboard

SingleAxisTrackerMount doesn't store "tracking" values when calling ModelChain.run()

Open btaute opened this issue 3 years ago • 4 comments

Describe the bug I don't believe SingleAxisTrackerMount gets properly modeled using a ModelChain. I believe it's being modeled as a Fixed-Tilt system. The following condition lies in ModelChain.prepare_inputs():

if isinstance(self.system, SingleAxisTracker):
            self._prep_inputs_tracking()
            get_irradiance = partial(
                self.system.get_irradiance,
                self.results.tracking['surface_tilt'],
                self.results.tracking['surface_azimuth'],
                self.results.solar_position['apparent_zenith'],
                self.results.solar_position['azimuth'])
        else:
            self._prep_inputs_fixed()
            get_irradiance = partial(
                self.system.get_irradiance,
                self.results.solar_position['apparent_zenith'],
                self.results.solar_position['azimuth'])

I created a ModelChain using SingleAxisTrackerMount instead of SingleAxisTracker, and the self.results.tracking fields never got set. Also, isinstance(mc.system, pvlib.tracking.SingleAxisTracker) is False.

To Reproduce Try running a ModelChain using SingleAxisTrackerMount instead of SingleAxisTracker.

Expected behavior I would expect ModelChain.run_model() to check isinstance(self.system, SingleAxisTrackerMount) in addition to SingleAxisTracker (which is deprecated). (And thus, I'd expect the ModelChain class to import SingleAxisTrackerMount, which it currently doesn't.)

Versions:

  • pvlib.__version__: 0.9.0

Additional context Happy to submit a PR for the above-mentioned changes if that's the correct expected behavior.

btaute avatar Oct 22 '21 21:10 btaute

I think the scope of the problem may be larger than I initially thought. I believe pvlib.pvsystem needs some code updates as well. Also, I came across this error when I tried to run mc._prep_inputs_tracking(): 'PVSystem' object has no attribute 'singleaxis'

btaute avatar Oct 22 '21 21:10 btaute

Can you provide a full example code to reproduce fixed-tilt outputs coming from tracker inputs? This short example using SingleAxisTrackerMount with ModelChain seems to produce a tracker profile as expected:

Click to expand!
import pvlib  # v0.9.0
import pandas as pd

location = pvlib.location.Location(40, -80)
times = pd.date_range('2019-06-01', '2019-06-02', freq='15min', tz='Etc/GMT+5')
weather = location.get_clearsky(times)
weather['temp_air'] = 20
weather['windspeed'] = 1
temperature_model_parameters = pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS['sapm']['open_rack_glass_polymer']
array = pvlib.pvsystem.Array(pvlib.tracking.SingleAxisTrackerMount(),
                             module_parameters={'pdc0': 1, 'gamma_pdc': -0.004},
                             temperature_model_parameters=temperature_model_parameters)
system = pvlib.pvsystem.PVSystem([array],
                                 inverter_parameters={'pdc0': 1})
mc = pvlib.modelchain.ModelChain(system, location, spectral_model='no_loss', aoi_model='no_loss')
mc.run_model(weather)
mc.results.dc.plot()

isinstance(self.system, SingleAxisTrackerMount)

This doesn't really make sense; unlike the now-deprecated SingleAxisTracker, it's not that a PVSystem is a Mount but rather that it has a Mount (or rather, it has an Array that has a Mount). The idea is that the Mount handles all the module orientation details so that the higher-level objects (Array, PVSystem, ModelChain) don't need to worry about it and are generic enough to handle any mounting configuration so long as the Mount produces the tilt & azimuth values.

and the self.results.tracking fields never got set

That may be a bug -- I don't recall that being an intentional decision. Maybe ModelChain should always copy the output of mount.get_orientation() to that field. And possibly rename to something more generic (results.orientation?) so that it doesn't exclude FT.

kandersolar avatar Oct 24 '21 15:10 kandersolar

I agree that the isinstance() code doesn't make sense. That's the root of the bug, I believe. When ModelChain.prepare_inputs() gets called, it runs that check, which will always turn up false now that SingleAxisTracker is deprecated, meaning self._prep_inputs_fixed() will get called for all PVSystems. That's also why self.results.tracking never gets set.

I'll post an example here later today.

btaute avatar Oct 25 '21 15:10 btaute

I was able to dig deeper into the source of the problem. The example code you shared fully reproduces it. While ModelChain.run_model() does model the system with self._prep_inputs_fixed(), when it run get_irradiance, eventually this calls the mount.get_orientation() method, which returns the proper surface tilt and azimuth values.

The title for this github issue is misleading. The real bug is that you can't get surface_azimuth or surface_tilt values when you run ModelChain with a SingleAxisTrackerMount. This was stored in self.results.tracking with the previous implementation but doesn't get stored anywhere anymore.

To test this, use the example code above and then check that mc.results.tracking == None

As a side note (but tied into this general conversation), some of the functions are misleadingly named after the new implementation as well.

btaute avatar Oct 25 '21 16:10 btaute