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

Applied PVsyst-type losses in ModelChain

Open ncroft-b4 opened this issue 4 years ago • 3 comments

I would like to start a discussion around developing features that implement PVsyst style losses that act as direct physical operators rather than as percentage factors on just the dc section of the ModelChain. For instance, implementing soiling losses as monthly percentage inputs that operate on the irradiance input leading to effective irradiance, DC ohmic losses as a percentage at STC loss from which a resistance value is calculated and operates on the current of the DC output, and/or AC ohmic Losses as a STC loss percentage that operates on the output of the ac_model.

It is my understanding that loss models in the ModelChain are currently implemented as a single operation after the dc_model has been run and before the ac_model and only affect the dc outputs. Therefore "pvsyst_losses" functionality would not be an additional loss model at the losses_model part of the chain, but would require extra steps added to the chain.

I wanted to bring this up and open it for discussion about preferred ways to implement this. For instance , a soiling_loss function could be added that executes before the aoi_model. This potentially depreciates the losses_model as a single self-contained function.

I suppose what I am suggesting is to remove the losses_model in favor of new functions like soiling_losses, dc_losses, ac_losses. What to run for each of these could then be defined per model strategy whether it is pvwatts, sapm, or pvsyst, etc,. If this strategy seems valid I would like to attempt a pull request to begin implementing it.

ncroft-b4 avatar Sep 25 '20 20:09 ncroft-b4

The only legacy interface for loss models is in ModelChain.losses_model, which sits between ModelChain.dc_model and ModelChain.ac_model in the various run_model methods. The current options for losses_model are PVSystem.pvwatts_losses and ModelChain.no_extra_losses. We could rename losses_model to something more specific dc_losses as you suggest, and preserve the PVWatts function at that stage. That creates space to name and insert other loss model methods, e.g., poa_losses for soiling and snow.

cwhanse avatar Oct 05 '20 21:10 cwhanse

Or perhaps instead of renaming losses_model, it could be kept as a ModelChain attribute where a user could specify it to be either 'pvwatts' or 'pvsyst'? Then instead of the ModelChain.losses_model being a function, it is a label that gets used to decide which functions to run at various losses methods.

And if it is 'pvsyst' then there would be 'pvsyst' specific keys in the 'losses_parameters' that are used by PVSystem.

Is this a place to display first passes at code for comment and checks? Here is something I am working on for a pvsyst style dc ohmic loss. Users would pass a 'dc_ohmic_percent' as a 'losses_parameter' when creating PVSystem. There would be a PVSystem method to calculate the equivalent resistance from that:

 def equivalent_resistance_from_percent_stc(self):
    
    vmp = self.modules_per_string * self.module_parameters['V_mp_ref']
    
    imp = self.strings_per_inverter * self.module_parameters['I_mp_ref']
    
    Rw = (self.losses_parameters['dc_ohmic_percent'] / 100) * (vmp / imp)
    
    return Rw 

And an accompanying ModelChain method that would apply that to dc output:

def ohmic_loss_from_percent_stc(self.system):
    
    Rw = equivalent_resistance_from_percent_stc(self)
    
    ohmic_loss_fraction = Rw * (self.dc['i_mp']/self.dc['v_mp'])

    ohmic_loss = ohmic_loss_fraction * self.dc['p_mp']
    
    self.dc['p_mp'] = self.dc['p_mp'] - ohmic_loss
    
    return self

I have more work for testing and documentation and writing in checks for the 'dc_ohmic_percent' parameter before making a pull request, but if there is any feedback in the meantime about this approach I am happy to hear it.

ncroft-b4 avatar Oct 09 '20 22:10 ncroft-b4

Or perhaps instead of renaming losses_model, it could be kept as a ModelChain attribute where a user could specify it to be either 'pvwatts' or 'pvsyst'? Then instead of the ModelChain.losses_model being a function, it is a label that gets used to decide which functions to run at various losses methods.

I think this is how it works now. There's some internal plumbing using a decorator @losses_model.setter that marks code which is executed when a value e.g. 'pvwatts' is assigned to ModelChain.losses_model. In effect, assigning ModelChain.losses_model = 'pvwatts' also sets a value for Modelchain._losses_model which is a function handle. Then when ModelChain.losses_model is referenced, the decorator @property marks code that is run, i.e., executes the function ModelChain._losses_model.

And if it is 'pvsyst' then there would be 'pvsyst' specific keys in the 'losses_parameters' that are used by PVSystem.

Yes. We would need to add a new method ModelChain.pvsyst_losses to handle the calculation.

Is this a place to display first passes at code for comment and checks? Here is something I am working on for a pvsyst style dc ohmic loss. Users would pass a 'dc_ohmic_percent' as a 'losses_parameter' when creating PVSystem. There would be a PVSystem method to calculate the equivalent resistance from that:

 def equivalent_resistance_from_percent_stc(self):
    
    vmp = self.modules_per_string * self.module_parameters['V_mp_ref']
    
    imp = self.strings_per_inverter * self.module_parameters['I_mp_ref']
    
    Rw = (self.losses_parameters['dc_ohmic_percent'] / 100) * (vmp / imp)
    
    return Rw 

And an accompanying ModelChain method that would apply that to dc output:

def ohmic_loss_from_percent_stc(self.system):
    
    Rw = equivalent_resistance_from_percent_stc(self)
    
    ohmic_loss_fraction = Rw * (self.dc['i_mp']/self.dc['v_mp'])

    ohmic_loss = ohmic_loss_fraction * self.dc['p_mp']
    
    self.dc['p_mp'] = self.dc['p_mp'] - ohmic_loss
    
    return self

I have more work for testing and documentation and writing in checks for the 'dc_ohmic_percent' parameter before making a pull request, but if there is any feedback in the meantime about this approach I am happy to hear it.

That looks to be in the right direction. I'm not sure about the ModelChain method, we'll need to look at it in the context of executing a losses model.

cwhanse avatar Oct 14 '20 14:10 cwhanse