Source code for pvfactors.run

"""Module containing the functions to run engine calculations in normal or
parallel mode."""

from pvfactors import logging
from pvfactors.geometry import OrderedPVArray
from pvfactors.irradiance import HybridPerezOrdered
from pvfactors.viewfactors import VFCalculator
from pvfactors.engine import PVEngine
from multiprocessing import Pool, cpu_count
import numpy as np
import pandas as pd
from time import time


LOGGER = logging.getLogger(__name__)
LOGGER.setLevel(logging.INFO)


[docs]def run_timeseries_engine(fn_build_report, pvarray_parameters, timestamps, dni, dhi, solar_zenith, solar_azimuth, surface_tilt, surface_azimuth, albedo, cls_pvarray=OrderedPVArray, cls_engine=PVEngine, cls_irradiance=HybridPerezOrdered, cls_vf=VFCalculator, fast_mode_pvrow_index=None, fast_mode_segment_index=None, irradiance_model_params=None, vf_calculator_params=None, ghi=None): """Run timeseries simulation without multiprocessing. This is the functional approach to the :py:class:`~pvfactors.engine.PVEngine` class. Parameters ---------- fn_build_report : function Function that will build the report of the simulation pvarray_parameters : dict The parameters defining the PV array timestamps : array-like List of timestamps of the simulation. dni : array-like Direct normal irradiance values [W/m2] dhi : array-like Diffuse horizontal irradiance values [W/m2] solar_zenith : array-like Solar zenith angles [deg] solar_azimuth : array-like Solar azimuth angles [deg] surface_tilt : array-like Surface tilt angles, from 0 to 180 [deg] surface_azimuth : array-like Surface azimuth angles [deg] albedo : array-like Albedo values (or ground reflectivity) cls_pvarray : class of PV array, optional Class that will be used to build the PV array (Default = :py:class:`~pvfactors.geometry.pvarray.OrderedPVArray` class) cls_engine : class of PV engine, optional Class of the engine to use to run the simulations (Default = :py:class:`~pvfactors.engine.PVEngine` class) cls_irradiance : class of irradiance model, optional The irradiance model that will be applied to the PV array (Default = :py:class:`~pvfactors.irradiance.models.HybridPerezOrdered` class) cls_vf : class of VF calculator, optional Calculator that will be used to calculate the view factor matrices (Default = :py:class:`~pvfactors.viewfactors.calculator.VFCalculator` class) fast_mode_pvrow_index : int, optional If a valid pvrow index is passed, then the PVEngine fast mode will be activated and the engine calculation will be done only for the back surface of the selected pvrow (Default = None) fast_mode_segment_index : int, optional If a segment index is passed, then the PVEngine fast mode will calculate back surface irradiance only for the selected segment of the selected back surface (Default = None) irradiance_model_params : dict, optional Dictionary of parameters that will be passed to the irradiance model class as kwargs at instantiation (Default = None) vf_calculator_params : dict, optional Dictionary of parameters that will be passed to the VF calculator class as kwargs at instantiation (Default = None) ghi : array-like, optional Global horizontal irradiance values [W/m2] (Default = None) Returns ------- report Saved results from the simulation, as specified by user's report function """ # Prepare input parameters irradiance_model_params = irradiance_model_params or {} vf_calculator_params = vf_calculator_params or {} # Instantiate classes and engine irradiance_model = cls_irradiance(**irradiance_model_params) vf_calculator = cls_vf(**vf_calculator_params) pvarray = cls_pvarray.init_from_dict(pvarray_parameters) eng = cls_engine(pvarray, irradiance_model=irradiance_model, vf_calculator=vf_calculator, fast_mode_pvrow_index=fast_mode_pvrow_index, fast_mode_segment_index=fast_mode_segment_index) # Fit engine eng.fit(timestamps, dni, dhi, solar_zenith, solar_azimuth, surface_tilt, surface_azimuth, albedo, ghi=ghi) # Run all timesteps report = (eng.run_full_mode(fn_build_report=fn_build_report) if fast_mode_pvrow_index is None else eng.run_fast_mode(fn_build_report=fn_build_report)) return report
[docs]def run_parallel_engine(report_builder, pvarray_parameters, timestamps, dni, dhi, solar_zenith, solar_azimuth, surface_tilt, surface_azimuth, albedo, cls_pvarray=OrderedPVArray, cls_engine=PVEngine, cls_irradiance=HybridPerezOrdered, cls_vf=VFCalculator, fast_mode_pvrow_index=None, fast_mode_segment_index=None, irradiance_model_params=None, vf_calculator_params=None, n_processes=2, ghi=None): """Run timeseries simulation using multiprocessing. Here, instead of a function that will build the report, the users will need to pass a class (or an object). Parameters ---------- report_builder : class or object Class or object that will build and merge the reports. It **must** have a ``build()`` and a ``merge()`` method that perform the tasks pvarray_parameters : dict The parameters defining the PV array timestamps : array-like List of timestamps of the simulation. dni : array-like Direct normal irradiance values [W/m2] dhi : array-like Diffuse horizontal irradiance values [W/m2] solar_zenith : array-like Solar zenith angles [deg] solar_azimuth : array-like Solar azimuth angles [deg] surface_tilt : array-like Surface tilt angles, from 0 to 180 [deg] surface_azimuth : array-like Surface azimuth angles [deg] albedo : array-like Albedo values (or ground reflectivity) cls_pvarray : class of PV array, optional Class that will be used to build the PV array (Default = :py:class:`~pvfactors.geometry.pvarray.OrderedPVArray` class) cls_engine : class of PV engine, optional Class of the engine to use to run the simulations (Default = :py:class:`~pvfactors.engine.PVEngine` class) cls_irradiance : class of irradiance model, optional The irradiance model that will be applied to the PV array (Default = :py:class:`~pvfactors.irradiance.models.HybridPerezOrdered` class) cls_vf : class of VF calculator, optional Calculator that will be used to calculate the view factor matrices (Default = :py:class:`~pvfactors.viewfactors.calculator.VFCalculator` class) fast_mode_pvrow_index : int, optional If a valid pvrow index is passed, then the PVEngine fast mode will be activated and the engine calculation will be done only for the back surface of the selected pvrow (Default = None) fast_mode_segment_index : int, optional If a segment index is passed, then the PVEngine fast mode will calculate back surface irradiance only for the selected segment of the selected back surface (Default = None) irradiance_model_params : dict, optional Dictionary of parameters that will be passed to the irradiance model class as kwargs at instantiation (Default = None) vf_calculator_params : dict, optional Dictionary of parameters that will be passed to the VF calculator class as kwargs at instantiation (Default = None) n_processes : int, optional Number of parallel processes to run for the calculation (Default = 2) ghi : array-like, optional Global horizontal irradiance values [W/m2] (Default = None) Returns ------- report Saved results from the simulation, as specified by user's report class (or object) """ # Choose number of workers if n_processes == -1: n_processes = cpu_count() # Make sure albedo is iterable if np.isscalar(albedo): albedo = albedo * np.ones(len(dni)) # Prepare class input parameters irradiance_model_params = irradiance_model_params or {} vf_calculator_params = vf_calculator_params or {} # Fix: np.array_split doesn't work well on pd.DatetimeIndex objects if isinstance(timestamps, pd.DatetimeIndex): timestamps = timestamps.to_pydatetime() # Split all arguments according to number of processes (folds_timestamps, folds_surface_azimuth, folds_surface_tilt, folds_solar_zenith, folds_solar_azimuth, folds_dni, folds_dhi, folds_albedo) = map(np.array_split, [timestamps, surface_azimuth, surface_tilt, solar_zenith, solar_azimuth, dni, dhi, albedo], [n_processes] * 8) folds_report_builder = [report_builder] * n_processes folds_params = [pvarray_parameters] * n_processes folds_cls_pvarray = [cls_pvarray] * n_processes folds_cls_engine = [cls_engine] * n_processes folds_cls_irradiance = [cls_irradiance] * n_processes folds_cls_vf = [cls_vf] * n_processes folds_fast_mode_pvrow_index = [fast_mode_pvrow_index] * n_processes folds_fast_mode_segment_index = [fast_mode_segment_index] * n_processes folds_irradiance_model_params = [irradiance_model_params] * n_processes folds_vf_calculator_params = [vf_calculator_params] * n_processes folds_ghi = ([ghi] * n_processes if ghi is None else np.array_split(ghi, n_processes)) report_indices = list(range(n_processes)) # Zip all the folds together list_folds = zip(*(folds_report_builder, folds_params, folds_timestamps, folds_dni, folds_dhi, folds_solar_zenith, folds_solar_azimuth, folds_surface_tilt, folds_surface_azimuth, folds_albedo, folds_cls_pvarray, folds_cls_engine, folds_cls_irradiance, folds_cls_vf, folds_fast_mode_pvrow_index, folds_fast_mode_segment_index, folds_irradiance_model_params, folds_vf_calculator_params, folds_ghi, report_indices)) # Start multiprocessing pool = Pool(n_processes) start = time() indexed_reports = pool.map(_run_serially, list_folds) end = time() pool.close() pool.join() sorted_indexed_reports = sorted(indexed_reports, key=lambda tup: tup[1]) sorted_reports = [tup[0] for tup in sorted_indexed_reports] LOGGER.info("Parallel calculation elapsed time: %s sec" % str(end - start)) report = report_builder.merge(sorted_reports) return report
# Utility function for parallel run def _run_serially(args): """Helper function used to run calculations in parallel Parameters ---------- args : tuple List of arguments where most will be used in :py:func:`~pvfactors.run.run_timeseries_engine` Returns ------- report Saved results from the simulation, as specified by user's report class (or object) idx : int Index of the report, which will be used to sort the final list of reports after all the parallel simulations are over """ report_builder, pvarray_parameters, timestamps, dni, dhi, \ solar_zenith, solar_azimuth, surface_tilt, surface_azimuth,\ albedo, cls_pvarray, cls_engine, cls_irradiance, cls_vf, \ fast_mode_pvrow_index, fast_mode_segment_index, \ irradiance_model_params, vf_calculator_params, ghi, idx = args report = run_timeseries_engine( report_builder.build, pvarray_parameters, timestamps, dni, dhi, solar_zenith, solar_azimuth, surface_tilt, surface_azimuth, albedo, cls_pvarray=cls_pvarray, cls_engine=cls_engine, cls_irradiance=cls_irradiance, cls_vf=cls_vf, fast_mode_pvrow_index=fast_mode_pvrow_index, fast_mode_segment_index=fast_mode_segment_index, irradiance_model_params=irradiance_model_params, vf_calculator_params=vf_calculator_params, ghi=ghi) return report, idx