Source code for pyH2A.Analysis.Sensitivity_Analysis

import copy
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from pyH2A.Discounted_Cash_Flow import Discounted_Cash_Flow
from pyH2A.Utilities.input_modification import num, convert_input_to_dictionary, parse_parameter, get_by_path, set_by_path
from pyH2A.Utilities.output_utilities import make_bold, Figure_Lean, dynamic_value_formatting

import pprint

[docs]class Sensitivity_Analysis: '''Sensitivity analysis for multiple parameters. Parameters ---------- Sensitivity_Analysis > [...] > Name : str Display name for parameter, e.g. used for plot labels. Sensitivity_Analysis > [...] > Type : str Type of parameter values. If `Type` is 'value', provided values are used as is. If `Type` is 'factor', provided values are multiplied with base value of parameter in input file. Sensitivity_Analysis > [...] > Values : str Value pair to be used for sensitivity analysis. One value should be higher than the base value, the other should be lower. Specified in following format: value A; value B (order is irrelevant). E.g. '0.3; 10'. Notes ----- `Sensitivity_Analysis` contains parameters which are to be varied in sensitivity analysis. First column specifies path to parameter in input file (top key > middle key > bottom key format, e.g. Catalyst > Cost per kg ($) > Value). Order of parameters is not relevant. ''' def __init__(self, input_file): self.inp = convert_input_to_dictionary(input_file) self.base_case = Discounted_Cash_Flow(input_file, print_info = False) #self.results = self.perform_sensitivity_analysis()
[docs] def perform_sensitivity_analysis(self, format_cutoff = 7): '''Perform sensitivity analysis. Parameters ---------- format_cutoff : int Length of number string above which dyanmic formatting is applied. ''' sensitivity_results = {} for key in self.inp['Sensitivity_Analysis']: parameters = parse_parameter(key) name = self.inp['Sensitivity_Analysis'][key]['Name'] sensitivity_results[name] = {} sensitivity_results[name]['Base'] = dynamic_value_formatting(get_by_path(self.inp, parameters), cutoff = format_cutoff) sensitivity_results[name]['Values'] = {} values = parse_parameter(self.inp['Sensitivity_Analysis'][key]['Values'], delimiter = ';') for value in values: input_dict = copy.deepcopy(self.inp) numerical_value = num(value) value_type = self.inp['Sensitivity_Analysis'][key]['Type'] set_by_path(input_dict, parameters, numerical_value, value_type = value_type) if self.inp['Sensitivity_Analysis'][key]['Type'] == 'factor': sensitivity_results[name]['Base'] = '1.0x' shown_value = '{0}x'.format(numerical_value) else: if '%' in value: shown_value = value sensitivity_results[name]['Base'] = '{0}%'.format(dynamic_value_formatting( get_by_path(self.inp, parameters) * 100), cutoff = format_cutoff) else: shown_value = dynamic_value_formatting(numerical_value, cutoff = format_cutoff) dcf = Discounted_Cash_Flow(input_dict, print_info = False) sensitivity_results[name]['Values'][shown_value] = dcf.h2_cost return sensitivity_results
[docs] def sort_h2_cost_values(self, data): '''Sort H2 cost values. ''' for key in data: values = data[key]['Values'] low_key = min(values, key = values.get) high_key = max(values, key = values.get) data[key]['Low - Name'] = low_key data[key]['Low - Value'] = values[low_key] data[key]['High - Name'] = high_key data[key]['High - Value'] = values[high_key] del data[key]['Values']
[docs] def sensitivity_box_plot(self, ax = None, figure_lean = True, height = 0.8, label_offset = 0.1, lim_extra = 0.2, format_cutoff = 7, plot_kwargs = {}, **kwargs): '''Plot sensitivity box plot. Parameters ---------- ax : matplotlib.axes, optional Axes object in which plot is drawn. Default is None, creating new plot. figure_lean : bool, optional If figure_lean is True, matplotlib.fig object is returned. height : float, optional Height of bars. label_offset : float, optional Offset for bar labels. lim_extra : float, optional Fractional increase of x axis limits. format_cutoff : int Length of number string above which dyanmic formatting is applied. plot_kwargs: dict, optional Dictionary containing optional keyword arguments for :func:`~pyH2A.Utilities.output_utilities.Figure_Lean`, has priority over `**kwargs`. **kwargs: Additional `kwargs` passed to :func:`~pyH2A.Utilities.output_utilities.Figure_Lean` Returns ------- figure : matplotlib.fig or None matplotlib.fig is returned if `figure_lean` is True. Notes ----- In plot, parameters are sorted by descending cost increase magnitude. ''' self.results = self.perform_sensitivity_analysis(format_cutoff = format_cutoff) data = copy.deepcopy(self.results) self.sort_h2_cost_values(data) df = pd.DataFrame.from_dict(data) df.sort_values(by = ['High - Value'], axis = 1, na_position = 'first', inplace = True) kwargs = {**{'left': 0.45, 'right': 0.99, 'bottom': 0.2, 'top': 0.95, 'fig_width': 7.5, 'fig_height': 4, 'name': 'Sensitivity_Box_Plot'}, **kwargs, **plot_kwargs} if ax is None: figure = Figure_Lean(**kwargs) ax = figure.ax number_of_entries = len(df.columns) base_case = self.base_case.h2_cost max_value = df.loc['High - Value'].max(skipna = True) min_value = df.loc['Low - Value'].min(skipna = True) x_width = max_value - min_value label_offset = x_width * label_offset extra = x_width * lim_extra xlim = [min_value - extra, max_value + extra] ylim = [-height, number_of_entries] labels = [] for counter, key in enumerate(df): lower = df[key]['Low - Value'] upper = df[key]['High - Value'] rectangle_left = patches.Rectangle((lower, counter-height/2), base_case - lower, height, edgecolor = 'none', facecolor = 'darkgreen') rectangle_right = patches.Rectangle((base_case, counter-height/2), upper - base_case, height, edgecolor = 'none', facecolor = 'darkred') ax.add_patch(rectangle_left) ax.add_patch(rectangle_right) ax.annotate('${:.2f}'.format(lower), xy = (lower - label_offset, counter), va = 'center', ha = 'center') ax.annotate('${:.2f}'.format(upper), xy = (upper + label_offset, counter), va = 'center', ha = 'center') labels.append('{0}\n{1}, {2}, {3}'.format(make_bold(key), df[key]['Low - Name'], df[key]['Base'], df[key]['High - Name'])) ax.set_xlabel(r'Cost sensitivity / USD per kg $H_{2}$') ax.set_yticks(np.arange(0, number_of_entries)) ax.set_yticklabels(labels) ax.grid(color = 'grey', linestyle = '--', linewidth = 0.2) ax.set_xlim(xlim[0], xlim[1]) ax.set_ylim(ylim[0], ylim[1]) ax.plot((base_case, base_case), (ylim[0], ylim[1]), '--', color = 'black') if figure_lean is True: figure.execute() return figure.fig