pvrpm.core package
Subpackages
Submodules
pvrpm.core.case module
- class pvrpm.core.case.SamCase(sam_json_dir: str, config: str, num_realizations: int = 0, results_folder: str | None = None)[source]
Bases:
object
SAM Case loader, verifier, and simulation
- base_case_sim() None [source]
Runs the base case simulation for this case, with no failures and optimal lifetime losses
This also sets base case output parameters of this object
- get_npv()[source]
Returns the NPV for the case after a simulation has been ran, regardless of financial model used.
- output(name: str) None | float | dict | list | str [source]
Get an output variable by string name, without specifying the module the variable resides in.
This will search all of the module’s outputs. If the value is not found in all of the modules, an AttributeError is raised.
- Parameters:
name (str) – Name of the output
- Returns:
The value of the output variable
- precalculate_tracker_losses()[source]
Precalculate_tracker_losses calculates an array of coefficients (one for every day of the year) that account for the “benefit” of trackers on that particular day. This is used to determine how much power is lost if a tracker fails.
- simulate(verbose: int = 0) None [source]
Executes simulations for all modules in this case.
- Parameters:
verbose (int) – 0 for no log messages, 1 for simulation log messages
- value(name: str, value: Any | None = None) None | float | dict | list | str [source]
Get or set by string name a module value, without specifying the module the variable resides in.
If there is no value provided, the value is returned for the variable name.
This will search the module’s data and update the variable if found. If the value is not found in all of the modules, an AttributeError is raised.
- Parameters:
name (str) – Name of the value
value (Any, optional) – Value to set variable to
- Returns:
Value or the variable if value is None
Note
Some modules have the same keys, this function will return the first key found in the module order specified in the configuration. Because of the way modules share data in PySAM, setting the value in the first module will propagate it to the other modules.
pvrpm.core.components module
- class pvrpm.core.components.Components(case: SamCase)[source]
Bases:
object
Data container for each component in the simulation, as well as component and simulation level data
- ac_availability() float [source]
Calculates the availability of AC power due to DC component outages, including inverters, disconnects, transformers, and the grid
- Returns:
Decimal percentage of AC modules available
- Return type:
float
- static compound_failures(function: str, parameters: dict, num_fails: int)[source]
Compounds the failures using the provided function and it’s parameters to calculate the number of days to reduce the time to detection by
- Possible functions and their parameters are:
- step: Failures follow a step function, each step reducing the detection time by a static amount
threshold (float): fraction 0 <= threshold <= 1 that signifies the amount of modules that must fail before next step is reached. So if this is 0.2, every 0.2 * total_components components that fail will reduce detection time by step
step (int): The amount of days to reduce detection time for every step. So 2 steps reduces detection time by 2 * step
- exponential: Failures compound on an exponential function
base (float): The base for the exponential function > 0
- log: Failures compound on a logorithmic function
base (float): The base for the log function > 0
- linear: Failures compound linearly
slope (float): Slope of the linear function > 0
- constant: Each failure reduces the time to detection by a static fraction constant
constant (float): fraction 0 <= frac <= 1 that specifies how much of the overall time each failure reduces. So if fraction is 0.1, a failure will reduce time to detection by “time_to_detection * 0.1”
- current_degradation() float [source]
Calculates the current module degradation, which is averaged for only operational modules, since the power production hit from degradation of non-operational modules would be double counted
- Returns:
Average degradation of operational modules
- Return type:
float
- dc_availability() float [source]
Calculates the availability of the DC power due to DC component outages, including modules, strings, and combiners
- Returns:
Decimal percentage of available DC modules
- Return type:
float
- initialize_components(component_level: str) DataFrame [source]
Initalizes all components for the first time
- Parameters:
component_level (str) – The configuration key for this component level
- Returns:
A dataframe containing the initalized values for this component level
- Return type:
pd.DataFrame
- Note: Individual components have these columns:
state (bool): Operational (True) or failed (False)
defective (bool): Whehter component has a defect. True means the component is also eligible for the defective failure mode
time_to_failure (float): Number of days until component fails
failure_type (str): The name of the failure type time_to_failure represents
time_to_repair (float): Number of days from failure until compoent is repaired
time_to_detection (float): Number of days until the component failure is detected and repairs start
repair_times (float): the total repair time for this repair
monitor_times (float): the total monitoring time before repairs start
time_left_on_warranty (int): Number of days left on warranty (if applicable)
cumulative_failures (int): Total number of failures for that component
cumulative_oow_failures (int): Total number of out of warranty failures (if applicable)
failure_by_type_n (int): Each failure will have its own column with the number of failures of this type
defective (bool): Whether this component is defective or not (for defective failures)
defective_failures (int): Total number of defective failures
avail_downtime (int): How many hours this component was available
degradation_factor (float): 1 - percentage component has degraded at this time (module only)
days_of_degradation (int): Time that the module has been degrading for
- snapshot()[source]
Returns the current state of the simulation including all internal dataframes, arrays, and variables for this object
- Returns:
A dictionary containing the simulation snapshot data
- Return type:
dict
Note
The returned objects are copies of this components objects to avoid changing data in the simulation unintentionally
- The returned dictionary has these keys and values:
module: DataFrame of simulation data for module level
string: DataFrame of simulation data for string level
combiner: DataFrame of simulation data for combiner level
inverter: DataFrame of simulation data for inverter level
disconnect: DataFrame of simulation data for disconnect level
transformer: DataFrame of simulation data for transformer level
grid: DataFrame of simulation data for grid level
tracker: DataFrame of simulation data for tracker level
misc_data: DataFrame containing costs (for each level), module degradation, dc and ac availability, and tracker loss/availability if tracking is used
- summarize_failures(component_level: str)[source]
Returns the number of failures per day for every failure defined
- Parameters:
component_level (str) – The configuration key for this component level
- Returns:
Dictionary containing the failure mode mapped to an np array of fails per each day
- Return type:
dict
- tracker_power_loss(day: int) Tuple[float, float] [source]
Calculates the current loss factor due to failed trackers
- Parameters:
day (int) – Current day in the simulation
- Returns:
The fraction of trackers operational and the loss factor for failed trackers
- Return type:
Tuple[float, float]
- update_fails(component_level: str, day: int)[source]
Changes state of a component to failed, incrementing failures and checking warranty only for failed components of each failure type
- Parameters:
component_level (str) – The component level to check for failures
day (int) – Current day in the simulation
Note
Updates the underlying dataframes in place
- update_indep_monitor(day: int)[source]
If independent monitoring is defined, check it for the current day in simulation
- Parameters:
day (int) – Current day in the simulation
- update_labor_rates(new_labor: float)[source]
Update labor rates for a all levels for all types of repairs
- Parameters:
new_labor (float) – The new labor rate
- update_monitor(component_level: str, day: int)[source]
Updates time to detection from component level, static, and cross component level monitoring based on number of failures
Monitoring defined for each level is unaffected, only cross level monitoring on levels with no monitoring at that level have times updated based on failures, since monitoring defined at the component level uses the defined monitoring distribution for those components instead of the cross level monitoring
- Parameters:
component_level (str) – The component level to check for monitoring
day (int) – Current day in the simulation
Note
Updates the underlying dataframes in place
- update_repairs(component_level: str, day: int)[source]
Changes the state of a component to operational once repairs are complete, only for components where the time to repair is zero
- Parameters:
component_level (str) – The component level of this repair
day (int) – Current day in the simulation
Note
Updates the underlying dataframes in place
pvrpm.core.enums module
- class pvrpm.core.enums.ConfigKeys[source]
Bases:
object
- BASE = 'base'
- CAN_FAIL = 'can_fail'
- CAN_MONITOR = 'can_monitor'
- CAN_REPAIR = 'can_repair'
- COMBINER = 'combiner'
- COMBINER_PER_INVERTER = 'num_combiners_per_inverter'
- COMP_FUNC = 'compounding_function'
- COMP_MONITOR = 'component_level_monitoring'
- COMP_PARAM = 'compound_parameters'
- CONF_INTERVAL = 'conf_interval'
- CONST = 'constant'
- COST = 'cost'
- COST_PER_WATT = 'cost_per_watt'
- DAYS = 'days'
- DECAY_FRAC = 'decay_fraction'
- DEGRADE = 'degradation'
- DISCONNECT = 'disconnect'
- DIST = 'distribution'
- EXPON = 'exponential'
- FAILURE = 'failures'
- FAIL_PER_THRESH = 'failure_per_threshold'
- FAIL_THRESH = 'global_threshold'
- FRAC = 'fraction'
- GRID = 'grid'
- INDEP_MONITOR = 'indep_monitoring'
- INFLATION = 'inflation'
- INTERVAL = 'interval'
- INVERTER = 'inverter'
- INVERTER_PER_TRANS = 'num_inverters_per_transformer'
- INVERTER_SIZE = 'inverter_size'
- LABOR = 'labor_time'
- LABOR_RATE = 'present_day_labor_rate'
- LEVELS = 'levels'
- LIFETIME_YRS = 'system_lifetime_yrs'
- LINEAR = 'linear'
- LOG = 'log'
- LOGNORM = 'lognormal'
- MEAN = 'mean'
- MODULE = 'module'
- MODULES_PER_STR = 'num_modules_per_string'
- MODULE_ORDER = 'module_order'
- MONITORING = 'monitoring'
- MULTI_SUBARRAY = 'has_multiple_subarrays'
- NAME = 'name'
- NORMAL = 'normal'
- NUM_COMBINERS = 'num_combiners'
- NUM_COMPONENT = 'count'
- NUM_REALIZATION = 'num_realizations'
- NUM_TRACKERS = 'num_trackers'
- NUM_TRANSFORMERS = 'num_transformers'
- PARAM = 'parameters'
- PARTIAL_FAIL = 'concurrent_failures'
- PARTIAL_REPAIR = 'concurrent_repairs'
- REPAIR = 'repairs'
- RESULTS_FOLDER = 'results_folder'
- SHAPE = 'shape'
- SLOPE = 'slope'
- STD = 'std'
- STEP = 'step'
- STRING = 'string'
- STR_PER_COMBINER = 'num_strings_per_combiner'
- THRESH = 'threshold'
- TRACKER = 'tracker'
- TRACKING = 'is_tracking_system'
- TRANSFORMER = 'transformer'
- UNIFORM = 'uniform'
- WARRANTY = 'warranty'
- WEIBULL = 'weibull'
- WORST_TRACKER = 'use_worst_case_tracker'
- component_keys = ['module', 'string', 'combiner', 'inverter', 'disconnect', 'transformer', 'grid', 'tracker']
- compound_funcs = ['step', 'log', 'linear', 'exponential', 'constant']
- compound_keys = ['distribution', 'parameters']
- compound_levels = ['string', 'combiner', 'inverter', 'disconnect', 'transformer', 'grid']
- dists = ['normal', 'exponential', 'weibull', 'lognormal', 'uniform']
- failure_keys = ['distribution', 'parameters', 'labor_time', 'cost']
- indep_monitor_keys = ['cost', 'levels', 'labor_time']
- losses = ['annual_poa_shading_loss_percent', 'annual_poa_soiling_loss_percent', 'annual_poa_cover_loss_percent', 'annual_dc_module_loss_percent', 'annual_dc_mppt_clip_loss_percent', 'annual_dc_mismatch_loss_percent', 'annual_dc_diodes_loss_percent', 'annual_dc_wiring_loss_percent', 'annual_dc_tracking_loss_percent', 'annual_dc_nameplate_loss_percent', 'annual_dc_optimizer_loss_percent', 'annual_dc_perf_adj_loss_percent', 'annual_ac_inv_clip_loss_percent', 'annual_ac_inv_pso_loss_percent', 'annual_ac_inv_pnt_loss_percent', 'annual_ac_inv_eff_loss_percent', 'ac_loss', 'annual_transmission_loss_percent', 'annual_ac_perf_adj_loss_percent', 'annual_xfmr_loss_percent']
- monitoring_keys = ['distribution', 'parameters']
- needed_keys = ['module_order', 'num_realizations', 'num_combiners', 'num_transformers', 'num_trackers', 'results_folder', 'conf_interval', 'present_day_labor_rate', 'inflation', 'use_worst_case_tracker', 'module', 'string', 'combiner', 'inverter', 'disconnect', 'transformer', 'grid']
- partial_failure_keys = ['distribution', 'parameters', 'labor_time', 'cost']
- partial_repair_keys = ['distribution', 'parameters']
- repair_keys = ['distribution', 'parameters']
pvrpm.core.exceptions module
pvrpm.core.logger module
pvrpm.core.simulation module
- pvrpm.core.simulation.cf_interval(alpha: float, std: float, num_samples: int) float [source]
Calculates the two tails margin of error given the desired input. The margin of error is the value added and subtracted by the sample mean to obtain the confidence interval
Sample sizes less then equal to 30 use t score, greater then 30 use z score
- Parameters:
alpha (float) – The significance level for the interval
std (float) – The standard deviation of the data
num_samples (int) – The number of samples in the data
- Returns:
The margin of error
- Return type:
float
- pvrpm.core.simulation.gen_results(case: SamCase, results: List[Components]) List[DataFrame] [source]
Generates results for the given SAM case and list of component objects containing the results of each realization.
- Parameters:
case (
SamCase
) – The loaded and verified case to use with the simulationresults (
list(Components)
) – List of component objects that contain the results for each realization
- Returns:
List of dataframes containing the results.
- Return type:
list(pd.DataFrame)
Note
- The order of the returned dataframes is:
Summary Results
Degradation Results
DC Power
AC Power
Yearly Costs
- pvrpm.core.simulation.graph_results(case: SamCase, results: List[Components], save_path: str | None = None) None [source]
Generate graphs from a list of Component objects from each realization
- Parameters:
case (
SamCase
) – The loaded and verified case to use with the simulationresults (
list(Components)
) – List of component objects that contain the results for each realizationsave_path (str, Optional) – Path to save graphs to, if provided
- pvrpm.core.simulation.pvrpm_sim(case: SamCase, save_results: bool = False, save_graphs: bool = False, progress_bar: bool = False, debug: int = 0, threads: int = 1) List[Components] [source]
Run the PVRPM simulation on a specific case. Results will be saved to the folder specified in the configuration.
- Parameters:
case (
SamCase
) – The loaded and verified case to use with the simulationsave_results (bool, Optional) – Whether to save output csv results
save_graphs (bool, Optional) – Whether to save output graphs
progress_bar (bool, Optional) – Whether to display progress bar for each realization
debug (int, Optional) – Whether to save simulation state every debug days (0 to turn off)
threads (int, Optional) – Number of threads to use for paralizing realizations
- Returns:
Returns the list of results Component objects for each realization
- Return type:
list(Components)
- pvrpm.core.simulation.run_system_realization(case: SamCase, seed: bool = False, realization_num: int = 0, progress_bar: bool = False, debug: int = 0) Components [source]
Run a full realization for calculating costs
- Parameters:
case (
SamCase
) – The loaded and verified case to use with the simulationseed (bool, Optional) – Whether to seed the random number generator, for multiprocessing
realization_num (int, Optional) – Current realization number, used for multiprocessing
progress_bar (bool, Optional) – Whether to display progress bar during the realization
debug (int, Optional) – Whether to save simulation state every debug days (0 to turn off)
- Returns:
The components object which contains all the data for this realization
- Return type:
Components
- pvrpm.core.simulation.simulate_day(case: SamCase, comp: Components, day: int)[source]
Updates and increments the simulation by a day, performing all neccesary component updates.
- Parameters:
case (
SamCase
) – The current Sam Case of the simulationcomp (
Components
) – The components class containing all the outputs for this simulationday (int) – Current day in the simulation
pvrpm.core.utils module
- pvrpm.core.utils.component_degradation(percent_per_day: float, t: int) float [source]
Calculate the degradation of a component given the time since last replacement
- Parameters:
percent_per_day (float) – The percent degradation per day of the module
t (int) – Time since the module was last replaced, or if its a new module, installed
- Returns:
The performance of the module, between 0 and 1
- Return type:
float
Note
This gives the overall module performance based on degradation, so if the module has degraded 2 percent so far, this function returns 0.98
- pvrpm.core.utils.filename_to_module(filename: str) object [source]
Takes the filename of an exported json file from SAM, extracts the module name, and returns a callback to that module that can be used to create an object
- Parameters:
filename (str) – Filename of the exported case
- Returns:
PySAM object the file represents
- Return type:
PySAM
- pvrpm.core.utils.get_components_per(array_to_split: array, split_indicies: array, per: int)[source]
Splits a 1D array into a 2D array split up by split indicies, with per amount for each row
This will handle when the data cannot be evenly split.
- Parameters:
array_to_split (np.array) – 1D array to split.
split_indicies (np.array) – List of row indicies for the new array
per (int) – The amount to fill each row with
- Returns:
The newly shaped array
- Return type:
np.array
- pvrpm.core.utils.get_higher_components(top_level: str, start_level: str, case, start_level_df: DataFrame | None = None) Tuple[array, array, int] [source]
Calculates the indicies of the top level that correspond to the given level df indicies and returns the given level indicies count per top level component and the total number of start_level components per top_level component
- Parameters:
top_level (str) – The string name of the component level to calculate indicies for
start_level (str) – The string name of the component level to start at
case (SamCase) – The case object for this simulation
start_level_df (
pd.DataFrame
, Optional) – The dataframe of the component level for which to find the corresponding top level indicies for
- Returns:
If start_level_df is given, returns the top level indicies, the number of start_level components in start_level_df per top level index, and the total number of start_level components per top_level component. If start_level_df is None this only returns the total number of start_level components per top_level component.
- Return type:
tuple(
np.array
,np.array
, int)
- pvrpm.core.utils.load_pysam_modules()[source]
Loads ALL of PySAM’s modules manually and globalizes them
This is needed because PySAM is a wrapper for the ssc and sdk of SAM, which includes dynamic modules that are not properly defined for pybind, so using pkgutil’s walk_packages function does not work (import error). Since the modules need to be loaded in order for getattr to find it, this must be done once when the program starts
- pvrpm.core.utils.sample(distribution: str, parameters: dict, num_samples: int) array [source]
Sample data from a distribution. If distribution is a supported distribution, parameters should be a dictionary with keys “mean” and “std”. Otherwise, distribution should be a scipy stats function and parameters be the kwargs for the distribution.
- Supported Distributions (only requires mean and std):
lognormal
normal
uniform (one std around mean)
weibull
exponential
- Parameters:
distribution (str) – Name of the distribution function
parameters (
dict
) – Kwargs for the distribution (for a supported distribution should only be the mean and std)num_samples (int) – Number of samples to return from distribution
- Returns:
obj:(list): List of floats containing samples from the distribution
- pvrpm.core.utils.summarize_dc_energy(dc_power_output: tuple, split: int) array [source]
Calculates the DC energy (kWh) based on an input array of timeseries DC power (kW) for the system lifetime (likely the ‘dc_net’ output from SAM)
Can be used to summarize similar hourly, daily data to yearly
- Parameters:
dc_power_output (
tuple
) – Tuple output from SAM simulationsplit (int) – The frequency to split the data too, typically this is the number of years the system was simulated for (system_lifetime_yrs)
- Returns:
Numpy array of length system_lifetime_yrs containing the yearly energy in kWh
- Return type:
np.array