"""
InfraFair: Modelling tool for Infrastructure Cost Allocation
Developed by: Mohamed A.Eltahir Elabbas - November 23, 2023

mabbas@comillas.edu
mohamed.a.eltahir@hotmail.com
https://www.iit.comillas.edu/people/mabbas

Instituto de Investigacion Tecnologica
Escuela Tecnica Superior de Ingenieria - ICAI
UNIVERSIDAD PONTIFICIA COMILLAS
C. de Sta. Cruz de Marcenado, 26
28015 Madrid, Spain
"""

from xml.sax.saxutils import prepare_input_source
from matplotlib.collections import Collection
from collections import Counter
import pandas as pd
import numpy as np
import os
import sys
import warnings
import time
from typing import Tuple  # For Python 3.8
import argparse
import platform

os.system('color')
warnings.filterwarnings("ignore")

#%% definitions
parser = argparse.ArgumentParser(description='Introducing main parameters...')
parser.add_argument('--case',   type=str, default=None)
parser.add_argument('--dir',    type=str, default=None)
parser.add_argument('--config', type=str, default=None)

os_name = platform.system()
DIR     = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..'))
CASE    = os.path.join('Examples','Simple_ex','Simple_Example')
CONFIGF = 'InfraFair control inputs'

# Thanks to http://patorjk.com/software/taag/
logo = r"""
$$$$$$\            $$$$$$\                      $$$$$$$$\           $$\           
\_$$  _|          $$  __$$\                     $$  _____|          \__|          
  $$ |  $$$$$$$\  $$ /  \__| $$$$$$\   $$$$$$\  $$ |       $$$$$$\  $$\  $$$$$$\  
  $$ |  $$  __$$\ $$$$\     $$  __$$\  \____$$\ $$$$$\     \____$$\ $$ |$$  __$$\ 
  $$ |  $$ |  $$ |$$  _|    $$ |  \__| $$$$$$$ |$$  __|    $$$$$$$ |$$ |$$ |  \__|
  $$ |  $$ |  $$ |$$ |      $$ |      $$  __$$ |$$ |      $$  __$$ |$$ |$$ |      
$$$$$$\ $$ |  $$ |$$ |      $$ |      \$$$$$$$ |$$ |      \$$$$$$$ |$$ |$$ |      
\______|\__|  \__|\__|      \__|       \_______|\__|       \_______|\__|\__|      
"""


#%% utility/auxiliary functions

def get_line_index(lines: pd.DataFrame, node1: int, node2: int) -> int:
    "This function return the index of the line, from the lines matrix, connecting two nodes"
    # Note: The assumption here is that there is no two lines with the same nodes, i.e., no double circuits

    line_name   = str(node1) + "-" + str(node2)
    temp        = lines[lines["Line"]  == line_name].index.values
    if len(temp) == 0: # if it is empty
        line_name   = str(node2) + "-" + str(node1)
      
    return lines[lines["Line"]  == line_name].index.values


def get_node_index(node: int, nodes_matrix: pd.DataFrame) -> int:
    "This function return the index of a node"

    return nodes_matrix[nodes_matrix["Node"] == node].index.values[0]


def get_total_nodal_flows(flows: np.ndarray, gen: np.ndarray, dem: np.ndarray) -> np.ndarray:
    "This function return a flow matrix with the generation and demand as inflows and outflows, respectively"

    nodal       = dem - gen
    flows_node  = np.diag(nodal[:,0])
    flows_node  += flows

    return flows_node


def get_node_owner(node: int, nodes_matrix: pd.DataFrame, column: str) -> int:
    "This function return the country of a node"

    return nodes_matrix[column][nodes_matrix[nodes_matrix["Node"] == node].index.values[0]]


def get_line_SOs(Line_name:str, attribute_DF: pd.DataFrame, nodes_DF: pd.DataFrame, attribute_dict:dict) -> Tuple[str,str]:
    "This functions return the name of the SOs owning the line"

    node1, node2    = Line_name.split("-")
    node1, node2    =  int(node1), int(node2)
    SO1,  SO2       = "",""
    if "Line" in attribute_DF.columns:
        Temp_DF         = attribute_DF.set_index(["Line"])
    else:
        Temp_DF         = attribute_DF
    L_Type          = Temp_DF["Type"][Temp_DF[Temp_DF.index == Line_name].index.values[0]]
    
    if "Three-winding Transformer" in attribute_dict:
        if attribute_dict[L_Type] == "Three-winding Transformer":     # check if it is 3 winding transformer
            if isinstance(get_node_owner(node2, nodes_DF, "SO 2"),str):
                SO1 = get_node_owner(node2, nodes_DF, "SO 1")
                SO2 = get_node_owner(node2, nodes_DF, "SO 2")
            else:
                SO1 = get_node_owner(node1, nodes_DF, "SO 1")
                SO2 = get_node_owner(node1, nodes_DF, "SO 2")
    else:
        SO1 = get_node_owner(node1, nodes_DF, "SO 1")
        SO2 = get_node_owner(node2, nodes_DF, "SO 1")
    
    return SO1, SO2 
        

def extract_negative_demand(demand: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
    "This function separates the negative demand (generation) from the normal demand"

    n_demand = np.zeros(demand.shape)
    for index in range(len(demand)):
        if demand[index] < 0:
            n_demand[index] = demand[index]

    p_demand = demand - n_demand
    
    return n_demand, p_demand


def get_flow_direction(line_matrix: pd.DataFrame, contribution_matrix)-> pd.DataFrame:
    "This function returns the contribution matrix with the direction of the flow as the direction of the input flow"

    flow_signs = np.sign(line_matrix["Flow"].to_numpy())[None]
    if isinstance(contribution_matrix, pd.DataFrame):
        matrix_with_direction = pd.DataFrame(index=contribution_matrix.index)
        for column in contribution_matrix.columns:
            matrix_with_direction[column] = (contribution_matrix[column].to_numpy()[None] * flow_signs).transpose()
    elif isinstance(contribution_matrix, np.ndarray):
        matrix_with_direction = contribution_matrix * flow_signs

    return matrix_with_direction


def get_negative_demand_contribution(negative_demand: np.ndarray, generation: np.ndarray, contribution_matrix: np.ndarray, 
                                    nodes_matrix: pd.DataFrame, lines_matrix: pd.DataFrame) -> pd.DataFrame:
    "This functions gives separate accounts to the contribution of the generation and the negative demand at the same node"

    indices_with_negative_demand                = np.nonzero((negative_demand < 0) * negative_demand)[0]
    indices_with_negative_demand_and_generation = np.nonzero(((negative_demand < 0) & (generation > 0)))[0]
    indices_with_negative_demand_only           = [i for i in indices_with_negative_demand if i not in indices_with_negative_demand_and_generation]
    indices_with_negative_demand_only_panda     = [1+i for i in indices_with_negative_demand if i not in indices_with_negative_demand_and_generation]

    ngd_contribution = pd.DataFrame(
        contribution_matrix[indices_with_negative_demand_only],
        index=nodes_matrix["Node"][indices_with_negative_demand_only_panda].astype(str)
        + "ND",
        columns=lines_matrix["Line"],
    )
    temp = pd.DataFrame(contribution_matrix[indices_with_negative_demand_and_generation], columns=lines_matrix["Line"],)
    for i in range(len(indices_with_negative_demand_and_generation)):
        node_index      = indices_with_negative_demand_and_generation[i]
        node            = nodes_matrix["Node"][node_index+1]

        ngd             = -negative_demand[node_index]
        g               = generation[node_index]
        sum             = ngd + g
        ngd_ratio       = ngd / sum
        g_ratio         = g / sum

        ngd_ser         = temp.xs(i) * ngd_ratio
        ngd_ser.name    = str(node) + "ND"
        g_ser           = temp.xs(i) * g_ratio
        g_ser.name      = str(node) + "G"

        ngd_contribution = pd.concat([ngd_contribution, pd.DataFrame(ngd_ser).transpose()])
        ngd_contribution = pd.concat([ngd_contribution, pd.DataFrame(g_ser).transpose()])

    return ngd_contribution


def get_aggregation_per_category(group_contribution_per_asset:pd.DataFrame, attributes_DF:pd.DataFrame) -> pd.DataFrame:
    "This function receive the contribution per asset and aggregate them according to asset type and voltage level"

    summation   = pd.DataFrame(index=group_contribution_per_asset.columns)
    asset_types = Counter(sorted(attributes_DF["Type"]))
    for a_type in asset_types:
        a_type_indices      = attributes_DF.index[attributes_DF["Type"] == a_type].tolist()
        selected_asset_type = attributes_DF.loc[a_type_indices,:]
        asset_voltages      = Counter(sorted(selected_asset_type["Voltage"], reverse=True))
        for a_voltage in asset_voltages:
            a_voltage_indices   = selected_asset_type.index[selected_asset_type["Voltage"] == a_voltage].tolist()
            summation[f'Asset Type:{a_type},Voltage:{a_voltage} kV'] = group_contribution_per_asset.loc[a_voltage_indices,:].sum().to_list()

    return summation


def get_utilization_per_category(flow_km_contribution:pd.DataFrame, flow_contribution:pd.DataFrame, flow_km_matrix:pd.DataFrame, flow_matrix:pd.DataFrame, attribute_dic:dict) -> pd.DataFrame:
    "This functions return the utilization of asset per category by using flow-Km for lines and flow for other assets"

    transmission_key            = [key for key, val in attribute_dic.items() if val == 'Transmission line']
    columns_to_drop1            = [col for col in flow_contribution.columns if col.startswith("Asset Type:"+str(transmission_key[0]))]
    columns_to_drop2            = [col for col in flow_km_contribution.columns if not col.startswith("Asset Type:"+str(transmission_key[0]))]
    flow_contribution_joint     = pd.concat([flow_km_contribution.drop(columns=columns_to_drop2), flow_contribution.drop(columns=columns_to_drop1)], axis=1)
    flow_rated_joint            = pd.concat([flow_km_matrix.drop(columns=columns_to_drop2), flow_matrix.drop(columns=columns_to_drop1)], axis=1)
    output                      = 100*flow_contribution_joint.to_numpy()/flow_rated_joint.to_numpy().transpose()[:,0]
    output[np.isnan(output)]    = 0
    output[np.isinf(output)]    = 0
    
    return  pd.DataFrame(output, index=flow_contribution_joint.index, columns=flow_contribution_joint.columns)
          

def remove_zero_rows_and_columns(data_frame:pd.DataFrame, rows:bool=True, columns:bool=True) -> pd.DataFrame:
    "This functions remove empty rows and/or columns from a DataFrame"

    df = data_frame.copy()# I would need to rename the index
    if rows:
        # Remove rows where all values are zero
        df = df.loc[(df != 0).any(axis=1)]
    if columns:
        # Remove columns where all values are zero
        df = df.loc[:, (df != 0).any(axis=0)]

    return df


def print_to_csv(name: str, matrix: np.ndarray, index: pd.Series, columns: pd.Series, total: bool = False, remove_zeros: bool = False):
    "This function exporting/printing the result of numpy array to a csv file"

    Data_frame = pd.DataFrame(matrix, index=index, columns=columns)
    if total:
        Data_frame                  = Data_frame.transpose()
        last_row                    = Data_frame.sum(axis=1)
        Data_frame["Total"]    = last_row
        Data_frame                  = Data_frame.transpose()
    if remove_zeros:
        # Remove rows where all values are zero
        Data_frame = Data_frame.loc[(Data_frame != 0).any(axis=1)]
        # Remove columns where all values are zero
        Data_frame = Data_frame.loc[:, (Data_frame != 0).any(axis=0)]

    Data_frame.to_csv("%s.csv" % name)


def exit_error(msg: str):
    RED = "\033[31m"
    RESET = "\033[0m"
    print(f"{RED}ERROR{RESET}: {msg}", file=sys.stderr)
    sys.exit(1)


#%% primary functions

def get_input_matrices(lines_matrix: pd.DataFrame, nodes_matrix: pd.DataFrame, attribute_matrix: pd.DataFrame, attribute_dic:dict, index_name:str = 'Line', SO_owner:bool = False, process_line_ownership:bool = False, reactance:bool = False) -> Tuple[np.ndarray, np.ndarray, list, np.ndarray, np.ndarray, np.ndarray, pd.DataFrame, pd.DataFrame, pd.DataFrame]:
    "This function prepares the basic input matrices from the excel file and also returns interconnections between countries and owners of the lines"
    
    if index_name == "Line ID":
        lines_matrix.set_index([index_name],inplace=True)
    gen                 = nodes_matrix["Generation"].to_numpy()[None].transpose()           # The generation matrix
    dem                 = nodes_matrix["Demand"].to_numpy()[None].transpose()               # The demand matrix
    phi                 = lines_matrix["Flow"].to_numpy()[None].transpose()                 # The flow matrix
    phi_positive        = np.absolute(phi)                                                  # Positive flow matrix
    interconnections_C  = pd.DataFrame(columns=["Line","Country 1", "Country 2", "Flow"])   # Interconnection matrix between countries
    interconnections_T  = pd.DataFrame(columns=["Line","SO 1", "SO 2", "Flow"])             # Interconnection matrix between SOs
    ownership           = pd.DataFrame(lines_matrix["Line"],index = lines_matrix.index)
    if reactance:
        react = attribute_matrix["React"].to_numpy().tolist()  # The reactance matrix
    else:
        react = []
    flows_matrix                        = np.zeros((nodes_matrix.shape[0], nodes_matrix.shape[0]))  # Flow matrix that shows the inflows (negative) and outflows (positive) of each node
    ownership["Country 1"]              = ownership["Country 2"]            = ""
    ownership["Country 1 Ownership"]    = ownership["Country 2 Ownership"]  = 0.0
    if process_line_ownership and SO_owner:
        ownership["SO Owner 1"]     = ownership["SO Owner 2"]      = ""
        ownership["SO 1 Ownership"] = ownership["SO 2 Ownership"]  = 0.0
    
    for index in lines_matrix.index:
        node1, node2 = lines_matrix["Line"][index].split("-")
        node1, node2 =  int(node1), int(node2)
        flows_matrix[get_node_index(node1, nodes_matrix) - 1, get_node_index(node2, nodes_matrix) - 1] += lines_matrix["Flow"][index]
        flows_matrix[get_node_index(node2, nodes_matrix) - 1, get_node_index(node1, nodes_matrix) - 1] -= lines_matrix["Flow"][index]
        # extracting interconnections and ownership
        country1                        = get_node_owner(node1, nodes_matrix, "Country")
        country2                        = get_node_owner(node2, nodes_matrix, "Country")
        ownership["Country 1"][index]   = country1
        ownership["Country 2"][index]   = country2
        if country1 != country2:
            interconnections_C = pd.concat([interconnections_C, pd.DataFrame.from_records([{"Line": lines_matrix["Line"][index], "Country 1": country1, "Country 2": country2, "Flow": lines_matrix["Flow"][index]}], index =[index])]) #updated for pandas 2.2
            ownership["Country 1 Ownership"][index] = 0.5
            ownership["Country 2 Ownership"][index] = 0.5
        else:
            ownership["Country 1 Ownership"][index] = 1
            ownership["Country 2 Ownership"][index] = 0
        if SO_owner:
            L_SO1, L_SO2           = get_line_SOs(lines_matrix["Line"][index],attribute_matrix, nodes_matrix,attribute_dic)
            if L_SO1 != L_SO2 and isinstance(L_SO2,str):
                interconnections_T = pd.concat([interconnections_T, pd.DataFrame.from_records([{"Line": lines_matrix["Line"][index], "SO 1": L_SO1, "SO 2": L_SO2, "Flow": lines_matrix["Flow"][index]}], index =[index])])
      
        if process_line_ownership and SO_owner:
            ownership["SO Owner 1"][index], ownership["SO Owner 2"][index] = L_SO1, L_SO2
            if not isinstance(L_SO2,str):  # fill in the empty SO
                ownership["SO Owner 2"][index]     = L_SO1
            if L_SO1 == L_SO2 or isinstance(L_SO2,float):
                ownership["SO 1 Ownership"][index] = 1
                ownership["SO 2 Ownership"][index] = 0
            else:
                ownership["SO 1 Ownership"][index] = 0.5
                ownership["SO 2 Ownership"][index] = 0.5

    # interconnections_C  = interconnections_C.set_index(["Line"])  # upgrade 3.12 comment
    # interconnections_T  = interconnections_T.set_index(["Line"])  # upgrade 3.12 comment

    return gen, dem, react, flows_matrix, phi, phi_positive, interconnections_C, interconnections_T, ownership


def get_pout_pg_matrices(lines_matrix: pd.DataFrame, nodes_matrix: pd.DataFrame, flows: np.ndarray, gen: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
    "This function calculates the contribution of inflows to outflows"

    number_of_lines = int(lines_matrix.shape[0])
    pout            = np.zeros((number_of_lines, number_of_lines)).astype(float)
    pg              = np.zeros((number_of_lines, len(gen))).astype(float)

    sum_of_inflows_and_injections = ((flows < 0) * flows).sum(1) * -1.0

    for index in lines_matrix.index:
        temp = lines_matrix["Line"][index].split("-")
        flow_on_the_line = 0.0

        if lines_matrix["Flow"][index] > 0:
            sending_node = int(temp[0])
            flow_on_the_line = lines_matrix["Flow"][index]
        else:
            sending_node = int(temp[1])
            flow_on_the_line = -lines_matrix["Flow"][index]

        sending_node_index                  = get_node_index(sending_node, nodes_matrix)
        sending_nodes_indices               = np.nonzero((flows[sending_node_index - 1, :] < 0) * flows[sending_node_index - 1, :])[0]
        sending_nodes_indices               += 1  # adding +1 because these are matrix indices, starts from 0, from flows to indices in nodes_matrix, starts from 1.
        sending_nodes_of_line_sending_node  = nodes_matrix["Node"][sending_nodes_indices].tolist()

        if sum_of_inflows_and_injections[sending_node_index - 1] > 0:
            contribution = flow_on_the_line/ sum_of_inflows_and_injections[sending_node_index - 1]
        else:
            contribution = 0.0

        for j in range(len(sending_nodes_of_line_sending_node)):
            if sending_node != sending_nodes_of_line_sending_node[j]:
                temp_index = get_line_index(lines_matrix, sending_nodes_of_line_sending_node[j], sending_node)
                for i in temp_index:
                    pout[index - 1, i - 1] = contribution

        if gen[sending_node_index - 1, 0] != 0:
            pg[index - 1, sending_node_index - 1] = contribution

    return pout, pg


def get_pin_pd_matrices(lines_matrix: pd.DataFrame, nodes_matrix: pd.DataFrame, flows: np.ndarray, dem: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
    "This function calculates the contribution of outflows to inflows"

    number_of_lines = int(lines_matrix.shape[0])
    pin             = np.zeros((number_of_lines, number_of_lines)).astype(float)
    pd              = np.zeros((number_of_lines, len(dem))).astype(float)
    
    sum_of_outflows_and_withdrawals = ((flows > 0) * flows).sum(1)

    for index in lines_matrix.index:
        temp                = lines_matrix["Line"][index].split("-")
        flow_on_the_line    = 0.0

        if lines_matrix["Flow"][index] < 0:
            receiving_node      = int(temp[0])
            flow_on_the_line    = -lines_matrix["Flow"][index]
        else:
            receiving_node      = int(temp[1])
            flow_on_the_line    = lines_matrix["Flow"][index]

        receiving_node_index                    = get_node_index(receiving_node, nodes_matrix)
        receiving_nodes_indices                 = np.nonzero((flows[receiving_node_index - 1, :] > 0) * flows[receiving_node_index - 1, :])[0]
        receiving_nodes_indices                 += 1
        receiving_nodes_of_line_receiving_node  = nodes_matrix["Node"][receiving_nodes_indices].tolist()

        if sum_of_outflows_and_withdrawals[receiving_node_index - 1] > 0:
            contribution = flow_on_the_line/sum_of_outflows_and_withdrawals[receiving_node_index - 1]
        else:
            contribution = 0.0

        for j in range(len(receiving_nodes_of_line_receiving_node)):
            if receiving_node != receiving_nodes_of_line_receiving_node[j]:
                temp_index                 = get_line_index(lines_matrix, receiving_node, receiving_nodes_of_line_receiving_node[j])
                for i in temp_index:
                    pin[index - 1, i - 1]  = contribution

        if dem[receiving_node_index - 1, 0] != 0:
            pd[index - 1, receiving_node_index - 1] = contribution

    return pin, pd


def get_contribution_per_asset(contribution_matrix: np.ndarray, nodes_matrix: pd.DataFrame, lines_matrix: pd.DataFrame, grouping: str, index_name:str) -> Tuple[pd.DataFrame, pd.DataFrame]:
    "This function aggregates the contribution of a group of agents, such as countries, SOs or even zones, per network asset"

    groups               = Counter(nodes_matrix[grouping])  # type: Collection.Counters
    groups_contribution  = pd.DataFrame(index = lines_matrix[index_name])
    group_node           = pd.DataFrame(nodes_matrix["Node"], index = nodes_matrix.index)
    for x in groups: # countries loop
        group_node[x]                       = 0.0
        group_nodes_indices                 = nodes_matrix.index[nodes_matrix[grouping] == x].tolist()
        group_node[x][group_nodes_indices]  = 1
        group_nodes_indices                 = [i - 1 for i in group_nodes_indices]
        groups_contribution[x]              = np.sum(np.array(contribution_matrix[group_nodes_indices]), 0)
    
    return groups_contribution, group_node


def get_contribution_per_group(contribution_by_group_matrix: pd.DataFrame, reactance: list, factor: float, Ownership_DF: pd.DataFrame, group_interconnections: pd.DataFrame, grouping: str) -> Tuple[pd.DataFrame, pd.DataFrame]:
    "This function calculates the contribution of each group of agents, such as countries, SOs or even zones, per group of network assets"

    intermediate_matrix1    = pd.DataFrame(index=contribution_by_group_matrix.index)
    Line_country_owner      = pd.DataFrame(0.0, index=Ownership_DF.index, columns=contribution_by_group_matrix.columns)
    diff_owner_line_indices = Ownership_DF.index[Ownership_DF[grouping+" 1"] != Ownership_DF[grouping+" 2"]].tolist()

    for group in contribution_by_group_matrix:
        if len(reactance) > 0:
            intermediate_matrix1[group] = (contribution_by_group_matrix[group] * reactance * factor)
        else:
            intermediate_matrix1[group] = contribution_by_group_matrix[group]

        country_line_indices                                        = Ownership_DF.index[Ownership_DF[grouping+" 1"] == group].tolist()        
        if grouping == "Country" or grouping == "Zone":
            Line_country_owner[group][country_line_indices]         = 1
        else:
            Line_country_owner.loc[country_line_indices, group]     = Ownership_DF.loc[country_line_indices,"SO 1 Ownership"]

        country_line_indices                                        = Ownership_DF[(Ownership_DF[grouping+" 2"] == group) & (Ownership_DF.index.isin(diff_owner_line_indices))].index.tolist()
        if grouping == "Country":
            Line_country_owner[group][country_line_indices]         = 1
            Line_country_owner[group][group_interconnections.index] *= 0.5  
        else:
            Line_country_owner.loc[country_line_indices, group]     = Ownership_DF.loc[country_line_indices,"SO 2 Ownership"]
            
    countries_responsibility_matrix                     = pd.DataFrame(np.matmul(intermediate_matrix1.to_numpy().transpose(),Line_country_owner.to_numpy()), index=contribution_by_group_matrix.columns, columns=contribution_by_group_matrix.columns)
    diagonal                                            = np.diag(countries_responsibility_matrix)
    use_of                                              = countries_responsibility_matrix.sum(axis=1) - diagonal
    use_by                                              = countries_responsibility_matrix.sum() - diagonal
    countries_responsibility_matrix["Used by others"]   = use_by
    countries_responsibility_matrix["Use of others"]    = use_of
    countries_responsibility_matrix["Net use"]          = use_by - use_of

    return countries_responsibility_matrix, Line_country_owner


#%% running the model function

def InfraFair_run(directory_file:str, case_file:str, config_file:str) -> float:
    "This is the main function to run the model"

    start_time = time.time()

    #%% read inputs
    # data inputs
    input_file                  = os.path.join(directory_file, case_file + '.xlsx')
    nodes_sn                    = pd.read_excel(input_file, sheet_name ="Network", index_col=0) 
    lines_sn                    = pd.read_excel(input_file, sheet_name ="Flows", index_col=0)
    lines_attributes            = pd.read_excel(input_file, sheet_name ="Assets attributes", index_col=0)

    # re-indexing all dataframes
    nodes_sn.reset_index(inplace=True, drop=True)
    nodes_sn.index          +=1
    lines_sn.reset_index(inplace=True, drop=True)
    lines_sn.index          +=1
    lines_attributes.reset_index(inplace=True, drop=True)
    lines_attributes.index  +=1

    #%% input data checks
    # check if the number of assets is the same in lines_sn and line_attribute
    if len(lines_sn) != len(lines_attributes):
        exit_error("The number of assets is not the same in the 'Assets attributes' and 'Flows' tabs. " \
        "Please make sure that both tabs have the same number of assets (rows) and re-run the software again.")

    # check if the assets have the same indices in both tabs
    same        = lines_sn['Line'] == lines_attributes['Line']
    all_same    = same.all()

    if not all_same:
        # sort by lines and reindex for both
        lines_sn                = lines_sn.sort_values(by=['Line'])
        lines_attributes        = lines_attributes.sort_values(by=['Line'])
        lines_sn.reset_index(inplace=True, drop=True)
        lines_sn.index          +=1
        lines_attributes.reset_index(inplace=True, drop=True)
        lines_attributes.index  +=1

    # check if the ordered list is the same in both tabs    
    same        = lines_sn['Line'] == lines_attributes['Line']
    all_same    = same.all()
    if not all_same:
        exit_error("The list of assets is different in the 'Flows' and 'Assets attributes' tabs. Please make sure that both tabs have "\
                   "the same list of assets under column 'Line' and re-run the software again.")

    # sort for easy calculation
    if "ID" in lines_sn.columns and "ID" in lines_attributes.columns:
        lines_sn                    = lines_sn.sort_values(by=['Line',"ID"])
        lines_attributes            = lines_attributes.sort_values(by=['Line',"ID"])
    elif "ID" in lines_attributes.columns:
        lines_sn["ID"]              = lines_attributes["ID"]
        lines_sn                    = lines_sn.sort_values(by=['Line',"ID"])
        lines_attributes            = lines_attributes.sort_values(by=['Line',"ID"])
    elif "ID" in lines_sn.columns:
        lines_attributes["ID"]      = lines_sn["ID"]
        lines_sn                    = lines_sn.sort_values(by=['Line',"ID"])
        lines_attributes            = lines_attributes.sort_values(by=['Line',"ID"])
    else:
        lines_sn                    = lines_sn.sort_values(by=['Line'])
        lines_attributes            = lines_attributes.sort_values(by=['Line'])
    
    lines_sn.reset_index(inplace=True, drop=True)
    lines_sn.index          +=1
    lines_attributes.reset_index(inplace=True, drop=True)
    lines_attributes.index  +=1

    # check if there are duplicated assets and ID
    dup_flow = lines_sn['Line'].duplicated().any()
    dup_attr = lines_attributes['Line'].duplicated().any()
    if dup_flow and "ID" not in lines_sn.columns:
        exit_error("Duplicated assets were found in the 'Flows' tab without ID. An 'ID' column is required to distinguish duplicated assets. " \
        "Please add an 'ID' column and assign different IDs for duplicated assets and re-run the software again.")
    if dup_attr and "ID" not in lines_attributes.columns:
        exit_error("Duplicated assets were found in the 'Asset attributes' tab without ID. An 'ID' column is required to distinguish duplicated assets. " \
        "Please add an 'ID' column and assign different IDs for duplicated assets and re-run the software again.")
    
    # check if there is inconsistency in the duplication
    if dup_flow != dup_attr:
        exit_error("The 'Flows' and 'Asset attributes' tabs have inconsistent duplicated assets. Please make sure that the same list of assets" \
        " is provided in both tabs and re-run the software again.")

    if "ID" in lines_sn.columns:
    # check if with the provided ID, the line-ID is unique
        lines_sn['Line ID']         = lines_sn['Line'].astype(str) + '-' + lines_sn['ID'].astype(str)
        lines_attributes['Line ID'] = lines_attributes['Line'].astype(str) + '-' + lines_attributes['ID'].astype(str)
        dup2_flow                   = lines_sn['Line ID'].duplicated().any()
        dup2_attr                   = lines_attributes['Line ID'].duplicated().any()
        if dup2_flow:
            exit_error("Duplicated assets were found in the 'Flows' tab with the same ID. The 'ID' values must be unique for duplicated assets. " \
            "Please make sure to assign different IDs for each duplicated asset and re-run the software again.")
        if dup2_attr:
            exit_error("Duplicated assets were found in the 'Asset attributes' tab with the same ID. The 'ID' values must be unique for duplicated assets. " \
            "Please make sure to assign different IDs for each duplicated asset and re-run the software again.")
        
        # check if the ordered list of assets is the same in both tabs with provided ID
        same2        = lines_sn['Line ID'] == lines_attributes['Line ID']
        all_same2    = same2.all()
        
        if not all_same2:
            exit_error("The list of assets (line with ID) is different in the 'Flows' and 'Assets attributes' tabs. Please make sure that both tabs have "\
                    "the same list of assets under columns 'Line' and 'ID' and re-run the software again.")
        
        lines_attributes.set_index(["Line ID"],inplace=True)
        index_column = 'Line ID'
    else:
        lines_attributes.set_index(["Line"],inplace=True)
        index_column = 'Line'

    #%% control inputs
    config_path                     = os.path.abspath(os.path.join(input_file, '..'))
    configuration_file              = os.path.join(config_path, config_file + '.xlsx')
    control_inputs                  = pd.read_excel(configuration_file, index_col=0) 
    control_inputs                  = control_inputs.set_index(["Inputs"])
    nodal_aggregation               = control_inputs.loc["Nodal Aggregation"][0]                                    # binary 0/1   
    demand_weight                   = control_inputs.loc["Demand Cost Responsibility (%)"][0]/100                   # percentage 0-100 
    generation_weight               = control_inputs.loc["Generation Cost Responsibility (%)"][0]/100               # percentage 0-100
    demand_socialized_weight        = control_inputs.loc["Demand Socialized Cost Responsibility (%)"][0]/100        # percentage 0-100 
    generation_socialized_weight    = control_inputs.loc["Generation Socialized Cost Responsibility (%)"][0]/100    # percentage 0-100  
    asset_types                     = control_inputs.loc["Asset Types"][0].split(",")                               # list
    n_snapshots                     = control_inputs.loc["Number of Snapshots"][0]                                  # integer
    snapshots_weights               = control_inputs.loc["Snapshots Weights"][0]                                    # list with length equals n_snapshots
    voltage_threshold               = control_inputs.loc["Voltage Threshold (kV)"][0]                               # Float
    cost_assignment_op              = control_inputs.loc["Cost Allocation Option"][0]                               # integer equals 1 or 2 or 3 or 4                     
    utilization_threshold           = control_inputs.loc["Utilization Threshold (%)"][0]                            # percentage 0-100, only if cost_assignment_op equals 4 
    show_snapshot_results           = control_inputs.loc["Snapshots Results"][0]                                    # binary 0/1
    show_agent_results              = control_inputs.loc["Agent Results"][0]                                        # binary 0/1
    show_country_results            = control_inputs.loc["Country Results"][0]                                      # binary 0/1
    show_SO_results                 = control_inputs.loc["SO Results"][0]                                           # binary 0/1
    show_aggregated_results         = control_inputs.loc["Aggregated Results"][0]                                   # binary 0/1
    show_intermediary_results       = control_inputs.loc["Intermediary Results"][0]                                 # binary 0/1
    cost_of_unused_capacity_op      = control_inputs.loc["Cost of Unused Capacity"][0]                              # integer equals 0 or 1 or 2 or 3
    
    # new inputs with exception handling to be compatible with the template of input variables of version 1.0.0 
    try:   
        losses_allocation_results   = control_inputs.loc["Losses Allocation Results"][0]                            # binary 0/1    
    except KeyError:
        losses_allocation_results   =  0
    try:
        demand_losses_weight        = control_inputs.loc["Demand Losses Responsibility (%)"][0]/100                 # percentage 0-100 
    except KeyError:
        demand_losses_weight        =  0
    try:
        generation_losses_weight    = control_inputs.loc["Generation Losses Responsibility (%)"][0]/100             # percentage 0-100
    except KeyError:
        generation_losses_weight    =  0
    try:
        losses_price                = control_inputs.loc["Losses price ($/MWh)"][0]                                 # float
    except KeyError:
        losses_price                =  0
    try:
        regional_losses             = control_inputs.loc["Regional losses"][0]                                      # float
    except KeyError:
        regional_losses             =  0
    try:
        regional_cost               = control_inputs.loc["Cost of regional assets"][0]                              # float
    except KeyError:
        regional_cost               =  0        
    try:
        length_per_reactance        = control_inputs.loc["Length per Reactance (PU)"][0]                            # integer
    except KeyError:
        length_per_reactance        = 1

    # initializing control variables
    remove_zero_values  = id_col            = Reactance_process = False                                             # internal setting to input variable to remove the zero value from the results 
    usage_result   = fraction_result        = cost_result       = False
    ownership_processing                    = True
    SO_aggregation = category_aggregation   = asset_type_cost   = False
    asset_type_dic                          = {int(asset_types[i].split(":")[1]):asset_types[i].split(":")[0] for i in range(len(asset_types))} 
    if snapshots_weights == "Equal" or snapshots_weights == "equal" or snapshots_weights == "EQUAL":
        snapshots_weights_dic               = {i:8760/n_snapshots for i in range(1,n_snapshots+1)}
    else:
        snapshots_weights                   = snapshots_weights.split(",")
        snapshots_weights_dic               = {int(snapshots_weights[i].split(":")[0]):float(snapshots_weights[i].split(":")[1]) for i in range(len(snapshots_weights))} 

    # checking the optional provided attributes
    attributes_provided = lines_attributes.columns
    if "Length" in attributes_provided and show_intermediary_results:
        usage_result                 = True                      # for calculating the usage MW*Km
        line_length_matrix           = lines_attributes['Length'].to_numpy()[None].transpose()
    if "Capacity" in attributes_provided:
        fraction_result              = True                      # for calculating the fraction of asset used Flow[Mw]/rated capacity[MW] %
        line_capacity_matrix         = lines_attributes['Capacity'].to_numpy()[None].transpose()
    if "Cost" in attributes_provided:
        cost_result                  = True * fraction_result    # the fraction_result needs to be true to calculate the cost results
        if "Voltage" in attributes_provided and voltage_threshold > 0:                               # excluding the assets below the voltage threshold by making their costs zeros
            excluded_asset_indices                              = lines_attributes.index[lines_attributes["Voltage"] < voltage_threshold].tolist()
            lines_attributes["Cost"][excluded_asset_indices]    = 0
        line_cost_matrix             = lines_attributes['Cost'].to_numpy()[None].transpose()
    if "Type" in attributes_provided and "Voltage" in attributes_provided and show_aggregated_results:
        category_aggregation         = True
        if cost_result:
            cost_per_category        = get_aggregation_per_category(pd.DataFrame(data=lines_attributes["Cost"].to_numpy(), index=lines_attributes.index, columns=["Cost"]),lines_attributes)
        if fraction_result:
            flow_per_category        = get_aggregation_per_category(pd.DataFrame(data=lines_attributes["Capacity"].to_numpy(), index=lines_attributes.index, columns=["Flow"]),lines_attributes)
            if usage_result:
                flow_km_per_category = get_aggregation_per_category(pd.DataFrame(data=(lines_attributes["Capacity"].to_numpy()*lines_attributes['Length'].to_numpy()), index=lines_attributes.index, columns=["Flow"]),lines_attributes)
    if "Exist/Planned" in attributes_provided:
        asset_type_cost              = True
        existing_assets              = (lines_attributes["Exist/Planned"]== 'Exist').astype(int).to_numpy()
    if "SO 1" in nodes_sn.columns:
        SO_aggregation               = True
        if "SO Owner 1" in attributes_provided and "SO 1 Ownership" in attributes_provided and "SO Owner 2" in attributes_provided and "SO 2 Ownership" in attributes_provided:
            ownership_processing     = False
    if "ID" in attributes_provided:
        id_col                      = True
        id_column                   = lines_attributes["ID"]
    if "Regional Assets" not in attributes_provided:
        regional_losses             = 0
        regional_cost               = 0
    else:
        regional_assets             = lines_attributes['Regional Assets'].to_numpy()[None].transpose()
    
    # checking control inputs
    if length_per_reactance == 0:
        length_per_reactance        = 1                 # It doesn't have an effect on the calculation in this case
    elif "React" in attributes_provided:
        Reactance_process           = True
    if cost_assignment_op == 1:
        cost_of_unused_capacity_op  = 0                 # don't calculate the socialized cost if the full cost is allocated

    show_SO_results = show_SO_results*SO_aggregation    # don't show SO results if it is not possible to aggregate results SO-wise

    # initializing outputs from the snapshot loop
    gen_agent_flow_contribution_per_asset_overall   = np.zeros((int(nodes_sn.shape[0]),lines_sn.shape[0]))
    dem_agent_flow_contribution_per_asset_overall   = np.zeros((int(nodes_sn.shape[0]),lines_sn.shape[0]))
    line_flow_overall                               = np.zeros((int(lines_sn.shape[0]),1))
    line_losses_overall                             = np.zeros((int(lines_sn.shape[0]),1))
    generation_overall                              = np.zeros((nodes_sn.shape[0],1))
    modified_generation_overall                     = np.zeros((nodes_sn.shape[0],1))
    positive_demand_overall                         = np.zeros((nodes_sn.shape[0],1))
    negative_demand_overall                         = np.zeros((nodes_sn.shape[0],1))
    if losses_allocation_results:
        gen_agent_losses_allocation_per_asset_overall   = np.zeros((int(nodes_sn.shape[0]),lines_sn.shape[0]))
        dem_agent_losses_allocation_per_asset_overall   = np.zeros((int(nodes_sn.shape[0]),lines_sn.shape[0]))

    #%% processing input data and basic results per snapshot
    for snapshot in range(1,n_snapshots+1):
        if os_name == "Windows":
            output_file         = "Scenario " + str(snapshot) +" results\\"
        else:
            output_file         = "Scenario " + str(snapshot) +" results/"
        output_file         = os.path.join(config_path, output_file)
        current_snapshot    = str(snapshot)

        if "Losses sn"+current_snapshot in lines_sn.columns:   # checking if losses are provided
            lines           = lines_sn[["Line","Flow sn"+current_snapshot,"Losses sn"+current_snapshot, index_column]].copy()
            lines           = lines.rename(columns={"Flow sn"+current_snapshot:"Flow","Losses sn"+current_snapshot: "Losses"})
        else:
            lines                       = lines_sn[["Line","Flow sn"+current_snapshot, index_column]].copy()
            lines                       = lines.rename(columns={"Flow sn"+current_snapshot:"Flow"})
            losses_allocation_results   = 0

        if id_col:
            lines["ID"] = id_column.to_numpy()
        
        # remove duplicated columns, in case index_column equals Line
        lines = lines.loc[:, ~lines.columns.duplicated()]

        other_attributes    = [i for i in nodes_sn.columns if "Generation" not in i]
        other_attributes    = [i for i in other_attributes if "Demand" not in i]
        nodes               = nodes_sn[["Generation sn"+current_snapshot,"Demand sn"+current_snapshot] + other_attributes].copy()
        nodes               = nodes.rename(columns={"Generation sn"+current_snapshot:"Generation","Demand sn"+current_snapshot: "Demand"})

        # aggregating generation and demand of the same node, case 2
        if nodal_aggregation:
            indices_of_nodes_with_generation_and_demand = nodes.index[(nodes["Demand"] != 0) & (nodes["Generation"] != 0)].tolist()
            for i in range(len(indices_of_nodes_with_generation_and_demand)):
                aggregation = (
                    nodes.loc[indices_of_nodes_with_generation_and_demand[i], "Generation"]
                    - nodes.loc[indices_of_nodes_with_generation_and_demand[i], "Demand"]
                )
                if aggregation > 0:
                    nodes.loc[indices_of_nodes_with_generation_and_demand[i], "Generation"] = aggregation
                    nodes.loc[indices_of_nodes_with_generation_and_demand[i], "Demand"] = 0.0
                else:
                    nodes.loc[indices_of_nodes_with_generation_and_demand[i], "Generation"] = 0.0
                    nodes.loc[indices_of_nodes_with_generation_and_demand[i], "Demand"] = abs(aggregation)
        
        generation, demand, reactance, flows, phi, phiPositive, countries_interconnections, SOs_interconnections, Ownership_matrix = get_input_matrices(lines.copy(), nodes, lines_attributes, asset_type_dic, index_column, SO_aggregation, ownership_processing, Reactance_process)
        negative_demand, positive_demand    = extract_negative_demand(demand)
        modified_generation                 = generation - negative_demand
        is_all_ND_zeros                     = np.all(negative_demand == 0)

        # fill in the ownership matrix if given in the attribute file
        # Ownership_matrix                       = Ownership_matrix.set_index([index_column])   # upgrade 3.12 comment
        if not ownership_processing:    
            Ownership_matrix["SO Owner 1"]     = lines_attributes["SO Owner 1"] 
            Ownership_matrix["SO Owner 2"]     = lines_attributes["SO Owner 2"] 
            Ownership_matrix["SO 1 Ownership"] = lines_attributes["SO 1 Ownership"]
            Ownership_matrix["SO 2 Ownership"] = lines_attributes["SO 2 Ownership"]
        
        Pout, PG    = get_pout_pg_matrices(lines, nodes, get_total_nodal_flows(flows, modified_generation, np.zeros(modified_generation.shape)),modified_generation)
        Pin, PD     = get_pin_pd_matrices(lines, nodes, get_total_nodal_flows(flows, np.zeros(positive_demand.shape), positive_demand), positive_demand)

        AG = np.matmul(np.linalg.inv(np.identity(len(Pout)) - Pout), PG)
        AD = np.matmul(np.linalg.inv(np.identity(len(Pin)) - Pin), PD)
        
        # calculating the contribution of each agent to the flow of the lines
        # the assumption here is that each node has only one agent, there cannot be two demand agents and two generator agents in one node
        gen_agent_flow_contribution_per_asset           = (AG * modified_generation[:, 0]).transpose()
        dem_agent_flow_contribution_per_asset           = (AD * positive_demand[:, 0]).transpose()

        # place holder for average overall result calculation
        gen_agent_flow_contribution_per_asset_overall   += gen_agent_flow_contribution_per_asset*snapshots_weights_dic[snapshot]
        dem_agent_flow_contribution_per_asset_overall   += dem_agent_flow_contribution_per_asset*snapshots_weights_dic[snapshot]
        generation_overall                              += generation*snapshots_weights_dic[snapshot]
        modified_generation_overall                     += modified_generation*snapshots_weights_dic[snapshot]
        positive_demand_overall                         += positive_demand*snapshots_weights_dic[snapshot]
        negative_demand_overall                         += negative_demand*snapshots_weights_dic[snapshot]
        line_flow                                       = lines["Flow"].to_numpy()[None].transpose()
        line_flow                                       = np.absolute(line_flow)
        line_flow_overall                               += line_flow*snapshots_weights_dic[snapshot]
        if losses_allocation_results:
            line_losses                                 = lines["Losses"].to_numpy()[None].transpose()
            line_losses                                 = np.absolute(line_losses)
            line_losses_overall                         += line_losses*snapshots_weights_dic[snapshot]

        # defining some matrices in advance
        x, country_nodes_matrix_G   = get_contribution_per_asset(gen_agent_flow_contribution_per_asset, nodes, lines, "Country", index_column)
        x, country_nodes_matrix_D   = get_contribution_per_asset(dem_agent_flow_contribution_per_asset, nodes, lines, "Country", index_column)
        x, countries_lines          = get_contribution_per_group(x, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
        if SO_aggregation:
            y, SO_nodes_matrix_G   = get_contribution_per_asset(gen_agent_flow_contribution_per_asset, nodes, lines, "SO 1", index_column)
            y, SO_nodes_matrix_D   = get_contribution_per_asset(dem_agent_flow_contribution_per_asset, nodes, lines, "SO 1", index_column)
            y,   SOs_lines         = get_contribution_per_group(y, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")

        # calculating the overall losses results
        if losses_allocation_results:
            gen_agent_losses_allocation_per_asset           = line_losses[:,0]*gen_agent_flow_contribution_per_asset/line_flow[:,0]
            dem_agent_losses_allocation_per_asset           = line_losses[:,0]*dem_agent_flow_contribution_per_asset/line_flow[:,0]
            
            if regional_losses:
                gen_agent_losses_allocation_per_asset       = regional_assets[:,0]*gen_agent_losses_allocation_per_asset
                dem_agent_losses_allocation_per_asset       = regional_assets[:,0]*dem_agent_losses_allocation_per_asset

            gen_agent_losses_allocation_per_asset[np.isnan(gen_agent_losses_allocation_per_asset)]    = 0
            dem_agent_losses_allocation_per_asset[np.isnan(dem_agent_losses_allocation_per_asset)]    = 0
            gen_agent_losses_allocation_per_asset[np.isinf(gen_agent_losses_allocation_per_asset)]    = 0
            dem_agent_losses_allocation_per_asset[np.isinf(dem_agent_losses_allocation_per_asset)]    = 0      
            
            gen_agent_losses_allocation_per_asset           = gen_agent_losses_allocation_per_asset*generation_losses_weight
            dem_agent_losses_allocation_per_asset           = dem_agent_losses_allocation_per_asset*demand_losses_weight
            
            # total losses allocation weighted per snapshot hours
            gen_agent_losses_allocation_per_asset_overall   += gen_agent_losses_allocation_per_asset*snapshots_weights_dic[snapshot]
            dem_agent_losses_allocation_per_asset_overall   += dem_agent_losses_allocation_per_asset*snapshots_weights_dic[snapshot]

        #%% calculating results per snapshot
        if show_snapshot_results:
            if not os.path.exists(output_file):
                os.makedirs(output_file)

            if not is_all_ND_zeros:
                negative_dem_agent_contribution_per_asset = get_negative_demand_contribution(negative_demand, generation, gen_agent_flow_contribution_per_asset, nodes, lines)
            
            if show_country_results:
                # calculating the contribution of each country to the flow of each line
                gen_country_flow_contribution_per_asset, country_nodes_matrix_G = get_contribution_per_asset(gen_agent_flow_contribution_per_asset, nodes, lines, "Country", index_column)
                dem_country_flow_contribution_per_asset, country_nodes_matrix_D = get_contribution_per_asset(dem_agent_flow_contribution_per_asset, nodes, lines, "Country", index_column)
                # another way to calculate contribution_by_countries_G is through matrix multiplication = np.matmul(gen_agent_contribution_per_asset.transpose(),country_nodes_matrix_G.drop(columns=['Node']).to_numpy())
                # but I decided to keep the function since I need the loop to calculate the nodal matrix anyway, so there is no efficiency gain from removing it. 
                if show_aggregated_results:
                    # calculating the contribution of each country to the flow in other countries
                    gen_country_flow_contribution_per_country, countries_lines  = get_contribution_per_group(gen_country_flow_contribution_per_asset, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
                    dem_country_flow_contribution_per_country, countries_lines  = get_contribution_per_group(dem_country_flow_contribution_per_asset, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country")    
                    if category_aggregation:
                        gen_country_flow_contribution_per_asset_category        = get_aggregation_per_category(gen_country_flow_contribution_per_asset, lines_attributes)
                        dem_country_flow_contribution_per_asset_category        = get_aggregation_per_category(dem_country_flow_contribution_per_asset, lines_attributes)
                      
            if show_SO_results:
                # calculating the contribution of each SO to the flow of each line
                gen_SO_flow_contribution_per_asset, SO_nodes_matrix_G = get_contribution_per_asset(gen_agent_flow_contribution_per_asset, nodes, lines, "SO 1", index_column)
                dem_SO_flow_contribution_per_asset, SO_nodes_matrix_D = get_contribution_per_asset(dem_agent_flow_contribution_per_asset, nodes, lines, "SO 1", index_column)
                if show_aggregated_results:
                    # calculating the contribution of each SO to the flow in other SOs
                    gen_SO_flow_contribution_per_SO,   SOs_lines    = get_contribution_per_group(gen_SO_flow_contribution_per_asset, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                    dem_SO_flow_contribution_per_SO,   SOs_lines    = get_contribution_per_group(dem_SO_flow_contribution_per_asset, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                    if category_aggregation:
                        gen_SO_flow_contribution_per_asset_category = get_aggregation_per_category(gen_SO_flow_contribution_per_asset, lines_attributes)
                        dem_SO_flow_contribution_per_asset_category = get_aggregation_per_category(dem_SO_flow_contribution_per_asset, lines_attributes)

            # here the order matters! because country_lines and SO_lines need to be calculated first
            if show_aggregated_results and show_agent_results:
                # calculating the contribution of each agent to the flow in each country
                gen_agent_flow_contribution_per_country   = np.matmul(gen_agent_flow_contribution_per_asset,countries_lines.to_numpy())
                dem_agent_flow_contribution_per_country   = np.matmul(dem_agent_flow_contribution_per_asset,countries_lines.to_numpy())
                if SO_aggregation:    
                    # calculating the contribution of each agent to the flow in each SO
                    gen_agent_flow_contribution_per_SO   = np.matmul(gen_agent_flow_contribution_per_asset,SOs_lines.to_numpy())
                    dem_agent_flow_contribution_per_SO   = np.matmul(dem_agent_flow_contribution_per_asset,SOs_lines.to_numpy())
                if category_aggregation:
                    gen_agent_flow_contribution_per_asset_category  = get_aggregation_per_category(pd.DataFrame(gen_agent_flow_contribution_per_asset.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
                    dem_agent_flow_contribution_per_asset_category  = get_aggregation_per_category(pd.DataFrame(dem_agent_flow_contribution_per_asset.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)

            #%% usage results in terms of flow-km (MW*km)            
            if usage_result:
                gen_agent_flow_km_contribution_per_asset                    = gen_agent_flow_contribution_per_asset*line_length_matrix[:,0]
                dem_agent_flow_km_contribution_per_asset                    = dem_agent_flow_contribution_per_asset*line_length_matrix[:,0]
                if show_agent_results and show_aggregated_results:
                    gen_agent_flow_km_contribution_per_country              = np.matmul(gen_agent_flow_km_contribution_per_asset,countries_lines.to_numpy())
                    dem_agent_flow_km_contribution_per_country              = np.matmul(dem_agent_flow_km_contribution_per_asset,countries_lines.to_numpy())
                    if SO_aggregation:  
                        gen_agent_flow_km_contribution_per_SO               = np.matmul(gen_agent_flow_km_contribution_per_asset,SOs_lines.to_numpy())
                        dem_agent_flow_km_contribution_per_SO               = np.matmul(dem_agent_flow_km_contribution_per_asset,SOs_lines.to_numpy())
                    if category_aggregation:
                        gen_agent_flow_km_contribution_per_asset_category   = get_aggregation_per_category(pd.DataFrame(gen_agent_flow_km_contribution_per_asset.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
                        dem_agent_flow_km_contribution_per_asset_category   = get_aggregation_per_category(pd.DataFrame(dem_agent_flow_km_contribution_per_asset.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
                    
                if show_country_results:
                    gen_country_flow_km_contribution_per_asset, country_nodes_matrix_G  = get_contribution_per_asset(gen_agent_flow_km_contribution_per_asset, nodes, lines, "Country", index_column)
                    dem_country_flow_km_contribution_per_asset, country_nodes_matrix_D  = get_contribution_per_asset(dem_agent_flow_km_contribution_per_asset, nodes, lines, "Country", index_column)
                    if show_aggregated_results:
                        gen_country_flow_km_contribution_per_country, countries_lines   = get_contribution_per_group(gen_country_flow_km_contribution_per_asset, reactance, length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
                        dem_country_flow_km_contribution_per_country, countries_lines   = get_contribution_per_group(dem_country_flow_km_contribution_per_asset, reactance, length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
                        if category_aggregation:
                            gen_country_flow_km_contribution_per_asset_category         = get_aggregation_per_category(gen_country_flow_km_contribution_per_asset, lines_attributes)
                            dem_country_flow_km_contribution_per_asset_category         = get_aggregation_per_category(dem_country_flow_km_contribution_per_asset, lines_attributes)

                if show_SO_results:
                    gen_SO_flow_km_contribution_per_asset, SO_nodes_matrix_G  = get_contribution_per_asset(gen_agent_flow_km_contribution_per_asset, nodes, lines, "SO 1", index_column)
                    dem_SO_flow_km_contribution_per_asset, SO_nodes_matrix_D  = get_contribution_per_asset(dem_agent_flow_km_contribution_per_asset, nodes, lines, "SO 1", index_column) 
                    if show_aggregated_results:
                        gen_SO_flow_km_contribution_per_SO,   SOs_lines       = get_contribution_per_group(gen_SO_flow_km_contribution_per_asset, reactance, length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                        dem_SO_flow_km_contribution_per_SO,   SOs_lines       = get_contribution_per_group(dem_SO_flow_km_contribution_per_asset, reactance, length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                        if category_aggregation:
                            gen_SO_flow_km_contribution_per_asset_category    = get_aggregation_per_category(gen_SO_flow_km_contribution_per_asset, lines_attributes)
                            dem_SO_flow_km_contribution_per_asset_category    = get_aggregation_per_category(dem_SO_flow_km_contribution_per_asset, lines_attributes)
                        
            #%% utilization results
            if fraction_result:
                if cost_assignment_op == 1:     # utilization with respect to the used capacity
                    gen_agent_utilization_fraction_per_asset        = 100*gen_agent_flow_contribution_per_asset/line_flow[:,0]
                    dem_agent_utilization_fraction_per_asset        = 100*dem_agent_flow_contribution_per_asset/line_flow[:,0]
                else:   # utilization with respect to the rated capacity
                    gen_agent_utilization_fraction_per_asset        = 100*gen_agent_flow_contribution_per_asset/line_capacity_matrix[:,0]
                    dem_agent_utilization_fraction_per_asset        = 100*dem_agent_flow_contribution_per_asset/line_capacity_matrix[:,0]
                    if cost_assignment_op == 3 or cost_assignment_op == 4:  # utilization based on asset type and threshold 
                        gen_agent_utilization_fraction_per_asset2   = 100*gen_agent_flow_contribution_per_asset/line_flow[:,0]
                        dem_agent_utilization_fraction_per_asset2   = 100*dem_agent_flow_contribution_per_asset/line_flow[:,0]
                        # treatment
                        gen_agent_utilization_fraction_per_asset2[np.isnan(gen_agent_utilization_fraction_per_asset2)]  = 0
                        dem_agent_utilization_fraction_per_asset2[np.isnan(dem_agent_utilization_fraction_per_asset2)]  = 0
                        gen_agent_utilization_fraction_per_asset2[np.isinf(gen_agent_utilization_fraction_per_asset2)]  = 0
                        dem_agent_utilization_fraction_per_asset2[np.isinf(dem_agent_utilization_fraction_per_asset2)]  = 0
                        gen_agent_utilization_fraction_per_asset2                                                       = np.where(gen_agent_utilization_fraction_per_asset2 > 100, 100, gen_agent_utilization_fraction_per_asset2)
                        dem_agent_utilization_fraction_per_asset2                                                       = np.where(dem_agent_utilization_fraction_per_asset2 > 100, 100, dem_agent_utilization_fraction_per_asset2)     
                
                gen_agent_utilization_fraction_per_asset[np.isnan(gen_agent_utilization_fraction_per_asset)]    = 0
                dem_agent_utilization_fraction_per_asset[np.isnan(dem_agent_utilization_fraction_per_asset)]    = 0
                gen_agent_utilization_fraction_per_asset[np.isinf(gen_agent_utilization_fraction_per_asset)]    = 0
                dem_agent_utilization_fraction_per_asset[np.isinf(dem_agent_utilization_fraction_per_asset)]    = 0                

                # forcing elements that have more than 100% utilization back to 100%
                gen_agent_utilization_fraction_per_asset = np.where(gen_agent_utilization_fraction_per_asset > 100, 100, gen_agent_utilization_fraction_per_asset)
                dem_agent_utilization_fraction_per_asset = np.where(dem_agent_utilization_fraction_per_asset > 100, 100, dem_agent_utilization_fraction_per_asset)

                if show_intermediary_results:
                    if show_agent_results and show_aggregated_results and category_aggregation and usage_result:    # this is needed to for the lines since lines utilization is based on MW-km not just MW
                        gen_agent_utilization_fraction_per_asset_category   = get_utilization_per_category(gen_agent_flow_km_contribution_per_asset_category, gen_agent_flow_contribution_per_asset_category, flow_km_per_category, flow_per_category, asset_type_dic)                    
                        dem_agent_utilization_fraction_per_asset_category   = get_utilization_per_category(dem_agent_flow_km_contribution_per_asset_category, dem_agent_flow_contribution_per_asset_category, flow_km_per_category, flow_per_category, asset_type_dic)
   
                    if show_country_results:
                        gen_country_utilization_fraction_per_asset, country_nodes_matrix_G  = get_contribution_per_asset(gen_agent_utilization_fraction_per_asset, nodes, lines, "Country", index_column)
                        dem_country_utilization_fraction_per_asset, country_nodes_matrix_D  = get_contribution_per_asset(dem_agent_utilization_fraction_per_asset, nodes, lines, "Country", index_column)
                        if category_aggregation and usage_result and show_aggregated_results:
                            gen_country_utilization_fraction_per_asset_category             = get_utilization_per_category(gen_country_flow_km_contribution_per_asset_category, gen_country_flow_contribution_per_asset_category, flow_km_per_category, flow_per_category, asset_type_dic)
                            dem_country_utilization_fraction_per_asset_category             = get_utilization_per_category(dem_country_flow_km_contribution_per_asset_category, dem_country_flow_contribution_per_asset_category, flow_km_per_category, flow_per_category, asset_type_dic)
                    
                    if show_SO_results:
                        gen_SO_utilization_fraction_per_asset, SO_nodes_matrix_G  = get_contribution_per_asset(gen_agent_utilization_fraction_per_asset, nodes, lines, "SO 1", index_column)
                        dem_SO_utilization_fraction_per_asset, SO_nodes_matrix_D  = get_contribution_per_asset(dem_agent_utilization_fraction_per_asset, nodes, lines, "SO 1", index_column)
                        if category_aggregation and usage_result and show_aggregated_results:
                            gen_SO_utilization_fraction_per_asset_category        = get_utilization_per_category(gen_SO_flow_km_contribution_per_asset_category, gen_SO_flow_contribution_per_asset_category, flow_km_per_category, flow_per_category, asset_type_dic)
                            dem_SO_utilization_fraction_per_asset_category        = get_utilization_per_category(dem_SO_flow_km_contribution_per_asset_category, dem_SO_flow_contribution_per_asset_category, flow_km_per_category, flow_per_category, asset_type_dic)
            #%% losses allocation
            if losses_allocation_results:
                if show_agent_results and show_aggregated_results:
                    gen_agent_losses_allocation_per_country = np.matmul(gen_agent_losses_allocation_per_asset,countries_lines.to_numpy())
                    dem_agent_losses_allocation_per_country = np.matmul(dem_agent_losses_allocation_per_asset,countries_lines.to_numpy())
                    gen_agent_total_losses_allocation       = np.sum(gen_agent_losses_allocation_per_asset, axis=1) 
                    dem_agent_total_losses_allocation       = np.sum(dem_agent_losses_allocation_per_asset, axis=1)
                    if SO_aggregation:
                        gen_agent_losses_allocation_per_SO  = np.matmul(gen_agent_losses_allocation_per_asset,SOs_lines.to_numpy())
                        dem_agent_losses_allocation_per_SO  = np.matmul(dem_agent_losses_allocation_per_asset,SOs_lines.to_numpy())
                    if category_aggregation:
                        gen_agent_losses_allocation_per_asset_category   = get_aggregation_per_category(pd.DataFrame(gen_agent_losses_allocation_per_asset.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
                        dem_agent_losses_allocation_per_asset_category   = get_aggregation_per_category(pd.DataFrame(dem_agent_losses_allocation_per_asset.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
                              
                if show_country_results:
                    gen_country_losses_allocation_per_asset, country_nodes_matrix_G = get_contribution_per_asset(gen_agent_losses_allocation_per_asset, nodes, lines, "Country", index_column)
                    dem_country_losses_allocation_per_asset, country_nodes_matrix_D = get_contribution_per_asset(dem_agent_losses_allocation_per_asset, nodes, lines, "Country", index_column)
                    if show_aggregated_results:
                        gen_country_losses_allocation_per_country, countries_lines  = get_contribution_per_group(gen_country_losses_allocation_per_asset, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
                        dem_country_losses_allocation_per_country, countries_lines  = get_contribution_per_group(dem_country_losses_allocation_per_asset, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
                        country_losses_allocation_per_country                       = dem_country_losses_allocation_per_country + gen_country_losses_allocation_per_country
                        if category_aggregation:
                            gen_country_losses_allocation_per_asset_category        = get_aggregation_per_category(gen_country_losses_allocation_per_asset, lines_attributes)
                            dem_country_losses_allocation_per_asset_category        = get_aggregation_per_category(dem_country_losses_allocation_per_asset, lines_attributes)
                         
                if show_SO_results:
                    gen_SO_losses_allocation_per_asset, SO_nodes_matrix_G   = get_contribution_per_asset(gen_agent_losses_allocation_per_asset, nodes, lines, "SO 1", index_column)
                    dem_SO_losses_allocation_per_asset, SO_nodes_matrix_D   = get_contribution_per_asset(dem_agent_losses_allocation_per_asset, nodes, lines, "SO 1", index_column)
                    if show_aggregated_results:
                        gen_SO_losses_allocation_per_SO,   SOs_lines        = get_contribution_per_group(gen_SO_losses_allocation_per_asset, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                        dem_SO_losses_allocation_per_SO,   SOs_lines        = get_contribution_per_group(dem_SO_losses_allocation_per_asset, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                        SO_losses_allocation_per_SO                         = dem_SO_losses_allocation_per_SO + gen_SO_losses_allocation_per_SO
                        if category_aggregation:
                            gen_SO_losses_allocation_per_asset_category     = get_aggregation_per_category(gen_SO_losses_allocation_per_asset, lines_attributes)
                            dem_SO_losses_allocation_per_asset_category     = get_aggregation_per_category(dem_SO_losses_allocation_per_asset, lines_attributes)
                
                if losses_price:
                    gen_agent_losses_allocation_cost_per_asset  = gen_agent_losses_allocation_per_asset*losses_price*snapshots_weights_dic[snapshot]*0.001
                    dem_agent_losses_allocation_cost_per_asset  = dem_agent_losses_allocation_per_asset*losses_price*snapshots_weights_dic[snapshot]*0.001

                    if show_agent_results and show_aggregated_results:
                        gen_agent_losses_allocation_cost_per_country = gen_agent_losses_allocation_per_country*losses_price*snapshots_weights_dic[snapshot]*0.001
                        dem_agent_losses_allocation_cost_per_country = dem_agent_losses_allocation_per_country*losses_price*snapshots_weights_dic[snapshot]*0.001
                        gen_agent_total_losses_allocation_cost       = gen_agent_total_losses_allocation*losses_price*snapshots_weights_dic[snapshot]*0.001
                        dem_agent_total_losses_allocation_cost       = dem_agent_total_losses_allocation*losses_price*snapshots_weights_dic[snapshot]*0.001
                        if SO_aggregation:
                            gen_agent_losses_allocation_cost_per_SO  = gen_agent_losses_allocation_per_SO*losses_price*snapshots_weights_dic[snapshot]*0.001
                            dem_agent_losses_allocation_cost_per_SO  = dem_agent_losses_allocation_per_SO*losses_price*snapshots_weights_dic[snapshot]*0.001
                        if category_aggregation:
                            gen_agent_losses_allocation_cost_per_asset_category   = gen_agent_losses_allocation_per_asset_category*losses_price*snapshots_weights_dic[snapshot]*0.001
                            dem_agent_losses_allocation_cost_per_asset_category   = dem_agent_losses_allocation_per_asset_category*losses_price*snapshots_weights_dic[snapshot]*0.001
                                
                    if show_country_results:
                        gen_country_losses_allocation_cost_per_asset = gen_country_losses_allocation_per_asset*losses_price*snapshots_weights_dic[snapshot]*0.001
                        dem_country_losses_allocation_cost_per_asset = dem_country_losses_allocation_per_asset*losses_price*snapshots_weights_dic[snapshot]*0.001
                        if show_aggregated_results:
                            gen_country_losses_allocation_cost_per_country  = gen_country_losses_allocation_per_country*losses_price*snapshots_weights_dic[snapshot]*0.001
                            dem_country_losses_allocation_cost_per_country  = dem_country_losses_allocation_per_country*losses_price*snapshots_weights_dic[snapshot]*0.001
                            country_losses_allocation_cost_per_country      = dem_country_losses_allocation_cost_per_country + gen_country_losses_allocation_cost_per_country
                            if category_aggregation:
                                gen_country_losses_allocation_cost_per_asset_category    = gen_country_losses_allocation_per_asset_category*losses_price*snapshots_weights_dic[snapshot]*0.001
                                dem_country_losses_allocation_cost_per_asset_category    = dem_country_losses_allocation_per_asset_category*losses_price*snapshots_weights_dic[snapshot]*0.001
                            
                    if show_SO_results:
                        gen_SO_losses_allocation_cost_per_asset = gen_SO_losses_allocation_per_asset*losses_price*snapshots_weights_dic[snapshot]*0.001
                        dem_SO_losses_allocation_cost_per_asset = dem_SO_losses_allocation_per_asset*losses_price*snapshots_weights_dic[snapshot]*0.001
                        if show_aggregated_results:
                            gen_SO_losses_allocation_cost_per_SO = gen_SO_losses_allocation_per_SO*losses_price*snapshots_weights_dic[snapshot]*0.001
                            dem_SO_losses_allocation_cost_per_SO = dem_SO_losses_allocation_per_SO*losses_price*snapshots_weights_dic[snapshot]*0.001
                            SO_losses_allocation_cost_per_SO     = dem_SO_losses_allocation_cost_per_SO + gen_SO_losses_allocation_cost_per_SO
                            if category_aggregation:
                                gen_SO_losses_allocation_cost_per_asset_category = gen_SO_losses_allocation_per_asset_category*losses_price*snapshots_weights_dic[snapshot]*0.001
                                dem_SO_losses_allocation_cost_per_asset_category = dem_SO_losses_allocation_per_asset_category*losses_price*snapshots_weights_dic[snapshot]*0.001

            #%% cost results kUS$
            if cost_result:
                if cost_assignment_op == 1 or cost_assignment_op == 2:    
                    gen_agent_cost_per_asset    = gen_agent_utilization_fraction_per_asset*line_cost_matrix[:,0]/100
                    dem_agent_cost_per_asset    = dem_agent_utilization_fraction_per_asset*line_cost_matrix[:,0]/100
                else:
                    if cost_assignment_op == 3: # full cost if the asset exist, used capacity cost if asset is planned
                        if asset_type_cost:
                            gen_agent_utilization_fraction_per_asset_partial    = np.matmul(gen_agent_utilization_fraction_per_asset,np.diag(1-existing_assets))    # cost of used capacity for planned assets
                            dem_agent_utilization_fraction_per_asset_partial    = np.matmul(dem_agent_utilization_fraction_per_asset,np.diag(1-existing_assets))
                            gen_agent_utilization_fraction_per_asset2           = np.matmul(gen_agent_utilization_fraction_per_asset2,np.diag(existing_assets))     # full cost for existing assets
                            dem_agent_utilization_fraction_per_asset2           = np.matmul(dem_agent_utilization_fraction_per_asset2,np.diag(existing_assets))
                        else:   # if the 'Exist/Planned' are not classified, use the cost of used capacity
                            gen_agent_utilization_fraction_per_asset_partial    = gen_agent_utilization_fraction_per_asset
                            dem_agent_utilization_fraction_per_asset_partial    = dem_agent_utilization_fraction_per_asset
                            gen_agent_utilization_fraction_per_asset2           = np.matmul(gen_agent_utilization_fraction_per_asset2,np.zeros((gen_agent_utilization_fraction_per_asset2.shape[1],gen_agent_utilization_fraction_per_asset2.shape[1])))    # making this matrix zero
                            dem_agent_utilization_fraction_per_asset2           = np.matmul(dem_agent_utilization_fraction_per_asset2,np.zeros((dem_agent_utilization_fraction_per_asset2.shape[1],dem_agent_utilization_fraction_per_asset2.shape[1])))

                    if cost_assignment_op == 4: # full cost if the asset is utilized above the threshold, otherwise, used capacity cost
                        # identifying assets above and below the utilization threshold (UT) separately
                        line_utilization    = np.squeeze(100*line_flow/line_capacity_matrix)
                        line_above_UT       = np.where(line_utilization>utilization_threshold,1,0)

                        gen_agent_utilization_fraction_per_asset_partial    = np.matmul(gen_agent_utilization_fraction_per_asset,np.diag(1-line_above_UT))    # cost of used capacity for assets below the UT
                        dem_agent_utilization_fraction_per_asset_partial    = np.matmul(dem_agent_utilization_fraction_per_asset,np.diag(1-line_above_UT))
                        gen_agent_utilization_fraction_per_asset2           = np.matmul(gen_agent_utilization_fraction_per_asset2,np.diag(line_above_UT))     # full cost for assets above the UT
                        dem_agent_utilization_fraction_per_asset2           = np.matmul(dem_agent_utilization_fraction_per_asset2,np.diag(line_above_UT))

                    gen_agent_cost_per_asset    = (gen_agent_utilization_fraction_per_asset_partial + gen_agent_utilization_fraction_per_asset2)*line_cost_matrix[:,0]/100
                    dem_agent_cost_per_asset    = (dem_agent_utilization_fraction_per_asset_partial + dem_agent_utilization_fraction_per_asset2)*line_cost_matrix[:,0]/100

                gen_agent_cost_per_asset = gen_agent_cost_per_asset*generation_weight
                dem_agent_cost_per_asset = dem_agent_cost_per_asset*demand_weight 
                
                if regional_cost:
                    gen_agent_cost_per_asset   = regional_assets[:,0]*gen_agent_cost_per_asset
                    dem_agent_cost_per_asset   = regional_assets[:,0]*dem_agent_cost_per_asset

                if not is_all_ND_zeros:
                    negative_dem_agent_cost_per_asset       = get_negative_demand_contribution(negative_demand, generation, gen_agent_cost_per_asset, nodes, lines)

                if show_agent_results and show_aggregated_results:
                    gen_agent_cost_per_country              = np.matmul(gen_agent_cost_per_asset,countries_lines.to_numpy())
                    dem_agent_cost_per_country              = np.matmul(dem_agent_cost_per_asset,countries_lines.to_numpy())
                    gen_agent_total_cost                    = np.sum(gen_agent_cost_per_country, axis=1) 
                    dem_agent_total_cost                    = np.sum(dem_agent_cost_per_country, axis=1)
                    if SO_aggregation:
                        gen_agent_cost_per_SO               = np.matmul(gen_agent_cost_per_asset,SOs_lines.to_numpy())
                        dem_agent_cost_per_SO               = np.matmul(dem_agent_cost_per_asset,SOs_lines.to_numpy())
                    if category_aggregation:
                        gen_agent_cost_per_asset_category   = get_aggregation_per_category(pd.DataFrame(gen_agent_cost_per_asset.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
                        dem_agent_cost_per_asset_category   = get_aggregation_per_category(pd.DataFrame(dem_agent_cost_per_asset.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
                        # final cost-weighted utilization of the whole network
                        if usage_result:
                            gen_agent_network_utilization_fraction  = ((gen_agent_utilization_fraction_per_asset_category*cost_per_category.to_numpy().transpose()[:,0]).sum(axis=1)/cost_per_category.sum(axis=1)[0]).to_frame(name='Network Utilization %')              
                            dem_agent_network_utilization_fraction  = ((dem_agent_utilization_fraction_per_asset_category*cost_per_category.to_numpy().transpose()[:,0]).sum(axis=1)/cost_per_category.sum(axis=1)[0]).to_frame(name='Network Utilization %')
                            
                if show_country_results:
                    gen_country_cost_per_asset, country_nodes_matrix_G      = get_contribution_per_asset(gen_agent_cost_per_asset, nodes, lines, "Country", index_column)
                    dem_country_cost_per_asset, country_nodes_matrix_D      = get_contribution_per_asset(dem_agent_cost_per_asset, nodes, lines, "Country", index_column)
                    if show_aggregated_results:
                        gen_country_cost_per_country, countries_lines       = get_contribution_per_group(gen_country_cost_per_asset, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
                        dem_country_cost_per_country, countries_lines       = get_contribution_per_group(dem_country_cost_per_asset, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
                        country_cost_per_country                            = gen_country_cost_per_country + dem_country_cost_per_country
                        if category_aggregation:
                            gen_country_cost_per_asset_category             = get_aggregation_per_category(gen_country_cost_per_asset, lines_attributes)
                            dem_country_cost_per_asset_category             = get_aggregation_per_category(dem_country_cost_per_asset, lines_attributes)
                            if usage_result:
                                gen_country_network_utilization_fraction    = ((gen_country_utilization_fraction_per_asset_category*cost_per_category.to_numpy().transpose()[:,0]).sum(axis=1)/cost_per_category.sum(axis=1)[0]).to_frame(name='Network Utilization %')
                                dem_country_network_utilization_fraction    = ((dem_country_utilization_fraction_per_asset_category*cost_per_category.to_numpy().transpose()[:,0]).sum(axis=1)/cost_per_category.sum(axis=1)[0]).to_frame(name='Network Utilization %')
                        
                if show_SO_results:
                    gen_SO_cost_per_asset, SO_nodes_matrix_G        = get_contribution_per_asset(gen_agent_cost_per_asset, nodes, lines, "SO 1", index_column)
                    dem_SO_cost_per_asset, SO_nodes_matrix_D        = get_contribution_per_asset(dem_agent_cost_per_asset, nodes, lines, "SO 1", index_column)
                    if show_aggregated_results:
                        gen_SO_cost_per_SO,   SOs_lines             = get_contribution_per_group(gen_SO_cost_per_asset, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                        dem_SO_cost_per_SO,   SOs_lines             = get_contribution_per_group(dem_SO_cost_per_asset, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                        SO_cost_per_SO                              = dem_SO_cost_per_SO + gen_SO_cost_per_SO
                        if category_aggregation:
                            gen_SO_cost_per_asset_category          = get_aggregation_per_category(gen_SO_cost_per_asset, lines_attributes)
                            dem_SO_cost_per_asset_category          = get_aggregation_per_category(dem_SO_cost_per_asset, lines_attributes)
                            if usage_result:
                                gen_SO_network_utilization_fraction = ((gen_SO_utilization_fraction_per_asset_category*cost_per_category.to_numpy().transpose()[:,0]).sum(axis=1)/cost_per_category.sum(axis=1)[0]).to_frame(name='Network Utilization %')
                                dem_SO_network_utilization_fraction = ((dem_SO_utilization_fraction_per_asset_category*cost_per_category.to_numpy().transpose()[:,0]).sum(axis=1)/cost_per_category.sum(axis=1)[0]).to_frame(name='Network Utilization %')

                # calculating the socialized cost of the grid
                if cost_of_unused_capacity_op:        
                    gen_total_allocated_cost_per_asset          = gen_agent_cost_per_asset.sum(axis=0)[None].transpose()
                    dem_total_allocated_cost_per_asset          = dem_agent_cost_per_asset.sum(axis=0)[None].transpose()
                    total_cost_to_be_socialized                 = line_cost_matrix - gen_total_allocated_cost_per_asset - dem_total_allocated_cost_per_asset
                    gen_cost_to_socialize_per_asset             = total_cost_to_be_socialized*generation_socialized_weight
                    dem_cost_to_socialize_per_asset             = total_cost_to_be_socialized*demand_socialized_weight
                    gen_cost_to_socialize_per_asset             = np.where(gen_cost_to_socialize_per_asset < 0, 0, gen_cost_to_socialize_per_asset)
                    dem_cost_to_socialize_per_asset             = np.where(dem_cost_to_socialize_per_asset < 0, 0, dem_cost_to_socialize_per_asset)

                    if cost_of_unused_capacity_op == 1:     # socialize the cost equally among agents who use the asset
                        gen_agent_users_per_asset               = np.where(gen_agent_flow_contribution_per_asset > 0, 1, 0)    # identifying the agents using each line (no matter how small the flow, >0) by 1
                        dem_agent_users_per_asset               = np.where(dem_agent_flow_contribution_per_asset > 0, 1, 0)
                        gen_agent_users_average_per_asset       = gen_agent_users_per_asset.sum(axis=0)[None].transpose()
                        dem_agent_users_average_per_asset       = dem_agent_users_per_asset.sum(axis=0)[None].transpose()
                        gen_agent_socialized_weight_per_asset   = gen_agent_users_per_asset/gen_agent_users_average_per_asset[:,0]
                        dem_agent_socialized_weight_per_asset   = dem_agent_users_per_asset/dem_agent_users_average_per_asset[:,0]
                        
                        gen_agent_socialized_weight_per_asset[np.isnan(gen_agent_socialized_weight_per_asset)]  = 0
                        dem_agent_socialized_weight_per_asset[np.isnan(dem_agent_socialized_weight_per_asset)]  = 0
                        gen_agent_socialized_weight_per_asset[np.isinf(gen_agent_socialized_weight_per_asset)]  = 0
                        dem_agent_socialized_weight_per_asset[np.isinf(dem_agent_socialized_weight_per_asset)]  = 0  
                        
                        gen_agent_socialized_cost_per_asset = gen_agent_socialized_weight_per_asset*gen_cost_to_socialize_per_asset[:,0]
                        dem_agent_socialized_cost_per_asset = dem_agent_socialized_weight_per_asset*dem_cost_to_socialize_per_asset[:,0]

                    elif cost_of_unused_capacity_op == 2:  # socialize the cost equally among the agents belonging to the country(ise) that owns the asset
                        gen_agent_per_country       = country_nodes_matrix_G.set_index(["Node"]).to_numpy()
                        dem_agent_per_country       = country_nodes_matrix_D.set_index(["Node"]).to_numpy()
                        gen_agent_per_asset_country = np.matmul(gen_agent_per_country,countries_lines.to_numpy().transpose())
                        dem_agent_per_asset_country = np.matmul(dem_agent_per_country,countries_lines.to_numpy().transpose())
                        gen_agent_per_asset_country = np.where(gen_agent_per_asset_country> 0, 1, 0)
                        dem_agent_per_asset_country = np.where(dem_agent_per_asset_country> 0, 1, 0)
                        
                        gen_agent_socialized_weight_per_asset   = gen_agent_per_asset_country/gen_agent_per_asset_country.sum(axis=0)[None].transpose()[:,0]
                        dem_agent_socialized_weight_per_asset   = dem_agent_per_asset_country/dem_agent_per_asset_country.sum(axis=0)[None].transpose()[:,0]
                        
                        gen_agent_socialized_weight_per_asset[np.isnan(gen_agent_socialized_weight_per_asset)]  = 0
                        dem_agent_socialized_weight_per_asset[np.isnan(dem_agent_socialized_weight_per_asset)]  = 0
                        gen_agent_socialized_weight_per_asset[np.isinf(gen_agent_socialized_weight_per_asset)]  = 0
                        dem_agent_socialized_weight_per_asset[np.isinf(dem_agent_socialized_weight_per_asset)]  = 0  
                        
                        gen_agent_socialized_cost_per_asset = gen_agent_socialized_weight_per_asset*gen_cost_to_socialize_per_asset[:,0]
                        dem_agent_socialized_cost_per_asset = dem_agent_socialized_weight_per_asset*dem_cost_to_socialize_per_asset[:,0]

                    elif cost_of_unused_capacity_op == 3:  # socialize the cost equally among all agents
                        generation_agents                       = np.where(modified_generation > 0, 1, 0)
                        demand_agents                           = np.where(positive_demand > 0, 1, 0)
                        gen_agent_socialized_weight_per_asset   = generation_agents/generation_agents.sum(axis=0)[0]
                        dem_agent_socialized_weight_per_asset   = demand_agents/demand_agents.sum(axis=0)[0]
                        gen_agent_socialized_cost_per_asset     = gen_agent_socialized_weight_per_asset*gen_cost_to_socialize_per_asset[:,0]
                        dem_agent_socialized_cost_per_asset     = dem_agent_socialized_weight_per_asset*dem_cost_to_socialize_per_asset[:,0]

            #%% export results per snapshot
            # agent flow results
            if show_agent_results:
                print_to_csv(output_file+"Generation agents flow contribution per asset sn_"+current_snapshot, gen_agent_flow_contribution_per_asset, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                print_to_csv(output_file+"Demand agents flow contribution per asset sn_"+current_snapshot, dem_agent_flow_contribution_per_asset, index=nodes["Node"], columns=lines["Line"],total=True, remove_zeros=remove_zero_values)
                if not is_all_ND_zeros:
                    remove_zero_rows_and_columns(negative_dem_agent_contribution_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Negative demand agents flow contribution per asset sn_"+current_snapshot+".csv")
                if show_aggregated_results:
                    print_to_csv(output_file+"Generation agents flow contribution per country sn_"+current_snapshot, gen_agent_flow_contribution_per_country, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                    print_to_csv(output_file+"Demand agents flow contribution per country sn_"+current_snapshot, dem_agent_flow_contribution_per_country, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                    if SO_aggregation:  
                        print_to_csv(output_file+"Generation agents flow contribution per SO sn_"+current_snapshot, gen_agent_flow_contribution_per_SO, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                        print_to_csv(output_file+"Demand agents flow contribution per SO sn_"+current_snapshot, dem_agent_flow_contribution_per_SO, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                    if category_aggregation:
                        remove_zero_rows_and_columns(gen_agent_flow_contribution_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents flow contribution per asset category sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_agent_flow_contribution_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents flow contribution per asset category sn_"+current_snapshot+".csv")
            
            # countries flow results
            if show_country_results:
                remove_zero_rows_and_columns(gen_country_flow_contribution_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation flow contribution per asset sn_"+current_snapshot+".csv")
                remove_zero_rows_and_columns(dem_country_flow_contribution_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand flow contribution per asset sn_"+current_snapshot+".csv")
                if show_aggregated_results:
                    remove_zero_rows_and_columns(gen_country_flow_contribution_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation flow contribution per country sn_"+current_snapshot+".csv")
                    remove_zero_rows_and_columns(dem_country_flow_contribution_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand flow contribution per country sn_"+current_snapshot+".csv")
                    if category_aggregation:
                        remove_zero_rows_and_columns(gen_country_flow_contribution_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation flow contribution per asset category sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_country_flow_contribution_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand flow contribution per asset category sn_"+current_snapshot+".csv")

            # SOs flow results
            if show_SO_results:
                remove_zero_rows_and_columns(gen_SO_flow_contribution_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation flow contribution per asset sn_"+current_snapshot+".csv")
                remove_zero_rows_and_columns(dem_SO_flow_contribution_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand flow contribution per asset sn_"+current_snapshot+".csv")
                if show_aggregated_results:
                    remove_zero_rows_and_columns(gen_SO_flow_contribution_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation flow contribution per SO sn_"+current_snapshot+".csv")
                    remove_zero_rows_and_columns(dem_SO_flow_contribution_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand flow contribution per SO sn_"+current_snapshot+".csv")
                    if category_aggregation:
                        remove_zero_rows_and_columns(gen_SO_flow_contribution_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation flow contribution per asset category sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_SO_flow_contribution_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand flow contribution per asset category sn_"+current_snapshot+".csv")
            
            # usage results
            if usage_result:
                if show_agent_results:
                    print_to_csv(output_file+"Generation agents flow-km contribution per asset sn_"+current_snapshot, gen_agent_flow_km_contribution_per_asset, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                    print_to_csv(output_file+"Demand agents flow-km contribution per asset sn_"+current_snapshot, dem_agent_flow_km_contribution_per_asset, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                    if show_aggregated_results:
                        print_to_csv(output_file+"Generation agents flow-km contribution per country sn_"+current_snapshot, gen_agent_flow_km_contribution_per_country, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                        print_to_csv(output_file+"Demand agents flow-km contribution per country sn_"+current_snapshot, dem_agent_flow_km_contribution_per_country, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                        if SO_aggregation: 
                            print_to_csv(output_file+"Generation agents flow-km contribution per SO sn_"+current_snapshot, gen_agent_flow_km_contribution_per_SO, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                            print_to_csv(output_file+"Demand agents flow-km contribution per SO sn_"+current_snapshot, dem_agent_flow_km_contribution_per_SO, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                        if category_aggregation:
                            remove_zero_rows_and_columns(gen_agent_flow_km_contribution_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents flow-km contribution per asset category sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(dem_agent_flow_km_contribution_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents flow-km contribution per asset category sn_"+current_snapshot+".csv")
                
                if show_country_results:
                    remove_zero_rows_and_columns(gen_country_flow_km_contribution_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation flow-km contribution per asset sn_"+current_snapshot+".csv")
                    remove_zero_rows_and_columns(dem_country_flow_km_contribution_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand flow-km contribution per asset sn_"+current_snapshot+".csv")
                    if show_aggregated_results:
                        remove_zero_rows_and_columns(gen_country_flow_km_contribution_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation flow-km contribution per country sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_country_flow_km_contribution_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand flow-km contribution per country sn_"+current_snapshot+".csv")
                        if category_aggregation:
                            remove_zero_rows_and_columns(gen_country_flow_km_contribution_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation flow-km contribution per asset category sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(dem_country_flow_km_contribution_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand flow-km contribution per asset category sn_"+current_snapshot+".csv")

                if show_SO_results:
                    remove_zero_rows_and_columns(gen_SO_flow_km_contribution_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation flow-km contribution per asset sn_"+current_snapshot+".csv")
                    remove_zero_rows_and_columns(dem_SO_flow_km_contribution_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand flow-km contribution per asset sn_"+current_snapshot+".csv")
                    if show_aggregated_results:
                        remove_zero_rows_and_columns(gen_SO_flow_km_contribution_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation flow-km contribution per SO sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_SO_flow_km_contribution_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand flow-km contribution per SO sn_"+current_snapshot+".csv")
                        if category_aggregation:
                            remove_zero_rows_and_columns(gen_SO_flow_km_contribution_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation flow-km contribution per asset category sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(dem_SO_flow_km_contribution_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand flow-km contribution per asset category sn_"+current_snapshot+".csv")
                    
            # utilization fraction results
            if fraction_result and show_intermediary_results:
                if show_agent_results:
                    print_to_csv(output_file+"Generation agents utilization fraction per asset sn_"+current_snapshot, gen_agent_utilization_fraction_per_asset, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                    print_to_csv(output_file+"Demand agents utilization fraction per asset sn_"+current_snapshot, dem_agent_utilization_fraction_per_asset, index=nodes["Node"], columns=lines["Line"],total=True, remove_zeros=remove_zero_values)
                    if show_aggregated_results and category_aggregation and usage_result:
                        remove_zero_rows_and_columns(gen_agent_utilization_fraction_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents utilization fraction per asset category sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_agent_utilization_fraction_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents utilization fraction per asset category sn_"+current_snapshot+".csv")

                if show_country_results:
                    remove_zero_rows_and_columns(gen_country_utilization_fraction_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation utilization fraction per asset sn_"+current_snapshot+".csv")
                    remove_zero_rows_and_columns(dem_country_utilization_fraction_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand utilization fraction per asset sn_"+current_snapshot+".csv")
                    if show_aggregated_results and category_aggregation and usage_result:
                        remove_zero_rows_and_columns(gen_country_utilization_fraction_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation utilization fraction per asset category sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_country_utilization_fraction_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand utilization fraction per asset category sn_"+current_snapshot+".csv")              

                if show_SO_results:
                    remove_zero_rows_and_columns(gen_SO_utilization_fraction_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation utilization fraction per asset sn_"+current_snapshot+".csv")
                    remove_zero_rows_and_columns(dem_SO_utilization_fraction_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand utilization fraction per asset sn_"+current_snapshot+".csv")
                    if show_aggregated_results and category_aggregation and usage_result:
                        remove_zero_rows_and_columns(gen_SO_utilization_fraction_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation utilization fraction per asset category sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_SO_utilization_fraction_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand utilization fraction per asset category sn_"+current_snapshot+".csv")
            
            # losses allocation results
            if losses_allocation_results:
                if show_agent_results:
                    print_to_csv(output_file+"Generation agents losses allocation per asset sn_"+current_snapshot, gen_agent_losses_allocation_per_asset, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                    print_to_csv(output_file+"Demand agents losses allocation per asset sn_"+current_snapshot, dem_agent_losses_allocation_per_asset, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                    if show_aggregated_results:
                        print_to_csv(output_file+"Generation agents losses allocation per country sn_"+current_snapshot, gen_agent_losses_allocation_per_country, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                        print_to_csv(output_file+"Demand agents losses allocation per country sn_"+current_snapshot, dem_agent_losses_allocation_per_country, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                        print_to_csv(output_file+"Generation agents total losses allocation sn_"+current_snapshot, gen_agent_total_losses_allocation, index=nodes["Node"], columns=['Total losses allocation MW'], total=True, remove_zeros=remove_zero_values)
                        print_to_csv(output_file+"Demand agents total losses allocation sn_"+current_snapshot, dem_agent_total_losses_allocation, index=nodes["Node"], columns=['Total losses allocation'], total=True, remove_zeros=remove_zero_values)
                        if SO_aggregation: 
                            print_to_csv(output_file+"Generation agents losses allocation per SO sn_"+current_snapshot, gen_agent_losses_allocation_per_SO, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                            print_to_csv(output_file+"Demand agents losses allocation per SO sn_"+current_snapshot, dem_agent_losses_allocation_per_SO, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                        if category_aggregation:
                            remove_zero_rows_and_columns(gen_agent_losses_allocation_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents losses allocation per asset category sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(dem_agent_losses_allocation_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents losses allocation per asset category sn_"+current_snapshot+".csv")
                
                if show_country_results:
                    remove_zero_rows_and_columns(gen_country_losses_allocation_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation losses allocation per asset sn_"+current_snapshot+".csv")
                    remove_zero_rows_and_columns(dem_country_losses_allocation_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand losses allocation per asset sn_"+current_snapshot+".csv")
                    if show_aggregated_results:
                        remove_zero_rows_and_columns(gen_country_losses_allocation_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation losses allocation per country sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_country_losses_allocation_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand losses allocation per country sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(country_losses_allocation_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country joint losses allocation per country sn_"+current_snapshot+".csv")
                        if category_aggregation:
                            remove_zero_rows_and_columns(gen_country_losses_allocation_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation losses allocation per asset category sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(dem_country_losses_allocation_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand losses allocation per asset category sn_"+current_snapshot+".csv")

                if show_SO_results:
                    remove_zero_rows_and_columns(gen_SO_losses_allocation_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation losses allocation per asset sn_"+current_snapshot+".csv")
                    remove_zero_rows_and_columns(dem_SO_losses_allocation_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand losses allocation per asset sn_"+current_snapshot+".csv")
                    if show_aggregated_results:
                        remove_zero_rows_and_columns(gen_SO_losses_allocation_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation losses allocation per SO sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_SO_losses_allocation_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand losses allocation per SO sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(SO_losses_allocation_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO joint losses allocation per SO sn_"+current_snapshot+".csv")
                        if category_aggregation:
                            remove_zero_rows_and_columns(gen_SO_losses_allocation_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation losses allocation per asset category sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(dem_SO_losses_allocation_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand losses allocation per asset category sn_"+current_snapshot+".csv")
                
                if losses_price:
                    if show_agent_results:
                        print_to_csv(output_file+"Generation agents losses allocation cost per asset sn_"+current_snapshot, gen_agent_losses_allocation_cost_per_asset, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                        print_to_csv(output_file+"Demand agents losses allocation cost per asset sn_"+current_snapshot, dem_agent_losses_allocation_cost_per_asset, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                        if show_aggregated_results:
                            print_to_csv(output_file+"Generation agents losses allocation cost per country sn_"+current_snapshot, gen_agent_losses_allocation_cost_per_country, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                            print_to_csv(output_file+"Demand agents losses allocation cost per country sn_"+current_snapshot, dem_agent_losses_allocation_cost_per_country, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                            print_to_csv(output_file+"Generation agents total losses allocation cost sn_"+current_snapshot, gen_agent_total_losses_allocation_cost, index=nodes["Node"], columns=['Total losses allocation MW'], total=True, remove_zeros=remove_zero_values)
                            print_to_csv(output_file+"Demand agents total losses allocation cost sn_"+current_snapshot, dem_agent_total_losses_allocation_cost, index=nodes["Node"], columns=['Total losses allocation'], total=True, remove_zeros=remove_zero_values)
                            if SO_aggregation: 
                                print_to_csv(output_file+"Generation agents losses allocation cost per SO sn_"+current_snapshot, gen_agent_losses_allocation_cost_per_SO, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                                print_to_csv(output_file+"Demand agents losses allocation cost per SO sn_"+current_snapshot, dem_agent_losses_allocation_cost_per_SO, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                            if category_aggregation:
                                remove_zero_rows_and_columns(gen_agent_losses_allocation_cost_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents losses allocation cost per asset category sn_"+current_snapshot+".csv")
                                remove_zero_rows_and_columns(dem_agent_losses_allocation_cost_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents losses allocation cost per asset category sn_"+current_snapshot+".csv")
                    
                    if show_country_results:
                        remove_zero_rows_and_columns(gen_country_losses_allocation_cost_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation losses allocation cost per asset sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_country_losses_allocation_cost_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand losses allocation cost per asset sn_"+current_snapshot+".csv")
                        if show_aggregated_results:
                            remove_zero_rows_and_columns(gen_country_losses_allocation_cost_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation losses allocation cost per country sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(dem_country_losses_allocation_cost_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand losses allocation cost per country sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(country_losses_allocation_cost_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country joint losses allocation cost per country sn_"+current_snapshot+".csv")
                            if category_aggregation:
                                remove_zero_rows_and_columns(gen_country_losses_allocation_cost_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation losses allocation cost per asset category sn_"+current_snapshot+".csv")
                                remove_zero_rows_and_columns(dem_country_losses_allocation_cost_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand losses allocation cost per asset category sn_"+current_snapshot+".csv")

                    if show_SO_results:
                        remove_zero_rows_and_columns(gen_SO_losses_allocation_cost_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation losses allocation cost per asset sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_SO_losses_allocation_cost_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand losses allocation cost per asset sn_"+current_snapshot+".csv")
                        if show_aggregated_results:
                            remove_zero_rows_and_columns(gen_SO_losses_allocation_cost_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation losses allocation cost per SO sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(dem_SO_losses_allocation_cost_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand losses allocation cost per SO sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(SO_losses_allocation_cost_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO joint losses allocation cost per SO sn_"+current_snapshot+".csv")
                            if category_aggregation:
                                remove_zero_rows_and_columns(gen_SO_losses_allocation_cost_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation losses allocation cost per asset category sn_"+current_snapshot+".csv")
                                remove_zero_rows_and_columns(dem_SO_losses_allocation_cost_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand losses allocation cost per asset category sn_"+current_snapshot+".csv")

            # cost results
            if cost_result:
                if show_agent_results:
                    print_to_csv(output_file+"Generation agents network usage cost per asset sn_"+current_snapshot, gen_agent_cost_per_asset, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                    print_to_csv(output_file+"Demand agents network usage cost per asset sn_"+current_snapshot, dem_agent_cost_per_asset, index=nodes["Node"], columns=lines["Line"],total=True, remove_zeros=remove_zero_values)
                    if not is_all_ND_zeros:
                        remove_zero_rows_and_columns(negative_dem_agent_cost_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Negative demand agents network usage cost per asset sn_"+current_snapshot+".csv")
                    if cost_of_unused_capacity_op:
                        print_to_csv(output_file+"Generation agents socialized network usage cost per asset sn_"+current_snapshot, gen_agent_socialized_cost_per_asset, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                        print_to_csv(output_file+"Demand agents socialized network usage cost per asset sn_"+current_snapshot, dem_agent_socialized_cost_per_asset, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                    if show_aggregated_results:
                        print_to_csv(output_file+"Generation agents network usage cost per country sn_"+current_snapshot, gen_agent_cost_per_country, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                        print_to_csv(output_file+"Demand agents network usage cost per country sn_"+current_snapshot, dem_agent_cost_per_country, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                        print_to_csv(output_file+"Generation agents total network usage cost sn_"+current_snapshot, gen_agent_total_cost, index=nodes["Node"], columns=['Total cost KUS$'], total=True, remove_zeros=remove_zero_values)
                        print_to_csv(output_file+"Demand agents total network usage cost sn_"+current_snapshot, dem_agent_total_cost, index=nodes["Node"], columns=['Total cost KUS$'], total=True, remove_zeros=remove_zero_values)
                        if SO_aggregation:  
                            print_to_csv(output_file+"Generation agents network usage cost per SO sn_"+current_snapshot, gen_agent_cost_per_SO, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                            print_to_csv(output_file+"Demand agents network usage cost per SO sn_"+current_snapshot, dem_agent_cost_per_SO, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                        if category_aggregation:
                            remove_zero_rows_and_columns(gen_agent_cost_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents network usage cost per asset category sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(dem_agent_cost_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents network usage cost per asset category sn_"+current_snapshot+".csv")
                            if usage_result:
                                remove_zero_rows_and_columns(gen_agent_network_utilization_fraction, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents network utilization sn_"+current_snapshot+".csv")
                                remove_zero_rows_and_columns(dem_agent_network_utilization_fraction, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents network utilization sn_"+current_snapshot+".csv")
                    
                if show_country_results:
                    remove_zero_rows_and_columns(gen_country_cost_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation network usage cost per asset sn_"+current_snapshot+".csv")
                    remove_zero_rows_and_columns(dem_country_cost_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand network usage cost per asset sn_"+current_snapshot+".csv")
                    if show_aggregated_results:
                        remove_zero_rows_and_columns(gen_country_cost_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation network usage cost per country sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_country_cost_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand network usage cost per country sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(country_cost_per_country.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country joint network usage cost per country sn_"+current_snapshot+".csv")
                        if category_aggregation:
                            remove_zero_rows_and_columns(gen_country_cost_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation network usage cost per asset category sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(dem_country_cost_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand network usage cost per asset category sn_"+current_snapshot+".csv")
                            if usage_result:
                                remove_zero_rows_and_columns(gen_country_network_utilization_fraction, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation network utilization sn_"+current_snapshot+".csv")
                                remove_zero_rows_and_columns(dem_country_network_utilization_fraction, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand network utilization sn_"+current_snapshot+".csv")

                if show_SO_results:
                    remove_zero_rows_and_columns(gen_SO_cost_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation network usage cost per asset sn_"+current_snapshot+".csv")
                    remove_zero_rows_and_columns(dem_SO_cost_per_asset, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand network usage cost per asset sn_"+current_snapshot+".csv")
                    if show_aggregated_results:
                        remove_zero_rows_and_columns(gen_SO_cost_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation network usage cost per SO sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(dem_SO_cost_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand network usage cost per SO sn_"+current_snapshot+".csv")
                        remove_zero_rows_and_columns(SO_cost_per_SO.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO joint network usage cost per SO sn_"+current_snapshot+".csv")
                        if category_aggregation:
                            remove_zero_rows_and_columns(gen_SO_cost_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation network usage cost per asset category sn_"+current_snapshot+".csv")
                            remove_zero_rows_and_columns(dem_SO_cost_per_asset_category, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand network usage cost per asset category sn_"+current_snapshot+".csv")
                            if usage_result:
                                remove_zero_rows_and_columns(gen_SO_network_utilization_fraction, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation network utilization sn_"+current_snapshot+".csv")
                                remove_zero_rows_and_columns(dem_SO_network_utilization_fraction, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand network utilization sn_"+current_snapshot+".csv")

    #%% overall results
    if os_name == "Windows":
        output_file         = "Overall results\\"
    else:    
        output_file         = "Overall results/"
    output_file         = os.path.join(config_path, output_file)
    if not os.path.exists(output_file):
        os.makedirs(output_file)

    overall_snapshots_weight                        = sum(snapshots_weights_dic.values())
    line_flow_overall                               = line_flow_overall/overall_snapshots_weight
    line_losses_overall                             = line_losses_overall/overall_snapshots_weight
    modified_generation_overall                     = modified_generation_overall/overall_snapshots_weight
    generation_overall                              = generation_overall/overall_snapshots_weight
    positive_demand_overall                         = positive_demand_overall/overall_snapshots_weight
    negative_demand_overall                         = negative_demand_overall/overall_snapshots_weight
    is_all_ND_zeros                                 = np.all(negative_demand_overall == 0)
    gen_agent_flow_contribution_per_asset_overall   = gen_agent_flow_contribution_per_asset_overall/overall_snapshots_weight
    dem_agent_flow_contribution_per_asset_overall   = dem_agent_flow_contribution_per_asset_overall/overall_snapshots_weight
     
    if not is_all_ND_zeros:
        negative_dem_agent_contribution_per_asset_overall   = get_negative_demand_contribution(negative_demand_overall, generation_overall, gen_agent_flow_contribution_per_asset_overall, nodes_sn, lines_sn)

    if show_country_results:
        gen_country_flow_contribution_per_asset_overall, country_nodes_matrix_G = get_contribution_per_asset(gen_agent_flow_contribution_per_asset_overall, nodes, lines, "Country", index_column)
        dem_country_flow_contribution_per_asset_overall, country_nodes_matrix_D = get_contribution_per_asset(dem_agent_flow_contribution_per_asset_overall, nodes, lines, "Country", index_column)
        if show_aggregated_results:
            gen_country_flow_contribution_per_country_overall, countries_lines  = get_contribution_per_group(gen_country_flow_contribution_per_asset_overall, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
            dem_country_flow_contribution_per_country_overall, countries_lines  = get_contribution_per_group(dem_country_flow_contribution_per_asset_overall, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
            if category_aggregation:
                gen_country_flow_contribution_per_asset_category_overall        = get_aggregation_per_category(gen_country_flow_contribution_per_asset_overall, lines_attributes)
                dem_country_flow_contribution_per_asset_category_overall        = get_aggregation_per_category(dem_country_flow_contribution_per_asset_overall, lines_attributes)
                
    if show_SO_results:
        gen_SO_flow_contribution_per_asset_overall, SO_nodes_matrix_G = get_contribution_per_asset(gen_agent_flow_contribution_per_asset_overall, nodes, lines, "SO 1", index_column)
        dem_SO_flow_contribution_per_asset_overall, SO_nodes_matrix_D = get_contribution_per_asset(dem_agent_flow_contribution_per_asset_overall, nodes, lines, "SO 1", index_column)
        if show_aggregated_results:
            gen_SO_flow_contribution_per_SO_overall,   SOs_lines      = get_contribution_per_group(gen_SO_flow_contribution_per_asset_overall, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
            dem_SO_flow_contribution_per_SO_overall,   SOs_lines      = get_contribution_per_group(dem_SO_flow_contribution_per_asset_overall, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
            if category_aggregation:
                gen_SO_flow_contribution_per_asset_category_overall   = get_aggregation_per_category(gen_SO_flow_contribution_per_asset_overall, lines_attributes)
                dem_SO_flow_contribution_per_asset_category_overall   = get_aggregation_per_category(dem_SO_flow_contribution_per_asset_overall, lines_attributes)
                
    if show_agent_results and show_aggregated_results:
        gen_agent_flow_contribution_per_country_overall             = np.matmul(gen_agent_flow_contribution_per_asset_overall,countries_lines.to_numpy())
        dem_agent_flow_contribution_per_country_overall             = np.matmul(dem_agent_flow_contribution_per_asset_overall,countries_lines.to_numpy())
        if SO_aggregation:  
            gen_agent_flow_contribution_per_SO_overall              = np.matmul(gen_agent_flow_contribution_per_asset_overall,SOs_lines.to_numpy())
            dem_agent_flow_contribution_per_SO_overall              = np.matmul(dem_agent_flow_contribution_per_asset_overall,SOs_lines.to_numpy())
        if category_aggregation:
            gen_agent_flow_contribution_per_asset_category_overall  = get_aggregation_per_category(pd.DataFrame(gen_agent_flow_contribution_per_asset_overall.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
            dem_agent_flow_contribution_per_asset_category_overall  = get_aggregation_per_category(pd.DataFrame(dem_agent_flow_contribution_per_asset_overall.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)

    if fraction_result:
        if cost_assignment_op == 1:     # utilization with respect to the used capacity
            gen_agent_utilization_fraction_per_asset_overall        = 100*gen_agent_flow_contribution_per_asset_overall/line_flow_overall[:,0]
            dem_agent_utilization_fraction_per_asset_overall        = 100*dem_agent_flow_contribution_per_asset_overall/line_flow_overall[:,0]    
        else:   # utilization with respect to the rated capacity
            gen_agent_utilization_fraction_per_asset_overall        = 100*gen_agent_flow_contribution_per_asset_overall/line_capacity_matrix[:,0]
            dem_agent_utilization_fraction_per_asset_overall        = 100*dem_agent_flow_contribution_per_asset_overall/line_capacity_matrix[:,0]
            if cost_assignment_op == 3 or cost_assignment_op == 4:  # utilization based on asset type and threshold 
                gen_agent_utilization_fraction_per_asset2_overall   = 100*gen_agent_flow_contribution_per_asset_overall/line_flow_overall[:,0]
                dem_agent_utilization_fraction_per_asset2_overall   = 100*dem_agent_flow_contribution_per_asset_overall/line_flow_overall[:,0]
                # treatment
                gen_agent_utilization_fraction_per_asset2_overall[np.isnan(gen_agent_utilization_fraction_per_asset2_overall)]  = 0
                dem_agent_utilization_fraction_per_asset2_overall[np.isnan(dem_agent_utilization_fraction_per_asset2_overall)]  = 0
                gen_agent_utilization_fraction_per_asset2_overall[np.isinf(gen_agent_utilization_fraction_per_asset2_overall)]  = 0
                dem_agent_utilization_fraction_per_asset2_overall[np.isinf(dem_agent_utilization_fraction_per_asset2_overall)]  = 0
                gen_agent_utilization_fraction_per_asset2_overall                                                               = np.where(gen_agent_utilization_fraction_per_asset2_overall > 100, 100, gen_agent_utilization_fraction_per_asset2_overall)
                dem_agent_utilization_fraction_per_asset2_overall                                                               = np.where(dem_agent_utilization_fraction_per_asset2_overall > 100, 100, dem_agent_utilization_fraction_per_asset2_overall)     

        gen_agent_utilization_fraction_per_asset_overall[np.isnan(gen_agent_utilization_fraction_per_asset_overall)]    = 0
        dem_agent_utilization_fraction_per_asset_overall[np.isnan(dem_agent_utilization_fraction_per_asset_overall)]    = 0
        gen_agent_utilization_fraction_per_asset_overall[np.isinf(gen_agent_utilization_fraction_per_asset_overall)]    = 0
        dem_agent_utilization_fraction_per_asset_overall[np.isinf(dem_agent_utilization_fraction_per_asset_overall)]    = 0
        gen_agent_utilization_fraction_per_asset_overall                                                                = np.where(gen_agent_utilization_fraction_per_asset_overall > 100, 100, gen_agent_utilization_fraction_per_asset_overall)
        dem_agent_utilization_fraction_per_asset_overall                                                                = np.where(dem_agent_utilization_fraction_per_asset_overall > 100, 100, dem_agent_utilization_fraction_per_asset_overall)                
    
    if cost_result:
        if cost_assignment_op == 1 or cost_assignment_op == 2:    
            gen_agent_cost_per_asset_overall    = gen_agent_utilization_fraction_per_asset_overall*line_cost_matrix[:,0]/100
            dem_agent_cost_per_asset_overall    = dem_agent_utilization_fraction_per_asset_overall*line_cost_matrix[:,0]/100
        else:
            if cost_assignment_op == 3: # full cost if the asset exist, used capacity cost if asset is planned
                if asset_type_cost:
                    gen_agent_utilization_fraction_per_asset_overall_partial    = np.matmul(gen_agent_utilization_fraction_per_asset_overall,np.diag(1-existing_assets))    # cost of used capacity for planned assets
                    dem_agent_utilization_fraction_per_asset_overall_partial    = np.matmul(dem_agent_utilization_fraction_per_asset_overall,np.diag(1-existing_assets))
                    gen_agent_utilization_fraction_per_asset2_overall           = np.matmul(gen_agent_utilization_fraction_per_asset2_overall,np.diag(existing_assets))     # full cost for existing assets
                    dem_agent_utilization_fraction_per_asset2_overall           = np.matmul(dem_agent_utilization_fraction_per_asset2_overall,np.diag(existing_assets))
                else:   # if the 'Exist/Planned' are not classified, use the cost of used capacity
                    gen_agent_utilization_fraction_per_asset_overall_partial    = gen_agent_utilization_fraction_per_asset_overall
                    dem_agent_utilization_fraction_per_asset_overall_partial    = dem_agent_utilization_fraction_per_asset_overall
                    gen_agent_utilization_fraction_per_asset2_overall           = np.matmul(gen_agent_utilization_fraction_per_asset2_overall,np.zeros((gen_agent_utilization_fraction_per_asset2_overall.shape[1],gen_agent_utilization_fraction_per_asset2_overall.shape[1])))     # full cost for existing assets
                    dem_agent_utilization_fraction_per_asset2_overall           = np.matmul(dem_agent_utilization_fraction_per_asset2_overall,np.zeros((dem_agent_utilization_fraction_per_asset2_overall.shape[1],dem_agent_utilization_fraction_per_asset2_overall.shape[1])))

            if cost_assignment_op == 4: # full cost if the asset is utilized above the threshold, otherwise, used capacity cost
                # identifying assets above and below the utilization threshold (UT) separately
                line_utilization_overall    = np.squeeze(100*line_flow_overall/line_capacity_matrix)
                line_above_UT_overall       = np.where(line_utilization_overall>utilization_threshold,1,0)

                gen_agent_utilization_fraction_per_asset_overall_partial    = np.matmul(gen_agent_utilization_fraction_per_asset_overall,np.diag(1-line_above_UT_overall))    # cost of used capacity for assets below the UT
                dem_agent_utilization_fraction_per_asset_overall_partial    = np.matmul(dem_agent_utilization_fraction_per_asset_overall,np.diag(1-line_above_UT_overall))
                gen_agent_utilization_fraction_per_asset2_overall           = np.matmul(gen_agent_utilization_fraction_per_asset2_overall,np.diag(line_above_UT_overall))     # full cost for assets above the UT
                dem_agent_utilization_fraction_per_asset2_overall           = np.matmul(dem_agent_utilization_fraction_per_asset2_overall,np.diag(line_above_UT_overall))

            gen_agent_cost_per_asset_overall    = (gen_agent_utilization_fraction_per_asset_overall_partial + gen_agent_utilization_fraction_per_asset2_overall)*line_cost_matrix[:,0]/100
            dem_agent_cost_per_asset_overall    = (dem_agent_utilization_fraction_per_asset_overall_partial + dem_agent_utilization_fraction_per_asset2_overall)*line_cost_matrix[:,0]/100
        
        gen_agent_cost_per_asset_overall        = gen_agent_cost_per_asset_overall*generation_weight
        dem_agent_cost_per_asset_overall        = dem_agent_cost_per_asset_overall*demand_weight 
        
        if regional_cost:
            gen_agent_cost_per_asset_overall   = regional_assets[:,0]*gen_agent_cost_per_asset_overall
            dem_agent_cost_per_asset_overall   = regional_assets[:,0]*dem_agent_cost_per_asset_overall

        if not is_all_ND_zeros:
            negative_dem_agent_cost_per_asset_overall = get_negative_demand_contribution(negative_demand_overall, generation_overall, gen_agent_cost_per_asset_overall, nodes_sn, lines_sn)

        # calculating the socialized cost of the grid
        if cost_of_unused_capacity_op:
            gen_total_allocated_cost_per_asset_overall  = gen_agent_cost_per_asset_overall.sum(axis=0)[None].transpose()
            dem_total_allocated_cost_per_asset_overall  = dem_agent_cost_per_asset_overall.sum(axis=0)[None].transpose()
            total_cost_to_be_socialized_overall         = line_cost_matrix - gen_total_allocated_cost_per_asset_overall - dem_total_allocated_cost_per_asset_overall
            gen_cost_to_socialize_per_asset_overall     = total_cost_to_be_socialized_overall*generation_socialized_weight
            dem_cost_to_socialize_per_asset_overall     = total_cost_to_be_socialized_overall*demand_socialized_weight
            gen_cost_to_socialize_per_asset_overall     = np.where(gen_cost_to_socialize_per_asset_overall < 0, 0, gen_cost_to_socialize_per_asset_overall)
            dem_cost_to_socialize_per_asset_overall     = np.where(dem_cost_to_socialize_per_asset_overall < 0, 0, dem_cost_to_socialize_per_asset_overall)

            if cost_of_unused_capacity_op == 1:     # socialize the cost equally among agents who use the asset
                gen_agent_users_per_asset_overall               = np.where(gen_agent_flow_contribution_per_asset_overall > 0, 1, 0)    # identifying the agents using each line (no matter how small the flow, >0) by 1
                dem_agent_users_per_asset_overall               = np.where(dem_agent_flow_contribution_per_asset_overall > 0, 1, 0)
                gen_agent_users_average_per_asset_overall       = gen_agent_users_per_asset_overall.sum(axis=0)[None].transpose()
                dem_agent_users_average_per_asset_overall       = dem_agent_users_per_asset_overall.sum(axis=0)[None].transpose()
                gen_agent_socialized_weight_per_asset_overall   = gen_agent_users_per_asset_overall/gen_agent_users_average_per_asset_overall[:,0]
                dem_agent_socialized_weight_per_asset_overall   = dem_agent_users_per_asset_overall/dem_agent_users_average_per_asset_overall[:,0]
                
                gen_agent_socialized_weight_per_asset_overall[np.isnan(gen_agent_socialized_weight_per_asset_overall)]  = 0
                dem_agent_socialized_weight_per_asset_overall[np.isnan(dem_agent_socialized_weight_per_asset_overall)]  = 0
                gen_agent_socialized_weight_per_asset_overall[np.isinf(gen_agent_socialized_weight_per_asset_overall)]  = 0
                dem_agent_socialized_weight_per_asset_overall[np.isinf(dem_agent_socialized_weight_per_asset_overall)]  = 0  
                
                gen_agent_socialized_cost_per_asset_overall = gen_agent_socialized_weight_per_asset_overall*gen_cost_to_socialize_per_asset_overall[:,0]
                dem_agent_socialized_cost_per_asset_overall = dem_agent_socialized_weight_per_asset_overall*dem_cost_to_socialize_per_asset_overall[:,0]

            elif cost_of_unused_capacity_op == 2:  # socialize the cost equally among the agents belonging to the country(ise) that owns the asset
                gen_agent_per_country       = country_nodes_matrix_G.set_index(["Node"]).to_numpy()
                dem_agent_per_country       = country_nodes_matrix_D.set_index(["Node"]).to_numpy()
                gen_agent_per_asset_country = np.matmul(gen_agent_per_country,countries_lines.to_numpy().transpose())
                dem_agent_per_asset_country = np.matmul(dem_agent_per_country,countries_lines.to_numpy().transpose())
                gen_agent_per_asset_country = np.where(gen_agent_per_asset_country > 0, 1, 0)
                dem_agent_per_asset_country = np.where(dem_agent_per_asset_country > 0, 1, 0)
                
                gen_agent_socialized_weight_per_asset_overall   = gen_agent_per_asset_country/gen_agent_per_asset_country.sum(axis=0)[None].transpose()[:,0]
                dem_agent_socialized_weight_per_asset_overall   = dem_agent_per_asset_country/dem_agent_per_asset_country.sum(axis=0)[None].transpose()[:,0]
                
                gen_agent_socialized_weight_per_asset_overall[np.isnan(gen_agent_socialized_weight_per_asset_overall)]  = 0
                dem_agent_socialized_weight_per_asset_overall[np.isnan(dem_agent_socialized_weight_per_asset_overall)]  = 0
                gen_agent_socialized_weight_per_asset_overall[np.isinf(gen_agent_socialized_weight_per_asset_overall)]  = 0
                dem_agent_socialized_weight_per_asset_overall[np.isinf(dem_agent_socialized_weight_per_asset_overall)]  = 0  
                
                gen_agent_socialized_cost_per_asset_overall = gen_agent_socialized_weight_per_asset_overall*gen_cost_to_socialize_per_asset_overall[:,0]
                dem_agent_socialized_cost_per_asset_overall = dem_agent_socialized_weight_per_asset_overall*dem_cost_to_socialize_per_asset_overall[:,0]

            elif cost_of_unused_capacity_op == 3:  # socialize the cost equally among all agents
                generation_agents_overall                       = np.where(modified_generation_overall > 0, 1, 0)
                demand_agents_overall                           = np.where(positive_demand_overall > 0, 1, 0)
                gen_agent_socialized_weight_per_asset_overall   = generation_agents_overall/generation_agents_overall.sum(axis=0)[0]
                dem_agent_socialized_weight_per_asset_overall   = demand_agents_overall/demand_agents_overall.sum(axis=0)[0]
                gen_agent_socialized_cost_per_asset_overall     = gen_agent_socialized_weight_per_asset_overall*gen_cost_to_socialize_per_asset_overall[:,0]
                dem_agent_socialized_cost_per_asset_overall     = dem_agent_socialized_weight_per_asset_overall*dem_cost_to_socialize_per_asset_overall[:,0]
    
        # the remaining cost results
        if show_country_results:
            gen_country_cost_per_asset_overall, country_nodes_matrix_G  = get_contribution_per_asset(gen_agent_cost_per_asset_overall, nodes, lines, "Country", index_column)
            dem_country_cost_per_asset_overall, country_nodes_matrix_D  = get_contribution_per_asset(dem_agent_cost_per_asset_overall, nodes, lines, "Country", index_column)
            if show_aggregated_results:
                gen_country_cost_per_country_overall, countries_lines   = get_contribution_per_group(gen_country_cost_per_asset_overall, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
                dem_country_cost_per_country_overall, countries_lines   = get_contribution_per_group(dem_country_cost_per_asset_overall, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country") 
                country_cost_per_country_overall                        = gen_country_cost_per_country_overall + dem_country_cost_per_country_overall
                if category_aggregation:
                    gen_country_cost_per_asset_category_overall         = get_aggregation_per_category(gen_country_cost_per_asset_overall, lines_attributes)
                    dem_country_cost_per_asset_category_overall         = get_aggregation_per_category(dem_country_cost_per_asset_overall, lines_attributes)

        if show_SO_results:
            gen_SO_cost_per_asset_overall, SO_nodes_matrix_G            = get_contribution_per_asset(gen_agent_cost_per_asset_overall, nodes, lines, "SO 1", index_column)
            dem_SO_cost_per_asset_overall, SO_nodes_matrix_D            = get_contribution_per_asset(dem_agent_cost_per_asset_overall, nodes, lines, "SO 1", index_column)
            if show_aggregated_results:
                gen_SO_cost_per_SO_overall,   SOs_lines                 = get_contribution_per_group(gen_SO_cost_per_asset_overall, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                dem_SO_cost_per_SO_overall,   SOs_lines                 = get_contribution_per_group(dem_SO_cost_per_asset_overall, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                SO_cost_per_SO_overall                                  = gen_SO_cost_per_SO_overall + dem_SO_cost_per_SO_overall
                if category_aggregation:
                    gen_SO_cost_per_asset_category_overall              = get_aggregation_per_category(gen_SO_cost_per_asset_overall, lines_attributes)
                    dem_SO_cost_per_asset_category_overall              = get_aggregation_per_category(dem_SO_cost_per_asset_overall, lines_attributes)

        if show_agent_results and show_aggregated_results:
            gen_agent_cost_per_country_overall                          = np.matmul(gen_agent_cost_per_asset_overall,countries_lines.to_numpy())
            dem_agent_cost_per_country_overall                          = np.matmul(dem_agent_cost_per_asset_overall,countries_lines.to_numpy())
            gen_agent_total_cost_overall                                = np.sum(gen_agent_cost_per_country_overall, axis=1) 
            dem_agent_total_cost_overall                                = np.sum(dem_agent_cost_per_country_overall, axis=1)
            if SO_aggregation:  
                gen_agent_cost_per_SO_overall                           = np.matmul(gen_agent_cost_per_asset_overall,SOs_lines.to_numpy())
                dem_agent_cost_per_SO_overall                           = np.matmul(dem_agent_cost_per_asset_overall,SOs_lines.to_numpy())
            if category_aggregation:
                gen_agent_cost_per_asset_category_overall               = get_aggregation_per_category(pd.DataFrame(gen_agent_cost_per_asset_overall.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
                dem_agent_cost_per_asset_category_overall               = get_aggregation_per_category(pd.DataFrame(dem_agent_cost_per_asset_overall.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)

    if losses_allocation_results:
        gen_agent_losses_allocation_per_asset_overall   = gen_agent_losses_allocation_per_asset_overall/overall_snapshots_weight
        dem_agent_losses_allocation_per_asset_overall   = dem_agent_losses_allocation_per_asset_overall/overall_snapshots_weight
        if show_agent_results and show_aggregated_results:
            gen_agent_losses_allocation_per_country_overall = np.matmul(gen_agent_losses_allocation_per_asset_overall,countries_lines.to_numpy())
            dem_agent_losses_allocation_per_country_overall = np.matmul(dem_agent_losses_allocation_per_asset_overall,countries_lines.to_numpy())
            gen_agent_total_losses_allocation_overall       = np.sum(gen_agent_losses_allocation_per_asset_overall, axis=1) 
            dem_agent_total_losses_allocation_overall       = np.sum(dem_agent_losses_allocation_per_asset_overall, axis=1)
            if SO_aggregation:
                gen_agent_losses_allocation_per_SO_overall  = np.matmul(gen_agent_losses_allocation_per_asset_overall,SOs_lines.to_numpy())
                dem_agent_losses_allocation_per_SO_overall  = np.matmul(dem_agent_losses_allocation_per_asset_overall,SOs_lines.to_numpy())
            if category_aggregation:
                gen_agent_losses_allocation_per_asset_category_overall   = get_aggregation_per_category(pd.DataFrame(gen_agent_losses_allocation_per_asset_overall.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
                dem_agent_losses_allocation_per_asset_category_overall   = get_aggregation_per_category(pd.DataFrame(dem_agent_losses_allocation_per_asset_overall.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
                        
        if show_country_results:
            gen_country_losses_allocation_per_asset_overall, country_nodes_matrix_G = get_contribution_per_asset(gen_agent_losses_allocation_per_asset_overall, nodes, lines, "Country", index_column)
            dem_country_losses_allocation_per_asset_overall, country_nodes_matrix_D = get_contribution_per_asset(dem_agent_losses_allocation_per_asset_overall, nodes, lines, "Country", index_column)
            if show_aggregated_results:
                gen_country_losses_allocation_per_country_overall, countries_lines  = get_contribution_per_group(gen_country_losses_allocation_per_asset_overall, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
                dem_country_losses_allocation_per_country_overall, countries_lines  = get_contribution_per_group(dem_country_losses_allocation_per_asset_overall, [], length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
                country_losses_allocation_per_country_overall                       = dem_country_losses_allocation_per_country_overall + gen_country_losses_allocation_per_country_overall
                if category_aggregation:
                    gen_country_losses_allocation_per_asset_category_overall        = get_aggregation_per_category(gen_country_losses_allocation_per_asset_overall, lines_attributes)
                    dem_country_losses_allocation_per_asset_category_overall        = get_aggregation_per_category(dem_country_losses_allocation_per_asset_overall, lines_attributes)
                    
        if show_SO_results:
            gen_SO_losses_allocation_per_asset_overall, SO_nodes_matrix_G   = get_contribution_per_asset(gen_agent_losses_allocation_per_asset_overall, nodes, lines, "SO 1", index_column)
            dem_SO_losses_allocation_per_asset_overall, SO_nodes_matrix_D   = get_contribution_per_asset(dem_agent_losses_allocation_per_asset_overall, nodes, lines, "SO 1", index_column)
            if show_aggregated_results:
                gen_SO_losses_allocation_per_SO_overall,   SOs_lines        = get_contribution_per_group(gen_SO_losses_allocation_per_asset_overall, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                dem_SO_losses_allocation_per_SO_overall,   SOs_lines        = get_contribution_per_group(dem_SO_losses_allocation_per_asset_overall, [], length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                SO_losses_allocation_per_SO_overall                         = dem_SO_losses_allocation_per_SO_overall + gen_SO_losses_allocation_per_SO_overall
                if category_aggregation:
                    gen_SO_losses_allocation_per_asset_category_overall     = get_aggregation_per_category(gen_SO_losses_allocation_per_asset_overall, lines_attributes)
                    dem_SO_losses_allocation_per_asset_category_overall     = get_aggregation_per_category(dem_SO_losses_allocation_per_asset_overall, lines_attributes)
        
        if losses_price:
            gen_agent_losses_allocation_cost_per_asset_overall   = gen_agent_losses_allocation_per_asset_overall*losses_price*overall_snapshots_weight*0.001
            dem_agent_losses_allocation_cost_per_asset_overall   = dem_agent_losses_allocation_per_asset_overall*losses_price*overall_snapshots_weight*0.001

            if show_agent_results and show_aggregated_results:
                gen_agent_losses_allocation_cost_per_country_overall = gen_agent_losses_allocation_per_country_overall*losses_price*overall_snapshots_weight*0.001
                dem_agent_losses_allocation_cost_per_country_overall = dem_agent_losses_allocation_per_country_overall*losses_price*overall_snapshots_weight*0.001
                gen_agent_total_losses_allocation_cost_overall       = gen_agent_total_losses_allocation_overall*losses_price*overall_snapshots_weight*0.001
                dem_agent_total_losses_allocation_cost_overall       = dem_agent_total_losses_allocation_overall*losses_price*overall_snapshots_weight*0.001
                if SO_aggregation:
                    gen_agent_losses_allocation_cost_per_SO_overall  = gen_agent_losses_allocation_per_SO_overall*losses_price*overall_snapshots_weight*0.001
                    dem_agent_losses_allocation_cost_per_SO_overall  = dem_agent_losses_allocation_per_SO_overall*losses_price*overall_snapshots_weight*0.001
                if category_aggregation:
                    gen_agent_losses_allocation_cost_per_asset_category_overall = gen_agent_losses_allocation_per_asset_category_overall*losses_price*overall_snapshots_weight*0.001
                    dem_agent_losses_allocation_cost_per_asset_category_overall = dem_agent_losses_allocation_per_asset_category_overall*losses_price*overall_snapshots_weight*0.001
                            
            if show_country_results:
                gen_country_losses_allocation_cost_per_asset_overall = gen_country_losses_allocation_per_asset_overall*losses_price*overall_snapshots_weight*0.001
                dem_country_losses_allocation_cost_per_asset_overall = dem_country_losses_allocation_per_asset_overall*losses_price*overall_snapshots_weight*0.001
                if show_aggregated_results:
                    gen_country_losses_allocation_cost_per_country_overall   = gen_country_losses_allocation_per_country_overall*losses_price*overall_snapshots_weight*0.001
                    dem_country_losses_allocation_cost_per_country_overall   = dem_country_losses_allocation_per_country_overall*losses_price*overall_snapshots_weight*0.001
                    country_losses_allocation_cost_per_country_overall       = dem_country_losses_allocation_cost_per_country_overall + gen_country_losses_allocation_cost_per_country_overall
                    if category_aggregation:
                        gen_country_losses_allocation_cost_per_asset_category_overall    = gen_country_losses_allocation_per_asset_category_overall*losses_price*overall_snapshots_weight*0.001
                        dem_country_losses_allocation_cost_per_asset_category_overall    = dem_country_losses_allocation_per_asset_category_overall*losses_price*overall_snapshots_weight*0.001
                        
            if show_SO_results:
                gen_SO_losses_allocation_cost_per_asset_overall  = gen_SO_losses_allocation_per_asset_overall*losses_price*overall_snapshots_weight*0.001
                dem_SO_losses_allocation_cost_per_asset_overall  = dem_SO_losses_allocation_per_asset_overall*losses_price*overall_snapshots_weight*0.001
                if show_aggregated_results:
                    gen_SO_losses_allocation_cost_per_SO_overall = gen_SO_losses_allocation_per_SO_overall*losses_price*overall_snapshots_weight*0.001
                    dem_SO_losses_allocation_cost_per_SO_overall = dem_SO_losses_allocation_per_SO_overall*losses_price*overall_snapshots_weight*0.001
                    SO_losses_allocation_cost_per_SO_overall     = dem_SO_losses_allocation_cost_per_SO_overall + gen_SO_losses_allocation_cost_per_SO_overall
                    if category_aggregation:
                        gen_SO_losses_allocation_cost_per_asset_category_overall = gen_SO_losses_allocation_per_asset_category_overall*losses_price*overall_snapshots_weight*0.001
                        dem_SO_losses_allocation_cost_per_asset_category_overall = dem_SO_losses_allocation_per_asset_category_overall*losses_price*overall_snapshots_weight*0.001

    #%% overall intermediary results
    if show_intermediary_results:    
        if usage_result:
            gen_agent_flow_km_contribution_per_asset_overall                    = gen_agent_flow_contribution_per_asset_overall*line_length_matrix[:,0]
            dem_agent_flow_km_contribution_per_asset_overall                    = dem_agent_flow_contribution_per_asset_overall*line_length_matrix[:,0]
            if show_agent_results and show_aggregated_results:
                gen_agent_flow_km_contribution_per_country_overall              = np.matmul(gen_agent_flow_km_contribution_per_asset_overall,countries_lines.to_numpy())
                dem_agent_flow_km_contribution_per_country_overall              = np.matmul(dem_agent_flow_km_contribution_per_asset_overall,countries_lines.to_numpy())
                if SO_aggregation:  
                    gen_agent_flow_km_contribution_per_SO_overall               = np.matmul(gen_agent_flow_km_contribution_per_asset_overall,SOs_lines.to_numpy())
                    dem_agent_flow_km_contribution_per_SO_overall               = np.matmul(dem_agent_flow_km_contribution_per_asset_overall,SOs_lines.to_numpy())
                if category_aggregation:
                    gen_agent_flow_km_contribution_per_asset_category_overall   = get_aggregation_per_category(pd.DataFrame(gen_agent_flow_km_contribution_per_asset_overall.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
                    dem_agent_flow_km_contribution_per_asset_category_overall   = get_aggregation_per_category(pd.DataFrame(dem_agent_flow_km_contribution_per_asset_overall.transpose(), index=lines[index_column], columns=nodes["Node"]), lines_attributes)
            
            if show_country_results:
                gen_country_flow_km_contribution_per_asset_overall, country_nodes_matrix_G  = get_contribution_per_asset(gen_agent_flow_km_contribution_per_asset_overall, nodes, lines, "Country", index_column)
                dem_country_flow_km_contribution_per_asset_overall, country_nodes_matrix_D  = get_contribution_per_asset(dem_agent_flow_km_contribution_per_asset_overall, nodes, lines, "Country", index_column)
                if show_aggregated_results:
                    gen_country_flow_km_contribution_per_country_overall, countries_lines   = get_contribution_per_group(gen_country_flow_km_contribution_per_asset_overall, reactance, length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
                    dem_country_flow_km_contribution_per_country_overall, countries_lines   = get_contribution_per_group(dem_country_flow_km_contribution_per_asset_overall, reactance, length_per_reactance, Ownership_matrix, countries_interconnections, "Country")
                    if category_aggregation:
                        gen_country_flow_km_contribution_per_asset_category_overall         = get_aggregation_per_category(gen_country_flow_km_contribution_per_asset_overall, lines_attributes)
                        dem_country_flow_km_contribution_per_asset_category_overall         = get_aggregation_per_category(dem_country_flow_km_contribution_per_asset_overall, lines_attributes)
            
            if show_SO_results:
                gen_SO_flow_km_contribution_per_asset_overall, SO_nodes_matrix_G = get_contribution_per_asset(gen_agent_flow_km_contribution_per_asset_overall, nodes, lines, "SO 1", index_column)
                dem_SO_flow_km_contribution_per_asset_overall, SO_nodes_matrix_D = get_contribution_per_asset(dem_agent_flow_km_contribution_per_asset_overall, nodes, lines, "SO 1", index_column)
                if show_aggregated_results:
                    gen_SO_flow_km_contribution_per_SO_overall,   SOs_lines      = get_contribution_per_group(gen_SO_flow_km_contribution_per_asset_overall, reactance, length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                    dem_SO_flow_km_contribution_per_SO_overall,   SOs_lines      = get_contribution_per_group(dem_SO_flow_km_contribution_per_asset_overall, reactance, length_per_reactance, Ownership_matrix, SOs_interconnections, "SO Owner")
                    if category_aggregation:
                        gen_SO_flow_km_contribution_per_asset_category_overall   = get_aggregation_per_category(gen_SO_flow_km_contribution_per_asset_overall, lines_attributes)
                        dem_SO_flow_km_contribution_per_asset_category_overall   = get_aggregation_per_category(dem_SO_flow_km_contribution_per_asset_overall, lines_attributes)

        if fraction_result:
            if show_agent_results and show_aggregated_results and category_aggregation and usage_result:
                gen_agent_utilization_fraction_per_asset_category_overall   = get_utilization_per_category(gen_agent_flow_km_contribution_per_asset_category_overall, gen_agent_flow_contribution_per_asset_category_overall, flow_km_per_category, flow_per_category, asset_type_dic)                    
                dem_agent_utilization_fraction_per_asset_category_overall   = get_utilization_per_category(dem_agent_flow_km_contribution_per_asset_category_overall, dem_agent_flow_contribution_per_asset_category_overall, flow_km_per_category, flow_per_category, asset_type_dic)
                if cost_result:
                    gen_agent_network_utilization_fraction_overall          = ((gen_agent_utilization_fraction_per_asset_category_overall*cost_per_category.to_numpy().transpose()[:,0]).sum(axis=1)/cost_per_category.sum(axis=1)[0]).to_frame(name='Network Utilization %')              
                    dem_agent_network_utilization_fraction_overall          = ((dem_agent_utilization_fraction_per_asset_category_overall*cost_per_category.to_numpy().transpose()[:,0]).sum(axis=1)/cost_per_category.sum(axis=1)[0]).to_frame(name='Network Utilization %')
            
            if show_country_results:
                gen_country_utilization_fraction_per_asset_overall, country_nodes_matrix_G  = get_contribution_per_asset(gen_agent_utilization_fraction_per_asset_overall, nodes, lines, "Country", index_column)
                dem_country_utilization_fraction_per_asset_overall, country_nodes_matrix_D  = get_contribution_per_asset(dem_agent_utilization_fraction_per_asset_overall, nodes, lines, "Country", index_column)
                if show_aggregated_results and category_aggregation and usage_result:
                    gen_country_utilization_fraction_per_asset_category_overall             = get_utilization_per_category(gen_country_flow_km_contribution_per_asset_category_overall, gen_country_flow_contribution_per_asset_category_overall, flow_km_per_category, flow_per_category, asset_type_dic)
                    dem_country_utilization_fraction_per_asset_category_overall             = get_utilization_per_category(dem_country_flow_km_contribution_per_asset_category_overall, dem_country_flow_contribution_per_asset_category_overall, flow_km_per_category, flow_per_category, asset_type_dic)        
                    if cost_result:
                        gen_country_network_utilization_fraction_overall                    = ((gen_country_utilization_fraction_per_asset_category_overall*cost_per_category.to_numpy().transpose()[:,0]).sum(axis=1)/cost_per_category.sum(axis=1)[0]).to_frame(name='Network Utilization %')
                        dem_country_network_utilization_fraction_overall                    = ((dem_country_utilization_fraction_per_asset_category_overall*cost_per_category.to_numpy().transpose()[:,0]).sum(axis=1)/cost_per_category.sum(axis=1)[0]).to_frame(name='Network Utilization %')

            if show_SO_results:
                gen_SO_utilization_fraction_per_asset_overall, SO_nodes_matrix_G   = get_contribution_per_asset(gen_agent_utilization_fraction_per_asset_overall, nodes, lines, "SO 1", index_column)
                dem_SO_utilization_fraction_per_asset_overall, SO_nodes_matrix_D   = get_contribution_per_asset(dem_agent_utilization_fraction_per_asset_overall, nodes, lines, "SO 1", index_column)
                if show_aggregated_results and category_aggregation and usage_result:
                    gen_SO_utilization_fraction_per_asset_category_overall         = get_utilization_per_category(gen_SO_flow_km_contribution_per_asset_category_overall, gen_SO_flow_contribution_per_asset_category_overall, flow_km_per_category, flow_per_category, asset_type_dic)
                    dem_SO_utilization_fraction_per_asset_category_overall         = get_utilization_per_category(dem_SO_flow_km_contribution_per_asset_category_overall, dem_SO_flow_contribution_per_asset_category_overall, flow_km_per_category, flow_per_category, asset_type_dic)
                    if cost_result:
                        gen_SO_network_utilization_fraction_overall                = ((gen_SO_utilization_fraction_per_asset_category_overall*cost_per_category.to_numpy().transpose()[:,0]).sum(axis=1)/cost_per_category.sum(axis=1)[0]).to_frame(name='Network Utilization %')
                        dem_SO_network_utilization_fraction_overall                = ((dem_SO_utilization_fraction_per_asset_category_overall*cost_per_category.to_numpy().transpose()[:,0]).sum(axis=1)/cost_per_category.sum(axis=1)[0]).to_frame(name='Network Utilization %')

    #%% exporting overall results
    if show_agent_results:
        print_to_csv(output_file+"Generation agents overall flow contribution per asset", gen_agent_flow_contribution_per_asset_overall, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
        print_to_csv(output_file+"Demand agents overall flow contribution per asset", dem_agent_flow_contribution_per_asset_overall, index=nodes["Node"], columns=lines["Line"],total=True, remove_zeros=remove_zero_values)
        if not np.all(negative_demand_overall == 0):
            remove_zero_rows_and_columns(negative_dem_agent_contribution_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Negative demand agents overall flow contribution per asset.csv")
        if show_aggregated_results:
            print_to_csv(output_file+"Generation agents overall flow contribution per country", gen_agent_flow_contribution_per_country_overall, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
            print_to_csv(output_file+"Demand agents overall flow contribution per country", dem_agent_flow_contribution_per_country_overall, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
            if SO_aggregation:
                print_to_csv(output_file+"Generation agents overall flow contribution per SO", gen_agent_flow_contribution_per_SO_overall, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                print_to_csv(output_file+"Demand agents overall flow contribution per SO", dem_agent_flow_contribution_per_SO_overall, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
            if category_aggregation:
                remove_zero_rows_and_columns(gen_agent_flow_contribution_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents overall flow contribution per asset category.csv")
                remove_zero_rows_and_columns(dem_agent_flow_contribution_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents overall flow contribution per asset category.csv")
                
    if show_country_results:
        remove_zero_rows_and_columns(gen_country_flow_contribution_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall flow contribution per asset.csv")
        remove_zero_rows_and_columns(dem_country_flow_contribution_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall flow contribution per asset.csv")
        if show_aggregated_results:
            remove_zero_rows_and_columns(gen_country_flow_contribution_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall flow contribution per country.csv")
            remove_zero_rows_and_columns(dem_country_flow_contribution_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall flow contribution per country.csv")
            if category_aggregation:
                remove_zero_rows_and_columns(gen_country_flow_contribution_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall flow contribution per asset category.csv")
                remove_zero_rows_and_columns(dem_country_flow_contribution_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall flow contribution per asset category.csv")
                
    if show_SO_results:
        remove_zero_rows_and_columns(gen_SO_flow_contribution_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall flow contribution per asset.csv")
        remove_zero_rows_and_columns(dem_SO_flow_contribution_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall flow contribution per asset.csv")
        if show_aggregated_results:
            remove_zero_rows_and_columns(gen_SO_flow_contribution_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall flow contribution per SO.csv")
            remove_zero_rows_and_columns(dem_SO_flow_contribution_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall flow contribution per SO.csv")
            if category_aggregation:
                remove_zero_rows_and_columns(gen_SO_flow_contribution_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall flow contribution per asset category.csv")
                remove_zero_rows_and_columns(dem_SO_flow_contribution_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall flow contribution per asset category.csv")

    if losses_allocation_results:
        if show_agent_results:
            print_to_csv(output_file+"Generation agents overall losses allocation per asset", gen_agent_losses_allocation_per_asset_overall, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
            print_to_csv(output_file+"Demand agents overall losses allocation per asset", dem_agent_losses_allocation_per_asset_overall, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
            if show_aggregated_results:
                print_to_csv(output_file+"Generation agents overall losses allocation per country", gen_agent_losses_allocation_per_country_overall, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                print_to_csv(output_file+"Demand agents overall losses allocation per country", dem_agent_losses_allocation_per_country_overall, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                print_to_csv(output_file+"Generation agents overall total losses allocation", gen_agent_total_losses_allocation_overall, index=nodes["Node"], columns=['Total losses allocation MW'], total=True, remove_zeros=remove_zero_values)
                print_to_csv(output_file+"Demand agents overall total losses allocation", dem_agent_total_losses_allocation_overall, index=nodes["Node"], columns=['Total losses allocation'], total=True, remove_zeros=remove_zero_values)
                if SO_aggregation: 
                    print_to_csv(output_file+"Generation agents overall losses allocation per SO", gen_agent_losses_allocation_per_SO_overall, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                    print_to_csv(output_file+"Demand agents overall losses allocation per SO", dem_agent_losses_allocation_per_SO_overall, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                if category_aggregation:
                    remove_zero_rows_and_columns(gen_agent_losses_allocation_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents overall losses allocation per asset category.csv")
                    remove_zero_rows_and_columns(dem_agent_losses_allocation_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents overall losses allocation per asset category.csv")
        
        if show_country_results:
            remove_zero_rows_and_columns(gen_country_losses_allocation_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall losses allocation per asset.csv")
            remove_zero_rows_and_columns(dem_country_losses_allocation_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall losses allocation per asset.csv")
            if show_aggregated_results:
                remove_zero_rows_and_columns(gen_country_losses_allocation_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall losses allocation per country.csv")
                remove_zero_rows_and_columns(dem_country_losses_allocation_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall losses allocation per country.csv")
                remove_zero_rows_and_columns(country_losses_allocation_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country joint overall losses allocation per country.csv")
                if category_aggregation:
                    remove_zero_rows_and_columns(gen_country_losses_allocation_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall losses allocation per asset category.csv")
                    remove_zero_rows_and_columns(dem_country_losses_allocation_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall losses allocation per asset category.csv")

        if show_SO_results:
            remove_zero_rows_and_columns(gen_SO_losses_allocation_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall losses allocation per asset.csv")
            remove_zero_rows_and_columns(dem_SO_losses_allocation_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall losses allocation per asset.csv")
            if show_aggregated_results:
                remove_zero_rows_and_columns(gen_SO_losses_allocation_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall losses allocation per SO.csv")
                remove_zero_rows_and_columns(dem_SO_losses_allocation_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall losses allocation per SO.csv")
                remove_zero_rows_and_columns(SO_losses_allocation_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO joint overall losses allocation per SO.csv")
                if category_aggregation:
                    remove_zero_rows_and_columns(gen_SO_losses_allocation_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall losses allocation per asset category.csv")
                    remove_zero_rows_and_columns(dem_SO_losses_allocation_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall losses allocation per asset category.csv")

        if losses_price:
            if show_agent_results:
                print_to_csv(output_file+"Generation agents overall losses allocation cost per asset", gen_agent_losses_allocation_cost_per_asset_overall, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                print_to_csv(output_file+"Demand agents overall losses allocation cost per asset", dem_agent_losses_allocation_cost_per_asset_overall, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                if show_aggregated_results:
                    print_to_csv(output_file+"Generation agents overall losses allocation cost per country", gen_agent_losses_allocation_cost_per_country_overall, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                    print_to_csv(output_file+"Demand agents overall losses allocation cost per country", dem_agent_losses_allocation_cost_per_country_overall, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                    print_to_csv(output_file+"Generation agents overall total losses allocation cost", gen_agent_total_losses_allocation_cost_overall, index=nodes["Node"], columns=['Total losses allocation MW'], total=True, remove_zeros=remove_zero_values)
                    print_to_csv(output_file+"Demand agents overall total losses allocation cost", dem_agent_total_losses_allocation_cost_overall, index=nodes["Node"], columns=['Total losses allocation'], total=True, remove_zeros=remove_zero_values)
                    if SO_aggregation: 
                        print_to_csv(output_file+"Generation agents overall losses allocation cost per SO", gen_agent_losses_allocation_cost_per_SO_overall, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                        print_to_csv(output_file+"Demand agents overall losses allocation cost per SO", dem_agent_losses_allocation_cost_per_SO_overall, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                    if category_aggregation:
                        remove_zero_rows_and_columns(gen_agent_losses_allocation_cost_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents overall losses allocation cost per asset category.csv")
                        remove_zero_rows_and_columns(dem_agent_losses_allocation_cost_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents overall losses allocation cost per asset category.csv")
            
            if show_country_results:
                remove_zero_rows_and_columns(gen_country_losses_allocation_cost_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall losses allocation cost per asset.csv")
                remove_zero_rows_and_columns(dem_country_losses_allocation_cost_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall losses allocation cost per asset.csv")
                if show_aggregated_results:
                    remove_zero_rows_and_columns(gen_country_losses_allocation_cost_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall losses allocation cost per country.csv")
                    remove_zero_rows_and_columns(dem_country_losses_allocation_cost_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall losses allocation cost per country.csv")
                    remove_zero_rows_and_columns(country_losses_allocation_cost_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country joint overall losses allocation cost per country.csv")
                    if category_aggregation:
                        remove_zero_rows_and_columns(gen_country_losses_allocation_cost_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall losses allocation cost per asset category.csv")
                        remove_zero_rows_and_columns(dem_country_losses_allocation_cost_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall losses allocation cost per asset category.csv")

            if show_SO_results:
                remove_zero_rows_and_columns(gen_SO_losses_allocation_cost_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall losses allocation cost per asset.csv")
                remove_zero_rows_and_columns(dem_SO_losses_allocation_cost_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall losses allocation cost per asset.csv")
                if show_aggregated_results:
                    remove_zero_rows_and_columns(gen_SO_losses_allocation_cost_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall losses allocation cost per SO.csv")
                    remove_zero_rows_and_columns(dem_SO_losses_allocation_cost_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall losses allocation cost per SO.csv")
                    remove_zero_rows_and_columns(SO_losses_allocation_cost_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO joint overall losses allocation cost per SO.csv")
                    if category_aggregation:
                        remove_zero_rows_and_columns(gen_SO_losses_allocation_cost_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall losses allocation cost per asset category.csv")
                        remove_zero_rows_and_columns(dem_SO_losses_allocation_cost_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall losses allocation cost per asset category.csv")

    if cost_result:  
        if show_agent_results:
            print_to_csv(output_file+"Generation agents overall network usage cost per asset", gen_agent_cost_per_asset_overall, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
            print_to_csv(output_file+"Demand agents overall network usage cost per asset", dem_agent_cost_per_asset_overall, index=nodes["Node"], columns=lines["Line"],total=True, remove_zeros=remove_zero_values)
            if not is_all_ND_zeros:
                remove_zero_rows_and_columns(negative_dem_agent_cost_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Negative demand agents overall network usage cost per asset.csv")
            if cost_of_unused_capacity_op:
                print_to_csv(output_file+"Generation agents socialized network usage cost per asset", gen_agent_socialized_cost_per_asset_overall, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                print_to_csv(output_file+"Demand agents socialized network usage cost per asset", dem_agent_socialized_cost_per_asset_overall, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
            if show_aggregated_results:
                print_to_csv(output_file+"Generation agents overall network usage cost per country", gen_agent_cost_per_country_overall, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                print_to_csv(output_file+"Demand agents overall network usage cost per country", dem_agent_cost_per_country_overall, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                print_to_csv(output_file+"Generation agents overall network usage total cost", gen_agent_total_cost_overall, index=nodes["Node"], columns=['Total cost KUS$'], total=True, remove_zeros=remove_zero_values)
                print_to_csv(output_file+"Demand agents overall network usage total cost", dem_agent_total_cost_overall, index=nodes["Node"], columns=['Total cost KUS$'], total=True, remove_zeros=remove_zero_values)
                if SO_aggregation:
                    print_to_csv(output_file+"Generation agents overall network usage cost per SO", gen_agent_cost_per_SO_overall, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                    print_to_csv(output_file+"Demand agents overall network usage cost per SO", dem_agent_cost_per_SO_overall, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                if category_aggregation:
                    remove_zero_rows_and_columns(gen_agent_cost_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents overall network usage cost per asset category.csv")
                    remove_zero_rows_and_columns(dem_agent_cost_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents overall network usage cost per asset category.csv")

        if show_country_results:
            remove_zero_rows_and_columns(gen_country_cost_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall network usage cost per asset"+".csv")
            remove_zero_rows_and_columns(dem_country_cost_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall network usage cost per asset"+".csv")
            if show_aggregated_results:
                remove_zero_rows_and_columns(gen_country_cost_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall network usage cost per country.csv")
                remove_zero_rows_and_columns(dem_country_cost_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall network usage cost per country.csv")
                remove_zero_rows_and_columns(country_cost_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country joint overall network usage cost per country.csv")
                if category_aggregation:
                    remove_zero_rows_and_columns(gen_country_cost_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall network usage cost per asset category.csv")
                    remove_zero_rows_and_columns(dem_country_cost_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall network usage cost per asset category.csv")

        if show_SO_results:
            remove_zero_rows_and_columns(gen_SO_cost_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall network usage cost per asset.csv")
            remove_zero_rows_and_columns(dem_SO_cost_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall network usage cost per asset.csv")    
            if show_aggregated_results:
                remove_zero_rows_and_columns(gen_SO_cost_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall network usage cost per SO.csv")
                remove_zero_rows_and_columns(dem_SO_cost_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall network usage cost per SO.csv")
                remove_zero_rows_and_columns(SO_cost_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO joint overall network usage cost per SO.csv")
                if category_aggregation:
                    remove_zero_rows_and_columns(gen_SO_cost_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall network usage cost per asset category.csv")
                    remove_zero_rows_and_columns(dem_SO_cost_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall network usage cost per asset category.csv")
    
    # other intermediary results
    if show_intermediary_results:
        if fraction_result:
            if show_agent_results:
                print_to_csv(output_file+"Generation agents overall utilization fraction per asset", gen_agent_utilization_fraction_per_asset_overall, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                print_to_csv(output_file+"Demand agents overall utilization fraction per asset", dem_agent_utilization_fraction_per_asset_overall, index=nodes["Node"], columns=lines["Line"],total=True, remove_zeros=remove_zero_values)
                if show_aggregated_results and category_aggregation and usage_result:
                    remove_zero_rows_and_columns(gen_agent_utilization_fraction_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents overall utilization fraction per asset category.csv")
                    remove_zero_rows_and_columns(dem_agent_utilization_fraction_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents overall utilization fraction per asset category.csv")
                    if cost_result:
                        remove_zero_rows_and_columns(gen_agent_network_utilization_fraction_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents overall network utilization.csv")
                        remove_zero_rows_and_columns(dem_agent_network_utilization_fraction_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents overall network utilization.csv")

            if show_country_results:
                remove_zero_rows_and_columns(gen_country_utilization_fraction_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall utilization fraction per asset.csv")
                remove_zero_rows_and_columns(dem_country_utilization_fraction_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall utilization fraction per asset.csv")
                if show_aggregated_results and category_aggregation and usage_result:
                    remove_zero_rows_and_columns(gen_country_utilization_fraction_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall utilization fraction per asset category.csv")
                    remove_zero_rows_and_columns(dem_country_utilization_fraction_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall utilization fraction per asset category.csv")
                    if cost_result:
                        remove_zero_rows_and_columns(gen_country_network_utilization_fraction_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall network utilization.csv")
                        remove_zero_rows_and_columns(dem_country_network_utilization_fraction_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall network utilization.csv")
                    
            if show_SO_results:
                remove_zero_rows_and_columns(gen_SO_utilization_fraction_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall utilization fraction per asset.csv")
                remove_zero_rows_and_columns(dem_SO_utilization_fraction_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand utilization overall fraction per asset.csv")              
                if show_aggregated_results and category_aggregation and usage_result:
                    remove_zero_rows_and_columns(gen_SO_utilization_fraction_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall utilization fraction per asset category.csv")
                    remove_zero_rows_and_columns(dem_SO_utilization_fraction_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall utilization fraction per asset category.csv")
                    if cost_result:
                        remove_zero_rows_and_columns(gen_SO_network_utilization_fraction_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall network utilization.csv")
                        remove_zero_rows_and_columns(dem_SO_network_utilization_fraction_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall network utilization.csv")
                    
        if usage_result:
            if show_agent_results:
                print_to_csv(output_file+"Generation agents overall flow-km contribution per asset", gen_agent_flow_km_contribution_per_asset_overall, index=nodes["Node"], columns=lines["Line"], total=True, remove_zeros=remove_zero_values)
                print_to_csv(output_file+"Demand agents overall flow-km contribution per asset", dem_agent_flow_km_contribution_per_asset_overall, index=nodes["Node"], columns=lines["Line"],total=True, remove_zeros=remove_zero_values)
                if show_aggregated_results:
                    print_to_csv(output_file+"Generation agents overall flow-km contribution per country", gen_agent_flow_km_contribution_per_country_overall, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                    print_to_csv(output_file+"Demand agents overall flow-km contribution per country", dem_agent_flow_km_contribution_per_country_overall, index=nodes["Node"], columns=countries_lines.columns, total=False, remove_zeros=remove_zero_values)
                    if SO_aggregation:
                        print_to_csv(output_file+"Generation agents overall flow-km contribution per SO", gen_agent_flow_km_contribution_per_SO_overall, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)
                        print_to_csv(output_file+"Demand agents overall flow-km contribution per SO", dem_agent_flow_km_contribution_per_SO_overall, index=nodes["Node"], columns=SOs_lines.columns, total=False, remove_zeros=remove_zero_values)    
                    if category_aggregation:
                        remove_zero_rows_and_columns(gen_agent_flow_km_contribution_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Generation agents overall flow-km contribution per asset category.csv")
                        remove_zero_rows_and_columns(dem_agent_flow_km_contribution_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Demand agents overall flow-km contribution per asset category.csv")

            if show_country_results:
                remove_zero_rows_and_columns(gen_country_flow_km_contribution_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall flow-km contribution per asset.csv")
                remove_zero_rows_and_columns(dem_country_flow_km_contribution_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall flow-km contribution per asset.csv")
                if show_aggregated_results:
                    remove_zero_rows_and_columns(gen_country_flow_km_contribution_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall flow-km contribution per country.csv")
                    remove_zero_rows_and_columns(dem_country_flow_km_contribution_per_country_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall flow-km contribution per country.csv")
                    if category_aggregation:
                        remove_zero_rows_and_columns(gen_country_flow_km_contribution_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country generation overall flow-km contribution per asset category.csv")
                        remove_zero_rows_and_columns(dem_country_flow_km_contribution_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"Country demand overall flow-km contribution per asset category.csv")
            
            if show_SO_results:
                remove_zero_rows_and_columns(gen_SO_flow_km_contribution_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall flow-km contribution per asset.csv")
                remove_zero_rows_and_columns(dem_SO_flow_km_contribution_per_asset_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall flow-km contribution per asset.csv")
                if show_aggregated_results:
                    remove_zero_rows_and_columns(gen_SO_flow_km_contribution_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall flow-km contribution per SO.csv")
                    remove_zero_rows_and_columns(dem_SO_flow_km_contribution_per_SO_overall.transpose(), remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall flow-km contribution per SO.csv")
                    if category_aggregation:
                        remove_zero_rows_and_columns(gen_SO_flow_km_contribution_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO generation overall flow-km contribution per asset category.csv")
                        remove_zero_rows_and_columns(dem_SO_flow_km_contribution_per_asset_category_overall, remove_zero_values, remove_zero_values).to_csv(output_file+"SO demand overall flow-km contribution per asset category.csv")
            
    #%% End!
    return (time.time() - start_time)


#%% default main function

def main():
    "This is the main function for reading inputs from the user and running the model"
    
    args = parser.parse_args()
    if args.dir is None:
        args.dir    = input('Input Dir    Name (Default {}): '.format(DIR))
        if args.dir == '':
            args.dir = DIR
    if args.case is None:
        args.case   = input('Input Case   Name (Default {}): '.format(CASE))
        if args.case == '':
            args.case = CASE
    if args.config is None:
        args.config = input('Input configuration file Name (Default {}): '.format(CONFIGF))
        if args.config == '':
            args.config = CONFIGF

    print('\n*************************************!RUNNING!*************************************')
    print(logo)
    execution_time = InfraFair_run(args.dir, args.case, args.config)
    print("*****************************!EXECUTION TIME %s!*****************************" % time.strftime('%H:%M:%S', time.gmtime(execution_time)))
    print('\n**************************!COST HAS BEEN FAIRLY ALLOCATED!*************************')

if __name__ == '__main__':
    main()
