<filename>cea/utilities/create_mixed_use_type.py
"""
This script creates a new use-type by aggregating values from a list of different use-types
"""




import os

import numpy as np
import pandas as pd

import cea
import cea.config
import cea.inputlocator
from cea.datamanagement.archetypes_mapper import calculate_average_multiuse
from cea.datamanagement.schedule_helper import calc_single_mixed_schedule, ScheduleData
from cea.utilities.schedule_reader import save_cea_schedule


__author__ = "<NAME>"
__copyright__ = "Copyright 2018, Architecture and Building Systems - ETH Zurich"
__credits__ = ["<NAME>, <NAME>"]
__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "<NAME>"
__email__ = "<EMAIL>"
__status__ = "Production"


DEFAULT_USE_TYPE = 'MULTI_RES'
COLUMN_VAR_NAME_TEMPLATE = 'USE_{}'
COLUMN_VAR_VAL_TEMPLATE = 'USE_{}_R'


def create_mixed_use_type(locator, internal_loads_df, indoor_comfort_df,
                          use_type_name, use_type_metadata, use_type_ratios_dict):
    """
    Takes a list of use-types and their respective ratios to aggregate and create a new use-type
    with schedules, internal loads and indoor comfort data

    :param schedules_path:
    :param internal_loads_df:
    :param indoor_comfort_df:
    :param use_type_name:
    :param use_type_metadata:
    :param use_type_ratios_dict:
    :return:
    """
    list_uses = use_type_ratios_dict.keys()
    list_var_names = [COLUMN_VAR_NAME_TEMPLATE.format(i) for i in range(len(use_type_ratios_dict))]
    list_var_values = [COLUMN_VAR_VAL_TEMPLATE.format(i) for i in range(len(use_type_ratios_dict))]

    # Creating required parameters
    properties_dict = {}
    for i, (k, v) in enumerate(use_type_ratios_dict.items()):
        properties_dict[list_var_names[i]] = k
        properties_dict[list_var_values[i]] = v
    properties_df = pd.DataFrame([properties_dict])
    occupant_densities = calculate_occupant_density(list_uses, internal_loads_df)

    print("Calculating internal loads...")
    new_internal_loads_df = calculate_mixed_loads(properties_df, internal_loads_df, occupant_densities, list_uses,
                                                  use_type_name, list_var_names, list_var_values)
    print("Calculating indoor comfort...")
    new_indoor_comfort_df = calculate_mixed_loads(properties_df, indoor_comfort_df, occupant_densities, list_uses,
                                                  use_type_name, list_var_names, list_var_values)

    prop_df_c = properties_df.copy()
    prop_df_c['Name'] = '0'  # Set a `Name` column as index for function to work
    prop_df_c.set_index('Name', inplace=True)
    schedule_data_all_uses = ScheduleData(locator)
    internal_loads = internal_loads_df.set_index('code')
    print("Calculating schedules...")
    schedule_new_data, schedule_complementary_data = calc_single_mixed_schedule(list_uses, occupant_densities,
                                                                                prop_df_c, internal_loads, '0',
                                                                                schedule_data_all_uses, list_var_names,
                                                                                list_var_values, use_type_metadata)

    print("Writing to disk...")
    use_type_properties_path = locator.get_database_use_types_properties()
    with pd.ExcelWriter(use_type_properties_path) as writer:
        new_internal_loads_df.to_excel(writer, sheet_name='INTERNAL_LOADS', index=False)
        new_indoor_comfort_df.to_excel(writer, sheet_name='INDOOR_COMFORT', index=False)

    schedule_path = os.path.join(locator.get_database_use_types_folder(), '{}.csv'.format(use_type_name))
    save_cea_schedule(schedule_new_data, schedule_complementary_data, schedule_path)


def calculate_mixed_loads(properties_df, loads_df, occupant_densities, list_uses, use_type_name, list_var_names, list_var_values):
    prop_df = properties_df.copy().merge(loads_df, left_on=list_var_names[0], right_on='code')
    loads_df_columns = loads_df.columns
    calculated_loads_df = calculate_average_multiuse(loads_df_columns, prop_df, occupant_densities,
                                                     list_uses, loads_df,
                                                     list_var_names, list_var_values).loc[:, loads_df_columns]
    calculated_loads_df['code'] = use_type_name
    # Remove rows that have the same `code` as new row
    clean_loads_df = loads_df[loads_df['code'] != use_type_name]
    return clean_loads_df.append(calculated_loads_df)


def calculate_occupant_density(use_types, internal_loads_df):
    occupant_densities = {}
    internal_loads = internal_loads_df.copy().set_index('code')
    for use in use_types:
        if internal_loads.loc[use, 'Occ_m2p'] > 0.0:
            occupant_densities[use] = 1.0 / internal_loads.loc[use, 'Occ_m2p']
        else:
            occupant_densities[use] = 0.0
    return occupant_densities


def main(config):
    # Config Parameters
    use_type_name = config.create_mixed_use_type.use_type
    use_type_metadata = config.create_mixed_use_type.metadata
    use_type_ratios = config.create_mixed_use_type.ratios
    use_type_ratios_dict = {k: float(v) for k, v in [ratio.split('|') for ratio in use_type_ratios]}

    locator = cea.inputlocator.InputLocator(scenario=config.scenario)
    use_type_properties_df = pd.read_excel(locator.get_database_use_types_properties(), sheet_name=None)
    internal_loads_df = use_type_properties_df['INTERNAL_LOADS']
    indoor_comfort_df = use_type_properties_df['INDOOR_COMFORT']

    assert use_type_name not in internal_loads_df['code'].tolist() and use_type_name not in indoor_comfort_df['code'].tolist(), \
        'Use-type name {} already exists'.format(use_type_name)

    create_mixed_use_type(locator,
                          internal_loads_df=internal_loads_df,
                          indoor_comfort_df=indoor_comfort_df,
                          use_type_name=use_type_name,
                          use_type_metadata=use_type_metadata,
                          use_type_ratios_dict=use_type_ratios_dict)


if __name__ == '__main__':
    main(cea.config.Configuration())


<filename>cea/utilities/create_mixed_use_type.py
"""
This script creates a new use-type by aggregating values from a list of different use-types
"""




import os

import numpy as np
import pandas as pd

import cea
import cea.config
import cea.inputlocator
from cea.datamanagement.archetypes_mapper import calculate_average_multiuse
from cea.datamanagement.schedule_helper import calc_single_mixed_schedule, ScheduleData
from cea.utilities.schedule_reader import save_cea_schedule


__author__ = "<NAME>"
__copyright__ = "Copyright 2018, Architecture and Building Systems - ETH Zurich"
__credits__ = ["<NAME>, <NAME>"]
__license__ = "MIT"
__version__ = "0.1"
__maintainer__ = "<NAME>"
__email__ = "<EMAIL>"
__status__ = "Production"


DEFAULT_USE_TYPE = 'MULTI_RES'
COLUMN_VAR_NAME_TEMPLATE = 'USE_{}'
COLUMN_VAR_VAL_TEMPLATE = 'USE_{}_R'


def create_mixed_use_type(locator, internal_loads_df, indoor_comfort_df,
                          use_type_name, use_type_metadata, use_type_ratios_dict):
    """
    Takes a list of use-types and their respective ratios to aggregate and create a new use-type
    with schedules, internal loads and indoor comfort data

    :param schedules_path:
    :param internal_loads_df:
    :param indoor_comfort_df:
    :param use_type_name:
    :param use_type_metadata:
    :param use_type_ratios_dict:
    :return:
    """
    list_uses = use_type_ratios_dict.keys()
    list_var_names = [COLUMN_VAR_NAME_TEMPLATE.format(i) for i in range(len(use_type_ratios_dict))]
    list_var_values = [COLUMN_VAR_VAL_TEMPLATE.format(i) for i in range(len(use_type_ratios_dict))]

    # Creating required parameters
    properties_dict = {}
    for i, (k, v) in enumerate(use_type_ratios_dict.items()):
        properties_dict[list_var_names[i]] = k
        properties_dict[list_var_values[i]] = v
    properties_df = pd.DataFrame([properties_dict])
    occupant_densities = calculate_occupant_density(list_uses, internal_loads_df)

    print("Calculating internal loads...")
    new_internal_loads_df = calculate_mixed_loads(properties_df, internal_loads_df, occupant_densities, list_uses,
                                                  use_type_name, list_var_names, list_var_values)
    print("Calculating indoor comfort...")
    new_indoor_comfort_df = calculate_mixed_loads(properties_df, indoor_comfort_df, occupant_densities, list_uses,
                                                  use_type_name, list_var_names, list_var_values)

    prop_df_c = properties_df.copy()
    prop_df_c['Name'] = '0'  # Set a `Name` column as index for function to work
    prop_df_c.set_index('Name', inplace=True)
    schedule_data_all_uses = ScheduleData(locator)
    internal_loads = internal_loads_df.set_index('code')
    print("Calculating schedules...")
    schedule_new_data, schedule_complementary_data = calc_single_mixed_schedule(list_uses, occupant_densities,
                                                                                prop_df_c, internal_loads, '0',
                                                                                schedule_data_all_uses, list_var_names,
                                                                                list_var_values, use_type_metadata)

    print("Writing to disk...")
    use_type_properties_path = locator.get_database_use_types_properties()
    with pd.ExcelWriter(use_type_properties_path) as writer:
        new_internal_loads_df.to_excel(writer, sheet_name='INTERNAL_LOADS', index=False)
        new_indoor_comfort_df.to_excel(writer, sheet_name='INDOOR_COMFORT', index=False)

    schedule_path = os.path.join(locator.get_database_use_types_folder(), '{}.csv'.format(use_type_name))
    save_cea_schedule(schedule_new_data, schedule_complementary_data, schedule_path)


def calculate_mixed_loads(properties_df, loads_df, occupant_densities, list_uses, use_type_name, list_var_names, list_var_values):
    prop_df = properties_df.copy().merge(loads_df, left_on=list_var_names[0], right_on='code')
    loads_df_columns = loads_df.columns
    calculated_loads_df = calculate_average_multiuse(loads_df_columns, prop_df, occupant_densities,
                                                     list_uses, loads_df,
                                                     list_var_names, list_var_values).loc[:, loads_df_columns]
    calculated_loads_df['code'] = use_type_name
    # Remove rows that have the same `code` as new row
    clean_loads_df = loads_df[loads_df['code'] != use_type_name]
    return clean_loads_df.append(calculated_loads_df)


def calculate_occupant_density(use_types, internal_loads_df):
    occupant_densities = {}
    internal_loads = internal_loads_df.copy().set_index('code')
    for use in use_types:
        if internal_loads.loc[use, 'Occ_m2p'] > 0.0:
            occupant_densities[use] = 1.0 / internal_loads.loc[use, 'Occ_m2p']
        else:
            occupant_densities[use] = 0.0
    return occupant_densities


def main(config):
    # Config Parameters
    use_type_name = config.create_mixed_use_type.use_type
    use_type_metadata = config.create_mixed_use_type.metadata
    use_type_ratios = config.create_mixed_use_type.ratios
    use_type_ratios_dict = {k: float(v) for k, v in [ratio.split('|') for ratio in use_type_ratios]}

    locator = cea.inputlocator.InputLocator(scenario=config.scenario)
    use_type_properties_df = pd.read_excel(locator.get_database_use_types_properties(), sheet_name=None)
    internal_loads_df = use_type_properties_df['INTERNAL_LOADS']
    indoor_comfort_df = use_type_properties_df['INDOOR_COMFORT']

    assert use_type_name not in internal_loads_df['code'].tolist() and use_type_name not in indoor_comfort_df['code'].tolist(), \
        'Use-type name {} already exists'.format(use_type_name)

    create_mixed_use_type(locator,
                          internal_loads_df=internal_loads_df,
                          indoor_comfort_df=indoor_comfort_df,
                          use_type_name=use_type_name,
                          use_type_metadata=use_type_metadata,
                          use_type_ratios_dict=use_type_ratios_dict)


if __name__ == '__main__':
    main(cea.config.Configuration())


This script creates a new use-type by aggregating values from a list of different use-types Takes a list of use-types and their respective ratios to aggregate and create a new use-type     with schedules, internal loads and indoor comfort data      :param schedules_path:     :param internal_loads_df:     :param indoor_comfort_df:     :param use_type_name:     :param use_type_metadata:     :param use_type_ratios_dict:     :return: # Creating required parameters # Set a `Name` column as index for function to work # Remove rows that have the same `code` as new row # Config Parameters