<filename>analysis/daily_summaries.py
"""
Calculation of daily performance metrics for a given piece of equipment (e.g. a heat pump).  This function is also
embedded in oTherm instance and can be updated daily as a cron job.  Included here to document methods and allow
for customization.

Daily metrics include, each integrated for one day:
    - Heating and cooling degree days, relative to 65F base temperature
    - Heat pump run time (hours)
    - Heat pump energy usage (kWh)
    - Auxiliary heat energy usage (kWh)
    - Thermal energy generated by heat pump under heating and cooling modes (MBtu)
    - Thermal energy exchanged with the ground (MBtu)
    - Average outdoor air temperature (F)
    - Source minimum and maximum temperatures (F)
    - Number of monitoring records for day


.. note::
    Modifying this script will not change calculations in oTherm instance.  See oTherm instance administrator to update
    codebase.

"""

import pandas as pd
import numpy as np
from db_tools import otherm_db_reader
from datetime import date


def create_daily_summaries(data, heatpump_threshold_watts):
    """

    Parameters
    ----------
    data : pandas.DataFrame
        Heat pump operating data from oTherm db

    heatpump_threshold_watts : float
        Threshold to determine if heat pump is on or off.


    Returns
    -------
        pandas.DataFrame

        The returned DataFrame contains daily summary metrics described above

    """

    data['OAT_F'] = data['outdoor_temperature']*(9/5) + 32.

    data['cooling_degrees'] = np.where(data['OAT_F'] > 65.,
                                       (data['OAT_F'] -
                                        65)*data['time_elapsed']/24, 0.)
    data['heating_degrees'] = np.where(data['OAT_F'] < 65.,
                                       (65 - data['OAT_F'])
                                       * data['time_elapsed']/24, 0.)

    data['heatpump_on'] = np.where(data['heatpump_power'] > heatpump_threshold_watts, True, False)

    data['ewt_on'] = (data['heatpump_on'] * data['source_supplytemp']).apply(lambda x: np.nan
                                                          if x == 0 else x)

    data['heatpump_compressor_kwh'] = np.where(data['time_elapsed'] < 0.083,
                                      data['heatpump_power'] * data['time_elapsed'] / 1000., 0)

    if 'heatpump_aux' in data.columns:
        data['heatpump_aux_kwh'] = np.where(data['time_elapsed'] < 0.083,
                                     data['heatpump_aux'] * data['time_elapsed']/1000.,0)

    if 'sourcefluid_pump_power' in data.columns:
        data['sourcefluid_pump_kwh'] = np.where(data['time_elapsed'] < 0.083,
                                     data['sourcefluid_pump_power'] * data['time_elapsed']/1000.,0)

    data['delta_t'] = np.where(data['heatpump_on'],
                                      data['source_supplytemp'] - data['source_returntemp'], 0)

    data['heatpump_runtime'] = np.where((data['time_elapsed'] < 0.083) & (data['heatpump_on']),
                                        data['heatpump_on']*data['time_elapsed'], 0)

    if 'heat_flow_rate' not in data.columns:
        data['btus_exchanged'] = np.where((data['time_elapsed'] < 0.083) & (data['heatpump_on']),
                                          900*data['sourcefluid_flowrate']*data['delta_t']*data['time_elapsed'], 0)
    else:
        data['btus_exchanged'] = np.where((data['time_elapsed'] < 0.083) & (data['heatpump_on']),
                                          data['heat_flow_rate']*data['time_elapsed'], 0)

    data['btu_heating'] = np.where((data['heatpump_on'] & data['btus_exchanged'] > 0),
                                   3412.14 * data['heatpump_compressor_kwh'], 0)

    data['btu_cooling'] = np.where((data['heatpump_on'] & data['btus_exchanged'] < 0),
                                   3412.14 * data['heatpump_compressor_kwh'], 0)

    # Initialize data frame for computing and storing daily values
    # use np.nan as placeholder, as needed to make consistent with
    ds = pd.DataFrame()

    ds['runtime'] = data['heatpump_runtime'].resample('D').sum()
    ds['heatpump_kwh'] = data['heatpump_compressor_kwh'].resample('D').sum()
    ds['auxiliary_kwh'] = data['heatpump_aux_kwh'].resample('D').sum()
    #ds['kwh_loop_pump'] = data['loop_pump_kwh'].resample('D').sum()
    ds['total_kwh'] = ds['heatpump_kwh'] + ds['auxiliary_kwh'] #+ ds['kwh_loop_pump']

    ds['cooling_degree_days'] = data['cooling_degrees'].resample('D').sum()
    ds['heating_degree_days'] = data['heating_degrees'].resample('D').sum()
    ds['mbtus_exchanged'] = data['btus_exchanged'].resample('D').sum()/1000

    ds['mbtus_heat'] = data['btu_heating'].resample('D').sum()/1000
    ds['mbtus_cool'] = data['btu_cooling'].resample('D').sum()/1000

    ds['ewt_min'] = data['ewt_on'].resample('D').min()*(9/5)+32.
    ds['ewt_max'] = data['ewt_on'].resample('D').max()*(9/5)+32.

    ds['OAT_F'] = data['OAT_F'].resample('D').mean()
    ds['n_records'] = data['OAT_F'].resample('D').count()

    ds['date'] = ds.index.strftime("%Y-%m-%d")

    return ds

if __name__ == '__main__':
    site_name = '110722'
    start_date = '2016-01-01'
    end_date = '2022-04-01'
    timezone = 'US/Eastern'
    db = 'otherm_cgb'
    #db = 'localhost'

    site = otherm_db_reader.get_site_info(site_name, db)
    equipment = otherm_db_reader.get_equipment(site.id, db)
    hp_data = otherm_db_reader.get_equipment_data(site.id, start_date, end_date, site.timezone, db)

    dailysummary = create_daily_summaries(hp_data, heatpump_threshold_watts=500)

    output_file = '../temp_files/daily_summary_{}_{}_{}.csv'.format(site_name, db, str(date.today().strftime("%m-%d-%y")))
    dailysummary.to_csv(output_file)
<filename>analysis/daily_summaries.py
"""
Calculation of daily performance metrics for a given piece of equipment (e.g. a heat pump).  This function is also
embedded in oTherm instance and can be updated daily as a cron job.  Included here to document methods and allow
for customization.

Daily metrics include, each integrated for one day:
    - Heating and cooling degree days, relative to 65F base temperature
    - Heat pump run time (hours)
    - Heat pump energy usage (kWh)
    - Auxiliary heat energy usage (kWh)
    - Thermal energy generated by heat pump under heating and cooling modes (MBtu)
    - Thermal energy exchanged with the ground (MBtu)
    - Average outdoor air temperature (F)
    - Source minimum and maximum temperatures (F)
    - Number of monitoring records for day


.. note::
    Modifying this script will not change calculations in oTherm instance.  See oTherm instance administrator to update
    codebase.

"""

import pandas as pd
import numpy as np
from db_tools import otherm_db_reader
from datetime import date


def create_daily_summaries(data, heatpump_threshold_watts):
    """

    Parameters
    ----------
    data : pandas.DataFrame
        Heat pump operating data from oTherm db

    heatpump_threshold_watts : float
        Threshold to determine if heat pump is on or off.


    Returns
    -------
        pandas.DataFrame

        The returned DataFrame contains daily summary metrics described above

    """

    data['OAT_F'] = data['outdoor_temperature']*(9/5) + 32.

    data['cooling_degrees'] = np.where(data['OAT_F'] > 65.,
                                       (data['OAT_F'] -
                                        65)*data['time_elapsed']/24, 0.)
    data['heating_degrees'] = np.where(data['OAT_F'] < 65.,
                                       (65 - data['OAT_F'])
                                       * data['time_elapsed']/24, 0.)

    data['heatpump_on'] = np.where(data['heatpump_power'] > heatpump_threshold_watts, True, False)

    data['ewt_on'] = (data['heatpump_on'] * data['source_supplytemp']).apply(lambda x: np.nan
                                                          if x == 0 else x)

    data['heatpump_compressor_kwh'] = np.where(data['time_elapsed'] < 0.083,
                                      data['heatpump_power'] * data['time_elapsed'] / 1000., 0)

    if 'heatpump_aux' in data.columns:
        data['heatpump_aux_kwh'] = np.where(data['time_elapsed'] < 0.083,
                                     data['heatpump_aux'] * data['time_elapsed']/1000.,0)

    if 'sourcefluid_pump_power' in data.columns:
        data['sourcefluid_pump_kwh'] = np.where(data['time_elapsed'] < 0.083,
                                     data['sourcefluid_pump_power'] * data['time_elapsed']/1000.,0)

    data['delta_t'] = np.where(data['heatpump_on'],
                                      data['source_supplytemp'] - data['source_returntemp'], 0)

    data['heatpump_runtime'] = np.where((data['time_elapsed'] < 0.083) & (data['heatpump_on']),
                                        data['heatpump_on']*data['time_elapsed'], 0)

    if 'heat_flow_rate' not in data.columns:
        data['btus_exchanged'] = np.where((data['time_elapsed'] < 0.083) & (data['heatpump_on']),
                                          900*data['sourcefluid_flowrate']*data['delta_t']*data['time_elapsed'], 0)
    else:
        data['btus_exchanged'] = np.where((data['time_elapsed'] < 0.083) & (data['heatpump_on']),
                                          data['heat_flow_rate']*data['time_elapsed'], 0)

    data['btu_heating'] = np.where((data['heatpump_on'] & data['btus_exchanged'] > 0),
                                   3412.14 * data['heatpump_compressor_kwh'], 0)

    data['btu_cooling'] = np.where((data['heatpump_on'] & data['btus_exchanged'] < 0),
                                   3412.14 * data['heatpump_compressor_kwh'], 0)

    # Initialize data frame for computing and storing daily values
    # use np.nan as placeholder, as needed to make consistent with
    ds = pd.DataFrame()

    ds['runtime'] = data['heatpump_runtime'].resample('D').sum()
    ds['heatpump_kwh'] = data['heatpump_compressor_kwh'].resample('D').sum()
    ds['auxiliary_kwh'] = data['heatpump_aux_kwh'].resample('D').sum()
    #ds['kwh_loop_pump'] = data['loop_pump_kwh'].resample('D').sum()
    ds['total_kwh'] = ds['heatpump_kwh'] + ds['auxiliary_kwh'] #+ ds['kwh_loop_pump']

    ds['cooling_degree_days'] = data['cooling_degrees'].resample('D').sum()
    ds['heating_degree_days'] = data['heating_degrees'].resample('D').sum()
    ds['mbtus_exchanged'] = data['btus_exchanged'].resample('D').sum()/1000

    ds['mbtus_heat'] = data['btu_heating'].resample('D').sum()/1000
    ds['mbtus_cool'] = data['btu_cooling'].resample('D').sum()/1000

    ds['ewt_min'] = data['ewt_on'].resample('D').min()*(9/5)+32.
    ds['ewt_max'] = data['ewt_on'].resample('D').max()*(9/5)+32.

    ds['OAT_F'] = data['OAT_F'].resample('D').mean()
    ds['n_records'] = data['OAT_F'].resample('D').count()

    ds['date'] = ds.index.strftime("%Y-%m-%d")

    return ds

if __name__ == '__main__':
    site_name = '110722'
    start_date = '2016-01-01'
    end_date = '2022-04-01'
    timezone = 'US/Eastern'
    db = 'otherm_cgb'
    #db = 'localhost'

    site = otherm_db_reader.get_site_info(site_name, db)
    equipment = otherm_db_reader.get_equipment(site.id, db)
    hp_data = otherm_db_reader.get_equipment_data(site.id, start_date, end_date, site.timezone, db)

    dailysummary = create_daily_summaries(hp_data, heatpump_threshold_watts=500)

    output_file = '../temp_files/daily_summary_{}_{}_{}.csv'.format(site_name, db, str(date.today().strftime("%m-%d-%y")))
    dailysummary.to_csv(output_file)
Calculation of daily performance metrics for a given piece of equipment (e.g. a heat pump).  This function is also embedded in oTherm instance and can be updated daily as a cron job.  Included here to document methods and allow for customization.  Daily metrics include, each integrated for one day:     - Heating and cooling degree days, relative to 65F base temperature     - Heat pump run time (hours)     - Heat pump energy usage (kWh)     - Auxiliary heat energy usage (kWh)     - Thermal energy generated by heat pump under heating and cooling modes (MBtu)     - Thermal energy exchanged with the ground (MBtu)     - Average outdoor air temperature (F)     - Source minimum and maximum temperatures (F)     - Number of monitoring records for day   .. note::     Modifying this script will not change calculations in oTherm instance.  See oTherm instance administrator to update     codebase. Parameters     ----------     data : pandas.DataFrame         Heat pump operating data from oTherm db      heatpump_threshold_watts : float         Threshold to determine if heat pump is on or off.       Returns     -------         pandas.DataFrame          The returned DataFrame contains daily summary metrics described above # Initialize data frame for computing and storing daily values # use np.nan as placeholder, as needed to make consistent with #ds['kwh_loop_pump'] = data['loop_pump_kwh'].resample('D').sum() #+ ds['kwh_loop_pump'] #db = 'localhost'