Source code for model_package.Calibrate.summarize_calibration_results

import subprocess as sp
import numpy
import os
import sys
import argparse
import time
import glob
import yaml
import inspect

import seaborn
import matplotlib.pyplot
import pandas


[docs] def write_elastic_material_card(output_file, input_dict): '''Write elastic micromorphic material card :param str output_file: The root filename of the output yaml file :param dict input_dict: A dictionary containing calibrated parameters Returns: Writes ``output_file``.yml ''' defaults = { 'lamb': 0.0, 'mu': 0.0, 'eta': 0.0, 'tau': 0.0, 'kappa': 0.0, 'nu': 0.0, 'sigma': 0.0, 'tau1': 0.0, 'tau2': 0.0, 'tau3': 0.0, 'tau4': 0.0, 'tau5': 0.0, 'tau6': 0.0, 'tau7': 0.0001, 'tau8': 0.0, 'tau9': 0.0, 'tau10': 0.0, 'tau11': 0.0} # Use defaults if a parameter is not specified for key in defaults.keys(): if key not in input_dict.keys(): input_dict[key] = defaults[key] # elastic output_dict = {} output_dict['line 1'] = f"2 {input_dict['lamb']} {input_dict['mu']}" output_dict['line 2'] = f"5 {input_dict['eta']} {input_dict['tau']} {input_dict['kappa']} {input_dict['nu']} {input_dict['sigma']}" output_dict['line 3'] = f"11 {input_dict['tau1']} {input_dict['tau2']} {input_dict['tau3']} {input_dict['tau4']} {input_dict['tau5']} {input_dict['tau6']} {input_dict['tau7']} {input_dict['tau8']} {input_dict['tau9']} {input_dict['tau10']} {input_dict['tau11']}" output_dict['line 4'] = f"2 {input_dict['tau']} {input_dict['sigma']}" with open(f'{output_file}.yml', 'w') as f: yaml.dump(output_dict, f) return 0
[docs] def write_plastic_material_card(output_file, input_dict): '''Write elastic micromorphic material card :param str output_file: The root filename of the output yaml file :param dict input_dict: A dictionary containing calibrated parameters Returns: Writes ``output_file``.yml ''' multiplier = 10 defaults = { 'cu0': 3.192202765, 'Hu': 1e-8, 'cchi0': 1e-8, 'Hchi': 1e-8, 'friction': 0, 'cgradchi0': 1e-8, 'Hgradchi': 1e-8, 'lamb': 0.0, 'mu': 0.0, 'eta': 0.0, 'tau': 0.0, 'kappa': 0.0, 'nu': 0.0, 'sigma': 0.0, 'tau1': 0.0, 'tau2': 0.0, 'tau3': 0.0, 'tau4': 0.0, 'tau5': 0.0, 'tau6': 0.0, 'tau7': 0.0001, 'tau8': 0.0, 'tau9': 0.0, 'tau10': 0.0, 'tau11': 0.0, 'int_params_a': 0.5, 'int_params_b': 1e-9} # Use defaults if a parameter is not specified for key in defaults.keys(): if key not in input_dict.keys(): input_dict[key] = defaults[key] output_dict = {} # plastic output_dict['line 01'] = f"2 {input_dict['cu0']} {-1*multiplier*input_dict['mu']}" output_dict['line 02'] = f'2 1e8 1e-8' output_dict['line 03'] = f'2 1e8 1e-8' output_dict['line 04'] = "2 0. 0." output_dict['line 05'] = "2 0. 0." output_dict['line 06'] = "2 0. 0." output_dict['line 07'] = "2 0. 0." output_dict['line 08'] = "2 0. 0." output_dict['line 09'] = "2 0. 0." # elastic output_dict['line 10'] = f"2 {input_dict['lamb']} {input_dict['mu']}" output_dict['line 11'] = f"5 {input_dict['eta']} {input_dict['tau']} {input_dict['kappa']} {input_dict['nu']} {input_dict['sigma']}" output_dict['line 12'] = f"11 {input_dict['tau1']} {input_dict['tau2']} {input_dict['tau3']} {input_dict['tau4']} {input_dict['tau5']} {input_dict['tau6']} {input_dict['tau7']} {input_dict['tau8']} {input_dict['tau9']} {input_dict['tau10']} {input_dict['tau11']}" output_dict['line 13'] = f"2 {input_dict['tau']} {input_dict['sigma']}" # integration output_dict['line 14'] = '0.5 0.5 0.5 1e-9 1e-9' with open(f'{output_file}_plastic_{multiplier}.yml', 'w') as f: yaml.dump(output_dict, f) return 0
[docs] def collect_parameters(parameter_sets, case): '''Collect calibration results from one or more yaml files :param list parameter_sets: List of yaml files containing calibration results :param int case: The calibration "case". 1: two parameter, 2: 7 parameter,\ 3: 7 parameter plus tau7, 4: all 18 parameters :returns: dictionary containing list of parameter results with each key corresponding to a parameter name ''' results_dict = { 'element':[], 'lamb':[], 'mu':[], 'eta':[], 'tau':[], 'kappa':[], 'nu':[], 'sigma':[], 'tau1':[], 'tau2':[], 'tau3':[], 'tau4':[], 'tau5':[], 'tau6':[], 'tau7':[], 'tau8':[], 'tau9':[], 'tau10':[], 'tau11':[]} # unpack all 18 values even if they're zero for i, set in enumerate(parameter_sets): # Load yaml file stream = open(set, 'r') UI = yaml.load(stream, Loader=yaml.FullLoader) stream.close() mat_line_1 = UI['line 1'] mat_line_2 = UI['line 2'] mat_line_3 = UI['line 3'] mat_line_4 = UI['line 4'] # Store results into dictionary results_dict['element'].append(i) results_dict['lamb'].append(float(mat_line_1.split(' ')[1])) results_dict['mu'].append(float(mat_line_1.split(' ')[2])) results_dict['eta'].append(float(mat_line_2.split(' ')[1])) results_dict['tau'].append(float(mat_line_2.split(' ')[2])) results_dict['kappa'].append(float(mat_line_2.split(' ')[3])) results_dict['nu'].append(float(mat_line_2.split(' ')[4])) results_dict['sigma'].append(float(mat_line_2.split(' ')[5])) results_dict['tau1'].append(float(mat_line_3.split(' ')[1])) results_dict['tau2'].append(float(mat_line_3.split(' ')[2])) results_dict['tau3'].append(float(mat_line_3.split(' ')[3])) results_dict['tau4'].append(float(mat_line_3.split(' ')[4])) results_dict['tau5'].append(float(mat_line_3.split(' ')[5])) results_dict['tau6'].append(float(mat_line_3.split(' ')[6])) results_dict['tau7'].append(float(mat_line_3.split(' ')[7])) results_dict['tau8'].append(float(mat_line_3.split(' ')[8])) results_dict['tau9'].append(float(mat_line_3.split(' ')[9])) results_dict['tau10'].append(float(mat_line_3.split(' ')[10])) results_dict['tau11'].append(float(mat_line_3.split(' ')[11])) # remove zero entries depending on case remove = [] if case == 1: remove = ['eta','tau','kappa','nu','sigma','tau1','tau2','tau3', 'tau4','tau5','tau6','tau7','tau8','tau9','tau10','tau11'] elif case == 2: remove = ['tau1','tau2','tau3','tau4','tau5','tau6','tau7','tau8', 'tau9','tau10','tau11'] elif case == 3: remove = ['tau1','tau2','tau3','tau4','tau5','tau6','tau8','tau9', 'tau10','tau11'] for item in remove: results_dict.pop(item) return(results_dict)
[docs] def make_summary_csv(summary_csv, results_dict): '''Make a csv file summarizing the mean, min, max, and standard deviation of calibrated parameters :param str summary_csv: Filename to store summary statistics of calibrated parameters :param dict results_dict: Results dictionary containing list of parameters with each key corresponding to a parameter name :returns: ``summary_csv`` ''' params, means, mins, maxs, devs = [], [], [], [], [] for key in set(results_dict) - {'element'}: # get stats params.append(key) means.append(numpy.mean(results_dict[key])) mins.append(numpy.min(results_dict[key])) maxs.append(numpy.max(results_dict[key])) devs.append(numpy.std(results_dict[key])) # output df = pandas.DataFrame({'param': params, 'mean': means, 'min': mins, 'max': maxs, 'dev': devs}) df.to_csv(summary_csv, header=True, sep=',', index=False) return 0
[docs] def kde(rootname, results_dict, type, kde_best_parameters=None): '''Create a kernel density estimate (KDE) plot for each calibrated parameter :param str rootname: The rootname of the output plot :param dict results_dict: Dictionary containing list of parameter results with each key corresponding to a parameter :param str type: A string specifying the type of KDE to plot. 'kde' gives a regular KDE plot. 'hist' gives a KDE plot with histograms shown :param str kde_best_parameters: Optional root filename to output a yaml file containing the "best" parameters sampled from the kernel density estimate associated with "kde_best" :returns: ``{rootname}_{key}_{type}.PNG`` for each key in `results_dict`, write ``{kde_best_parameters}.yml`` if requested ''' output_parameters = {} for key in set(results_dict) - {'element'}: matplotlib.pyplot.figure() if type != 'best': if type == 'kde': ax = seaborn.displot(results_dict[key], kind='kde', color='red', fill=True) elif type == 'hist': ax = seaborn.displot(results_dict[key], kde=True, color='red', fill=True) ax.set(xlabel=f'parameter {key}', ylabel='KDE') matplotlib.pyplot.title(key) matplotlib.pyplot.tight_layout() matplotlib.pyplot.savefig(f'{rootname}_{key}_{type}.PNG') else: ax = seaborn.kdeplot(results_dict[key], color='red', fill=False) xs, ys = ax.lines[-1].get_data() ax.fill_between(xs, ys, color='red', alpha=0.1) mode_idx = numpy.argmax(ys) output_parameters[key] = xs[mode_idx] best_value = f'{xs[mode_idx]:.6f}' ax.set(xlabel=f'parameter {key}', ylabel='KDE') matplotlib.pyplot.title(f'Best {key} = {best_value}') matplotlib.pyplot.tight_layout() matplotlib.pyplot.savefig(f'{rootname}_{key}.png') # output if kde_best_parameters: write_elastic_material_card(kde_best_parameters, output_parameters) write_plastic_material_card(kde_best_parameters, output_parameters) return 0
[docs] def summarize_calibration_results(parameter_sets, case, results_csv=None, summary_csv=None, kde_hist_plot=None, kde_plot=None, kde_best=None, kde_best_parameters=None,): '''Main function to drive parameter summary and output :param list parameter_sets: List of yaml files containing calibration results :param int case: The calibration "case". 1: two parameter, 2: 7 parameter,\ 3: 7 parameter plus tau7, 4: all 18 parameters :param str results_csv: Optional filename to store all calibrated parameter values :param str summary_csv: Optional filename to store summary statistics of calibrated parameters :param str kde_hist_plot: Optional root filename to plot kernel density estimate of each calibrated parameter with histogram :param str kde_plot: Optional root filename to plot kernel density estimate of each calibrated parameter :param str kde_best_parameters: Optional root filename to output a yaml file containing the "best" parameters sampled from the kernel density estimate associated with "kde_best" ''' results_dict = collect_parameters(parameter_sets, case) if results_csv: results_df = pandas.DataFrame(results_dict) results_df.to_csv(results_csv, sep=',', index=False) if summary_csv: make_summary_csv(summary_csv, results_dict) if kde_hist_plot: kde(kde_hist_plot, results_dict, 'hist') if kde_plot: kde(kde_plot, results_dict, 'kde') if kde_best: kde(kde_best, results_dict, 'best', kde_best_parameters) return 0
def get_parser(): filename = inspect.getfile(lambda: None) basename = os.path.basename(filename) basename_without_extension, extension = os.path.splitext(basename) cli_description = "Summarize results of parameter calibration" parser = argparse.ArgumentParser(description=cli_description, prog=os.path.basename(filename)) parser.add_argument('--parameter-sets', nargs="+", required=True, help='Specify the list of yaml files containing calibration results') parser.add_argument('--case', type=int, required=True, help='Specify the calibration "case". 1: two parameter, 2: 7 parameter,\ 3: 7 parameter plus tau7, 4: all 18 parameters') parser.add_argument('--results-csv', type=str, required=False, help='Optional filename to store all calibrated parameter values') parser.add_argument('--summary-csv', type=str, required=False, help='Optional filename to store summary statistics of calibrated parameters') parser.add_argument('--kde-hist-plot', type=str, required=False, help='Optional root filename to plot kernel density estimate of each calibrated parameter with histogram') parser.add_argument('--kde-plot', type=str, required=False, help='Optional root filename to plot kernel density estimate of each calibrated parameter') parser.add_argument('--kde-best', type=str, required=False, help='Optional root filename to plot kernel density estimate of each calibrated parameter with maximum value in title') parser.add_argument('--kde-best-parameters', type=str, required=False, default=None, help='Optional root filename to output a yaml file containing the "best" parameters sampled from the kernel density estimate associated with "--kde-best"') return parser if __name__ == '__main__': parser = get_parser() args, unknown = parser.parse_known_args() sys.exit(summarize_calibration_results(parameter_sets=args.parameter_sets, case=args.case, results_csv=args.results_csv, summary_csv=args.summary_csv, kde_hist_plot=args.kde_hist_plot, kde_plot=args.kde_plot, kde_best=args.kde_best, kde_best_parameters=args.kde_best_parameters, ))