############################################################################
#               Figure generation (plotting, ML, inverse design)

# Created by:   Huy Pham
#               University of California, Berkeley

# Date created: April 2024

# Description:  Main file which imports the structural database and starts the
# loss estimation

# Open issues:  (1) 

############################################################################
import sys
# caution: path[0] is reserved for script path (or '' in REPL)
sys.path.insert(1, '../')

import pickle
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
from doe import GP

plt.rcParams["text.usetex"] = True
plt.rcParams["font.family"] = "serif"
plt.rcParams["mathtext.fontset"] = "dejavuserif"
title_font=20
axis_font = 18
subt_font = 18
label_size = 16
mpl.rcParams['xtick.labelsize'] = label_size 
mpl.rcParams['ytick.labelsize'] = label_size 

import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning) 
warnings.filterwarnings("ignore", category=FutureWarning) 
pd.options.mode.chained_assignment = None  

plt.close('all')

main_obj = pd.read_pickle("../../data/loss/structural_db_complete_loss.pickle")

# with open("../../data/tfp_mf_db.pickle", 'rb') as picklefile:
#     main_obj = pickle.load(picklefile)
    
main_obj.calculate_collapse()

df_raw = main_obj.ops_analysis
df_raw = df_raw.reset_index(drop=True)

# remove the singular outlier point
from scipy import stats
df = df_raw[np.abs(stats.zscore(df_raw['collapse_prob'])) < 5].copy()

# df = df.drop(columns=['index'])
# df = df_whole.head(100).copy()

df['max_drift'] = df.PID.apply(max)
df['log_drift'] = np.log(df['max_drift'])

df['max_velo'] = df.PFV.apply(max)
df['max_accel'] = df.PFA.apply(max)

df['T_ratio'] = df['T_m'] / df['T_fb']
df['T_ratio_e'] = df['T_m'] / df['T_fbe']
pi = 3.14159
g = 386.4

zetaRef = [0.02, 0.05, 0.10, 0.20, 0.30, 0.40, 0.50]
BmRef   = [0.8, 1.0, 1.2, 1.5, 1.7, 1.9, 2.0]
df['Bm'] = np.interp(df['zeta_e'], zetaRef, BmRef)

df['gap_ratio'] = (df['constructed_moat']*4*pi**2)/ \
    (g*(df['sa_tm']/df['Bm'])*df['T_m']**2)

df_loss = main_obj.loss_data

max_obj = pd.read_pickle("../../data/loss/structural_db_complete_max_loss.pickle")
df_loss_max = max_obj.max_loss

#%%
# make a generalized 2D plotting grid, defaulted to gap and Ry
# grid is based on the bounds of input data
def make_2D_plotting_space(X, res, x_var='gap_ratio', y_var='RI', 
                           all_vars=['gap_ratio', 'RI', 'T_ratio', 'zeta_e'],
                           third_var_set = None, fourth_var_set = None,
                           x_bounds=None, y_bounds=None):
    
    if x_bounds == None:
        x_min = min(X[x_var])
        x_max = max(X[x_var])
    else:
        x_min = x_bounds[0]
        x_max = x_bounds[1]
    if y_bounds == None:
        y_min = min(X[y_var])
        y_max = max(X[y_var])
    else:
        y_min = y_bounds[0]
        y_max = y_bounds[1]
    xx, yy = np.meshgrid(np.linspace(x_min,
                                     x_max,
                                     res),
                         np.linspace(y_min,
                                     y_max,
                                     res))

    rem_vars = [i for i in all_vars if i not in [x_var, y_var]]
    third_var = rem_vars[0]
    fourth_var = rem_vars[-1]
       
    xx = xx
    yy = yy
    
    if third_var_set is None:
        third_var_val= X[third_var].median()
    else:
        third_var_val = third_var_set
    if fourth_var_set is None:
        fourth_var_val = X[fourth_var].median()
    else:
        fourth_var_val = fourth_var_set
    
    
    X_pl = pd.DataFrame({x_var:xx.ravel(),
                         y_var:yy.ravel(),
                         third_var:np.repeat(third_var_val,
                                             res*res),
                         fourth_var:np.repeat(fourth_var_val, 
                                              res*res)})
    X_plot = X_pl[all_vars]
                         
    return(X_plot)


#%% normalize DVs and prepare all variables
df['bldg_area'] = df['L_bldg']**2 * (df['num_stories'] + 1)

df['replacement_cost'] = 600.0*(df['bldg_area'])
df['total_cmp_cost'] = df_loss_max['cost_50%']
df['cmp_replace_cost_ratio'] = df['total_cmp_cost']/df['replacement_cost']
df['median_cost_ratio'] = df_loss['cost_50%']/df['replacement_cost']
df['cmp_cost_ratio'] = df_loss['cost_50%']/df['total_cmp_cost']

# but working in parallel (2x faster)
df['replacement_time'] = df['bldg_area']/1000*365
df['total_cmp_time'] = df_loss_max['time_l_50%']
df['cmp_replace_time_ratio'] = df['total_cmp_time']/df['replacement_time']
df['median_time_ratio'] = df_loss['time_l_50%']/df['replacement_time']
df['cmp_time_ratio'] = df_loss['time_l_50%']/df['total_cmp_time']

df['replacement_freq'] = df_loss['replacement_freq']

df[['B_50%', 'C_50%', 'D_50%', 'E_50%']] = df_loss[['B_50%', 'C_50%', 'D_50%', 'E_50%']]

df['impacted'] = pd.to_numeric(df['impacted'])

cost_var = 'cmp_cost_ratio'
time_var = 'cmp_time_ratio'
covariate_list = ['gap_ratio', 'RI', 'T_ratio', 'zeta_e']

mask = df['B_50%'].isnull()

df['B_50%'].loc[mask] = df_loss_max['B_50%'].loc[mask]
df['C_50%'].loc[mask] = df_loss_max['C_50%'].loc[mask]
df['D_50%'].loc[mask] = df_loss_max['D_50%'].loc[mask]
df['E_50%'].loc[mask] = df_loss_max['E_50%'].loc[mask]


#%% subsets

df_no_impact = df[df['impacted'] == 0]

# remove the singular outlier point
from scipy import stats
df_no_impact = df_no_impact[np.abs(stats.zscore(df_no_impact['cmp_cost_ratio'])) < 5].copy()

df_tfp = df_no_impact[df_no_impact['isolator_system'] == 'TFP']
df_lrb = df_no_impact[df_no_impact['isolator_system'] == 'LRB']
df_cbf = df_no_impact[df_no_impact['superstructure_system'] == 'CBF']
df_mf = df_no_impact[df_no_impact['superstructure_system'] == 'MF']



#%% Calculate upfront cost of data

def moment_frame_cost(df, steel_per_unit=1.25):
    n_bays = df.num_bays
    
    # ft
    L_beam = df.L_bay
    h_story = df.h_story
    
    all_beams = df.beam
    all_cols = df.column
    
    # sum of per-length-weight of all floors
    col_wt = [float(member.split('X',1)[1]) for member in all_cols]
    beam_wt = [float(member.split('X',1)[1]) for member in all_beams] 
    
    # col_all_wt = np.array(list(map(sum, col_wt)))
    # beam_all_wt = np.array(list(map(sum, beam_wt)))
    
    # only 2 lateral frames
    n_frames = 4
    n_cols = 4*n_bays
    
    floor_col_length = np.array(n_cols*h_story, dtype=float)
    floor_beam_length = np.array(L_beam * n_bays * n_frames, dtype=float)
        
    floor_col_wt = col_wt*floor_col_length 
    floor_beam_wt = beam_wt*floor_beam_length
    
    bldg_wt = sum(floor_col_wt) + sum(floor_beam_wt)
    
    steel_cost = steel_per_unit*bldg_wt
    return(steel_cost)

def braced_frame_cost(df, brace_db, steel_per_unit=1.25):
    n_bays = df.num_bays
    
    # ft
    L_beam = df.L_bay
    h_story = df.h_story
    n_stories = df.num_stories
    
    from math import atan, cos
    theta = atan(h_story/(L_beam/2))
    L_brace = (L_beam/2)/cos(theta)
    
    all_beams = df.beam
    all_cols = df.column
    all_braces = df.brace
    
    n_braced = int(round(n_bays/2.25))
    n_braced = max(n_braced, 1)
    
    # sum of per-length-weight of all floors
    col_wt = [float(member.split('X',1)[1]) for member in all_cols]
    beam_wt = [float(member.split('X',1)[1]) for member in all_beams] 
    brace_wt = [brace_db.loc[brace_db['AISC_Manual_Label'] == brace_name]['W'].item() 
                    for brace_name in all_braces]
    
    # only 2 lateral frames
    n_frames = 4
    
    # in CBF, only count the big frames
    n_cols = 4*(n_braced+1)
    
    floor_col_length = np.array(n_cols*h_story, dtype=float)
    floor_beam_length = np.array(L_beam * n_braced * n_frames, dtype=float)
    floor_brace_length = np.array(L_brace * n_braced * n_frames, dtype=float)
    
    n_every_col = 4*n_bays
    full_frame_col_length = np.array(n_every_col*h_story, dtype=float)
    full_frame_beam_length = np.array(L_beam * n_bays * n_frames, dtype=float)
    grav_col_length = full_frame_col_length - floor_col_length
    grav_beam_length = full_frame_beam_length - floor_beam_length
    
    # assume W14x120 grav columns, W16x31 beams
    grav_col_wt = np.repeat(120.0, n_stories)*grav_col_length
    grav_beam_wt = np.repeat(31.0, n_stories)*grav_beam_length
    
    floor_col_wt = col_wt*floor_col_length 
    floor_beam_wt = beam_wt*floor_beam_length
    floor_brace_wt = brace_wt*floor_brace_length
    
    bldg_wt = (sum(floor_col_wt) + sum(floor_beam_wt) + sum(floor_brace_wt) +
               sum(grav_col_wt) + sum(grav_beam_wt))
    
    steel_cost = steel_per_unit*bldg_wt
    
    return(steel_cost)

def calc_steel_cost(df, brace_db, steel_per_unit=1.25):
    superstructure_system = df.superstructure_system
    
    if superstructure_system == 'MF':
        return moment_frame_cost(df, steel_per_unit=steel_per_unit)
    else:
        return braced_frame_cost(df, brace_db, steel_per_unit=steel_per_unit)
    
    
db_string = '../../resource/'
brace_db = pd.read_csv(db_string+'braceShapes.csv', index_col=None, header=0)  

df['steel_cost'] = df.apply(
       lambda row: calc_steel_cost(
           row, brace_db=brace_db,
           steel_per_unit=1.25),
       axis='columns', result_type='expand')

df['steel_cost_per_sf'] = df['steel_cost'] / df['bldg_area']

#%% steel weight calc plot

# plt.close('all')

df_cbf = df[df['superstructure_system'] == 'CBF']
df_mf = df[df['superstructure_system'] == 'MF']


cmap = plt.cm.tab10

fig, ax = plt.subplots(1, 1, figsize=(8,6))
ax.scatter(df_cbf['Vs'], df_cbf['steel_cost'], alpha=0.5, marker='^',
           c=df_cbf['bldg_area'], label='CBF')
ax.scatter(df_mf['Vs'], df_mf['steel_cost'], alpha=0.5, marker='o',
           c=df_mf['bldg_area'], label='MF')

ax.set_ylabel("Steel cost (\$)", fontsize=axis_font)
ax.set_xlabel('$V_s$ (kip)', fontsize=axis_font)

ax.legend()

#%% two loss metrics

# # plt.close('all')

# df_cbf = df[df['superstructure_system'] == 'CBF']
# df_mf = df[df['superstructure_system'] == 'MF']

# df_cbf_max = df_loss_max[df['superstructure_system'] == 'CBF']
# df_mf_max = df_loss_max[df['superstructure_system'] == 'MF']

# cmap = plt.cm.tab10

# fig, ax = plt.subplots(1, 1, figsize=(8,6))
# ax.scatter(df_cbf['steel_cost'], df_cbf_max['B_50%'], alpha=0.5, color=cmap(1), label='CBF')
# ax.scatter(df_mf['steel_cost'], df_mf_max['B_50%'], alpha=0.5, color=cmap(0), label='MF')

# ax.set_ylabel("Structural component cost (\$)", fontsize=axis_font)
# ax.set_xlabel('Steel cost (\$)', fontsize=axis_font)

# ax.legend()

#%% area normalization

# plt.close('all')

df_cbf = df[df['superstructure_system'] == 'CBF']
df_mf = df[df['superstructure_system'] == 'MF']


cmap = plt.cm.tab10
fig = plt.figure(figsize=(16, 7))
ax = fig.add_subplot(1, 2, 1)
ax.scatter(df_cbf['bldg_area'], df_cbf['Vs'], alpha=0.5, color=cmap(1), label='CBF')
ax.scatter(df_mf['bldg_area'], df_mf['Vs'], alpha=0.5, color=cmap(0), label='MF')

ax.set_xlabel("Building area (sq ft)", fontsize=axis_font)
ax.set_ylabel('$V_s$ (kip)', fontsize=axis_font)

ax.legend()

ax = fig.add_subplot(1, 2, 2)
ax.scatter(df_cbf['Vs'], df_cbf['steel_cost_per_sf'], 
           alpha=0.5, marker='^', c=df_cbf['bldg_area'], label='CBF')
sc=ax.scatter(df_mf['Vs'], df_mf['steel_cost_per_sf'], 
           alpha=0.5, c=df_mf['bldg_area'], label='MF')

ax.set_ylabel("Steel cost per sf (\$)", fontsize=axis_font)
ax.set_xlabel('$V_s$ (kip)', fontsize=axis_font)
cbar = plt.colorbar(sc)
cbar.set_label('Building area (sf)', rotation = 270, fontsize=axis_font)
ax.legend()
fig.tight_layout()
#%% regressions of cost

# linear regress cost as f(base shear)
from sklearn.linear_model import LinearRegression
reg_mf = LinearRegression(fit_intercept=False)
reg_mf.fit(X=df_mf[['Vs']], y=df_mf[['steel_cost']])

reg_cbf = LinearRegression(fit_intercept=False)
reg_cbf.fit(X=df_cbf[['Vs']], y=df_cbf[['steel_cost']])

reg_dict = {
    'mf':reg_mf,
    'cbf':reg_cbf
    }
#%% calculate cost of new point

def calc_upfront_cost(X, config_dict, steel_cost_dict,
                      land_cost_per_sqft=2837/(3.28**2)):
    
    from scipy.interpolate import interp1d
    zeta_ref = [0.02, 0.05, 0.10, 0.20, 0.30, 0.40, 0.50]
    Bm_ref = [0.8, 1.0, 1.2, 1.5, 1.7, 1.9, 2.0]
    interp_f = interp1d(zeta_ref, Bm_ref)
    Bm = interp_f(X['zeta_e'])
    
    # estimate Tm
    config_df = pd.DataFrame(config_dict, index=[0])
    from loads import estimate_period, define_gravity_loads
    W_and_loads = config_df.apply(lambda row: define_gravity_loads(row),
                                            axis='columns', result_type='expand')
    
    # order of outputs are below
    # W_seis, W_super, w_on_frame, P_on_leaning_column, all_w_cases, all_plc_cases
    W_seis = W_and_loads.iloc[0][0]
    W_super = W_and_loads.iloc[0][1]
    
    # perform calculation for both MF and CBF
    X_query = X.copy()
    X_query['h_bldg'] = config_dict['num_stories'] * config_dict['h_story']
    
    # estimate periods
    X_mf = X_query.copy()
    X_mf['superstructure_system'] = 'MF'
    X_mf['T_fbe'] = X_mf.apply(lambda row: estimate_period(row),
                                                     axis='columns', result_type='expand')
    
    X_cbf = X_query.copy()
    X_cbf['superstructure_system'] = 'CBF'
    X_cbf['h_bldg'] = config_dict['num_stories'] * config_dict['h_story']
    X_cbf['T_fbe'] = X_cbf.apply(lambda row: estimate_period(row),
                                                     axis='columns', result_type='expand')
    
    
    X_query['T_fbe_mf'] = X_mf['T_fbe']
    X_query['T_fbe_cbf'] = X_cbf['T_fbe']
    
    X_query['T_m_mf'] = X_query['T_fbe_mf'] * X_query['T_ratio']
    X_query['T_m_cbf'] = X_query['T_fbe_cbf'] * X_query['T_ratio']
    
    # calculate moat gap
    pi = 3.14159
    g = 386.4
    SaTm_mf = config_dict['S_1']/X_query['T_m_mf']
    moat_gap_mf = X_query['gap_ratio'] * (g*(SaTm_mf/Bm)*X_query['T_m_mf']**2)/(4*pi**2)
    
    # calculate design base shear
    kM_mf = (1/g)*(2*pi/X_query['T_m_mf'])**2
    Dm_mf = g*config_dict['S_1']*X_query['T_m_mf']/(4*pi**2*Bm)
    Vb_mf = Dm_mf * kM_mf * W_super / 2
    Vst_mf = Vb_mf*(W_super/W_seis)**(1 - 2.5*X_query['zeta_e'])
    Vs_mf = Vst_mf/X_query['RI']
    
    # regression was done for steel cost ~ Vs
    reg_mf = steel_cost_dict['mf']
    try:
        steel_cost_mf = reg_mf.intercept_.item() + reg_mf.coef_.item()*Vs_mf
    except:
        steel_cost_mf = reg_mf.intercept_ + reg_mf.coef_.item()*Vs_mf    
    
    L_bldg = config_dict['L_bay']*config_dict['num_bays']
    land_area_mf = (L_bldg*12.0 + moat_gap_mf)**2
    land_cost_mf = land_cost_per_sqft/144.0 * land_area_mf
    
    # repeat for cbf
    # calculate moat gap
    pi = 3.14159
    g = 386.4
    SaTm_cbf = config_dict['S_1']/X_query['T_m_cbf']
    moat_gap_cbf = X_query['gap_ratio'] * (g*(SaTm_cbf/Bm)*X_query['T_m_cbf']**2)/(4*pi**2)
    
    # calculate design base shear
    kM_cbf = (1/g)*(2*pi/X_query['T_m_cbf'])**2
    Dm_cbf = g*config_dict['S_1']*X_query['T_m_cbf']/(4*pi**2*Bm)
    Vb_cbf = Dm_cbf * kM_cbf * W_super / 2
    Vst_cbf = Vb_cbf*(W_super/W_seis)**(1 - 2.5*X_query['zeta_e'])
    Vs_cbf = Vst_cbf/X_query['RI']
    
    # regression was done for steel cost ~ Vs
    reg_cbf = steel_cost_dict['cbf']
    try:
        steel_cost_cbf = reg_cbf.intercept_.item() + reg_cbf.coef_.item()*Vs_cbf
    except:
        steel_cost_cbf = reg_cbf.intercept_ + reg_cbf.coef_.item()*Vs_cbf
        
    L_bldg = config_dict['L_bay']*config_dict['num_bays']
    land_area_cbf = (L_bldg*12.0 + moat_gap_cbf)**2
    land_cost_cbf = land_cost_per_sqft/144.0 * land_area_cbf
    
    return({'total_mf': steel_cost_mf + land_cost_mf,
            'steel_mf': steel_cost_mf,
            'land_mf': land_cost_mf,
           'total_cbf': steel_cost_cbf + land_cost_cbf,
           'steel_cbf': steel_cost_cbf,
           'land_cbf': land_cost_cbf,
           'Vs_cbf': Vs_cbf,
           'Vs_mf': Vs_mf})

def make_design_space(res, zeta_fix=None):
    if zeta_fix is None:
        xx, yy, uu, vv = np.meshgrid(np.linspace(0.6, 1.5,
                                                 res),
                                     np.linspace(0.5, 2.25,
                                                 res),
                                     np.linspace(2.0, 5.0,
                                                 res),
                                     np.linspace(0.1, 0.25,
                                                 res))
    else:
        xx, yy, uu, vv = np.meshgrid(np.linspace(0.6, 1.5,
                                                 res),
                                     np.linspace(0.5, 2.25,
                                                 res),
                                     np.linspace(2.0, 5.0,
                                                 res),
                                     zeta_fix)    
                                 
    X_space = pd.DataFrame({'gap_ratio':xx.ravel(),
                         'RI':yy.ravel(),
                         'T_ratio':uu.ravel(),
                         'zeta_e':vv.ravel()})

    return(X_space)

#%%
res_des = 5
X_space = make_design_space(res_des)

config_dict = {
    'num_stories': 2,
    'h_story': 13.0,
    'num_bays': 2,
    'num_frames': 2,
    'S_s': 2.2815,
    'L_bay': 30.0,
    'S_1': 1.017
    }

cost_dict = calc_upfront_cost(X_space, config_dict=config_dict, steel_cost_dict=reg_dict)

#%% 

cmap = plt.cm.tab10

fig, ax = plt.subplots(1, 1, figsize=(8,6))
ax.scatter(cost_dict['Vs_cbf'], cost_dict['steel_cbf'], color=cmap(1), label='CBF-design')
ax.scatter(cost_dict['Vs_mf'], cost_dict['steel_mf'], color=cmap(0), label='MF-design')

ax.scatter(df_cbf['Vs'], df_cbf['steel_cost'], 
           alpha=0.3, color=cmap(1), marker='^', label='CBF-data')
ax.scatter(df_mf['Vs'], df_mf['steel_cost'], 
           alpha=0.3, color=cmap(0), marker='^', label='MF-data')

ax.set_ylabel("Upfront cost (\$)", fontsize=axis_font)
ax.set_xlabel('$V_s$ (kip)', fontsize=axis_font)

ax.legend()

#%% 

cmap = plt.cm.tab10

fig, ax = plt.subplots(1, 1, figsize=(8,6))
ax.scatter(df_cbf['Vs'], df_cbf['steel_cost'], 
           alpha=0.3, color=cmap(1), label='CBF-data')
ax.scatter(df_mf['Vs'], df_mf['steel_cost'], 
           alpha=0.3, color=cmap(0), label='MF-data')

Vs = np.linspace(0, 7000, 200)
cost_regr_mf = reg_mf.coef_.item()*Vs
cost_regr_cbf = reg_cbf.coef_.item()*Vs

ax.plot(Vs, cost_regr_mf, color=cmap(0), label='MF cost model')
ax.plot(Vs, cost_regr_cbf, color=cmap(1), label='CBF cost model')

ax.set_ylabel("Upfront cost (\$)", fontsize=axis_font)
ax.set_xlabel('$V_s$ (kip)', fontsize=axis_font)

ax.legend()

#%% subset by stories

# plt.close('all')

cmap = plt.cm.tab10

fig = plt.figure(figsize=(16, 7))
ax = fig.add_subplot(1, 2, 1)
ax.scatter(df_cbf['Vs'], df_cbf['steel_cost'], 
           alpha=0.3, color=cmap(1), label='CBF-data')
ax.scatter(df_mf['Vs'], df_mf['steel_cost'], 
           alpha=0.3, color=cmap(0), label='MF-data')

# joined model
reg_mf = LinearRegression(fit_intercept=False)
reg_mf.fit(X=df_mf[['Vs']], y=df_mf[['steel_cost']])
reg_cbf = LinearRegression(fit_intercept=False)
reg_cbf.fit(X=df_cbf[['Vs']], y=df_cbf[['steel_cost']])
Vs = np.linspace(0, 7000, 200)
cost_regr_mf = reg_mf.coef_.item()*Vs
cost_regr_cbf = reg_cbf.coef_.item()*Vs
ax.plot(Vs, cost_regr_mf, color=cmap(0), label='MF cost model')
ax.plot(Vs, cost_regr_cbf, color=cmap(1), label='CBF cost model')

# 2 stories only
df_mf_set = df_mf[df_mf['num_stories'] == 2]
df_cbf_set = df_cbf[df_cbf['num_stories'] == 2]
reg_mf = LinearRegression(fit_intercept=False)
reg_mf.fit(X=df_mf_set[['Vs']], y=df_mf_set[['steel_cost']])
reg_cbf = LinearRegression(fit_intercept=False)
reg_cbf.fit(X=df_cbf_set[['Vs']], y=df_cbf_set[['steel_cost']])
cost_regr_mf = reg_mf.coef_.item()*Vs
cost_regr_cbf = reg_cbf.coef_.item()*Vs
ax.plot(Vs, cost_regr_mf, color=cmap(0), linewidth=0.9, 
        linestyle=':', label='MF-story conditioned')
ax.plot(Vs, cost_regr_cbf, color=cmap(1), linewidth=0.9, 
        linestyle=':', label='CBF-story conditioned')

ax.legend()

for n in range(3,8):
    # 3 stories only
    df_mf_set = df_mf[df_mf['num_stories'] == n]
    df_cbf_set = df_cbf[df_cbf['num_stories'] == n]
    reg_mf = LinearRegression(fit_intercept=False)
    reg_mf.fit(X=df_mf_set[['Vs']], y=df_mf_set[['steel_cost']])
    reg_cbf = LinearRegression(fit_intercept=False)
    reg_cbf.fit(X=df_cbf_set[['Vs']], y=df_cbf_set[['steel_cost']])
    cost_regr_mf = reg_mf.coef_.item()*Vs
    cost_regr_cbf = reg_cbf.coef_.item()*Vs
    ax.plot(Vs, cost_regr_mf, color=cmap(0), linewidth=0.9, 
            linestyle=':', label='MF-story conditioned')
    ax.plot(Vs, cost_regr_cbf, color=cmap(1), linewidth=0.9, 
            linestyle=':', label='CBF-story conditioned')
    
ax.set_ylabel("Upfront cost (\$)", fontsize=axis_font)
ax.set_xlabel('$V_s$ (kip)', fontsize=axis_font)

ax = fig.add_subplot(1, 2, 2)
ax.scatter(df_cbf['Vs'], df_cbf['steel_cost'], 
           alpha=0.3, color=cmap(1), label='CBF-data')
ax.scatter(df_mf['Vs'], df_mf['steel_cost'], 
           alpha=0.3, color=cmap(0), label='MF-data')

# joined model
reg_mf = LinearRegression(fit_intercept=False)
reg_mf.fit(X=df_mf[['Vs']], y=df_mf[['steel_cost']])
reg_cbf = LinearRegression(fit_intercept=False)
reg_cbf.fit(X=df_cbf[['Vs']], y=df_cbf[['steel_cost']])
Vs = np.linspace(0, 7000, 200)
cost_regr_mf = reg_mf.coef_.item()*Vs
cost_regr_cbf = reg_cbf.coef_.item()*Vs
ax.plot(Vs, cost_regr_mf, color=cmap(0), label='MF cost model')
ax.plot(Vs, cost_regr_cbf, color=cmap(1), label='CBF cost model')

# 2 stories only
df_mf_set = df_mf[df_mf['num_stories'] == 2]
df_cbf_set = df_cbf[df_cbf['num_stories'] == 2]
reg_mf = LinearRegression(fit_intercept=False)
reg_mf.fit(X=df_mf_set[['Vs']], y=df_mf_set[['steel_cost']])
reg_cbf = LinearRegression(fit_intercept=False)
reg_cbf.fit(X=df_cbf_set[['Vs']], y=df_cbf_set[['steel_cost']])
cost_regr_mf = reg_mf.coef_.item()*Vs
cost_regr_cbf = reg_cbf.coef_.item()*Vs
ax.plot(Vs, cost_regr_mf, color=cmap(0), linewidth=0.9, 
        linestyle=':', label='MF-bay conditioned')
ax.plot(Vs, cost_regr_cbf, color=cmap(1), linewidth=0.9, 
        linestyle=':', label='CBF-bay conditioned')

ax.legend()

for n in range(3,8):
    # 3 stories only
    df_mf_set = df_mf[df_mf['num_bays'] == n]
    df_cbf_set = df_cbf[df_cbf['num_bays'] == n]
    reg_mf = LinearRegression(fit_intercept=False)
    reg_mf.fit(X=df_mf_set[['Vs']], y=df_mf_set[['steel_cost']])
    reg_cbf = LinearRegression(fit_intercept=False)
    reg_cbf.fit(X=df_cbf_set[['Vs']], y=df_cbf_set[['steel_cost']])
    cost_regr_mf = reg_mf.coef_.item()*Vs
    cost_regr_cbf = reg_cbf.coef_.item()*Vs
    ax.plot(Vs, cost_regr_mf, color=cmap(0), linewidth=0.9, 
            linestyle=':', label='MF-bay conditioned')
    ax.plot(Vs, cost_regr_cbf, color=cmap(1), linewidth=0.9, 
            linestyle=':', label='CBF-bay conditioned')
    
ax.set_ylabel("Upfront cost (\$)", fontsize=axis_font)
ax.set_xlabel('$V_s$ (kip)', fontsize=axis_font)